diff --git a/CMakeLists.txt b/CMakeLists.txt index e9255bff6ac523e8bfdf61fe42044e4366d3993f..4b302fe373681cdc862851e871c53d3842d0d842 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -573,6 +573,7 @@ target_link_libraries( pugs PugsMesh PugsAlgebra + PugsAnalysis PugsUtils PugsLanguage PugsLanguageAST @@ -606,7 +607,7 @@ if(${CMAKE_VERSION} VERSION_LESS "3.13.0") LIBRARY DESTINATION lib ARCHIVE DESTINATION lib) else() - install(TARGETS pugs PugsAlgebra PugsUtils PugsLanguage PugsLanguageAST PugsLanguageModules PugsLanguageAlgorithms PugsLanguageUtils PugsMesh PugsScheme PugsOutput + install(TARGETS pugs PugsAlgebra PugsAnalysis PugsUtils PugsLanguage PugsLanguageAST PugsLanguageModules PugsLanguageAlgorithms PugsLanguageUtils PugsMesh PugsScheme PugsOutput RUNTIME DESTINATION bin LIBRARY DESTINATION lib diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 16904a7be0cddc9aa54206638ab4b5c759cd0de8..54cae625bc7c899c433bfdf4021ef6242dd5aaf4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -12,6 +12,9 @@ add_subdirectory(language) # Pugs algebra add_subdirectory(algebra) +# Pugs analysis +add_subdirectory(analysis) + # Pugs mesh add_subdirectory(mesh) diff --git a/src/analysis/CMakeLists.txt b/src/analysis/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..3cbded76d7fadead5565ba862289aec3dcdbaad8 --- /dev/null +++ b/src/analysis/CMakeLists.txt @@ -0,0 +1,13 @@ +# ------------------- Source files -------------------- + +add_library( + PugsAnalysis + CubeGaussQuadrature.cpp + QuadratureManager.cpp + PrismGaussQuadrature.cpp + PyramidGaussQuadrature.cpp + SquareGaussQuadrature.cpp + TensorialGaussLegendreQuadrature.cpp + TensorialGaussLobattoQuadrature.cpp + TetrahedronGaussQuadrature.cpp + TriangleGaussQuadrature.cpp) diff --git a/src/analysis/CubeGaussQuadrature.cpp b/src/analysis/CubeGaussQuadrature.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1d35bd875ee46c0faf5d492328c34d9ec7e6466c --- /dev/null +++ b/src/analysis/CubeGaussQuadrature.cpp @@ -0,0 +1,501 @@ +#include <analysis/CubeGaussQuadrature.hpp> +#include <utils/Exceptions.hpp> + +void +CubeGaussQuadrature::_buildPointAndWeightLists(const size_t degree) +{ + using R3 = TinyVector<3>; + + struct Descriptor + { + int id; + double weight; + std::vector<double> lambda_list; + }; + + auto fill_quadrature_points = [](auto descriptor_list, auto& point_list, auto& weight_list) { + Assert(point_list.size() == weight_list.size()); + + size_t k = 0; + for (size_t i = 0; i < descriptor_list.size(); ++i) { + const auto [id, unit_weight, position_list] = descriptor_list[i]; + + const double w = 8. * unit_weight; + + switch (id) { + case 1: { + Assert(position_list.size() == 0); + point_list[k] = {0, 0, 0}; + weight_list[k] = w; + ++k; + break; + } + case 2: { + Assert(position_list.size() == 1); + const double a = position_list[0]; + + point_list[k + 0] = {+a, 0, 0}; + point_list[k + 1] = {-a, 0, 0}; + point_list[k + 2] = {0, +a, 0}; + point_list[k + 3] = {0, -a, 0}; + point_list[k + 4] = {0, 0, +a}; + point_list[k + 5] = {0, 0, -a}; + + for (size_t l = 0; l < 6; ++l) { + weight_list[k + l] = w; + } + + k += 6; + break; + } + case 3: { + Assert(position_list.size() == 1); + const double a = position_list[0]; + + point_list[k + 0] = {+a, +a, +a}; + point_list[k + 1] = {+a, +a, -a}; + point_list[k + 2] = {+a, -a, +a}; + point_list[k + 3] = {+a, -a, -a}; + point_list[k + 4] = {-a, +a, +a}; + point_list[k + 5] = {-a, +a, -a}; + point_list[k + 6] = {-a, -a, +a}; + point_list[k + 7] = {-a, -a, -a}; + + for (size_t l = 0; l < 8; ++l) { + weight_list[k + l] = w; + } + + k += 8; + break; + } + case 4: { + Assert(position_list.size() == 1); + const double a = position_list[0]; + + point_list[k + 0] = {+a, +a, 0}; + point_list[k + 1] = {+a, -a, 0}; + point_list[k + 2] = {-a, +a, 0}; + point_list[k + 3] = {-a, -a, 0}; + point_list[k + 4] = {+a, 0, +a}; + point_list[k + 5] = {+a, 0, -a}; + point_list[k + 6] = {-a, 0, +a}; + point_list[k + 7] = {-a, 0, -a}; + point_list[k + 8] = {0, +a, +a}; + point_list[k + 9] = {0, +a, -a}; + point_list[k + 10] = {0, -a, +a}; + point_list[k + 11] = {0, -a, -a}; + + for (size_t l = 0; l < 12; ++l) { + weight_list[k + l] = w; + } + + k += 12; + break; + } + case 5: { + Assert(position_list.size() == 2); + const double a = position_list[0]; + const double b = position_list[1]; + + point_list[k + 0] = {+a, +b, 0}; + point_list[k + 1] = {+a, -b, 0}; + point_list[k + 2] = {-a, +b, 0}; + point_list[k + 3] = {-a, -b, 0}; + point_list[k + 4] = {+b, +a, 0}; + point_list[k + 5] = {-b, +a, 0}; + point_list[k + 6] = {+b, -a, 0}; + point_list[k + 7] = {-b, -a, 0}; + point_list[k + 8] = {+a, 0, +b}; + point_list[k + 9] = {+a, 0, -b}; + point_list[k + 10] = {-a, 0, +b}; + point_list[k + 11] = {-a, 0, -b}; + point_list[k + 12] = {+b, 0, +a}; + point_list[k + 13] = {-b, 0, +a}; + point_list[k + 14] = {+b, 0, -a}; + point_list[k + 15] = {-b, 0, -a}; + point_list[k + 16] = {0, +a, +b}; + point_list[k + 17] = {0, +a, -b}; + point_list[k + 18] = {0, -a, +b}; + point_list[k + 19] = {0, -a, -b}; + point_list[k + 20] = {0, +b, +a}; + point_list[k + 21] = {0, -b, +a}; + point_list[k + 22] = {0, +b, -a}; + point_list[k + 23] = {0, -b, -a}; + + for (size_t l = 0; l < 24; ++l) { + weight_list[k + l] = w; + } + + k += 24; + break; + } + case 6: { + Assert(position_list.size() == 2); + const double a = position_list[0]; + const double b = position_list[1]; + + point_list[k + 0] = {+a, +a, +b}; + point_list[k + 1] = {+a, +a, -b}; + point_list[k + 2] = {+a, -a, +b}; + point_list[k + 3] = {+a, -a, -b}; + point_list[k + 4] = {-a, +a, +b}; + point_list[k + 5] = {-a, +a, -b}; + point_list[k + 6] = {-a, -a, +b}; + point_list[k + 7] = {-a, -a, -b}; + point_list[k + 8] = {+a, +b, +a}; + point_list[k + 9] = {+a, -b, +a}; + point_list[k + 10] = {+a, +b, -a}; + point_list[k + 11] = {+a, -b, -a}; + point_list[k + 12] = {-a, +b, +a}; + point_list[k + 13] = {-a, -b, +a}; + point_list[k + 14] = {-a, +b, -a}; + point_list[k + 15] = {-a, -b, -a}; + point_list[k + 16] = {+b, +a, +a}; + point_list[k + 17] = {-b, +a, +a}; + point_list[k + 18] = {+b, +a, -a}; + point_list[k + 19] = {-b, +a, -a}; + point_list[k + 20] = {+b, -a, +a}; + point_list[k + 21] = {-b, -a, +a}; + point_list[k + 22] = {+b, -a, -a}; + point_list[k + 23] = {-b, -a, -a}; + + for (size_t l = 0; l < 24; ++l) { + weight_list[k + l] = w; + } + + k += 24; + break; + } + case 7: { + Assert(position_list.size() == 3); + const double a = position_list[0]; + const double b = position_list[1]; + const double c = position_list[2]; + + point_list[k + 0] = {+a, +b, +c}; + point_list[k + 1] = {+a, +b, -c}; + point_list[k + 2] = {+a, -b, +c}; + point_list[k + 3] = {+a, -b, -c}; + point_list[k + 4] = {-a, +b, +c}; + point_list[k + 5] = {-a, +b, -c}; + point_list[k + 6] = {-a, -b, +c}; + point_list[k + 7] = {-a, -b, -c}; + point_list[k + 8] = {+a, +c, +b}; + point_list[k + 9] = {+a, -c, +b}; + point_list[k + 10] = {+a, +c, -b}; + point_list[k + 11] = {+a, -c, -b}; + point_list[k + 12] = {-a, +c, +b}; + point_list[k + 13] = {-a, -c, +b}; + point_list[k + 14] = {-a, +c, -b}; + point_list[k + 15] = {-a, -c, -b}; + point_list[k + 16] = {+b, +a, +c}; + point_list[k + 17] = {+b, +a, -c}; + point_list[k + 18] = {-b, +a, +c}; + point_list[k + 19] = {-b, +a, -c}; + point_list[k + 20] = {+b, -a, +c}; + point_list[k + 21] = {+b, -a, -c}; + point_list[k + 22] = {-b, -a, +c}; + point_list[k + 23] = {-b, -a, -c}; + point_list[k + 24] = {+b, +c, +a}; + point_list[k + 25] = {+b, -c, +a}; + point_list[k + 26] = {-b, +c, +a}; + point_list[k + 27] = {-b, -c, +a}; + point_list[k + 28] = {+b, +c, -a}; + point_list[k + 29] = {+b, -c, -a}; + point_list[k + 30] = {-b, +c, -a}; + point_list[k + 31] = {-b, -c, -a}; + point_list[k + 32] = {+c, +a, +b}; + point_list[k + 33] = {-c, +a, +b}; + point_list[k + 34] = {+c, +a, -b}; + point_list[k + 35] = {-c, +a, -b}; + point_list[k + 36] = {+c, -a, +b}; + point_list[k + 37] = {-c, -a, +b}; + point_list[k + 38] = {+c, -a, -b}; + point_list[k + 39] = {-c, -a, -b}; + point_list[k + 40] = {+c, +b, +a}; + point_list[k + 41] = {-c, +b, +a}; + point_list[k + 42] = {+c, -b, +a}; + point_list[k + 43] = {-c, -b, +a}; + point_list[k + 44] = {+c, +b, -a}; + point_list[k + 45] = {-c, +b, -a}; + point_list[k + 46] = {+c, -b, -a}; + point_list[k + 47] = {-c, -b, -a}; + + for (size_t l = 0; l < 48; ++l) { + weight_list[k + l] = w; + } + + k += 48; + break; + } + // LCOV_EXCL_START + default: { + throw UnexpectedError("invalid quadrature id"); + } + // LCOV_EXCL_STOP + } + } + }; + + switch (degree) { + case 0: + case 1: { + constexpr size_t nb_points = 1; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{1, 1.000000000000000e+00, {}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 2: + case 3: { + constexpr size_t nb_points = 6; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{2, 1.666666666666667e-01, {+1.000000000000000e+00}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 4: + case 5: { + constexpr size_t nb_points = 14; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{2, 1.108033240997230e-01, {-7.958224257542215e-01}}, + Descriptor{3, 4.189750692520776e-02, {+7.587869106393281e-01}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 6: + case 7: { + constexpr size_t nb_points = 34; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{2, 3.400458474980031e-02, {-9.388053721060176e-01}}, + Descriptor{3, 2.529672440135186e-02, {+7.463336100128160e-01}}, + Descriptor{3, 5.417063533485642e-02, {+4.101308983320144e-01}}, + Descriptor{4, 1.335280113429432e-02, {+9.064606901228371e-01}}}; + + fill_quadrature_points(descriptor_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 = 58; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{2, 5.415937446870682e-02, {-6.136814695917090e-01}}, + Descriptor{3, 6.268599412418628e-03, {+8.700997846619759e-01}}, + Descriptor{3, 2.485747976800294e-02, {+5.641108070200300e-01}}, + Descriptor{4, 1.147372576702221e-02, {+8.776871232576783e-01}}, + Descriptor{6, 1.201460043917167e-02, {+4.322679026308622e-01, +9.385304218646717e-01}}}; + + fill_quadrature_points(descriptor_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 = 90; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{2, 2.961692452402056e-02, {+7.221330388744185e-01}}, + Descriptor{3, 7.751183787523073e-03, {+8.094882019630989e-01}}, + Descriptor{3, 2.222100810905048e-02, {-5.336540088804971e-01}}, + Descriptor{3, 1.698870214455200e-02, {+2.807725866512744e-01}}, + Descriptor{4, 1.602728177693560e-02, {+8.039334672152845e-01}}, + Descriptor{6, 1.618821190032323e-03, {+9.800994910090715e-01, -5.307838311938264e-01}}, + Descriptor{6, 8.976342110119554e-03, {+4.056859801950964e-01, +9.545832189295661e-01}}}; + + fill_quadrature_points(descriptor_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 = 154; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{2, 1.739128248747042e-02, {-6.344099893707986e-01}}, + Descriptor{3, 1.838657780061070e-03, {+9.078540479628353e-01}}, + Descriptor{3, 1.129102483142921e-02, {-2.362052584516462e-01}}, + Descriptor{4, 5.975759635289482e-03, {+7.375746343132366e-01}}, + Descriptor{5, 8.691231524417118e-03, {+4.607161476964481e-01, +9.333452030108366e-01}}, + Descriptor{6, 1.061455871034256e-02, {+3.733841515799997e-01, +6.642163895931538e-01}}, + Descriptor{6, 1.690358916666084e-03, {+9.495110814642814e-01, +2.576763878569212e-01}}, + Descriptor{6, 2.284240552839863e-03, {+6.656694827601780e-01, +9.948700428018972e-01}}, + Descriptor{6, 6.674015652391932e-03, {-8.051009105032320e-01, -4.521405059548300e-01}}}; + + fill_quadrature_points(descriptor_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 = 256; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{2, 3.340305010694517e-03, {+9.239155149504112e-01}}, + Descriptor{2, 5.018552337877279e-03, {-2.173948613666498e-01}}, + Descriptor{3, 9.082758817224784e-03, {+3.384731869494254e-01}}, + Descriptor{3, 2.936408738387597e-03, {+7.930891310393379e-01}}, + Descriptor{4, 9.318238647048784e-03, {+6.965519027266717e-01}}, + Descriptor{5, 6.990786235751096e-03, {+2.642667592628472e-01, +5.849899486873243e-01}}, + Descriptor{5, 2.841005747490632e-03, {+5.529505913370675e-01, +9.828048727801773e-01}}, + Descriptor{6, 5.309574072330840e-03, {+2.720325890860906e-01, +8.780894076733160e-01}}, + Descriptor{6, 3.570894536567292e-03, {+6.186478600855522e-01, +9.399813353075436e-01}}, + Descriptor{6, 3.505872179585672e-03, {+8.631544625530380e-01, +3.042225951752605e-01}}, + Descriptor{6, 6.665199051138311e-03, {+4.616057726468051e-01, +7.371361183496182e-01}}, + Descriptor{6, 7.781518386120085e-04, {+9.603141805416257e-01, +7.670146080341008e-01}}, + Descriptor{7, 6.249800796596737e-04, {+2.802518397917547e-01, +8.885938329579797e-01, +9.942601945848643e-01}}}; + + fill_quadrature_points(descriptor_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 = 346; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{2, 9.614592128929721e-03, {+4.853150302302675e-01}}, + Descriptor{3, 4.393827602159037e-03, {+7.406788158740985e-01}}, + Descriptor{3, 4.964725194523337e-05, {+9.999995835822517e-01}}, + Descriptor{4, 2.506284464832531e-03, {+7.546268052131762e-01}}, + Descriptor{4, 6.133232482070283e-03, {+5.496818141686911e-01}}, + Descriptor{4, 3.052513689971173e-04, {+9.996685037422811e-01}}, + Descriptor{5, 2.825437733033075e-03, {+6.157290991684734e-01, +9.530419407049950e-01}}, + Descriptor{5, 4.817704598799924e-03, {+2.756812731993550e-01, +8.171240681070916e-01}}, + Descriptor{6, 2.283142338953617e-03, {+2.553429540372821e-01, +9.697740446619386e-01}}, + Descriptor{6, 1.177437487278679e-03, {+9.352363848980443e-01, +7.467233074183380e-01}}, + Descriptor{6, 6.184060750627916e-03, {+3.430591461388653e-01, +6.186639578085585e-01}}, + Descriptor{6, 2.674655837593652e-03, {+2.555841601150721e-01, -1.540702494043778e-01}}, + Descriptor{6, 3.419177677578799e-03, {+5.416211416468879e-01, +8.956569517854811e-01}}, + Descriptor{6, 2.334617556615003e-03, {+8.874561091440486e-01, +2.414649778934788e-01}}, + Descriptor{7, 1.052790164887146e-03, {+8.014733742030056e-01, +9.887847181449660e-01, +4.683593080344387e-01}}, + Descriptor{7, 2.743830940763945e-03, {+6.099140660050306e-01, +7.868230999431114e-01, +3.205108203811766e-01}}}; + + fill_quadrature_points(descriptor_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 = 454; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{2, 2.057371005731085e-03, {+2.357950388975374e-01}}, + Descriptor{3, 9.660877915728369e-04, {+8.884950400440639e-01}}, + Descriptor{3, 1.635901446799172e-03, {+6.691818469930052e-01}}, + Descriptor{5, 8.499912813105116e-04, {+7.123100397018546e-01, +9.982977792850621e-01}}, + Descriptor{5, 3.595003721736422e-03, {+3.997141162742279e-01, +1.720241294475643e-01}}, + Descriptor{5, 3.836063429622649e-03, {+8.765805264721680e-01, -4.319090088935915e-01}}, + Descriptor{6, 5.044128485798918e-03, {-3.101731974045544e-01, +5.411043641351523e-01}}, + Descriptor{6, 1.951830532879285e-04, {+9.841852549757261e-01, +8.206649948892372e-01}}, + Descriptor{6, 1.758454840661237e-03, {+8.443872335315854e-01, -1.473766326322086e-01}}, + Descriptor{6, 3.887320262932200e-03, {+4.875993998852213e-01, +7.674914745033637e-01}}, + Descriptor{6, 1.887401083675721e-03, {+7.641318497967444e-01, +3.863910365012072e-01}}, + Descriptor{6, 1.699165183521457e-03, {+7.112537388224306e-01, +9.032012949929131e-01}}, + Descriptor{6, 7.588378288377641e-04, {+9.551489495939087e-01, +2.226160644570115e-01}}, + Descriptor{6, 1.455762954103218e-03, {+1.696919803869971e-01, +9.651628675592381e-01}}, + Descriptor{6, 4.007905075757146e-03, {+6.085335258834057e-01, +9.412726803541549e-02}}, + Descriptor{6, 1.399186075584291e-03, {+4.265517787687217e-01, +9.784781131096041e-01}}, + Descriptor{6, 4.099280788926685e-03, {+1.836920702608942e-01, +7.457754226757105e-01}}, + Descriptor{7, 1.951861257384991e-03, {+6.535330886596633e-01, +9.133523126050157e-01, +2.888629020786040e-01}}, + Descriptor{7, 9.537937942918817e-04, {+8.475635090984786e-01, +9.748482139426561e-01, +5.534277540813458e-01}}}; + + fill_quadrature_points(descriptor_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 = 580; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{2, 3.007917561622623e-03, {-6.174957125232848e-01}}, + Descriptor{2, 6.157551855986320e-03, {-2.913675401437903e-01}}, + Descriptor{3, 7.451864938264940e-04, {+8.622583182294242e-01}}, + Descriptor{3, 3.473649875824585e-03, {+5.666798116095041e-01}}, + Descriptor{5, 5.231065457280251e-04, {+7.962288576876380e-01, +9.999999871114571e-01}}, + Descriptor{5, 4.721261422431887e-03, {+6.935661772320008e-01, +3.463806774517028e-01}}, + Descriptor{5, 2.337222373763527e-03, {+8.718362020420203e-01, -6.252215000307171e-01}}, + Descriptor{6, 3.841754898565957e-03, {-4.164545409594995e-01, +8.053481425029153e-01}}, + Descriptor{6, 1.507767719634259e-04, {+9.738519593091541e-01, +8.745003988374457e-01}}, + Descriptor{6, 3.214079409518292e-03, {+7.290234505608810e-01, +2.451675433295293e-01}}, + Descriptor{6, 2.245446622613030e-03, {+6.496117102813809e-01, +8.441031264282526e-01}}, + Descriptor{6, 1.041367673151780e-03, {+8.919707516952021e-01, +1.301935885566839e-01}}, + Descriptor{6, 5.920000965024342e-04, {+7.833271437290619e-01, +9.532187072534166e-01}}, + Descriptor{6, 4.100172337698149e-04, {+9.699411873288849e-01, +2.710159328732420e-01}}, + Descriptor{6, 7.465850926621290e-04, {+1.720339772207737e-01, +9.847690037797490e-01}}, + Descriptor{6, 3.743289683970358e-03, {+5.380985926191851e-01, -2.207631346215846e-01}}, + Descriptor{6, 4.534357504253366e-04, {+5.536849035893876e-01, +9.989728978231427e-01}}, + Descriptor{6, 4.182867578178122e-03, {+2.235580139510551e-01, +4.418577456047065e-01}}, + Descriptor{6, 7.389797381822837e-04, {+8.700625815926416e-01, +4.988147208937697e-01}}, + Descriptor{7, 1.371282553387760e-03, {+7.501439986013229e-01, +9.439853549264192e-01, +3.972114022576276e-01}}, + Descriptor{7, 3.675472168789246e-04, {+9.025858122958752e-01, +9.846237882037482e-01, +6.307126444914427e-01}}, + Descriptor{7, 1.258019483515844e-03, {+2.217794596478607e-01, +9.822849317288322e-02, +8.721988578583585e-01}}, + Descriptor{7, 1.516565561694638e-03, {+9.568422563542535e-01, +2.081392891496346e-01, +4.958409266028638e-01}}}; + + fill_quadrature_points(descriptor_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 " + + std::to_string(CubeGaussQuadrature::max_degree) + " on cubes"); + } + } +} diff --git a/src/analysis/CubeGaussQuadrature.hpp b/src/analysis/CubeGaussQuadrature.hpp new file mode 100644 index 0000000000000000000000000000000000000000..bd4ed179dd3cf3745e0dc4512eaa543f1ba6e1b9 --- /dev/null +++ b/src/analysis/CubeGaussQuadrature.hpp @@ -0,0 +1,39 @@ +#ifndef CUBE_GAUSS_QUADRATURE_HPP +#define CUBE_GAUSS_QUADRATURE_HPP + +#include <analysis/QuadratureFormula.hpp> + +/** + * Defines Cube Gauss quadrature on the reference element + * \f$]-1,1[^3\f$. + * + * \note formulae are provided by + * + * "Addendum to the paper 'High-order symmetric cubature rules for + * tetrahedra and pyramids'" Jan JasĖkowiec & N. Sukumar (2020). + */ +class CubeGaussQuadrature final : public QuadratureFormula<3> +{ + public: + constexpr static size_t max_degree = 21; + + private: + void _buildPointAndWeightLists(const size_t degree); + + public: + CubeGaussQuadrature(CubeGaussQuadrature&&) = default; + CubeGaussQuadrature(const CubeGaussQuadrature&) = default; + + private: + friend class QuadratureManager; + + explicit CubeGaussQuadrature(const size_t degree) : QuadratureFormula<3>{QuadratureType::Gauss} + { + this->_buildPointAndWeightLists(degree); + } + + CubeGaussQuadrature() = delete; + ~CubeGaussQuadrature() = default; +}; + +#endif // CUBE_GAUSS_QUADRATURE_HPP diff --git a/src/analysis/GaussLegendreQuadratureDescriptor.hpp b/src/analysis/GaussLegendreQuadratureDescriptor.hpp new file mode 100644 index 0000000000000000000000000000000000000000..c37122516fa67650307aaab421120da9353f51d0 --- /dev/null +++ b/src/analysis/GaussLegendreQuadratureDescriptor.hpp @@ -0,0 +1,50 @@ +#ifndef GAUSS_LEGENDRE_QUADRATURE_DESCRIPTOR_HPP +#define GAUSS_LEGENDRE_QUADRATURE_DESCRIPTOR_HPP + +#include <analysis/IQuadratureDescriptor.hpp> + +#include <sstream> + +class GaussLegendreQuadratureDescriptor final : public IQuadratureDescriptor +{ + private: + size_t m_degree; + + public: + bool + isTensorial() const + { + return true; + } + + QuadratureType + type() const + { + return QuadratureType::GaussLegendre; + } + + size_t + degree() const + { + return m_degree; + } + + std::string + name() const + { + std::ostringstream os; + os << ::name(this->type()) << "(" << m_degree << ")"; + return os.str(); + } + + GaussLegendreQuadratureDescriptor(size_t degree) : m_degree{degree} {} + GaussLegendreQuadratureDescriptor() noexcept = delete; + + GaussLegendreQuadratureDescriptor(const GaussLegendreQuadratureDescriptor&) = default; + + GaussLegendreQuadratureDescriptor(GaussLegendreQuadratureDescriptor&&) noexcept = default; + + virtual ~GaussLegendreQuadratureDescriptor() noexcept = default; +}; + +#endif // GAUSS_LEGENDRE_QUADRATURE_DESCRIPTOR_HPP diff --git a/src/analysis/GaussLobattoQuadratureDescriptor.hpp b/src/analysis/GaussLobattoQuadratureDescriptor.hpp new file mode 100644 index 0000000000000000000000000000000000000000..0cc3a8e6ef108af6708098c0735338621ed880a4 --- /dev/null +++ b/src/analysis/GaussLobattoQuadratureDescriptor.hpp @@ -0,0 +1,50 @@ +#ifndef GAUSS_LOBATTO_QUADRATURE_DESCRIPTOR_HPP +#define GAUSS_LOBATTO_QUADRATURE_DESCRIPTOR_HPP + +#include <analysis/IQuadratureDescriptor.hpp> + +#include <sstream> + +class GaussLobattoQuadratureDescriptor final : public IQuadratureDescriptor +{ + private: + size_t m_degree; + + public: + bool + isTensorial() const + { + return true; + } + + QuadratureType + type() const + { + return QuadratureType::GaussLobatto; + } + + size_t + degree() const + { + return m_degree; + } + + std::string + name() const + { + std::ostringstream os; + os << ::name(this->type()) << "(" << m_degree << ")"; + return os.str(); + } + + GaussLobattoQuadratureDescriptor(size_t degree) : m_degree{degree} {} + GaussLobattoQuadratureDescriptor() noexcept = delete; + + GaussLobattoQuadratureDescriptor(const GaussLobattoQuadratureDescriptor&) = default; + + GaussLobattoQuadratureDescriptor(GaussLobattoQuadratureDescriptor&&) noexcept = default; + + virtual ~GaussLobattoQuadratureDescriptor() noexcept = default; +}; + +#endif // GAUSS_LOBATTO_QUADRATURE_DESCRIPTOR_HPP diff --git a/src/analysis/GaussQuadratureDescriptor.hpp b/src/analysis/GaussQuadratureDescriptor.hpp new file mode 100644 index 0000000000000000000000000000000000000000..752ac40d4fa3b609f848ea82bf10b0576a3e794f --- /dev/null +++ b/src/analysis/GaussQuadratureDescriptor.hpp @@ -0,0 +1,50 @@ +#ifndef GAUSS_QUADRATURE_DESCRIPTOR_HPP +#define GAUSS_QUADRATURE_DESCRIPTOR_HPP + +#include <analysis/IQuadratureDescriptor.hpp> + +#include <sstream> + +class GaussQuadratureDescriptor final : public IQuadratureDescriptor +{ + private: + size_t m_degree; + + public: + bool + isTensorial() const + { + return false; + } + + QuadratureType + type() const + { + return QuadratureType::Gauss; + } + + size_t + degree() const + { + return m_degree; + } + + std::string + name() const + { + std::ostringstream os; + os << ::name(this->type()) << "(" << m_degree << ")"; + return os.str(); + } + + GaussQuadratureDescriptor(size_t degree) : m_degree{degree} {} + GaussQuadratureDescriptor() noexcept = delete; + + GaussQuadratureDescriptor(const GaussQuadratureDescriptor&) = default; + + GaussQuadratureDescriptor(GaussQuadratureDescriptor&&) noexcept = default; + + virtual ~GaussQuadratureDescriptor() noexcept = default; +}; + +#endif // GAUSS_QUADRATURE_DESCRIPTOR_HPP diff --git a/src/analysis/IQuadratureDescriptor.hpp b/src/analysis/IQuadratureDescriptor.hpp new file mode 100644 index 0000000000000000000000000000000000000000..5d7e3685a8c7a8a6014ce7d8753d231183ba52aa --- /dev/null +++ b/src/analysis/IQuadratureDescriptor.hpp @@ -0,0 +1,25 @@ +#ifndef I_QUADRATURE_DESCRIPTOR_HPP +#define I_QUADRATURE_DESCRIPTOR_HPP + +#include <analysis/QuadratureType.hpp> + +#include <string> + +class IQuadratureDescriptor +{ + public: + virtual QuadratureType type() const = 0; + virtual bool isTensorial() const = 0; + virtual size_t degree() const = 0; + virtual std::string name() const = 0; + + IQuadratureDescriptor() noexcept = default; + + IQuadratureDescriptor(const IQuadratureDescriptor&) = default; + + IQuadratureDescriptor(IQuadratureDescriptor&&) noexcept = default; + + virtual ~IQuadratureDescriptor() noexcept = default; +}; + +#endif // I_QUADRATURE_DESCRIPTOR_HPP diff --git a/src/analysis/PrismGaussQuadrature.cpp b/src/analysis/PrismGaussQuadrature.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c2cde582ba1c4e2b6b5077e976a43dea5deaca77 --- /dev/null +++ b/src/analysis/PrismGaussQuadrature.cpp @@ -0,0 +1,804 @@ +#include <analysis/PrismGaussQuadrature.hpp> +#include <utils/Exceptions.hpp> + +void +PrismGaussQuadrature::_buildPointAndWeightLists(const size_t degree) +{ + using R2 = TinyVector<2>; + using R3 = TinyVector<3>; + + struct Descriptor + { + int id; + double weight; + std::vector<double> lambda_list; + }; + + auto fill_quadrature_points = [](auto descriptor_list, auto& point_list, auto& weight_list) { + auto to_R3 = [](R2 X, double z) { return R3{X[0], X[1], z}; }; + + Assert(point_list.size() == weight_list.size()); + + const R2 A = {0, 0}; + const R2 B = {1, 0}; + const R2 C = {0, 1}; + + size_t k = 0; + for (size_t i = 0; i < descriptor_list.size(); ++i) { + const auto [id, w, value_list] = descriptor_list[i]; + + switch (id) { + case 1: { + Assert(value_list.size() == 0); + + point_list[k] = {1. / 3, 1. / 3, 0.}; + weight_list[k] = w; + + k += 1; + break; + } + case 2: { + Assert(value_list.size() == 1); + const double c = value_list[0]; + point_list[k + 0] = {1. / 3, 1. / 3, +c}; + point_list[k + 1] = {1. / 3, 1. / 3, -c}; + + for (size_t l = 0; l < 2; ++l) { + weight_list[k + l] = w; + } + + k += 2; + break; + } + case 3: { + Assert(value_list.size() == 1); + const double l0 = value_list[0]; + const double l1 = 1 - 2 * l0; + + point_list[k + 0] = to_R3(l0 * A + l0 * B + l1 * C, 0); + point_list[k + 1] = to_R3(l0 * A + l1 * B + l0 * C, 0); + point_list[k + 2] = to_R3(l1 * A + l0 * B + l0 * C, 0); + + for (size_t l = 0; l < 3; ++l) { + weight_list[k + l] = w; + } + + k += 3; + break; + } + case 4: { + Assert(value_list.size() == 2); + const double l0 = value_list[0]; + const double l1 = 1 - 2 * l0; + const double z = value_list[1]; + + point_list[k + 0] = to_R3(l0 * A + l0 * B + l1 * C, +z); + point_list[k + 1] = to_R3(l0 * A + l1 * B + l0 * C, +z); + point_list[k + 2] = to_R3(l1 * A + l0 * B + l0 * C, +z); + point_list[k + 3] = to_R3(l0 * A + l0 * B + l1 * C, -z); + point_list[k + 4] = to_R3(l0 * A + l1 * B + l0 * C, -z); + point_list[k + 5] = to_R3(l1 * A + l0 * B + l0 * C, -z); + + for (size_t l = 0; l < 6; ++l) { + weight_list[k + l] = w; + } + + k += 6; + break; + } + case 5: { + Assert(value_list.size() == 2); + const double l0 = value_list[0]; + const double l1 = value_list[1]; + const double l2 = 1 - l0 - l1; + + point_list[k + 0] = to_R3(l0 * A + l1 * B + l2 * C, 0); + point_list[k + 1] = to_R3(l0 * A + l2 * B + l1 * C, 0); + point_list[k + 2] = to_R3(l1 * A + l0 * B + l2 * C, 0); + point_list[k + 3] = to_R3(l1 * A + l2 * B + l0 * C, 0); + point_list[k + 4] = to_R3(l2 * A + l0 * B + l1 * C, 0); + point_list[k + 5] = to_R3(l2 * A + l1 * B + l0 * C, 0); + + for (size_t l = 0; l < 6; ++l) { + weight_list[k + l] = w; + } + + k += 6; + break; + } + case 6: { + Assert(value_list.size() == 3); + const double l0 = value_list[0]; + const double l1 = value_list[1]; + const double l2 = 1 - l0 - l1; + const double z = value_list[2]; + + point_list[k + 0] = to_R3(l0 * A + l1 * B + l2 * C, +z); + point_list[k + 1] = to_R3(l0 * A + l2 * B + l1 * C, +z); + point_list[k + 2] = to_R3(l1 * A + l0 * B + l2 * C, +z); + point_list[k + 3] = to_R3(l1 * A + l2 * B + l0 * C, +z); + point_list[k + 4] = to_R3(l2 * A + l0 * B + l1 * C, +z); + point_list[k + 5] = to_R3(l2 * A + l1 * B + l0 * C, +z); + point_list[k + 6] = to_R3(l0 * A + l1 * B + l2 * C, -z); + point_list[k + 7] = to_R3(l0 * A + l2 * B + l1 * C, -z); + point_list[k + 8] = to_R3(l1 * A + l0 * B + l2 * C, -z); + point_list[k + 9] = to_R3(l1 * A + l2 * B + l0 * C, -z); + point_list[k + 10] = to_R3(l2 * A + l0 * B + l1 * C, -z); + point_list[k + 11] = to_R3(l2 * A + l1 * B + l0 * C, -z); + + for (size_t l = 0; l < 12; ++l) { + weight_list[k + l] = w; + } + + k += 12; + break; + } + // LCOV_EXCL_START + default: { + throw UnexpectedError("invalid quadrature id"); + } + // LCOV_EXCL_STOP + } + } + }; + + switch (degree) { + case 0: + case 1: { + constexpr size_t nb_points = 1; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{1, 1.000000000000000e+00, {}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 2: { + constexpr size_t nb_points = 5; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{2, 2.344355869392759e-01, {-8.431650688665664e-01}}, + Descriptor{3, 1.770429420404827e-01, {+1.046424703769979e-01}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 3: { + constexpr size_t nb_points = 8; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{2, 1.803034341765672e-01, {-9.614404179888022e-01}}, + Descriptor{3, 1.134313729984015e-01, {+4.890588576053607e-01}}, + Descriptor{3, 9.969967088388698e-02, {+7.783177802730620e-02}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 4: { + constexpr size_t nb_points = 11; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{2, 1.079119748155355e-01, {-8.668619740090348e-01}}, + Descriptor{3, 1.364146126054776e-01, {+4.686558098619952e-01}}, + Descriptor{4, 6.248870209208267e-02, {+1.007404057989106e-01, +6.756398236822597e-01}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 5: { + constexpr size_t nb_points = 16; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{1, 2.071428343483058e-01, {}}, Descriptor{3, 3.807558903099764e-02, {+5.176461782716475e-02}}, + Descriptor{4, 7.637426139226190e-02, {+1.663967696311171e-01, +8.071634863884439e-01}}, + Descriptor{4, 3.673080503418831e-02, {+4.976649895838920e-01, -3.972616744496609e-01}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 6: { + constexpr size_t nb_points = 28; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{2, 3.614462938209505e-02, {+9.850385924415599e-01}}, + Descriptor{2, 5.544690202422076e-02, {-5.039978952117941e-01}}, + Descriptor{3, 1.164296357658436e-02, {+1.750424465865124e-02}}, + Descriptor{3, 7.688064192655711e-02, {+1.617417813899514e-01}}, + Descriptor{4, 4.962685514962321e-02, {+4.656535513495914e-01, +4.811426008466984e-01}}, + Descriptor{6, 2.112374914835039e-02, {+3.459486985245699e-02, +2.025039451729335e-01, -8.094634904091534e-01}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 7: { + constexpr size_t nb_points = 35; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{2, 2.844568111268929e-02, {+9.802280695908916e-01}}, + Descriptor{3, 6.118242173095039e-03, {+8.337595466021473e-03}}, + Descriptor{4, 2.155086408622646e-02, {+4.815219753291366e-01, -8.413873542065260e-01}}, + Descriptor{4, 2.917852490209846e-02, {+9.548324837148936e-02, -7.958490905869831e-01}}, + Descriptor{5, 2.551485633514925e-02, {+7.429966820728956e-01, +1.214913159837829e-02}}, + Descriptor{6, 3.894070327620761e-02, {+1.529845984247976e-01, +3.051562164322261e-01, +4.039345605321099e-01}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 8: { + constexpr size_t nb_points = 46; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{2, 2.073493664285546e-02, {+2.244338661059906e-01}}, + Descriptor{2, 5.108942711218155e-02, {-6.818254415708658e-01}}, + Descriptor{3, 5.269974490650717e-02, {+4.600889628137106e-01}}, + Descriptor{3, 1.815224878414972e-02, {+5.341235093690714e-02}}, + Descriptor{4, 7.145357753538616e-03, {+4.723878583976938e-02, +8.288154430586802e-01}}, + Descriptor{4, 4.062926265898933e-02, {+1.740616079243704e-01, +4.060842293545903e-01}}, + Descriptor{4, 1.114302734846531e-02, {+1.597492639425890e-01, +9.658651665406544e-01}}, + Descriptor{4, 2.108650929358649e-02, {+4.585690687909513e-01, +8.761959100002542e-01}}, + Descriptor{6, 1.364752909087307e-02, {+8.588127507759013e-03, +7.285980718010000e-01, +5.773502691896257e-01}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 9: { + constexpr size_t nb_points = 59; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{2, 3.428347129092372e-02, {-2.750184190077768e-01}}, + Descriptor{3, 1.639279770445363e-02, {+4.938630638969568e-01}}, + Descriptor{4, 2.347178069870322e-02, {+2.362540169543293e-01, +8.712387576289576e-01}}, + Descriptor{4, 5.761848158278895e-03, {+7.223833941638236e-02, +9.551937402361604e-01}}, + Descriptor{4, 3.492479305778020e-02, {+4.383137607101617e-01, +4.364117817130079e-01}}, + Descriptor{4, 7.373899623212321e-03, {+3.643401649407788e-02, +5.030056360566418e-01}}, + Descriptor{4, 5.722460846448911e-03, {+4.828779929693860e-01, -9.817457230015865e-01}}, + Descriptor{4, 2.433874301444529e-02, {+1.628698857202373e-01, -1.748668736196710e-01}}, + Descriptor{5, 9.412963663135166e-03, {+8.213377527237301e-01, +1.626087609745086e-01}}, + Descriptor{6, 1.801797749439730e-02, {+4.249444950639278e-02, +2.561926710584905e-01, +6.836158559766136e-01}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 10: { + constexpr size_t nb_points = 84; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{1, 3.219608823836797e-02, {}}, + Descriptor{2, 1.323959532338741e-02, {+9.650866816169476e-01}}, + Descriptor{3, 1.663071726413940e-02, {+4.300104731739727e-01}}, + Descriptor{3, 2.237117375679376e-02, {+1.095696683547513e-01}}, + Descriptor{3, 2.965144268028371e-03, {+1.581483663138682e-02}}, + Descriptor{4, 2.041220712674361e-02, {+4.356018236697312e-01, +7.829035904287732e-01}}, + Descriptor{4, 1.414434969765846e-02, {+1.485976165307029e-01, +7.673257532061416e-01}}, + Descriptor{4, 3.545708824271026e-03, {+5.196648358223575e-02, +4.892913949246038e-01}}, + Descriptor{4, 6.058080482992846e-03, {+4.990219694442680e-01, +6.916716292769725e-01}}, + Descriptor{4, 3.555888039958573e-03, {+4.155250160277021e-02, +8.910010843120678e-01}}, + Descriptor{4, 3.038102466521747e-02, {+2.343945196820784e-01, +4.651342767282841e-01}}, + Descriptor{6, 6.211856757092111e-03, {+5.281151684656214e-02, +2.716521744885937e-01, +9.566215690575565e-01}}, + Descriptor{6, 6.618419166146100e-03, {+1.675738337212976e-01, +1.019125209869291e-02, +5.391797458851759e-01}}, + Descriptor{6, 1.607306259567184e-02, {+3.291869417398026e-01, +5.090816276695182e-02, -2.642847151350913e-01}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 11: { + constexpr size_t nb_points = 99; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{2, 2.168014406730469e-02, {-5.549549808499665e-01}}, + Descriptor{2, 1.045760798587228e-02, {+9.704322100480244e-01}}, + Descriptor{2, 3.493462507713402e-03, {-8.225054517645587e-02}}, + Descriptor{3, 1.610610418171415e-02, {+4.269221881685347e-01}}, + Descriptor{4, 2.203310285466430e-02, {+4.396327659106838e-01, +6.759979260851990e-01}}, + Descriptor{4, 1.274418696180960e-02, {+2.009128761138035e-01, +8.360535436001461e-01}}, + Descriptor{4, 2.842526101831001e-03, {+2.158509804317693e-02, +5.861905524880673e-01}}, + Descriptor{4, 1.509857722810566e-03, {+4.941546402080231e-01, +9.747001655491775e-01}}, + Descriptor{4, 3.650427064786428e-03, {+5.996027726544360e-02, +9.450272677498353e-01}}, + Descriptor{4, 2.100290671698337e-02, {+2.328102236807494e-01, +2.635224843921006e-01}}, + Descriptor{4, 1.876195853667291e-02, {+1.213201391549184e-01, +4.439791020520624e-01}}, + Descriptor{4, 5.194819129164601e-03, {+4.987543911906001e-01, +5.750153420806698e-01}}, + Descriptor{5, 7.050587938770526e-03, {+1.046140524481813e-01, +1.651849633425114e-02}}, + Descriptor{6, 5.901269948294771e-03, {+7.196325697558484e-02, +2.979854667459965e-01, +9.371332380619902e-01}}, + Descriptor{6, 6.212665465530579e-03, {+1.998026706474004e-01, +1.720948255102629e-02, +7.302645437140292e-01}}, + Descriptor{6, 1.385914960018441e-02, {+3.197359768880742e-01, +4.628523865251271e-02, -2.345966255449601e-01}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 12: { + constexpr size_t nb_points = 136; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{2, 1.122540095264984e-02, {+9.249605281775015e-01}}, + Descriptor{2, 2.250978701634355e-02, {+3.174565048121913e-01}}, + Descriptor{3, 5.489424083937044e-03, {+4.853372007888398e-02}}, + Descriptor{3, 4.964406537953573e-04, {+3.340541016130764e-04}}, + Descriptor{4, 1.020904001099484e-02, {+4.849074297077183e-01, +5.587032406470354e-01}}, + Descriptor{4, 2.100649550809441e-03, {+1.497566246841529e-01, -9.990255354639939e-01}}, + Descriptor{4, 1.520942066705075e-02, {+2.344536517846724e-01, +3.308248202440709e-01}}, + Descriptor{4, 1.365828920018060e-02, {+4.409030162469282e-01, -7.263193646044468e-02}}, + Descriptor{4, 2.788739322048965e-03, {+4.870412467653055e-01, +9.373420953931805e-01}}, + Descriptor{4, 2.252095085593022e-03, {+2.486381930021292e-02, +6.814367870790086e-01}}, + Descriptor{4, 9.917448258967848e-03, {+1.118542147928236e-01, +7.546508799087877e-01}}, + Descriptor{5, 9.524594103832613e-03, {+1.207867185816364e-01, +7.097236881695401e-01}}, + Descriptor{5, 6.688135429090100e-03, {+6.481099336610571e-01, +3.419306029008594e-01}}, + Descriptor{6, 5.667322471331417e-03, {+2.009036502771764e-02, +1.335404714654308e-01, +3.889378443355619e-01}}, + Descriptor{6, 1.258664545850983e-02, {+3.214917379706315e-01, +1.648190492804087e-01, +7.118012620024268e-01}}, + Descriptor{6, 1.143701180003211e-02, {+6.899565054914573e-02, +6.636404691861656e-01, -4.223089212637487e-01}}, + Descriptor{6, 4.495597556144068e-03, {+1.996263664334138e-02, +2.615529990296567e-01, +8.442893497066150e-01}}, + Descriptor{6, 1.189774020910150e-03, {+9.002977238916547e-02, +1.552185633457250e-02, +9.525314828501794e-01}}, + Descriptor{6, 4.663778699523011e-03, {+1.172214513692467e-01, +5.641016399337317e-01, -9.443120180277191e-01}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 13: { + constexpr size_t nb_points = 162; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{4, 2.629059706793623e-03, {+4.898439392870481e-01, +9.257498273505042e-01}}, + Descriptor{4, 5.973423749312596e-03, {+4.652402431593082e-01, -6.807809122309588e-01}}, + Descriptor{4, 8.093549424155690e-03, {+1.189161740974999e-01, +8.113054084779335e-01}}, + Descriptor{4, 6.819116259035672e-03, {+4.065656818638698e-01, +1.925054913726048e-02}}, + Descriptor{4, 4.933451368773049e-03, {+3.731243598486834e-01, +9.244211981221383e-01}}, + Descriptor{4, 2.014708013288427e-03, {+2.222577118367550e-02, +2.903696330212439e-01}}, + Descriptor{4, 1.233577073707530e-02, {+4.252710267490136e-01, +6.716647847389562e-01}}, + Descriptor{4, 1.136479433767108e-02, {+2.896929731593648e-01, +3.940165471189255e-01}}, + Descriptor{4, 6.666864960682452e-03, {+1.072868932263340e-01, +1.612419567102727e-01}}, + Descriptor{4, 1.194522013639762e-02, {+2.080125480772502e-01, +2.621034383425459e-01}}, + Descriptor{4, 1.068788094061122e-02, {+2.230030950549982e-01, +7.517293034088793e-01}}, + Descriptor{4, 1.666344327463221e-03, {+2.617439160849268e-02, +8.530545934139608e-01}}, + Descriptor{5, 4.512051617065152e-03, {+6.914170159250816e-03, +2.742659465495736e-01}}, + Descriptor{5, 3.488706839443290e-03, {+1.210652398684976e-01, +2.342377584496339e-02}}, + Descriptor{5, 1.118035069441576e-02, {+9.353601775463583e-02, +5.415308571572887e-01}}, + Descriptor{6, 4.205260232450528e-03, {+1.908095378196189e-02, +4.425451813256520e-01, +3.662111224258147e-01}}, + Descriptor{6, 4.376791749742736e-03, {+2.923396969545124e-01, +1.817765226028588e-02, +7.893982266689565e-01}}, + Descriptor{6, 4.406755041936957e-03, {+2.123093816715971e-02, +8.615902483468726e-01, +5.566323460176222e-01}}, + Descriptor{6, 1.203503267726805e-02, {+2.541452627735283e-01, +7.525507194012332e-02, -4.323213872909485e-01}}, + Descriptor{6, 1.398692188464922e-03, {+1.414034499801619e-01, +2.485309321657718e-02, +9.754978010051167e-01}}, + Descriptor{6, 4.755154887378063e-03, {+5.920519581168684e-01, +1.079442302776815e-01, +9.602045342477669e-01}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 14: { + constexpr size_t nb_points = 194; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{2, 1.177233712035789e-02, {-5.431508197665302e-01}}, + Descriptor{3, 1.353619130586776e-02, {+1.531409494078462e-01}}, + Descriptor{3, 2.863624459018961e-03, {+1.094642266754876e-01}}, + Descriptor{4, 2.831710195314422e-03, {+4.852139749601931e-01, +9.499413855584002e-01}}, + Descriptor{4, 4.354649559352045e-03, {+4.811857851081537e-01, -3.416804188824072e-01}}, + Descriptor{4, 9.145278212110571e-04, {+8.542525491697950e-02, +9.993425247803482e-01}}, + Descriptor{4, 1.640665865351787e-03, {+4.949498254464672e-01, +4.043764192878801e-01}}, + Descriptor{4, 1.217329578934041e-02, {+2.006722689888837e-01, +6.704323691216523e-01}}, + Descriptor{4, 1.062128023171532e-03, {+1.346314023891985e-02, +4.402219142928553e-01}}, + Descriptor{4, 8.146219031353574e-03, {+3.888073656098609e-01, +8.664942125245655e-01}}, + Descriptor{4, 1.188198250865211e-02, {+2.589597694248802e-01, -3.805332165701859e-01}}, + Descriptor{4, 4.510606073543659e-03, {+6.566746391585167e-02, +3.180500426640964e-01}}, + Descriptor{4, 1.201058503487853e-02, {+4.462504387663027e-01, +6.737378781532631e-01}}, + Descriptor{4, 4.766438302156675e-03, {+1.155506883468244e-01, +8.527706525272908e-01}}, + Descriptor{4, 9.777024948606015e-04, {+2.579397983791752e-02, +9.172594869558284e-01}}, + Descriptor{5, 5.111880702605887e-03, {+2.313133650799548e-02, +3.737411598567404e-01}}, + Descriptor{5, 2.171762107022176e-03, {+7.808376567245785e-02, +8.716783743732383e-03}}, + Descriptor{5, 1.040227457387526e-02, {+1.932090397525293e-01, +4.408189862889988e-01}}, + Descriptor{6, 3.590362689299532e-03, {+1.106956102435793e-02, +3.495104935335414e-01, +6.888113400872247e-01}}, + Descriptor{6, 5.210848278113965e-03, {+2.813786819004687e-01, +7.252407174904094e-02, +8.818281117320524e-01}}, + Descriptor{6, 2.902421092721445e-03, {+1.360674597305564e-02, +7.694543610610796e-01, +2.082229797704095e-01}}, + Descriptor{6, 1.093709739870311e-02, {+3.160642637515643e-01, +9.806129213500263e-02, -2.960531739682007e-01}}, + Descriptor{6, 1.070623154200375e-03, {+2.010219519914552e-01, +1.015338057469439e-02, +9.567691001326991e-01}}, + Descriptor{6, 2.366054231962321e-03, {+5.404862370418329e-01, +1.675040220811526e-01, +9.843823434581401e-01}}, + Descriptor{6, 2.619672090010859e-03, {+1.016331118955575e-01, +1.682509189588544e-02, +7.176031930976530e-01}}, + Descriptor{6, 7.096030229028862e-03, {+7.553391402298588e-01, +5.528506804337090e-02, -4.978572721822902e-01}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 15: { + constexpr size_t nb_points = 238; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{2, 1.097348853586182e-02, {+6.802218229609156e-01}}, + Descriptor{2, 3.261395830734888e-03, {+9.049666192679098e-01}}, + Descriptor{3, 9.394140546438022e-03, {+2.180179116942069e-01}}, + Descriptor{3, 7.472192538440717e-03, {+1.819996803717089e-01}}, + Descriptor{3, 1.125148661004542e-03, {+1.740140116312610e-02}}, + Descriptor{3, 4.027894259445648e-03, {+5.427115018599665e-02}}, + Descriptor{4, 4.698740527412616e-03, {+3.702896314191779e-01, +1.017726699824298e-01}}, + Descriptor{4, 4.423106873185891e-03, {+6.837923242190364e-02, +7.328812049735380e-01}}, + Descriptor{4, 1.190871191679164e-02, {+4.041029865296590e-01, -3.417820508269636e-01}}, + Descriptor{4, 3.419058355265174e-03, {+4.924009437532922e-01, -1.425907114174295e-01}}, + Descriptor{4, 7.607869583069166e-03, {+4.679592294726652e-01, +6.612792268372575e-01}}, + Descriptor{4, 3.487721814344312e-03, {+2.538613877625208e-01, +9.653983029752667e-01}}, + Descriptor{4, 4.126571123768199e-03, {+1.490233678882002e-01, +9.207186791179688e-01}}, + Descriptor{4, 2.055229043939243e-03, {+4.943016520035221e-01, +8.528797591642616e-01}}, + Descriptor{5, 5.333436981117544e-03, {+2.380227290434666e-01, +1.919120975700847e-02}}, + Descriptor{6, 4.565836294062908e-03, {+2.658819381343187e-01, +9.470242762478344e-02, +8.051851008291565e-01}}, + Descriptor{6, 5.459132755230557e-04, {+2.824880313716481e-02, +6.797646253429619e-03, +5.550126100536413e-01}}, + Descriptor{6, 4.319194829106329e-03, {+6.410939576871652e-01, +1.511219453234863e-02, +4.965601017444452e-01}}, + Descriptor{6, 5.377414350253174e-03, {+1.570345607673937e-01, +7.920488512684705e-02, +2.807402393928705e-01}}, + Descriptor{6, 7.161694599840893e-03, {+2.618681572601245e-01, +1.978262294209248e-01, +5.539260799071125e-01}}, + Descriptor{6, 5.425741614460213e-04, {+6.532458874680514e-03, +4.868056225266830e-02, +9.130997730502041e-01}}, + Descriptor{6, 1.437669184909563e-03, {+3.702624031957258e-01, +9.129771330289427e-02, +9.857586619210927e-01}}, + Descriptor{6, 1.116039038725027e-03, {+1.377079768509805e-01, +3.730083695338125e-02, +9.761262490766817e-01}}, + Descriptor{6, 4.855981285749960e-03, {+4.784950101267365e-01, +1.635654688089934e-01, +8.308622970412985e-01}}, + Descriptor{6, 1.797153116855535e-03, {+3.278240979071815e-01, +2.496158166292168e-02, +9.410500001533124e-01}}, + Descriptor{6, 9.605058598669360e-03, {+3.475735063324100e-01, +8.713022883913982e-02, -2.293965609348112e-01}}, + Descriptor{6, 2.702127731284175e-03, {+1.096327891311607e-01, +1.283956773909193e-02, +3.801848607953903e-01}}, + Descriptor{6, 5.504446034785920e-03, {+2.078784801536998e-01, +8.490456755292054e-02, +5.633005891537184e-01}}, + Descriptor{6, 2.394682993576167e-03, {+1.953330193360589e-01, +1.430457871757475e-02, +7.767703733759026e-01}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 16: { + constexpr size_t nb_points = 287; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{2, 1.260828009387497e-02, {+6.806235853917343e-01}}, + Descriptor{3, 5.804416586274102e-04, {+8.954084031214650e-03}}, + Descriptor{3, 1.451527527703537e-03, {+5.539081004402164e-02}}, + Descriptor{3, 1.103925194575912e-02, {+3.916317627335951e-01}}, + Descriptor{4, 2.389660788445647e-03, {+5.610007788583466e-02, +7.685450672389825e-01}}, + Descriptor{4, 1.118529592275642e-02, {+2.669967593271997e-01, +3.187166719009041e-01}}, + Descriptor{4, 4.452710626148950e-03, {+1.619375672046858e-01, +7.425213340738127e-01}}, + Descriptor{4, 9.931042920523256e-03, {+4.259891438745869e-01, -5.391540839796620e-01}}, + Descriptor{4, 2.798331509865767e-03, {+4.943682456985981e-01, +2.910077027212657e-01}}, + Descriptor{4, 4.595079144000768e-03, {+4.745817664118026e-01, +7.702843820193086e-01}}, + Descriptor{4, 2.649741982735800e-03, {+2.785739189962955e-01, +9.637659513314421e-01}}, + Descriptor{4, 2.379174945004374e-03, {+1.564426776295505e-01, +9.700236378009609e-01}}, + Descriptor{4, 1.290211537994051e-03, {+4.933597406415689e-01, +9.402630634429575e-01}}, + Descriptor{5, 7.174970445767767e-03, {+5.254267651000835e-01, +9.931494549031464e-02}}, + Descriptor{5, 3.904196912906489e-03, {+3.482743570815052e-01, +2.127155614722863e-02}}, + Descriptor{5, 5.896847921349438e-03, {+1.654756461617898e-01, +8.608509799836524e-02}}, + Descriptor{6, 2.434940232310643e-03, {+1.639763763638563e-01, +5.517222908705197e-02, +8.775190479419079e-01}}, + Descriptor{6, 7.867926281754163e-04, {+3.703825228193449e-02, +1.050366659141256e-02, +5.241361844419883e-01}}, + Descriptor{6, 1.973345895093291e-03, {+6.350080118967869e-01, +5.563959422105249e-03, +6.546900713490693e-01}}, + Descriptor{6, 3.902804476486658e-03, {+1.297894012222233e-01, +7.248681972075718e-02, +4.803772456633624e-01}}, + Descriptor{6, 2.865194848993297e-03, {+3.059321030072774e-01, +6.212018826128094e-02, +8.420714610259229e-01}}, + Descriptor{6, 4.265862973729131e-03, {+1.677554820715698e-01, +2.612303617350463e-01, +6.466653853149219e-01}}, + Descriptor{6, 2.763846307136280e-04, {+1.529621929633006e-03, +3.376869229909243e-02, +8.957708274465785e-01}}, + Descriptor{6, 1.594720494514084e-03, {+3.532796606132861e-01, +9.492422215886979e-02, +9.832783024215900e-01}}, + Descriptor{6, 5.967018601525356e-04, {+9.592623259204197e-02, +2.488171702893576e-02, +9.797358781454657e-01}}, + Descriptor{6, 5.089010857368133e-03, {+4.963305263335406e-01, +1.757029526928022e-01, +8.611424584617942e-01}}, + Descriptor{6, 1.023252728565292e-03, {+2.738501035919119e-01, +1.407861220922605e-02, +9.516023826285763e-01}}, + Descriptor{6, 4.833611837936114e-03, {+3.828844998895772e-01, +5.651716232003427e-02, -3.926210681927463e-01}}, + Descriptor{6, 2.256570449498587e-03, {+8.993653239530038e-02, +1.924125702016291e-02, +2.277368351329287e-01}}, + Descriptor{6, 4.394217441895532e-03, {+2.516074150213084e-01, +6.113701845424014e-02, +5.771276473820092e-01}}, + Descriptor{6, 1.441280420852857e-03, {+1.524244609819593e-01, +5.018269956194812e-03, +7.029237083896506e-01}}, + Descriptor{6, 7.638903866482450e-03, {+2.475011786624472e-01, +1.365910574355268e-01, -2.555004528315441e-01}}, + Descriptor{6, 3.266920063147978e-03, {+7.591852986956938e-01, +1.735437181095786e-02, +2.659716737332686e-01}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 17: { + constexpr size_t nb_points = 338; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{2, 7.521652592973654e-03, {+7.332980977058475e-01}}, + Descriptor{4, 3.952340142081542e-03, {+4.665556153120432e-01, +7.407048594232563e-01}}, + Descriptor{4, 2.658797102389008e-03, {+4.923809674098066e-01, +1.925784688493710e-01}}, + Descriptor{4, 2.303261680132425e-03, {+4.466963397682847e-01, +9.724914617208265e-01}}, + Descriptor{4, 4.300609620564292e-03, {+2.058899494758731e-01, +2.386810048778012e-01}}, + Descriptor{4, 3.022106015301819e-03, {+2.305779360323416e-01, +3.012229853956593e-01}}, + Descriptor{4, 3.076949950084475e-04, {+7.072650234259644e-03, +6.517254037629554e-01}}, + Descriptor{4, 3.073440319150984e-03, {+5.248385455049231e-02, -5.044383522897413e-01}}, + Descriptor{4, 4.905529550079285e-03, {+2.780743897936196e-01, -4.157283981367805e-01}}, + Descriptor{4, 2.706669648409243e-03, {+3.893995813144771e-01, -8.036253483433273e-01}}, + Descriptor{4, 3.457774927613496e-03, {+1.132999955833483e-01, +4.250397278118490e-01}}, + Descriptor{4, 5.170517454197127e-03, {+4.687774749283292e-01, -2.967208107336694e-01}}, + Descriptor{4, 1.402258311530629e-03, {+4.942337889964747e-01, +8.919484290177192e-01}}, + Descriptor{4, 4.240102604381064e-03, {+2.906999098818323e-01, +1.317224598994015e-01}}, + Descriptor{4, 3.284148741170156e-03, {+9.376930399184973e-02, +8.547449509711846e-01}}, + Descriptor{4, 1.134225985312425e-03, {+1.632812980104028e-01, +9.979247130558654e-01}}, + Descriptor{4, 7.470854816360809e-03, {+1.774626418569745e-01, -6.791385858496140e-01}}, + Descriptor{4, 3.434038461352071e-03, {+3.930786561208929e-01, +2.690582708305222e-01}}, + Descriptor{4, 3.146260969412623e-03, {+2.711153947647855e-01, +9.623986887607461e-01}}, + Descriptor{4, 5.752613942102343e-04, {+2.430622100156484e-02, +9.425587161003264e-01}}, + Descriptor{5, 6.555279553032400e-03, {+1.273859447314594e-01, +2.765687474993688e-01}}, + Descriptor{6, 2.945409561987205e-03, {+2.450510833431427e-01, +8.524685018280553e-02, +9.106045966534763e-01}}, + Descriptor{6, 2.453063041563170e-03, {+3.192911229101512e-01, +2.764498521125525e-02, +5.755372475087557e-02}}, + Descriptor{6, 2.870396640498966e-03, {+4.577741357714497e-01, +1.385428807092584e-01, -9.235677741171985e-02}}, + Descriptor{6, 1.826827790065983e-03, {+2.421105196372634e-01, +1.245683910267135e-02, -2.750816491221573e-01}}, + Descriptor{6, 4.684287720797846e-03, {+7.269945541994681e-01, +8.880930240992388e-02, +2.353034707366664e-01}}, + Descriptor{6, 6.198783236777368e-03, {+4.870517086755036e-01, +1.725779658472295e-01, -5.739332375158235e-01}}, + Descriptor{6, 4.197863049050683e-03, {+1.582123188291182e-01, +3.108975273704328e-01, +8.562321460031186e-01}}, + Descriptor{6, 2.552814201463011e-03, {+5.973833093262283e-01, +4.329678563553625e-02, +7.520938435967152e-01}}, + Descriptor{6, 2.090115170917154e-03, {+1.111929938785087e-01, +3.682608320557917e-02, +2.115412627288322e-02}}, + Descriptor{6, 7.568671403396213e-04, {+3.878650062905668e-02, +7.045410253068108e-03, +2.249484087437713e-01}}, + Descriptor{6, 1.300065728839461e-03, {+1.417441449927015e-01, +6.656135005864013e-03, +3.824194976983090e-01}}, + Descriptor{6, 8.479873802967710e-04, {+1.343472140817544e-01, +2.698141838221961e-02, +9.741848074979857e-01}}, + Descriptor{6, 6.404613040101877e-03, {+3.195031824862086e-01, +8.134405613722046e-02, +4.381759877407309e-01}}, + Descriptor{6, 1.132352094196614e-03, {+8.263084385883397e-02, +1.026354650397643e-02, +7.684631026560178e-01}}, + Descriptor{6, 2.064410253144382e-03, {+3.827807429336583e-01, +6.749013415056980e-03, +5.465728592769658e-01}}, + Descriptor{6, 1.048193458332381e-03, {+2.446543644502634e-01, +5.650199208693200e-03, +8.553667006980621e-01}}, + Descriptor{6, 9.390285812952761e-04, {+2.637071367985937e-02, +6.264598409479015e-01, +9.755523282064171e-01}}, + Descriptor{6, 4.216060332324916e-03, {+4.340745420159236e-02, +1.947680793017931e-01, +6.465743617002622e-01}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 18: { + constexpr size_t nb_points = 396; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{4, 2.257692848096014e-03, {+4.728631477307805e-01, +9.068774432765224e-01}}, + Descriptor{4, 3.522000993611865e-03, {+1.090318158369727e-01, +5.191310054808369e-01}}, + Descriptor{4, 4.461723497786998e-03, {+2.141954002982068e-01, +6.975267033041567e-01}}, + Descriptor{4, 3.707999359392404e-04, {+8.415088753342596e-03, +4.704963597796460e-01}}, + Descriptor{4, 2.423661142721756e-03, {+4.941564402940962e-02, -3.771046294090744e-01}}, + Descriptor{4, 2.814996700016239e-03, {+4.574258170355346e-01, -2.709290831593626e-01}}, + Descriptor{4, 5.337642166957648e-03, {+2.945570490820424e-01, -1.757797989950063e-01}}, + Descriptor{4, 8.574266664464696e-03, {+4.148583469418042e-01, -2.903119874076979e-01}}, + Descriptor{4, 2.265725871486650e-03, {+1.801567120271234e-01, -2.996313713953939e-01}}, + Descriptor{4, 2.955157959707394e-03, {+4.092592655375933e-01, -8.687914069087144e-01}}, + Descriptor{4, 3.919466496845992e-03, {+4.106876572727113e-01, -7.102916194693503e-01}}, + Descriptor{4, 6.030674708196229e-04, {+4.942616172602019e-01, +9.613370670800333e-01}}, + Descriptor{4, 4.577980994542588e-03, {+1.455821883151533e-01, +2.580797174139677e-01}}, + Descriptor{4, 2.430663642304682e-03, {+7.759286964629900e-02, +8.574527537341975e-01}}, + Descriptor{4, 2.159969925839523e-03, {+1.688466480848478e-01, +9.442832226314590e-01}}, + Descriptor{4, 7.901051089233524e-03, {+2.737821968608845e-01, -5.261705496722796e-01}}, + Descriptor{4, 2.173845391531516e-03, {+3.193703110432156e-01, +7.838756187326278e-01}}, + Descriptor{4, 2.248646315174777e-03, {+2.789278090499041e-01, +9.684120338438452e-01}}, + Descriptor{4, 3.442548195872391e-04, {+1.473433086781356e-02, +9.055493494371784e-01}}, + Descriptor{5, 8.069935581612784e-03, {+2.803931989784251e-01, +1.730708483947652e-01}}, + Descriptor{6, 2.387723163590078e-03, {+3.067402740370590e-01, +4.725833161993727e-02, +8.686462758628247e-01}}, + Descriptor{6, 3.430528221040949e-03, {+5.587472044782793e-01, +6.374864935475613e-02, +1.027445357789138e-01}}, + Descriptor{6, 6.029545367216524e-03, {+1.295467219204834e-01, +2.834002542935580e-01, -4.512744270430775e-01}}, + Descriptor{6, 3.276823879158102e-03, {+2.943165499688927e-01, +3.236061609245209e-02, -4.364849670272578e-01}}, + Descriptor{6, 3.663549210540714e-03, {+7.045618883179275e-01, +6.827271159006545e-02, +1.782321853488997e-01}}, + Descriptor{6, 4.424488262807732e-03, {+5.336092397180819e-01, +8.232278479338200e-02, -6.571528038169470e-01}}, + Descriptor{6, 2.760063523214631e-03, {+1.659343236267790e-01, +2.958566157742775e-01, +8.788603720074640e-01}}, + Descriptor{6, 1.392109889443924e-03, {+5.873912217089957e-01, +9.153855225433397e-03, +7.488835368067833e-01}}, + Descriptor{6, 2.138435872642536e-03, {+1.216404492275597e-01, +4.924556835776799e-02, -8.479900295560096e-02}}, + Descriptor{6, 5.166067073488927e-04, {+4.208095332260363e-02, +7.753734519664009e-03, +9.396055358943239e-02}}, + Descriptor{6, 1.953953141133318e-03, {+4.516351625773616e-01, +2.282191697171249e-02, +4.454084028264259e-01}}, + Descriptor{6, 1.255008598363820e-03, {+1.252580641579170e-01, +7.396327404727600e-03, +3.172925739593950e-01}}, + Descriptor{6, 1.042334114181810e-03, {+1.765722195894258e-01, +6.530021157253776e-02, +9.730112939053892e-01}}, + Descriptor{6, 1.279342041886178e-03, {+2.404267015692479e-01, +8.587901550681881e-03, +1.654571949278815e-01}}, + Descriptor{6, 1.087772234137440e-03, {+6.440585522631566e-02, +1.226780343665597e-02, +7.058192837170146e-01}}, + Descriptor{6, 8.506443220554228e-04, {+2.681069831840066e-01, +4.479326561367245e-03, +6.566582555690533e-01}}, + Descriptor{6, 1.071738436276040e-03, {+1.727205252244992e-01, +1.173345352446697e-02, +8.740347679939118e-01}}, + Descriptor{6, 1.222389838372311e-03, {+1.118329953359960e-01, +5.446775610503505e-01, +9.879516615930261e-01}}, + Descriptor{6, 1.426482164900413e-03, {+5.899536365475773e-01, +8.017587417702520e-03, +1.572003893989445e-01}}, + Descriptor{6, 3.834177899773436e-03, {+9.615405978617643e-02, +2.067498834662211e-01, +7.510430318557424e-01}}, + Descriptor{6, 4.758021594541443e-04, {+3.068968355307726e-01, +1.177465532391100e-02, +9.786522981024399e-01}}, + Descriptor{6, 3.711298716255058e-04, {+7.984864478527595e-02, +1.740633561957181e-02, +9.787643170060012e-01}}, + Descriptor{6, 2.736409660029034e-03, {+3.607777906277682e-02, +1.618562004775664e-01, +5.932565552690645e-01}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 19: { + constexpr size_t nb_points = 420; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{2, 6.766510972429800e-03, {+5.244830821459505e-01}}, + Descriptor{2, 2.666997686915707e-03, {+7.453333881549420e-02}}, + Descriptor{2, 2.198296683612197e-03, {+9.566097292149883e-01}}, + Descriptor{3, 1.803557661024045e-03, {+4.935398626809867e-01}}, + Descriptor{3, 6.354430508374619e-03, {+2.767659367008514e-01}}, + Descriptor{3, 1.636834721720784e-03, {+5.457779485028427e-02}}, + Descriptor{3, 4.893654007837226e-04, {+1.399697352188861e-02}}, + Descriptor{4, 1.846418513040312e-03, {+1.418740786751734e-01, +9.552594993861951e-01}}, + Descriptor{4, 2.773402798745861e-04, {+8.395599010104145e-03, +6.731987542402844e-01}}, + Descriptor{4, 2.823634437215422e-03, {+1.035973359771996e-01, -2.005717856238193e-01}}, + Descriptor{4, 7.726075998933063e-03, {+3.956080996828434e-01, +3.080298478277679e-01}}, + Descriptor{4, 2.193983773241012e-04, {+1.400193119774357e-02, +2.354401887617481e-01}}, + Descriptor{4, 4.366650366888420e-03, {+4.801897764603656e-01, +4.828040748109914e-01}}, + Descriptor{4, 4.029293922819735e-03, {+1.623484102426076e-01, -2.002124012363609e-01}}, + Descriptor{4, 1.130768692395794e-03, {+4.972236736522475e-01, +7.211608708255114e-01}}, + Descriptor{4, 4.287863606686208e-03, {+1.990216655966096e-01, +7.769851170153003e-01}}, + Descriptor{4, 1.592256072404633e-03, {+1.202889101503504e-01, -6.997989522584932e-01}}, + Descriptor{4, 2.052668995583038e-03, {+5.321915260988313e-02, +6.322324604037224e-01}}, + Descriptor{4, 3.894795325529755e-03, {+4.012796612843944e-01, +8.985968033126313e-01}}, + Descriptor{4, 1.803402089659100e-03, {+1.089883669604236e-01, +6.414118273921905e-01}}, + Descriptor{4, 4.906673814096024e-03, {+4.472748897677901e-01, +1.418065900083249e-01}}, + Descriptor{4, 8.385245625735418e-04, {+6.923354485715784e-02, +9.592516295656434e-01}}, + Descriptor{4, 1.344422701677694e-03, {+2.475145234973103e-01, +9.911400740550351e-01}}, + Descriptor{4, 1.212351202429953e-03, {+4.533377451558121e-01, +9.881823361248698e-01}}, + Descriptor{4, 2.704967330298844e-04, {+1.808374112681072e-02, +9.537067614804079e-01}}, + Descriptor{5, 1.194495738162939e-03, {+1.297897131077726e-01, +6.917496569505294e-03}}, + Descriptor{5, 3.103142225008695e-03, {+3.779418721990778e-01, +3.100617423599103e-02}}, + Descriptor{5, 5.131660654552337e-03, {+6.446313119552312e-02, +2.203251202566757e-01}}, + Descriptor{6, 4.803074338815450e-03, {+1.625899734623090e-01, +2.824754920851798e-01, +1.568351483023571e-01}}, + Descriptor{6, 8.150376242849885e-04, {+8.118414809439785e-03, +5.478835112834492e-02, -3.967511256013889e-01}}, + Descriptor{6, 4.498489872233412e-03, {+6.582273496659641e-01, +1.178005364736766e-01, -4.885151647510187e-01}}, + Descriptor{6, 2.731777351387361e-03, {+2.876874815978630e-01, +3.552685414544682e-02, +5.867894747260645e-01}}, + Descriptor{6, 3.917995492165165e-03, {+2.839484400308330e-01, +2.073917255967352e-01, +4.831782153742011e-01}}, + Descriptor{6, 8.946420147168489e-04, {+2.824570038349533e-02, +8.622300269568527e-02, -2.019344195912693e-01}}, + Descriptor{6, 1.272619581981183e-03, {+3.915043117238656e-01, +5.619651603686126e-03, +3.317594047785773e-01}}, + Descriptor{6, 4.539117516816274e-03, {+7.376676137243446e-02, +3.389265718024346e-01, -3.045944670757652e-01}}, + Descriptor{6, 1.228077139941574e-03, {+1.582419524500696e-01, +8.020518897879757e-03, +6.242276968562098e-01}}, + Descriptor{6, 2.481352686408294e-03, {+2.270465393157224e-01, +7.611830639869993e-02, +7.779863298475371e-01}}, + Descriptor{6, 6.742435916065792e-04, {+1.074023202728770e-02, +6.748601969235382e-02, +8.305354371679037e-01}}, + Descriptor{6, 3.085688768414200e-03, {+4.506297544312898e-02, +1.495289831435912e-01, +3.936943128499052e-01}}, + Descriptor{6, 2.827744882828859e-03, {+3.899263834124326e-01, +5.365999012062311e-02, +8.362140373651296e-01}}, + Descriptor{6, 7.880156766981593e-04, {+1.426168210785968e-02, +4.039638109964547e-01, +9.545849701585185e-01}}, + Descriptor{6, 9.734356783437631e-04, {+3.314062155351160e-01, +8.833083116611448e-03, +7.096795149078843e-01}}, + Descriptor{6, 2.344473397349397e-04, {+1.223644156202090e-01, +1.039237935936368e-02, +9.900280695189960e-01}}, + Descriptor{6, 2.754928134962740e-03, {+2.929652829983945e-01, +1.324448044285512e-01, +9.178743530773790e-01}}, + Descriptor{6, 8.530955496579550e-04, {+2.534748953911949e-01, +5.351470915991541e-02, +9.845698380380822e-01}}, + Descriptor{6, 1.720791066604888e-03, {+4.407858720850005e-02, +1.461188761758480e-01, +8.569909006217998e-01}}, + Descriptor{6, 5.238060160822010e-03, {+5.031457633505478e-01, +1.264604222462178e-01, +6.487185269932558e-01}}, + Descriptor{6, 7.780035531900878e-04, {+8.749997984117155e-03, +2.433623618774898e-01, +9.028600070589583e-01}}, + Descriptor{6, 2.799719934133974e-03, {+4.433279475253553e-01, +2.569581578007861e-01, +7.536500284803950e-01}}, + Descriptor{6, 1.887126925839933e-03, {+2.485412372956145e-01, +1.127715403373798e-02, +2.418109616381699e-01}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 20: { + constexpr size_t nb_points = 518; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{2, 4.747044232976959e-03, {+8.420166009462728e-01}}, + Descriptor{3, 6.640322548036050e-04, {+1.441108736989831e-02}}, + Descriptor{3, 9.620914054915759e-04, {+5.949741342252451e-02}}, + Descriptor{4, 2.742173179580797e-03, {+4.716249531173324e-01, +8.152882860873994e-01}}, + Descriptor{4, 2.814324102526247e-03, {+4.084460043805324e-01, +5.308959921730525e-01}}, + Descriptor{4, 3.864759174126348e-03, {+2.544280410411358e-01, +7.145164808360277e-01}}, + Descriptor{4, 3.774538054936480e-03, {+4.774877095488475e-01, +3.302023087843083e-01}}, + Descriptor{4, 2.695893315348362e-04, {+8.029263668218678e-03, +5.253966144526213e-01}}, + Descriptor{4, 1.117541442536487e-03, {+4.968613511179721e-01, +1.678823330502635e-01}}, + Descriptor{4, 1.168183967320753e-03, {+4.952615769053836e-01, +7.059801252317832e-01}}, + Descriptor{4, 9.039109611475474e-04, {+3.535780971713121e-02, +3.380124871900346e-01}}, + Descriptor{4, 3.369833201547859e-03, {+2.045970282680664e-01, -9.824414827677468e-02}}, + Descriptor{4, 2.639764171119988e-03, {+1.406131665045265e-01, +6.840978690759630e-01}}, + Descriptor{4, 2.599301978924752e-03, {+9.825610533777711e-02, -2.793583988322257e-01}}, + Descriptor{4, 1.282233014437331e-03, {+5.059516645881403e-02, +5.440523359665514e-01}}, + Descriptor{4, 1.290196339749456e-03, {+4.494558038329708e-01, +9.661789228499832e-01}}, + Descriptor{4, 3.634034328176076e-03, {+2.188296334498393e-01, +5.161030390440184e-01}}, + Descriptor{4, 3.865555241109362e-03, {+3.839280551265914e-01, +6.414153617240698e-01}}, + Descriptor{4, 1.054906754865126e-03, {+5.997065917075951e-02, +8.943918441529238e-01}}, + Descriptor{4, 1.562311721738531e-03, {+2.735494152095392e-01, +9.793184961065893e-01}}, + Descriptor{4, 4.729101647325770e-04, {+4.907393281824849e-01, +9.886251338305795e-01}}, + Descriptor{4, 1.740638131578173e-04, {+1.149301083025444e-02, +9.267723967676791e-01}}, + Descriptor{4, 2.895959965319792e-03, {+4.048678509173179e-01, +9.164077711364235e-01}}, + Descriptor{4, 5.234744278809832e-03, {+2.917111538437177e-01, -3.721772106793935e-01}}, + Descriptor{4, 3.176639444983119e-03, {+4.459340787080981e-01, +3.782961145575000e-02}}, + Descriptor{5, 2.716223123318332e-03, {+2.107382124681030e-01, +3.137124037930802e-02}}, + Descriptor{5, 3.281825797738248e-03, {+2.031438036613264e-01, +1.114400380412596e-01}}, + Descriptor{5, 3.187894698489262e-03, {+3.734168270486775e-01, +3.629012071225871e-02}}, + Descriptor{6, 3.590341132235904e-03, {+5.331515253263366e-01, +1.335223252058013e-01, +7.802503826507077e-01}}, + Descriptor{6, 5.184823629819776e-04, {+3.105220296426577e-03, +6.506617704521390e-02, -2.884770252636346e-01}}, + Descriptor{6, 2.044053800301851e-03, {+7.387825606686489e-01, +9.320636776575365e-02, -2.442855072953742e-01}}, + Descriptor{6, 2.454384702584994e-03, {+2.402209181076414e-01, +3.428169043211691e-02, +4.260690982676672e-01}}, + Descriptor{6, 4.119406732850509e-03, {+8.161298386181808e-02, +3.087274419444517e-01, +2.420309868035705e-01}}, + Descriptor{6, 5.762946980041836e-03, {+1.728159430622389e-01, +3.228866908185781e-01, -2.377845513467044e-01}}, + Descriptor{6, 3.254649507017313e-03, {+2.247127800382396e-01, +1.327427633967232e-01, +4.683664775890787e-01}}, + Descriptor{6, 1.376952861188114e-03, {+2.850103512086270e-02, +1.058138309132070e-01, -1.189934946219634e-01}}, + Descriptor{6, 1.390144266230514e-03, {+3.896100790636586e-01, +1.097122964947396e-02, +4.812562527542947e-01}}, + Descriptor{6, 1.973482620122281e-03, {+2.493335646225524e-01, +3.397868885786173e-01, -3.494229691424887e-02}}, + Descriptor{6, 1.112029053786251e-03, {+7.042023600039281e-03, +3.177207979690921e-01, +2.078247495083118e-01}}, + Descriptor{6, 1.196110133680204e-03, {+1.229469656661441e-01, +1.566757860788512e-02, +6.094751351099792e-01}}, + Descriptor{6, 1.888982141486211e-03, {+2.259160262165568e-01, +5.215188464418734e-02, +8.360830877198899e-01}}, + Descriptor{6, 5.659037184544154e-04, {+9.471493326637022e-03, +4.964414152642235e-02, +7.613841735998289e-01}}, + Descriptor{6, 1.832188797223636e-03, {+5.243114241272343e-02, +1.452721772236918e-01, +4.996792895702993e-01}}, + Descriptor{6, 8.460253945737610e-04, {+8.872202555510618e-03, +3.816302433543118e-01, +8.877001109429070e-01}}, + Descriptor{6, 1.597513197343773e-03, {+2.592518129005248e-01, +5.551397100853696e-01, +8.790486279875863e-01}}, + Descriptor{6, 2.678157870344808e-03, {+3.527097683072426e-01, +4.546097143409199e-02, +6.369991526576181e-01}}, + Descriptor{6, 7.373212126545897e-04, {+1.450709676542589e-01, +1.181702543851609e-02, +8.952124765779996e-01}}, + Descriptor{6, 1.390059413378896e-03, {+1.874143309040665e-01, +1.371981166173774e-01, +9.134247047008914e-01}}, + Descriptor{6, 7.964285504550415e-04, {+6.814016086596048e-02, +1.498311852045099e-01, +9.751784156687211e-01}}, + Descriptor{6, 1.460116442574025e-03, {+3.340585216441213e-01, +5.496962861346901e-02, +9.356631230196827e-01}}, + Descriptor{6, 1.348373684024378e-03, {+6.785157976700519e-02, +1.205147270278029e-01, +7.655747942493478e-01}}, + Descriptor{6, 3.286050878128491e-03, {+5.023136055537912e-01, +1.076311573233394e-01, +5.182173603742516e-01}}, + Descriptor{6, 1.124720118777690e-03, {+7.819399743424233e-03, +2.556542053755758e-01, +7.166820851155357e-01}}, + Descriptor{6, 2.127107274890790e-03, {+6.609230621965876e-01, +9.839569585073644e-02, +6.803594853699388e-01}}, + Descriptor{6, 7.135219223491392e-04, {+1.784736485903538e-01, +1.796539994312394e-03, +2.866535225594761e-01}}, + Descriptor{6, 3.719588400835986e-04, {+2.532227359651285e-01, +1.312175908589084e-02, +9.829888431964284e-01}}, + Descriptor{6, 2.151829924432428e-04, {+1.443505367133109e-02, +6.867387590589011e-02, +9.834928544568246e-01}}, + Descriptor{6, 8.163226512583331e-04, {+2.794904874495157e-01, +1.274003485132245e-01, +9.907920620663775e-01}}}; + + fill_quadrature_points(descriptor_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 " + + std::to_string(PrismGaussQuadrature::max_degree) + "on prisms"); + } + } +} diff --git a/src/analysis/PrismGaussQuadrature.hpp b/src/analysis/PrismGaussQuadrature.hpp new file mode 100644 index 0000000000000000000000000000000000000000..2750d76c29894fd960b89afbfd29ec908c54d03b --- /dev/null +++ b/src/analysis/PrismGaussQuadrature.hpp @@ -0,0 +1,38 @@ +#ifndef PRISM_GAUSS_QUADRATURE_HPP +#define PRISM_GAUSS_QUADRATURE_HPP + +#include <analysis/QuadratureFormula.hpp> + +/** + * Defines Gauss quadrature on the reference prism element + * + * \note formulae are provided by + * + * 'High-order symmetric cubature rules for tetrahedra and pyramids' + * Jan JasĖkowiec & N. Sukumar (2020). + */ +class PrismGaussQuadrature final : public QuadratureFormula<3> +{ + public: + constexpr static size_t max_degree = 20; + + private: + void _buildPointAndWeightLists(const size_t degree); + + public: + PrismGaussQuadrature(PrismGaussQuadrature&&) = default; + PrismGaussQuadrature(const PrismGaussQuadrature&) = default; + + private: + friend class QuadratureManager; + + explicit PrismGaussQuadrature(const size_t degree) : QuadratureFormula<3>(QuadratureType::Gauss) + { + this->_buildPointAndWeightLists(degree); + } + + PrismGaussQuadrature() = delete; + ~PrismGaussQuadrature() = default; +}; + +#endif // PRISM_GAUSS_QUADRATURE_HPP diff --git a/src/analysis/PyramidGaussQuadrature.cpp b/src/analysis/PyramidGaussQuadrature.cpp new file mode 100644 index 0000000000000000000000000000000000000000..869408a914c58c2402e2b9b8c7954549466a97f7 --- /dev/null +++ b/src/analysis/PyramidGaussQuadrature.cpp @@ -0,0 +1,976 @@ +#include <analysis/PyramidGaussQuadrature.hpp> +#include <utils/Exceptions.hpp> + +void +PyramidGaussQuadrature::_buildPointAndWeightLists(const size_t degree) +{ + using R3 = TinyVector<3>; + + struct Descriptor + { + int id; + double weight; + std::vector<double> lambda_list; + }; + + auto fill_quadrature_points = [](auto descriptor_list, auto& point_list, auto& weight_list) { + Assert(point_list.size() == weight_list.size()); + + size_t k = 0; + for (size_t i = 0; i < descriptor_list.size(); ++i) { + const auto [id, unit_weight, value_list] = descriptor_list[i]; + + const double w = (4. / 3) * unit_weight; + + switch (id) { + case 1: { + Assert(value_list.size() == 1); + const double z = value_list[0]; + + point_list[k] = {0, 0, z}; + weight_list[k] = w; + ++k; + break; + } + case 2: { + Assert(value_list.size() == 2); + const double a = value_list[0]; + const double z = value_list[1]; + + point_list[k + 0] = {+a, 0, z}; + point_list[k + 1] = {-a, 0, z}; + point_list[k + 2] = {0, +a, z}; + point_list[k + 3] = {0, -a, z}; + + for (size_t l = 0; l < 4; ++l) { + weight_list[k + l] = w; + } + + k += 4; + break; + } + case 3: { + Assert(value_list.size() == 2); + const double a = value_list[0]; + const double z = value_list[1]; + + point_list[k + 0] = {+a, +a, z}; + point_list[k + 1] = {+a, -a, z}; + point_list[k + 2] = {-a, +a, z}; + point_list[k + 3] = {-a, -a, z}; + + for (size_t l = 0; l < 4; ++l) { + weight_list[k + l] = w; + } + + k += 4; + break; + } + case 4: { + Assert(value_list.size() == 3); + const double a = value_list[0]; + const double b = value_list[1]; + const double z = value_list[2]; + + point_list[k + 0] = {+a, +b, z}; + point_list[k + 1] = {+a, -b, z}; + point_list[k + 2] = {-a, +b, z}; + point_list[k + 3] = {-a, -b, z}; + point_list[k + 4] = {+b, +a, z}; + point_list[k + 5] = {-b, +a, z}; + point_list[k + 6] = {+b, -a, z}; + point_list[k + 7] = {-b, -a, z}; + + for (size_t l = 0; l < 8; ++l) { + weight_list[k + l] = w; + } + + k += 8; + break; + } + // LCOV_EXCL_START + default: { + throw UnexpectedError("invalid quadrature id"); + } + // LCOV_EXCL_STOP + } + } + }; + + switch (degree) { + case 0: + case 1: { + constexpr size_t nb_points = 1; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{1, 1.000000000000000e+00, {+2.500000000000000e-01}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 2: { + constexpr size_t nb_points = 5; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{1, 2.798666789016337e-01, {+5.606322125356171e-01}}, + Descriptor{3, 1.800333302745916e-01, {+5.269974873671749e-01, +1.292784570090256e-01}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 3: { + constexpr size_t nb_points = 6; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{1, 1.534506474854593e-01, {+3.032132711145601e-02}}, + Descriptor{1, 2.613312220748051e-01, {+5.656071879789744e-01}}, + Descriptor{3, 1.463045326099339e-01, {+5.845963663947116e-01, +1.666666666666667e-01}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 4: { + constexpr size_t nb_points = 10; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{1, 2.068834025895523e-01, {+1.251369531087465e-01}}, + Descriptor{1, 1.137418831706419e-01, {+6.772327888861374e-01}}, + Descriptor{2, 1.063245878893255e-01, {+6.505815563982326e-01, +3.223841495782137e-01}}, + Descriptor{3, 6.351909067062594e-02, {+6.579669971216900e-01, +3.924828389881535e-02}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 5: { + constexpr size_t nb_points = 15; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{1, 6.773442693037113e-02, {+7.307094695547904e-01}}, + Descriptor{1, 6.470893518150579e-02, {+6.197232858190588e-03}}, + Descriptor{1, 1.772715490151452e-01, {+2.684458095343137e-01}}, + Descriptor{2, 5.910777216655192e-02, {+7.534406130793294e-01, +1.250000000000000e-01}}, + Descriptor{3, 6.537546219121122e-02, {+4.171520024257513e-01, +4.218217110028595e-01}}, + Descriptor{3, 4.808803786048134e-02, {+6.740225164778704e-01, +6.579572180745927e-02}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 6: { + constexpr size_t nb_points = 23; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{1, 1.023699419233705e-01, {+1.335312170632148e-01}}, + Descriptor{1, 2.544552509057920e-02, {+8.083918187874604e-01}}, + Descriptor{1, 1.074435834226933e-01, {+3.784035206635531e-01}}, + Descriptor{2, 3.715744178992644e-02, {+4.210459518278233e-01, +5.563577402280808e-01}}, + Descriptor{2, 3.663269740345384e-02, {+8.358409250652439e-01, +9.682668434012107e-02}}, + Descriptor{3, 7.134885171305939e-02, {+5.134178134130217e-01, +2.554780750374050e-01}}, + Descriptor{3, 8.659461394440064e-03, {+8.719795336426682e-01, +3.348911098405843e-02}}, + Descriptor{3, 3.738678508995950e-02, {+4.773315577677307e-01, +2.776222122928558e-02}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 7: { + constexpr size_t nb_points = 31; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{1, 1.005139817749384e-01, {+3.936504852592841e-01}}, + Descriptor{1, 1.571901760701542e-02, {+8.386341427229903e-01}}, + Descriptor{1, 2.499658963028166e-02, {+1.985131073852604e-05}}, + Descriptor{2, 2.871093750000000e-02, {+6.172133998483676e-01, +3.333333333333333e-01}}, + Descriptor{2, 2.669175929300292e-02, {+8.640987597877147e-01, +6.666666666666667e-02}}, + Descriptor{3, 3.572750182264944e-02, {+5.248875603037457e-01, +2.904549108425410e-01}}, + Descriptor{3, 2.951904528668866e-02, {+2.541968221946381e-01, +6.054783556814159e-01}}, + Descriptor{3, 6.594160872648229e-02, {+3.540511188101694e-01, +1.293188463105600e-01}}, + Descriptor{3, 1.333274388639106e-02, {+6.142719454511971e-01, +1.008633926811357e-04}}, + Descriptor{3, 1.476900623172677e-02, {+8.028224862699490e-01, +8.012951317750569e-02}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 8: { + constexpr size_t nb_points = 47; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{1, 5.595524252285600e-02, {+7.395194949759915e-02}}, + Descriptor{1, 6.694668391641566e-02, {+4.806418077857804e-01}}, + Descriptor{1, 4.752523069833954e-03, {+8.978770012649402e-01}}, + Descriptor{2, 1.488586682102477e-02, {+2.536785615782182e-01, +7.039949439220020e-01}}, + Descriptor{2, 2.455698624881831e-02, {+7.102737577690728e-01, +1.599976229101533e-01}}, + Descriptor{2, 1.608138988371910e-02, {+6.364336235983890e-01, +3.474084640816018e-01}}, + Descriptor{2, 1.442915622061931e-02, {+6.233792819622643e-01, +1.127682420195144e-02}}, + Descriptor{3, 2.488836268558412e-02, {+5.122596817100590e-01, +6.351022006373874e-02}}, + Descriptor{3, 3.016542061786949e-02, {+3.796590137942965e-01, +4.628422688700697e-01}}, + Descriptor{3, 1.825943823062004e-02, {+6.914008694052951e-01, +1.917713050993898e-01}}, + Descriptor{3, 4.052705114084869e-03, {+8.674219079854986e-01, +1.630913438364360e-02}}, + Descriptor{3, 5.109969513593878e-02, {+3.171232262910623e-01, +2.368198703013063e-01}}, + Descriptor{4, 9.833683332222407e-03, {+8.937479716183564e-01, +4.052832634656467e-01, +5.005997974535450e-02}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 9: { + constexpr size_t nb_points = 62; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{1, 3.517982458221282e-03, {+9.033806033428579e-01}}, + Descriptor{1, 4.216520928063209e-02, {+5.649644435959712e-01}}, + Descriptor{2, 8.521043257455639e-03, {+2.199358452633800e-01, +7.485612463519468e-01}}, + Descriptor{2, 2.087072229798968e-02, {+2.558015573793007e-01, +1.346997662955544e-01}}, + Descriptor{2, 1.073969585101612e-02, {+8.739242228416501e-01, +5.467616134251216e-02}}, + Descriptor{2, 2.521321637389669e-02, {+6.206970648203557e-01, +1.894626948405005e-01}}, + Descriptor{2, 1.961258547003659e-02, {+4.808872023980156e-01, +2.248423582708249e-02}}, + Descriptor{2, 1.643323197880765e-02, {+5.476633755989256e-01, +4.134082258927628e-01}}, + Descriptor{3, 1.830589291063876e-02, {+3.171678212066174e-01, +5.507723363912053e-01}}, + Descriptor{3, 1.130841811263377e-02, {+5.811421463327766e-01, +3.191414755591298e-01}}, + Descriptor{3, 2.507245299443831e-02, {+5.230813443611307e-01, +8.935238781868592e-02}}, + Descriptor{3, 4.419409904347655e-03, {+8.727886385585986e-01, +6.151583405729108e-02}}, + Descriptor{3, 4.065272607298719e-02, {+2.744783026131462e-01, +3.264219851596609e-01}}, + Descriptor{4, 1.219793270502279e-02, {+4.578740192946059e-01, +7.687455968654898e-01, +1.755724204367565e-01}}, + Descriptor{4, 6.516970715496498e-03, {+5.294592086619503e-01, +8.651632950329239e-01, +1.570840570495663e-02}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 10: { + constexpr size_t nb_points = 80; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{1, 2.226887246752692e-03, {+9.176665489678424e-01}}, + Descriptor{1, 1.676862119517167e-02, {+7.090093740468727e-01}}, + Descriptor{1, 5.218524659101940e-02, {+2.271396740104223e-01}}, + Descriptor{1, 2.912684113372536e-02, {+6.874011069480644e-02}}, + Descriptor{2, 2.061250827144200e-02, {+6.542017017611934e-01, +1.239254499739905e-01}}, + Descriptor{2, 1.001318317045432e-02, {+7.663392799174616e-01, +2.096299791450872e-02}}, + Descriptor{2, 3.805894719789539e-03, {+8.042105610181555e-01, +1.657731354676645e-01}}, + Descriptor{2, 1.603356460939568e-02, {+2.171975788362678e-01, +4.934052093395356e-01}}, + Descriptor{2, 4.210573985824022e-03, {+2.093734735103665e-01, +7.896976713483934e-01}}, + Descriptor{2, 8.129732309410973e-03, {+5.283070905328926e-01, +4.716928890485879e-01}}, + Descriptor{3, 1.345646795638387e-02, {+3.468149019049753e-01, +2.011394567580291e-02}}, + Descriptor{3, 1.016376299548378e-02, {+5.423477423323926e-01, +3.682210199892779e-01}}, + Descriptor{3, 2.981645762492043e-02, {+4.296576954455671e-01, +1.266159486770112e-01}}, + Descriptor{3, 8.657127834237414e-03, {+7.187141460172495e-01, +2.433819982878694e-02}}, + Descriptor{3, 9.531999164931240e-03, {+7.624400857874878e-01, +1.270144250256904e-01}}, + Descriptor{3, 7.139582674758052e-04, {+9.642735008631930e-01, +1.067692573406055e-02}}, + Descriptor{3, 1.519293397619959e-02, {+2.789738869874377e-01, +5.970429731303039e-01}}, + Descriptor{4, 1.008533639437561e-02, {+7.312452983523516e-01, +3.711506789000326e-01, +2.175616631549504e-01}}, + Descriptor{4, 5.859338229960730e-03, {+9.219480705797174e-01, +4.196652283339353e-01, +4.137857207280887e-02}}, + Descriptor{4, 2.134779341185569e-02, {+1.995426151915722e-01, +4.434009744724249e-01, +3.261536572399062e-01}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 11: { + constexpr size_t nb_points = 103; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{1, 1.286363653695535e-02, {+6.929563964750883e-01}}, + Descriptor{1, 2.595721225427735e-03, {+9.110152344627592e-01}}, + Descriptor{1, 8.176385700475526e-03, {+2.503292907254847e-01}}, + Descriptor{2, 5.119414398042891e-03, {+3.095914411121506e-01, +5.040798390564714e-02}}, + Descriptor{2, 6.846996666462350e-03, {+7.699392208102979e-01, +1.178348626907169e-02}}, + Descriptor{2, 2.021405278036776e-02, {+7.002703811744613e-01, +1.010394090255615e-01}}, + Descriptor{2, 1.240017518258633e-02, {+4.609503542907282e-01, +3.427275760580460e-01}}, + Descriptor{2, 1.050060859922616e-02, {+2.992893821695951e-01, +6.286989821677651e-01}}, + Descriptor{2, 1.207523991498537e-02, {+5.911494375715570e-01, +2.582284852308509e-01}}, + Descriptor{2, 7.945494399371682e-03, {+1.861308147704910e-02, +4.358344954832800e-01}}, + Descriptor{2, 8.979308019639792e-03, {+1.603429097546466e-01, +2.192831941429789e-01}}, + Descriptor{3, 4.328610077172669e-03, {+1.445075355444747e-01, +7.879743305346877e-01}}, + Descriptor{3, 9.591505938503333e-03, {+5.936945097967551e-01, +3.089295886910713e-01}}, + Descriptor{3, 8.458896075424903e-03, {+2.749014180295009e-01, +1.781185684646454e-02}}, + Descriptor{3, 2.093917618186587e-02, {+2.968007724724139e-01, +1.112703360898260e-01}}, + Descriptor{3, 1.007335618421271e-02, {+5.984926370656903e-01, +2.444716310077481e-02}}, + Descriptor{3, 1.474935950898293e-02, {+6.103141530732866e-01, +1.204187551930976e-01}}, + Descriptor{3, 4.054320200259096e-03, {+3.734502308185636e-01, +5.775253255524150e-01}}, + Descriptor{3, 1.768012056788626e-02, {+2.624599146327740e-01, +4.916980190881633e-01}}, + Descriptor{3, 2.349367280688882e-02, {+3.686063571979057e-01, +2.631132571277226e-01}}, + Descriptor{3, 3.003553459527201e-03, {+8.702629344236114e-01, +1.908681361607608e-02}}, + Descriptor{3, 4.330579718905655e-03, {+8.102574500242316e-01, +1.169261992676211e-01}}, + Descriptor{4, 7.882977643914898e-03, {+7.896765746747297e-01, +3.552721383504759e-01, +1.796809539017722e-01}}, + Descriptor{4, 5.094911855326565e-03, {+9.280503494413060e-01, +4.148421023475579e-01, +3.535559961728909e-02}}, + Descriptor{4, 6.675422227745319e-03, {+2.331378908359926e-01, +5.562877919132911e-01, +4.146440202422456e-01}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 12: { + constexpr size_t nb_points = 127; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{1, 2.715854620871203e-02, {+4.570070042407191e-01}}, + Descriptor{1, 4.353142424489953e-04, {+9.624848010480895e-01}}, + Descriptor{1, 1.391222140872406e-02, {+2.656531684537741e-02}}, + Descriptor{2, 3.872881466492529e-03, {+6.175240822879710e-01, +5.374720825773919e-03}}, + Descriptor{2, 2.179679715936184e-03, {+9.538341781347592e-01, +3.942123626649530e-02}}, + Descriptor{2, 1.267133485574918e-02, {+5.950300580138582e-01, +7.619184421748394e-02}}, + Descriptor{2, 8.734641630353807e-03, {+4.353935982023290e-01, +5.246187553362018e-01}}, + Descriptor{2, 2.891467316158506e-03, {+1.329135556120804e-01, +8.387199403114260e-01}}, + Descriptor{2, 3.366868485115227e-03, {+7.971436348244696e-01, +2.007518977789794e-01}}, + Descriptor{2, 1.476038031344119e-03, {+3.107829504939940e-01, +6.826546910531470e-01}}, + Descriptor{2, 1.998444773599242e-02, {+4.689689670336921e-01, +3.171338246752144e-01}}, + Descriptor{2, 6.189271706444372e-03, {+6.329314929065794e-02, +1.270962903467187e-01}}, + Descriptor{3, 8.200787054788633e-03, {+1.169412447366524e-01, +6.712417429492287e-01}}, + Descriptor{3, 5.096515464581623e-03, {+4.771085065521420e-01, +4.586280271864225e-01}}, + Descriptor{3, 1.739298850473944e-02, {+3.479673540088846e-01, +1.193889061370197e-01}}, + Descriptor{3, 1.948797782027694e-02, {+2.174809398989127e-01, +2.574178486652196e-01}}, + Descriptor{3, 5.388962434670257e-03, {+6.742620754102585e-01, +2.260502558938976e-02}}, + Descriptor{3, 6.769117314513475e-03, {+6.541531257781691e-01, +8.746307755558261e-02}}, + Descriptor{3, 4.675876093665083e-03, {+2.604386899595714e-01, +6.714016412797261e-01}}, + Descriptor{3, 1.838172037009153e-02, {+2.744210786837723e-01, +4.760425504887897e-01}}, + Descriptor{3, 1.407964506457295e-02, {+5.125902273710998e-01, +2.277795581554027e-01}}, + Descriptor{3, 2.833700634607033e-03, {+8.687887353904908e-01, +5.850272176027390e-02}}, + Descriptor{3, 4.791372228177735e-03, {+7.118168180030836e-01, +2.205399573194206e-01}}, + Descriptor{3, 9.906806338191463e-03, {+3.675456953238826e-01, +2.548724290196442e-02}}, + Descriptor{4, 5.355743630233014e-03, {+8.489693748245684e-01, +5.120364631720311e-01, +1.114583653780480e-01}}, + Descriptor{4, 8.168185107182221e-04, {+9.738540313599703e-01, +7.467034094055778e-01, +3.392208246799127e-03}}, + Descriptor{4, 8.541753721892767e-03, {+3.230240551801264e-01, +6.255561325380413e-01, +3.272515164405167e-01}}, + Descriptor{4, 1.018769584471249e-02, {+1.945007634528372e-01, +6.980595936427326e-01, +1.480516686189832e-01}}, + Descriptor{4, 5.723677926726618e-03, {+3.289488538718914e-01, +8.538315289662523e-01, +2.487563023274973e-02}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 13: { + constexpr size_t nb_points = 152; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{1, 1.203669565577547e-03, {+9.297400586425600e-01}}, + Descriptor{1, 1.890734566258640e-02, {+5.838703604447901e-01}}, + Descriptor{1, 2.412883548353303e-02, {+1.094245815067315e-01}}, + Descriptor{1, 1.430958560741041e-02, {+3.004359812964663e-01}}, + Descriptor{2, 1.462233467606358e-02, {+4.122389208832898e-01, +4.035176514416959e-01}}, + Descriptor{2, 1.310471335067461e-03, {+9.448240879795888e-01, +5.541396470307911e-03}}, + Descriptor{2, 1.315348594597115e-03, {+1.501230655029512e-01, +8.497929440328683e-01}}, + Descriptor{2, 6.041729387793333e-03, {+3.633828357756222e-01, +6.071950436217343e-01}}, + Descriptor{2, 8.289343691958597e-03, {+3.289712237345070e-01, +2.033792783786767e-02}}, + Descriptor{2, 1.293341373858936e-02, {+5.570493589160862e-01, +1.060119987373025e-01}}, + Descriptor{2, 5.638854191543832e-03, {+7.106035443742125e-01, +2.491041991532026e-01}}, + Descriptor{2, 4.504991398813604e-03, {+8.853174870868126e-01, +8.107956240970675e-02}}, + Descriptor{3, 3.636184206108946e-03, {+4.888475450384162e-01, +9.508151681060791e-03}}, + Descriptor{3, 3.888421168021828e-03, {+4.503177245667275e-01, +4.881936050921409e-01}}, + Descriptor{3, 4.023653208263601e-03, {+6.587295691554786e-01, +2.769083115660864e-01}}, + Descriptor{3, 9.559019492448712e-03, {+6.258827191179884e-01, +1.224809382042812e-01}}, + Descriptor{3, 1.938656716858041e-02, {+2.517896003319362e-01, +2.232305727986451e-01}}, + Descriptor{3, 9.687548837381962e-04, {+9.133819128044913e-01, +1.207165002118426e-02}}, + Descriptor{3, 5.022143502861996e-03, {+1.111786164172054e-01, +7.551872471669051e-01}}, + Descriptor{3, 1.448769412031482e-02, {+3.781492498737534e-01, +8.424825204838618e-02}}, + Descriptor{3, 4.599764313830424e-03, {+2.314619569157776e-01, +6.318857723177680e-01}}, + Descriptor{3, 1.107636061349879e-02, {+1.859866728257666e-01, +3.989297765923411e-01}}, + Descriptor{3, 4.692602004327276e-03, {+7.294149054289296e-01, +2.502635713295603e-02}}, + Descriptor{3, 2.851949824498801e-03, {+8.041924177792682e-01, +1.203800076513554e-01}}, + Descriptor{3, 1.323033835935081e-02, {+4.703608283841747e-01, +2.927035935703978e-01}}, + Descriptor{3, 1.119723439728825e-03, {+2.753565752001155e-01, +7.074274892155881e-01}}, + Descriptor{3, 9.182464621381196e-03, {+2.584044366257879e-01, +5.283274650941000e-01}}, + Descriptor{4, 4.564906537010502e-03, {+7.745630168641912e-01, +4.397893897194206e-01, +1.953840901290468e-01}}, + Descriptor{4, 5.475034834428800e-03, {+7.201414655134084e-01, +2.217479044308266e-01, +2.260035188498128e-02}}, + Descriptor{4, 9.922612076457428e-03, {+1.750984955638136e-01, +5.856079751486080e-01, +2.160852053363709e-01}}, + Descriptor{4, 1.103829121564573e-03, {+9.376254731805550e-01, +7.398267532513132e-01, +6.232437306564607e-02}}, + Descriptor{4, 2.362282939586705e-03, {+9.258882242137035e-01, +5.000209314552113e-01, +1.929314718254384e-02}}, + Descriptor{4, 6.306665849348717e-03, {+2.682073921041632e-01, +5.618519868919964e-01, +4.010246655048774e-01}}, + Descriptor{4, 6.754925131024099e-03, {+3.620795943973790e-01, +7.924562807098640e-01, +9.200529105614789e-02}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 14: { + constexpr size_t nb_points = 184; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{1, 6.009828410914801e-04, {+9.455096078380157e-01}}, + Descriptor{1, 1.255487583666288e-02, {+6.138243564839928e-01}}, + Descriptor{1, 2.319377258130698e-02, {+2.454049718059621e-01}}, + Descriptor{1, 1.905556551345681e-02, {+4.183282539085985e-01}}, + Descriptor{2, 1.191795956205729e-02, {+4.218261367348597e-01, +4.017536316056771e-01}}, + Descriptor{2, 3.867184412332806e-03, {+8.465613435886886e-02, +8.958821481037450e-02}}, + Descriptor{2, 1.923763095174742e-03, {+9.516713196592316e-01, +3.128290548598175e-02}}, + Descriptor{2, 1.234179804493060e-03, {+1.221288178114563e-01, +8.656263522240111e-01}}, + Descriptor{2, 4.716648039115899e-03, {+3.459755786873036e-01, +5.615491563602975e-01}}, + Descriptor{2, 5.134044973384534e-03, {+3.250020921247040e-01, +1.398939848661482e-02}}, + Descriptor{2, 1.154564746408180e-03, {+8.527465617518474e-01, +1.655718296284047e-03}}, + Descriptor{2, 1.181264118995304e-02, {+6.382775647715264e-01, +6.493816225859560e-02}}, + Descriptor{2, 2.436937834631011e-03, {+6.723114741458501e-01, +3.226524499585241e-01}}, + Descriptor{2, 2.442180393951459e-03, {+8.537496059510902e-01, +1.428460235322913e-01}}, + Descriptor{2, 2.760272065188771e-03, {+3.235182852814910e-01, +6.650982181901243e-01}}, + Descriptor{2, 1.491875937488001e-02, {+4.969751483237657e-01, +1.927846766563645e-01}}, + Descriptor{3, 8.607885480520022e-03, {+5.041706295584495e-01, +5.324772752904031e-02}}, + Descriptor{3, 9.201054026224215e-04, {+6.385320288130391e-01, +3.499922479913266e-01}}, + Descriptor{3, 3.506580713358855e-03, {+7.643224482486065e-01, +1.609611231580418e-01}}, + Descriptor{3, 1.184517921997258e-02, {+5.613330619383329e-01, +1.603998892409423e-01}}, + Descriptor{3, 1.517200950119656e-02, {+2.878680539515507e-01, +1.373276390573706e-01}}, + Descriptor{3, 7.988570964665479e-04, {+9.016308382757633e-01, +1.032358209500777e-02}}, + Descriptor{3, 3.465322056721376e-03, {+9.459747575878658e-02, +7.677917941640774e-01}}, + Descriptor{3, 5.649017528916505e-03, {+2.627574405731676e-01, +4.943554173327801e-02}}, + Descriptor{3, 3.144992576543379e-03, {+3.864091536381419e-01, +5.560266141216673e-01}}, + Descriptor{3, 1.042467052306092e-02, {+2.282300577985542e-01, +4.962791997555249e-01}}, + Descriptor{3, 1.353353344199375e-03, {+7.057872269283543e-01, +2.008807154101613e-03}}, + Descriptor{3, 6.863946049178268e-04, {+9.147875524427646e-01, +4.956231677804342e-02}}, + Descriptor{3, 8.488466463152199e-03, {+5.088306451368273e-01, +3.463558696873174e-01}}, + Descriptor{3, 1.389764713997917e-03, {+2.183390551054974e-01, +7.454288363105724e-01}}, + Descriptor{3, 5.646871721661347e-03, {+2.052421004307298e-01, +6.415316471289261e-01}}, + Descriptor{3, 1.822286920356053e-02, {+2.910901390165372e-01, +3.062273833527194e-01}}, + Descriptor{3, 4.755535844463758e-03, {+7.486540248046429e-01, +4.936880562940795e-02}}, + Descriptor{4, 3.308393786732543e-03, {+7.378246466058306e-01, +4.928495648091606e-01, +2.369940069990296e-01}}, + Descriptor{4, 4.070045103160022e-03, {+8.589060620098202e-01, +3.738196822630493e-01, +2.776225858911670e-02}}, + Descriptor{4, 8.268489304502566e-03, {+2.243615064922758e-01, +6.317949456704877e-01, +2.592830550287851e-01}}, + Descriptor{4, 2.221378811027735e-03, {+9.001757758936474e-01, +6.261867885017652e-01, +7.806621986847780e-02}}, + Descriptor{4, 5.341491722009947e-04, {+9.789501849840820e-01, +6.256578399323836e-01, +4.430014519257858e-03}}, + Descriptor{4, 4.879462347378159e-03, {+2.560758373363789e-01, +5.119481066576588e-01, +4.542857276885983e-01}}, + Descriptor{4, 7.897297568864630e-03, {+2.974176206871381e-01, +7.755395865083232e-01, +1.176110467333258e-01}}, + Descriptor{4, 2.696628566117115e-03, {+2.907965956609688e-01, +6.192615227882655e-01, +7.834837395674860e-03}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 15: { + constexpr size_t nb_points = 234; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{1, 4.253301554860054e-04, {+9.516784060639266e-01}}, + Descriptor{1, 1.525748792328103e-02, {+2.989009214424757e-01}}, + Descriptor{2, 5.280176625857056e-03, {+7.001403574239718e-01, +1.037252232620472e-01}}, + Descriptor{2, 2.446394589904036e-03, {+9.193631484833984e-01, +6.052669044962753e-02}}, + Descriptor{2, 9.737060312972353e-04, {+1.101334889442361e-01, +8.776707213450818e-01}}, + Descriptor{2, 7.776124953823158e-03, {+4.465008567015498e-01, +3.306143190884451e-01}}, + Descriptor{2, 2.676970927679192e-03, {+8.020538575801487e-01, +1.891305716440682e-01}}, + Descriptor{2, 6.190812842666219e-03, {+5.301512452732464e-01, +1.554979319555147e-01}}, + Descriptor{2, 6.561865616728806e-04, {+9.732273442892753e-01, +4.905110329399738e-03}}, + Descriptor{2, 6.569940566182691e-03, {+5.055718663406419e-01, +6.238803484862593e-02}}, + Descriptor{2, 2.673087432145158e-03, {+4.618938260051262e-02, +5.328414641791853e-01}}, + Descriptor{2, 1.759495302160485e-03, {+6.230136406382800e-01, +3.769559380708412e-01}}, + Descriptor{2, 3.312857608561831e-03, {+2.950931045827234e-01, +6.814825140552475e-01}}, + Descriptor{2, 7.510345065720940e-03, {+4.776005857611240e-01, +2.309753566333424e-01}}, + Descriptor{2, 8.931665290893454e-03, {+3.689801580562112e-01, +5.033566690504305e-01}}, + Descriptor{3, 5.568418259966719e-03, {+3.723782904830595e-01, +4.235367529321636e-01}}, + Descriptor{3, 2.649457392781329e-03, {+5.341902002288372e-01, +4.129667979379346e-01}}, + Descriptor{3, 1.970289990554734e-03, {+6.063808134784291e-02, +7.864057957899899e-01}}, + Descriptor{3, 5.134839039660163e-03, {+4.777068770658753e-01, +3.265377521300765e-01}}, + Descriptor{3, 7.421925481559295e-03, {+1.987543120573730e-01, +5.291423306214975e-02}}, + Descriptor{3, 1.644857216298594e-03, {+7.599695611037520e-01, +6.930996189193400e-03}}, + Descriptor{3, 5.534536939100995e-03, {+5.055458420266429e-01, +1.799129130112892e-02}}, + Descriptor{3, 3.256281564205464e-03, {+2.206482423626575e-01, +8.304773708384203e-03}}, + Descriptor{3, 1.515060824261142e-03, {+3.440503418178477e-01, +6.178873991598769e-01}}, + Descriptor{3, 5.911265567277567e-03, {+1.962412964100753e-01, +1.926549836686368e-01}}, + Descriptor{3, 8.392379781416604e-04, {+9.194790158373803e-01, +1.617257265834036e-02}}, + Descriptor{3, 4.022404010252260e-03, {+2.620925839988805e-01, +5.954881060323367e-01}}, + Descriptor{3, 2.231695755198927e-03, {+1.744887942814471e-01, +7.673520458998934e-01}}, + Descriptor{3, 6.156882008161937e-03, {+1.325632428580384e-01, +6.445714883912202e-01}}, + Descriptor{3, 8.642320589201948e-03, {+3.077710707446309e-01, +2.682338927247724e-01}}, + Descriptor{3, 7.452703387505539e-03, {+4.543788145456805e-01, +1.924966376990235e-01}}, + Descriptor{3, 5.028803835070171e-03, {+1.820389321231959e-01, +3.545120556149344e-01}}, + Descriptor{3, 8.796385122255454e-03, {+1.880443006828807e-01, +1.378439700992989e-01}}, + Descriptor{3, 1.747812460887048e-03, {+8.528586603669460e-01, +8.819642588395045e-02}}, + Descriptor{3, 9.189893838229260e-03, {+1.939535843143651e-01, +4.412634170405248e-01}}, + Descriptor{3, 6.208073919367888e-03, {+6.362056944924487e-01, +1.812670653663255e-01}}, + Descriptor{3, 5.683980552459499e-03, {+7.160962950323663e-01, +6.273138420630826e-02}}, + Descriptor{3, 1.836585716232118e-03, {+7.297058862326863e-01, +2.223880047949926e-01}}, + Descriptor{4, 2.218692647777552e-03, {+8.582850877054248e-01, +5.768403835499213e-01, +1.231132989726892e-01}}, + Descriptor{4, 2.609887405864026e-03, {+7.633676619034022e-01, +2.116780932527140e-01, +2.653658688975024e-02}}, + Descriptor{4, 6.168756108593601e-03, {+2.161303509635070e-01, +5.839223522583539e-01, +3.294970252944507e-01}}, + Descriptor{4, 1.229957612267995e-03, {+9.561584299674409e-01, +6.424182794168720e-01, +2.375108271645151e-02}}, + Descriptor{4, 1.954938784233806e-03, {+8.759221925259401e-01, +3.779756583128506e-01, +1.156156746353602e-02}}, + Descriptor{4, 3.467639337694073e-03, {+2.445394062188940e-01, +4.671941605403201e-01, +5.047812448827769e-01}}, + Descriptor{4, 6.770266043344008e-03, {+3.706058970009432e-01, +5.485269061480423e-01, +9.182493970820699e-02}}, + Descriptor{4, 1.678294163556885e-03, {+6.156798284057371e-01, +7.140171587890908e-03, +1.061641469954417e-02}}, + Descriptor{4, 7.130797590166880e-03, {+7.101327396551219e-01, +2.791894198719184e-01, +1.869924830554508e-01}}, + Descriptor{4, 4.675472898850534e-03, {+8.258711059677443e-01, +3.568302621331758e-01, +7.551964039133613e-02}}, + Descriptor{4, 2.534207524207739e-03, {+4.755766339064903e-01, +6.928649578239733e-01, +2.863100113252361e-01}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 16: { + constexpr size_t nb_points = 285; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{1, 2.767212020768290e-04, {+9.586035463620837e-01}}, + Descriptor{2, 7.349442577079450e-03, {+5.187038802297479e-01, +1.406555941365744e-01}}, + Descriptor{2, 1.487404370728813e-03, {+9.153129245676680e-01, +4.316491102619298e-02}}, + Descriptor{2, 3.876936384211876e-03, {+1.655472656731889e-02, +3.952283264601336e-01}}, + Descriptor{2, 1.030614824039442e-02, {+3.691213557507810e-01, +2.989012556159393e-01}}, + Descriptor{2, 2.726731988438958e-03, {+2.060330211667108e-02, +6.870461262955434e-02}}, + Descriptor{2, 2.446292134085587e-03, {+8.719419371010426e-01, +1.119349596786030e-01}}, + Descriptor{2, 5.549243997617444e-03, {+3.153842078793646e-01, +5.666543504043285e-01}}, + Descriptor{2, 5.022624174664197e-03, {+6.139955556315307e-01, +1.595773278635465e-01}}, + Descriptor{2, 6.711117008479383e-04, {+9.765007634893953e-02, +8.922021492300448e-01}}, + Descriptor{2, 3.168735186737549e-03, {+7.317646448078422e-01, +2.475499337151233e-01}}, + Descriptor{2, 2.307072686856537e-03, {+8.405422094352291e-01, +1.014565417563986e-02}}, + Descriptor{2, 2.233554340355750e-03, {+5.557460950562904e-01, +4.288551242077440e-01}}, + Descriptor{2, 2.286856931321262e-03, {+2.643802171735182e-01, +7.164979649536070e-01}}, + Descriptor{3, 5.838886999649284e-03, {+1.375503146864574e-01, +1.787752340257923e-01}}, + Descriptor{3, 4.120387561185287e-03, {+5.559992997537619e-01, +2.929550108496573e-01}}, + Descriptor{3, 1.730379481687403e-03, {+6.803760252907728e-01, +2.744752357294187e-01}}, + Descriptor{3, 4.106809066021676e-03, {+6.898707466220132e-01, +1.571412723940531e-01}}, + Descriptor{3, 6.354389480672592e-03, {+4.665601661638106e-01, +2.503592476644397e-01}}, + Descriptor{3, 4.326210184433355e-04, {+9.365742707871645e-01, +2.983913639912041e-02}}, + Descriptor{3, 3.452632929818020e-03, {+1.066846406851088e-01, +7.018965704311338e-01}}, + Descriptor{3, 4.240714557365053e-03, {+5.636286631903044e-01, +5.534643995880605e-02}}, + Descriptor{3, 3.405266316789942e-03, {+8.721470315267314e-02, +5.880318078594904e-01}}, + Descriptor{3, 7.009429293023371e-03, {+2.882648291123767e-01, +3.576004004129416e-01}}, + Descriptor{3, 3.711845099382991e-03, {+2.350324970540493e-01, +6.380849983494681e-01}}, + Descriptor{3, 6.557699894218194e-03, {+2.450858218595137e-01, +1.118004676798527e-01}}, + Descriptor{3, 1.699962978331957e-03, {+5.003064978621564e-01, +4.579960420164317e-01}}, + Descriptor{3, 1.347400048357294e-03, {+5.973130190403576e-02, +8.160093965927975e-01}}, + Descriptor{3, 3.633969504612614e-03, {+3.628596393971073e-01, +5.597294995869231e-02}}, + Descriptor{3, 1.216194629008639e-03, {+8.316301192301562e-01, +1.257310660131593e-01}}, + Descriptor{3, 5.495797083167567e-03, {+5.981515120789380e-01, +1.068019913435455e-01}}, + Descriptor{3, 9.733027356279389e-04, {+3.245246862338501e-01, +6.465862007088805e-01}}, + Descriptor{3, 7.253930032328553e-03, {+1.840043782869460e-01, +2.540941713633634e-01}}, + Descriptor{3, 2.616000670590770e-03, {+8.068558507667803e-01, +5.465918013108818e-02}}, + Descriptor{3, 5.483336923370839e-03, {+3.903817283942642e-01, +4.534593946231034e-01}}, + Descriptor{3, 1.501870645161511e-03, {+1.620565672046460e-01, +7.891766078049036e-01}}, + Descriptor{4, 2.242112763518706e-03, {+7.955779101854147e-01, +5.265131942175433e-01, +1.868978854107283e-01}}, + Descriptor{4, 2.543570121402526e-03, {+8.200116575745190e-01, +5.876389794788515e-01, +1.494308906905272e-02}}, + Descriptor{4, 5.361444814068662e-03, {+4.810677594905461e-01, +1.491370161533038e-01, +3.977024606563388e-01}}, + Descriptor{4, 1.505662384876206e-03, {+9.169801723597639e-01, +6.303394356928483e-01, +6.620609897561705e-02}}, + Descriptor{4, 1.126519980001580e-03, {+9.578199602162939e-01, +3.327783186859149e-01, +1.432824105432797e-02}}, + Descriptor{4, 2.836972153671841e-03, {+2.122679281909628e-01, +4.214367174540187e-01, +5.509963820368152e-01}}, + Descriptor{4, 4.234433041605569e-03, {+2.485957380035636e-01, +6.262321767993255e-01, +2.800030049831467e-01}}, + Descriptor{4, 3.184147857413263e-03, {+5.534790138573062e-01, +1.881580592010290e-01, +2.436330465584662e-01}}, + Descriptor{4, 4.029779987731148e-03, {+8.242282785245648e-01, +3.637620573617559e-01, +7.506931441576017e-02}}, + Descriptor{4, 3.669736816875404e-03, {+1.460654272875972e-01, +4.426831022376114e-01, +5.795059845476017e-02}}, + Descriptor{4, 2.488887287575317e-03, {+3.881072073502287e-01, +6.235512572087863e-01, +3.563115863132650e-01}}, + Descriptor{4, 4.888892260572901e-04, {+9.567448428329013e-01, +7.984451750366893e-01, +5.975255115121650e-03}}, + Descriptor{4, 3.252645155099476e-03, {+6.098484948586518e-01, +3.120515076281816e-01, +1.006650964023973e-02}}, + Descriptor{4, 4.955059091457157e-03, {+2.484742721540007e-01, +1.340653178754635e-01, +4.761968373134181e-01}}, + Descriptor{4, 4.570242180251667e-03, {+6.991894353535666e-01, +1.776787645087477e-01, +5.836635447459246e-02}}, + Descriptor{4, 4.810617642413540e-03, {+3.601541528165914e-01, +4.301177602083764e-01, +1.649556291845448e-01}}, + Descriptor{4, 5.387917947217286e-03, {+7.366874205051257e-01, +3.029873517367453e-01, +1.596398472135355e-01}}, + Descriptor{4, 2.469280567426453e-03, {+3.142480630211401e-01, +2.522065148266495e-02, +1.331460692424767e-02}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 17: { + constexpr size_t nb_points = 319; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{1, 1.221682107890185e-04, {+9.722032338703692e-01}}, + Descriptor{1, 5.639436295815340e-03, {+6.387035292668141e-01}}, + Descriptor{1, 1.871168380432278e-03, {+6.802004320805534e-01}}, + Descriptor{2, 8.790055406139772e-04, {+9.524140858124460e-01, +4.194980824924494e-02}}, + Descriptor{2, 6.397368832390104e-04, {+8.275692125030436e-02, +9.014118320415641e-01}}, + Descriptor{2, 1.919424779584283e-03, {+2.657854504312773e-01, +6.843252932276896e-01}}, + Descriptor{2, 1.088568001837918e-03, {+8.115594002847951e-01, +8.245324867689100e-08}}, + Descriptor{2, 5.791783484828203e-03, {+3.523279995401680e-01, +5.541739087364920e-01}}, + Descriptor{2, 3.335679832473916e-03, {+6.030377121897242e-01, +3.625880598876809e-01}}, + Descriptor{2, 4.839934014148432e-03, {+7.840260420215905e-01, +1.387570850346267e-01}}, + Descriptor{2, 1.171223275540323e-02, {+4.934647219864639e-01, +2.426016748645620e-01}}, + Descriptor{2, 7.818032837412321e-03, {+3.503875164890664e-01, +4.013077580688794e-01}}, + Descriptor{2, 3.163898916366554e-03, {+3.364043121074268e-03, +3.815297326937233e-01}}, + Descriptor{2, 8.136278822739700e-03, {+4.307451267906745e-01, +1.190145691544862e-01}}, + Descriptor{2, 4.719826157526003e-03, {+5.925480128294769e-01, +4.928012549325394e-02}}, + Descriptor{2, 9.623713493802133e-04, {+2.255068603658533e-01, +7.620639151935824e-01}}, + Descriptor{3, 1.623787740135037e-03, {+6.397586374033618e-01, +3.115346949712161e-01}}, + Descriptor{3, 8.713459275997466e-03, {+1.646347487963126e-01, +2.565099172621796e-01}}, + Descriptor{3, 4.120086184663263e-03, {+4.930356331962961e-01, +7.449733603189460e-02}}, + Descriptor{3, 5.220647228935927e-04, {+7.479128039630975e-01, +1.307885480845669e-03}}, + Descriptor{3, 3.897164563433518e-03, {+2.625131786428597e-01, +5.285858021846196e-01}}, + Descriptor{3, 2.229921875344444e-03, {+1.748421558986807e-01, +9.552210724735053e-03}}, + Descriptor{3, 9.418067622583964e-03, {+2.760246878567057e-01, +3.414298990596975e-01}}, + Descriptor{3, 6.615832230310311e-04, {+4.351255240898762e-01, +2.702292596780164e-04}}, + Descriptor{3, 1.073942218989596e-04, {+9.530769415773807e-01, +4.692242455320396e-02}}, + Descriptor{3, 3.031478525882112e-03, {+4.842559790519491e-01, +3.444971328350538e-01}}, + Descriptor{3, 8.193264106692307e-04, {+2.938106184332757e-01, +6.681192301420841e-01}}, + Descriptor{3, 4.651214490706081e-03, {+1.605720050369202e-01, +6.739128715712450e-01}}, + Descriptor{3, 1.676067168115160e-03, {+8.101452921420736e-01, +3.437584591482228e-02}}, + Descriptor{3, 8.257689574656562e-03, {+1.800932575491559e-01, +1.554287257829705e-01}}, + Descriptor{3, 3.975458595443641e-03, {+5.013679940745993e-01, +2.697182873385593e-01}}, + Descriptor{3, 5.172252054798609e-04, {+9.228440785543659e-01, +1.181428825288093e-02}}, + Descriptor{3, 6.241363480381797e-03, {+3.207724957060760e-01, +6.366317285532444e-02}}, + Descriptor{3, 2.499541224162367e-03, {+2.145401504974506e-02, +6.762724457801919e-02}}, + Descriptor{3, 3.441345824053468e-03, {+6.529307874193767e-01, +2.014966460540852e-01}}, + Descriptor{3, 3.730857641897916e-03, {+3.810920673681604e-01, +4.858674466671989e-01}}, + Descriptor{3, 9.853795017806486e-03, {+4.141312471403079e-01, +1.907105246425098e-01}}, + Descriptor{3, 7.367579520284493e-03, {+1.431188794593187e-01, +5.103737585320696e-01}}, + Descriptor{3, 1.780487305606260e-03, {+6.816745760360433e-02, +8.035124551324651e-01}}, + Descriptor{3, 2.423131685196213e-03, {+2.297724242201254e-01, +4.121355156423638e-02}}, + Descriptor{3, 1.057340089483043e-03, {+7.821120027007296e-01, +1.776001617612250e-01}}, + Descriptor{3, 1.450363434917984e-03, {+4.764642149060935e-01, +4.843901243932818e-01}}, + Descriptor{3, 2.710579935745260e-03, {+6.655005676200287e-01, +4.796979480806327e-02}}, + Descriptor{3, 1.120145668844513e-03, {+1.575537160038546e-01, +8.010812345834409e-01}}, + Descriptor{4, 1.209171043596973e-03, {+7.476025549089913e-01, +1.335733555833585e-01, +2.410142270350212e-01}}, + Descriptor{4, 1.624713950736176e-03, {+6.402449723756475e-01, +3.697899872598127e-01, +1.069891762813818e-02}}, + Descriptor{4, 6.208589669146640e-03, {+2.772500272074544e-01, +6.588035927979838e-01, +2.398863138338967e-01}}, + Descriptor{4, 1.357245778023027e-03, {+8.843596956349281e-01, +7.690144551026831e-01, +8.514410320936129e-02}}, + Descriptor{4, 7.768823018224295e-04, {+9.543208345441746e-01, +2.756529256636570e-01, +8.471105348916165e-03}}, + Descriptor{4, 1.905388500388057e-03, {+1.961068637617923e-01, +4.881593428940726e-01, +4.956224506553615e-01}}, + Descriptor{4, 1.836355855674232e-03, {+5.253928688656228e-01, +9.036540229831336e-01, +4.642983560786509e-02}}, + Descriptor{4, 1.733122655911971e-03, {+7.871050645706265e-01, +5.305666908542513e-01, +1.965615185289643e-01}}, + Descriptor{4, 8.755868144016887e-04, {+8.730512492238405e-01, +5.824961459878540e-01, +6.875723092085683e-03}}, + Descriptor{4, 5.299199352810601e-03, {+4.953985501065977e-01, +2.191018460614218e-01, +3.867051301301994e-01}}, + Descriptor{4, 1.909231403394242e-03, {+8.695725428246946e-01, +3.055722326033879e-01, +1.089610679849025e-01}}, + Descriptor{4, 3.332703296489462e-03, {+8.255682153916121e-01, +1.820166521926553e-01, +4.416884971526350e-02}}, + Descriptor{4, 1.372582739425581e-03, {+2.263367583189702e-01, +3.553849916667940e-01, +6.248925484789940e-01}}, + Descriptor{4, 4.405628951728082e-03, {+5.513678656050841e-01, +7.486875952236592e-01, +1.172732959999338e-01}}, + Descriptor{4, 6.902657704569894e-03, {+6.416804127385760e-01, +2.589654916989230e-01, +1.195843625945489e-01}}, + Descriptor{4, 2.027344695276262e-03, {+4.862393601034299e-01, +1.128685901856588e-01, +1.562091696416078e-02}}, + Descriptor{4, 2.046435953340190e-03, {+4.272869183745079e-01, +6.283616414580556e-01, +3.513262055700426e-01}}, + Descriptor{4, 3.453264166213793e-04, {+9.787077639713484e-01, +7.341055271589447e-01, +1.323405399603627e-02}}, + Descriptor{4, 2.425089503329792e-03, {+7.058505258664157e-01, +4.135891617947305e-01, +2.986233869137579e-02}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 18: { + constexpr size_t nb_points = 357; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{1, 1.340052013254401e-04, {+9.689131877314755e-01}}, + Descriptor{2, 6.532829236534353e-03, {+7.386927583195001e-01, +1.121808531538677e-01}}, + Descriptor{2, 2.462677829860450e-03, {+7.680665730295287e-01, +2.095203731422156e-01}}, + Descriptor{2, 2.362663198775904e-03, {+3.167394480989801e-01, +4.504333920940983e-01}}, + Descriptor{2, 2.412846260195942e-03, {+6.187757221807219e-01, +3.671380924150245e-01}}, + Descriptor{2, 5.639399189884141e-03, {+3.723529440295544e-01, +5.149694555513888e-01}}, + Descriptor{2, 5.308794645373922e-03, {+5.038719357078286e-01, +2.465874064866041e-01}}, + Descriptor{2, 3.303209677609701e-03, {+7.220783650726965e-01, +3.347288009925681e-02}}, + Descriptor{2, 7.157096872930287e-03, {+3.940311335958268e-01, +1.760491594601057e-01}}, + Descriptor{2, 3.560209000799229e-03, {+1.181947980612448e-01, +1.262767090030246e-01}}, + Descriptor{2, 2.869089106153775e-03, {+5.117986204426422e-01, +1.146186842907397e-02}}, + Descriptor{2, 1.192387955426962e-03, {+9.344056049843052e-02, +8.286557181156362e-01}}, + Descriptor{2, 2.357089773027461e-04, {+9.778630528838397e-01, +4.114776635706134e-03}}, + Descriptor{2, 3.324152026523092e-03, {+2.689311802882549e-01, +6.643176008593026e-01}}, + Descriptor{2, 6.442449838790662e-04, {+1.858887671719376e-01, +8.071453164684427e-01}}, + Descriptor{3, 9.304082839731633e-04, {+8.803206212322914e-01, +6.759778909905437e-02}}, + Descriptor{3, 6.153126385517773e-04, {+6.814521213676156e-01, +2.940343113268007e-01}}, + Descriptor{3, 2.890748228612777e-04, {+4.969903643427416e-01, +4.966550809316037e-01}}, + Descriptor{3, 9.579280577883828e-03, {+3.063401808222882e-01, +2.791132054901511e-01}}, + Descriptor{3, 2.562433782912423e-03, {+5.853996645538505e-01, +7.876704807666435e-02}}, + Descriptor{3, 1.970097108482327e-03, {+7.769439547694348e-01, +4.825635484814583e-02}}, + Descriptor{3, 2.248538016231859e-03, {+1.869536840196541e-01, +8.812474861667117e-03}}, + Descriptor{3, 1.783785036670776e-03, {+6.440284406129158e-01, +2.005872107121198e-02}}, + Descriptor{3, 4.615488477875886e-04, {+1.993968440939729e-01, +7.563909496805638e-01}}, + Descriptor{3, 3.835673525848779e-03, {+4.915166272295902e-01, +1.515550593825411e-01}}, + Descriptor{3, 4.243233892689520e-03, {+2.197188373659789e-01, +6.084275881937196e-01}}, + Descriptor{3, 2.977098509258866e-03, {+3.818186027529240e-01, +5.256954545937250e-01}}, + Descriptor{3, 7.500976584211740e-03, {+1.323357443649693e-01, +4.028122600425206e-01}}, + Descriptor{3, 2.080642319051259e-03, {+2.643490668003158e-01, +4.148931197347632e-02}}, + Descriptor{3, 6.762965500915199e-03, {+2.625901672258577e-01, +1.466170076483845e-01}}, + Descriptor{3, 3.005874847678541e-03, {+6.368304996885981e-01, +2.566159742055003e-01}}, + Descriptor{3, 5.694731752763933e-03, {+5.033323003573335e-01, +2.555236724339244e-01}}, + Descriptor{3, 3.293452280749932e-03, {+4.305306648769874e-01, +3.698185671948173e-01}}, + Descriptor{3, 3.193430746935616e-03, {+4.412117799623165e-01, +1.554708555805914e-02}}, + Descriptor{3, 3.007859639579343e-03, {+1.233852653491083e-01, +4.951092940950103e-02}}, + Descriptor{3, 6.210180814260240e-03, {+2.819646674678744e-01, +4.572992412719536e-01}}, + Descriptor{3, 6.903801293936010e-03, {+1.230206594250918e-01, +2.586539281154879e-01}}, + Descriptor{3, 1.006183863763346e-04, {+9.699534085616927e-01, +1.471561063742728e-02}}, + Descriptor{3, 1.356307828233825e-04, {+1.536759742301584e-01, +8.430293850954313e-01}}, + Descriptor{3, 7.789376721955394e-04, {+3.232491600294373e-01, +6.422131631619533e-01}}, + Descriptor{3, 2.674414703364759e-03, {+7.979061002341173e-02, +7.081546894975584e-01}}, + Descriptor{3, 4.775459413065313e-04, {+5.572751587573097e-02, +9.075661676644768e-01}}, + Descriptor{3, 7.406610401180713e-04, {+8.040718007941732e-01, +1.580109891260832e-01}}, + Descriptor{3, 5.291370439452658e-03, {+1.063079492932114e-01, +5.586401442375718e-01}}, + Descriptor{3, 1.500664611055249e-03, {+1.496811655200803e-01, +7.655341121253637e-01}}, + Descriptor{3, 2.626273999362915e-03, {+7.217980235897704e-01, +1.203862817704082e-01}}, + Descriptor{4, 1.065436899176937e-03, {+8.179717082248776e-01, +6.432021548505883e-01, +1.654004245581700e-01}}, + Descriptor{4, 6.080722561497974e-03, {+4.547777230252971e-01, +1.663641899799587e-01, +7.191647566286845e-02}}, + Descriptor{4, 5.310023010585634e-03, {+2.207750902147102e-01, +6.491941928630117e-01, +2.436936622868156e-01}}, + Descriptor{4, 2.020033424832363e-03, {+8.584914437706522e-01, +2.644232091625772e-01, +3.997911405124788e-02}}, + Descriptor{4, 2.164703930837454e-03, {+1.908724705162439e-01, +4.565598584631854e-01, +5.240352269645050e-01}}, + Descriptor{4, 4.353306989152711e-03, {+3.778781661386005e-01, +6.640629325475310e-01, +6.332251756914624e-02}}, + Descriptor{4, 6.863403477821615e-04, {+8.939555664639546e-01, +1.728332917834724e-01, +6.271673653011652e-03}}, + Descriptor{4, 4.019067831153739e-03, {+4.099141505393519e-01, +5.003413197772252e-02, +3.461255047044217e-01}}, + Descriptor{4, 7.912728473970523e-04, {+9.319810865442065e-01, +1.066217398606188e-01, +4.934944134498662e-02}}, + Descriptor{4, 2.446710528967660e-03, {+2.801822060720651e-01, +8.499319598680132e-01, +1.205025919278488e-01}}, + Descriptor{4, 1.950381902056960e-03, {+5.772816541361394e-01, +4.620142974473129e-01, +3.942812057164277e-01}}, + Descriptor{4, 1.105915938820858e-03, {+8.445158080852770e-01, +6.175679175506062e-01, +8.380194537906345e-03}}, + Descriptor{4, 5.030114823747663e-03, {+5.294157289381186e-01, +2.334853358468202e-01, +3.799152175151670e-01}}, + Descriptor{4, 6.596708157003132e-04, {+9.282752180189467e-01, +6.794178627981728e-01, +6.658426856019066e-02}}, + Descriptor{4, 6.132163978139013e-04, {+9.683651638409505e-01, +4.614425143846638e-01, +1.360996700708025e-02}}, + Descriptor{4, 8.965714244660760e-04, {+1.674457184003009e-01, +3.143041479415947e-01, +6.737791163005959e-01}}, + Descriptor{4, 3.639835604771190e-03, {+4.923271845449609e-01, +7.398884292540342e-01, +1.512239686451382e-01}}, + Descriptor{4, 2.111289190280422e-03, {+8.565997422827011e-01, +5.406106561720058e-01, +5.960704457999711e-02}}, + Descriptor{4, 5.700622245430812e-03, {+2.670227736126091e-01, +5.753139352915381e-01, +1.555725209349524e-01}}, + Descriptor{4, 1.955327766010427e-03, {+4.150645766534223e-01, +7.173101873515257e-01, +2.646731283533919e-01}}, + Descriptor{4, 6.238495350617601e-04, {+9.446623957916176e-01, +8.161908018659551e-01, +1.193065095103094e-02}}, + Descriptor{4, 1.517921654020750e-03, {+7.145052262408169e-01, +3.117978322705600e-01, +7.294130256492850e-03}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 19: { + constexpr size_t nb_points = 418; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{1, 1.287002239747240e-04, {+9.673913352370350e-01}}, + Descriptor{1, 5.390761254300309e-03, {+5.436653246463873e-01}}, + Descriptor{2, 6.666871057805598e-03, {+3.736572163452879e-01, +4.188756062275946e-01}}, + Descriptor{2, 6.198011213798800e-03, {+4.375282703042845e-01, +2.977489444568584e-01}}, + Descriptor{2, 1.196903942172590e-03, {+5.578275629324269e-01, +4.363255890435926e-01}}, + Descriptor{2, 9.000351976243133e-03, {+2.727587922914985e-01, +1.312347586523022e-01}}, + Descriptor{2, 4.164637105384020e-03, {+2.887241175382593e-01, +5.688216954681572e-01}}, + Descriptor{2, 1.824497208727276e-03, {+1.127746562325076e-01, +6.623057363188606e-01}}, + Descriptor{2, 4.523718683330509e-03, {+6.547023041522421e-01, +2.196378912459858e-01}}, + Descriptor{2, 8.161116064814124e-03, {+2.229510128266209e-01, +2.273269633283456e-01}}, + Descriptor{2, 1.648326828637079e-03, {+3.517668912115330e-01, +5.417515126253033e-03}}, + Descriptor{2, 5.571492309500324e-04, {+2.069773541366567e-01, +7.929490613648335e-01}}, + Descriptor{2, 1.118215252194827e-03, {+9.311118902772667e-01, +4.180662980331772e-02}}, + Descriptor{2, 1.885810158761153e-03, {+8.430335844595135e-01, +1.361551806457953e-01}}, + Descriptor{2, 2.828101226263676e-04, {+7.303948013428374e-02, +9.187547560280617e-01}}, + Descriptor{2, 1.815863546152488e-03, {+6.780735133862854e-01, +3.019190562178010e-01}}, + Descriptor{2, 1.247082448220326e-03, {+8.819848262866421e-01, +9.387499849089011e-03}}, + Descriptor{2, 1.074162553027278e-03, {+3.858781168610365e-01, +6.065859845746238e-01}}, + Descriptor{2, 2.579770777378314e-03, {+1.370888473751836e-01, +7.535348220210553e-01}}, + Descriptor{3, 9.170154497260322e-04, {+5.255852110826873e-01, +4.408685369060898e-01}}, + Descriptor{3, 3.068778721173566e-03, {+4.530164257058980e-01, +4.188977508155631e-01}}, + Descriptor{3, 1.871058171917288e-03, {+6.712511632017596e-01, +1.251810432139165e-02}}, + Descriptor{3, 1.536909390806274e-04, {+3.695141864916882e-01, +6.246014838381103e-01}}, + Descriptor{3, 3.845290732110408e-03, {+2.883822343558625e-01, +5.439973273857342e-02}}, + Descriptor{3, 2.243116164244068e-04, {+8.285723838946580e-01, +1.619186219316668e-01}}, + Descriptor{3, 8.402087626133961e-04, {+6.724607008544720e-01, +2.930033138342824e-01}}, + Descriptor{3, 3.041957674540431e-03, {+4.873668933896256e-01, +2.634265889387019e-01}}, + Descriptor{3, 2.294841766987932e-04, {+9.503664431507984e-01, +1.127614473867753e-02}}, + Descriptor{3, 4.182420591869638e-03, {+9.132353058612172e-02, +3.580798461499961e-01}}, + Descriptor{3, 6.327091081505453e-03, {+1.552069555141659e-01, +4.714188671670859e-01}}, + Descriptor{3, 7.592834005951271e-04, {+5.052806321356114e-02, +8.544640711209540e-01}}, + Descriptor{3, 4.596836662276725e-03, {+3.978139280416619e-01, +1.293031169145601e-01}}, + Descriptor{3, 2.766364274235799e-03, {+3.760791314064199e-01, +7.899233073306565e-02}}, + Descriptor{3, 2.144850801510551e-03, {+1.643638267982826e-01, +1.672886065733771e-02}}, + Descriptor{3, 5.283144486182838e-03, {+3.468892555686117e-01, +3.885050437237611e-01}}, + Descriptor{3, 4.881052322614178e-04, {+1.191332579371944e-01, +8.475473975749326e-01}}, + Descriptor{3, 2.120695458348499e-03, {+7.454583814188197e-01, +1.626360280018163e-01}}, + Descriptor{3, 1.615060199482018e-03, {+7.610495209730348e-01, +7.862268330374027e-02}}, + Descriptor{3, 6.942257092948444e-03, {+2.420812058877188e-01, +3.202806437619411e-01}}, + Descriptor{3, 1.002683020081214e-03, {+8.445798381566891e-01, +1.382133423647079e-02}}, + Descriptor{3, 9.207753167491697e-04, {+1.645646578166248e-01, +7.687752250435795e-01}}, + Descriptor{3, 3.556169477445426e-03, {+2.747842347238860e-01, +5.301402408730526e-01}}, + Descriptor{3, 2.186178713296525e-03, {+5.849919450560005e-01, +3.008923824441204e-01}}, + Descriptor{3, 2.691651662032098e-03, {+1.489738124603387e-01, +6.167319270078593e-01}}, + Descriptor{3, 3.016740104757321e-03, {+4.389290397617306e-01, +1.376377254881576e-02}}, + Descriptor{3, 7.466645241550527e-04, {+8.798197120003726e-01, +7.210305012229555e-02}}, + Descriptor{3, 2.997482336902333e-03, {+1.168533193079235e-01, +6.238118616203953e-02}}, + Descriptor{3, 1.447847026063246e-03, {+3.428716485856084e-01, +5.855795349165888e-01}}, + Descriptor{4, 1.072809629353361e-03, {+8.643327984186001e-01, +6.422236743536752e-01, +1.179192064779849e-01}}, + Descriptor{4, 4.839037348378018e-03, {+5.784047959665971e-01, +1.570037147921136e-01, +1.114252341292851e-01}}, + Descriptor{4, 2.747099059820038e-03, {+3.108799114935293e-01, +5.391600980992765e-01, +2.750267281218793e-01}}, + Descriptor{4, 4.335016889029408e-03, {+2.047256512125053e-01, +5.650506986268603e-01, +3.472846972655921e-01}}, + Descriptor{4, 2.718100159849547e-03, {+1.547714831454746e-01, +8.008730085913268e-01, +7.549551730236130e-02}}, + Descriptor{4, 9.168547398610547e-04, {+9.112222485018308e-01, +3.619692710244549e-01, +3.464296962031117e-02}}, + Descriptor{4, 6.808951019688473e-03, {+2.376393444235864e-01, +4.605447477525737e-01, +2.044152977923567e-01}}, + Descriptor{4, 4.013856896610910e-04, {+9.302667501209977e-01, +3.215980764268125e-01, +6.972695561067982e-02}}, + Descriptor{4, 2.155002895452285e-03, {+2.733067099141755e-01, +7.541757880282322e-01, +2.199898046581558e-01}}, + Descriptor{4, 1.611542573023053e-03, {+6.197790831123378e-01, +4.009499952384629e-01, +3.646225494795918e-01}}, + Descriptor{4, 2.743455266744436e-04, {+9.673179731072893e-01, +7.175030678238746e-01, +4.586334961223785e-03}}, + Descriptor{4, 2.300082975062185e-03, {+2.810759624172646e-01, +1.446964075338812e-01, +6.664230048871306e-01}}, + Descriptor{4, 2.945835759051771e-04, {+9.572349478971794e-01, +8.054431343183734e-01, +3.975302308577006e-02}}, + Descriptor{4, 6.007312216772520e-04, {+9.341504389265958e-01, +5.642632183544610e-01, +3.073598825835916e-02}}, + Descriptor{4, 2.620175037577330e-04, {+2.212443839381749e-01, +2.763723337715620e-01, +7.207735178967332e-01}}, + Descriptor{4, 4.192832498709637e-03, {+5.144086015486090e-01, +6.711096936374128e-01, +1.403609469612069e-01}}, + Descriptor{4, 1.736294308688135e-03, {+8.466968176319485e-01, +6.476309524361428e-01, +5.264191965632582e-02}}, + Descriptor{4, 9.439101669434532e-04, {+5.837234015734821e-01, +7.587849158481068e-01, +2.270233248942167e-01}}, + Descriptor{4, 2.175513608503740e-03, {+2.312548427820351e-01, +7.579578663965916e-01, +2.881326163838643e-02}}, + Descriptor{4, 1.283394690183355e-03, {+6.535198164687628e-01, +2.118649081243290e-01, +5.321389368184961e-03}}, + Descriptor{4, 2.726150499605700e-03, {+6.953450152489690e-01, +1.860513163719893e-01, +1.591709313067350e-01}}, + Descriptor{4, 3.185339603850620e-03, {+8.127234831798691e-02, +5.241033074238067e-01, +4.286780869626788e-02}}, + Descriptor{4, 2.663092866644570e-03, {+6.731624418813449e-01, +4.707459336103425e-01, +2.281921560389168e-01}}, + Descriptor{4, 2.326668465288244e-03, {+8.297715217071255e-01, +3.845634575264398e-01, +1.149758475625305e-01}}, + Descriptor{4, 9.734631151970315e-04, {+8.530842873329166e-01, +4.855129905435616e-01, +6.546603573639168e-03}}, + Descriptor{4, 3.483456851399480e-03, {+4.467073185069126e-01, +1.775709599102257e-01, +4.889658061311413e-01}}, + Descriptor{4, 4.061954216963042e-03, {+6.700967212030146e-01, +4.619994161131860e-01, +5.843691849737929e-02}}, + Descriptor{4, 3.324559356884226e-04, {+9.767336037107472e-01, +2.679001927626974e-01, +6.104985413274207e-03}}, + Descriptor{4, 9.232817417531915e-04, {+3.188790007212526e-01, +4.538176463136764e-01, +5.340866401557672e-01}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 20: { + constexpr size_t nb_points = 489; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{1, 5.374309731479196e-03, {+6.041261328156059e-01}}, + Descriptor{2, 5.671734293778256e-03, {+4.816935434431252e-01, +1.283254121370188e-01}}, + Descriptor{2, 3.248860881724051e-03, {+6.985803886987003e-01, +2.363645279387677e-01}}, + Descriptor{2, 3.452094526682737e-03, {+5.346865795177097e-01, +3.694814396873626e-01}}, + Descriptor{2, 6.666033444769521e-04, {+4.222838087844267e-01, +5.741352229223836e-01}}, + Descriptor{2, 3.995792460381601e-03, {+3.068045188877912e-01, +5.709702769195857e-01}}, + Descriptor{2, 4.992778959530078e-03, {+2.287749849768982e-01, +4.453272633438413e-01}}, + Descriptor{2, 2.469622976420997e-03, {+5.538968741280718e-01, +1.850719926469714e-01}}, + Descriptor{2, 7.066155754130616e-03, {+3.848922804233133e-01, +2.828189872249547e-01}}, + Descriptor{2, 1.916980035371976e-03, {+2.571105687384414e-01, +7.453813550512145e-03}}, + Descriptor{2, 2.387541558193644e-04, {+9.495420833471157e-01, +2.730608888531540e-03}}, + Descriptor{2, 1.680239670130047e-04, {+9.635090648066924e-02, +8.947468307319109e-01}}, + Descriptor{2, 9.944327373233232e-04, {+9.104493126181845e-01, +5.489260378459437e-02}}, + Descriptor{2, 3.454941677138827e-03, {+2.683082435742811e-01, +1.789054761711333e-01}}, + Descriptor{2, 1.377780657771690e-03, {+8.274465668629972e-01, +1.443872792953364e-01}}, + Descriptor{2, 6.135678341459227e-05, {+3.789270083108932e-02, +9.600532902975129e-01}}, + Descriptor{2, 9.961596076112076e-04, {+5.735205240815813e-01, +4.226237395657491e-01}}, + Descriptor{2, 1.734688844684138e-03, {+7.423115722700304e-01, +9.373411784322374e-03}}, + Descriptor{2, 6.408905290179002e-04, {+2.846909641320057e-01, +7.051164480862681e-01}}, + Descriptor{2, 1.747701749929037e-03, {+1.128162795069089e-01, +8.097603763752680e-01}}, + Descriptor{3, 5.356183098283481e-04, {+4.535676239967043e-01, +5.210700225779646e-01}}, + Descriptor{3, 3.744128155669667e-03, {+3.336110385261160e-01, +4.762219126204001e-01}}, + Descriptor{3, 3.648498543938937e-03, {+3.773337527822211e-01, +4.553198949867700e-02}}, + Descriptor{3, 2.722104630492699e-04, {+3.061117491692780e-01, +6.823651677845297e-01}}, + Descriptor{3, 4.038058627934289e-03, {+2.904460076524542e-01, +3.676651830752369e-01}}, + Descriptor{3, 2.849455013152634e-03, {+5.914106884092367e-01, +3.140155892114704e-02}}, + Descriptor{3, 4.946318515118939e-04, {+7.660549649135295e-01, +2.085476317987768e-01}}, + Descriptor{3, 3.435750243515581e-03, {+4.496216926317984e-01, +3.209594399518608e-01}}, + Descriptor{3, 7.654793642697566e-04, {+6.125691075458759e-01, +3.559054105435636e-01}}, + Descriptor{3, 9.270297025443059e-05, {+9.651777563788078e-01, +1.963481046583392e-02}}, + Descriptor{3, 4.440447400598151e-03, {+1.850944308523854e-01, +5.811084832537615e-01}}, + Descriptor{3, 4.995284180274901e-03, {+1.305339914072845e-01, +2.203018355115161e-01}}, + Descriptor{3, 2.327605643441156e-03, {+8.713330755302490e-02, +7.074337461014996e-01}}, + Descriptor{3, 3.058461110576954e-03, {+1.162657955161678e-01, +4.975461839293467e-01}}, + Descriptor{3, 2.716703334283396e-04, {+3.353132384174681e-02, +9.019799487990967e-01}}, + Descriptor{3, 3.592040414552888e-03, {+6.300704464975707e-01, +1.583017481238254e-01}}, + Descriptor{3, 4.506232324626833e-03, {+1.008155351127816e-01, +3.470348929613336e-01}}, + Descriptor{3, 2.662059522271117e-04, {+9.712721271803038e-02, +8.772759077750505e-01}}, + Descriptor{3, 1.722422251895809e-03, {+6.503674461202499e-01, +2.509808878874181e-01}}, + Descriptor{3, 1.529902163082495e-03, {+7.881670555390969e-01, +1.228748706112481e-01}}, + Descriptor{3, 4.331723455652033e-03, {+4.632610253517699e-01, +2.156955721524682e-01}}, + Descriptor{3, 8.698495590594387e-04, {+8.742622562545352e-01, +4.316688220319717e-02}}, + Descriptor{3, 3.166557615941483e-03, {+9.693365579654889e-02, +1.072427543090557e-01}}, + Descriptor{3, 1.455167758465003e-03, {+5.265123436991546e-01, +3.296427782470148e-01}}, + Descriptor{3, 1.137616034931676e-03, {+2.105801835055998e-01, +7.160068077591689e-01}}, + Descriptor{3, 1.884904388466294e-03, {+4.834178601814259e-01, +4.197363107268692e-01}}, + Descriptor{3, 6.049803062524013e-03, {+2.723239805399290e-01, +1.077197094023458e-01}}, + Descriptor{3, 2.785053160390842e-04, {+8.874839070114657e-01, +9.137076099343852e-02}}, + Descriptor{3, 1.644290914957632e-03, {+3.400434017708192e-01, +5.743322455524006e-01}}, + Descriptor{3, 4.384669874639433e-03, {+2.465713452115888e-01, +2.965278956806727e-01}}, + Descriptor{3, 2.508217360325574e-03, {+7.203261185246220e-01, +6.861567128774998e-02}}, + Descriptor{4, 6.403192997163759e-04, {+8.693467247184354e-01, +6.605377674376229e-01, +1.211268750412950e-01}}, + Descriptor{4, 2.743609819133677e-03, {+5.165700364414527e-01, +1.268114432243165e-01, +6.232922095164157e-02}}, + Descriptor{4, 4.425132157331708e-03, {+2.141949283591463e-01, +5.351420520651734e-01, +2.887837560282615e-01}}, + Descriptor{4, 3.793533547619605e-03, {+3.860615525036007e-01, +1.430987462436435e-01, +4.198199632798237e-01}}, + Descriptor{4, 2.598731880891428e-03, {+3.148265223116505e-01, +5.788734905442336e-01, +3.671971633512633e-01}}, + Descriptor{4, 1.100562071404283e-03, {+1.333776220074420e-01, +8.685734808776638e-01, +3.539982573087990e-02}}, + Descriptor{4, 7.559451274546276e-04, {+8.933451426565783e-01, +2.970093961186454e-01, +6.894095497062928e-03}}, + Descriptor{4, 4.164432957175231e-03, {+6.420732128180285e-01, +2.185904390936289e-01, +1.803409782254840e-01}}, + Descriptor{4, 7.986472006319258e-04, {+9.015566925902675e-01, +2.850450105795807e-01, +8.701177937660884e-02}}, + Descriptor{4, 1.274772831709237e-03, {+1.795078173861985e-01, +6.796606097350029e-01, +3.018403418988506e-01}}, + Descriptor{4, 7.742072015194865e-04, {+5.287716454511575e-01, +3.752537914501156e-01, +4.637531647615307e-01}}, + Descriptor{4, 1.079867868775378e-03, {+8.568477683810934e-01, +7.061426122653948e-01, +1.259447070049874e-02}}, + Descriptor{4, 1.550935782403934e-03, {+2.374464971047839e-01, +9.039264484495425e-02, +6.846455484276207e-01}}, + Descriptor{4, 4.993786208816673e-04, {+9.406598770106565e-01, +7.437511960991476e-01, +4.669618994654997e-02}}, + Descriptor{4, 4.262366420646442e-04, {+9.654498557948427e-01, +5.581648667244832e-01, +9.979099797204329e-03}}, + Descriptor{4, 5.244528523523384e-04, {+1.185997715939458e-01, +1.973055345489109e-01, +7.917076093806301e-01}}, + Descriptor{4, 2.954838737142077e-03, {+4.383682874673118e-01, +6.801053445689546e-01, +2.323974680712023e-01}}, + Descriptor{4, 1.540648448261571e-03, {+8.501501583895467e-01, +5.776785987998531e-01, +6.212941698545271e-02}}, + Descriptor{4, 4.849861236258662e-03, {+4.097788353774976e-01, +5.992649167860331e-01, +1.025000747100843e-01}}, + Descriptor{4, 7.495372210984812e-04, {+6.254025057545211e-01, +7.793811396398747e-01, +1.963810536401145e-01}}, + Descriptor{4, 1.677329035907760e-03, {+1.658794771155705e-01, +6.513788165859978e-01, +3.807225396126873e-02}}, + Descriptor{4, 2.242040914713952e-03, {+5.062559144366789e-01, +2.470826877566723e-01, +9.699938299695787e-03}}, + Descriptor{4, 3.054238951987089e-03, {+7.429293632807329e-01, +1.682359345705867e-01, +8.712730173221997e-02}}, + Descriptor{4, 2.363709150448725e-03, {+1.867609649526593e-02, +2.536204599781817e-01, +4.169093747605618e-02}}, + Descriptor{4, 4.124773767916695e-03, {+2.608600527928172e-01, +4.094605558894180e-01, +1.898222236268910e-01}}, + Descriptor{4, 2.522814373870828e-03, {+7.938808312983506e-01, +4.691881899824492e-01, +1.276217397945529e-01}}, + Descriptor{4, 1.143364037200234e-03, {+7.930116554406030e-01, +2.986457776503003e-01, +1.955063271970715e-01}}, + Descriptor{4, 2.785004192577059e-03, {+4.492999606983316e-01, +1.696796572740249e-01, +4.935677375430703e-01}}, + Descriptor{4, 2.222625782566179e-03, {+7.687383145879386e-01, +3.967745055048160e-01, +3.472481178210238e-02}}, + Descriptor{4, 2.609946044201681e-04, {+9.785997597757148e-01, +1.909470577592247e-01, +1.518094278770999e-02}}, + Descriptor{4, 1.252174210689572e-03, {+2.135890927684384e-01, +3.604161529615568e-01, +6.154203152262100e-01}}, + Descriptor{4, 1.279670338642788e-03, {+7.962525773875013e-01, +1.562852697636821e-01, +1.257520475253165e-01}}, + Descriptor{4, 7.990495656729902e-04, {+9.193985656269752e-01, +4.148607451061945e-01, +4.457888016467764e-02}}, + Descriptor{4, 7.812219859741840e-04, {+5.150733025160915e-01, +6.896293007082364e-01, +3.017078195063375e-01}}, + Descriptor{4, 2.172588051809931e-04, {+9.636121389116856e-01, +8.595767942792535e-01, +5.771284380553639e-03}}, + Descriptor{4, 7.595577614438183e-04, {+7.214071149093607e-01, +4.920954370020814e-01, +2.395309192181843e-03}}}; + + fill_quadrature_points(descriptor_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 " + + std::to_string(PyramidGaussQuadrature::max_degree) + " on pyramids"); + } + } +} diff --git a/src/analysis/PyramidGaussQuadrature.hpp b/src/analysis/PyramidGaussQuadrature.hpp new file mode 100644 index 0000000000000000000000000000000000000000..b68c518040e39611a0f1670758f40563271abb11 --- /dev/null +++ b/src/analysis/PyramidGaussQuadrature.hpp @@ -0,0 +1,38 @@ +#ifndef PYRAMID_GAUSS_QUADRATURE_HPP +#define PYRAMID_GAUSS_QUADRATURE_HPP + +#include <analysis/QuadratureFormula.hpp> + +/** + * Defines Gauss quadrature on the reference pyramid element + * + * \note formulae are provided by + * + * 'High-order symmetric cubature rules for tetrahedra and pyramids' + * Jan JasĖkowiec & N. Sukumar (2020). + */ +class PyramidGaussQuadrature final : public QuadratureFormula<3> +{ + public: + constexpr static size_t max_degree = 20; + + private: + void _buildPointAndWeightLists(const size_t degree); + + public: + PyramidGaussQuadrature(PyramidGaussQuadrature&&) = default; + PyramidGaussQuadrature(const PyramidGaussQuadrature&) = default; + + private: + friend class QuadratureManager; + + explicit PyramidGaussQuadrature(const size_t degree) : QuadratureFormula<3>(QuadratureType::Gauss) + { + this->_buildPointAndWeightLists(degree); + } + + PyramidGaussQuadrature() = delete; + ~PyramidGaussQuadrature() = default; +}; + +#endif // PYRAMID_GAUSS_QUADRATURE_HPP diff --git a/src/analysis/QuadratureFormula.hpp b/src/analysis/QuadratureFormula.hpp new file mode 100644 index 0000000000000000000000000000000000000000..c472e3556a298d14df73d1cb45a8d32c9fe6dc28 --- /dev/null +++ b/src/analysis/QuadratureFormula.hpp @@ -0,0 +1,63 @@ +#ifndef QUADRATURE_FORMULA_HPP +#define QUADRATURE_FORMULA_HPP + +#include <algebra/TinyVector.hpp> +#include <analysis/QuadratureType.hpp> +#include <utils/PugsAssert.hpp> +#include <utils/PugsMacros.hpp> +#include <utils/SmallArray.hpp> + +template <size_t Dimension> +class QuadratureFormula +{ + public: + protected: + QuadratureType m_type; + SmallArray<const TinyVector<Dimension>> m_point_list; + SmallArray<const double> m_weight_list; + + public: + PUGS_INLINE size_t + numberOfPoints() const + { + Assert(m_point_list.size() == m_weight_list.size()); + return m_point_list.size(); + } + + PUGS_INLINE + const SmallArray<const TinyVector<Dimension>>& + pointList() const + { + return m_point_list; + } + + PUGS_INLINE + const TinyVector<Dimension>& + point(const size_t i) const + { + return m_point_list[i]; + } + + PUGS_INLINE + const SmallArray<const double>& + weightList() const + { + return m_weight_list; + } + + PUGS_INLINE + const double& + weight(const size_t i) const + { + return m_weight_list[i]; + } + + protected: + explicit QuadratureFormula(const QuadratureType type) : m_type{type} {} + + public: + QuadratureFormula() = default; + virtual ~QuadratureFormula() = default; +}; + +#endif // QUADRATURE_FORMULA_HPP diff --git a/src/analysis/QuadratureManager.cpp b/src/analysis/QuadratureManager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ca63299d184197d3a63168b87111646aec9bf5b7 --- /dev/null +++ b/src/analysis/QuadratureManager.cpp @@ -0,0 +1,194 @@ +#include <analysis/QuadratureManager.hpp> + +#include <analysis/CubeGaussQuadrature.hpp> +#include <analysis/PrismGaussQuadrature.hpp> +#include <analysis/PyramidGaussQuadrature.hpp> +#include <analysis/SquareGaussQuadrature.hpp> +#include <analysis/TensorialGaussLegendreQuadrature.hpp> +#include <analysis/TensorialGaussLobattoQuadrature.hpp> +#include <analysis/TetrahedronGaussQuadrature.hpp> +#include <analysis/TriangleGaussQuadrature.hpp> + +QuadratureManager* QuadratureManager::s_instance{nullptr}; + +void +QuadratureManager::create() +{ + Assert(s_instance == nullptr, "QuadratureManager is already created"); + s_instance = new QuadratureManager; +} + +void +QuadratureManager::destroy() +{ + Assert(s_instance != nullptr, "QuadratureManager was not created!"); + + delete s_instance; + s_instance = nullptr; +} + +Array<const QuadratureFormula<1>> +QuadratureManager::_buildLineGaussLegendreFormulaList() +{ + Array<QuadratureFormula<1>> line_gauss_legendre_formula_list(TensorialGaussLegendreQuadrature<1>::max_degree / 2 + 1); + for (size_t i = 0; i < TensorialGaussLegendreQuadrature<1>::max_degree / 2 + 1; ++i) { + line_gauss_legendre_formula_list[i] = TensorialGaussLegendreQuadrature<1>(2 * i + 1); + } + + return line_gauss_legendre_formula_list; +} + +Array<const QuadratureFormula<1>> +QuadratureManager::_buildLineGaussLobattoFormulaList() +{ + Array<QuadratureFormula<1>> line_gauss_lobatto_formula_list(TensorialGaussLobattoQuadrature<1>::max_degree / 2 + 1); + for (size_t i = 0; i < TensorialGaussLobattoQuadrature<1>::max_degree / 2 + 1; ++i) { + line_gauss_lobatto_formula_list[i] = TensorialGaussLobattoQuadrature<1>(2 * i + 1); + } + + return line_gauss_lobatto_formula_list; +} + +Array<const QuadratureFormula<2>> +QuadratureManager::_buildSquareGaussFormulaList() +{ + Array<QuadratureFormula<2>> square_gauss_formula_list(SquareGaussQuadrature::max_degree / 2 + 1); + for (size_t i = 0; i < SquareGaussQuadrature::max_degree / 2 + 1; ++i) { + square_gauss_formula_list[i] = SquareGaussQuadrature(2 * i + 1); + } + + return square_gauss_formula_list; +} + +Array<const QuadratureFormula<2>> +QuadratureManager::_buildSquareGaussLegendreFormulaList() +{ + Array<QuadratureFormula<2>> square_gauss_legendre_formula_list(TensorialGaussLegendreQuadrature<2>::max_degree / 2 + + 1); + for (size_t i = 0; i < TensorialGaussLegendreQuadrature<2>::max_degree / 2 + 1; ++i) { + square_gauss_legendre_formula_list[i] = TensorialGaussLegendreQuadrature<2>(2 * i + 1); + } + + return square_gauss_legendre_formula_list; +} + +Array<const QuadratureFormula<2>> +QuadratureManager::_buildSquareGaussLobattoFormulaList() +{ + Array<QuadratureFormula<2>> square_gauss_lobatto_formula_list(TensorialGaussLobattoQuadrature<2>::max_degree / 2 + 1); + for (size_t i = 0; i < TensorialGaussLobattoQuadrature<2>::max_degree / 2 + 1; ++i) { + square_gauss_lobatto_formula_list[i] = TensorialGaussLobattoQuadrature<2>(2 * i + 1); + } + + return square_gauss_lobatto_formula_list; +} + +Array<const QuadratureFormula<2>> +QuadratureManager::_buildTriangleGaussFormulaList() +{ + Array<QuadratureFormula<2>> triangle_gauss_formula_list(TriangleGaussQuadrature::max_degree); + for (size_t i = 0; i < TriangleGaussQuadrature::max_degree; ++i) { + triangle_gauss_formula_list[i] = TriangleGaussQuadrature(i + 1); + } + + return triangle_gauss_formula_list; +} + +Array<const QuadratureFormula<3>> +QuadratureManager::_buildCubeGaussFormulaList() +{ + Array<QuadratureFormula<3>> cube_gauss_formula_list(CubeGaussQuadrature::max_degree / 2 + 1); + for (size_t i = 0; i < CubeGaussQuadrature::max_degree / 2 + 1; ++i) { + cube_gauss_formula_list[i] = CubeGaussQuadrature(2 * i + 1); + } + + return cube_gauss_formula_list; +} + +Array<const QuadratureFormula<3>> +QuadratureManager::_buildCubeGaussLegendreFormulaList() +{ + Array<QuadratureFormula<3>> cube_gauss_legendre_formula_list(TensorialGaussLegendreQuadrature<3>::max_degree / 2 + 1); + for (size_t i = 0; i < TensorialGaussLegendreQuadrature<3>::max_degree / 2 + 1; ++i) { + cube_gauss_legendre_formula_list[i] = TensorialGaussLegendreQuadrature<3>(2 * i + 1); + } + + return cube_gauss_legendre_formula_list; +} + +Array<const QuadratureFormula<3>> +QuadratureManager::_buildCubeGaussLobattoFormulaList() +{ + Array<QuadratureFormula<3>> cube_gauss_lobatto_formula_list(TensorialGaussLobattoQuadrature<3>::max_degree / 2 + 1); + for (size_t i = 0; i < TensorialGaussLobattoQuadrature<3>::max_degree / 2 + 1; ++i) { + cube_gauss_lobatto_formula_list[i] = TensorialGaussLobattoQuadrature<3>(2 * i + 1); + } + + return cube_gauss_lobatto_formula_list; +} + +Array<const QuadratureFormula<3>> +QuadratureManager::_buildPrismGaussFormulaList() +{ + Array<QuadratureFormula<3>> prism_gauss_formula_list(PrismGaussQuadrature::max_degree); + for (size_t i = 0; i < PrismGaussQuadrature::max_degree; ++i) { + prism_gauss_formula_list[i] = PrismGaussQuadrature(i + 1); + } + + return prism_gauss_formula_list; +} + +Array<const QuadratureFormula<3>> +QuadratureManager::_buildPyramidGaussFormulaList() +{ + Array<QuadratureFormula<3>> pyramid_gauss_formula_list(PyramidGaussQuadrature::max_degree); + for (size_t i = 0; i < PyramidGaussQuadrature::max_degree; ++i) { + pyramid_gauss_formula_list[i] = PyramidGaussQuadrature(i + 1); + } + + return pyramid_gauss_formula_list; +} + +Array<const QuadratureFormula<3>> +QuadratureManager::_buildTetrahedronGaussFormulaList() +{ + Array<QuadratureFormula<3>> tetrahedron_gauss_formula_list(TetrahedronGaussQuadrature::max_degree); + for (size_t i = 0; i < TetrahedronGaussQuadrature::max_degree; ++i) { + tetrahedron_gauss_formula_list[i] = TetrahedronGaussQuadrature(i + 1); + } + + return tetrahedron_gauss_formula_list; +} + +QuadratureManager::QuadratureManager() + : m_line_gauss_legendre_formula_list{this->_buildLineGaussLegendreFormulaList()}, + m_line_gauss_lobatto_formula_list{this->_buildLineGaussLobattoFormulaList()}, + // + m_square_gauss_formula_list{this->_buildSquareGaussFormulaList()}, + m_square_gauss_legendre_formula_list{this->_buildSquareGaussLegendreFormulaList()}, + m_square_gauss_lobatto_formula_list{this->_buildSquareGaussLobattoFormulaList()}, + m_triangle_gauss_formula_list{this->_buildTriangleGaussFormulaList()}, + // + m_cube_gauss_formula_list{this->_buildCubeGaussFormulaList()}, + m_cube_gauss_legendre_formula_list{this->_buildCubeGaussLegendreFormulaList()}, + m_cube_gauss_lobatto_formula_list{this->_buildCubeGaussLobattoFormulaList()}, + m_prism_gauss_formula_list{this->_buildPrismGaussFormulaList()}, + m_pyramid_gauss_formula_list{this->_buildPyramidGaussFormulaList()}, + m_tetrahedron_gauss_formula_list{this->_buildTetrahedronGaussFormulaList()} +{ + Assert(m_line_gauss_legendre_formula_list.size() * 2 - 1 == TensorialGaussLegendreQuadrature<1>::max_degree); + Assert(m_square_gauss_legendre_formula_list.size() * 2 - 1 == TensorialGaussLegendreQuadrature<2>::max_degree); + Assert(m_cube_gauss_legendre_formula_list.size() * 2 - 1 == TensorialGaussLegendreQuadrature<3>::max_degree); + + Assert(m_line_gauss_lobatto_formula_list.size() * 2 - 1 == TensorialGaussLobattoQuadrature<1>::max_degree); + Assert(m_square_gauss_lobatto_formula_list.size() * 2 - 1 == TensorialGaussLobattoQuadrature<2>::max_degree); + Assert(m_cube_gauss_lobatto_formula_list.size() * 2 - 1 == TensorialGaussLobattoQuadrature<3>::max_degree); + + Assert(m_square_gauss_formula_list.size() * 2 - 1 == SquareGaussQuadrature::max_degree); + Assert(m_triangle_gauss_formula_list.size() == TriangleGaussQuadrature::max_degree); + + Assert(m_cube_gauss_formula_list.size() * 2 - 1 == CubeGaussQuadrature::max_degree); + Assert(m_prism_gauss_formula_list.size() == PrismGaussQuadrature::max_degree); + Assert(m_pyramid_gauss_formula_list.size() == PyramidGaussQuadrature::max_degree); + Assert(m_tetrahedron_gauss_formula_list.size() == TetrahedronGaussQuadrature::max_degree); +} diff --git a/src/analysis/QuadratureManager.hpp b/src/analysis/QuadratureManager.hpp new file mode 100644 index 0000000000000000000000000000000000000000..b0f81c543c0612181cc5728b2c7ef36fc1e25515 --- /dev/null +++ b/src/analysis/QuadratureManager.hpp @@ -0,0 +1,282 @@ +#ifndef QUADRATURE_MANAGER_HPP +#define QUADRATURE_MANAGER_HPP + +#include <analysis/IQuadratureDescriptor.hpp> +#include <analysis/QuadratureFormula.hpp> +#include <utils/Array.hpp> +#include <utils/Exceptions.hpp> +#include <utils/PugsAssert.hpp> +#include <utils/PugsMacros.hpp> + +class QuadratureManager +{ + private: + static QuadratureManager* s_instance; + + Array<const QuadratureFormula<1>> m_line_gauss_legendre_formula_list; + Array<const QuadratureFormula<1>> m_line_gauss_lobatto_formula_list; + + Array<const QuadratureFormula<2>> m_square_gauss_formula_list; + Array<const QuadratureFormula<2>> m_square_gauss_legendre_formula_list; + Array<const QuadratureFormula<2>> m_square_gauss_lobatto_formula_list; + Array<const QuadratureFormula<2>> m_triangle_gauss_formula_list; + + Array<const QuadratureFormula<3>> m_cube_gauss_formula_list; + Array<const QuadratureFormula<3>> m_cube_gauss_legendre_formula_list; + Array<const QuadratureFormula<3>> m_cube_gauss_lobatto_formula_list; + Array<const QuadratureFormula<3>> m_prism_gauss_formula_list; + Array<const QuadratureFormula<3>> m_pyramid_gauss_formula_list; + Array<const QuadratureFormula<3>> m_tetrahedron_gauss_formula_list; + + Array<const QuadratureFormula<1>> _buildLineGaussLobattoFormulaList(); + Array<const QuadratureFormula<1>> _buildLineGaussLegendreFormulaList(); + + Array<const QuadratureFormula<2>> _buildSquareGaussFormulaList(); + Array<const QuadratureFormula<2>> _buildSquareGaussLegendreFormulaList(); + Array<const QuadratureFormula<2>> _buildSquareGaussLobattoFormulaList(); + Array<const QuadratureFormula<2>> _buildTriangleGaussFormulaList(); + + Array<const QuadratureFormula<3>> _buildCubeGaussFormulaList(); + Array<const QuadratureFormula<3>> _buildCubeGaussLegendreFormulaList(); + Array<const QuadratureFormula<3>> _buildCubeGaussLobattoFormulaList(); + Array<const QuadratureFormula<3>> _buildPrismGaussFormulaList(); + Array<const QuadratureFormula<3>> _buildPyramidGaussFormulaList(); + Array<const QuadratureFormula<3>> _buildTetrahedronGaussFormulaList(); + + public: + const QuadratureFormula<1>& + getLineFormula(const IQuadratureDescriptor& quadrature_descriptor) const + { + switch (quadrature_descriptor.type()) { + case QuadratureType::Gauss: + case QuadratureType::GaussLegendre: { + return m_line_gauss_legendre_formula_list[quadrature_descriptor.degree() / 2]; + break; + } + case QuadratureType::GaussLobatto: { + return m_line_gauss_lobatto_formula_list[quadrature_descriptor.degree() / 2]; + } + default: { + throw UnexpectedError("invalid quadrature type"); + } + } + } + + const QuadratureFormula<2>& + getTriangleFormula(const IQuadratureDescriptor& quadrature_descriptor) const + { + switch (quadrature_descriptor.type()) { + case QuadratureType::Gauss: { + return m_triangle_gauss_formula_list[quadrature_descriptor.degree() - 1]; + } + default: { + throw UnexpectedError(quadrature_descriptor.name() + " is not defined on triangles"); + } + } + } + + const QuadratureFormula<2>& + getSquareFormula(const IQuadratureDescriptor& quadrature_descriptor) const + { + switch (quadrature_descriptor.type()) { + case QuadratureType::Gauss: { + return m_square_gauss_formula_list[quadrature_descriptor.degree() / 2]; + } + case QuadratureType::GaussLegendre: { + return m_square_gauss_legendre_formula_list[quadrature_descriptor.degree() / 2]; + } + case QuadratureType::GaussLobatto: { + return m_square_gauss_lobatto_formula_list[quadrature_descriptor.degree() / 2]; + } + default: { + throw UnexpectedError("invalid quadrature type"); + } + } + } + + const QuadratureFormula<3>& + getTetrahedronFormula(const IQuadratureDescriptor& quadrature_descriptor) const + { + switch (quadrature_descriptor.type()) { + case QuadratureType::Gauss: { + return m_tetrahedron_gauss_formula_list[quadrature_descriptor.degree() - 1]; + } + default: { + throw UnexpectedError(quadrature_descriptor.name() + " is not defined on tetrahedron"); + } + } + } + + const QuadratureFormula<3>& + getPrismFormula(const IQuadratureDescriptor& quadrature_descriptor) const + { + switch (quadrature_descriptor.type()) { + case QuadratureType::Gauss: { + return m_prism_gauss_formula_list[quadrature_descriptor.degree() - 1]; + } + default: { + throw UnexpectedError(quadrature_descriptor.name() + " is not defined on prism"); + } + } + } + + const QuadratureFormula<3>& + getPyramidFormula(const IQuadratureDescriptor& quadrature_descriptor) const + { + switch (quadrature_descriptor.type()) { + case QuadratureType::Gauss: { + return m_pyramid_gauss_formula_list[quadrature_descriptor.degree() - 1]; + } + default: { + throw UnexpectedError(quadrature_descriptor.name() + " is not defined on pyramid"); + } + } + } + + const QuadratureFormula<3>& + getCubeFormula(const IQuadratureDescriptor& quadrature_descriptor) const + { + switch (quadrature_descriptor.type()) { + case QuadratureType::Gauss: { + return m_cube_gauss_formula_list[quadrature_descriptor.degree() / 2]; + } + case QuadratureType::GaussLegendre: { + return m_cube_gauss_legendre_formula_list[quadrature_descriptor.degree() / 2]; + break; + } + case QuadratureType::GaussLobatto: { + return m_cube_gauss_lobatto_formula_list[quadrature_descriptor.degree() / 2]; + } + default: { + throw UnexpectedError("invalid quadrature type"); + } + } + } + + size_t + maxLineDegree(const QuadratureType type) const + { + switch (type) { + case QuadratureType::Gauss: + case QuadratureType::GaussLegendre: { + return m_line_gauss_legendre_formula_list.size() * 2 - 1; + } + case QuadratureType::GaussLobatto: { + return m_line_gauss_lobatto_formula_list.size() * 2 - 1; + } + default: { + throw UnexpectedError("invalid quadrature type"); + } + } + } + + size_t + maxSquareDegree(const QuadratureType type) const + { + switch (type) { + case QuadratureType::Gauss: { + return m_square_gauss_formula_list.size() * 2 - 1; + } + case QuadratureType::GaussLegendre: { + return m_square_gauss_legendre_formula_list.size() * 2 - 1; + } + case QuadratureType::GaussLobatto: { + return m_square_gauss_lobatto_formula_list.size() * 2 - 1; + } + default: { + throw UnexpectedError("invalid quadrature type"); + } + } + } + + size_t + maxTriangleDegree(const QuadratureType type) const + { + switch (type) { + case QuadratureType::Gauss: { + return m_triangle_gauss_formula_list.size(); + } + default: { + throw UnexpectedError(name(type) + " is not defined on triangle"); + } + } + } + + size_t + maxCubeDegree(const QuadratureType type) const + { + switch (type) { + case QuadratureType::Gauss: { + return m_cube_gauss_formula_list.size() * 2 - 1; + } + case QuadratureType::GaussLegendre: { + return m_cube_gauss_legendre_formula_list.size() * 2 - 1; + } + case QuadratureType::GaussLobatto: { + return m_cube_gauss_lobatto_formula_list.size() * 2 - 1; + } + default: { + throw UnexpectedError("invalid quadrature type"); + } + } + } + + size_t + maxPrismDegree(const QuadratureType type) const + { + switch (type) { + case QuadratureType::Gauss: { + return m_prism_gauss_formula_list.size(); + } + default: { + throw UnexpectedError(::name(type) + " is not defined on prism"); + } + } + } + + size_t + maxPyramidDegree(const QuadratureType type) const + { + switch (type) { + case QuadratureType::Gauss: { + return m_pyramid_gauss_formula_list.size(); + } + default: { + throw UnexpectedError(::name(type) + " is not defined on pyramid"); + } + } + } + + size_t + maxTetrahedronDegree(const QuadratureType type) const + { + switch (type) { + case QuadratureType::Gauss: { + return m_tetrahedron_gauss_formula_list.size(); + } + default: { + throw UnexpectedError(::name(type) + " is not defined on tetrahedron"); + } + } + } + + static void create(); + static void destroy(); + + PUGS_INLINE + static const QuadratureManager& + instance() + { + Assert(s_instance != nullptr, "QuadratureManager was not created!"); + return *s_instance; + } + + private: + QuadratureManager(const QuadratureManager&) = delete; + QuadratureManager(QuadratureManager&&) = delete; + + QuadratureManager(); + ~QuadratureManager() = default; +}; + +#endif // QUADRATURE_MANAGER_HPP diff --git a/src/analysis/QuadratureType.hpp b/src/analysis/QuadratureType.hpp new file mode 100644 index 0000000000000000000000000000000000000000..1c67daa0daec9f4692e909194a5f2861245f0c7a --- /dev/null +++ b/src/analysis/QuadratureType.hpp @@ -0,0 +1,36 @@ +#ifndef QUADRATURE_TYPE_HPP +#define QUADRATURE_TYPE_HPP + +#include <utils/Exceptions.hpp> +#include <utils/PugsMacros.hpp> + +#include <string> + +enum class QuadratureType +{ + Gauss = 0, + GaussLegendre = 1, + GaussLobatto = 2, +}; + +PUGS_INLINE +std::string +name(QuadratureType type) +{ + switch (type) { + case QuadratureType::Gauss: { + return "Gauss"; + } + case QuadratureType::GaussLegendre: { + return "Gauss-Legendre"; + } + case QuadratureType::GaussLobatto: { + return "Gauss-Lobatto"; + } + default: { + throw UnexpectedError("unknown quadrature type name"); + } + } +} + +#endif // QUADRATURE_TYPE_HPP diff --git a/src/analysis/SquareGaussQuadrature.cpp b/src/analysis/SquareGaussQuadrature.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f0df6af9f2cbbc23318e861403dbaadaa844d749 --- /dev/null +++ b/src/analysis/SquareGaussQuadrature.cpp @@ -0,0 +1,327 @@ +#include <analysis/SquareGaussQuadrature.hpp> +#include <utils/Exceptions.hpp> + +void +SquareGaussQuadrature::_buildPointAndWeightLists(const size_t degree) +{ + using R2 = TinyVector<2>; + + struct Descriptor + { + int id; + double weight; + std::vector<double> lambda_list; + }; + + auto fill_quadrature_points = [](auto descriptor_list, auto& point_list, auto& weight_list) { + Assert(point_list.size() == weight_list.size()); + + size_t k = 0; + for (size_t i = 0; i < descriptor_list.size(); ++i) { + const auto [id, w, position_list] = descriptor_list[i]; + + switch (id) { + case 1: { + Assert(position_list.size() == 0); + + point_list[k] = {0, 0}; + weight_list[k] = w; + + k += 1; + break; + } + case 2: { + Assert(position_list.size() == 1); + const double& a = position_list[0]; + + point_list[k + 0] = {+a, 0}; + point_list[k + 1] = {-a, 0}; + point_list[k + 2] = {0, +a}; + point_list[k + 3] = {0, -a}; + + for (size_t l = 0; l < 4; ++l) { + weight_list[k + l] = w; + } + + k += 4; + break; + } + case 3: { + Assert(position_list.size() == 1); + const double& a = position_list[0]; + + point_list[k + 0] = {+a, +a}; + point_list[k + 1] = {+a, -a}; + point_list[k + 2] = {-a, +a}; + point_list[k + 3] = {-a, -a}; + + for (size_t l = 0; l < 4; ++l) { + weight_list[k + l] = w; + } + + k += 4; + break; + } + case 4: { + Assert(position_list.size() == 2); + const double& a = position_list[0]; + const double& b = position_list[1]; + + point_list[k + 0] = {+a, +b}; + point_list[k + 1] = {+a, -b}; + point_list[k + 2] = {-a, +b}; + point_list[k + 3] = {-a, -b}; + point_list[k + 4] = {+b, +a}; + point_list[k + 5] = {+b, -a}; + point_list[k + 6] = {-b, +a}; + point_list[k + 7] = {-b, -a}; + + for (size_t l = 0; l < 8; ++l) { + weight_list[k + l] = w; + } + + k += 8; + break; + } + // LCOV_EXCL_START + default: { + throw UnexpectedError("invalid quadrature id"); + } + // LCOV_EXCL_STOP + } + } + + Assert(k == point_list.size(), "invalid number of quadrature points"); + }; + + switch (degree) { + case 0: + case 1: { + constexpr size_t nb_points = 1; + SmallArray<R2> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{1, 4.000000000000000e+00, {}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 2: + case 3: { + constexpr size_t nb_points = 4; + SmallArray<R2> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{3, 1.000000000000000e+00, {5.773502691896257e-01}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 4: + case 5: { + constexpr size_t nb_points = 8; + SmallArray<R2> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{2, 8.163265306122449e-01, {6.831300510639732e-01}}, + Descriptor{3, 1.836734693877551e-01, {8.819171036881969e-01}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 6: + case 7: { + constexpr size_t nb_points = 12; + SmallArray<R2> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{2, 2.419753086419753e-01, {9.258200997725514e-01}}, + Descriptor{3, 2.374317746906302e-01, {8.059797829185987e-01}}, + Descriptor{3, 5.205929166673945e-01, {3.805544332083157e-01}}}; + + fill_quadrature_points(descriptor_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 descriptor_list = // + {Descriptor{2, 4.541639606867490e-01, {4.889268569743691e-01}}, + Descriptor{3, 4.273123186577577e-02, {9.396552580968377e-01}}, + Descriptor{3, 2.142003609268616e-01, {6.908805504863439e-01}}, + Descriptor{4, 1.444522232603068e-01, {9.186204410567222e-01, 3.448720253644036e-01}}}; + + fill_quadrature_points(descriptor_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 = 28; + SmallArray<R2> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{2, 2.174004398687120e-01, {7.146178296646060e-01}}, + Descriptor{3, 2.772741029838511e-01, {2.736572101714596e-01}}, + Descriptor{3, 2.139336378782481e-01, {6.366039322123010e-01}}, + Descriptor{4, 4.407456911498309e-02, {9.516303887840335e-01, 8.155654336896384e-01}}, + Descriptor{4, 1.016213405196113e-01, {3.462072000476454e-01, 9.355678714875911e-01}}}; + + fill_quadrature_points(descriptor_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 = 37; + SmallArray<R2> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{1, 2.999933443589096e-01, {}}, + Descriptor{2, 3.812862534985274e-02, {9.834613326132455e-01}}, + Descriptor{2, 1.845354689698072e-01, {6.398614183671097e-01}}, + Descriptor{3, 3.950714064745244e-02, {9.187784880797114e-01}}, + Descriptor{3, 2.313985194006854e-01, {3.796285051867438e-01}}, + Descriptor{3, 1.372420967130035e-01, {6.995542165133511e-01}}, + Descriptor{4, 3.351978005038143e-02, {6.435973749966181e-01, 9.750688839059836e-01}}, + Descriptor{4, 1.135751263643542e-01, {3.335398811647831e-01, 8.644276092670619e-01}}}; + + fill_quadrature_points(descriptor_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 = 48; + SmallArray<R2> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{2, 1.149329272635254e-01, {7.980989878970071e-01}}, + Descriptor{2, 1.816857589672718e-01, {3.038530263984597e-01}}, + Descriptor{3, 4.123848378876581e-02, {8.824222701068853e-01}}, + Descriptor{3, 5.933746485839221e-03, {9.777897995399027e-01}}, + Descriptor{4, 1.011491434774324e-01, {8.087121358195035e-01, 5.672135733965907e-01}}, + Descriptor{4, 1.478367216328812e-01, {3.046547990370526e-01, 5.787361940358066e-01}}, + Descriptor{4, 2.327319414467321e-02, {9.805048437245319e-01, 6.974636319909671e-01}}, + Descriptor{4, 5.584548249231202e-02, {2.648441558723162e-01, 9.557425198095117e-01}}}; + + fill_quadrature_points(descriptor_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 descriptor_list = // + {Descriptor{2, 1.388043776872199e-01, {5.450429872091483e-01}}, + Descriptor{2, 6.534782380746491e-02, {9.174971882191532e-01}}, + Descriptor{3, 1.428564196221996e-01, {1.925542426140469e-01}}, + Descriptor{3, 3.671590848525151e-02, {8.713286846954432e-01}}, + Descriptor{3, 8.625569963814381e-02, {6.943880900895507e-01}}, + Descriptor{3, 1.345562732119169e-01, {4.576829928831555e-01}}, + Descriptor{3, 7.655633414909936e-03, {9.692042560915087e-01}}, + Descriptor{4, 1.031767247849354e-01, {7.620882760801982e-01, 2.794777667151921e-01}}, + Descriptor{4, 5.482640023729144e-02, {9.073943521982236e-01, 5.468986704143101e-01}}, + Descriptor{4, 1.511981038825686e-02, {7.612486664390827e-01, 9.837879715015495e-01}}, + Descriptor{4, 2.078099665596304e-02, {9.870947070447679e-01, 3.028074817888614e-01}}}; + + fill_quadrature_points(descriptor_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 descriptor_list = // + {Descriptor{2, 9.773736469282875e-02, {7.143442595727942e-01}}, + Descriptor{2, 1.393076129224823e-01, {2.656720521209637e-01}}, + Descriptor{2, 3.486958349188791e-02, {9.644342692579673e-01}}, + Descriptor{3, 4.780454716279579e-02, {8.033797294676850e-01}}, + Descriptor{3, 1.617715177911761e-03, {9.921654058971348e-01}}, + Descriptor{3, 1.744104803435576e-02, {9.294496027996094e-01}}, + Descriptor{4, 1.177258328400561e-01, {5.102782573693434e-01, 2.666403145945622e-01}}, + Descriptor{4, 1.617957761165785e-02, {3.907342057752498e-01, 9.878929331417353e-01}}, + Descriptor{4, 8.284661898340490e-02, {7.171679213097452e-01, 5.124918772160977e-01}}, + Descriptor{4, 6.498908149259605e-02, {2.654400078112960e-01, 8.689024341545042e-01}}, + Descriptor{4, 3.898055239641054e-02, {6.200353986932564e-01, 9.263029558071293e-01}}, + Descriptor{4, 9.889400934743484e-03, {8.016715847185969e-01, 9.884465306839737e-01}}}; + + fill_quadrature_points(descriptor_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 = 85; + SmallArray<R2> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{1, 1.351928403561428e-01, {}}, + Descriptor{2, 1.067941587859404e-01, {4.733510743582242e-01}}, + Descriptor{2, 6.625720800494439e-02, {8.352784297558683e-01}}, + Descriptor{3, 1.198844836463405e-01, {2.573719006072290e-01}}, + Descriptor{3, 8.229461289220009e-03, {9.633378321156234e-01}}, + Descriptor{3, 3.060364092877565e-02, {8.624519253796515e-01}}, + Descriptor{3, 9.679179189359521e-02, {4.968979625193457e-01}}, + Descriptor{3, 6.151634148131656e-02, {7.043321751954006e-01}}, + Descriptor{4, 8.672849951320823e-02, {2.418781854767020e-01, 6.741462199553178e-01}}, + Descriptor{4, 5.587911740412735e-02, {4.801569663127951e-01, 8.246473752709207e-01}}, + Descriptor{4, 3.712882744091382e-02, {9.322419359217540e-01, 2.706991841016649e-01}}, + Descriptor{4, 2.877560085102053e-02, {9.349023258240106e-01, 6.750395674370753e-01}}, + Descriptor{4, 1.150952044249317e-02, {9.904554675295242e-01, 4.889162511771669e-01}}, + Descriptor{4, 7.528482130401646e-03, {8.311352459759014e-01, 9.889606113865724e-01}}, + Descriptor{4, 1.051230415825108e-02, {9.146960092229130e-02, 9.840171484895990e-01}}}; + + fill_quadrature_points(descriptor_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 " + + std::to_string(SquareGaussQuadrature::max_degree) + " on squares"); + } + } +} diff --git a/src/analysis/SquareGaussQuadrature.hpp b/src/analysis/SquareGaussQuadrature.hpp new file mode 100644 index 0000000000000000000000000000000000000000..71ea25a7a7f25c65f862fbddc92f31f4d5057fa4 --- /dev/null +++ b/src/analysis/SquareGaussQuadrature.hpp @@ -0,0 +1,39 @@ +#ifndef SQUARE_GAUSS_QUADRATURE_HPP +#define SQUARE_GAUSS_QUADRATURE_HPP + +#include <analysis/QuadratureFormula.hpp> + +/** + * Defines Square Gauss quadrature on the reference element + * \f$]-1,1[^2\f$ + * + * \note formulae are provided by + * + * âOn the identification of symmetric quadrature rules for finite + * element methodsâ by F.D. Witherden & P.E. Vincent (2015). + */ +class SquareGaussQuadrature final : public QuadratureFormula<2> +{ + public: + constexpr static size_t max_degree = 21; + + private: + void _buildPointAndWeightLists(const size_t degree); + + public: + SquareGaussQuadrature(SquareGaussQuadrature&&) = default; + SquareGaussQuadrature(const SquareGaussQuadrature&) = default; + + private: + friend class QuadratureManager; + + explicit SquareGaussQuadrature(const size_t degree) : QuadratureFormula<2>(QuadratureType::Gauss) + { + this->_buildPointAndWeightLists(degree); + } + + SquareGaussQuadrature() = delete; + ~SquareGaussQuadrature() = default; +}; + +#endif // SQUARE_GAUSS_QUADRATURE_HPP diff --git a/src/analysis/TensorialGaussLegendreQuadrature.cpp b/src/analysis/TensorialGaussLegendreQuadrature.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9a4b524c0f70cbc3a68088bd5b14ad17d6c521ea --- /dev/null +++ b/src/analysis/TensorialGaussLegendreQuadrature.cpp @@ -0,0 +1,292 @@ +#include <analysis/TensorialGaussLegendreQuadrature.hpp> +#include <utils/Exceptions.hpp> + +template <> +void +TensorialGaussLegendreQuadrature<1>::_buildPointAndWeightLists(const size_t degree) +{ + const size_t nb_points = degree / 2 + 1; + + SmallArray<TinyVector<1>> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + switch (degree) { + case 0: + case 1: { + point_list[0] = 0; + + weight_list[0] = 2; + break; + } + case 2: + case 3: { + point_list[0] = -0.5773502691896257645091488; + point_list[1] = +0.5773502691896257645091488; + + weight_list[0] = 1; + weight_list[1] = 1; + break; + } + case 4: + case 5: { + point_list[0] = -0.7745966692414833770358531; + point_list[1] = 0; + point_list[2] = +0.7745966692414833770358531; + + weight_list[0] = 0.5555555555555555555555556; + weight_list[1] = 0.8888888888888888888888889; + weight_list[2] = 0.5555555555555555555555556; + break; + } + case 6: + case 7: { + point_list[0] = -0.8611363115940525752239465; + point_list[1] = -0.3399810435848562648026658; + point_list[2] = +0.3399810435848562648026658; + point_list[3] = +0.8611363115940525752239465; + + weight_list[0] = 0.3478548451374538573730639; + weight_list[1] = 0.6521451548625461426269361; + weight_list[2] = 0.6521451548625461426269361; + weight_list[3] = 0.3478548451374538573730639; + break; + } + case 8: + case 9: { + point_list[0] = -0.9061798459386639927976269; + point_list[1] = -0.5384693101056830910363144; + point_list[2] = 0; + point_list[3] = +0.5384693101056830910363144; + point_list[4] = +0.9061798459386639927976269; + + weight_list[0] = 0.2369268850561890875142640; + weight_list[1] = 0.4786286704993664680412915; + weight_list[2] = 0.5688888888888888888888889; + weight_list[3] = 0.4786286704993664680412915; + weight_list[4] = 0.2369268850561890875142640; + break; + } + case 10: + case 11: { + point_list[0] = -0.9324695142031520278123016; + point_list[1] = -0.6612093864662645136613996; + point_list[2] = -0.2386191860831969086305017; + point_list[3] = +0.2386191860831969086305017; + point_list[4] = +0.6612093864662645136613996; + point_list[5] = +0.9324695142031520278123016; + + weight_list[0] = 0.1713244923791703450402961; + weight_list[1] = 0.3607615730481386075698335; + weight_list[2] = 0.4679139345726910473898703; + weight_list[3] = 0.4679139345726910473898703; + weight_list[4] = 0.3607615730481386075698335; + weight_list[5] = 0.1713244923791703450402961; + break; + } + case 12: + case 13: { + point_list[0] = -0.9491079123427585245261897; + point_list[1] = -0.7415311855993944398638648; + point_list[2] = -0.4058451513773971669066064; + point_list[3] = 0; + point_list[4] = +0.4058451513773971669066064; + point_list[5] = +0.7415311855993944398638648; + point_list[6] = +0.9491079123427585245261897; + + weight_list[0] = 0.1294849661688696932706114; + weight_list[1] = 0.2797053914892766679014678; + weight_list[2] = 0.3818300505051189449503698; + weight_list[3] = 0.4179591836734693877551020; + weight_list[4] = 0.3818300505051189449503698; + weight_list[5] = 0.2797053914892766679014678; + weight_list[6] = 0.1294849661688696932706114; + break; + } + case 14: + case 15: { + point_list[0] = -0.9602898564975362316835609; + point_list[1] = -0.7966664774136267395915539; + point_list[2] = -0.5255324099163289858177390; + point_list[3] = -0.1834346424956498049394761; + point_list[4] = +0.1834346424956498049394761; + point_list[5] = +0.5255324099163289858177390; + point_list[6] = +0.7966664774136267395915539; + point_list[7] = +0.9602898564975362316835609; + + weight_list[0] = 0.1012285362903762591525314; + weight_list[1] = 0.2223810344533744705443560; + weight_list[2] = 0.3137066458778872873379622; + weight_list[3] = 0.3626837833783619829651504; + weight_list[4] = 0.3626837833783619829651504; + weight_list[5] = 0.3137066458778872873379622; + weight_list[6] = 0.2223810344533744705443560; + weight_list[7] = 0.1012285362903762591525314; + break; + } + case 16: + case 17: { + point_list[0] = -0.9681602395076260898355762; + point_list[1] = -0.8360311073266357942994298; + point_list[2] = -0.6133714327005903973087020; + point_list[3] = -0.3242534234038089290385380; + point_list[4] = 0; + point_list[5] = +0.3242534234038089290385380; + point_list[6] = +0.6133714327005903973087020; + point_list[7] = +0.8360311073266357942994298; + point_list[8] = +0.9681602395076260898355762; + + weight_list[0] = 0.0812743883615744119718922; + weight_list[1] = 0.1806481606948574040584720; + weight_list[2] = 0.2606106964029354623187429; + weight_list[3] = 0.3123470770400028400686304; + weight_list[4] = 0.3302393550012597631645251; + weight_list[5] = 0.3123470770400028400686304; + weight_list[6] = 0.2606106964029354623187429; + weight_list[7] = 0.1806481606948574040584720; + weight_list[8] = 0.0812743883615744119718922; + break; + } + case 18: + case 19: { + point_list[0] = -0.9739065285171717200779640; + point_list[1] = -0.8650633666889845107320967; + point_list[2] = -0.6794095682990244062343274; + point_list[3] = -0.4333953941292471907992659; + point_list[4] = -0.1488743389816312108848260; + point_list[5] = +0.1488743389816312108848260; + point_list[6] = +0.4333953941292471907992659; + point_list[7] = +0.6794095682990244062343274; + point_list[8] = +0.8650633666889845107320967; + point_list[9] = +0.9739065285171717200779640; + + weight_list[0] = 0.0666713443086881375935688; + weight_list[1] = 0.1494513491505805931457763; + weight_list[2] = 0.2190863625159820439955349; + weight_list[3] = 0.2692667193099963550912269; + weight_list[4] = 0.2955242247147528701738930; + weight_list[5] = 0.2955242247147528701738930; + weight_list[6] = 0.2692667193099963550912269; + weight_list[7] = 0.2190863625159820439955349; + weight_list[8] = 0.1494513491505805931457763; + weight_list[9] = 0.0666713443086881375935688; + break; + } + case 20: + case 21: { + point_list[0] = -0.9782286581460569928039380; + point_list[1] = -0.8870625997680952990751578; + point_list[2] = -0.7301520055740493240934163; + point_list[3] = -0.5190961292068118159257257; + point_list[4] = -0.2695431559523449723315320; + point_list[5] = 0; + point_list[6] = +0.2695431559523449723315320; + point_list[7] = +0.5190961292068118159257257; + point_list[8] = +0.7301520055740493240934163; + point_list[9] = +0.8870625997680952990751578; + point_list[10] = +0.9782286581460569928039380; + + weight_list[0] = 0.0556685671161736664827537; + weight_list[1] = 0.1255803694649046246346940; + weight_list[2] = 0.1862902109277342514260980; + weight_list[3] = 0.2331937645919904799185237; + weight_list[4] = 0.2628045445102466621806889; + weight_list[5] = 0.2729250867779006307144835; + weight_list[6] = 0.2628045445102466621806889; + weight_list[7] = 0.2331937645919904799185237; + weight_list[8] = 0.1862902109277342514260980; + weight_list[9] = 0.1255803694649046246346940; + weight_list[10] = 0.0556685671161736664827537; + break; + } + case 22: + case 23: { + point_list[0] = -0.9815606342467192506905491; + point_list[1] = -0.9041172563704748566784659; + point_list[2] = -0.7699026741943046870368938; + point_list[3] = -0.5873179542866174472967024; + point_list[4] = -0.3678314989981801937526915; + point_list[5] = -0.1252334085114689154724414; + point_list[6] = +0.1252334085114689154724414; + point_list[7] = +0.3678314989981801937526915; + point_list[8] = +0.5873179542866174472967024; + point_list[9] = +0.7699026741943046870368938; + point_list[10] = +0.9041172563704748566784659; + point_list[11] = +0.9815606342467192506905491; + + weight_list[0] = 0.0471753363865118271946160; + weight_list[1] = 0.1069393259953184309602547; + weight_list[2] = 0.1600783285433462263346525; + weight_list[3] = 0.2031674267230659217490645; + weight_list[4] = 0.2334925365383548087608499; + weight_list[5] = 0.2491470458134027850005624; + weight_list[6] = 0.2491470458134027850005624; + weight_list[7] = 0.2334925365383548087608499; + weight_list[8] = 0.2031674267230659217490645; + weight_list[9] = 0.1600783285433462263346525; + weight_list[10] = 0.1069393259953184309602547; + weight_list[11] = 0.0471753363865118271946160; + break; + } + default: { + throw NormalError("Gauss-Legendre quadrature formulae handle degrees up to " + + std::to_string(TensorialGaussLegendreQuadrature<1>::max_degree)); + } + } + + m_point_list = point_list; + m_weight_list = weight_list; +} + +template <> +void +TensorialGaussLegendreQuadrature<2>::_buildPointAndWeightLists(const size_t degree) +{ + const size_t nb_points_1d = degree / 2 + 1; + const size_t nb_points = nb_points_1d * nb_points_1d; + + SmallArray<TinyVector<2>> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + TensorialGaussLegendreQuadrature<1> gauss_legendre_1d(degree); + const auto& point_list_1d = gauss_legendre_1d.pointList(); + const auto& weight_list_1d = gauss_legendre_1d.weightList(); + + size_t l = 0; + for (size_t i = 0; i < nb_points_1d; ++i) { + for (size_t j = 0; j < nb_points_1d; ++j, ++l) { + point_list[l] = TinyVector<2>{point_list_1d[i][0], point_list_1d[j][0]}; + weight_list[l] = weight_list_1d[i] * weight_list_1d[j]; + } + } + + this->m_point_list = point_list; + this->m_weight_list = weight_list; +} + +template <> +void +TensorialGaussLegendreQuadrature<3>::_buildPointAndWeightLists(const size_t degree) +{ + const size_t nb_points_1d = degree / 2 + 1; + const size_t nb_points = nb_points_1d * nb_points_1d * nb_points_1d; + + SmallArray<TinyVector<3>> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + TensorialGaussLegendreQuadrature<1> gauss_legendre_1d(degree); + const auto& point_list_1d = gauss_legendre_1d.pointList(); + const auto& weight_list_1d = gauss_legendre_1d.weightList(); + + size_t l = 0; + for (size_t i = 0; i < nb_points_1d; ++i) { + for (size_t j = 0; j < nb_points_1d; ++j) { + for (size_t k = 0; k < nb_points_1d; ++k, ++l) { + point_list[l] = TinyVector<3>{point_list_1d[i][0], point_list_1d[j][0], point_list_1d[k][0]}; + weight_list[l] = weight_list_1d[i] * weight_list_1d[j] * weight_list_1d[k]; + } + } + } + + this->m_point_list = point_list; + this->m_weight_list = weight_list; +} diff --git a/src/analysis/TensorialGaussLegendreQuadrature.hpp b/src/analysis/TensorialGaussLegendreQuadrature.hpp new file mode 100644 index 0000000000000000000000000000000000000000..51aadae6f64b13f2f8c3b68a59665174ad74150e --- /dev/null +++ b/src/analysis/TensorialGaussLegendreQuadrature.hpp @@ -0,0 +1,40 @@ +#ifndef TENSORIAL_GAUSS_LEGENDRE_QUADRATURE_HPP +#define TENSORIAL_GAUSS_LEGENDRE_QUADRATURE_HPP + +#include <analysis/QuadratureFormula.hpp> + +/** + * Defines Gauss Legendre 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] + */ +template <size_t Dimension> +class TensorialGaussLegendreQuadrature final : public QuadratureFormula<Dimension> +{ + public: + constexpr static size_t max_degree = 23; + + private: + void _buildPointAndWeightLists(const size_t degree); + + public: + TensorialGaussLegendreQuadrature(TensorialGaussLegendreQuadrature&&) = default; + TensorialGaussLegendreQuadrature(const TensorialGaussLegendreQuadrature&) = default; + + private: + friend class QuadratureManager; + + template <size_t D> + friend class TensorialGaussLegendreQuadrature; + + explicit TensorialGaussLegendreQuadrature(const size_t degree) : QuadratureFormula<Dimension>(QuadratureType::Gauss) + { + this->_buildPointAndWeightLists(degree); + } + + TensorialGaussLegendreQuadrature() = delete; + ~TensorialGaussLegendreQuadrature() = default; +}; + +#endif // TENSORIAL_GAUSS_LEGENDRE_QUADRATURE_HPP diff --git a/src/analysis/TensorialGaussLobattoQuadrature.cpp b/src/analysis/TensorialGaussLobattoQuadrature.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3ab97460b55dad3a2a48a24db56f5c575542361e --- /dev/null +++ b/src/analysis/TensorialGaussLobattoQuadrature.cpp @@ -0,0 +1,181 @@ +#include <analysis/TensorialGaussLobattoQuadrature.hpp> +#include <utils/Exceptions.hpp> + +template <> +void +TensorialGaussLobattoQuadrature<1>::_buildPointAndWeightLists(const size_t degree) +{ + const size_t nb_points = degree / 2 + 2; + + SmallArray<TinyVector<1>> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + switch (degree) { + case 0: + case 1: { + point_list[0] = -1; + point_list[1] = +1; + + weight_list[0] = 1; + weight_list[1] = 1; + break; + } + case 2: + case 3: { + point_list[0] = -1; + point_list[1] = 0; + point_list[2] = +1; + + weight_list[0] = 0.3333333333333333333333333; + weight_list[1] = 1.3333333333333333333333333; + weight_list[2] = 0.3333333333333333333333333; + break; + } + case 4: + case 5: { + point_list[0] = -1; + point_list[1] = -0.4472135954999579392818347; + point_list[2] = +0.4472135954999579392818347; + point_list[3] = +1; + + weight_list[0] = 0.1666666666666666666666667; + weight_list[1] = 0.8333333333333333333333333; + weight_list[2] = 0.8333333333333333333333333; + weight_list[3] = 0.1666666666666666666666667; + break; + } + case 6: + case 7: { + point_list[0] = -1; + point_list[1] = -0.6546536707079771437982925; + point_list[2] = 0; + point_list[3] = +0.6546536707079771437982925; + point_list[4] = +1; + + weight_list[0] = 0.1; + weight_list[1] = 0.5444444444444444444444444; + weight_list[2] = 0.7111111111111111111111111; + weight_list[3] = 0.5444444444444444444444444; + weight_list[4] = 0.1; + break; + } + case 8: + case 9: { + point_list[0] = -1; + point_list[1] = -0.7650553239294646928510030; + point_list[2] = -0.2852315164806450963141510; + point_list[3] = +0.2852315164806450963141510; + point_list[4] = +0.7650553239294646928510030; + point_list[5] = +1; + + weight_list[0] = 0.0666666666666666666666667; + weight_list[1] = 0.3784749562978469803166128; + weight_list[2] = 0.5548583770354863530167205; + weight_list[3] = 0.5548583770354863530167205; + weight_list[4] = 0.3784749562978469803166128; + weight_list[5] = 0.0666666666666666666666667; + break; + } + case 10: + case 11: { + point_list[0] = -1; + point_list[1] = -0.8302238962785669298720322; + point_list[2] = -0.4688487934707142138037719; + point_list[3] = 0; + point_list[4] = +0.4688487934707142138037719; + point_list[5] = +0.8302238962785669298720322; + point_list[6] = +1; + + weight_list[0] = 0.0476190476190476190476190; + weight_list[1] = 0.2768260473615659480107004; + weight_list[2] = 0.4317453812098626234178710; + weight_list[3] = 0.4876190476190476190476190; + weight_list[4] = 0.4317453812098626234178710; + weight_list[5] = 0.2768260473615659480107004; + weight_list[6] = 0.0476190476190476190476190; + break; + } + case 12: + case 13: { + point_list[0] = -1; + point_list[1] = -0.8717401485096066153374457; + point_list[2] = -0.5917001814331423021445107; + point_list[3] = -0.2092992179024788687686573; + point_list[4] = +0.2092992179024788687686573; + point_list[5] = +0.5917001814331423021445107; + point_list[6] = +0.8717401485096066153374457; + point_list[7] = +1; + + weight_list[0] = 0.0357142857142857142857143; + weight_list[1] = 0.2107042271435060393829921; + weight_list[2] = 0.3411226924835043647642407; + weight_list[3] = 0.4124587946587038815670530; + weight_list[4] = 0.4124587946587038815670530; + weight_list[5] = 0.3411226924835043647642407; + weight_list[6] = 0.2107042271435060393829921; + weight_list[7] = 0.0357142857142857142857143; + break; + } + default: { + throw NormalError("Gauss-Lobatto quadrature formulae handle degrees up to " + + std::to_string(TensorialGaussLobattoQuadrature<1>::max_degree)); + } + } + + m_point_list = point_list; + m_weight_list = weight_list; +} + +template <> +void +TensorialGaussLobattoQuadrature<2>::_buildPointAndWeightLists(const size_t degree) +{ + const size_t nb_points_1d = degree / 2 + 2; + const size_t nb_points = nb_points_1d * nb_points_1d; + + SmallArray<TinyVector<2>> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + TensorialGaussLobattoQuadrature<1> gauss_lobatto_1d(degree); + const auto& point_list_1d = gauss_lobatto_1d.pointList(); + const auto& weight_list_1d = gauss_lobatto_1d.weightList(); + + size_t l = 0; + for (size_t i = 0; i < nb_points_1d; ++i) { + for (size_t j = 0; j < nb_points_1d; ++j, ++l) { + point_list[l] = TinyVector<2>{point_list_1d[i][0], point_list_1d[j][0]}; + weight_list[l] = weight_list_1d[i] * weight_list_1d[j]; + } + } + + this->m_point_list = point_list; + this->m_weight_list = weight_list; +} + +template <> +void +TensorialGaussLobattoQuadrature<3>::_buildPointAndWeightLists(const size_t degree) +{ + const size_t nb_points_1d = degree / 2 + 2; + const size_t nb_points = nb_points_1d * nb_points_1d * nb_points_1d; + + SmallArray<TinyVector<3>> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + TensorialGaussLobattoQuadrature<1> gauss_lobatto_1d(degree); + const auto& point_list_1d = gauss_lobatto_1d.pointList(); + const auto& weight_list_1d = gauss_lobatto_1d.weightList(); + + size_t l = 0; + for (size_t i = 0; i < nb_points_1d; ++i) { + for (size_t j = 0; j < nb_points_1d; ++j) { + for (size_t k = 0; k < nb_points_1d; ++k, ++l) { + point_list[l] = TinyVector<3>{point_list_1d[i][0], point_list_1d[j][0], point_list_1d[k][0]}; + weight_list[l] = weight_list_1d[i] * weight_list_1d[j] * weight_list_1d[k]; + } + } + } + + this->m_point_list = point_list; + this->m_weight_list = weight_list; +} diff --git a/src/analysis/TensorialGaussLobattoQuadrature.hpp b/src/analysis/TensorialGaussLobattoQuadrature.hpp new file mode 100644 index 0000000000000000000000000000000000000000..1a578bbbc1af1d7d4efdae4183cea1e3c6fb76ff --- /dev/null +++ b/src/analysis/TensorialGaussLobattoQuadrature.hpp @@ -0,0 +1,40 @@ +#ifndef TENSORIAL_GAUSS_LOBATTO_QUADRATURE_HPP +#define TENSORIAL_GAUSS_LOBATTO_QUADRATURE_HPP + +#include <analysis/QuadratureFormula.hpp> + +/** + * Defines Gauss Lobatto 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] + */ +template <size_t Dimension> +class TensorialGaussLobattoQuadrature final : public QuadratureFormula<Dimension> +{ + public: + constexpr static size_t max_degree = 13; + + private: + void _buildPointAndWeightLists(const size_t degree); + + public: + TensorialGaussLobattoQuadrature(TensorialGaussLobattoQuadrature&&) = default; + TensorialGaussLobattoQuadrature(const TensorialGaussLobattoQuadrature&) = default; + + private: + friend class QuadratureManager; + + template <size_t D> + friend class TensorialGaussLobattoQuadrature; + + explicit TensorialGaussLobattoQuadrature(const size_t degree) : QuadratureFormula<Dimension>(QuadratureType::Gauss) + { + this->_buildPointAndWeightLists(degree); + } + + TensorialGaussLobattoQuadrature() = delete; + ~TensorialGaussLobattoQuadrature() = default; +}; + +#endif // TENSORIAL_GAUSS_LOBATTO_QUADRATURE_HPP diff --git a/src/analysis/TetrahedronGaussQuadrature.cpp b/src/analysis/TetrahedronGaussQuadrature.cpp new file mode 100644 index 0000000000000000000000000000000000000000..644e2e29387821a274fa2ae8dd2861c60f2c4abc --- /dev/null +++ b/src/analysis/TetrahedronGaussQuadrature.cpp @@ -0,0 +1,688 @@ +#include <analysis/TetrahedronGaussQuadrature.hpp> +#include <utils/Exceptions.hpp> + +void +TetrahedronGaussQuadrature::_buildPointAndWeightLists(const size_t degree) +{ + using R3 = TinyVector<3>; + + struct Descriptor + { + int id; + double weight; + std::vector<double> lambda_list; + }; + + auto fill_quadrature_points = [](auto descriptor_list, auto& point_list, auto& weight_list) { + Assert(point_list.size() == weight_list.size()); + + const R3 A = {0, 0, 0}; + const R3 B = {1, 0, 0}; + const R3 C = {0, 1, 0}; + const R3 D = {0, 0, 1}; + + size_t k = 0; + for (size_t i = 0; i < descriptor_list.size(); ++i) { + const auto [id, unit_weight, lambda_list] = descriptor_list[i]; + + const double w = (1. / 6) * unit_weight; + + switch (id) { + case 1: { + Assert(lambda_list.size() == 0); + point_list[k] = (1. / 4) * (A + B + C + D); + weight_list[k] = w; + ++k; + break; + } + case 2: { + Assert(lambda_list.size() == 1); + const double l0 = lambda_list[0]; + const double l1 = 1 - 3 * l0; + + point_list[k + 0] = l0 * A + l0 * B + l0 * C + l1 * D; + point_list[k + 1] = l0 * A + l0 * B + l1 * C + l0 * D; + point_list[k + 2] = l0 * A + l1 * B + l0 * C + l0 * D; + point_list[k + 3] = l1 * A + l0 * B + l0 * C + l0 * D; + + for (size_t l = 0; l < 4; ++l) { + weight_list[k + l] = w; + } + + k += 4; + break; + } + case 3: { + Assert(lambda_list.size() == 1); + const double l0 = lambda_list[0]; + const double l1 = 0.5 - l0; + + point_list[k + 0] = l0 * A + l0 * B + l1 * C + l1 * D; + point_list[k + 1] = l0 * A + l1 * B + l0 * C + l1 * D; + point_list[k + 2] = l0 * A + l1 * B + l1 * C + l0 * D; + point_list[k + 3] = l1 * A + l0 * B + l0 * C + l1 * D; + point_list[k + 4] = l1 * A + l0 * B + l1 * C + l0 * D; + point_list[k + 5] = l1 * A + l1 * B + l0 * C + l0 * D; + + for (size_t l = 0; l < 6; ++l) { + weight_list[k + l] = w; + } + + k += 6; + break; + } + case 4: { + Assert(lambda_list.size() == 2); + const double l0 = lambda_list[0]; + const double l1 = lambda_list[1]; + const double l2 = 1 - 2 * l0 - l1; + + point_list[k + 0] = l0 * A + l0 * B + l1 * C + l2 * D; + point_list[k + 1] = l0 * A + l0 * B + l2 * C + l1 * D; + point_list[k + 2] = l0 * A + l1 * B + l0 * C + l2 * D; + point_list[k + 3] = l0 * A + l1 * B + l2 * C + l0 * D; + point_list[k + 4] = l0 * A + l2 * B + l0 * C + l1 * D; + point_list[k + 5] = l0 * A + l2 * B + l1 * C + l0 * D; + point_list[k + 6] = l1 * A + l0 * B + l0 * C + l2 * D; + point_list[k + 7] = l1 * A + l0 * B + l2 * C + l0 * D; + point_list[k + 8] = l1 * A + l2 * B + l0 * C + l0 * D; + point_list[k + 9] = l2 * A + l0 * B + l0 * C + l1 * D; + point_list[k + 10] = l2 * A + l0 * B + l1 * C + l0 * D; + point_list[k + 11] = l2 * A + l1 * B + l0 * C + l0 * D; + + for (size_t l = 0; l < 12; ++l) { + weight_list[k + l] = w; + } + + k += 12; + break; + } + case 5: { + Assert(lambda_list.size() == 3); + const double l0 = lambda_list[0]; + const double l1 = lambda_list[1]; + const double l2 = lambda_list[2]; + const double l3 = 1 - l0 - l1 - l2; + + point_list[k + 0] = l0 * A + l1 * B + l2 * C + l3 * D; + point_list[k + 1] = l0 * A + l1 * B + l3 * C + l2 * D; + point_list[k + 2] = l0 * A + l2 * B + l1 * C + l3 * D; + point_list[k + 3] = l0 * A + l2 * B + l3 * C + l1 * D; + point_list[k + 4] = l0 * A + l3 * B + l1 * C + l2 * D; + point_list[k + 5] = l0 * A + l3 * B + l2 * C + l1 * D; + point_list[k + 6] = l1 * A + l0 * B + l2 * C + l3 * D; + point_list[k + 7] = l1 * A + l0 * B + l3 * C + l2 * D; + point_list[k + 8] = l1 * A + l2 * B + l0 * C + l3 * D; + point_list[k + 9] = l1 * A + l2 * B + l3 * C + l0 * D; + point_list[k + 10] = l1 * A + l3 * B + l0 * C + l2 * D; + point_list[k + 11] = l1 * A + l3 * B + l2 * C + l0 * D; + point_list[k + 12] = l2 * A + l0 * B + l1 * C + l3 * D; + point_list[k + 13] = l2 * A + l0 * B + l3 * C + l1 * D; + point_list[k + 14] = l2 * A + l1 * B + l0 * C + l3 * D; + point_list[k + 15] = l2 * A + l1 * B + l3 * C + l0 * D; + point_list[k + 16] = l2 * A + l3 * B + l0 * C + l1 * D; + point_list[k + 17] = l2 * A + l3 * B + l1 * C + l0 * D; + point_list[k + 18] = l3 * A + l0 * B + l1 * C + l2 * D; + point_list[k + 19] = l3 * A + l0 * B + l2 * C + l1 * D; + point_list[k + 20] = l3 * A + l1 * B + l0 * C + l2 * D; + point_list[k + 21] = l3 * A + l1 * B + l2 * C + l0 * D; + point_list[k + 22] = l3 * A + l2 * B + l0 * C + l1 * D; + point_list[k + 23] = l3 * A + l2 * B + l1 * C + l0 * D; + + for (size_t l = 0; l < 24; ++l) { + weight_list[k + l] = w; + } + + k += 24; + break; + } + // LCOV_EXCL_START + default: { + throw UnexpectedError("invalid quadrature id"); + } + // LCOV_EXCL_STOP + } + } + }; + + switch (degree) { + case 0: + case 1: { + constexpr size_t nb_points = 1; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{1, 1.000000000000000e+00, {}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 2: { + constexpr size_t nb_points = 4; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{2, 2.500000000000000e-01, {1.381966011250105e-01}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 3: { + constexpr size_t nb_points = 8; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{2, 1.274913115575064e-01, {3.286811466653490e-01}}, + Descriptor{2, 1.225086884424936e-01, {1.119207275092916e-01}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 4: { + constexpr size_t nb_points = 14; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{2, 6.540916363445218e-02, {3.095821653179519e-01}}, + Descriptor{2, 5.935526423100475e-02, {8.344277230397758e-02}}, + Descriptor{3, 8.349038142302871e-02, {4.227790459299413e-01}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 5: { + constexpr size_t nb_points = 14; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{2, 1.126879257180158e-01, {3.108859192633006e-01}}, + Descriptor{2, 7.349304311636196e-02, {9.273525031089122e-02}}, + Descriptor{3, 4.254602077708147e-02, {4.544962958743504e-01}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 6: { + constexpr size_t nb_points = 24; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{2, 1.007721105532064e-02, {4.067395853461135e-02}}, + Descriptor{2, 5.535718154365472e-02, {3.223378901422755e-01}}, + Descriptor{2, 3.992275025816749e-02, {2.146028712591520e-01}}, + Descriptor{4, 4.821428571428572e-02, {6.366100187501753e-02, 6.030056647916492e-01}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 7: { + constexpr size_t nb_points = 35; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{1, 9.548528946413085e-02, {}}, Descriptor{2, 4.232958120996703e-02, {3.157011497782028e-01}}, + Descriptor{3, 3.189692783285758e-02, {4.495101774016036e-01}}, + Descriptor{4, 8.110770829903342e-03, {2.126547254148325e-02, 8.108302410985485e-01}}, + Descriptor{4, 3.720713072833462e-02, {1.888338310260010e-01, 5.751716375870001e-01}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 8: { + constexpr size_t nb_points = 46; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{2, 4.781298803430666e-02, {1.868127582707210e-01}}, + Descriptor{2, 2.972785408679422e-02, {1.144624067612305e-01}}, + Descriptor{2, 4.352732421897527e-02, {3.138065922724016e-01}}, + Descriptor{2, 8.632736020814975e-03, {4.457737944884625e-02}}, + Descriptor{3, 3.689054126986636e-02, {6.548349054384239e-02}}, + Descriptor{4, 1.449702671085950e-02, {2.038931746621103e-01, 5.073320750421590e-03}}, + Descriptor{4, 7.157401867243608e-03, {2.124777966957167e-02, 7.146769263933049e-01}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 9: { + constexpr size_t nb_points = 59; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{1, 5.686662425355173e-02, {}}, + Descriptor{2, 2.569427668952318e-02, {1.679066052367428e-01}}, + Descriptor{2, 2.298923353028370e-03, {9.143627051407625e-02}}, + Descriptor{2, 3.045603866759101e-02, {3.218556648176533e-01}}, + Descriptor{2, 7.123722340238881e-03, {4.183769590036560e-02}}, + Descriptor{3, 3.684365548094388e-02, {1.067294385748464e-01}}, + Descriptor{4, 1.032205678220985e-02, {3.395716818308889e-02, 7.183930939814244e-01}}, + Descriptor{4, 7.634887153980855e-03, {4.606581810547776e-01, 7.868363447668793e-02}}, + Descriptor{4, 2.035802261874757e-02, {1.843879435000152e-01, 5.972107227618499e-01}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 10: { + constexpr size_t nb_points = 81; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{1, 5.165089225609747e-02, {}}, + Descriptor{2, 1.346797267166026e-02, {7.255175741743780e-02}}, + Descriptor{2, 2.646691924968953e-02, {3.078959478669229e-01}}, + Descriptor{3, 5.107047828143525e-03, {2.371913960722093e-02}}, + Descriptor{3, 2.364999615824560e-02, {4.034202269308927e-01}}, + Descriptor{4, 2.531736665096822e-02, {2.017386068476799e-01, 7.385418101848620e-02}}, + Descriptor{4, 5.416263407447926e-03, {1.548397007438618e-01, 6.875048558830396e-01}}, + Descriptor{4, 8.153659012054226e-03, {4.125991504993639e-01, 1.741437164939321e-01}}, + Descriptor{4, 1.112597175961278e-02, {3.889072755780651e-02, 2.657575065627199e-01}}, + Descriptor{4, 1.325678848264236e-03, {5.604847951021338e-03, 9.324134903525841e-02}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 11: { + constexpr size_t nb_points = 110; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{2, 1.468934358613075e-02, {2.993130923993425e-01}}, + Descriptor{2, 3.380869530621681e-03, {3.263284396518180e-02}}, + Descriptor{3, 1.676676867722563e-02, {1.742044154846892e-01}}, + Descriptor{3, 1.932364034775851e-02, {4.012153758583749e-01}}, + Descriptor{3, 1.653253610375797e-03, {4.942980948772996e-01}}, + Descriptor{4, 9.799971247032874e-03, {1.231206549747224e-01, 7.273303463463835e-01}}, + Descriptor{4, 2.036278491304826e-03, {1.300387048559024e-02, 1.702280734892642e-01}}, + Descriptor{4, 8.207613752916718e-03, {4.293540117192574e-02, 6.182598097891158e-01}}, + Descriptor{4, 1.510498736666349e-02, {1.844240320470778e-01, 5.399001168557016e-01}}, + Descriptor{4, 1.274239266610639e-02, {2.591694074642826e-01, 4.554353196219595e-01}}, + Descriptor{5, 5.273427059689129e-03, {5.351420009314595e-01, 1.097757236596031e-02, 3.414518661958190e-01}} + + }; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 12: { + constexpr size_t nb_points = 168; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{2, 1.761491553503257e-02, {2.135679944533018e-01}}, + Descriptor{2, 8.351235933432746e-03, {8.080469951147343e-02}}, + Descriptor{2, 1.777571920669439e-02, {1.460894685275485e-01}}, + Descriptor{3, 1.016802439757214e-02, {4.359346229622011e-01}}, + Descriptor{3, 1.574040002395383e-02, {3.723816950753983e-01}}, + Descriptor{4, 1.511281145864287e-03, {1.481472606744865e-02, 6.940351772721454e-01}}, + Descriptor{4, 8.726569887485608e-04, {4.406791967562980e-02, 5.787943875724942e-04}}, + Descriptor{4, 3.712882661457528e-03, {2.900481455515819e-02, 7.927838364729656e-01}}, + Descriptor{4, 2.358314255727376e-03, {1.384125788015036e-01, 7.217318354185758e-01}}, + Descriptor{5, 4.490847036271700e-03, {1.155183527100142e-02, 2.002685156661767e-01, 4.459556015690982e-01}}, + Descriptor{5, 7.549616048899519e-03, {7.295863195082626e-02, 2.545920450251540e-01, 4.229332866644536e-01}}, + Descriptor{5, 1.850514589067692e-03, {5.001810761518710e-02, 3.937338659984053e-01, 5.538497716858680e-01}}, + Descriptor{5, 9.780703581954099e-03, {2.518367824271116e-01, 3.608735666657864e-02, 5.985486290544021e-01}} + + }; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 13: { + constexpr size_t nb_points = 172; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{2, 8.606417789141471e-04, {2.023816786180974e-02}}, + Descriptor{2, 2.260732681773922e-02, {2.890147352435263e-01}}, + Descriptor{2, 9.680037326838918e-03, {9.402870008212708e-02}}, + Descriptor{2, 7.170940325572750e-03, {1.976498544437255e-01}}, + Descriptor{3, 7.784870979280401e-03, {4.046189676018364e-02}}, + Descriptor{3, 5.120271481716123e-04, {4.999998048519694e-01}}, + Descriptor{4, 8.880272171422971e-03, {6.752926495280243e-02, 6.118971302042935e-01}}, + Descriptor{4, 1.062144779049374e-02, {1.360105145132029e-01, 4.868308338798159e-01}}, + Descriptor{4, 5.873089331995857e-03, {2.780783459563702e-01, 4.273786080349000e-01}}, + Descriptor{4, 9.235535397556015e-03, {1.967550197192861e-01, 5.667528680967985e-01}}, + Descriptor{4, 1.456732207916522e-02, {3.862498629203497e-01, 6.201970724197543e-02}}, + Descriptor{4, 2.658739862173390e-03, {2.353551905465277e-02, 1.086607820833199e-01}}, + Descriptor{5, 3.221852775001763e-03, {3.362108930747719e-01, 5.446964977019162e-01, 1.155925493534321e-01}}, + Descriptor{5, 1.464206741103990e-03, {6.859816301235152e-01, 2.886160494075550e-02, 2.745833302490004e-01}}, + Descriptor{5, 2.268354927450138e-03, {7.356772467818598e-01, 1.545866468273804e-01, 1.103371356908743e-02}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 14: { + constexpr size_t nb_points = 204; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{2, 3.445433050323388e-03, {3.298151517846193e-01}}, + Descriptor{2, 2.621255271870497e-03, {5.753828268975920e-02}}, + Descriptor{2, 1.107383241893503e-04, {5.856168613783504e-03}}, + Descriptor{2, 1.002858537247380e-02, {1.605554758479567e-01}}, + Descriptor{2, 6.790408457809412e-03, {9.873964607404909e-02}}, + Descriptor{2, 7.118148341899285e-03, {2.080531961597265e-01}}, + Descriptor{3, 1.060052294564051e-03, {4.902479711877765e-01}}, + Descriptor{3, 1.366983099498089e-02, {1.029394001155326e-01}}, + Descriptor{3, 2.690741094676155e-03, {3.791346346121514e-02}}, + Descriptor{3, 1.016460122584274e-02, {3.185735761838604e-01}}, + Descriptor{4, 1.354439963772740e-02, {2.499092188634998e-01, 4.189387788376669e-01}}, + Descriptor{4, 4.623340047669791e-03, {2.132633780618757e-01, 5.628766802497838e-01}}, + Descriptor{4, 8.331498452473301e-04, {4.918128494015905e-02, 8.954689727140162e-01}}, + Descriptor{4, 7.240296760857249e-03, {3.928626179700601e-01, 2.066357892967347e-02}}, + Descriptor{4, 8.751807809978078e-04, {1.261760553257071e-02, 1.269022024074958e-01}}, + Descriptor{5, 7.172536518098438e-03, {1.216187843486990e-01, 6.214000311762153e-02, 2.395005950785847e-01}}, + Descriptor{5, 4.286856342790781e-03, {3.489022960470246e-01, 5.517941321184247e-01, 8.378145261134291e-02}}, + Descriptor{5, 9.757527641506894e-04, {6.822383201682893e-01, 1.784164064765456e-02, 2.844407418708836e-01}}, + Descriptor{5, 3.757936299766722e-03, {7.339982986585810e-01, 1.695395507001622e-01, 7.868554787111390e-02}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 15: { + constexpr size_t nb_points = 264; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{2, 5.112029771454935e-04, {1.692642158547220e-02}}, + Descriptor{2, 1.620740592022658e-02, {2.836779254595722e-01}}, + Descriptor{2, 1.552578602041314e-02, {1.821984139975859e-01}}, + Descriptor{3, 1.219010259975421e-03, {1.450800515218459e-02}}, + Descriptor{3, 8.472862853125917e-03, {1.427441437658564e-01}}, + Descriptor{4, 1.797534305405733e-03, {7.321727256195354e-02, 7.766357493733004e-01}}, + Descriptor{4, 8.198015220760061e-04, {1.056558410489699e-02, 2.225606554924344e-01}}, + Descriptor{4, 7.681775272473012e-03, {2.637972626688146e-01, 5.575022240565973e-02}}, + Descriptor{4, 4.479850385774781e-03, {4.354902702993817e-01, 1.112909267055329e-01}}, + Descriptor{4, 5.615298608384355e-03, {5.347259364185193e-02, 5.448865322975603e-01}}, + Descriptor{4, 1.769703685797290e-03, {1.105308939580100e-01, 7.694703779405406e-01}}, + Descriptor{5, 1.131138329187022e-03, {4.104670514991076e-02, 6.030936440770986e-01, 2.328924415481402e-03}}, + Descriptor{5, 8.404993407577487e-04, {9.201667327695258e-02, 2.939319332917082e-02, 8.672646051241815e-01}}, + Descriptor{5, 3.011968607402684e-03, {6.822627868000052e-02, 7.077814873155971e-01, 2.200643755861662e-02}}, + Descriptor{5, 5.084429327522668e-03, {1.890015556386176e-01, 1.295809597674534e-01, 6.807532978800637e-02}}, + Descriptor{5, 7.139383728003996e-03, {3.054799663906012e-01, 4.695333003662676e-01, 7.251484323369149e-02}}, + Descriptor{5, 3.378550568229294e-03, {1.509145500825105e-01, 5.778346261482753e-01, 1.112774031280626e-02}}, + Descriptor{5, 2.201680777701462e-03, {3.368450658547645e-01, 1.082194753682293e-02, 4.176069528643034e-01}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 16: { + constexpr size_t nb_points = 304; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{2, 4.034878937238870e-03, {3.296714738440606e-01}}, + Descriptor{2, 5.263428008047628e-03, {1.120421044173788e-01}}, + Descriptor{2, 1.078639106857764e-02, {2.804460259110929e-01}}, + Descriptor{2, 1.892340029030997e-03, {3.942164444076166e-02}}, + Descriptor{3, 6.014511003000459e-03, {7.491741856476755e-02}}, + Descriptor{3, 8.692191232873023e-03, {3.356931029556346e-01}}, + Descriptor{4, 3.507623285784993e-03, {4.904898759556675e-02, 7.646870675801803e-01}}, + Descriptor{4, 1.188662273319198e-03, {1.412609568309253e-02, 2.328268045894251e-01}}, + Descriptor{4, 4.345225314466667e-03, {6.239652058154325e-02, 2.832417683077947e-01}}, + Descriptor{4, 2.660686570203166e-03, {1.890959275696560e-01, 1.283187405611824e-02}}, + Descriptor{4, 5.553174302124013e-03, {2.750176001295444e-01, 3.872709603194903e-01}}, + Descriptor{4, 1.531431405395808e-04, {5.944898252569946e-03, 3.723805935523542e-02}}, + Descriptor{4, 2.231204136715679e-03, {1.183058071099944e-01, 7.482941078308859e-01}}, + Descriptor{5, 2.472377156249970e-03, {8.011846127872502e-02, 5.146357887888395e-01, 3.908021114187921e-01}}, + Descriptor{5, 6.596122891817925e-03, {3.102585498627273e-01, 1.645739468379099e-01, 6.995093322963369e-02}}, + Descriptor{5, 6.004349067697421e-04, {1.085240801928985e-01, 3.435867950145696e-02, 8.557156992205752e-01}}, + Descriptor{5, 2.242330996876527e-03, {2.483824987814955e-01, 6.625317544850510e-01, 1.098323448764900e-02}}, + Descriptor{5, 8.244422362471837e-04, {3.960091211067035e-01, 1.226898678006519e-02, 1.878187449597510e-02}}, + Descriptor{5, 4.388015835267911e-03, {6.367516197137306e-02, 2.054604991324105e-01, 1.362449508885895e-01}}, + Descriptor{5, 3.454278425740962e-03, {1.757650466139104e-01, 4.610678860796995e-01, 1.387535709612253e-01}}, + Descriptor{5, 3.929289473335571e-03, {4.779942532006705e-01, 1.344788610299629e-02, 3.221398306538996e-01}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 17: { + constexpr size_t nb_points = 364; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{2, 2.943411054682655e-03, {1.092594110391400e-01}}, + Descriptor{2, 4.821254562130973e-04, {1.706905335350991e-02}}, + Descriptor{2, 1.633411882335971e-03, {6.030276440208671e-02}}, + Descriptor{2, 8.937260544733967e-03, {1.802936778752487e-01}}, + Descriptor{3, 3.539281041131444e-03, {2.075642494319923e-01}}, + Descriptor{3, 5.127876775122913e-03, {6.350561875036179e-02}}, + Descriptor{3, 8.505961705776655e-03, {1.425740948569834e-01}}, + Descriptor{3, 1.362001059565090e-03, {1.525498961135818e-02}}, + Descriptor{4, 1.952703594699083e-03, {2.817717468661823e-01, 6.605628545936354e-03}}, + Descriptor{4, 3.552482332702156e-03, {2.532792896616394e-01, 3.473076755269789e-01}}, + Descriptor{4, 4.735037872087881e-03, {1.194446836887992e-01, 5.129631932135305e-01}}, + Descriptor{4, 4.076204052523780e-03, {2.796975892179978e-01, 4.040135150131379e-01}}, + Descriptor{4, 4.397889616038591e-03, {5.914965001755916e-02, 2.771505768037979e-01}}, + Descriptor{4, 8.159915418039479e-04, {1.156645687972039e-02, 3.372693231713962e-01}}, + Descriptor{4, 6.436927403356441e-03, {2.546200946118619e-01, 8.899213511967391e-02}}, + Descriptor{4, 2.290937029978224e-04, {6.672914677865158e-03, 8.335377000797282e-02}}, + Descriptor{4, 3.188746694204980e-03, {5.954996366173630e-02, 1.488738514609226e-01}}, + Descriptor{5, 1.991266259969879e-03, {9.563829425828949e-02, 1.308047471312760e-02, 1.683493064182302e-01}}, + Descriptor{5, 1.209946636868781e-03, {6.035751534893870e-02, 6.376551993416253e-01, 1.062246299591423e-02}}, + Descriptor{5, 2.943417982183902e-03, {5.720629662753272e-01, 1.575062824084584e-01, 1.289545879798304e-02}}, + Descriptor{5, 3.454094554810564e-03, {5.982871618499548e-01, 1.530963612221368e-01, 6.489065131906320e-02}}, + Descriptor{5, 8.241135414777571e-04, {8.721077921772252e-02, 1.165500297046612e-02, 4.707766223753580e-02}}, + Descriptor{5, 1.383542378170185e-03, {4.137799680661914e-01, 4.085328910163256e-01, 1.048009320013415e-02}}, + Descriptor{5, 1.781445235926538e-03, {3.904989583719425e-01, 1.167932299246964e-02, 7.360595669274642e-02}}, + Descriptor{5, 6.969316351001401e-04, {7.735017403534717e-01, 8.163680371232981e-03, 2.545430962429988e-02}}, + Descriptor{5, 5.722888401891606e-03, {5.603440494408158e-02, 1.529886055031752e-01, 3.226986469260043e-01}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 18: { + constexpr size_t nb_points = 436; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{2, 1.505388406750596e-03, {2.063721818681210e-01}}, + Descriptor{2, 7.201441531528436e-03, {1.625387945176406e-01}}, + Descriptor{2, 5.801801233694815e-03, {3.116266728255643e-01}}, + Descriptor{2, 2.465088392849791e-03, {3.307279160890313e-01}}, + Descriptor{2, 8.235271059110021e-04, {3.374408201299506e-02}}, + Descriptor{2, 2.396153395824959e-03, {6.568138278425954e-02}}, + Descriptor{2, 1.662026538062453e-04, {1.169072420259711e-02}}, + Descriptor{3, 4.747626606883917e-05, {3.051729141214794e-01}}, + Descriptor{3, 5.654960404175805e-04, {2.498171653415399e-01}}, + Descriptor{3, 1.126644847587598e-03, {1.336652291605620e-02}}, + Descriptor{3, 1.348246151880201e-03, {2.503423435758855e-01}}, + Descriptor{3, 3.657069096677683e-04, {3.324517722542840e-01}}, + Descriptor{3, 5.853171992565114e-03, {3.328935974705466e-01}}, + Descriptor{3, 1.956691034821430e-03, {1.053889982941293e-01}}, + Descriptor{3, 1.673244252179039e-03, {4.317721941366494e-02}}, + Descriptor{4, 1.684409973125634e-03, {3.310306761504429e-02, 1.352754021303201e-01}}, + Descriptor{4, 9.489733030971150e-04, {1.946185784467675e-01, 1.171879047047253e-03}}, + Descriptor{4, 1.039083135931653e-03, {1.321252126131118e-02, 3.278960098149503e-01}}, + Descriptor{4, 2.868558324240348e-03, {1.229320721770598e-01, 2.028399843152170e-02}}, + Descriptor{4, 3.672202784572132e-03, {6.199506095168380e-02, 3.498961219623653e-01}}, + Descriptor{4, 4.747155546596363e-03, {8.407187546991698e-02, 1.666830796952924e-01}}, + Descriptor{4, 4.150884078212972e-04, {7.867048874453891e-03, 1.859179591228751e-01}}, + Descriptor{4, 2.504990122247683e-03, {4.217582498871236e-02, 2.482707411503117e-01}}, + Descriptor{4, 2.629919627710238e-04, {8.683491872138840e-03, 6.698102226768764e-02}}, + Descriptor{4, 5.237948818645674e-03, {1.111185367576208e-01, 2.918417077981162e-01}}, + Descriptor{5, 9.530517345502799e-04, {3.685463845606022e-03, 6.377078964518405e-02, 2.161982818015302e-01}}, + Descriptor{5, 4.424079498028044e-04, {9.147563979493070e-02, 4.024098103223798e-03, 4.866034767929566e-02}}, + Descriptor{5, 1.756179008422938e-03, {1.326563740184036e-01, 4.168774597385260e-01, 2.814320586294362e-02}}, + Descriptor{5, 2.434266881750153e-03, {4.439198669278809e-01, 2.464330224801677e-01, 2.919443405619611e-02}}, + Descriptor{5, 3.936511965938193e-03, {2.395450885895190e-01, 1.271207488070096e-01, 2.457574497117561e-01}}, + Descriptor{5, 3.199791269106457e-03, {1.657130887168779e-01, 2.137049061861850e-01, 7.023964653694080e-02}}, + Descriptor{5, 3.797610312158748e-03, {1.788776686026366e-01, 3.290353014877974e-01, 6.661063766146717e-02}}, + Descriptor{5, 1.495938562630981e-03, {3.340176116726106e-01, 4.950315956949369e-03, 1.887999372824127e-01}}, + Descriptor{5, 1.703996181224725e-03, {5.458773009126385e-01, 7.846288361681254e-03, 7.104964990519175e-02}}, + Descriptor{5, 3.628775117699059e-03, {2.510439859007851e-02, 1.293557534662013e-01, 2.529882400374321e-01}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 19: { + constexpr size_t nb_points = 487; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{1, 9.477424964421555e-03, {}}, + Descriptor{2, 2.309652046579032e-03, {9.623346794170115e-02}}, + Descriptor{2, 4.091492762240734e-03, {2.840710971185555e-01}}, + Descriptor{2, 1.173654667448287e-03, {4.201218049762310e-02}}, + Descriptor{3, 5.797759302818667e-03, {1.293925012179526e-01}}, + Descriptor{4, 2.028992639106921e-03, {5.339312125330306e-02, 7.679699947393867e-01}}, + Descriptor{4, 2.005858485106433e-04, {5.250553906919603e-03, 1.660339253205299e-01}}, + Descriptor{4, 2.908059972456899e-03, {2.128993323694659e-01, 1.034045995093328e-01}}, + Descriptor{4, 2.532078463287134e-03, {4.034135325977229e-01, 1.333356346432022e-01}}, + Descriptor{4, 7.343695736316139e-04, {1.188811930811271e-02, 5.532379678070896e-01}}, + Descriptor{4, 1.076183574539400e-03, {8.903116551206627e-02, 8.080695151909102e-01}}, + Descriptor{4, 1.986415677131464e-03, {5.151678695899160e-02, 4.873280365294901e-01}}, + Descriptor{4, 5.046317364293947e-03, {1.179992852297671e-01, 2.466149943644083e-01}}, + Descriptor{4, 2.692282460531053e-03, {4.608512334928590e-02, 2.781414318856127e-01}}, + Descriptor{4, 1.330636288503801e-03, {1.410186708097898e-01, 8.174649948389451e-03}}, + Descriptor{4, 1.782928900852855e-03, {1.411034408699267e-01, 5.855868767598970e-01}}, + Descriptor{4, 1.263015826184454e-04, {7.911862204821108e-03, 3.035883809061935e-02}}, + Descriptor{4, 3.244260943819173e-03, {1.761012114703174e-01, 2.461239587816849e-01}}, + Descriptor{5, 1.048498185712524e-03, {4.531137441520981e-02, 7.694124041149815e-01, 1.162671237541303e-02}}, + Descriptor{5, 3.605740745734604e-03, {1.902469770309511e-01, 1.139907343389768e-01, 4.902896398807803e-02}}, + Descriptor{5, 2.561558407869844e-03, {2.025882107314621e-01, 5.045224197189542e-01, 5.200356315054191e-02}}, + Descriptor{5, 1.498918467834416e-03, {6.280459865457699e-02, 3.899342137938394e-01, 9.651021927014570e-03}}, + Descriptor{5, 1.814324572327483e-03, {1.689034611068301e-01, 1.025101977116908e-02, 2.542260337897459e-01}}, + Descriptor{5, 2.883938073996170e-03, {1.282802298826546e-01, 3.714709314621824e-01, 2.826241348940526e-01}}, + Descriptor{5, 3.191411305221261e-03, {3.753164302248334e-01, 2.323738231259893e-01, 5.648574604597608e-02}}, + Descriptor{5, 3.955282336986757e-04, {8.176634693298535e-02, 2.823323910477210e-02, 8.840321921276471e-01}}, + Descriptor{5, 1.642211231915762e-03, {3.727215008878210e-01, 4.691373442926859e-01, 1.052014400647361e-02}}, + Descriptor{5, 4.640920897459689e-04, {2.881077012617455e-01, 6.241150434253934e-03, 2.040787180394686e-02}}, + Descriptor{5, 1.210865339994028e-03, {8.483677030488673e-03, 2.548571009364550e-01, 8.369886684600136e-02}}, + Descriptor{5, 3.653283017278065e-03, {1.193128036212033e-01, 5.081225906571617e-01, 5.013138003585081e-02}}, + Descriptor{5, 1.744791238762615e-03, {4.198369201417426e-01, 1.094996106379021e-02, 3.155028856836414e-01}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 20: { + constexpr size_t nb_points = 552; + SmallArray<R3> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{2, 5.418454790084648e-03, {2.967759596934131e-01}}, + Descriptor{2, 3.820897988248627e-03, {1.209047972112185e-01}}, + Descriptor{2, 4.057458152334048e-03, {3.177959071881044e-01}}, + Descriptor{2, 4.147670297750325e-03, {2.012655712414790e-01}}, + Descriptor{2, 5.289566609934361e-03, {1.678838969272885e-01}}, + Descriptor{2, 9.720418198623532e-04, {3.621493960968947e-02}}, + Descriptor{3, 2.988176136780452e-03, {5.260244961748377e-02}}, + Descriptor{3, 7.061746923528361e-03, {3.045785563313042e-01}}, + Descriptor{4, 1.138014164865969e-03, {3.228230549839516e-02, 8.181532733687802e-01}}, + Descriptor{4, 3.284328089439585e-04, {8.126514470519638e-03, 1.671963931828212e-01}}, + Descriptor{4, 4.517305074533165e-03, {1.851459522994347e-01, 6.611011876662430e-02}}, + Descriptor{4, 2.743957098139693e-03, {4.110775382017770e-01, 1.281831845252744e-01}}, + Descriptor{4, 5.345104029866354e-04, {1.005979740685446e-02, 5.566366248307155e-01}}, + Descriptor{4, 8.527602773365834e-04, {8.230161503723588e-02, 8.242515811428504e-01}}, + Descriptor{4, 1.608673320950611e-03, {3.801282860266467e-02, 6.072922714391159e-01}}, + Descriptor{4, 2.164021789623034e-03, {8.297816905794758e-02, 1.927591204214162e-01}}, + Descriptor{4, 1.298964551990821e-03, {3.232830149045374e-02, 2.290899793113822e-01}}, + Descriptor{4, 7.540221084980848e-04, {1.406521940177762e-01, 4.062459178585371e-03}}, + Descriptor{4, 3.936392177197076e-03, {1.139719439112915e-01, 5.168656572693773e-01}}, + Descriptor{4, 8.260437254311268e-05, {7.453571377174895e-03, 2.517856316811188e-02}}, + Descriptor{4, 2.202593581265821e-03, {1.110171267302689e-01, 3.907070674791312e-01}}, + Descriptor{5, 1.142912288312416e-03, {5.313810503913767e-02, 5.333767142737392e-01, 9.768492667580009e-03}}, + Descriptor{5, 8.037341179884985e-04, {9.439207428728114e-02, 9.450517146275739e-02, 7.609480923624367e-01}}, + Descriptor{5, 6.441055085633393e-04, {5.505445164272958e-02, 7.653955692270024e-01, 5.660747947619223e-03}}, + Descriptor{5, 2.284803061568028e-03, {1.798637301234305e-01, 9.751720382220438e-02, 3.466187077541209e-02}}, + Descriptor{5, 1.768215173403588e-03, {2.121920547752147e-01, 4.095036586170944e-01, 4.613078410418590e-02}}, + Descriptor{5, 1.364093116604035e-03, {1.290161512351960e-01, 4.765557207500070e-01, 9.956030373782836e-03}}, + Descriptor{5, 1.409513020242023e-03, {1.614873223066114e-01, 1.376084748677020e-02, 2.264813194055542e-01}}, + Descriptor{5, 5.352196172820926e-03, {1.059283078939860e-01, 4.143500741402470e-01, 1.944202417194029e-01}}, + Descriptor{5, 2.357251753798956e-03, {2.046229328456809e-01, 2.864083155254953e-01, 3.607794123452725e-02}}, + Descriptor{5, 2.335500281519085e-04, {7.441796869877018e-02, 2.361583233015298e-02, 8.995240292632410e-01}}, + Descriptor{5, 8.299191110448388e-04, {2.938352359686784e-01, 5.078745759286403e-01, 4.379772363790332e-03}}, + Descriptor{5, 3.480327275620159e-04, {2.899004919931303e-01, 2.388614940511808e-03, 2.095834844884252e-02}}, + Descriptor{5, 1.081306497459309e-03, {6.920395527608953e-03, 2.780090233488638e-01, 8.666224435610116e-02}}, + Descriptor{5, 3.363592992643566e-03, {1.053191068972152e-01, 5.431130574905816e-01, 4.625008859127536e-02}}, + Descriptor{5, 1.138819523953005e-03, {3.387615700292962e-01, 8.792325219258773e-03, 4.002505388571689e-01}}}; + + fill_quadrature_points(descriptor_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 " + + std::to_string(TetrahedronGaussQuadrature::max_degree) + " on tetrahedra"); + } + } +} diff --git a/src/analysis/TetrahedronGaussQuadrature.hpp b/src/analysis/TetrahedronGaussQuadrature.hpp new file mode 100644 index 0000000000000000000000000000000000000000..352ff079a409952d99af6931bf75b8b84b06d622 --- /dev/null +++ b/src/analysis/TetrahedronGaussQuadrature.hpp @@ -0,0 +1,38 @@ +#ifndef TETRAHEDRON_GAUSS_QUADRATURE_HPP +#define TETRAHEDRON_GAUSS_QUADRATURE_HPP + +#include <analysis/QuadratureFormula.hpp> + +/** + * Defines Gauss quadrature on the P1 reference tetrahedron element + * + * \note formulae are provided by + * + * 'High-order symmetric cubature rules for tetrahedra and pyramids' + * Jan JasĖkowiec & N. Sukumar (2020). + */ +class TetrahedronGaussQuadrature final : public QuadratureFormula<3> +{ + public: + constexpr static size_t max_degree = 20; + + private: + void _buildPointAndWeightLists(const size_t degree); + + public: + TetrahedronGaussQuadrature(TetrahedronGaussQuadrature&&) = default; + TetrahedronGaussQuadrature(const TetrahedronGaussQuadrature&) = default; + + private: + friend class QuadratureManager; + + explicit TetrahedronGaussQuadrature(const size_t degree) : QuadratureFormula<3>(QuadratureType::Gauss) + { + this->_buildPointAndWeightLists(degree); + } + + TetrahedronGaussQuadrature() = delete; + ~TetrahedronGaussQuadrature() = default; +}; + +#endif // TETRAHEDRON_GAUSS_QUADRATURE_HPP diff --git a/src/analysis/TriangleGaussQuadrature.cpp b/src/analysis/TriangleGaussQuadrature.cpp new file mode 100644 index 0000000000000000000000000000000000000000..df6a9a1ced3aa15d098aaa7696eb67af41c6090b --- /dev/null +++ b/src/analysis/TriangleGaussQuadrature.cpp @@ -0,0 +1,490 @@ +#include <analysis/TriangleGaussQuadrature.hpp> +#include <utils/Exceptions.hpp> + +void +TriangleGaussQuadrature::_buildPointAndWeightLists(const size_t degree) +{ + using R2 = TinyVector<2>; + + struct Descriptor + { + int id; + double weight; + std::vector<double> lambda_list; + }; + + auto fill_quadrature_points = [](auto descriptor_list, auto& point_list, auto& weight_list) { + Assert(point_list.size() == weight_list.size()); + + const R2 A = {0, 0}; + const R2 B = {1, 0}; + const R2 C = {0, 1}; + + size_t k = 0; + for (size_t i = 0; i < descriptor_list.size(); ++i) { + const auto [id, w, position_list] = descriptor_list[i]; + + switch (id) { + case 1: { + Assert(position_list.size() == 0); + + point_list[k] = (1. / 3) * (A + B + C); + weight_list[k] = w; + + k += 1; + break; + } + case 2: { + Assert(position_list.size() == 1); + const double& l0 = position_list[0]; + const double& l1 = 1 - 2 * l0; + + point_list[k + 0] = l0 * A + l0 * B + l1 * C; + point_list[k + 1] = l0 * A + l1 * B + l0 * C; + point_list[k + 2] = l1 * A + l0 * B + l0 * C; + + for (size_t l = 0; l < 3; ++l) { + weight_list[k + l] = w; + } + + k += 3; + break; + } + case 3: { + Assert(position_list.size() == 2); + const double& l0 = position_list[0]; + const double& l1 = position_list[1]; + const double& l2 = 1 - l0 - l1; + + point_list[k + 0] = l0 * A + l1 * B + l2 * C; + point_list[k + 1] = l0 * A + l2 * B + l1 * C; + point_list[k + 2] = l1 * A + l0 * B + l2 * C; + point_list[k + 3] = l1 * A + l2 * B + l0 * C; + point_list[k + 4] = l2 * A + l0 * B + l1 * C; + point_list[k + 5] = l2 * A + l1 * B + l0 * C; + + for (size_t l = 0; l < 6; ++l) { + weight_list[k + l] = w; + } + + k += 6; + break; + } + // LCOV_EXCL_START + default: { + throw UnexpectedError("invalid quadrature id"); + } + // LCOV_EXCL_STOP + } + } + + Assert(k == point_list.size(), "invalid number of quadrature points"); + }; + + switch (degree) { + case 0: + case 1: { + constexpr size_t nb_points = 1; + SmallArray<R2> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{1, 5.000000000000000e-01, {}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 2: { + constexpr size_t nb_points = 3; + SmallArray<R2> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{2, 1.666666666666667e-01, {1.666666666666667e-01}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 3: + case 4: { + constexpr size_t nb_points = 6; + SmallArray<R2> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{2, 1.116907948390057e-01, {4.459484909159649e-01}}, + Descriptor{2, 5.497587182766094e-02, {9.157621350977074e-02}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 5: { + constexpr size_t nb_points = 7; + SmallArray<R2> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{1, 1.125000000000000e-01, {}}, Descriptor{2, 6.296959027241357e-02, {1.012865073234563e-01}}, + Descriptor{2, 6.619707639425310e-02, {4.701420641051151e-01}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 6: { + constexpr size_t nb_points = 12; + SmallArray<R2> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{2, 2.542245318510341e-02, {6.308901449150223e-02}}, + Descriptor{2, 5.839313786318968e-02, {2.492867451709104e-01}}, + Descriptor{3, 4.142553780918679e-02, {3.103524510337844e-01, 5.314504984481695e-02}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 7: { + constexpr size_t nb_points = 15; + SmallArray<R2> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{2, 8.272525055396066e-03, {3.373064855458785e-02}}, + Descriptor{2, 6.397208561507779e-02, {2.415773825954036e-01}}, + Descriptor{2, 3.854332309299303e-02, {4.743096925047182e-01}}, + Descriptor{3, 2.793936645159989e-02, {1.986833147973516e-01, 4.703664465259523e-02}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 8: { + constexpr size_t nb_points = 16; + SmallArray<R2> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{1, 7.215780383889359e-02, {}}, Descriptor{2, 4.754581713364231e-02, {4.592925882927232e-01}}, + Descriptor{2, 5.160868526735912e-02, {1.705693077517602e-01}}, + Descriptor{2, 1.622924881159904e-02, {5.054722831703098e-02}}, + Descriptor{3, 1.361515708721750e-02, {2.631128296346381e-01, 8.394777409957605e-03}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 9: { + constexpr size_t nb_points = 19; + SmallArray<R2> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{1, 4.856789814139942e-02, {}}, + Descriptor{2, 3.891377050238714e-02, {4.370895914929366e-01}}, + Descriptor{2, 3.982386946360512e-02, {1.882035356190327e-01}}, + Descriptor{2, 1.566735011356954e-02, {4.896825191987376e-01}}, + Descriptor{2, 1.278883782934902e-02, {4.472951339445271e-02}}, + Descriptor{3, 2.164176968864469e-02, {2.219629891607657e-01, 3.683841205473629e-02}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 10: { + constexpr size_t nb_points = 25; + SmallArray<R2> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{1, 4.087166457314299e-02, {}}, + Descriptor{2, 6.676484406574783e-03, {3.205537321694351e-02}}, + Descriptor{2, 2.297898180237237e-02, {1.421611010565644e-01}}, + Descriptor{3, 3.195245319821202e-02, {1.481328857838206e-01, 3.218129952888354e-01}}, + Descriptor{3, 1.709232408147971e-02, {3.691467818278110e-01, 2.961988948872977e-02}}, + Descriptor{3, 1.264887885364419e-02, {1.637017337371825e-01, 2.836766533993844e-02}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 11: { + constexpr size_t nb_points = 28; + SmallArray<R2> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{1, 4.288058986611211e-02, {}}, + Descriptor{2, 5.215935256447348e-03, {2.848541761437191e-02}}, + Descriptor{2, 3.525784205585829e-02, {2.102199567031783e-01}}, + Descriptor{2, 1.931537961850966e-02, {1.026354827122464e-01}}, + Descriptor{2, 8.303136527292684e-03, {4.958919009658909e-01}}, + Descriptor{2, 3.365807703973415e-02, {4.384659267643522e-01}}, + Descriptor{3, 5.145144786476639e-03, {7.325427686064452e-03, 1.493247886520824e-01}}, + Descriptor{3, 2.016623832025028e-02, {2.895811256377058e-01, 4.601050016542996e-02}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 12: { + constexpr size_t nb_points = 33; + SmallArray<R2> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{2, 1.213341904072602e-02, {4.882037509455415e-01}}, + Descriptor{2, 1.424302603443877e-02, {1.092578276593543e-01}}, + Descriptor{2, 3.127060659795138e-02, {2.714625070149261e-01}}, + Descriptor{2, 3.965821254986819e-03, {2.464636343633559e-02}}, + Descriptor{2, 2.495916746403047e-02, {4.401116486585931e-01}}, + Descriptor{3, 1.089179251930378e-02, {2.303415635526714e-02, 2.916556797383409e-01}}, + Descriptor{3, 2.161368182970710e-02, {2.554542286385174e-01, 1.162960196779266e-01}}, + Descriptor{3, 7.541838788255719e-03, {2.138249025617059e-02, 8.513377925102400e-01}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 13: { + constexpr size_t nb_points = 37; + SmallArray<R2> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{1, 3.398001829341582e-02, {}}, + Descriptor{2, 1.199720096444737e-02, {4.890769464525394e-01}}, + Descriptor{2, 2.913924255959999e-02, {2.213722862918329e-01}}, + Descriptor{2, 2.780098376522666e-02, {4.269414142598004e-01}}, + Descriptor{2, 3.026168551769586e-03, {2.150968110884318e-02}}, + Descriptor{3, 1.208951990579691e-02, {1.635974010678505e-01, 8.789548303219732e-02}}, + Descriptor{3, 7.482700552582834e-03, {2.437018690109383e-02, 1.109220428034634e-01}}, + Descriptor{3, 1.732063807042419e-02, {6.801224355420665e-02, 3.084417608921178e-01}}, + Descriptor{3, 4.795340501771632e-03, {2.725158177734296e-01, 5.126389102382369e-03}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 14: { + constexpr size_t nb_points = 42; + SmallArray<R2> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{2, 2.108129436849651e-02, {1.772055324125434e-01}}, + Descriptor{2, 1.639417677206267e-02, {4.176447193404539e-01}}, + Descriptor{2, 7.216849834888334e-03, {6.179988309087260e-02}}, + Descriptor{2, 1.094179068471444e-02, {4.889639103621786e-01}}, + Descriptor{2, 2.588705225364579e-02, {2.734775283088386e-01}}, + Descriptor{2, 2.461701801200041e-03, {1.939096124870105e-02}}, + Descriptor{3, 7.218154056766920e-03, {1.464695005565441e-02, 2.983728821362577e-01}}, + Descriptor{3, 1.233287660628184e-02, {1.722666878213556e-01, 5.712475740364794e-02}}, + Descriptor{3, 1.928575539353034e-02, {9.291624935697182e-02, 3.368614597963450e-01}}, + Descriptor{3, 2.505114419250336e-03, {1.189744976969569e-01, 1.268330932872025e-03}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 15: { + constexpr size_t nb_points = 49; + SmallArray<R2> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{1, 2.216769369109204e-02, {}}, + Descriptor{2, 2.135689078573028e-02, {4.053622141339755e-01}}, + Descriptor{2, 8.222368781312581e-03, {7.017355289998602e-02}}, + Descriptor{2, 8.698074000381707e-03, {4.741706814380198e-01}}, + Descriptor{2, 2.339168086435481e-02, {2.263787134203496e-01}}, + Descriptor{2, 4.786923091230043e-03, {4.949969567691262e-01}}, + Descriptor{2, 1.480387318952688e-03, {1.581172625098864e-02}}, + Descriptor{3, 7.801286415287982e-03, {3.146482428124508e-01, 1.837611238568109e-02}}, + Descriptor{3, 2.014926686009050e-03, {7.094860523645553e-02, 9.139237037308396e-03}}, + Descriptor{3, 1.436029346260067e-02, {9.424205359215536e-02, 1.905355894763939e-01}}, + Descriptor{3, 5.836310590787923e-03, {1.863871372816638e-02, 1.680686452224144e-01}}, + Descriptor{3, 1.565773814248464e-02, {9.579672364760859e-02, 3.389506114752772e-01}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 16: { + constexpr size_t nb_points = 55; + SmallArray<R2> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{1, 2.263228303690940e-02, {}}, + Descriptor{2, 2.054646157184948e-02, {2.459900704671417e-01}}, + Descriptor{2, 2.035591665621268e-02, {4.155848968854205e-01}}, + Descriptor{2, 7.390817345112202e-03, {8.535556658670032e-02}}, + Descriptor{2, 1.470920484949405e-02, {1.619186441912712e-01}}, + Descriptor{2, 2.209273156075285e-03, {5.000000000000000e-01}}, + Descriptor{2, 1.298716664913858e-02, {4.752807275459421e-01}}, + Descriptor{3, 9.469136232207850e-03, {1.910747636405291e-01, 5.475517491470312e-02}}, + Descriptor{3, 8.272333574175241e-04, {8.552204200227611e-03, 2.320342776881371e-02}}, + Descriptor{3, 7.504300892142903e-03, {3.317645234741477e-01, 1.893177828040591e-02}}, + Descriptor{3, 3.973796966696249e-03, {8.069616698587292e-02, 1.903012974369745e-02}}, + Descriptor{3, 1.599180503968503e-02, {3.082449691963540e-01, 1.026061902393981e-01}}, + Descriptor{3, 2.695593558424406e-03, {1.874417824837821e-01, 5.936350016822270e-03}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 17: { + constexpr size_t nb_points = 60; + SmallArray<R2> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{2, 1.365546326405105e-02, {4.171034443615992e-01}}, + Descriptor{2, 1.386943788818821e-03, {1.475549166075395e-02}}, + Descriptor{2, 1.250972547524868e-02, {4.655978716188903e-01}}, + Descriptor{2, 1.315631529400899e-02, {1.803581162663706e-01}}, + Descriptor{2, 6.229500401152721e-03, {6.665406347959693e-02}}, + Descriptor{2, 1.885811857639764e-02, {2.857065024365866e-01}}, + Descriptor{3, 3.989150102964797e-03, {1.591922874727927e-01, 1.601764236211930e-02}}, + Descriptor{3, 1.124388627334553e-02, {6.734937786736120e-02, 3.062815917461865e-01}}, + Descriptor{3, 5.199219977919768e-03, {4.154754592952291e-01, 1.322967276008689e-02}}, + Descriptor{3, 1.027894916022726e-02, {1.687225134952595e-01, 7.804234056828242e-02}}, + Descriptor{3, 4.346107250500596e-03, {2.717918700553548e-01, 1.313587083400269e-02}}, + Descriptor{3, 2.292174200867934e-03, {7.250547079900242e-02, 1.157517590318062e-02}}, + Descriptor{3, 1.308581296766849e-02, {2.992189424769703e-01, 1.575054779268699e-01}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 18: { + constexpr size_t nb_points = 67; + SmallArray<R2> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{1, 1.817786765071333e-02, {}}, + Descriptor{2, 1.665223501669507e-02, {3.999556280675762e-01}}, + Descriptor{2, 6.023323816999855e-03, {4.875803015748695e-01}}, + Descriptor{2, 9.474585753389433e-03, {4.618095064064492e-01}}, + Descriptor{2, 1.823754470447182e-02, {2.422647025142720e-01}}, + Descriptor{2, 3.564663009859485e-03, {3.883025608868559e-02}}, + Descriptor{2, 8.279579976001624e-03, {9.194774212164319e-02}}, + Descriptor{3, 6.879808117471103e-03, {1.838227079254640e-01, 4.580491585986078e-02}}, + Descriptor{3, 1.189095545007642e-02, {1.226967573719275e-01, 2.063492574338379e-01}}, + Descriptor{3, 2.265267251128533e-03, {3.956834343322697e-01, 3.897611033473383e-03}}, + Descriptor{3, 3.420055059803591e-03, {1.081957937910333e-01, 1.346201674144499e-02}}, + Descriptor{3, 8.873744551010202e-03, {3.197516245253774e-01, 4.026028346990806e-02}}, + Descriptor{3, 2.505330437289861e-03, {2.357721849581917e-01, 5.298335186609765e-03}}, + Descriptor{3, 6.114740634805449e-04, {2.709091099516201e-02, 5.483600420423190e-04}}, + Descriptor{3, 1.274108765591222e-02, {3.334935294498808e-01, 1.205876951639246e-01}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 19: { + constexpr size_t nb_points = 73; + SmallArray<R2> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{1, 1.723469885200617e-02, {}}, + Descriptor{2, 3.554628298899065e-03, {5.252389035120897e-02}}, + Descriptor{2, 5.160877571472141e-03, {4.925126750413369e-01}}, + Descriptor{2, 7.617175546509150e-03, {1.114488733230214e-01}}, + Descriptor{2, 1.149179501337080e-02, {4.591942010395437e-01}}, + Descriptor{2, 1.576876744657749e-02, {4.039697225519012e-01}}, + Descriptor{2, 1.232595742409543e-02, {1.781701047817643e-01}}, + Descriptor{2, 8.826613882214238e-04, {1.163946118378945e-02}}, + Descriptor{2, 1.587650968300154e-02, {2.551616329136077e-01}}, + Descriptor{3, 4.847742243427523e-03, {3.914585933169222e-02, 1.306976762680324e-01}}, + Descriptor{3, 1.317316098869537e-02, {1.293125644701578e-01, 3.113176298095413e-01}}, + Descriptor{3, 1.641038275917910e-03, {3.646177809746111e-01, 2.068925896604807e-03}}, + Descriptor{3, 9.053972465606226e-03, {2.214348854323312e-01, 7.456029460162668e-02}}, + Descriptor{3, 1.463157551735100e-03, {1.424257573657563e-01, 5.007288257354491e-03}}, + Descriptor{3, 8.051081382012054e-03, {3.540280097352752e-01, 4.088801119601688e-02}}, + Descriptor{3, 4.227943749768248e-03, {1.492405208198407e-02, 2.418945789605796e-01}}, + Descriptor{3, 1.663600681429694e-03, {9.776025800888155e-03, 6.008627532230670e-02}}}; + + fill_quadrature_points(descriptor_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 20: { + constexpr size_t nb_points = 79; + SmallArray<R2> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array descriptor_list = // + {Descriptor{1, 1.391011070145312e-02, {}}, + Descriptor{2, 1.408320130752025e-02, {2.545792676733391e-01}}, + Descriptor{2, 7.988407910666199e-04, {1.097614102839776e-02}}, + Descriptor{2, 7.830230776074533e-03, {1.093835967117146e-01}}, + Descriptor{2, 9.173462974252915e-03, {1.862949977445409e-01}}, + Descriptor{2, 9.452399933232448e-03, {4.455510569559248e-01}}, + Descriptor{2, 2.161275410665577e-03, {3.731088059888470e-02}}, + Descriptor{2, 1.378805062907046e-02, {3.934253478170999e-01}}, + Descriptor{2, 7.101825303408441e-03, {4.762456115404990e-01}}, + Descriptor{3, 2.202897418558497e-03, {1.591337076570672e-01, 7.570780504696529e-03}}, + Descriptor{3, 5.986398578954690e-03, {1.985181322287882e-01, 4.656036490766432e-02}}, + Descriptor{3, 1.129869602125866e-03, {4.854937607623754e-03, 6.409058560843406e-02}}, + Descriptor{3, 8.667225567219333e-03, {3.331348173095875e-01, 5.498747914298681e-02}}, + Descriptor{3, 4.145711527613858e-03, {3.836368477537459e-02, 9.995229628813866e-02}}, + Descriptor{3, 7.722607822099230e-03, {2.156070573900944e-01, 1.062272047202700e-01}}, + Descriptor{3, 3.695681500255298e-03, {9.831548292802561e-03, 4.200237588162241e-01}}, + Descriptor{3, 1.169174573182774e-02, {1.398080719917999e-01, 3.178601238357720e-01}}, + Descriptor{3, 3.578200238457685e-03, {2.805814114236652e-01, 1.073721285601109e-02}}}; + + fill_quadrature_points(descriptor_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 " + + std::to_string(TriangleGaussQuadrature::max_degree) + " on triangles"); + } + } +} diff --git a/src/analysis/TriangleGaussQuadrature.hpp b/src/analysis/TriangleGaussQuadrature.hpp new file mode 100644 index 0000000000000000000000000000000000000000..9e1edd3dedc01392f5cfae1ed8c0ab277b3ab2ba --- /dev/null +++ b/src/analysis/TriangleGaussQuadrature.hpp @@ -0,0 +1,37 @@ +#ifndef TRIANGLE_GAUSS_QUADRATURE_HPP +#define TRIANGLE_GAUSS_QUADRATURE_HPP + +#include <analysis/QuadratureFormula.hpp> + +/** + * Defines Gauss quadrature on the P1 reference triangle + * + * \note formulae are provided by + * + * âOn the identification of symmetric quadrature rules for finite + * element methodsâ by F.D. Witherden & P.E. Vincent (2015). + */ +class TriangleGaussQuadrature final : public QuadratureFormula<2> +{ + public: + constexpr static size_t max_degree = 20; + + private: + void _buildPointAndWeightLists(const size_t degree); + + public: + TriangleGaussQuadrature(TriangleGaussQuadrature&&) = default; + TriangleGaussQuadrature(const TriangleGaussQuadrature&) = default; + + private: + friend class QuadratureManager; + explicit TriangleGaussQuadrature(const size_t degree) : QuadratureFormula<2>(QuadratureType::Gauss) + { + this->_buildPointAndWeightLists(degree); + } + + TriangleGaussQuadrature() = delete; + ~TriangleGaussQuadrature() = default; +}; + +#endif // TRIANGLE_GAUSS_QUADRATURE_HPP diff --git a/src/geometry/CubeTransformation.hpp b/src/geometry/CubeTransformation.hpp new file mode 100644 index 0000000000000000000000000000000000000000..7bc12c324e4a55750b41b1584633cc789f8a7b2d --- /dev/null +++ b/src/geometry/CubeTransformation.hpp @@ -0,0 +1,79 @@ +#ifndef CUBE_TRANSFORMATION_HPP +#define CUBE_TRANSFORMATION_HPP + +#include <algebra/TinyMatrix.hpp> +#include <algebra/TinyVector.hpp> + +#include <array> + +class CubeTransformation +{ + public: + constexpr static size_t Dimension = 3; + constexpr static size_t NumberOfPoints = 8; + + private: + TinyMatrix<Dimension, NumberOfPoints - 1> m_coefficients; + TinyVector<Dimension> m_shift; + + public: + PUGS_INLINE + TinyVector<Dimension> + operator()(const TinyVector<Dimension>& x) const + { + const TinyVector<NumberOfPoints - 1> X = + {x[0], x[1], x[2], x[0] * x[1], x[1] * x[2], x[0] * x[2], x[0] * x[1] * x[2]}; + return m_coefficients * X + m_shift; + } + + PUGS_INLINE double + jacobianDeterminant(const TinyVector<Dimension>& X) const + { + static_assert(Dimension == 3, "invalid dimension"); + const auto& T = m_coefficients; + const double& x = X[0]; + const double& y = X[1]; + const double& z = X[2]; + + const TinyMatrix<Dimension, Dimension> J = {T(0, 0) + T(0, 3) * y + T(0, 5) * z + T(0, 6) * y * z, + T(0, 1) + T(0, 3) * x + T(0, 4) * z + T(0, 6) * x * z, + T(0, 2) + T(0, 4) * y + T(0, 5) * x + T(0, 6) * x * y, + // + T(1, 0) + T(1, 3) * y + T(1, 5) * z + T(1, 6) * y * z, + T(1, 1) + T(1, 3) * x + T(1, 4) * z + T(1, 6) * x * z, + T(1, 2) + T(1, 4) * y + T(1, 5) * x + T(1, 6) * x * y, + // + T(2, 0) + T(2, 3) * y + T(2, 5) * z + T(2, 6) * y * z, + T(2, 1) + T(2, 3) * x + T(2, 4) * z + T(2, 6) * x * z, + T(2, 2) + T(2, 4) * y + T(2, 5) * x + T(2, 6) * x * y}; + + return det(J); + } + + PUGS_INLINE + CubeTransformation(const TinyVector<Dimension>& a, + const TinyVector<Dimension>& b, + const TinyVector<Dimension>& c, + const TinyVector<Dimension>& d, + const TinyVector<Dimension>& e, + const TinyVector<Dimension>& f, + const TinyVector<Dimension>& g, + const TinyVector<Dimension>& h) + { + for (size_t i = 0; i < Dimension; ++i) { + m_coefficients(i, 0) = 0.125 * (-a[i] + b[i] + c[i] - d[i] - e[i] + f[i] + g[i] - h[i]); + m_coefficients(i, 1) = 0.125 * (-a[i] - b[i] + c[i] + d[i] - e[i] - f[i] + g[i] + h[i]); + m_coefficients(i, 2) = 0.125 * (-a[i] - b[i] - c[i] - d[i] + e[i] + f[i] + g[i] + h[i]); + m_coefficients(i, 3) = 0.125 * (+a[i] - b[i] + c[i] - d[i] + e[i] - f[i] + g[i] - h[i]); + m_coefficients(i, 4) = 0.125 * (+a[i] + b[i] - c[i] - d[i] - e[i] - f[i] + g[i] + h[i]); + m_coefficients(i, 5) = 0.125 * (+a[i] - b[i] - c[i] + d[i] - e[i] + f[i] + g[i] - h[i]); + m_coefficients(i, 6) = 0.125 * (-a[i] + b[i] - c[i] + d[i] + e[i] - f[i] + g[i] - h[i]); + + m_shift[i] = 0.125 * (a[i] + b[i] + c[i] + d[i] + e[i] + f[i] + g[i] + h[i]); + } + } + + ~CubeTransformation() = default; +}; + +#endif // CUBE_TRANSFORMATION_HPP diff --git a/src/geometry/LineTransformation.hpp b/src/geometry/LineTransformation.hpp new file mode 100644 index 0000000000000000000000000000000000000000..ae0b00a8a1dce7e4b6b6bb13a737ee1114a202f1 --- /dev/null +++ b/src/geometry/LineTransformation.hpp @@ -0,0 +1,78 @@ +#ifndef LINE_TRANSFORMATION_HPP +#define LINE_TRANSFORMATION_HPP + +#include <algebra/TinyVector.hpp> + +template <size_t GivenDimension> +class LineTransformation; + +template <> +class LineTransformation<1> +{ + public: + constexpr static size_t Dimension = 1; + + private: + double m_jacobian; + TinyVector<Dimension> m_shift; + + public: + PUGS_INLINE + TinyVector<Dimension> + operator()(const TinyVector<1>& x) const + { + return m_jacobian * x + m_shift; + } + + double + jacobianDeterminant() const + { + return m_jacobian; + } + + PUGS_INLINE + LineTransformation(const TinyVector<Dimension>& a, const TinyVector<Dimension>& b) + { + m_jacobian = 0.5 * (b[0] - a[0]); + m_shift = 0.5 * (a + b); + } + + ~LineTransformation() = default; +}; + +template <size_t GivenDimension> +class LineTransformation +{ + public: + constexpr static size_t Dimension = GivenDimension; + + private: + TinyVector<Dimension> m_velocity; + const double m_velocity_norm; + TinyVector<Dimension> m_shift; + + public: + PUGS_INLINE + TinyVector<Dimension> + operator()(const TinyVector<1>& x) const + { + return x[0] * m_velocity + m_shift; + } + + double + velocityNorm() const + { + return m_velocity_norm; + } + + PUGS_INLINE + LineTransformation(const TinyVector<Dimension>& a, const TinyVector<Dimension>& b) + : m_velocity{0.5 * (b - a)}, m_velocity_norm{l2Norm(m_velocity)}, m_shift{0.5 * (a + b)} + { + static_assert(Dimension > 1); + } + + ~LineTransformation() = default; +}; + +#endif // LINE_TRANSFORMATION_HPP diff --git a/src/geometry/PrismTransformation.hpp b/src/geometry/PrismTransformation.hpp new file mode 100644 index 0000000000000000000000000000000000000000..5e6e509ed0c92023b81ea13a3e686392dec52fcd --- /dev/null +++ b/src/geometry/PrismTransformation.hpp @@ -0,0 +1,71 @@ +#ifndef PRISM_TRANSFORMATION_HPP +#define PRISM_TRANSFORMATION_HPP + +#include <algebra/TinyMatrix.hpp> +#include <algebra/TinyVector.hpp> + +class PrismTransformation +{ + private: + constexpr static size_t Dimension = 3; + constexpr static size_t NumberOfPoints = 6; + + TinyMatrix<Dimension, NumberOfPoints - 1> m_coefficients; + TinyVector<Dimension> m_shift; + + public: + PUGS_INLINE + TinyVector<Dimension> + operator()(const TinyVector<Dimension>& x) const + { + const TinyVector<NumberOfPoints - 1> X = {x[0], x[1], x[2], x[0] * x[2], x[1] * x[2]}; + return m_coefficients * X + m_shift; + } + + double + jacobianDeterminant(const TinyVector<Dimension>& X) const + { + const auto& T = m_coefficients; + const double& x = X[0]; + const double& y = X[1]; + const double& z = X[2]; + + const TinyMatrix<Dimension, Dimension> J = {T(0, 0) + T(0, 3) * z, // + T(0, 1) + T(0, 4) * z, // + T(0, 2) + T(0, 3) * x + T(0, 4) * y, + // + T(1, 0) + T(1, 3) * z, // + T(1, 1) + T(1, 4) * z, // + T(1, 2) + T(1, 3) * x + T(1, 4) * y, + // + T(2, 0) + T(2, 3) * z, // + T(2, 1) + T(2, 4) * z, // + T(2, 2) + T(2, 3) * x + T(2, 4) * y}; + return det(J); + } + + PUGS_INLINE + PrismTransformation(const TinyVector<Dimension>& a, + const TinyVector<Dimension>& b, + const TinyVector<Dimension>& c, + const TinyVector<Dimension>& d, + const TinyVector<Dimension>& e, + const TinyVector<Dimension>& f) + { + static_assert(Dimension == 3, "invalid dimension"); + + for (size_t i = 0; i < Dimension; ++i) { + m_coefficients(i, 0) = 0.5 * (b[i] - a[i] + e[i] - d[i]); + m_coefficients(i, 1) = 0.5 * (c[i] + f[i] - a[i] - d[i]); + m_coefficients(i, 2) = 0.5 * (d[i] - a[i]); + m_coefficients(i, 3) = 0.5 * (a[i] - b[i] + e[i] - d[i]); + m_coefficients(i, 4) = 0.5 * (f[i] - c[i] + a[i] - d[i]); + } + + m_shift = 0.5 * (a + d); + } + + ~PrismTransformation() = default; +}; + +#endif // PRISM_TRANSFORMATION_HPP diff --git a/src/geometry/PyramidTransformation.hpp b/src/geometry/PyramidTransformation.hpp new file mode 100644 index 0000000000000000000000000000000000000000..2fa3eaa8d8b010dda5ac3d591b1183db707ea3f8 --- /dev/null +++ b/src/geometry/PyramidTransformation.hpp @@ -0,0 +1,68 @@ +#ifndef PYRAMID_TRANSFORMATION_HPP +#define PYRAMID_TRANSFORMATION_HPP + +#include <algebra/TinyMatrix.hpp> +#include <algebra/TinyVector.hpp> + +class PyramidTransformation +{ + private: + constexpr static size_t Dimension = 3; + constexpr static size_t NumberOfPoints = 5; + + TinyMatrix<Dimension, NumberOfPoints - 1> m_coefficients; + TinyVector<Dimension> m_shift; + + public: + PUGS_INLINE + TinyVector<Dimension> + operator()(const TinyVector<Dimension>& x) const + { + const TinyVector<NumberOfPoints - 1> X = {x[0], x[1], x[2], x[0] * x[1]}; + return m_coefficients * X + m_shift; + } + + double + jacobianDeterminant(const TinyVector<Dimension>& X) const + { + const auto& T = m_coefficients; + const double& x = X[0]; + const double& y = X[1]; + + const TinyMatrix<Dimension, Dimension> J = {T(0, 0) + T(0, 3) * y, // + T(0, 1) + T(0, 3) * x, // + T(0, 2), + // + T(1, 0) + T(1, 3) * y, // + T(1, 1) + T(1, 3) * x, // + T(1, 2), + // + T(2, 0) + T(2, 3) * y, // + T(2, 1) + T(2, 3) * x, // + T(2, 2)}; + return det(J); + } + + PUGS_INLINE + PyramidTransformation(const TinyVector<Dimension>& a, + const TinyVector<Dimension>& b, + const TinyVector<Dimension>& c, + const TinyVector<Dimension>& d, + const TinyVector<Dimension>& e) + { + static_assert(Dimension == 3, "invalid dimension"); + + m_shift = 0.25 * (a + b + c + d); + + for (size_t i = 0; i < Dimension; ++i) { + m_coefficients(i, 0) = 0.5 * (b[i] + c[i]) - m_shift[i]; + m_coefficients(i, 1) = 0.5 * (c[i] + d[i]) - m_shift[i]; + m_coefficients(i, 2) = e[i] - m_shift[i]; + m_coefficients(i, 3) = 0.5 * (a[i] + c[i]) - m_shift[i]; + } + } + + ~PyramidTransformation() = default; +}; + +#endif // PYRAMID_TRANSFORMATION_HPP diff --git a/src/geometry/SquareTransformation.hpp b/src/geometry/SquareTransformation.hpp new file mode 100644 index 0000000000000000000000000000000000000000..d79ae12c96c696f6be0bcf6245ede0b16c5f2a83 --- /dev/null +++ b/src/geometry/SquareTransformation.hpp @@ -0,0 +1,123 @@ +#ifndef SQUARE_TRANSFORMATION_HPP +#define SQUARE_TRANSFORMATION_HPP + +#include <algebra/TinyMatrix.hpp> +#include <algebra/TinyVector.hpp> + +#include <array> + +template <size_t GivenDimension> +class SquareTransformation; + +template <> +class SquareTransformation<2> +{ + public: + constexpr static size_t Dimension = 2; + constexpr static size_t NumberOfPoints = 4; + + private: + TinyMatrix<Dimension, NumberOfPoints - 1> m_coefficients; + TinyVector<Dimension> m_shift; + + public: + PUGS_INLINE + TinyVector<Dimension> + operator()(const TinyVector<2>& x) const + { + const TinyVector<NumberOfPoints - 1> X = {x[0], x[1], x[0] * x[1]}; + return m_coefficients * X + m_shift; + } + + PUGS_INLINE double + jacobianDeterminant(const TinyVector<Dimension>& X) const + { + const auto& T = m_coefficients; + const double& x = X[0]; + const double& y = X[1]; + + const TinyMatrix<Dimension, Dimension> J = {T(0, 0) + T(0, 2) * y, // + T(0, 1) + T(0, 2) * x, + // + T(1, 0) + T(1, 2) * y, // + T(1, 1) + T(1, 2) * x}; + return det(J); + } + + PUGS_INLINE + SquareTransformation(const TinyVector<Dimension>& a, + const TinyVector<Dimension>& b, + const TinyVector<Dimension>& c, + const TinyVector<Dimension>& d) + { + for (size_t i = 0; i < Dimension; ++i) { + m_coefficients(i, 0) = 0.25 * (-a[i] + b[i] + c[i] - d[i]); + m_coefficients(i, 1) = 0.25 * (-a[i] - b[i] + c[i] + d[i]); + m_coefficients(i, 2) = 0.25 * (+a[i] - b[i] + c[i] - d[i]); + + m_shift[i] = 0.25 * (a[i] + b[i] + c[i] + d[i]); + } + } + + ~SquareTransformation() = default; +}; + +template <size_t GivenDimension> +class SquareTransformation +{ + public: + constexpr static size_t Dimension = GivenDimension; + static_assert(Dimension == 3, "Square transformation is defined in dimension 2 or 3"); + + constexpr static size_t NumberOfPoints = 4; + + private: + TinyMatrix<Dimension, NumberOfPoints - 1> m_coefficients; + TinyVector<Dimension> m_shift; + + public: + PUGS_INLINE + TinyVector<Dimension> + operator()(const TinyVector<2>& x) const + { + const TinyVector<NumberOfPoints - 1> X = {x[0], x[1], x[0] * x[1]}; + return m_coefficients * X + m_shift; + } + + PUGS_INLINE double + areaVariationNorm(const TinyVector<2>& X) const + { + const auto& T = m_coefficients; + const double& x = X[0]; + const double& y = X[1]; + + const TinyVector<Dimension> dxT = {T(0, 0) + T(0, 2) * y, // + T(1, 0) + T(1, 2) * y, // + T(2, 0) + T(2, 2) * y}; + + const TinyVector<Dimension> dyT = {T(0, 1) + T(0, 2) * x, // + T(1, 1) + T(1, 2) * x, // + T(2, 1) + T(2, 2) * x}; + + return l2Norm(crossProduct(dxT, dyT)); + } + + PUGS_INLINE + SquareTransformation(const TinyVector<Dimension>& a, + const TinyVector<Dimension>& b, + const TinyVector<Dimension>& c, + const TinyVector<Dimension>& d) + { + for (size_t i = 0; i < Dimension; ++i) { + m_coefficients(i, 0) = 0.25 * (-a[i] + b[i] + c[i] - d[i]); + m_coefficients(i, 1) = 0.25 * (-a[i] - b[i] + c[i] + d[i]); + m_coefficients(i, 2) = 0.25 * (+a[i] - b[i] + c[i] - d[i]); + + m_shift[i] = 0.25 * (a[i] + b[i] + c[i] + d[i]); + } + } + + ~SquareTransformation() = default; +}; + +#endif // SQUARE_TRANSFORMATION_HPP diff --git a/src/geometry/TetrahedronTransformation.hpp b/src/geometry/TetrahedronTransformation.hpp new file mode 100644 index 0000000000000000000000000000000000000000..64244266957a350e8be8f78c2eab3d5fead629e1 --- /dev/null +++ b/src/geometry/TetrahedronTransformation.hpp @@ -0,0 +1,53 @@ +#ifndef TETRAHEDRON_TRANSFORMATION_HPP +#define TETRAHEDRON_TRANSFORMATION_HPP + +#include <algebra/TinyMatrix.hpp> +#include <algebra/TinyVector.hpp> + +class TetrahedronTransformation +{ + public: + constexpr static size_t Dimension = 3; + + private: + constexpr static size_t NumberOfPoints = Dimension + 1; + + TinyMatrix<Dimension> m_jacobian; + TinyVector<Dimension> m_shift; + double m_jacobian_determinant; + + public: + PUGS_INLINE + TinyVector<Dimension> + operator()(const TinyVector<Dimension>& x) const + { + return m_jacobian * x + m_shift; + } + + double + jacobianDeterminant() const + { + return m_jacobian_determinant; + } + + PUGS_INLINE + TetrahedronTransformation(const TinyVector<Dimension>& a, + const TinyVector<Dimension>& b, + const TinyVector<Dimension>& c, + const TinyVector<Dimension>& d) + { + for (size_t i = 0; i < Dimension; ++i) { + m_jacobian(i, 0) = b[i] - a[i]; + m_jacobian(i, 1) = c[i] - a[i]; + m_jacobian(i, 2) = d[i] - a[i]; + } + + m_shift = a; + + m_jacobian_determinant = det(m_jacobian); + } + + ~TetrahedronTransformation() = default; +}; + +#endif // TETRAHEDRON_TRANSFORMATION_HPP diff --git a/src/geometry/TriangleTransformation.hpp b/src/geometry/TriangleTransformation.hpp new file mode 100644 index 0000000000000000000000000000000000000000..9210e0bda55bb19dfdfd877e509801fa87f0a4f0 --- /dev/null +++ b/src/geometry/TriangleTransformation.hpp @@ -0,0 +1,93 @@ +#ifndef TRIANGLE_TRANSFORMATION_HPP +#define TRIANGLE_TRANSFORMATION_HPP + +#include <algebra/TinyMatrix.hpp> +#include <algebra/TinyVector.hpp> + +template <size_t GivenDimension> +class TriangleTransformation; + +template <> +class TriangleTransformation<2> +{ + public: + constexpr static size_t Dimension = 2; + + private: + TinyMatrix<Dimension> m_jacobian; + TinyVector<Dimension> m_shift; + double m_jacobian_determinant; + + public: + PUGS_INLINE + TinyVector<Dimension> + operator()(const TinyVector<2>& x) const + { + return m_jacobian * x + m_shift; + } + + double + jacobianDeterminant() const + { + return m_jacobian_determinant; + } + + PUGS_INLINE + TriangleTransformation(const TinyVector<Dimension>& a, const TinyVector<Dimension>& b, const TinyVector<Dimension>& c) + { + for (size_t i = 0; i < Dimension; ++i) { + m_jacobian(i, 0) = b[i] - a[i]; + m_jacobian(i, 1) = c[i] - a[i]; + } + + m_shift = a; + + m_jacobian_determinant = det(m_jacobian); + } + + ~TriangleTransformation() = default; +}; + +template <size_t GivenDimension> +class TriangleTransformation +{ + public: + constexpr static size_t Dimension = GivenDimension; + static_assert(Dimension == 3, "Triangle transformation is defined in dimension 2 or 3"); + + private: + TinyMatrix<Dimension, 2> m_jacobian; + TinyVector<Dimension> m_shift; + double m_area_variation_norm; + + public: + PUGS_INLINE + TinyVector<Dimension> + operator()(const TinyVector<2>& x) const + { + return m_jacobian * x + m_shift; + } + + double + areaVariationNorm() const + { + return m_area_variation_norm; + } + + PUGS_INLINE + TriangleTransformation(const TinyVector<Dimension>& a, const TinyVector<Dimension>& b, const TinyVector<Dimension>& c) + { + for (size_t i = 0; i < Dimension; ++i) { + m_jacobian(i, 0) = b[i] - a[i]; + m_jacobian(i, 1) = c[i] - a[i]; + } + + m_shift = a; + + m_area_variation_norm = l2Norm(crossProduct(b - a, c - a)); + } + + ~TriangleTransformation() = default; +}; + +#endif // TRIANGLE_TRANSFORMATION_HPP diff --git a/src/language/modules/MeshModule.cpp b/src/language/modules/MeshModule.cpp index 61767078aeaa0f8362393196a01ce9cde167a064..fe0e438a80009cf18c15b3f2793361c931d12d68 100644 --- a/src/language/modules/MeshModule.cpp +++ b/src/language/modules/MeshModule.cpp @@ -4,7 +4,6 @@ #include <language/node_processor/ExecutionPolicy.hpp> #include <language/utils/BuiltinFunctionEmbedder.hpp> #include <language/utils/FunctionTable.hpp> -#include <language/utils/PugsFunctionAdapter.hpp> #include <language/utils/SymbolTable.hpp> #include <language/utils/TypeDescriptor.hpp> #include <mesh/CartesianMeshBuilder.hpp> @@ -12,7 +11,7 @@ #include <mesh/DiamondDualMeshManager.hpp> #include <mesh/GmshReader.hpp> #include <mesh/Mesh.hpp> -#include <mesh/MeshInterpoler.hpp> +#include <mesh/MeshRelaxer.hpp> #include <mesh/MeshTransformer.hpp> #include <utils/Exceptions.hpp> @@ -43,7 +42,7 @@ MeshModule::MeshModule() )); - this->_addBuiltinFunction("interpolate", + this->_addBuiltinFunction("relax", std::make_shared<BuiltinFunctionEmbedder< std::shared_ptr<const IMesh>(const std::shared_ptr<const IMesh>&, const std::shared_ptr<const IMesh>&, const double&)>>( @@ -51,7 +50,7 @@ MeshModule::MeshModule() [](const std::shared_ptr<const IMesh>& source_mesh, const std::shared_ptr<const IMesh>& destination_mesh, const double& theta) -> std::shared_ptr<const IMesh> { - return MeshInterpoler{}.interpolate(source_mesh, destination_mesh, theta); + return MeshRelaxer{}.relax(source_mesh, destination_mesh, theta); } )); diff --git a/src/language/modules/SchemeModule.cpp b/src/language/modules/SchemeModule.cpp index d989bff45dffa0c0f361607c1488f75f4dc9f0f4..fcebda3dedc014d935a7e73a96785762f4cb00e1 100644 --- a/src/language/modules/SchemeModule.cpp +++ b/src/language/modules/SchemeModule.cpp @@ -1,5 +1,8 @@ #include <language/modules/SchemeModule.hpp> +#include <analysis/GaussLegendreQuadratureDescriptor.hpp> +#include <analysis/GaussLobattoQuadratureDescriptor.hpp> +#include <analysis/GaussQuadratureDescriptor.hpp> #include <language/modules/BinaryOperatorRegisterForVh.hpp> #include <language/modules/MathFunctionRegisterForVh.hpp> #include <language/modules/UnaryOperatorRegisterForVh.hpp> @@ -17,9 +20,11 @@ #include <scheme/DirichletBoundaryConditionDescriptor.hpp> #include <scheme/DiscreteFunctionDescriptorP0.hpp> #include <scheme/DiscreteFunctionDescriptorP0Vector.hpp> +#include <scheme/DiscreteFunctionIntegrator.hpp> #include <scheme/DiscreteFunctionInterpoler.hpp> #include <scheme/DiscreteFunctionP0.hpp> #include <scheme/DiscreteFunctionUtils.hpp> +#include <scheme/DiscreteFunctionVectorIntegrator.hpp> #include <scheme/DiscreteFunctionVectorInterpoler.hpp> #include <scheme/FixedBoundaryConditionDescriptor.hpp> #include <scheme/FourierBoundaryConditionDescriptor.hpp> @@ -38,6 +43,7 @@ SchemeModule::SchemeModule() { this->_addTypeDescriptor(ast_node_data_type_from<std::shared_ptr<const IDiscreteFunction>>); this->_addTypeDescriptor(ast_node_data_type_from<std::shared_ptr<const IDiscreteFunctionDescriptor>>); + this->_addTypeDescriptor(ast_node_data_type_from<std::shared_ptr<const IQuadratureDescriptor>>); this->_addTypeDescriptor(ast_node_data_type_from<std::shared_ptr<const IBoundaryDescriptor>>); this->_addTypeDescriptor(ast_node_data_type_from<std::shared_ptr<const IBoundaryConditionDescriptor>>); @@ -59,6 +65,64 @@ SchemeModule::SchemeModule() )); + this->_addBuiltinFunction("Gauss", std::make_shared< + BuiltinFunctionEmbedder<std::shared_ptr<const IQuadratureDescriptor>(uint64_t)>>( + [](uint64_t degree) -> std::shared_ptr<const IQuadratureDescriptor> { + return std::make_shared<GaussQuadratureDescriptor>(degree); + } + + )); + + this->_addBuiltinFunction("GaussLobatto", + std::make_shared< + BuiltinFunctionEmbedder<std::shared_ptr<const IQuadratureDescriptor>(uint64_t)>>( + [](uint64_t degree) -> std::shared_ptr<const IQuadratureDescriptor> { + return std::make_shared<GaussLobattoQuadratureDescriptor>(degree); + } + + )); + + this->_addBuiltinFunction("GaussLegendre", + std::make_shared< + BuiltinFunctionEmbedder<std::shared_ptr<const IQuadratureDescriptor>(uint64_t)>>( + [](uint64_t degree) -> std::shared_ptr<const IQuadratureDescriptor> { + return std::make_shared<GaussLegendreQuadratureDescriptor>(degree); + } + + )); + + this + ->_addBuiltinFunction("integrate", + std::make_shared<BuiltinFunctionEmbedder< + std::shared_ptr<const IDiscreteFunction>(std::shared_ptr<const IMesh>, + std::shared_ptr<const IQuadratureDescriptor>, + std::shared_ptr<const IDiscreteFunctionDescriptor>, + const std::vector<FunctionSymbolId>&)>>( + [](std::shared_ptr<const IMesh> mesh, + std::shared_ptr<const IQuadratureDescriptor> quadrature_descriptor, + std::shared_ptr<const IDiscreteFunctionDescriptor> discrete_function_descriptor, + const std::vector<FunctionSymbolId>& function_id_list) + -> std::shared_ptr<const IDiscreteFunction> { + return DiscreteFunctionVectorIntegrator{mesh, quadrature_descriptor, + discrete_function_descriptor, function_id_list} + .integrate(); + } + + )); + + this->_addBuiltinFunction("integrate", + std::make_shared<BuiltinFunctionEmbedder< + std::shared_ptr<const IDiscreteFunction>(std::shared_ptr<const IMesh>, + std::shared_ptr<const IQuadratureDescriptor>, + const FunctionSymbolId&)>>( + [](std::shared_ptr<const IMesh> mesh, + std::shared_ptr<const IQuadratureDescriptor> quadrature_descriptor, + const FunctionSymbolId& function_id) -> std::shared_ptr<const IDiscreteFunction> { + return DiscreteFunctionIntegrator{mesh, quadrature_descriptor, function_id}.integrate(); + } + + )); + this->_addBuiltinFunction( "interpolate", std::make_shared<BuiltinFunctionEmbedder<std::shared_ptr< diff --git a/src/language/modules/SchemeModule.hpp b/src/language/modules/SchemeModule.hpp index 758b5f9c56fcdc928adfc4678a0a02a8dcfa5bd8..52fc163ee5b6bfcec2cbeceb6d618e9ce3d9c213 100644 --- a/src/language/modules/SchemeModule.hpp +++ b/src/language/modules/SchemeModule.hpp @@ -25,6 +25,11 @@ template <> inline ASTNodeDataType ast_node_data_type_from<std::shared_ptr<const IDiscreteFunctionDescriptor>> = ASTNodeDataType::build<ASTNodeDataType::type_id_t>("Vh_type"); +class IQuadratureDescriptor; +template <> +inline ASTNodeDataType ast_node_data_type_from<std::shared_ptr<const IQuadratureDescriptor>> = + ASTNodeDataType::build<ASTNodeDataType::type_id_t>("quadrature"); + class SchemeModule : public BuiltinModule { friend class MathFunctionRegisterForVh; diff --git a/src/language/utils/EvaluateAtPoints.hpp b/src/language/utils/EvaluateAtPoints.hpp new file mode 100644 index 0000000000000000000000000000000000000000..d842dd44b96b02caf23515d4c35da0a0ee277865 --- /dev/null +++ b/src/language/utils/EvaluateAtPoints.hpp @@ -0,0 +1,68 @@ +#ifndef EVALUATE_AT_POINTS_HPP +#define EVALUATE_AT_POINTS_HPP + +#include <language/utils/PugsFunctionAdapter.hpp> +#include <utils/Array.hpp> + +class FunctionSymbolId; + +template <typename T> +class EvaluateAtPoints; +template <typename OutputType, typename InputType> +class EvaluateAtPoints<OutputType(InputType)> : public PugsFunctionAdapter<OutputType(InputType)> +{ + using Adapter = PugsFunctionAdapter<OutputType(InputType)>; + + public: + template <typename InputArrayT, typename OutputArrayT> + static PUGS_INLINE void + evaluateTo(const FunctionSymbolId& function_symbol_id, const InputArrayT& position, OutputArrayT& value) + { + static_assert(std::is_same_v<std::remove_const_t<typename InputArrayT::data_type>, InputType>, + "invalid input data type"); + static_assert(std::is_same_v<std::remove_const_t<typename OutputArrayT::data_type>, OutputType>, + "invalid output data type"); + Assert(size(value) == size(position)); + + auto& expression = Adapter::getFunctionExpression(function_symbol_id); + auto convert_result = Adapter::getResultConverter(expression.m_data_type); + + auto context_list = Adapter::getContextList(expression); + + using execution_space = typename Kokkos::DefaultExecutionSpace::execution_space; + Kokkos::Experimental::UniqueToken<execution_space, Kokkos::Experimental::UniqueTokenScope::Global> tokens; + + if constexpr (std::is_arithmetic_v<OutputType>) { + value.fill(0); + } else if constexpr (is_tiny_vector_v<OutputType> or is_tiny_matrix_v<OutputType>) { + value.fill(zero); + } else { + static_assert(std::is_same_v<OutputType, double>, "unexpected output type"); + } + + parallel_for(size(position), [=, &expression, &tokens](typename InputArrayT::index_type i) { + const int32_t t = tokens.acquire(); + + auto& execution_policy = context_list[t]; + + Adapter::convertArgs(execution_policy.currentContext(), position[i]); + auto result = expression.execute(execution_policy); + value[i] = convert_result(std::move(result)); + + tokens.release(t); + }); + } + + template <class InputArrayT> + static PUGS_INLINE Array<OutputType> + evaluate(const FunctionSymbolId& function_symbol_id, const InputArrayT& position) + { + static_assert(std::is_same_v<std::remove_const_t<typename InputArrayT::data_type>, InputType>, + "invalid input data type"); + Array<OutputType> value(size(position)); + evaluateTo(function_symbol_id, position, value); + return value; + } +}; + +#endif // EVALUATE_AT_POINTS_HPP diff --git a/src/language/utils/IntegrateCellArray.hpp b/src/language/utils/IntegrateCellArray.hpp new file mode 100644 index 0000000000000000000000000000000000000000..41450de3b9675fbe929fcaf0fde855ccb1be2fe4 --- /dev/null +++ b/src/language/utils/IntegrateCellArray.hpp @@ -0,0 +1,69 @@ +#ifndef INTEGRATE_CELL_ARRAY_HPP +#define INTEGRATE_CELL_ARRAY_HPP + +#include <language/utils/IntegrateCellValue.hpp> +#include <mesh/CellType.hpp> +#include <mesh/ItemArray.hpp> + +template <typename T> +class IntegrateCellArray; +template <typename OutputType, typename InputType> +class IntegrateCellArray<OutputType(InputType)> +{ + static constexpr size_t Dimension = OutputType::Dimension; + + public: + template <typename MeshType> + PUGS_INLINE static CellArray<OutputType> + integrate(const std::vector<FunctionSymbolId>& function_symbol_id_list, + const IQuadratureDescriptor& quadrature_descriptor, + const MeshType& mesh) + { + CellArray<OutputType> cell_array{mesh.connectivity(), function_symbol_id_list.size()}; + + for (size_t i_function_symbol = 0; i_function_symbol < function_symbol_id_list.size(); ++i_function_symbol) { + const FunctionSymbolId& function_symbol_id = function_symbol_id_list[i_function_symbol]; + CellValue<OutputType> cell_value = + IntegrateCellValue<OutputType(InputType)>::integrate(function_symbol_id, quadrature_descriptor, mesh); + parallel_for( + cell_value.numberOfItems(), + PUGS_LAMBDA(CellId cell_id) { cell_array[cell_id][i_function_symbol] = cell_value[cell_id]; }); + } + + return cell_array; + } + + template <typename MeshType> + PUGS_INLINE static Table<OutputType> + integrate(const std::vector<FunctionSymbolId>& function_symbol_id_list, + const IQuadratureDescriptor& quadrature_descriptor, + const MeshType& mesh, + const Array<const CellId>& list_of_cells) + { + Table<OutputType> table{list_of_cells.size(), function_symbol_id_list.size()}; + + for (size_t i_function_symbol = 0; i_function_symbol < function_symbol_id_list.size(); ++i_function_symbol) { + const FunctionSymbolId& function_symbol_id = function_symbol_id_list[i_function_symbol]; + Array<OutputType> array = + IntegrateCellValue<OutputType(InputType)>::integrate(function_symbol_id, quadrature_descriptor, mesh, + list_of_cells); + + parallel_for( + array.size(), PUGS_LAMBDA(size_t i) { table[i][i_function_symbol] = array[i]; }); + } + + return table; + } + + template <typename MeshType> + PUGS_INLINE static Table<OutputType> + integrate(const std::vector<FunctionSymbolId>& function_symbol_id_list, + const IQuadratureDescriptor& quadrature_descriptor, + const MeshType& mesh, + const Array<CellId>& list_of_cells) + { + return integrate(function_symbol_id_list, quadrature_descriptor, mesh, Array<const CellId>{list_of_cells}); + } +}; + +#endif // INTEGRATE_CELL_ARRAY_HPP diff --git a/src/language/utils/IntegrateCellValue.hpp b/src/language/utils/IntegrateCellValue.hpp new file mode 100644 index 0000000000000000000000000000000000000000..c4eafc151712219101a42d28ba2e8eb774ab0060 --- /dev/null +++ b/src/language/utils/IntegrateCellValue.hpp @@ -0,0 +1,52 @@ +#ifndef INTEGRATE_CELL_VALUE_HPP +#define INTEGRATE_CELL_VALUE_HPP + +#include <analysis/IQuadratureDescriptor.hpp> +#include <language/utils/IntegrateOnCells.hpp> +#include <mesh/ItemType.hpp> +#include <mesh/ItemValue.hpp> +#include <mesh/Mesh.hpp> + +template <typename T> +class IntegrateCellValue; +template <typename OutputType, typename InputType> +class IntegrateCellValue<OutputType(InputType)> +{ + public: + template <typename MeshType> + PUGS_INLINE static CellValue<OutputType> + integrate(const FunctionSymbolId& function_symbol_id, + const IQuadratureDescriptor& quadrature_descriptor, + const MeshType& mesh) + { + CellValue<OutputType> value(mesh.connectivity()); + IntegrateOnCells<OutputType(const InputType)>::template integrateTo<MeshType>(function_symbol_id, + quadrature_descriptor, mesh, value); + + return value; + } + + template <typename MeshType> + PUGS_INLINE static Array<OutputType> + integrate(const FunctionSymbolId& function_symbol_id, + const IQuadratureDescriptor& quadrature_descriptor, + const MeshType& mesh, + const Array<const CellId>& list_of_cells) + { + return IntegrateOnCells<OutputType(const InputType)>::integrate(function_symbol_id, quadrature_descriptor, mesh, + list_of_cells); + } + + template <typename MeshType> + PUGS_INLINE static Array<OutputType> + integrate(const FunctionSymbolId& function_symbol_id, + const IQuadratureDescriptor& quadrature_descriptor, + const MeshType& mesh, + const Array<CellId>& list_of_cells) + { + return IntegrateOnCells<OutputType(const InputType)>::integrate(function_symbol_id, quadrature_descriptor, mesh, + Array<const CellId>{list_of_cells}); + } +}; + +#endif // INTEGRATE_CELL_VALUE_HPP diff --git a/src/language/utils/IntegrateOnCells.hpp b/src/language/utils/IntegrateOnCells.hpp new file mode 100644 index 0000000000000000000000000000000000000000..8b6008d73672a24ee5473369250f00ce05342d7e --- /dev/null +++ b/src/language/utils/IntegrateOnCells.hpp @@ -0,0 +1,603 @@ +#ifndef INTEGRATE_ON_CELLS_HPP +#define INTEGRATE_ON_CELLS_HPP + +#include <analysis/IQuadratureDescriptor.hpp> +#include <analysis/QuadratureManager.hpp> +#include <geometry/CubeTransformation.hpp> +#include <geometry/LineTransformation.hpp> +#include <geometry/PrismTransformation.hpp> +#include <geometry/PyramidTransformation.hpp> +#include <geometry/SquareTransformation.hpp> +#include <geometry/TetrahedronTransformation.hpp> +#include <geometry/TriangleTransformation.hpp> +#include <language/utils/PugsFunctionAdapter.hpp> +#include <mesh/CellType.hpp> +#include <mesh/Connectivity.hpp> +#include <mesh/ItemId.hpp> +#include <utils/Array.hpp> + +class FunctionSymbolId; + +template <typename T> +class IntegrateOnCells; +template <typename OutputType, typename InputType> +class IntegrateOnCells<OutputType(InputType)> : public PugsFunctionAdapter<OutputType(InputType)> +{ + private: + using Adapter = PugsFunctionAdapter<OutputType(InputType)>; + + template <size_t Dimension> + class AllCells + { + private: + const Connectivity<Dimension>& m_connectivity; + + public: + using index_type = CellId; + + PUGS_INLINE + CellId + cellId(const CellId cell_id) const + { + return cell_id; + } + + PUGS_INLINE + size_t + size() const + { + return m_connectivity.numberOfCells(); + } + + PUGS_INLINE + AllCells(const Connectivity<Dimension>& connectivity) : m_connectivity{connectivity} {} + }; + + class CellList + { + private: + const Array<CellId>& m_cell_list; + + public: + using index_type = Array<CellId>::index_type; + + PUGS_INLINE + CellId + cellId(const index_type index) const + { + return m_cell_list[index]; + } + + PUGS_INLINE + size_t + size() const + { + return m_cell_list.size(); + } + + PUGS_INLINE + CellList(const Array<CellId>& cell_list) : m_cell_list{cell_list} {} + }; + + template <typename MeshType, typename OutputArrayT, typename ListTypeT> + static PUGS_INLINE void + _tensorialIntegrateTo(const FunctionSymbolId& function_symbol_id, + const IQuadratureDescriptor& quadrature_descriptor, + const MeshType& mesh, + const ListTypeT& cell_list, + OutputArrayT& value) + { + constexpr size_t Dimension = MeshType::Dimension; + + static_assert(std::is_same_v<TinyVector<Dimension>, InputType>, "invalid input data type"); + static_assert(std::is_same_v<std::remove_const_t<typename OutputArrayT::data_type>, OutputType>, + "invalid output data type"); + + auto& expression = Adapter::getFunctionExpression(function_symbol_id); + auto convert_result = Adapter::getResultConverter(expression.m_data_type); + + auto context_list = Adapter::getContextList(expression); + + using execution_space = typename Kokkos::DefaultExecutionSpace::execution_space; + Kokkos::Experimental::UniqueToken<execution_space, Kokkos::Experimental::UniqueTokenScope::Global> tokens; + + if constexpr (std::is_arithmetic_v<OutputType>) { + value.fill(0); + } else if constexpr (is_tiny_vector_v<OutputType> or is_tiny_matrix_v<OutputType>) { + value.fill(zero); + } else { + static_assert(std::is_same_v<OutputType, double>, "unexpected output type"); + } + + const auto& connectivity = mesh.connectivity(); + + const auto cell_to_node_matrix = connectivity.cellToNodeMatrix(); + const auto cell_type = connectivity.cellType(); + const auto xr = mesh.xr(); + + auto invalid_cell = std::make_pair(false, CellId{}); + + const auto qf = [&] { + if constexpr (Dimension == 1) { + return QuadratureManager::instance().getLineFormula(quadrature_descriptor); + } else if constexpr (Dimension == 2) { + return QuadratureManager::instance().getSquareFormula(quadrature_descriptor); + } else { + static_assert(Dimension == 3); + return QuadratureManager::instance().getCubeFormula(quadrature_descriptor); + } + }(); + + parallel_for(cell_list.size(), [=, &expression, &tokens, &invalid_cell, &qf, + &cell_list](typename ListTypeT::index_type index) { + const int32_t t = tokens.acquire(); + auto& execution_policy = context_list[t]; + + const CellId cell_id = cell_list.cellId(index); + + const auto cell_to_node = cell_to_node_matrix[cell_id]; + + if constexpr (Dimension == 1) { + switch (cell_type[cell_id]) { + case CellType::Line: { + const LineTransformation<1> T(xr[cell_to_node[0]], xr[cell_to_node[1]]); + + for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { + const auto xi = qf.point(i_point); + Adapter::convertArgs(execution_policy.currentContext(), T(xi)); + auto result = expression.execute(execution_policy); + value[index] += qf.weight(i_point) * T.jacobianDeterminant() * convert_result(std::move(result)); + } + break; + } + default: { + invalid_cell = std::make_pair(true, cell_id); + break; + } + } + } else if constexpr (Dimension == 2) { + switch (cell_type[cell_id]) { + case CellType::Triangle: { + const SquareTransformation<2> T(xr[cell_to_node[0]], xr[cell_to_node[1]], xr[cell_to_node[2]], + xr[cell_to_node[2]]); + + for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { + const auto xi = qf.point(i_point); + Adapter::convertArgs(execution_policy.currentContext(), T(xi)); + auto result = expression.execute(execution_policy); + value[index] += qf.weight(i_point) * T.jacobianDeterminant(xi) * convert_result(std::move(result)); + } + break; + } + case CellType::Quadrangle: { + const SquareTransformation<2> T(xr[cell_to_node[0]], xr[cell_to_node[1]], xr[cell_to_node[2]], + xr[cell_to_node[3]]); + + for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { + const auto xi = qf.point(i_point); + Adapter::convertArgs(execution_policy.currentContext(), T(xi)); + auto result = expression.execute(execution_policy); + value[index] += qf.weight(i_point) * T.jacobianDeterminant(xi) * convert_result(std::move(result)); + } + break; + } + default: { + invalid_cell = std::make_pair(true, cell_id); + break; + } + } + } else { + static_assert(Dimension == 3); + + switch (cell_type[cell_id]) { + case CellType::Tetrahedron: { + const CubeTransformation T(xr[cell_to_node[0]], xr[cell_to_node[1]], xr[cell_to_node[2]], + xr[cell_to_node[2]], // + xr[cell_to_node[3]], xr[cell_to_node[3]], xr[cell_to_node[3]], + xr[cell_to_node[3]]); + + for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { + const auto xi = qf.point(i_point); + Adapter::convertArgs(execution_policy.currentContext(), T(xi)); + auto result = expression.execute(execution_policy); + value[index] += qf.weight(i_point) * T.jacobianDeterminant(xi) * convert_result(std::move(result)); + } + break; + } + case CellType::Pyramid: { + if (cell_to_node.size() == 5) { + const CubeTransformation T(xr[cell_to_node[0]], xr[cell_to_node[1]], xr[cell_to_node[2]], // + xr[cell_to_node[3]], // + xr[cell_to_node[4]], xr[cell_to_node[4]], xr[cell_to_node[4]], + xr[cell_to_node[4]]); + + for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { + const auto xi = qf.point(i_point); + Adapter::convertArgs(execution_policy.currentContext(), T(xi)); + auto result = expression.execute(execution_policy); + value[index] += qf.weight(i_point) * T.jacobianDeterminant(xi) * convert_result(std::move(result)); + } + } else { + throw NotImplementedError("integration on pyramid with non-quadrangular base (number of nodes " + + std::to_string(cell_to_node.size()) + ")"); + } + break; + } + case CellType::Diamond: { + if (cell_to_node.size() == 5) { + { // top tetrahedron + const CubeTransformation T0(xr[cell_to_node[1]], xr[cell_to_node[2]], xr[cell_to_node[3]], + xr[cell_to_node[3]], // + xr[cell_to_node[4]], xr[cell_to_node[4]], xr[cell_to_node[4]], + xr[cell_to_node[4]]); + + for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { + const auto xi = qf.point(i_point); + Adapter::convertArgs(execution_policy.currentContext(), T0(xi)); + auto result = expression.execute(execution_policy); + value[index] += qf.weight(i_point) * T0.jacobianDeterminant(xi) * convert_result(std::move(result)); + } + } + { // bottom tetrahedron + const CubeTransformation T1(xr[cell_to_node[3]], xr[cell_to_node[3]], xr[cell_to_node[2]], + xr[cell_to_node[1]], // + xr[cell_to_node[0]], xr[cell_to_node[0]], xr[cell_to_node[0]], + xr[cell_to_node[0]]); + + for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { + const auto xi = qf.point(i_point); + Adapter::convertArgs(execution_policy.currentContext(), T1(xi)); + auto result = expression.execute(execution_policy); + value[index] += qf.weight(i_point) * T1.jacobianDeterminant(xi) * convert_result(std::move(result)); + } + } + } else if (cell_to_node.size() == 6) { + { // top pyramid + const CubeTransformation T0(xr[cell_to_node[1]], xr[cell_to_node[2]], xr[cell_to_node[3]], + xr[cell_to_node[4]], // + xr[cell_to_node[5]], xr[cell_to_node[5]], xr[cell_to_node[5]], + xr[cell_to_node[5]]); + + for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { + const auto xi = qf.point(i_point); + Adapter::convertArgs(execution_policy.currentContext(), T0(xi)); + auto result = expression.execute(execution_policy); + value[index] += qf.weight(i_point) * T0.jacobianDeterminant(xi) * convert_result(std::move(result)); + } + } + { // bottom pyramid + const CubeTransformation T1(xr[cell_to_node[4]], xr[cell_to_node[3]], xr[cell_to_node[2]], + xr[cell_to_node[1]], // + xr[cell_to_node[0]], xr[cell_to_node[0]], xr[cell_to_node[0]], + xr[cell_to_node[0]]); + + for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { + const auto xi = qf.point(i_point); + Adapter::convertArgs(execution_policy.currentContext(), T1(xi)); + auto result = expression.execute(execution_policy); + value[index] += qf.weight(i_point) * T1.jacobianDeterminant(xi) * convert_result(std::move(result)); + } + } + } else { + throw NotImplementedError("integration on diamond with non-quadrangular base (" + + std::to_string(cell_to_node.size()) + ")"); + } + break; + } + case CellType::Prism: { + const CubeTransformation T(xr[cell_to_node[0]], xr[cell_to_node[1]], // + xr[cell_to_node[2]], xr[cell_to_node[2]], // + xr[cell_to_node[3]], xr[cell_to_node[4]], // + xr[cell_to_node[5]], xr[cell_to_node[5]]); + + for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { + const auto xi = qf.point(i_point); + Adapter::convertArgs(execution_policy.currentContext(), T(xi)); + auto result = expression.execute(execution_policy); + value[index] += qf.weight(i_point) * T.jacobianDeterminant(xi) * convert_result(std::move(result)); + } + break; + } + case CellType::Hexahedron: { + const CubeTransformation T(xr[cell_to_node[0]], xr[cell_to_node[1]], xr[cell_to_node[2]], xr[cell_to_node[3]], + xr[cell_to_node[4]], xr[cell_to_node[5]], xr[cell_to_node[6]], + xr[cell_to_node[7]]); + + for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { + const auto xi = qf.point(i_point); + Adapter::convertArgs(execution_policy.currentContext(), T(xi)); + auto result = expression.execute(execution_policy); + value[index] += qf.weight(i_point) * T.jacobianDeterminant(xi) * convert_result(std::move(result)); + } + break; + } + default: { + invalid_cell = std::make_pair(true, cell_id); + break; + } + } + } + + tokens.release(t); + }); + + if (invalid_cell.first) { + std::ostringstream os; + os << "invalid cell type for integration: " << name(cell_type[invalid_cell.second]); + throw UnexpectedError(os.str()); + } + } + + template <typename MeshType, typename OutputArrayT, typename ListTypeT> + static PUGS_INLINE void + _directIntegrateTo(const FunctionSymbolId& function_symbol_id, + const IQuadratureDescriptor& quadrature_descriptor, + const MeshType& mesh, + const ListTypeT& cell_list, + OutputArrayT& value) + { + Assert(not quadrature_descriptor.isTensorial()); + + constexpr size_t Dimension = MeshType::Dimension; + + static_assert(std::is_same_v<TinyVector<Dimension>, InputType>, "invalid input data type"); + static_assert(std::is_same_v<std::remove_const_t<typename OutputArrayT::data_type>, OutputType>, + "invalid output data type"); + + auto& expression = Adapter::getFunctionExpression(function_symbol_id); + auto convert_result = Adapter::getResultConverter(expression.m_data_type); + + auto context_list = Adapter::getContextList(expression); + + using execution_space = typename Kokkos::DefaultExecutionSpace::execution_space; + Kokkos::Experimental::UniqueToken<execution_space, Kokkos::Experimental::UniqueTokenScope::Global> tokens; + + if constexpr (std::is_arithmetic_v<OutputType>) { + value.fill(0); + } else if constexpr (is_tiny_vector_v<OutputType> or is_tiny_matrix_v<OutputType>) { + value.fill(zero); + } else { + static_assert(std::is_same_v<OutputType, double>, "unexpected output type"); + } + + const auto& connectivity = mesh.connectivity(); + + const auto cell_to_node_matrix = connectivity.cellToNodeMatrix(); + const auto cell_type = connectivity.cellType(); + const auto xr = mesh.xr(); + + auto invalid_cell = std::make_pair(false, CellId{}); + + parallel_for(cell_list.size(), [=, &expression, &tokens, &invalid_cell, &quadrature_descriptor, + &cell_list](const typename ListTypeT::index_type& index) { + const int32_t t = tokens.acquire(); + auto& execution_policy = context_list[t]; + + const CellId cell_id = cell_list.cellId(index); + + const auto cell_to_node = cell_to_node_matrix[cell_id]; + + if constexpr (Dimension == 1) { + switch (cell_type[cell_id]) { + case CellType::Line: { + const LineTransformation<1> T(xr[cell_to_node[0]], xr[cell_to_node[1]]); + const auto qf = QuadratureManager::instance().getLineFormula(quadrature_descriptor); + + for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { + const auto xi = qf.point(i_point); + Adapter::convertArgs(execution_policy.currentContext(), T(xi)); + auto result = expression.execute(execution_policy); + value[index] += qf.weight(i_point) * T.jacobianDeterminant() * convert_result(std::move(result)); + } + break; + } + default: { + invalid_cell = std::make_pair(true, cell_id); + break; + } + } + } else if constexpr (Dimension == 2) { + switch (cell_type[cell_id]) { + case CellType::Triangle: { + const TriangleTransformation<2> T(xr[cell_to_node[0]], xr[cell_to_node[1]], xr[cell_to_node[2]]); + const auto qf = QuadratureManager::instance().getTriangleFormula(quadrature_descriptor); + + for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { + const auto xi = qf.point(i_point); + Adapter::convertArgs(execution_policy.currentContext(), T(xi)); + auto result = expression.execute(execution_policy); + value[index] += qf.weight(i_point) * T.jacobianDeterminant() * convert_result(std::move(result)); + } + break; + } + case CellType::Quadrangle: { + const SquareTransformation<2> T(xr[cell_to_node[0]], xr[cell_to_node[1]], xr[cell_to_node[2]], + xr[cell_to_node[3]]); + const auto qf = QuadratureManager::instance().getSquareFormula(quadrature_descriptor); + + for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { + const auto xi = qf.point(i_point); + Adapter::convertArgs(execution_policy.currentContext(), T(xi)); + auto result = expression.execute(execution_policy); + value[index] += qf.weight(i_point) * T.jacobianDeterminant(xi) * convert_result(std::move(result)); + } + break; + } + default: { + invalid_cell = std::make_pair(true, cell_id); + break; + } + } + } else { + static_assert(Dimension == 3); + + switch (cell_type[cell_id]) { + case CellType::Tetrahedron: { + const TetrahedronTransformation T(xr[cell_to_node[0]], xr[cell_to_node[1]], // + xr[cell_to_node[2]], xr[cell_to_node[3]]); + const auto qf = QuadratureManager::instance().getTetrahedronFormula(quadrature_descriptor); + + for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { + const auto xi = qf.point(i_point); + Adapter::convertArgs(execution_policy.currentContext(), T(xi)); + auto result = expression.execute(execution_policy); + value[index] += qf.weight(i_point) * T.jacobianDeterminant() * convert_result(std::move(result)); + } + break; + } + case CellType::Pyramid: { + if (cell_to_node.size() == 5) { + const PyramidTransformation T(xr[cell_to_node[0]], xr[cell_to_node[1]], xr[cell_to_node[2]], // + xr[cell_to_node[3]], xr[cell_to_node[4]]); + const auto qf = QuadratureManager::instance().getPyramidFormula(quadrature_descriptor); + + for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { + const auto xi = qf.point(i_point); + Adapter::convertArgs(execution_policy.currentContext(), T(xi)); + auto result = expression.execute(execution_policy); + value[index] += qf.weight(i_point) * T.jacobianDeterminant(xi) * convert_result(std::move(result)); + } + } else { + throw NotImplementedError("integration on pyramid with non-quadrangular base"); + } + break; + } + case CellType::Diamond: { + if (cell_to_node.size() == 5) { + const auto qf = QuadratureManager::instance().getTetrahedronFormula(quadrature_descriptor); + { // top tetrahedron + const TetrahedronTransformation T0(xr[cell_to_node[1]], xr[cell_to_node[2]], xr[cell_to_node[3]], // + xr[cell_to_node[4]]); + + for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { + const auto xi = qf.point(i_point); + Adapter::convertArgs(execution_policy.currentContext(), T0(xi)); + auto result = expression.execute(execution_policy); + value[index] += qf.weight(i_point) * T0.jacobianDeterminant() * convert_result(std::move(result)); + } + } + { // bottom tetrahedron + const TetrahedronTransformation T1(xr[cell_to_node[3]], xr[cell_to_node[2]], xr[cell_to_node[1]], // + xr[cell_to_node[0]]); + + for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { + const auto xi = qf.point(i_point); + Adapter::convertArgs(execution_policy.currentContext(), T1(xi)); + auto result = expression.execute(execution_policy); + value[index] += qf.weight(i_point) * T1.jacobianDeterminant() * convert_result(std::move(result)); + } + } + } else if (cell_to_node.size() == 6) { + const auto qf = QuadratureManager::instance().getPyramidFormula(quadrature_descriptor); + { // top pyramid + const PyramidTransformation T0(xr[cell_to_node[1]], xr[cell_to_node[2]], xr[cell_to_node[3]], + xr[cell_to_node[4]], xr[cell_to_node[5]]); + + for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { + const auto xi = qf.point(i_point); + Adapter::convertArgs(execution_policy.currentContext(), T0(xi)); + auto result = expression.execute(execution_policy); + value[index] += qf.weight(i_point) * T0.jacobianDeterminant(xi) * convert_result(std::move(result)); + } + } + { // bottom pyramid + const PyramidTransformation T1(xr[cell_to_node[4]], xr[cell_to_node[3]], xr[cell_to_node[2]], + xr[cell_to_node[1]], xr[cell_to_node[0]]); + + for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { + const auto xi = qf.point(i_point); + Adapter::convertArgs(execution_policy.currentContext(), T1(xi)); + auto result = expression.execute(execution_policy); + value[index] += qf.weight(i_point) * T1.jacobianDeterminant(xi) * convert_result(std::move(result)); + } + } + } else { + throw NotImplementedError("integration on diamond with non-quadrangular base (" + + std::to_string(cell_to_node.size()) + ")"); + } + break; + } + case CellType::Prism: { + const PrismTransformation T(xr[cell_to_node[0]], xr[cell_to_node[1]], xr[cell_to_node[2]], + xr[cell_to_node[3]], xr[cell_to_node[4]], xr[cell_to_node[5]]); + const auto qf = QuadratureManager::instance().getPrismFormula(quadrature_descriptor); + + for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { + const auto xi = qf.point(i_point); + Adapter::convertArgs(execution_policy.currentContext(), T(xi)); + auto result = expression.execute(execution_policy); + value[index] += qf.weight(i_point) * T.jacobianDeterminant(xi) * convert_result(std::move(result)); + } + break; + } + case CellType::Hexahedron: { + const CubeTransformation T(xr[cell_to_node[0]], xr[cell_to_node[1]], xr[cell_to_node[2]], xr[cell_to_node[3]], + xr[cell_to_node[4]], xr[cell_to_node[5]], xr[cell_to_node[6]], + xr[cell_to_node[7]]); + const auto qf = QuadratureManager::instance().getCubeFormula(quadrature_descriptor); + + for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { + const auto xi = qf.point(i_point); + Adapter::convertArgs(execution_policy.currentContext(), T(xi)); + auto result = expression.execute(execution_policy); + value[index] += qf.weight(i_point) * T.jacobianDeterminant(xi) * convert_result(std::move(result)); + } + break; + } + default: { + invalid_cell = std::make_pair(true, cell_id); + break; + } + } + } + + tokens.release(t); + }); + + if (invalid_cell.first) { + std::ostringstream os; + os << "invalid cell type for integration: " << name(cell_type[invalid_cell.second]); + throw UnexpectedError(os.str()); + } + } + + public: + template <typename MeshType, typename ArrayT> + static PUGS_INLINE void + integrateTo(const FunctionSymbolId& function_symbol_id, + const IQuadratureDescriptor& quadrature_descriptor, + const MeshType& mesh, + ArrayT& value) + { + constexpr size_t Dimension = MeshType::Dimension; + + if (quadrature_descriptor.isTensorial()) { + _tensorialIntegrateTo<MeshType, ArrayT>(function_symbol_id, quadrature_descriptor, mesh, + AllCells<Dimension>{mesh.connectivity()}, value); + } else { + _directIntegrateTo<MeshType, ArrayT>(function_symbol_id, quadrature_descriptor, mesh, + AllCells<Dimension>{mesh.connectivity()}, value); + } + } + + template <typename MeshType, template <typename DataType> typename ArrayT> + static PUGS_INLINE ArrayT<OutputType> + integrate(const FunctionSymbolId& function_symbol_id, + const IQuadratureDescriptor& quadrature_descriptor, + const MeshType& mesh, + const ArrayT<CellId>& cell_list) + { + ArrayT<OutputType> value(size(cell_list)); + if (quadrature_descriptor.isTensorial()) { + _tensorialIntegrateTo<MeshType, ArrayT<OutputType>>(function_symbol_id, quadrature_descriptor, mesh, + CellList{cell_list}, value); + } else { + _directIntegrateTo<MeshType, ArrayT<OutputType>>(function_symbol_id, quadrature_descriptor, mesh, + CellList{cell_list}, value); + } + + return value; + } +}; + +#endif // INTEGRATE_ON_CELLS_HPP diff --git a/src/language/utils/InterpolateItemArray.hpp b/src/language/utils/InterpolateItemArray.hpp index c507c527ca9f1c59070410c09f802f524a3de083..17b72de6d62e0ac68062343010154257c43d3006 100644 --- a/src/language/utils/InterpolateItemArray.hpp +++ b/src/language/utils/InterpolateItemArray.hpp @@ -2,17 +2,15 @@ #define INTERPOLATE_ITEM_ARRAY_HPP #include <language/utils/InterpolateItemValue.hpp> -#include <language/utils/PugsFunctionAdapter.hpp> #include <mesh/ItemArray.hpp> #include <mesh/ItemType.hpp> template <typename T> class InterpolateItemArray; template <typename OutputType, typename InputType> -class InterpolateItemArray<OutputType(InputType)> : public PugsFunctionAdapter<OutputType(InputType)> +class InterpolateItemArray<OutputType(InputType)> { static constexpr size_t Dimension = OutputType::Dimension; - using Adapter = PugsFunctionAdapter<OutputType(InputType)>; public: template <ItemType item_type> diff --git a/src/language/utils/InterpolateItemValue.hpp b/src/language/utils/InterpolateItemValue.hpp index de12b563a19ded640f0b4bbae3184f383d90a2f3..dc3ef056b0693d4d32e695a33b7772aa11264b73 100644 --- a/src/language/utils/InterpolateItemValue.hpp +++ b/src/language/utils/InterpolateItemValue.hpp @@ -1,46 +1,23 @@ #ifndef INTERPOLATE_ITEM_VALUE_HPP #define INTERPOLATE_ITEM_VALUE_HPP -#include <language/utils/PugsFunctionAdapter.hpp> +#include <language/utils/EvaluateAtPoints.hpp> #include <mesh/ItemType.hpp> #include <mesh/ItemValue.hpp> template <typename T> class InterpolateItemValue; template <typename OutputType, typename InputType> -class InterpolateItemValue<OutputType(InputType)> : public PugsFunctionAdapter<OutputType(InputType)> +class InterpolateItemValue<OutputType(InputType)> { - static constexpr size_t Dimension = OutputType::Dimension; - using Adapter = PugsFunctionAdapter<OutputType(InputType)>; - public: template <ItemType item_type> PUGS_INLINE static ItemValue<OutputType, item_type> interpolate(const FunctionSymbolId& function_symbol_id, const ItemValue<const InputType, item_type>& position) { - auto& expression = Adapter::getFunctionExpression(function_symbol_id); - auto convert_result = Adapter::getResultConverter(expression.m_data_type); - - Array<ExecutionPolicy> context_list = Adapter::getContextList(expression); - - using execution_space = typename Kokkos::DefaultExecutionSpace::execution_space; - Kokkos::Experimental::UniqueToken<execution_space, Kokkos::Experimental::UniqueTokenScope::Global> tokens; const IConnectivity& connectivity = *position.connectivity_ptr(); - ItemValue<OutputType, item_type> value(connectivity); - using ItemId = ItemIdT<item_type>; - - parallel_for(connectivity.template numberOf<item_type>(), [=, &expression, &tokens](ItemId i) { - const int32_t t = tokens.acquire(); - - auto& execution_policy = context_list[t]; - - Adapter::convertArgs(execution_policy.currentContext(), position[i]); - auto result = expression.execute(execution_policy); - value[i] = convert_result(std::move(result)); - - tokens.release(t); - }); + EvaluateAtPoints<OutputType(const InputType)>::evaluateTo(function_symbol_id, position, value); return value; } @@ -51,31 +28,15 @@ class InterpolateItemValue<OutputType(InputType)> : public PugsFunctionAdapter<O const ItemValue<const InputType, item_type>& position, const Array<const ItemIdT<item_type>>& list_of_items) { - auto& expression = Adapter::getFunctionExpression(function_symbol_id); - auto convert_result = Adapter::getResultConverter(expression.m_data_type); - - Array<ExecutionPolicy> context_list = Adapter::getContextList(expression); - - using execution_space = typename Kokkos::DefaultExecutionSpace::execution_space; - Kokkos::Experimental::UniqueToken<execution_space, Kokkos::Experimental::UniqueTokenScope::Global> tokens; - - Array<OutputType> value{list_of_items.size()}; + Array<InputType> item_position{list_of_items.size()}; using ItemId = ItemIdT<item_type>; + parallel_for( + list_of_items.size(), PUGS_LAMBDA(size_t i_item) { + ItemId item_id = list_of_items[i_item]; + item_position[i_item] = position[item_id]; + }); - parallel_for(list_of_items.size(), [=, &expression, &tokens](size_t i_item) { - ItemId item_id = list_of_items[i_item]; - const int32_t t = tokens.acquire(); - - auto& execution_policy = context_list[t]; - - Adapter::convertArgs(execution_policy.currentContext(), position[item_id]); - auto result = expression.execute(execution_policy); - value[i_item] = convert_result(std::move(result)); - - tokens.release(t); - }); - - return value; + return EvaluateAtPoints<OutputType(const InputType)>::evaluate(function_symbol_id, item_position); } template <ItemType item_type> diff --git a/src/language/utils/PugsFunctionAdapter.hpp b/src/language/utils/PugsFunctionAdapter.hpp index 3047652e3017fb2cd193b799a8edf454e3e4c22b..d39e0f4233df70709d3d765146447727f7541ae4 100644 --- a/src/language/utils/PugsFunctionAdapter.hpp +++ b/src/language/utils/PugsFunctionAdapter.hpp @@ -6,9 +6,9 @@ #include <language/utils/ASTNodeDataType.hpp> #include <language/utils/ASTNodeDataTypeTraits.hpp> #include <language/utils/SymbolTable.hpp> -#include <utils/Array.hpp> #include <utils/Exceptions.hpp> #include <utils/PugsMacros.hpp> +#include <utils/SmallArray.hpp> #include <Kokkos_Core.hpp> @@ -128,7 +128,7 @@ class PugsFunctionAdapter<OutputType(InputType...)> [[nodiscard]] PUGS_INLINE static auto getContextList(const ASTNode& expression) { - Array<ExecutionPolicy> context_list(Kokkos::DefaultExecutionSpace::impl_thread_pool_size()); + SmallArray<ExecutionPolicy> context_list(Kokkos::DefaultExecutionSpace::impl_thread_pool_size()); auto& context = expression.m_symbol_table->context(); for (size_t i = 0; i < context_list.size(); ++i) { diff --git a/src/main.cpp b/src/main.cpp index cf382d69b491e85968d977e9023ac094d81c3bc2..4b9dfffd985bc5f400ace5986355f55a591ff9f2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,3 +1,4 @@ +#include <analysis/QuadratureManager.hpp> #include <language/PugsParser.hpp> #include <mesh/DiamondDualConnectivityManager.hpp> #include <mesh/DiamondDualMeshManager.hpp> @@ -13,6 +14,7 @@ main(int argc, char* argv[]) SynchronizerManager::create(); RandomEngine::create(); + QuadratureManager::create(); MeshDataManager::create(); DiamondDualConnectivityManager::create(); DiamondDualMeshManager::create(); @@ -23,6 +25,7 @@ main(int argc, char* argv[]) DiamondDualConnectivityManager::destroy(); MeshDataManager::destroy(); RandomEngine::destroy(); + QuadratureManager::destroy(); SynchronizerManager::destroy(); finalize(); diff --git a/src/mesh/CMakeLists.txt b/src/mesh/CMakeLists.txt index f536bae7afe8b6d1bc979e4abd9feccaf7c86a7d..309e3323a435571b14d0e0d0f631675558c6314b 100644 --- a/src/mesh/CMakeLists.txt +++ b/src/mesh/CMakeLists.txt @@ -20,7 +20,7 @@ add_library( MeshFaceBoundary.cpp MeshFlatFaceBoundary.cpp MeshFlatNodeBoundary.cpp - MeshInterpoler.cpp + MeshRelaxer.cpp MeshLineNodeBoundary.cpp MeshNodeBoundary.cpp MeshRandomizer.cpp diff --git a/src/mesh/ConnectivityBuilderBase.cpp b/src/mesh/ConnectivityBuilderBase.cpp index 60c38bfb84fb975c0e2cdc3b07d1d97e39eb0021..3da4837ee005fffaf7744165e1470f6ac5730183 100644 --- a/src/mesh/ConnectivityBuilderBase.cpp +++ b/src/mesh/ConnectivityBuilderBase.cpp @@ -116,10 +116,36 @@ ConnectivityBuilderBase::_computeCellFaceAndFaceNodeConnectivities(ConnectivityD face_cells_map[f3].emplace_back(std::make_tuple(j, 3, f3.reversed())); break; } + case CellType::Prism: { + // face 0 + Face f0({cell_nodes[2], cell_nodes[1], cell_nodes[0]}, node_number_vector); + face_cells_map[f0].emplace_back(std::make_tuple(j, 0, f0.reversed())); + + // face 1 + Face f1({cell_nodes[3], cell_nodes[4], cell_nodes[5]}, node_number_vector); + face_cells_map[f1].emplace_back(std::make_tuple(j, 1, f1.reversed())); + + // face 2 + Face f2({cell_nodes[1], cell_nodes[2], cell_nodes[5], cell_nodes[4]}, node_number_vector); + face_cells_map[f2].emplace_back(std::make_tuple(j, 2, f2.reversed())); + + // face 3 + Face f3({cell_nodes[0], cell_nodes[1], cell_nodes[4], cell_nodes[3]}, node_number_vector); + face_cells_map[f3].emplace_back(std::make_tuple(j, 3, f3.reversed())); + + // face 4 + Face f4({cell_nodes[2], cell_nodes[0], cell_nodes[3], cell_nodes[5]}, node_number_vector); + face_cells_map[f4].emplace_back(std::make_tuple(j, 4, f4.reversed())); + + cell_nb_faces[j] = 5; + break; + } case CellType::Pyramid: { cell_nb_faces[j] = cell_nodes.size(); - std::vector<unsigned int> base_nodes; - std::copy_n(cell_nodes.begin(), cell_nodes.size() - 1, std::back_inserter(base_nodes)); + std::vector<unsigned int> base_nodes(cell_nodes.size() - 1); + for (size_t i = 0; i < base_nodes.size(); ++i) { + base_nodes[base_nodes.size() - 1 - i] = cell_nodes[i]; + } // base face { @@ -332,6 +358,22 @@ ConnectivityBuilderBase::_computeFaceEdgeAndEdgeNodeAndCellEdgeConnectivities(Co descriptor.cell_to_edge_vector.emplace_back(cell_edge_vector); break; } + case CellType::Prism: { + constexpr int local_edge[12][2] = {{0, 1}, {1, 2}, {2, 0}, {3, 4}, {4, 5}, {5, 3}, {0, 3}, {1, 4}, {2, 5}}; + std::vector<unsigned int> cell_edge_vector; + cell_edge_vector.reserve(9); + for (int i_edge = 0; i_edge < 9; ++i_edge) { + const auto e = local_edge[i_edge]; + Edge edge{{cell_nodes[e[0]], cell_nodes[e[1]]}, node_number_vector}; + auto i = edge_id_map.find(edge); + if (i == edge_id_map.end()) { + throw NormalError("could not find this edge"); + } + cell_edge_vector.push_back(i->second); + } + descriptor.cell_to_edge_vector.emplace_back(cell_edge_vector); + break; + } case CellType::Pyramid: { const size_t number_of_edges = 2 * cell_nodes.size(); std::vector<unsigned int> base_nodes; diff --git a/src/mesh/DiamondDualConnectivityBuilder.cpp b/src/mesh/DiamondDualConnectivityBuilder.cpp index 31d54be8997e9571958399f17c44dbcede1c35e4..bb9c9b3b643c87c4a71de31cf6a2a5c60e53b0e2 100644 --- a/src/mesh/DiamondDualConnectivityBuilder.cpp +++ b/src/mesh/DiamondDualConnectivityBuilder.cpp @@ -8,7 +8,6 @@ #include <mesh/Mesh.hpp> #include <mesh/RefId.hpp> #include <utils/Array.hpp> -#include <utils/ArrayUtils.hpp> #include <utils/Messenger.hpp> #include <vector> @@ -87,21 +86,27 @@ DiamondDualConnectivityBuilder::_buildDiamondConnectivityDescriptor(const Connec diamond_descriptor.cell_type_vector.resize(diamond_number_of_cells); const auto& primal_face_to_cell_matrix = primal_connectivity.faceToCellMatrix(); + const auto& primal_face_to_node_matrix = primal_connectivity.faceToNodeMatrix(); + static_assert(Dimension > 1); parallel_for(primal_number_of_faces, [&](FaceId face_id) { const size_t i_cell = face_id; const auto& primal_face_cell_list = primal_face_to_cell_matrix[face_id]; - if (primal_face_cell_list.size() == 1) { - diamond_descriptor.cell_type_vector[i_cell] = CellType::Triangle; - } else { - Assert(primal_face_cell_list.size() == 2); - diamond_descriptor.cell_type_vector[i_cell] = CellType::Quadrangle; - } - - if constexpr (Dimension == 3) { + if constexpr (Dimension == 2) { + if (primal_face_cell_list.size() == 1) { + diamond_descriptor.cell_type_vector[i_cell] = CellType::Triangle; + } else { + Assert(primal_face_cell_list.size() == 2); + diamond_descriptor.cell_type_vector[i_cell] = CellType::Quadrangle; + } + } else if constexpr (Dimension == 3) { if (primal_face_cell_list.size() == 1) { - diamond_descriptor.cell_type_vector[i_cell] = CellType::Pyramid; + if (primal_face_to_node_matrix[face_id].size() == 3) { + diamond_descriptor.cell_type_vector[i_cell] = CellType::Tetrahedron; + } else { + diamond_descriptor.cell_type_vector[i_cell] = CellType::Pyramid; + } } else { Assert(primal_face_cell_list.size() == 2); diamond_descriptor.cell_type_vector[i_cell] = CellType::Diamond; @@ -111,7 +116,6 @@ DiamondDualConnectivityBuilder::_buildDiamondConnectivityDescriptor(const Connec diamond_descriptor.cell_to_node_vector.resize(diamond_number_of_cells); - const auto& primal_face_to_node_matrix = primal_connectivity.faceToNodeMatrix(); const auto& primal_face_local_number_in_their_cells = primal_connectivity.faceLocalNumbersInTheirCells(); const auto& cell_face_is_reversed = primal_connectivity.cellFaceIsReversed(); parallel_for(primal_number_of_faces, [&](FaceId face_id) { @@ -130,12 +134,17 @@ DiamondDualConnectivityBuilder::_buildDiamondConnectivityDescriptor(const Connec diamond_descriptor.cell_to_node_vector[i_diamond_cell][primal_face_node_list.size()] = primal_number_of_nodes + cell_id; - if (cell_face_is_reversed(cell_id, i_face_in_cell)) { - if constexpr (Dimension == 2) { + if constexpr (Dimension == 2) { + if (cell_face_is_reversed(cell_id, i_face_in_cell)) { std::swap(diamond_descriptor.cell_to_node_vector[i_diamond_cell][0], diamond_descriptor.cell_to_node_vector[i_diamond_cell][1]); - - } else { + } + } else { + if (not cell_face_is_reversed(cell_id, i_face_in_cell)) { + // In 3D the basis of the pyramid is described in the + // indirect way IF the face is not reversed. In other words + // the "topological normal" must point to the "top" of the + // pyramid. for (size_t i_node = 0; i_node < primal_face_node_list.size() / 2; ++i_node) { std::swap(diamond_descriptor.cell_to_node_vector[i_diamond_cell][i_node], diamond_descriptor diff --git a/src/mesh/GmshReader.cpp b/src/mesh/GmshReader.cpp index 3a83ef5c3f49d068fbfd8e62d4ff002df50a8845..e91638131b70113a768ba5398869d4d729144b0d 100644 --- a/src/mesh/GmshReader.cpp +++ b/src/mesh/GmshReader.cpp @@ -9,7 +9,6 @@ #include <mesh/ItemValueUtils.hpp> #include <mesh/Mesh.hpp> #include <mesh/RefItemList.hpp> -#include <utils/ArrayUtils.hpp> #include <utils/Exceptions.hpp> #include <rang.hpp> @@ -249,9 +248,20 @@ GmshConnectivityBuilder<3>::GmshConnectivityBuilder(const GmshReader::GmshData& descriptor.cell_number_vector[jh] = gmsh_data.__hexahedra_number[j]; } + const size_t nb_prisms = gmsh_data.__prisms.size(); + for (size_t j = 0; j < nb_prisms; ++j) { + const size_t jp = nb_tetrahedra + nb_hexahedra + j; + descriptor.cell_to_node_vector[jp].resize(6); + for (int r = 0; r < 6; ++r) { + descriptor.cell_to_node_vector[jp][r] = gmsh_data.__prisms[j][r]; + } + descriptor.cell_type_vector[jp] = CellType::Prism; + descriptor.cell_number_vector[jp] = gmsh_data.__prisms_number[j]; + } + const size_t nb_pyramids = gmsh_data.__pyramids.size(); for (size_t j = 0; j < nb_pyramids; ++j) { - const size_t jh = nb_tetrahedra + nb_hexahedra + j; + const size_t jh = nb_tetrahedra + nb_hexahedra + nb_prisms + j; descriptor.cell_to_node_vector[jh].resize(5); for (int r = 0; r < 5; ++r) { descriptor.cell_to_node_vector[jh][r] = gmsh_data.__pyramids[j][r]; @@ -504,6 +514,8 @@ GmshReader::GmshReader(const std::string& filename) : m_filename(filename) __keywordList["$EndElements"] = ENDELEMENTS; __keywordList["$PhysicalNames"] = PHYSICALNAMES; __keywordList["$EndPhysicalNames"] = ENDPHYSICALNAMES; + __keywordList["$Periodic"] = PERIODIC; + __keywordList["$EndPeriodic"] = ENDPERIODIC; __numberOfPrimitiveNodes.resize(16); __numberOfPrimitiveNodes[0] = 2; // edge @@ -533,7 +545,7 @@ GmshReader::GmshReader(const std::string& filename) : m_filename(filename) __primitivesNames[4] = "hexahedra"; __supportedPrimitives[4] = true; __primitivesNames[5] = "prisms"; - __supportedPrimitives[5] = false; + __supportedPrimitives[5] = true; __primitivesNames[6] = "pyramids"; __supportedPrimitives[6] = true; __primitivesNames[7] = "second order edges"; @@ -719,6 +731,24 @@ GmshReader::__readPhysicalNames2_2() } } +void +GmshReader::__readPeriodic2_2() +{ + // This is just a compatibility reading, periodic information is not + // used + const int number_of_periodic = this->_getInteger(); + for (int i = 0; i < number_of_periodic; ++i) { + [[maybe_unused]] const int dimension = this->_getInteger(); + [[maybe_unused]] const int id = this->_getInteger(); + [[maybe_unused]] const int master_id = this->_getInteger(); + [[maybe_unused]] const int nb_corresponding_nodes = this->_getInteger(); + for (int i_node = 0; i_node < nb_corresponding_nodes; ++i_node) { + [[maybe_unused]] const int node_id = this->_getInteger(); + [[maybe_unused]] const int master_id = this->_getInteger(); + } + } +} + // std::shared_ptr<IConnectivity> // GmshReader::_buildConnectivity3D(const size_t nb_cells) // { @@ -1027,6 +1057,12 @@ GmshReader::__proceedData() m_mesh_data.__hexahedra_number.resize(elementNumber[i]); break; } + case 5: { // prism + m_mesh_data.__prisms = Array<GmshData::Prism>(elementNumber[i]); + m_mesh_data.__prisms_ref.resize(elementNumber[i]); + m_mesh_data.__prisms_number.resize(elementNumber[i]); + break; + } case 6: { // pyramid m_mesh_data.__pyramids = Array<GmshData::Pyramid>(elementNumber[i]); m_mesh_data.__pyramids_ref.resize(elementNumber[i]); @@ -1040,7 +1076,6 @@ GmshReader::__proceedData() break; } // Unsupported entities - case 5: // prism case 7: // second order edge case 8: // second order triangle case 9: // second order quadrangle @@ -1170,6 +1205,24 @@ GmshReader::__proceedData() hexahedronNumber++; // one more hexahedron break; } + case 5: { // prism + int& prism_number = elementNumber[5]; + const int a = m_mesh_data.__verticesCorrepondance[elementVertices[0]]; + const int b = m_mesh_data.__verticesCorrepondance[elementVertices[1]]; + const int c = m_mesh_data.__verticesCorrepondance[elementVertices[2]]; + const int d = m_mesh_data.__verticesCorrepondance[elementVertices[3]]; + const int e = m_mesh_data.__verticesCorrepondance[elementVertices[4]]; + const int f = m_mesh_data.__verticesCorrepondance[elementVertices[5]]; + if ((a < 0) or (b < 0) or (c < 0) or (d < 0) or (e < 0) or (f < 0)) { + throw NormalError("reading file '" + m_filename + "': error reading element " + std::to_string(i) + + " [bad vertices definition]"); + } + m_mesh_data.__prisms[prism_number] = GmshData::Prism(a, b, c, d, e, f); + m_mesh_data.__prisms_ref[prism_number] = m_mesh_data.__references[i]; + m_mesh_data.__prisms_number[prism_number] = m_mesh_data.__elementNumber[i]; + prism_number++; // one more prism + break; + } case 6: { // pyramid int& pyramid_number = elementNumber[6]; @@ -1182,7 +1235,7 @@ GmshReader::__proceedData() throw NormalError("reading file '" + m_filename + "': error reading element " + std::to_string(i) + " [bad vertices definition]"); } - m_mesh_data.__pyramids[pyramid_number] = GmshData::Pyramid(d, c, b, a, e); + m_mesh_data.__pyramids[pyramid_number] = GmshData::Pyramid(a, b, c, d, e); m_mesh_data.__pyramids_ref[pyramid_number] = m_mesh_data.__references[i]; m_mesh_data.__pyramids_number[pyramid_number] = m_mesh_data.__elementNumber[i]; pyramid_number++; // one more hexahedron @@ -1198,7 +1251,6 @@ GmshReader::__proceedData() point_number++; break; } - case 5: // prism case 7: // second order edge case 8: // second order triangle case 9: // second order quadrangle @@ -1353,7 +1405,15 @@ GmshReader::__readGmshFormat2_2() case PHYSICALNAMES: { this->__readPhysicalNames2_2(); if (this->__nextKeyword().second != ENDPHYSICALNAMES) { - throw NormalError("reading file '" + m_filename + "': expecting $EndNodes, '" + kw.first + "' was found"); + throw NormalError("reading file '" + m_filename + "': expecting $EndPhysicalNames, '" + kw.first + + "' was found"); + } + break; + } + case PERIODIC: { + this->__readPeriodic2_2(); + if (this->__nextKeyword().second != ENDPERIODIC) { + throw NormalError("reading file '" + m_filename + "': expecting $EndPeriodic, '" + kw.first + "' was found"); } break; } diff --git a/src/mesh/GmshReader.hpp b/src/mesh/GmshReader.hpp index 36e21508f10eda492ec1128816215d5a4d8c624d..860695ef57143b1b67575f54da95c12f8c7c2a01 100644 --- a/src/mesh/GmshReader.hpp +++ b/src/mesh/GmshReader.hpp @@ -109,6 +109,11 @@ class GmshReader : public MeshBuilderBase std::vector<int> __pyramids_ref; std::vector<int> __pyramids_number; + using Prism = TinyVector<6, unsigned int>; + Array<Prism> __prisms; + std::vector<int> __prisms_ref; + std::vector<int> __prisms_number; + using Hexahedron = TinyVector<8, unsigned int>; Array<Hexahedron> __hexahedra; std::vector<int> __hexahedra_ref; @@ -212,6 +217,8 @@ class GmshReader : public MeshBuilderBase ENDELEMENTS, PHYSICALNAMES, ENDPHYSICALNAMES, + PERIODIC, + ENDPERIODIC, Unknown, EndOfFile @@ -268,6 +275,12 @@ class GmshReader : public MeshBuilderBase */ void __readPhysicalNames2_2(); + /** + * Reads periodic + * + */ + void __readPeriodic2_2(); + public: GmshReader(const std::string& filename); ~GmshReader() = default; diff --git a/src/mesh/ItemValue.hpp b/src/mesh/ItemValue.hpp index ebc5f40511a0be6d1eeb519a0660b494d268f150..d48468f3931a2dc0dc546cb2a2dfee630df9e87e 100644 --- a/src/mesh/ItemValue.hpp +++ b/src/mesh/ItemValue.hpp @@ -175,6 +175,13 @@ class ItemValue ~ItemValue() = default; }; +template <typename DataType, ItemType item_type, typename ConnectivityPtr> +PUGS_INLINE size_t +size(const ItemValue<DataType, item_type, ConnectivityPtr>& item_value) +{ + return item_value.numberOfItems(); +} + template <typename DataType> using NodeValue = ItemValue<DataType, ItemType::node>; diff --git a/src/mesh/MeshInterpoler.hpp b/src/mesh/MeshInterpoler.hpp deleted file mode 100644 index f8a79eea4918bf71b6b7586683a14f2a67194df9..0000000000000000000000000000000000000000 --- a/src/mesh/MeshInterpoler.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef MESH_INTERPOLER_HPP -#define MESH_INTERPOLER_HPP - -class IMesh; - -template <typename ConnectivityType> -class Mesh; - -#include <memory> - -class MeshInterpoler -{ - private: - template <typename ConnectivityType> - std::shared_ptr<const Mesh<ConnectivityType>> _interpolate(const Mesh<ConnectivityType>& source_mesh, - const Mesh<ConnectivityType>& destination_mesh, - const double& theta) const; - - public: - std::shared_ptr<const IMesh> interpolate(const std::shared_ptr<const IMesh>& p_source_mesh, - const std::shared_ptr<const IMesh>& p_destination_mesh, - const double& theta) const; - MeshInterpoler() = default; - ~MeshInterpoler() = default; -}; - -#endif // MESH_INTERPOLER_HPP diff --git a/src/mesh/MeshInterpoler.cpp b/src/mesh/MeshRelaxer.cpp similarity index 57% rename from src/mesh/MeshInterpoler.cpp rename to src/mesh/MeshRelaxer.cpp index 26cba4bff5eeca4b75690b47e30126bac070646b..bda3cc7d17680bf8e2b43596d2e9ad2c7d9759ed 100644 --- a/src/mesh/MeshInterpoler.cpp +++ b/src/mesh/MeshRelaxer.cpp @@ -1,13 +1,13 @@ -#include <mesh/MeshInterpoler.hpp> +#include <mesh/MeshRelaxer.hpp> #include <mesh/Connectivity.hpp> #include <mesh/Mesh.hpp> template <typename ConnectivityType> std::shared_ptr<const Mesh<ConnectivityType>> -MeshInterpoler::_interpolate(const Mesh<ConnectivityType>& source_mesh, - const Mesh<ConnectivityType>& destination_mesh, - const double& theta) const +MeshRelaxer::_relax(const Mesh<ConnectivityType>& source_mesh, + const Mesh<ConnectivityType>& destination_mesh, + const double& theta) const { if (source_mesh.shared_connectivity() == destination_mesh.shared_connectivity()) { const ConnectivityType& connectivity = source_mesh.connectivity(); @@ -23,14 +23,14 @@ MeshInterpoler::_interpolate(const Mesh<ConnectivityType>& source_mesh, return std::make_shared<Mesh<ConnectivityType>>(source_mesh.shared_connectivity(), theta_xr); } else { - throw NormalError("interpolated meshes must share the same connectivity"); + throw NormalError("relaxed meshes must share the same connectivity"); } } std::shared_ptr<const IMesh> -MeshInterpoler::interpolate(const std::shared_ptr<const IMesh>& p_source_mesh, - const std::shared_ptr<const IMesh>& p_destination_mesh, - const double& theta) const +MeshRelaxer::relax(const std::shared_ptr<const IMesh>& p_source_mesh, + const std::shared_ptr<const IMesh>& p_destination_mesh, + const double& theta) const { if (p_source_mesh->dimension() != p_destination_mesh->dimension()) { throw NormalError("incompatible mesh dimensions"); @@ -38,18 +38,18 @@ MeshInterpoler::interpolate(const std::shared_ptr<const IMesh>& p_source_mesh, switch (p_source_mesh->dimension()) { case 1: { using MeshType = Mesh<Connectivity<1>>; - return this->_interpolate(dynamic_cast<const MeshType&>(*p_source_mesh), - dynamic_cast<const MeshType&>(*p_destination_mesh), theta); + return this->_relax(dynamic_cast<const MeshType&>(*p_source_mesh), + dynamic_cast<const MeshType&>(*p_destination_mesh), theta); } case 2: { using MeshType = Mesh<Connectivity<2>>; - return this->_interpolate(dynamic_cast<const MeshType&>(*p_source_mesh), - dynamic_cast<const MeshType&>(*p_destination_mesh), theta); + return this->_relax(dynamic_cast<const MeshType&>(*p_source_mesh), + dynamic_cast<const MeshType&>(*p_destination_mesh), theta); } case 3: { using MeshType = Mesh<Connectivity<3>>; - return this->_interpolate(dynamic_cast<const MeshType&>(*p_source_mesh), - dynamic_cast<const MeshType&>(*p_destination_mesh), theta); + return this->_relax(dynamic_cast<const MeshType&>(*p_source_mesh), + dynamic_cast<const MeshType&>(*p_destination_mesh), theta); } default: { throw UnexpectedError("invalid mesh dimension"); diff --git a/src/mesh/MeshRelaxer.hpp b/src/mesh/MeshRelaxer.hpp new file mode 100644 index 0000000000000000000000000000000000000000..96846cbadfefe61902199e927c99ecf96aaf176a --- /dev/null +++ b/src/mesh/MeshRelaxer.hpp @@ -0,0 +1,27 @@ +#ifndef MESH_RELAXER_HPP +#define MESH_RELAXER_HPP + +class IMesh; + +template <typename ConnectivityType> +class Mesh; + +#include <memory> + +class MeshRelaxer +{ + private: + template <typename ConnectivityType> + std::shared_ptr<const Mesh<ConnectivityType>> _relax(const Mesh<ConnectivityType>& source_mesh, + const Mesh<ConnectivityType>& destination_mesh, + const double& theta) const; + + public: + std::shared_ptr<const IMesh> relax(const std::shared_ptr<const IMesh>& p_source_mesh, + const std::shared_ptr<const IMesh>& p_destination_mesh, + const double& theta) const; + MeshRelaxer() = default; + ~MeshRelaxer() = default; +}; + +#endif // MESH_RELAXER_HPP diff --git a/src/mesh/MeshTransformer.cpp b/src/mesh/MeshTransformer.cpp index 67b3688926dcfb765c44799cff4674955515eb8b..167c4f337cd5c48147594623f3ae436874a47a22 100644 --- a/src/mesh/MeshTransformer.cpp +++ b/src/mesh/MeshTransformer.cpp @@ -3,15 +3,12 @@ #include <mesh/Connectivity.hpp> #include <mesh/Mesh.hpp> -#include <language/utils/FunctionTable.hpp> -#include <language/utils/PugsFunctionAdapter.hpp> -#include <language/utils/SymbolTable.hpp> +#include <language/utils/EvaluateAtPoints.hpp> template <typename OutputType, typename InputType> -class MeshTransformer::MeshTransformation<OutputType(InputType)> : public PugsFunctionAdapter<OutputType(InputType)> +class MeshTransformer::MeshTransformation<OutputType(InputType)> { static constexpr size_t Dimension = OutputType::Dimension; - using Adapter = PugsFunctionAdapter<OutputType(InputType)>; public: static inline std::shared_ptr<Mesh<Connectivity<Dimension>>> @@ -20,28 +17,9 @@ class MeshTransformer::MeshTransformation<OutputType(InputType)> : public PugsFu using MeshType = Mesh<Connectivity<Dimension>>; const MeshType& given_mesh = dynamic_cast<const MeshType&>(*p_mesh); - auto& expression = Adapter::getFunctionExpression(function_symbol_id); - auto convert_result = Adapter::getResultConverter(expression.m_data_type); - - Array<ExecutionPolicy> context_list = Adapter::getContextList(expression); - - NodeValue<const InputType> given_xr = given_mesh.xr(); NodeValue<OutputType> xr(given_mesh.connectivity()); - - using execution_space = typename Kokkos::DefaultExecutionSpace::execution_space; - Kokkos::Experimental::UniqueToken<execution_space, Kokkos::Experimental::UniqueTokenScope::Global> tokens; - - parallel_for(given_mesh.numberOfNodes(), [=, &expression, &tokens](NodeId r) { - const int32_t t = tokens.acquire(); - - auto& execution_policy = context_list[t]; - - Adapter::convertArgs(execution_policy.currentContext(), given_xr[r]); - auto result = expression.execute(execution_policy); - xr[r] = convert_result(std::move(result)); - - tokens.release(t); - }); + NodeValue<const InputType> given_xr = given_mesh.xr(); + EvaluateAtPoints<OutputType(InputType)>::evaluateTo(function_symbol_id, given_xr, xr); return std::make_shared<MeshType>(given_mesh.shared_connectivity(), xr); } diff --git a/src/output/VTKWriter.cpp b/src/output/VTKWriter.cpp index d01476cac3da67c1400efef7e3603e9bb91e096d..4f40e9af371333d2879ca28a2671278c365d6bbb 100644 --- a/src/output/VTKWriter.cpp +++ b/src/output/VTKWriter.cpp @@ -356,7 +356,6 @@ VTKWriter::_write(const std::shared_ptr<const MeshType>& mesh, // Adding basic mesh information output_named_item_data_set.add(NamedItemData{"cell_number", mesh->connectivity().cellNumber()}); output_named_item_data_set.add(NamedItemData{"node_number", mesh->connectivity().nodeNumber()}); - output_named_item_data_set.add(NamedItemData{"cell_center", MeshDataManager::instance().getMeshData(*mesh).xj()}); if (parallel::rank() == 0) { // write PVTK file std::ofstream fout(_getFilenamePVTU()); diff --git a/src/scheme/CMakeLists.txt b/src/scheme/CMakeLists.txt index 2131f2fec0748407ea7bb21a3375d398e1f6242a..115d7bc08ce9aa72dced807b9120431f17543864 100644 --- a/src/scheme/CMakeLists.txt +++ b/src/scheme/CMakeLists.txt @@ -3,6 +3,8 @@ add_library( PugsScheme AcousticSolver.cpp + DiscreteFunctionIntegrator.cpp DiscreteFunctionInterpoler.cpp DiscreteFunctionUtils.cpp + DiscreteFunctionVectorIntegrator.cpp DiscreteFunctionVectorInterpoler.cpp) diff --git a/src/scheme/CellIntegrator.hpp b/src/scheme/CellIntegrator.hpp new file mode 100644 index 0000000000000000000000000000000000000000..6960901d335f894e00a86239772f33f3abc50c67 --- /dev/null +++ b/src/scheme/CellIntegrator.hpp @@ -0,0 +1,574 @@ +#ifndef CELL_INTEGRATOR_HPP +#define CELL_INTEGRATOR_HPP + +#include <analysis/IQuadratureDescriptor.hpp> +#include <analysis/QuadratureManager.hpp> +#include <geometry/CubeTransformation.hpp> +#include <geometry/LineTransformation.hpp> +#include <geometry/PrismTransformation.hpp> +#include <geometry/PyramidTransformation.hpp> +#include <geometry/SquareTransformation.hpp> +#include <geometry/TetrahedronTransformation.hpp> +#include <geometry/TriangleTransformation.hpp> +#include <mesh/CellType.hpp> +#include <mesh/Connectivity.hpp> +#include <mesh/ItemId.hpp> +#include <utils/Array.hpp> + +#include <functional> + +class CellIntegrator +{ + private: + template <size_t Dimension> + class AllCells + { + private: + const Connectivity<Dimension>& m_connectivity; + + public: + using index_type = CellId; + + PUGS_INLINE + CellId + cellId(const CellId cell_id) const + { + return cell_id; + } + + PUGS_INLINE + size_t + size() const + { + return m_connectivity.numberOfCells(); + } + + PUGS_INLINE + AllCells(const Connectivity<Dimension>& connectivity) : m_connectivity{connectivity} {} + }; + + template <template <typename T> typename ArrayT> + class CellList + { + private: + const ArrayT<CellId>& m_cell_list; + + public: + using index_type = typename ArrayT<CellId>::index_type; + + PUGS_INLINE + CellId + cellId(const index_type index) const + { + return m_cell_list[index]; + } + + PUGS_INLINE + size_t + size() const + { + return m_cell_list.size(); + } + + PUGS_INLINE + CellList(const ArrayT<CellId>& cell_list) : m_cell_list{cell_list} {} + }; + + template <typename MeshType, typename OutputArrayT, typename ListTypeT, typename OutputType, typename InputType> + static PUGS_INLINE void + _tensorialIntegrateTo(std::function<OutputType(InputType)> function, + const IQuadratureDescriptor& quadrature_descriptor, + const MeshType& mesh, + const ListTypeT& cell_list, + OutputArrayT& value) + { + constexpr size_t Dimension = MeshType::Dimension; + + static_assert(std::is_same_v<TinyVector<Dimension>, std::decay_t<InputType>>, "invalid input data type"); + static_assert(std::is_same_v<std::remove_const_t<typename OutputArrayT::data_type>, OutputType>, + "invalid output data type"); + + using execution_space = typename Kokkos::DefaultExecutionSpace::execution_space; + Kokkos::Experimental::UniqueToken<execution_space, Kokkos::Experimental::UniqueTokenScope::Global> tokens; + + if constexpr (std::is_arithmetic_v<OutputType>) { + value.fill(0); + } else if constexpr (is_tiny_vector_v<OutputType> or is_tiny_matrix_v<OutputType>) { + value.fill(zero); + } else { + static_assert(std::is_same_v<OutputType, double>, "unexpected output type"); + } + + const auto& connectivity = mesh.connectivity(); + + const auto cell_to_node_matrix = connectivity.cellToNodeMatrix(); + const auto cell_type = connectivity.cellType(); + const auto xr = mesh.xr(); + + auto invalid_cell = std::make_pair(false, CellId{}); + + const auto qf = [&] { + if constexpr (Dimension == 1) { + return QuadratureManager::instance().getLineFormula(quadrature_descriptor); + } else if constexpr (Dimension == 2) { + return QuadratureManager::instance().getSquareFormula(quadrature_descriptor); + } else { + static_assert(Dimension == 3); + return QuadratureManager::instance().getCubeFormula(quadrature_descriptor); + } + }(); + + parallel_for(cell_list.size(), [=, &invalid_cell, &qf, &cell_list](typename ListTypeT::index_type index) { + const CellId cell_id = cell_list.cellId(index); + + const auto cell_to_node = cell_to_node_matrix[cell_id]; + + if constexpr (Dimension == 1) { + switch (cell_type[cell_id]) { + case CellType::Line: { + const LineTransformation<1> T(xr[cell_to_node[0]], xr[cell_to_node[1]]); + + for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { + const auto xi = qf.point(i_point); + value[index] += qf.weight(i_point) * T.jacobianDeterminant() * function(T(xi)); + } + break; + } + // LCOV_EXCL_START + default: { + invalid_cell = std::make_pair(true, cell_id); + break; + } + // LCOV_EXCL_STOP + } + } else if constexpr (Dimension == 2) { + switch (cell_type[cell_id]) { + case CellType::Triangle: { + const SquareTransformation<2> T(xr[cell_to_node[0]], xr[cell_to_node[1]], xr[cell_to_node[2]], + xr[cell_to_node[2]]); + + for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { + const auto xi = qf.point(i_point); + value[index] += qf.weight(i_point) * T.jacobianDeterminant(xi) * function(T(xi)); + } + break; + } + case CellType::Quadrangle: { + const SquareTransformation<2> T(xr[cell_to_node[0]], xr[cell_to_node[1]], xr[cell_to_node[2]], + xr[cell_to_node[3]]); + + for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { + const auto xi = qf.point(i_point); + value[index] += qf.weight(i_point) * T.jacobianDeterminant(xi) * function(T(xi)); + } + break; + } + // LCOV_EXCL_START + default: { + invalid_cell = std::make_pair(true, cell_id); + break; + } + // LCOV_EXCL_STOP + } + } else { + static_assert(Dimension == 3); + + switch (cell_type[cell_id]) { + case CellType::Tetrahedron: { + const CubeTransformation T(xr[cell_to_node[0]], xr[cell_to_node[1]], xr[cell_to_node[2]], + xr[cell_to_node[2]], // + xr[cell_to_node[3]], xr[cell_to_node[3]], xr[cell_to_node[3]], + xr[cell_to_node[3]]); + + for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { + const auto xi = qf.point(i_point); + value[index] += qf.weight(i_point) * T.jacobianDeterminant(xi) * function(T(xi)); + } + break; + } + case CellType::Pyramid: { + if (cell_to_node.size() == 5) { + const CubeTransformation T(xr[cell_to_node[0]], xr[cell_to_node[1]], xr[cell_to_node[2]], // + xr[cell_to_node[3]], // + xr[cell_to_node[4]], xr[cell_to_node[4]], xr[cell_to_node[4]], + xr[cell_to_node[4]]); + + for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { + const auto xi = qf.point(i_point); + value[index] += qf.weight(i_point) * T.jacobianDeterminant(xi) * function(T(xi)); + } + } else { + // LCOV_EXCL_START + throw NotImplementedError("integration on pyramid with non-quadrangular base (number of nodes " + + std::to_string(cell_to_node.size()) + ")"); + // LCOV_EXCL_STOP + } + break; + } + case CellType::Diamond: { + if (cell_to_node.size() == 5) { + { // top tetrahedron + const CubeTransformation T0(xr[cell_to_node[1]], xr[cell_to_node[2]], xr[cell_to_node[3]], + xr[cell_to_node[3]], // + xr[cell_to_node[4]], xr[cell_to_node[4]], xr[cell_to_node[4]], + xr[cell_to_node[4]]); + + for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { + const auto xi = qf.point(i_point); + value[index] += qf.weight(i_point) * T0.jacobianDeterminant(xi) * function(T0(xi)); + } + } + { // bottom tetrahedron + const CubeTransformation T1(xr[cell_to_node[3]], xr[cell_to_node[3]], xr[cell_to_node[2]], + xr[cell_to_node[1]], // + xr[cell_to_node[0]], xr[cell_to_node[0]], xr[cell_to_node[0]], + xr[cell_to_node[0]]); + + for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { + const auto xi = qf.point(i_point); + value[index] += qf.weight(i_point) * T1.jacobianDeterminant(xi) * function(T1(xi)); + } + } + } else if (cell_to_node.size() == 6) { + { // top pyramid + const CubeTransformation T0(xr[cell_to_node[1]], xr[cell_to_node[2]], xr[cell_to_node[3]], + xr[cell_to_node[4]], // + xr[cell_to_node[5]], xr[cell_to_node[5]], xr[cell_to_node[5]], + xr[cell_to_node[5]]); + + for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { + const auto xi = qf.point(i_point); + value[index] += qf.weight(i_point) * T0.jacobianDeterminant(xi) * function(T0(xi)); + } + } + { // bottom pyramid + const CubeTransformation T1(xr[cell_to_node[4]], xr[cell_to_node[3]], xr[cell_to_node[2]], + xr[cell_to_node[1]], // + xr[cell_to_node[0]], xr[cell_to_node[0]], xr[cell_to_node[0]], + xr[cell_to_node[0]]); + + for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { + const auto xi = qf.point(i_point); + value[index] += qf.weight(i_point) * T1.jacobianDeterminant(xi) * function(T1(xi)); + } + } + } else { + // LCOV_EXCL_START + throw NotImplementedError("integration on diamond with non-quadrangular base (" + + std::to_string(cell_to_node.size()) + ")"); + // LCOV_EXCL_STOP + } + break; + } + case CellType::Prism: { + const CubeTransformation T(xr[cell_to_node[0]], xr[cell_to_node[1]], // + xr[cell_to_node[2]], xr[cell_to_node[2]], // + xr[cell_to_node[3]], xr[cell_to_node[4]], // + xr[cell_to_node[5]], xr[cell_to_node[5]]); + + for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { + const auto xi = qf.point(i_point); + value[index] += qf.weight(i_point) * T.jacobianDeterminant(xi) * function(T(xi)); + } + break; + } + case CellType::Hexahedron: { + const CubeTransformation T(xr[cell_to_node[0]], xr[cell_to_node[1]], xr[cell_to_node[2]], xr[cell_to_node[3]], + xr[cell_to_node[4]], xr[cell_to_node[5]], xr[cell_to_node[6]], + xr[cell_to_node[7]]); + + for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { + const auto xi = qf.point(i_point); + value[index] += qf.weight(i_point) * T.jacobianDeterminant(xi) * function(T(xi)); + } + break; + } + // LCOV_EXCL_START + default: { + invalid_cell = std::make_pair(true, cell_id); + break; + } + // LCOV_EXCL_STOP + } + } + }); + + // LCOV_EXCL_START + if (invalid_cell.first) { + std::ostringstream os; + os << "invalid cell type for integration: " << name(cell_type[invalid_cell.second]); + throw UnexpectedError(os.str()); + } + // LCOV_EXCL_STOP + } + + template <typename MeshType, typename OutputArrayT, typename ListTypeT, typename OutputType, typename InputType> + static PUGS_INLINE void + _directIntegrateTo(std::function<OutputType(InputType)> function, + const IQuadratureDescriptor& quadrature_descriptor, + const MeshType& mesh, + const ListTypeT& cell_list, + OutputArrayT& value) + { + Assert(not quadrature_descriptor.isTensorial()); + + constexpr size_t Dimension = MeshType::Dimension; + + static_assert(std::is_same_v<TinyVector<Dimension>, std::decay_t<InputType>>, "invalid input data type"); + static_assert(std::is_same_v<std::remove_const_t<typename OutputArrayT::data_type>, OutputType>, + "invalid output data type"); + + if constexpr (std::is_arithmetic_v<OutputType>) { + value.fill(0); + } else if constexpr (is_tiny_vector_v<OutputType> or is_tiny_matrix_v<OutputType>) { + value.fill(zero); + } else { + static_assert(std::is_same_v<OutputType, double>, "unexpected output type"); + } + + const auto& connectivity = mesh.connectivity(); + + const auto cell_to_node_matrix = connectivity.cellToNodeMatrix(); + const auto cell_type = connectivity.cellType(); + const auto xr = mesh.xr(); + + auto invalid_cell = std::make_pair(false, CellId{}); + + parallel_for(cell_list.size(), [=, &invalid_cell, &quadrature_descriptor, + &cell_list](const typename ListTypeT::index_type& index) { + const CellId cell_id = cell_list.cellId(index); + + const auto cell_to_node = cell_to_node_matrix[cell_id]; + + if constexpr (Dimension == 1) { + switch (cell_type[cell_id]) { + case CellType::Line: { + const LineTransformation<1> T(xr[cell_to_node[0]], xr[cell_to_node[1]]); + const auto qf = QuadratureManager::instance().getLineFormula(quadrature_descriptor); + + for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { + const auto xi = qf.point(i_point); + value[index] += qf.weight(i_point) * T.jacobianDeterminant() * function(T(xi)); + } + break; + } + // LCOV_EXCL_START + default: { + invalid_cell = std::make_pair(true, cell_id); + break; + } + // LCOV_EXCL_STOP + } + } else if constexpr (Dimension == 2) { + switch (cell_type[cell_id]) { + case CellType::Triangle: { + const TriangleTransformation<2> T(xr[cell_to_node[0]], xr[cell_to_node[1]], xr[cell_to_node[2]]); + const auto qf = QuadratureManager::instance().getTriangleFormula(quadrature_descriptor); + + for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { + const auto xi = qf.point(i_point); + value[index] += qf.weight(i_point) * T.jacobianDeterminant() * function(T(xi)); + } + break; + } + case CellType::Quadrangle: { + const SquareTransformation<2> T(xr[cell_to_node[0]], xr[cell_to_node[1]], xr[cell_to_node[2]], + xr[cell_to_node[3]]); + const auto qf = QuadratureManager::instance().getSquareFormula(quadrature_descriptor); + + for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { + const auto xi = qf.point(i_point); + value[index] += qf.weight(i_point) * T.jacobianDeterminant(xi) * function(T(xi)); + } + break; + } + // LCOV_EXCL_START + default: { + invalid_cell = std::make_pair(true, cell_id); + break; + } + // LCOV_EXCL_STOP + } + } else { + static_assert(Dimension == 3); + + switch (cell_type[cell_id]) { + case CellType::Tetrahedron: { + const TetrahedronTransformation T(xr[cell_to_node[0]], xr[cell_to_node[1]], // + xr[cell_to_node[2]], xr[cell_to_node[3]]); + const auto qf = QuadratureManager::instance().getTetrahedronFormula(quadrature_descriptor); + + for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { + const auto xi = qf.point(i_point); + value[index] += qf.weight(i_point) * T.jacobianDeterminant() * function(T(xi)); + } + break; + } + case CellType::Pyramid: { + if (cell_to_node.size() == 5) { + const PyramidTransformation T(xr[cell_to_node[0]], xr[cell_to_node[1]], xr[cell_to_node[2]], // + xr[cell_to_node[3]], xr[cell_to_node[4]]); + const auto qf = QuadratureManager::instance().getPyramidFormula(quadrature_descriptor); + + for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { + const auto xi = qf.point(i_point); + value[index] += qf.weight(i_point) * T.jacobianDeterminant(xi) * function(T(xi)); + } + } else { + // LCOV_EXCL_START + throw NotImplementedError("integration on pyramid with non-quadrangular base"); + // LCOV_EXCL_STOP + } + break; + } + case CellType::Diamond: { + if (cell_to_node.size() == 5) { + const auto qf = QuadratureManager::instance().getTetrahedronFormula(quadrature_descriptor); + { // top tetrahedron + const TetrahedronTransformation T0(xr[cell_to_node[1]], xr[cell_to_node[2]], xr[cell_to_node[3]], // + xr[cell_to_node[4]]); + + for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { + const auto xi = qf.point(i_point); + value[index] += qf.weight(i_point) * T0.jacobianDeterminant() * function(T0(xi)); + } + } + { // bottom tetrahedron + const TetrahedronTransformation T1(xr[cell_to_node[3]], xr[cell_to_node[2]], xr[cell_to_node[1]], // + xr[cell_to_node[0]]); + + for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { + const auto xi = qf.point(i_point); + value[index] += qf.weight(i_point) * T1.jacobianDeterminant() * function(T1(xi)); + } + } + } else if (cell_to_node.size() == 6) { + const auto qf = QuadratureManager::instance().getPyramidFormula(quadrature_descriptor); + { // top pyramid + const PyramidTransformation T0(xr[cell_to_node[1]], xr[cell_to_node[2]], xr[cell_to_node[3]], + xr[cell_to_node[4]], xr[cell_to_node[5]]); + + for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { + const auto xi = qf.point(i_point); + value[index] += qf.weight(i_point) * T0.jacobianDeterminant(xi) * function(T0(xi)); + } + } + { // bottom pyramid + const PyramidTransformation T1(xr[cell_to_node[4]], xr[cell_to_node[3]], xr[cell_to_node[2]], + xr[cell_to_node[1]], xr[cell_to_node[0]]); + + for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { + const auto xi = qf.point(i_point); + value[index] += qf.weight(i_point) * T1.jacobianDeterminant(xi) * function(T1(xi)); + } + } + } else { + // LCOV_EXCL_START + throw NotImplementedError("integration on diamond with non-quadrangular base (" + + std::to_string(cell_to_node.size()) + ")"); + // LCOV_EXCL_STOP + } + break; + } + case CellType::Prism: { + const PrismTransformation T(xr[cell_to_node[0]], xr[cell_to_node[1]], xr[cell_to_node[2]], + xr[cell_to_node[3]], xr[cell_to_node[4]], xr[cell_to_node[5]]); + const auto qf = QuadratureManager::instance().getPrismFormula(quadrature_descriptor); + + for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { + const auto xi = qf.point(i_point); + value[index] += qf.weight(i_point) * T.jacobianDeterminant(xi) * function(T(xi)); + } + break; + } + case CellType::Hexahedron: { + const CubeTransformation T(xr[cell_to_node[0]], xr[cell_to_node[1]], xr[cell_to_node[2]], xr[cell_to_node[3]], + xr[cell_to_node[4]], xr[cell_to_node[5]], xr[cell_to_node[6]], + xr[cell_to_node[7]]); + const auto qf = QuadratureManager::instance().getCubeFormula(quadrature_descriptor); + + for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { + const auto xi = qf.point(i_point); + value[index] += qf.weight(i_point) * T.jacobianDeterminant(xi) * function(T(xi)); + } + break; + } + // LCOV_EXCL_START + default: { + invalid_cell = std::make_pair(true, cell_id); + break; + } + // LCOV_EXCL_STOP + } + } + }); + + // LCOV_EXCL_START + if (invalid_cell.first) { + std::ostringstream os; + os << "invalid cell type for integration: " << name(cell_type[invalid_cell.second]); + throw UnexpectedError(os.str()); + } + // LCOV_EXCL_STOP + } + + public: + template <typename MeshType, typename OutputArrayT, typename OutputType, typename InputType> + static PUGS_INLINE void + integrateTo(const std::function<OutputType(InputType)>& function, + const IQuadratureDescriptor& quadrature_descriptor, + const MeshType& mesh, + OutputArrayT& value) + { + constexpr size_t Dimension = MeshType::Dimension; + + if (quadrature_descriptor.isTensorial()) { + _tensorialIntegrateTo<MeshType, OutputArrayT>(function, quadrature_descriptor, mesh, + AllCells<Dimension>{mesh.connectivity()}, value); + } else { + _directIntegrateTo<MeshType, OutputArrayT>(function, quadrature_descriptor, mesh, + AllCells<Dimension>{mesh.connectivity()}, value); + } + } + + template <typename MeshType, typename OutputArrayT, typename FunctionType> + static PUGS_INLINE void + integrateTo(const FunctionType& function, + const IQuadratureDescriptor& quadrature_descriptor, + const MeshType& mesh, + OutputArrayT& value) + { + integrateTo(std::function(function), quadrature_descriptor, mesh, value); + } + + template <typename MeshType, typename OutputType, typename InputType, template <typename DataType> typename ArrayT> + static PUGS_INLINE ArrayT<OutputType> + integrate(const std::function<OutputType(InputType)>& function, + const IQuadratureDescriptor& quadrature_descriptor, + const MeshType& mesh, + const ArrayT<CellId>& cell_list) + { + ArrayT<OutputType> value(size(cell_list)); + if (quadrature_descriptor.isTensorial()) { + _tensorialIntegrateTo<MeshType, ArrayT<OutputType>>(function, quadrature_descriptor, mesh, CellList{cell_list}, + value); + } else { + _directIntegrateTo<MeshType, ArrayT<OutputType>>(function, quadrature_descriptor, mesh, CellList{cell_list}, + value); + } + + return value; + } + + template <typename MeshType, typename FunctionType, template <typename DataType> typename ArrayT> + static PUGS_INLINE auto + integrate(const FunctionType& function, + const IQuadratureDescriptor& quadrature_descriptor, + const MeshType& mesh, + const ArrayT<CellId>& cell_list) + { + return integrate(std::function(function), quadrature_descriptor, mesh, cell_list); + } +}; + +#endif // CELL_INTEGRATOR_HPP diff --git a/src/scheme/DiscreteFunctionIntegrator.cpp b/src/scheme/DiscreteFunctionIntegrator.cpp new file mode 100644 index 0000000000000000000000000000000000000000..91cf921df2764ad13f4470687fc4cc5f4d6bced1 --- /dev/null +++ b/src/scheme/DiscreteFunctionIntegrator.cpp @@ -0,0 +1,132 @@ +#include <scheme/DiscreteFunctionIntegrator.hpp> + +#include <language/utils/IntegrateCellValue.hpp> +#include <scheme/DiscreteFunctionP0.hpp> +#include <utils/Exceptions.hpp> + +template <size_t Dimension, typename DataType, typename ValueType> +std::shared_ptr<IDiscreteFunction> +DiscreteFunctionIntegrator::_integrate() const +{ + using MeshType = Mesh<Connectivity<Dimension>>; + std::shared_ptr mesh = std::dynamic_pointer_cast<const MeshType>(m_mesh); + + if constexpr (std::is_same_v<DataType, ValueType>) { + return std::make_shared< + DiscreteFunctionP0<Dimension, ValueType>>(mesh, + IntegrateCellValue<DataType(TinyVector<Dimension>)>::template integrate< + MeshType>(m_function_id, *m_quadrature_descriptor, *mesh)); + } else { + static_assert(std::is_convertible_v<DataType, ValueType>); + + CellValue<DataType> cell_data = + IntegrateCellValue<DataType(TinyVector<Dimension>)>::template integrate<MeshType>(m_function_id, + *m_quadrature_descriptor, + *mesh); + + CellValue<ValueType> cell_value{mesh->connectivity()}; + + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { cell_value[cell_id] = cell_data[cell_id]; }); + + return std::make_shared<DiscreteFunctionP0<Dimension, ValueType>>(mesh, cell_value); + } +} + +template <size_t Dimension> +std::shared_ptr<IDiscreteFunction> +DiscreteFunctionIntegrator::_integrate() const +{ + const auto& function_descriptor = m_function_id.descriptor(); + Assert(function_descriptor.domainMappingNode().children[1]->m_data_type == ASTNodeDataType::typename_t); + + const ASTNodeDataType& data_type = function_descriptor.domainMappingNode().children[1]->m_data_type.contentType(); + + switch (data_type) { + case ASTNodeDataType::bool_t: { + return this->_integrate<Dimension, bool, double>(); + } + case ASTNodeDataType::unsigned_int_t: { + return this->_integrate<Dimension, uint64_t, double>(); + } + case ASTNodeDataType::int_t: { + return this->_integrate<Dimension, int64_t, double>(); + } + case ASTNodeDataType::double_t: { + return this->_integrate<Dimension, double>(); + } + case ASTNodeDataType::vector_t: { + switch (data_type.dimension()) { + case 1: { + return this->_integrate<Dimension, TinyVector<1>>(); + } + case 2: { + return this->_integrate<Dimension, TinyVector<2>>(); + } + case 3: { + return this->_integrate<Dimension, TinyVector<3>>(); + } + // LCOV_EXCL_START + default: { + std::ostringstream os; + os << "invalid vector dimension " << rang::fgB::red << data_type.dimension() << rang::style::reset; + + throw UnexpectedError(os.str()); + } + // LCOV_EXCL_STOP + } + } + case ASTNodeDataType::matrix_t: { + Assert(data_type.numberOfColumns() == data_type.numberOfRows(), "undefined matrix type"); + switch (data_type.numberOfColumns()) { + case 1: { + return this->_integrate<Dimension, TinyMatrix<1>>(); + } + case 2: { + return this->_integrate<Dimension, TinyMatrix<2>>(); + } + case 3: { + return this->_integrate<Dimension, TinyMatrix<3>>(); + } + // LCOV_EXCL_START + default: { + std::ostringstream os; + os << "invalid vector dimension " << rang::fgB::red << data_type.dimension() << rang::style::reset; + + throw UnexpectedError(os.str()); + } + // LCOV_EXCL_STOP + } + } + // LCOV_EXCL_START + default: { + std::ostringstream os; + os << "invalid integrate value type: " << rang::fgB::red << dataTypeName(data_type) << rang::style::reset; + + throw UnexpectedError(os.str()); + } + // LCOV_EXCL_STOP + } +} + +std::shared_ptr<IDiscreteFunction> +DiscreteFunctionIntegrator::integrate() const +{ + std::shared_ptr<IDiscreteFunction> discrete_function; + switch (m_mesh->dimension()) { + case 1: { + return this->_integrate<1>(); + } + case 2: { + return this->_integrate<2>(); + } + case 3: { + return this->_integrate<3>(); + } + // LCOV_EXCL_START + default: { + throw UnexpectedError("invalid dimension"); + } + // LCOV_EXCL_STOP + } +} diff --git a/src/scheme/DiscreteFunctionIntegrator.hpp b/src/scheme/DiscreteFunctionIntegrator.hpp new file mode 100644 index 0000000000000000000000000000000000000000..1784f891eaa6fd7471b17006b3c9f277c31e51dd --- /dev/null +++ b/src/scheme/DiscreteFunctionIntegrator.hpp @@ -0,0 +1,39 @@ +#ifndef DISCRETE_FUNCTION_INTEGRATOR_HPP +#define DISCRETE_FUNCTION_INTEGRATOR_HPP + +#include <analysis/IQuadratureDescriptor.hpp> +#include <language/utils/FunctionSymbolId.hpp> +#include <mesh/IMesh.hpp> +#include <scheme/IDiscreteFunction.hpp> + +#include <memory> + +class DiscreteFunctionIntegrator +{ + private: + std::shared_ptr<const IMesh> m_mesh; + std::shared_ptr<const IQuadratureDescriptor> m_quadrature_descriptor; + const FunctionSymbolId m_function_id; + + template <size_t Dimension, typename DataType, typename ValueType = DataType> + std::shared_ptr<IDiscreteFunction> _integrate() const; + + template <size_t Dimension> + std::shared_ptr<IDiscreteFunction> _integrate() const; + + public: + std::shared_ptr<IDiscreteFunction> integrate() const; + + DiscreteFunctionIntegrator(const std::shared_ptr<const IMesh>& mesh, + const std::shared_ptr<const IQuadratureDescriptor>& quadrature_descriptor, + const FunctionSymbolId& function_id) + : m_mesh{mesh}, m_quadrature_descriptor{quadrature_descriptor}, m_function_id{function_id} + {} + + DiscreteFunctionIntegrator(const DiscreteFunctionIntegrator&) = delete; + DiscreteFunctionIntegrator(DiscreteFunctionIntegrator&&) = delete; + + ~DiscreteFunctionIntegrator() = default; +}; + +#endif // DISCRETE_FUNCTION_INTEGRATOR_HPP diff --git a/src/scheme/DiscreteFunctionVectorIntegrator.cpp b/src/scheme/DiscreteFunctionVectorIntegrator.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6d8937f84aeba6ae96ac5fc6e5ba523e5781f239 --- /dev/null +++ b/src/scheme/DiscreteFunctionVectorIntegrator.cpp @@ -0,0 +1,70 @@ +#include <scheme/DiscreteFunctionVectorIntegrator.hpp> + +#include <language/utils/IntegrateCellArray.hpp> + +#include <scheme/DiscreteFunctionP0Vector.hpp> +#include <utils/Exceptions.hpp> + +template <size_t Dimension, typename DataType> +std::shared_ptr<IDiscreteFunction> +DiscreteFunctionVectorIntegrator::_integrate() const +{ + std::shared_ptr mesh = std::dynamic_pointer_cast<const Mesh<Connectivity<Dimension>>>(m_mesh); + + return std::make_shared< + DiscreteFunctionP0Vector<Dimension, DataType>>(mesh, IntegrateCellArray<DataType(TinyVector<Dimension>)>:: + template integrate(m_function_id_list, + *m_quadrature_descriptor, *mesh)); +} + +template <size_t Dimension> +std::shared_ptr<IDiscreteFunction> +DiscreteFunctionVectorIntegrator::_integrate() const +{ + for (const auto& function_id : m_function_id_list) { + const auto& function_descriptor = function_id.descriptor(); + Assert(function_descriptor.domainMappingNode().children[1]->m_data_type == ASTNodeDataType::typename_t); + const ASTNodeDataType& data_type = function_descriptor.domainMappingNode().children[1]->m_data_type.contentType(); + + switch (data_type) { + case ASTNodeDataType::bool_t: + case ASTNodeDataType::unsigned_int_t: + case ASTNodeDataType::int_t: + case ASTNodeDataType::double_t: { + break; + } + default: { + std::ostringstream os; + os << "vector functions require scalar value type.\n" + << "Invalid interpolation value type: " << rang::fgB::red << dataTypeName(data_type) << rang::style::reset; + throw NormalError(os.str()); + } + } + } + return this->_integrate<Dimension, double>(); +} + +std::shared_ptr<IDiscreteFunction> +DiscreteFunctionVectorIntegrator::integrate() const +{ + if (m_discrete_function_descriptor->type() != DiscreteFunctionType::P0Vector) { + throw NormalError("invalid discrete function type for vector interpolation"); + } + + switch (m_mesh->dimension()) { + case 1: { + return this->_integrate<1>(); + } + case 2: { + return this->_integrate<2>(); + } + case 3: { + return this->_integrate<3>(); + } + // LCOV_EXCL_START + default: { + throw UnexpectedError("invalid dimension"); + } + // LCOV_EXCL_STOP + } +} diff --git a/src/scheme/DiscreteFunctionVectorIntegrator.hpp b/src/scheme/DiscreteFunctionVectorIntegrator.hpp new file mode 100644 index 0000000000000000000000000000000000000000..01e086e7efd9c2334d07dfdb3cf8dce1f33e49f1 --- /dev/null +++ b/src/scheme/DiscreteFunctionVectorIntegrator.hpp @@ -0,0 +1,47 @@ +#ifndef DISCRETE_FUNCTION_VECTOR_INTEGRATOR_HPP +#define DISCRETE_FUNCTION_VECTOR_INTEGRATOR_HPP + +#include <analysis/IQuadratureDescriptor.hpp> +#include <language/utils/FunctionSymbolId.hpp> +#include <mesh/IMesh.hpp> +#include <scheme/IDiscreteFunction.hpp> +#include <scheme/IDiscreteFunctionDescriptor.hpp> + +#include <memory> +#include <vector> + +class DiscreteFunctionVectorIntegrator +{ + private: + std::shared_ptr<const IMesh> m_mesh; + std::shared_ptr<const IQuadratureDescriptor> m_quadrature_descriptor; + std::shared_ptr<const IDiscreteFunctionDescriptor> m_discrete_function_descriptor; + const std::vector<FunctionSymbolId> m_function_id_list; + + template <size_t Dimension, typename DataType> + std::shared_ptr<IDiscreteFunction> _integrate() const; + + template <size_t Dimension> + std::shared_ptr<IDiscreteFunction> _integrate() const; + + public: + std::shared_ptr<IDiscreteFunction> integrate() const; + + DiscreteFunctionVectorIntegrator( + const std::shared_ptr<const IMesh>& mesh, + const std::shared_ptr<const IQuadratureDescriptor>& quadrature_descriptor, + const std::shared_ptr<const IDiscreteFunctionDescriptor>& discrete_function_descriptor, + const std::vector<FunctionSymbolId>& function_id_list) + : m_mesh{mesh}, + m_quadrature_descriptor(quadrature_descriptor), + m_discrete_function_descriptor{discrete_function_descriptor}, + m_function_id_list{function_id_list} + {} + + DiscreteFunctionVectorIntegrator(const DiscreteFunctionVectorIntegrator&) = delete; + DiscreteFunctionVectorIntegrator(DiscreteFunctionVectorIntegrator&&) = delete; + + ~DiscreteFunctionVectorIntegrator() = default; +}; + +#endif // DISCRETE_FUNCTION_VECTOR_INTEGRATOR_HPP diff --git a/src/scheme/EdgeIntegrator.hpp b/src/scheme/EdgeIntegrator.hpp new file mode 100644 index 0000000000000000000000000000000000000000..2bf287c3d6f61cb83ef3619124334a2124898f8c --- /dev/null +++ b/src/scheme/EdgeIntegrator.hpp @@ -0,0 +1,166 @@ +#ifndef EDGE_INTEGRATOR_HPP +#define EDGE_INTEGRATOR_HPP + +#include <analysis/IQuadratureDescriptor.hpp> +#include <analysis/QuadratureManager.hpp> +#include <geometry/LineTransformation.hpp> +#include <mesh/Connectivity.hpp> +#include <mesh/ItemId.hpp> +#include <utils/Array.hpp> + +#include <functional> + +class EdgeIntegrator +{ + private: + template <size_t Dimension> + class AllEdges + { + private: + const Connectivity<Dimension>& m_connectivity; + + public: + using index_type = EdgeId; + + PUGS_INLINE + EdgeId + edgeId(const EdgeId edge_id) const + { + return edge_id; + } + + PUGS_INLINE + size_t + size() const + { + return m_connectivity.numberOfEdges(); + } + + PUGS_INLINE + AllEdges(const Connectivity<Dimension>& connectivity) : m_connectivity{connectivity} {} + }; + + template <template <typename T> typename ArrayT> + class EdgeList + { + private: + const ArrayT<EdgeId>& m_edge_list; + + public: + using index_type = typename ArrayT<EdgeId>::index_type; + + PUGS_INLINE + EdgeId + edgeId(const index_type index) const + { + return m_edge_list[index]; + } + + PUGS_INLINE + size_t + size() const + { + return m_edge_list.size(); + } + + PUGS_INLINE + EdgeList(const ArrayT<EdgeId>& edge_list) : m_edge_list{edge_list} {} + }; + + template <typename MeshType, typename OutputArrayT, typename ListTypeT, typename OutputType, typename InputType> + static PUGS_INLINE void + _integrateTo(std::function<OutputType(InputType)> function, + const IQuadratureDescriptor& quadrature_descriptor, + const MeshType& mesh, + const ListTypeT& edge_list, + OutputArrayT& value) + { + constexpr size_t Dimension = MeshType::Dimension; + static_assert(Dimension == 3); + + static_assert(std::is_same_v<TinyVector<Dimension>, std::decay_t<InputType>>, "invalid input data type"); + static_assert(std::is_same_v<std::remove_const_t<typename OutputArrayT::data_type>, OutputType>, + "invalid output data type"); + + using execution_space = typename Kokkos::DefaultExecutionSpace::execution_space; + Kokkos::Experimental::UniqueToken<execution_space, Kokkos::Experimental::UniqueTokenScope::Global> tokens; + + if constexpr (std::is_arithmetic_v<OutputType>) { + value.fill(0); + } else if constexpr (is_tiny_vector_v<OutputType> or is_tiny_matrix_v<OutputType>) { + value.fill(zero); + } else { + static_assert(std::is_same_v<OutputType, double>, "unexpected output type"); + } + + const auto& connectivity = mesh.connectivity(); + + const auto edge_to_node_matrix = connectivity.edgeToNodeMatrix(); + const auto xr = mesh.xr(); + + const auto qf = QuadratureManager::instance().getLineFormula(quadrature_descriptor); + + parallel_for(edge_list.size(), [=, &qf, &edge_list](typename ListTypeT::index_type index) { + const EdgeId edge_id = edge_list.edgeId(index); + + const auto edge_to_node = edge_to_node_matrix[edge_id]; + + Assert(edge_to_node.size() == 2); + const LineTransformation<3> T(xr[edge_to_node[0]], xr[edge_to_node[1]]); + + for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { + const auto xi = qf.point(i_point); + value[index] += qf.weight(i_point) * T.velocityNorm() * function(T(xi)); + } + }); + } + + public: + template <typename MeshType, typename OutputArrayT, typename OutputType, typename InputType> + static PUGS_INLINE void + integrateTo(const std::function<OutputType(InputType)>& function, + const IQuadratureDescriptor& quadrature_descriptor, + const MeshType& mesh, + OutputArrayT& value) + { + constexpr size_t Dimension = MeshType::Dimension; + + _integrateTo<MeshType, OutputArrayT>(function, quadrature_descriptor, mesh, + AllEdges<Dimension>{mesh.connectivity()}, value); + } + + template <typename MeshType, typename OutputArrayT, typename FunctionType> + static PUGS_INLINE void + integrateTo(const FunctionType& function, + const IQuadratureDescriptor& quadrature_descriptor, + const MeshType& mesh, + OutputArrayT& value) + { + integrateTo(std::function(function), quadrature_descriptor, mesh, value); + } + + template <typename MeshType, typename OutputType, typename InputType, template <typename DataType> typename ArrayT> + static PUGS_INLINE ArrayT<OutputType> + integrate(const std::function<OutputType(InputType)>& function, + const IQuadratureDescriptor& quadrature_descriptor, + const MeshType& mesh, + const ArrayT<EdgeId>& edge_list) + { + ArrayT<OutputType> value(size(edge_list)); + _integrateTo<MeshType, ArrayT<OutputType>>(function, quadrature_descriptor, mesh, EdgeList{edge_list}, value); + + return value; + } + + template <typename MeshType, typename FunctionType, template <typename DataType> typename ArrayT> + static PUGS_INLINE auto + integrate(const FunctionType& function, + const IQuadratureDescriptor& quadrature_descriptor, + const MeshType& mesh, + const ArrayT<EdgeId>& edge_list) + { + return integrate(std::function(function), quadrature_descriptor, mesh, edge_list); + } +}; + +#endif // EDGE_INTEGRATOR_HPP diff --git a/src/scheme/FaceIntegrator.hpp b/src/scheme/FaceIntegrator.hpp new file mode 100644 index 0000000000000000000000000000000000000000..30ee39077ea12d898b4bdee00f12970be79e8753 --- /dev/null +++ b/src/scheme/FaceIntegrator.hpp @@ -0,0 +1,322 @@ +#ifndef FACE_INTEGRATOR_HPP +#define FACE_INTEGRATOR_HPP + +#include <analysis/IQuadratureDescriptor.hpp> +#include <analysis/QuadratureManager.hpp> +#include <geometry/LineTransformation.hpp> +#include <geometry/SquareTransformation.hpp> +#include <geometry/TriangleTransformation.hpp> +#include <mesh/Connectivity.hpp> +#include <mesh/ItemId.hpp> +#include <utils/Array.hpp> + +#include <functional> + +class FaceIntegrator +{ + private: + template <size_t Dimension> + class AllFaces + { + private: + const Connectivity<Dimension>& m_connectivity; + + public: + using index_type = FaceId; + + PUGS_INLINE + FaceId + faceId(const FaceId face_id) const + { + return face_id; + } + + PUGS_INLINE + size_t + size() const + { + return m_connectivity.numberOfFaces(); + } + + PUGS_INLINE + AllFaces(const Connectivity<Dimension>& connectivity) : m_connectivity{connectivity} {} + }; + + template <template <typename T> typename ArrayT> + class FaceList + { + private: + const ArrayT<FaceId>& m_face_list; + + public: + using index_type = typename ArrayT<FaceId>::index_type; + + PUGS_INLINE + FaceId + faceId(const index_type index) const + { + return m_face_list[index]; + } + + PUGS_INLINE + size_t + size() const + { + return m_face_list.size(); + } + + PUGS_INLINE + FaceList(const ArrayT<FaceId>& face_list) : m_face_list{face_list} {} + }; + + template <typename MeshType, typename OutputArrayT, typename ListTypeT, typename OutputType, typename InputType> + static PUGS_INLINE void + _tensorialIntegrateTo(std::function<OutputType(InputType)> function, + const IQuadratureDescriptor& quadrature_descriptor, + const MeshType& mesh, + const ListTypeT& face_list, + OutputArrayT& value) + { + constexpr size_t Dimension = MeshType::Dimension; + static_assert(Dimension > 1); + + static_assert(std::is_same_v<TinyVector<Dimension>, std::decay_t<InputType>>, "invalid input data type"); + static_assert(std::is_same_v<std::remove_const_t<typename OutputArrayT::data_type>, OutputType>, + "invalid output data type"); + + using execution_space = typename Kokkos::DefaultExecutionSpace::execution_space; + Kokkos::Experimental::UniqueToken<execution_space, Kokkos::Experimental::UniqueTokenScope::Global> tokens; + + if constexpr (std::is_arithmetic_v<OutputType>) { + value.fill(0); + } else if constexpr (is_tiny_vector_v<OutputType> or is_tiny_matrix_v<OutputType>) { + value.fill(zero); + } else { + static_assert(std::is_same_v<OutputType, double>, "unexpected output type"); + } + + const auto& connectivity = mesh.connectivity(); + + const auto face_to_node_matrix = connectivity.faceToNodeMatrix(); + const auto xr = mesh.xr(); + + if constexpr (Dimension == 2) { + const auto qf = QuadratureManager::instance().getLineFormula(quadrature_descriptor); + + parallel_for(face_list.size(), [=, &qf, &face_list](typename ListTypeT::index_type index) { + const FaceId face_id = face_list.faceId(index); + + const auto face_to_node = face_to_node_matrix[face_id]; + + Assert(face_to_node.size() == 2); + const LineTransformation<2> T(xr[face_to_node[0]], xr[face_to_node[1]]); + + for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { + const auto xi = qf.point(i_point); + value[index] += qf.weight(i_point) * T.velocityNorm() * function(T(xi)); + } + }); + + } else if constexpr (Dimension == 3) { + const auto qf = QuadratureManager::instance().getSquareFormula(quadrature_descriptor); + + auto invalid_face = std::make_pair(false, FaceId{}); + + parallel_for(face_list.size(), [=, &invalid_face, &qf, &face_list](typename ListTypeT::index_type index) { + const FaceId face_id = face_list.faceId(index); + + const auto face_to_node = face_to_node_matrix[face_id]; + + switch (face_to_node.size()) { + case 3: { + SquareTransformation<3> T(xr[face_to_node[0]], xr[face_to_node[1]], xr[face_to_node[2]], xr[face_to_node[2]]); + for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { + const auto xi = qf.point(i_point); + value[index] += qf.weight(i_point) * T.areaVariationNorm(xi) * function(T(xi)); + } + break; + } + case 4: { + SquareTransformation<3> T(xr[face_to_node[0]], xr[face_to_node[1]], xr[face_to_node[2]], xr[face_to_node[3]]); + for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { + const auto xi = qf.point(i_point); + value[index] += qf.weight(i_point) * T.areaVariationNorm(xi) * function(T(xi)); + } + break; + } + default: { + invalid_face = std::make_pair(true, face_id); + } + } + }); + + // LCOV_EXCL_START + if (invalid_face.first) { + std::ostringstream os; + os << "invalid face type for integration: " << face_to_node_matrix[invalid_face.second].size() << " points"; + throw UnexpectedError(os.str()); + } + // LCOV_EXCL_STOP + + } else { + throw UnexpectedError("invalid dimension for face integration"); + } + } + + template <typename MeshType, typename OutputArrayT, typename ListTypeT, typename OutputType, typename InputType> + static PUGS_INLINE void + _directIntegrateTo(std::function<OutputType(InputType)> function, + const IQuadratureDescriptor& quadrature_descriptor, + const MeshType& mesh, + const ListTypeT& face_list, + OutputArrayT& value) + { + Assert(not quadrature_descriptor.isTensorial()); + + constexpr size_t Dimension = MeshType::Dimension; + static_assert(Dimension > 1); + + static_assert(std::is_same_v<TinyVector<Dimension>, std::decay_t<InputType>>, "invalid input data type"); + static_assert(std::is_same_v<std::remove_const_t<typename OutputArrayT::data_type>, OutputType>, + "invalid output data type"); + + if constexpr (std::is_arithmetic_v<OutputType>) { + value.fill(0); + } else if constexpr (is_tiny_vector_v<OutputType> or is_tiny_matrix_v<OutputType>) { + value.fill(zero); + } else { + static_assert(std::is_same_v<OutputType, double>, "unexpected output type"); + } + + const auto& connectivity = mesh.connectivity(); + + const auto face_to_node_matrix = connectivity.faceToNodeMatrix(); + const auto xr = mesh.xr(); + + if constexpr (Dimension == 2) { + parallel_for(face_list.size(), + [=, &quadrature_descriptor, &face_list](const typename ListTypeT::index_type& index) { + const FaceId face_id = face_list.faceId(index); + + const auto face_to_node = face_to_node_matrix[face_id]; + + Assert(face_to_node.size() == 2); + const LineTransformation<2> T(xr[face_to_node[0]], xr[face_to_node[1]]); + const auto qf = QuadratureManager::instance().getLineFormula(quadrature_descriptor); + + for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { + const auto xi = qf.point(i_point); + value[index] += qf.weight(i_point) * T.velocityNorm() * function(T(xi)); + } + }); + + } else if constexpr (Dimension == 3) { + auto invalid_face = std::make_pair(false, FaceId{}); + + parallel_for(face_list.size(), + [=, &invalid_face, &quadrature_descriptor, &face_list](const typename ListTypeT::index_type& index) { + const FaceId face_id = face_list.faceId(index); + + const auto face_to_node = face_to_node_matrix[face_id]; + + switch (face_to_node.size()) { + case 3: { + const TriangleTransformation<3> T(xr[face_to_node[0]], xr[face_to_node[1]], xr[face_to_node[2]]); + const auto qf = QuadratureManager::instance().getTriangleFormula(quadrature_descriptor); + + for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { + const auto xi = qf.point(i_point); + value[index] += qf.weight(i_point) * T.areaVariationNorm() * function(T(xi)); + } + break; + } + case 4: { + const SquareTransformation<3> T(xr[face_to_node[0]], xr[face_to_node[1]], xr[face_to_node[2]], + xr[face_to_node[3]]); + const auto qf = QuadratureManager::instance().getSquareFormula(quadrature_descriptor); + + for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { + const auto xi = qf.point(i_point); + value[index] += qf.weight(i_point) * T.areaVariationNorm(xi) * function(T(xi)); + } + break; + } + // LCOV_EXCL_START + default: { + invalid_face = std::make_pair(true, face_id); + break; + } + // LCOV_EXCL_STOP + } + }); + + // LCOV_EXCL_START + if (invalid_face.first) { + std::ostringstream os; + os << "invalid face type for integration: " << face_to_node_matrix[invalid_face.second].size() << " points"; + throw UnexpectedError(os.str()); + } + // LCOV_EXCL_STOP + } + } + + public: + template <typename MeshType, typename OutputArrayT, typename OutputType, typename InputType> + static PUGS_INLINE void + integrateTo(const std::function<OutputType(InputType)>& function, + const IQuadratureDescriptor& quadrature_descriptor, + const MeshType& mesh, + OutputArrayT& value) + { + constexpr size_t Dimension = MeshType::Dimension; + + if (quadrature_descriptor.isTensorial()) { + _tensorialIntegrateTo<MeshType, OutputArrayT>(function, quadrature_descriptor, mesh, + AllFaces<Dimension>{mesh.connectivity()}, value); + } else { + _directIntegrateTo<MeshType, OutputArrayT>(function, quadrature_descriptor, mesh, + AllFaces<Dimension>{mesh.connectivity()}, value); + } + } + + template <typename MeshType, typename OutputArrayT, typename FunctionType> + static PUGS_INLINE void + integrateTo(const FunctionType& function, + const IQuadratureDescriptor& quadrature_descriptor, + const MeshType& mesh, + OutputArrayT& value) + { + integrateTo(std::function(function), quadrature_descriptor, mesh, value); + } + + template <typename MeshType, typename OutputType, typename InputType, template <typename DataType> typename ArrayT> + static PUGS_INLINE ArrayT<OutputType> + integrate(const std::function<OutputType(InputType)>& function, + const IQuadratureDescriptor& quadrature_descriptor, + const MeshType& mesh, + const ArrayT<FaceId>& face_list) + { + ArrayT<OutputType> value(size(face_list)); + if (quadrature_descriptor.isTensorial()) { + _tensorialIntegrateTo<MeshType, ArrayT<OutputType>>(function, quadrature_descriptor, mesh, FaceList{face_list}, + value); + } else { + _directIntegrateTo<MeshType, ArrayT<OutputType>>(function, quadrature_descriptor, mesh, FaceList{face_list}, + value); + } + + return value; + } + + template <typename MeshType, typename FunctionType, template <typename DataType> typename ArrayT> + static PUGS_INLINE auto + integrate(const FunctionType& function, + const IQuadratureDescriptor& quadrature_descriptor, + const MeshType& mesh, + const ArrayT<FaceId>& face_list) + { + return integrate(std::function(function), quadrature_descriptor, mesh, face_list); + } +}; + +#endif // FACE_INTEGRATOR_HPP diff --git a/src/utils/Array.hpp b/src/utils/Array.hpp index 54786db88592d7371e7b7fa5e9acd0aaec4fffe5..f78f543080edcfa614e6ad549a73349ffb66da74 100644 --- a/src/utils/Array.hpp +++ b/src/utils/Array.hpp @@ -6,6 +6,7 @@ #include <utils/PugsAssert.hpp> #include <utils/PugsMacros.hpp> #include <utils/PugsUtils.hpp> +#include <utils/Types.hpp> #include <Kokkos_CopyViews.hpp> #include <algorithm> @@ -140,8 +141,15 @@ class [[nodiscard]] Array ~Array() = default; }; +template <typename DataType> +[[nodiscard]] PUGS_INLINE size_t +size(const Array<DataType>& array) +{ + return array.size(); +} + template <typename DataType, typename... RT> -PUGS_INLINE Array<DataType> +[[nodiscard]] PUGS_INLINE Array<DataType> encapsulate(const Kokkos::View<DataType*, RT...>& values) { Array<DataType> array; @@ -150,7 +158,7 @@ encapsulate(const Kokkos::View<DataType*, RT...>& values) } template <typename DataType> -PUGS_INLINE Array<DataType> +[[nodiscard]] PUGS_INLINE Array<DataType> subArray(const Array<DataType>& array, typename Array<DataType>::index_type begin, typename Array<DataType>::index_type size) @@ -162,7 +170,7 @@ subArray(const Array<DataType>& array, // map, multimap, unordered_map and stack cannot be copied this way template <typename Container> -PUGS_INLINE Array<std::remove_const_t<typename Container::value_type>> +[[nodiscard]] PUGS_INLINE Array<std::remove_const_t<typename Container::value_type>> convert_to_array(const Container& given_container) { using DataType = typename Container::value_type; @@ -173,4 +181,185 @@ convert_to_array(const Container& given_container) return array; } +template <typename DataType> +[[nodiscard]] std::remove_const_t<DataType> +min(const Array<DataType>& array) +{ + using ArrayType = Array<DataType>; + using data_type = std::remove_const_t<typename ArrayType::data_type>; + using index_type = typename ArrayType::index_type; + + class ArrayMin + { + private: + const ArrayType m_array; + + public: + PUGS_INLINE + operator data_type() + { + data_type reduced_value; + parallel_reduce(m_array.size(), *this, reduced_value); + return reduced_value; + } + + PUGS_INLINE + void + operator()(const index_type& i, data_type& data) const + { + if (m_array[i] < data) { + data = m_array[i]; + } + } + + PUGS_INLINE + void + join(volatile data_type& dst, const volatile data_type& src) const + { + if (src < dst) { + dst = src; + } + } + + PUGS_INLINE + void + init(data_type& value) const + { + value = std::numeric_limits<data_type>::max(); + } + + PUGS_INLINE + ArrayMin(const ArrayType& array) : m_array(array) + { + ; + } + + PUGS_INLINE + ~ArrayMin() = default; + }; + + return ArrayMin(array); +} + +template <typename DataType> +[[nodiscard]] std::remove_const_t<DataType> +max(const Array<DataType>& array) +{ + using ArrayType = Array<DataType>; + using data_type = std::remove_const_t<typename ArrayType::data_type>; + using index_type = typename ArrayType::index_type; + + class ArrayMax + { + private: + const ArrayType m_array; + + public: + PUGS_INLINE + operator data_type() + { + data_type reduced_value; + parallel_reduce(m_array.size(), *this, reduced_value); + return reduced_value; + } + + PUGS_INLINE + void + operator()(const index_type& i, data_type& data) const + { + if (m_array[i] > data) { + data = m_array[i]; + } + } + + PUGS_INLINE + void + join(volatile data_type& dst, const volatile data_type& src) const + { + if (src > dst) { + dst = src; + } + } + + PUGS_INLINE + void + init(data_type& value) const + { + value = std::numeric_limits<data_type>::min(); + } + + PUGS_INLINE + ArrayMax(const ArrayType& array) : m_array(array) + { + ; + } + + PUGS_INLINE + ~ArrayMax() = default; + }; + + return ArrayMax(array); +} + +template <typename DataType> +[[nodiscard]] std::remove_const_t<DataType> +sum(const Array<DataType>& array) +{ + using ArrayType = Array<DataType>; + using data_type = std::remove_const_t<DataType>; + using index_type = typename ArrayType::index_type; + + class ArraySum + { + private: + const ArrayType m_array; + + public: + PUGS_INLINE + operator data_type() + { + data_type reduced_value; + parallel_reduce(m_array.size(), *this, reduced_value); + return reduced_value; + } + + PUGS_INLINE + void + operator()(const index_type& i, data_type& data) const + { + data += m_array[i]; + } + + PUGS_INLINE + void + join(volatile data_type& dst, const volatile data_type& src) const + { + dst += src; + } + + PUGS_INLINE + void + init(data_type& value) const + { + if constexpr (std::is_arithmetic_v<data_type>) { + value = 0; + } else { + static_assert(is_tiny_vector_v<data_type> or is_tiny_matrix_v<data_type>, "invalid data type"); + value = zero; + } + } + + PUGS_INLINE + ArraySum(const ArrayType& array) : m_array(array) + { + ; + } + + PUGS_INLINE + ~ArraySum() = default; + }; + + return ArraySum(array); +} + #endif // ARRAY_HPP diff --git a/src/utils/ArrayUtils.hpp b/src/utils/ArrayUtils.hpp deleted file mode 100644 index 3b3438294291af1deafe733374e7de9ddf4982b6..0000000000000000000000000000000000000000 --- a/src/utils/ArrayUtils.hpp +++ /dev/null @@ -1,211 +0,0 @@ -#ifndef ARRAY_UTILS_HPP -#define ARRAY_UTILS_HPP - -#include <utils/PugsMacros.hpp> -#include <utils/PugsTraits.hpp> -#include <utils/PugsUtils.hpp> - -#include <utils/Types.hpp> - -template <typename DataType, template <typename> typename ArrayT> -std::remove_const_t<DataType> -min(const ArrayT<DataType>& array) -{ - using ArrayType = ArrayT<DataType>; - using data_type = std::remove_const_t<typename ArrayType::data_type>; - using index_type = typename ArrayType::index_type; - - class ArrayMin - { - private: - const ArrayType m_array; - - public: - PUGS_INLINE - operator data_type() - { - data_type reduced_value; - parallel_reduce(m_array.size(), *this, reduced_value); - return reduced_value; - } - - PUGS_INLINE - void - operator()(const index_type& i, data_type& data) const - { - if (m_array[i] < data) { - data = m_array[i]; - } - } - - PUGS_INLINE - void - join(volatile data_type& dst, const volatile data_type& src) const - { - if (src < dst) { - dst = src; - } - } - - PUGS_INLINE - void - init(data_type& value) const - { - value = std::numeric_limits<data_type>::max(); - } - - PUGS_INLINE - ArrayMin(const ArrayType& array) : m_array(array) - { - ; - } - - PUGS_INLINE - ~ArrayMin() = default; - }; - - return ArrayMin(array); -} - -template <typename DataType, template <typename> typename ArrayT> -std::remove_const_t<DataType> -max(const ArrayT<DataType>& array) -{ - using ArrayType = ArrayT<DataType>; - using data_type = std::remove_const_t<typename ArrayType::data_type>; - using index_type = typename ArrayType::index_type; - - class ArrayMax - { - private: - const ArrayType m_array; - - public: - PUGS_INLINE - operator data_type() - { - data_type reduced_value; - parallel_reduce(m_array.size(), *this, reduced_value); - return reduced_value; - } - - PUGS_INLINE - void - operator()(const index_type& i, data_type& data) const - { - if (m_array[i] > data) { - data = m_array[i]; - } - } - - PUGS_INLINE - void - join(volatile data_type& dst, const volatile data_type& src) const - { - if (src > dst) { - dst = src; - } - } - - PUGS_INLINE - void - init(data_type& value) const - { - value = std::numeric_limits<data_type>::min(); - } - - PUGS_INLINE - ArrayMax(const ArrayType& array) : m_array(array) - { - ; - } - - PUGS_INLINE - ~ArrayMax() = default; - }; - - return ArrayMax(array); -} - -template <typename DataType, template <typename> typename ArrayT> -std::remove_const_t<DataType> -sum(const ArrayT<DataType>& array) -{ - using ArrayType = ArrayT<DataType>; - using data_type = std::remove_const_t<DataType>; - using index_type = typename ArrayType::index_type; - - class ArraySum - { - private: - const ArrayType m_array; - - public: - PUGS_INLINE - operator data_type() - { - data_type reduced_value; - parallel_reduce(m_array.size(), *this, reduced_value); - return reduced_value; - } - - PUGS_INLINE - void - operator()(const index_type& i, data_type& data) const - { - data += m_array[i]; - } - - PUGS_INLINE - void - join(volatile data_type& dst, const volatile data_type& src) const - { - dst += src; - } - - PUGS_INLINE - void - init(data_type& value) const - { - if constexpr (std::is_arithmetic_v<data_type>) { - value = 0; - } else { - static_assert(is_tiny_vector_v<data_type> or is_tiny_matrix_v<data_type>, "invalid data type"); - value = zero; - } - } - - PUGS_INLINE - ArraySum(const ArrayType& array) : m_array(array) - { - ; - } - - PUGS_INLINE - ~ArraySum() = default; - }; - - return ArraySum(array); -} - -template <template <typename... SourceT> typename SourceArray, - template <typename... ImageT> - typename ImageArray, - typename... SourceT, - typename... ImageT> -void -value_copy(const SourceArray<SourceT...>& source_array, ImageArray<ImageT...>& image_array) -{ - using SourceDataType = typename SourceArray<SourceT...>::data_type; - using ImageDataType = typename ImageArray<ImageT...>::data_type; - - static_assert(std::is_same_v<std::remove_const_t<SourceDataType>, ImageDataType>); - static_assert(not std::is_const_v<ImageDataType>); - - Assert(source_array.size() == image_array.size()); - - parallel_for( - source_array.size(), PUGS_LAMBDA(size_t i) { image_array[i] = source_array[i]; }); -} - -#endif // ARRAY_UTILS_HPP diff --git a/src/utils/CastArray.hpp b/src/utils/CastArray.hpp index d329b4ef35f70f3a612ca430c45d0ec23bb7ed9d..07c696428573db04f05186464d0891851c686756 100644 --- a/src/utils/CastArray.hpp +++ b/src/utils/CastArray.hpp @@ -32,6 +32,19 @@ class [[nodiscard]] CastArray return m_values[i]; } + template <typename ImageDataType, typename ImageCastDataType> + friend PUGS_INLINE void copy_to(const CastArray& source_array, + CastArray<ImageDataType, ImageCastDataType>& image_array) + { + static_assert(std::is_same_v<std::remove_const_t<CastDataType>, ImageCastDataType>); + static_assert(not std::is_const_v<ImageCastDataType>); + + Assert(source_array.size() == image_array.size()); + if (source_array.size() > 0) { + std::copy(source_array.m_values, source_array.m_values + source_array.size(), &image_array[0]); + } + } + PUGS_INLINE CastArray& operator=(const CastArray&) = default; diff --git a/src/utils/Messenger.hpp b/src/utils/Messenger.hpp index 7e8b30c1a8e92c05fc30178e325110617c73c823..75ef1732a496e367917b55b86e4f2075570acd86 100644 --- a/src/utils/Messenger.hpp +++ b/src/utils/Messenger.hpp @@ -5,7 +5,6 @@ #include <utils/PugsMacros.hpp> #include <utils/Array.hpp> -#include <utils/ArrayUtils.hpp> #include <utils/CastArray.hpp> #include <type_traits> @@ -136,7 +135,7 @@ class Messenger MPI_Gather(data_address, data_array.size(), mpi_datatype, gather_address, data_array.size(), mpi_datatype, rank, MPI_COMM_WORLD); #else // PUGS_HAS_MPI - value_copy(data_array, gather_array); + copy_to(data_array, gather_array); #endif // PUGS_HAS_MPI } @@ -177,7 +176,7 @@ class Messenger MPI_Gatherv(data_address, data_array.size(), mpi_datatype, gather_address, sizes_address, positions_address, mpi_datatype, rank, MPI_COMM_WORLD); #else // PUGS_HAS_MPI - value_copy(data_array, gather_array); + copy_to(data_array, gather_array); #endif // PUGS_HAS_MPI } @@ -222,7 +221,7 @@ class Messenger MPI_Allgather(data_address, data_array.size(), mpi_datatype, gather_address, data_array.size(), mpi_datatype, MPI_COMM_WORLD); #else // PUGS_HAS_MPI - value_copy(data_array, gather_array); + copy_to(data_array, gather_array); #endif // PUGS_HAS_MPI } @@ -262,7 +261,7 @@ class Messenger MPI_Allgatherv(data_address, data_array.size(), mpi_datatype, gather_address, sizes_address, positions_address, mpi_datatype, MPI_COMM_WORLD); #else // PUGS_HAS_MPI - value_copy(data_array, gather_array); + copy_to(data_array, gather_array); #endif // PUGS_HAS_MPI } @@ -323,7 +322,7 @@ class Messenger MPI_Alltoall(sent_address, count, mpi_datatype, recv_address, count, mpi_datatype, MPI_COMM_WORLD); #else // PUGS_HAS_MPI - value_copy(sent_array, recv_array); + copy_to(sent_array, recv_array); #endif // PUGS_HAS_MPI } @@ -378,7 +377,7 @@ class Messenger Assert(sent_array_list.size() == 1); Assert(recv_array_list.size() == 1); - value_copy(sent_array_list[0], recv_array_list[0]); + copy_to(sent_array_list[0], recv_array_list[0]); #endif // PUGS_HAS_MPI } diff --git a/src/utils/SmallArray.hpp b/src/utils/SmallArray.hpp index b5186a7f6341606a92084fd7ee5521b5d252b4ee..9e0782f1c0adb0b9bfa4bcf25bcaa8977a3800d4 100644 --- a/src/utils/SmallArray.hpp +++ b/src/utils/SmallArray.hpp @@ -6,6 +6,7 @@ #include <utils/PugsAssert.hpp> #include <utils/PugsMacros.hpp> #include <utils/PugsUtils.hpp> +#include <utils/Types.hpp> #include <algorithm> @@ -128,6 +129,13 @@ class [[nodiscard]] SmallArray ~SmallArray() = default; }; +template <typename DataType> +PUGS_INLINE size_t +size(const SmallArray<DataType>& array) +{ + return array.size(); +} + // map, multimap, unordered_map and stack cannot be copied this way template <typename Container> PUGS_INLINE SmallArray<std::remove_const_t<typename Container::value_type>> @@ -141,4 +149,60 @@ convert_to_small_array(const Container& given_container) return array; } +template <typename DataType> +[[nodiscard]] std::remove_const_t<DataType> +min(const SmallArray<DataType>& array) +{ + using data_type = std::remove_const_t<DataType>; + using index_type = typename SmallArray<DataType>::index_type; + + data_type min_value = std::numeric_limits<data_type>::max(); + for (index_type i = 0; i < array.size(); ++i) { + if (array[i] < min_value) { + min_value = array[i]; + } + } + return min_value; +} + +template <typename DataType> +[[nodiscard]] std::remove_const_t<DataType> +max(const SmallArray<DataType>& array) +{ + using data_type = std::remove_const_t<DataType>; + using index_type = typename SmallArray<DataType>::index_type; + + data_type max_value = -std::numeric_limits<data_type>::max(); + for (index_type i = 0; i < array.size(); ++i) { + if (array[i] > max_value) { + max_value = array[i]; + } + } + return max_value; +} + +template <typename DataType> +[[nodiscard]] std::remove_const_t<DataType> +sum(const SmallArray<DataType>& array) +{ + using data_type = std::remove_const_t<DataType>; + using index_type = typename SmallArray<DataType>::index_type; + + data_type sum_value = [] { + if constexpr (std::is_arithmetic_v<DataType>) { + return 0; + } else if constexpr (is_tiny_vector_v<DataType> or is_tiny_matrix_v<DataType>) { + return zero; + } else { + static_assert(std::is_arithmetic_v<DataType>, "invalid data type"); + } + }(); + + for (index_type i = 0; i < array.size(); ++i) { + sum_value += array[i]; + } + + return sum_value; +} + #endif // SMALL_ARRAY_HPP diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 25bcaa008af00dd141bfc4a0ba1fc65bb11a2003..f825a2cfdfcd2f869037039d10eb041aced9980c 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -11,7 +11,6 @@ add_executable (unit_tests test_AffectationToTupleProcessor.cpp test_Array.cpp test_ArraySubscriptProcessor.cpp - test_ArrayUtils.cpp test_ASTBuilder.cpp test_ASTDotPrinter.cpp test_ASTModulesImporter.cpp @@ -54,6 +53,7 @@ add_executable (unit_tests test_BuiltinFunctionEmbedderTable.cpp test_BuiltinFunctionProcessor.cpp test_CastArray.cpp + test_CellIntegrator.cpp test_ConsoleManager.cpp test_CG.cpp test_ContinueProcessor.cpp @@ -61,6 +61,8 @@ add_executable (unit_tests test_CRSGraph.cpp test_CRSMatrix.cpp test_CRSMatrixDescriptor.cpp + test_CubeGaussQuadrature.cpp + test_CubeTransformation.cpp test_DataVariant.cpp test_Demangle.cpp test_DiscreteFunctionDescriptorP0.cpp @@ -68,12 +70,14 @@ add_executable (unit_tests test_DiscreteFunctionType.cpp test_DiscreteFunctionUtils.cpp test_DoWhileProcessor.cpp + test_EdgeIntegrator.cpp test_EigenvalueSolver.cpp test_EmbeddedData.cpp test_EmbeddedIDiscreteFunctionUtils.cpp test_EscapedString.cpp test_Exceptions.cpp test_ExecutionPolicy.cpp + test_FaceIntegrator.cpp test_FakeProcessor.cpp test_ForProcessor.cpp test_FunctionArgumentConverter.cpp @@ -86,6 +90,7 @@ add_executable (unit_tests test_ItemType.cpp test_LinearSolver.cpp test_LinearSolverOptions.cpp + test_LineTransformation.cpp test_ListAffectationProcessor.cpp test_MathModule.cpp test_NameProcessor.cpp @@ -93,17 +98,29 @@ add_executable (unit_tests test_OStream.cpp test_ParseError.cpp test_PETScUtils.cpp + test_PrismGaussQuadrature.cpp + test_PrismTransformation.cpp test_PugsAssert.cpp test_PugsFunctionAdapter.cpp test_PugsUtils.cpp + test_PyramidGaussQuadrature.cpp + test_PyramidTransformation.cpp test_RevisionInfo.cpp test_SmallArray.cpp test_SmallVector.cpp + test_SquareGaussQuadrature.cpp + test_SquareTransformation.cpp test_SymbolTable.cpp test_Table.cpp + test_TetrahedronGaussQuadrature.cpp + test_TetrahedronTransformation.cpp + test_TensorialGaussLegendreQuadrature.cpp + test_TensorialGaussLobattoQuadrature.cpp test_Timer.cpp test_TinyMatrix.cpp test_TinyVector.cpp + test_TriangleGaussQuadrature.cpp + test_TriangleTransformation.cpp test_TupleToVectorProcessor.cpp test_UnaryExpressionProcessor.cpp test_UnaryOperatorMangler.cpp @@ -145,6 +162,7 @@ target_link_libraries (unit_tests PugsLanguage PugsMesh PugsAlgebra + PugsAnalysis PugsScheme PugsOutput PugsUtils @@ -160,6 +178,7 @@ target_link_libraries (unit_tests target_link_libraries (mpi_unit_tests test_Pugs_MeshDataBase PugsAlgebra + PugsAnalysis PugsUtils PugsLanguage PugsLanguageAST diff --git a/tests/MeshDataBaseForTests.cpp b/tests/MeshDataBaseForTests.cpp index 95399d4564f38313f443f144cf214298577f315a..b58cc22e8eef00cdbdc820d01efae0dce9147a44 100644 --- a/tests/MeshDataBaseForTests.cpp +++ b/tests/MeshDataBaseForTests.cpp @@ -1,8 +1,13 @@ #include <MeshDataBaseForTests.hpp> #include <mesh/CartesianMeshBuilder.hpp> #include <mesh/Connectivity.hpp> +#include <mesh/GmshReader.hpp> +#include <utils/Messenger.hpp> #include <utils/PugsAssert.hpp> +#include <filesystem> +#include <fstream> + const MeshDataBaseForTests* MeshDataBaseForTests::m_instance = nullptr; MeshDataBaseForTests::MeshDataBaseForTests() @@ -15,6 +20,10 @@ MeshDataBaseForTests::MeshDataBaseForTests() m_cartesian_3d_mesh = std::dynamic_pointer_cast<const Mesh<Connectivity<3>>>( CartesianMeshBuilder{TinyVector<3>{0, 1, 0}, TinyVector<3>{2, -1, 3}, TinyVector<3, size_t>{6, 7, 4}}.mesh()); + + m_unordered_1d_mesh = _buildUnordered1dMesh(); + m_hybrid_2d_mesh = _buildHybrid2dMesh(); + m_hybrid_3d_mesh = _buildHybrid3dMesh(); } const MeshDataBaseForTests& @@ -39,19 +48,913 @@ MeshDataBaseForTests::destroy() } std::shared_ptr<const Mesh<Connectivity<1>>> -MeshDataBaseForTests::cartesianMesh1D() const +MeshDataBaseForTests::cartesian1DMesh() const { return m_cartesian_1d_mesh; } std::shared_ptr<const Mesh<Connectivity<2>>> -MeshDataBaseForTests::cartesianMesh2D() const +MeshDataBaseForTests::cartesian2DMesh() const { return m_cartesian_2d_mesh; } std::shared_ptr<const Mesh<Connectivity<3>>> -MeshDataBaseForTests::cartesianMesh3D() const +MeshDataBaseForTests::cartesian3DMesh() const { return m_cartesian_3d_mesh; } + +std::shared_ptr<const Mesh<Connectivity<1>>> +MeshDataBaseForTests::unordered1DMesh() const +{ + return m_unordered_1d_mesh; +} + +std::shared_ptr<const Mesh<Connectivity<2>>> +MeshDataBaseForTests::hybrid2DMesh() const +{ + return m_hybrid_2d_mesh; +} + +std::shared_ptr<const Mesh<Connectivity<3>>> +MeshDataBaseForTests::hybrid3DMesh() const +{ + return m_hybrid_3d_mesh; +} + +std::shared_ptr<const Mesh<Connectivity<1>>> +MeshDataBaseForTests::_buildUnordered1dMesh() +{ + const std::string filename = std::filesystem::path{PUGS_BINARY_DIR}.append("tests").append("unordered-1d.msh"); + if (parallel::rank() == 0) { + std::ofstream fout(filename); + fout << R"($MeshFormat +2.2 0 8 +$EndMeshFormat +$PhysicalNames +4 +0 1 "XMIN" +0 2 "XMAX" +1 3 "LEFT" +1 4 "RIGHT" +$EndPhysicalNames +$Nodes +35 +1 0 0 0 +2 -1 0 0 +3 1 0 0 +4 0.03246387076421061 0 0 +5 0.07692961499792127 0 0 +6 0.1378343163027127 0 0 +7 0.2212554508344625 0 0 +8 0.3355173320316702 0 0 +9 0.4920217492706127 0 0 +10 0.7063857794730655 0 0 +11 -0.9513615311521172 0 0 +12 -0.9036693300347614 0 0 +13 -0.8569049934960202 0 0 +14 -0.8110504814343311 0 0 +15 -0.7660880891035384 0 0 +16 -0.7220004662902741 0 0 +17 -0.6787705699229041 0 0 +18 -0.6363817403249178 0 0 +19 -0.5948175927947426 0 0 +20 -0.5540620983944274 0 0 +21 -0.5140995098187926 0 0 +22 -0.4749144219806904 0 0 +23 -0.4364916774353312 0 0 +24 -0.3988164798351664 0 0 +25 -0.3618742567441507 0 0 +26 -0.3256507606537927 0 0 +27 -0.2901320091863738 0 0 +28 -0.2553042883413312 0 0 +29 -0.2211541538737678 0 0 +30 -0.1876684263237806 0 0 +31 -0.1548341743437643 0 0 +32 -0.1226387276497952 0 0 +33 -0.09106965120674937 0 0 +34 -0.0601147701140996 0 0 +35 -0.02976212372405818 0 0 +$EndNodes +$Elements +36 +1 15 2 1 2 2 +2 15 2 2 3 3 +3 1 2 4 1 1 4 +4 1 2 4 1 4 5 +5 1 2 4 1 5 6 +6 1 2 4 1 6 7 +7 1 2 4 1 7 8 +8 1 2 4 1 8 9 +9 1 2 4 1 9 10 +10 1 2 4 1 10 3 +11 1 2 3 2 2 11 +12 1 2 3 2 11 12 +13 1 2 3 2 12 13 +14 1 2 3 2 13 14 +15 1 2 3 2 14 15 +16 1 2 3 2 15 16 +17 1 2 3 2 16 17 +18 1 2 3 2 17 18 +19 1 2 3 2 18 19 +20 1 2 3 2 19 20 +21 1 2 3 2 20 21 +22 1 2 3 2 21 22 +23 1 2 3 2 22 23 +24 1 2 3 2 23 24 +25 1 2 3 2 24 25 +26 1 2 3 2 25 26 +27 1 2 3 2 26 27 +28 1 2 3 2 27 28 +29 1 2 3 2 28 29 +30 1 2 3 2 29 30 +31 1 2 3 2 30 31 +32 1 2 3 2 31 32 +33 1 2 3 2 32 33 +34 1 2 3 2 33 34 +35 1 2 3 2 34 35 +36 1 2 3 2 35 1 +$EndElements +)"; + } + + return std::dynamic_pointer_cast<const Mesh<Connectivity<1>>>(GmshReader{filename}.mesh()); +} + +std::shared_ptr<const Mesh<Connectivity<2>>> +MeshDataBaseForTests::_buildHybrid2dMesh() +{ + const std::string filename = std::filesystem::path{PUGS_BINARY_DIR}.append("tests").append("hybrid-2d.msh"); + if (parallel::rank() == 0) { + std::ofstream fout(filename); + fout << R"($MeshFormat +2.2 0 8 +$EndMeshFormat +$PhysicalNames +10 +0 7 "XMINYMIN" +0 8 "XMINYMAX" +0 9 "XMAXYMIN" +0 10 "XMAXYMAX" +1 1 "XMIN" +1 2 "XMAX" +1 3 "YMAX" +1 4 "YMIN" +2 5 "LEFT" +2 6 "RIGHT" +$EndPhysicalNames +$Nodes +53 +1 0 0 0 +2 1 0 0 +3 1 1 0 +4 0 1 0 +5 2 0 0 +6 2 1 0 +7 0 0.7500000000003477 0 +8 0 0.5000000000020616 0 +9 0 0.2500000000010419 0 +10 1 0.2499999999994109 0 +11 1 0.4999999999986918 0 +12 1 0.7499999999993401 0 +13 2 0.2499999999994109 0 +14 2 0.4999999999986918 0 +15 2 0.7499999999993401 0 +16 0.7500000000003477 1 0 +17 0.5000000000020616 1 0 +18 0.2500000000010419 1 0 +19 1.749999999999999 1 0 +20 1.499999999999998 1 0 +21 1.249999999999999 1 0 +22 0.2499999999994109 0 0 +23 0.4999999999986918 0 0 +24 0.7499999999993401 0 0 +25 1.250000000000001 0 0 +26 1.500000000000002 0 0 +27 1.750000000000001 0 0 +28 0.5645539210988633 0.7822119881665017 0 +29 0.8034002623653069 0.616177001724073 0 +30 0.6429040982169911 0.5281266166868597 0 +31 0.8070137458488089 0.4050273873671746 0 +32 0.193468206450602 0.7967828567280011 0 +33 0.192644796000149 0.6419508693748935 0 +34 0.3924123452244094 0.5739639975328588 0 +35 0.3555609898784376 0.7915857937795373 0 +36 0.1932938945983771 0.4291816994842411 0 +37 0.3837729988924632 0.3582605556259788 0 +38 0.5797710532625071 0.2819566416178859 0 +39 0.7822395465040892 0.7780567773069014 0 +40 0.355038784333282 0.2031847484281184 0 +41 0.2059222030287144 0.2167595959294507 0 +42 0.7859869002303115 0.2399319972346836 0 +43 1.212848849190124 0.2732369527435796 0 +44 1.307250451008527 0.5758879308566747 0 +45 1.493594137086004 0.410605759034483 0 +46 1.439097356236337 0.1761649793157971 0 +47 1.574782862067863 0.7190230111887566 0 +48 1.740502300977129 0.4934083027495074 0 +49 1.853320217111459 0.2440179674328906 0 +50 1.629419001691624 0.2206995018497341 0 +51 1.844214193840832 0.743738552322716 0 +52 1.151907331010239 0.7762099486172758 0 +53 1.354193535052909 0.8313717608489495 0 +$EndNodes +$Elements +86 +1 15 2 7 1 1 +2 15 2 8 4 4 +3 15 2 9 5 5 +4 15 2 10 6 6 +5 1 2 1 1 4 7 +6 1 2 1 1 7 8 +7 1 2 1 1 8 9 +8 1 2 1 1 9 1 +9 1 2 2 3 5 13 +10 1 2 2 3 13 14 +11 1 2 2 3 14 15 +12 1 2 2 3 15 6 +13 1 2 3 4 3 16 +14 1 2 3 4 16 17 +15 1 2 3 4 17 18 +16 1 2 3 4 18 4 +17 1 2 3 5 6 19 +18 1 2 3 5 19 20 +19 1 2 3 5 20 21 +20 1 2 3 5 21 3 +21 1 2 4 6 1 22 +22 1 2 4 6 22 23 +23 1 2 4 6 23 24 +24 1 2 4 6 24 2 +25 1 2 4 7 2 25 +26 1 2 4 7 25 26 +27 1 2 4 7 26 27 +28 1 2 4 7 27 5 +29 2 2 6 2 43 45 44 +30 2 2 6 2 46 45 43 +31 2 2 6 2 11 43 44 +32 2 2 6 2 45 48 47 +33 2 2 6 2 46 43 25 +34 2 2 6 2 44 45 47 +35 2 2 6 2 43 11 10 +36 2 2 6 2 48 50 49 +37 2 2 6 2 14 51 48 +38 2 2 6 2 45 50 48 +39 2 2 6 2 27 49 50 +40 2 2 6 2 52 11 44 +41 2 2 6 2 49 27 5 +42 2 2 6 2 47 19 20 +43 2 2 6 2 12 52 3 +44 2 2 6 2 52 21 3 +45 2 2 6 2 47 53 44 +46 2 2 6 2 27 50 26 +47 2 2 6 2 43 10 2 +48 2 2 6 2 25 43 2 +49 2 2 6 2 20 53 47 +50 2 2 6 2 21 53 20 +51 2 2 6 2 46 50 45 +52 2 2 6 2 26 50 46 +53 2 2 6 2 44 53 52 +54 2 2 6 2 46 25 26 +55 2 2 6 2 11 52 12 +56 2 2 6 2 47 48 51 +57 2 2 6 2 51 14 15 +58 2 2 6 2 13 49 5 +59 2 2 6 2 51 19 47 +60 2 2 6 2 21 52 53 +61 2 2 6 2 19 51 6 +62 2 2 6 2 51 15 6 +63 2 2 6 2 48 49 14 +64 2 2 6 2 49 13 14 +65 3 2 5 1 37 34 33 36 +66 3 2 5 1 30 31 11 29 +67 3 2 5 1 35 34 30 28 +68 3 2 5 1 30 29 39 28 +69 3 2 5 1 34 37 38 30 +70 3 2 5 1 37 40 23 38 +71 3 2 5 1 41 40 37 36 +72 3 2 5 1 28 17 18 35 +73 3 2 5 1 30 38 42 31 +74 3 2 5 1 11 31 42 10 +75 3 2 5 1 39 16 17 28 +76 3 2 5 1 33 32 4 7 +77 3 2 5 1 11 12 39 29 +78 3 2 5 1 35 18 4 32 +79 3 2 5 1 23 40 41 22 +80 3 2 5 1 16 39 12 3 +81 3 2 5 1 41 36 8 9 +82 3 2 5 1 9 1 22 41 +83 3 2 5 1 10 42 24 2 +84 3 2 5 1 23 24 42 38 +85 3 2 5 1 7 8 36 33 +86 3 2 5 1 35 32 33 34 +$EndElements +)"; + } + return std::dynamic_pointer_cast<const Mesh<Connectivity<2>>>(GmshReader{filename}.mesh()); +} + +std::shared_ptr<const Mesh<Connectivity<3>>> +MeshDataBaseForTests::_buildHybrid3dMesh() +{ + const std::string filename = std::filesystem::path{PUGS_BINARY_DIR}.append("tests").append("hybrid-3d.msh"); + if (parallel::rank() == 0) { + std::ofstream fout(filename); + fout << R"($MeshFormat +2.2 0 8 +$EndMeshFormat +$PhysicalNames +29 +0 40 "XMINYMINZMIN" +0 41 "XMAXYMINZMIN" +0 42 "XMINYMAXZMIN" +0 43 "XMINYMAXZMAX" +0 44 "XMINYMINZMAX" +0 45 "XMAXYMINZMAX" +0 47 "XMAXYMAXZMAX" +0 51 "XMAXYMAXZMIN" +1 28 "XMINZMIN" +1 29 "XMINZMAX" +1 30 "XMINYMAX" +1 31 "XMINYMIN" +1 32 "XMAXZMIN" +1 33 "XMAXZMAX" +1 34 "XMAXYMAX" +1 35 "XMAXYMIN" +1 36 "YMINZMIN" +1 37 "YMINZMAX" +1 38 "YMAXZMIN" +1 39 "YMAXZMAX" +2 22 "XMIN" +2 23 "XMAX" +2 24 "ZMAX" +2 25 "ZMIN" +2 26 "YMAX" +2 27 "YMIN" +3 52 "HEXAHEDRA" +3 53 "PYRAMIDS" +3 54 "TETRAHEDRA" +$EndPhysicalNames +$Nodes +132 +1 0 0 0 +2 0.7 0 0 +3 0.8 1 0 +4 0 1 0 +5 1.3 0 0 +6 1.2 1 0 +7 0 1 1 +8 0 0 1 +9 0.7 0 1 +10 0.8 1 1 +11 1.3 0 1 +12 1.2 1 1 +13 2 0 0 +14 2 1 0 +15 2 0 1 +16 2 1 1 +17 0 0.7500000000003466 0 +18 0 0.5000000000020587 0 +19 0 0.2500000000010403 0 +20 0.7249999999999414 0.2499999999994139 0 +21 0.7499999999998691 0.4999999999986909 0 +22 0.7749999999999342 0.7499999999993421 0 +23 1.266666666666749 0.3333333333325114 0 +24 1.23333333333342 0.6666666666657952 0 +25 0.4000000000010956 1 0 +26 0.3499999999991014 0 0 +27 0.9999999999987851 0 0 +28 0 0.7500000000003466 1 +29 0 0.5000000000020587 1 +30 0 0.2500000000010403 1 +31 0.3499999999991014 0 1 +32 0.7249999999999414 0.2499999999994139 1 +33 0.7499999999998691 0.4999999999986909 1 +34 0.7749999999999342 0.7499999999993421 1 +35 0.4000000000010956 1 1 +36 0 1 0.3333333333333333 +37 0 1 0.6666666666666666 +38 0 0 0.3333333333333333 +39 0 0 0.6666666666666666 +40 0.7 0 0.3333333333333333 +41 0.7 0 0.6666666666666666 +42 0.8 1 0.3333333333333333 +43 0.8 1 0.6666666666666666 +44 0.9999999999987851 0 1 +45 1.266666666666749 0.3333333333325114 1 +46 1.23333333333342 0.6666666666657952 1 +47 1.3 0 0.3333333333333333 +48 1.3 0 0.6666666666666666 +49 1.2 1 0.3333333333333333 +50 1.2 1 0.6666666666666666 +51 1.630495225600928 0 0 +52 1.630495225600928 0 1 +53 2 0 0.499999999998694 +54 2 0.499999999998694 1 +55 2 0.499999999998694 0 +56 1.577708829260476 1 0 +57 1.577708829258421 1 1 +58 2 1 0.499999999998694 +59 0.3962888297748171 0.7916234456658734 0 +60 0.5588133104363274 0.5235006176096062 0 +61 0.48540966431768 0.3326974099157888 0 +62 0.2545886146233393 0.4410037988896774 0 +63 0.1888904744336107 0.2469120833355397 0 +64 0.9952483415423343 0.5591370310039079 0 +65 1.009047204638942 0.8056163713004886 0 +66 0.9496163434716166 0.3148023652713143 0 +67 0 0.7500000000003466 0.3333333333333333 +68 0 0.7500000000003466 0.6666666666666666 +69 0 0.5000000000020587 0.3333333333333333 +70 0 0.5000000000020587 0.6666666666666666 +71 0 0.2500000000010403 0.3333333333333333 +72 0 0.2500000000010403 0.6666666666666666 +73 0.3499999999991014 0 0.3333333333333333 +74 0.3499999999991014 0 0.6666666666666666 +75 0.7249999999999414 0.2499999999994139 0.3333333333333333 +76 0.7249999999999414 0.2499999999994139 0.6666666666666666 +77 0.7499999999998691 0.4999999999986909 0.3333333333333333 +78 0.7499999999998691 0.4999999999986909 0.6666666666666666 +79 0.7749999999999342 0.7499999999993421 0.3333333333333333 +80 0.7749999999999342 0.7499999999993421 0.6666666666666666 +81 0.4000000000010956 1 0.3333333333333333 +82 0.4000000000010956 1 0.6666666666666666 +83 0.3962888297748171 0.7916234456658734 1 +84 0.5588133104363274 0.5235006176096062 1 +85 0.48540966431768 0.3326974099157888 1 +86 0.2545886146233393 0.4410037988896774 1 +87 0.1888904744336107 0.2469120833355397 1 +88 0.9999999999987851 0 0.3333333333333333 +89 0.9999999999987851 0 0.6666666666666666 +90 1.266666666666749 0.3333333333325114 0.3333333333333333 +91 1.266666666666749 0.3333333333325114 0.6666666666666666 +92 1.23333333333342 0.6666666666657952 0.3333333333333333 +93 1.23333333333342 0.6666666666657952 0.6666666666666666 +94 0.9952483415423343 0.5591370310039079 1 +95 1.009047204638942 0.8056163713004886 1 +96 0.9496163434716166 0.3148023652713143 1 +97 1.694794622046484 0 0.4999999999999999 +98 2 0.667671095007814 0.3323289049917093 +99 2 0.3400507564846686 0.5028063863717376 +100 2 0.7126842003874787 0.6873157996117608 +101 1.638498486684473 0.2509397074193687 1 +102 1.619828855633658 0.6299359336032246 1 +103 1.638498486684556 0.2509397074193682 0 +104 1.619828855634071 0.629935933603235 0 +105 1.657210007479593 1 0.5000000082593427 +106 0.3962888297748171 0.7916234456658734 0.3333333333333333 +107 0.3962888297748171 0.7916234456658734 0.6666666666666666 +108 0.5588133104363274 0.5235006176096062 0.3333333333333333 +109 0.5588133104363274 0.5235006176096062 0.6666666666666666 +110 0.48540966431768 0.3326974099157888 0.3333333333333333 +111 0.48540966431768 0.3326974099157888 0.6666666666666666 +112 0.2545886146233393 0.4410037988896774 0.3333333333333333 +113 0.2545886146233393 0.4410037988896774 0.6666666666666666 +114 0.1888904744336107 0.2469120833355397 0.3333333333333333 +115 0.1888904744336107 0.2469120833355397 0.6666666666666666 +116 0.9952483415423343 0.5591370310039079 0.3333333333333333 +117 0.9952483415423343 0.5591370310039079 0.6666666666666666 +118 1.009047204638942 0.8056163713004886 0.3333333333333333 +119 1.009047204638942 0.8056163713004886 0.6666666666666666 +120 0.9496163434716166 0.3148023652713143 0.3333333333333333 +121 0.9496163434716166 0.3148023652713143 0.6666666666666666 +122 1.605048220195734 0.3680048220187183 0.5 +123 1.521560099439846 0.6946560099431293 0.4999999999999999 +124 1.449585918125941 0.1832919251455124 0.1666666666666667 +125 1.449585918125941 0.1832919251455124 0.4999999999999999 +126 1.449585918125941 0.1832919251455124 0.8333333333333333 +127 1.416252584792843 0.5166252584784292 0.1666666666666667 +128 1.416252584792843 0.5166252584784292 0.4999999999999999 +129 1.416252584792843 0.5166252584784292 0.8333333333333333 +130 1.382919251459699 0.8499585918121965 0.1666666666666667 +131 1.382919251459699 0.8499585918121965 0.4999999999999999 +132 1.382919251459699 0.8499585918121965 0.8333333333333333 +$EndNodes +$Elements +384 +1 15 2 40 1 1 +2 15 2 42 4 4 +3 15 2 43 7 7 +4 15 2 44 8 8 +5 15 2 41 27 13 +6 15 2 51 28 14 +7 15 2 45 29 15 +8 15 2 47 30 16 +9 1 2 28 1 4 17 +10 1 2 28 1 17 18 +11 1 2 28 1 18 19 +12 1 2 28 1 19 1 +13 1 2 38 4 3 25 +14 1 2 38 4 25 4 +15 1 2 38 5 6 3 +16 1 2 36 6 1 26 +17 1 2 36 6 26 2 +18 1 2 36 7 2 27 +19 1 2 36 7 27 5 +20 1 2 29 12 7 28 +21 1 2 29 12 28 29 +22 1 2 29 12 29 30 +23 1 2 29 12 30 8 +24 1 2 37 13 8 31 +25 1 2 37 13 31 9 +26 1 2 39 15 10 35 +27 1 2 39 15 35 7 +28 1 2 30 17 4 36 +29 1 2 30 17 36 37 +30 1 2 30 17 37 7 +31 1 2 31 18 1 38 +32 1 2 31 18 38 39 +33 1 2 31 18 39 8 +34 1 2 37 35 9 44 +35 1 2 37 35 44 11 +36 1 2 39 37 12 10 +37 1 2 36 49 5 51 +38 1 2 36 49 51 13 +39 1 2 37 50 11 52 +40 1 2 37 50 52 15 +41 1 2 35 51 13 53 +42 1 2 35 51 53 15 +43 1 2 33 52 15 54 +44 1 2 33 52 54 16 +45 1 2 32 53 13 55 +46 1 2 32 53 55 14 +47 1 2 38 54 14 56 +48 1 2 38 54 56 6 +49 1 2 39 55 12 57 +50 1 2 39 55 57 16 +51 1 2 34 56 14 58 +52 1 2 34 56 58 16 +53 2 2 25 2 20 2 27 +54 2 2 25 2 23 27 5 +55 2 2 25 2 64 23 24 +56 2 2 25 2 22 65 3 +57 2 2 25 2 23 64 66 +58 2 2 25 2 65 6 3 +59 2 2 25 2 64 21 66 +60 2 2 25 2 65 24 6 +61 2 2 25 2 24 65 64 +62 2 2 25 2 65 22 64 +63 2 2 25 2 66 20 27 +64 2 2 25 2 21 64 22 +65 2 2 25 2 20 66 21 +66 2 2 25 2 23 66 27 +67 2 2 24 54 32 9 44 +68 2 2 24 54 45 44 11 +69 2 2 24 54 94 45 46 +70 2 2 24 54 34 95 10 +71 2 2 24 54 45 94 96 +72 2 2 24 54 95 12 10 +73 2 2 24 54 94 33 96 +74 2 2 24 54 95 46 12 +75 2 2 24 54 46 95 94 +76 2 2 24 54 95 34 94 +77 2 2 24 54 96 32 44 +78 2 2 24 54 33 94 34 +79 2 2 24 54 32 96 33 +80 2 2 24 54 45 96 44 +81 2 2 27 55 51 5 47 +82 2 2 27 55 48 11 52 +83 2 2 27 55 51 97 13 +84 2 2 27 55 97 53 13 +85 2 2 27 55 97 52 15 +86 2 2 27 55 15 53 97 +87 2 2 27 55 97 47 48 +88 2 2 27 55 47 97 51 +89 2 2 27 55 48 52 97 +90 2 2 23 56 53 99 13 +91 2 2 23 56 99 55 13 +92 2 2 23 56 55 98 14 +93 2 2 23 56 98 58 14 +94 2 2 23 56 99 53 15 +95 2 2 23 56 54 99 15 +96 2 2 23 56 100 54 16 +97 2 2 23 56 58 100 16 +98 2 2 23 56 100 99 54 +99 2 2 23 56 55 99 98 +100 2 2 23 56 100 58 98 +101 2 2 23 56 98 99 100 +102 2 2 24 57 45 101 11 +103 2 2 24 57 101 52 11 +104 2 2 24 57 46 12 57 +105 2 2 24 57 52 101 15 +106 2 2 24 57 101 54 15 +107 2 2 24 57 54 102 16 +108 2 2 24 57 102 57 16 +109 2 2 24 57 46 102 45 +110 2 2 24 57 101 45 102 +111 2 2 24 57 102 46 57 +112 2 2 24 57 102 54 101 +113 2 2 25 58 23 103 5 +114 2 2 25 58 103 51 5 +115 2 2 25 58 24 6 56 +116 2 2 25 58 51 103 13 +117 2 2 25 58 103 55 13 +118 2 2 25 58 55 104 14 +119 2 2 25 58 104 56 14 +120 2 2 25 58 24 104 23 +121 2 2 25 58 103 23 104 +122 2 2 25 58 104 24 56 +123 2 2 25 58 104 55 103 +124 2 2 26 59 6 49 56 +125 2 2 26 59 50 12 57 +126 2 2 26 59 56 105 14 +127 2 2 26 59 105 58 14 +128 2 2 26 59 105 57 16 +129 2 2 26 59 16 58 105 +130 2 2 26 59 105 49 50 +131 2 2 26 59 49 105 56 +132 2 2 26 59 50 57 105 +133 3 2 25 1 59 60 21 22 +134 3 2 25 1 22 3 25 59 +135 3 2 25 1 18 62 59 17 +136 3 2 25 1 25 4 17 59 +137 3 2 25 1 62 63 26 61 +138 3 2 25 1 60 61 20 21 +139 3 2 25 1 62 18 19 63 +140 3 2 25 1 26 2 20 61 +141 3 2 25 1 61 60 59 62 +142 3 2 25 1 19 1 26 63 +143 3 2 22 19 4 17 67 36 +144 3 2 22 19 36 67 68 37 +145 3 2 22 19 37 68 28 7 +146 3 2 22 19 17 18 69 67 +147 3 2 22 19 67 69 70 68 +148 3 2 22 19 68 70 29 28 +149 3 2 22 19 18 19 71 69 +150 3 2 22 19 69 71 72 70 +151 3 2 22 19 70 72 30 29 +152 3 2 22 19 19 1 38 71 +153 3 2 22 19 71 38 39 72 +154 3 2 22 19 72 39 8 30 +155 3 2 27 23 1 26 73 38 +156 3 2 27 23 38 73 74 39 +157 3 2 27 23 39 74 31 8 +158 3 2 27 23 26 2 40 73 +159 3 2 27 23 73 40 41 74 +160 3 2 27 23 74 41 9 31 +161 3 2 26 31 3 25 81 42 +162 3 2 26 31 42 81 82 43 +163 3 2 26 31 43 82 35 10 +164 3 2 26 31 25 4 36 81 +165 3 2 26 31 81 36 37 82 +166 3 2 26 31 82 37 7 35 +167 3 2 24 32 83 84 33 34 +168 3 2 24 32 34 10 35 83 +169 3 2 24 32 29 86 83 28 +170 3 2 24 32 35 7 28 83 +171 3 2 24 32 86 87 31 85 +172 3 2 24 32 84 85 32 33 +173 3 2 24 32 86 29 30 87 +174 3 2 24 32 31 9 32 85 +175 3 2 24 32 85 84 83 86 +176 3 2 24 32 30 8 31 87 +177 3 2 27 45 2 27 88 40 +178 3 2 27 45 40 88 89 41 +179 3 2 27 45 41 89 44 9 +180 3 2 27 45 27 5 47 88 +181 3 2 27 45 88 47 48 89 +182 3 2 27 45 89 48 11 44 +183 3 2 26 53 6 3 42 49 +184 3 2 26 53 49 42 43 50 +185 3 2 26 53 50 43 10 12 +186 4 2 54 3 90 103 127 122 +187 4 2 54 3 101 91 129 122 +188 4 2 54 3 103 90 124 122 +189 4 2 54 3 126 91 101 122 +190 4 2 54 3 92 104 130 123 +191 4 2 54 3 102 93 132 123 +192 4 2 54 3 129 45 91 101 +193 4 2 54 3 90 23 127 103 +194 4 2 54 3 45 126 91 101 +195 4 2 54 3 23 90 124 103 +196 4 2 54 3 92 127 104 123 +197 4 2 54 3 93 102 129 123 +198 4 2 54 3 125 90 91 122 +199 4 2 54 3 91 90 128 122 +200 4 2 54 3 104 127 103 122 +201 4 2 54 3 101 129 102 122 +202 4 2 54 3 127 122 104 123 +203 4 2 54 3 102 122 129 123 +204 4 2 54 3 103 124 97 122 +205 4 2 54 3 126 101 97 122 +206 4 2 54 3 132 57 102 123 +207 4 2 54 3 130 104 56 123 +208 4 2 54 3 46 93 132 102 +209 4 2 54 3 92 24 130 104 +210 4 2 54 3 129 93 46 102 +211 4 2 54 3 92 127 24 104 +212 4 2 54 3 102 100 54 122 +213 4 2 54 3 100 122 102 123 +214 4 2 54 3 54 101 102 122 +215 4 2 54 3 104 103 55 122 +216 4 2 54 3 51 103 124 97 +217 4 2 54 3 126 101 52 97 +218 4 2 54 3 105 130 56 123 +219 4 2 54 3 132 105 57 123 +220 4 2 54 3 98 104 55 122 +221 4 2 54 3 93 92 131 123 +222 4 2 54 3 93 128 92 123 +223 4 2 54 3 51 124 47 97 +224 4 2 54 3 52 48 126 97 +225 4 2 54 3 54 100 99 122 +226 4 2 54 3 104 122 98 123 +227 4 2 54 3 98 122 100 123 +228 4 2 54 3 54 99 101 122 +229 4 2 54 3 55 103 99 122 +230 4 2 54 3 49 130 56 105 +231 4 2 54 3 57 132 50 105 +232 4 2 54 3 55 99 98 122 +233 4 2 54 3 103 99 97 53 +234 4 2 54 3 101 15 97 53 +235 4 2 54 3 97 99 101 53 +236 4 2 54 3 105 100 102 123 +237 4 2 54 3 53 97 103 13 +238 4 2 54 3 103 97 99 122 +239 4 2 54 3 53 103 99 13 +240 4 2 54 3 15 101 99 53 +241 4 2 54 3 99 97 101 122 +242 4 2 54 3 105 104 98 123 +243 4 2 54 3 105 57 102 100 +244 4 2 54 3 98 105 56 104 +245 4 2 54 3 12 132 50 57 +246 4 2 54 3 56 6 130 49 +247 4 2 54 3 104 127 23 103 +248 4 2 54 3 129 45 101 102 +249 4 2 54 3 103 55 99 13 +250 4 2 54 3 15 99 101 54 +251 4 2 54 3 14 98 56 104 +252 4 2 54 3 52 101 15 97 +253 4 2 54 3 97 51 103 13 +254 4 2 54 3 105 56 104 123 +255 4 2 54 3 57 105 102 123 +256 4 2 54 3 56 105 98 14 +257 4 2 54 3 100 98 99 122 +258 4 2 54 3 57 12 132 46 +259 4 2 54 3 24 56 6 130 +260 4 2 54 3 105 16 57 100 +261 4 2 54 3 16 102 57 100 +262 4 2 54 3 126 11 48 52 +263 4 2 54 3 5 124 47 51 +264 4 2 54 3 58 98 105 14 +265 4 2 54 3 132 57 46 102 +266 4 2 54 3 24 56 130 104 +267 4 2 54 3 105 98 100 123 +268 4 2 54 3 100 105 16 58 +269 4 2 54 3 11 126 45 101 +270 4 2 54 3 23 124 5 103 +271 4 2 54 3 50 131 49 105 +272 4 2 54 3 45 129 46 102 +273 4 2 54 3 24 127 23 104 +274 4 2 54 3 54 102 16 100 +275 4 2 54 3 104 14 98 55 +276 4 2 54 3 124 5 103 51 +277 4 2 54 3 11 126 101 52 +278 4 2 54 3 105 100 98 58 +279 4 2 54 3 47 125 48 97 +280 4 2 54 3 93 128 129 91 +281 4 2 54 3 93 129 128 123 +282 4 2 54 3 122 129 128 91 +283 4 2 54 3 122 128 129 123 +284 4 2 54 3 122 128 127 90 +285 4 2 54 3 122 127 128 123 +286 4 2 54 3 92 127 128 90 +287 4 2 54 3 92 128 127 123 +288 4 2 54 3 91 125 126 48 +289 4 2 54 3 91 126 125 122 +290 4 2 54 3 97 126 125 48 +291 4 2 54 3 97 125 126 122 +292 4 2 54 3 97 125 124 47 +293 4 2 54 3 97 124 125 122 +294 4 2 54 3 90 124 125 47 +295 4 2 54 3 90 125 124 122 +296 4 2 54 3 105 131 132 50 +297 4 2 54 3 105 132 131 123 +298 4 2 54 3 93 132 131 50 +299 4 2 54 3 93 131 132 123 +300 4 2 54 3 92 131 130 49 +301 4 2 54 3 92 130 131 123 +302 4 2 54 3 105 130 131 49 +303 4 2 54 3 105 131 130 123 +304 5 2 52 1 21 22 59 60 77 79 106 108 +305 5 2 52 1 77 79 106 108 78 80 107 109 +306 5 2 52 1 78 80 107 109 33 34 83 84 +307 5 2 52 1 25 59 22 3 81 106 79 42 +308 5 2 52 1 81 106 79 42 82 107 80 43 +309 5 2 52 1 82 107 80 43 35 83 34 10 +310 5 2 52 1 59 17 18 62 106 67 69 112 +311 5 2 52 1 106 67 69 112 107 68 70 113 +312 5 2 52 1 107 68 70 113 83 28 29 86 +313 5 2 52 1 17 59 25 4 67 106 81 36 +314 5 2 52 1 67 106 81 36 68 107 82 37 +315 5 2 52 1 68 107 82 37 28 83 35 7 +316 5 2 52 1 26 61 62 63 73 110 112 114 +317 5 2 52 1 73 110 112 114 74 111 113 115 +318 5 2 52 1 74 111 113 115 31 85 86 87 +319 5 2 52 1 20 21 60 61 75 77 108 110 +320 5 2 52 1 75 77 108 110 76 78 109 111 +321 5 2 52 1 76 78 109 111 32 33 84 85 +322 5 2 52 1 19 63 62 18 71 114 112 69 +323 5 2 52 1 71 114 112 69 72 115 113 70 +324 5 2 52 1 72 115 113 70 30 87 86 29 +325 5 2 52 1 20 61 26 2 75 110 73 40 +326 5 2 52 1 75 110 73 40 76 111 74 41 +327 5 2 52 1 76 111 74 41 32 85 31 9 +328 5 2 52 1 59 62 61 60 106 112 110 108 +329 5 2 52 1 106 112 110 108 107 113 111 109 +330 5 2 52 1 107 113 111 109 83 86 85 84 +331 5 2 52 1 26 63 19 1 73 114 71 38 +332 5 2 52 1 73 114 71 38 74 115 72 39 +333 5 2 52 1 74 115 72 39 31 87 30 8 +334 6 2 53 2 27 20 2 88 75 40 +335 6 2 53 2 88 75 40 89 76 41 +336 6 2 53 2 89 76 41 44 32 9 +337 6 2 53 2 5 23 27 47 90 88 +338 6 2 53 2 47 90 88 48 91 89 +339 6 2 53 2 48 91 89 11 45 44 +340 6 2 53 2 24 64 23 92 116 90 +341 6 2 53 2 92 116 90 93 117 91 +342 6 2 53 2 93 117 91 46 94 45 +343 6 2 53 2 3 22 65 42 79 118 +344 6 2 53 2 42 79 118 43 80 119 +345 6 2 53 2 43 80 119 10 34 95 +346 6 2 53 2 66 23 64 120 90 116 +347 6 2 53 2 120 90 116 121 91 117 +348 6 2 53 2 121 91 117 96 45 94 +349 6 2 53 2 3 65 6 42 118 49 +350 6 2 53 2 42 118 49 43 119 50 +351 6 2 53 2 43 119 50 10 95 12 +352 6 2 53 2 66 64 21 120 116 77 +353 6 2 53 2 120 116 77 121 117 78 +354 6 2 53 2 121 117 78 96 94 33 +355 6 2 53 2 6 65 24 49 118 92 +356 6 2 53 2 49 118 92 50 119 93 +357 6 2 53 2 50 119 93 12 95 46 +358 6 2 53 2 64 24 65 116 92 118 +359 6 2 53 2 116 92 118 117 93 119 +360 6 2 53 2 117 93 119 94 46 95 +361 6 2 53 2 64 65 22 116 118 79 +362 6 2 53 2 116 118 79 117 119 80 +363 6 2 53 2 117 119 80 94 95 34 +364 6 2 53 2 27 66 20 88 120 75 +365 6 2 53 2 88 120 75 89 121 76 +366 6 2 53 2 89 121 76 44 96 32 +367 6 2 53 2 22 21 64 79 77 116 +368 6 2 53 2 79 77 116 80 78 117 +369 6 2 53 2 80 78 117 34 33 94 +370 6 2 53 2 21 20 66 77 75 120 +371 6 2 53 2 77 75 120 78 76 121 +372 6 2 53 2 78 76 121 33 32 96 +373 6 2 53 2 27 23 66 88 90 120 +374 6 2 53 2 88 90 120 89 91 121 +375 6 2 53 2 89 91 121 44 45 96 +376 7 2 54 3 5 23 90 47 124 +377 7 2 54 3 47 90 91 48 125 +378 7 2 54 3 48 91 45 11 126 +379 7 2 54 3 23 24 92 90 127 +380 7 2 54 3 90 92 93 91 128 +381 7 2 54 3 91 93 46 45 129 +382 7 2 54 3 24 6 49 92 130 +383 7 2 54 3 92 49 50 93 131 +384 7 2 54 3 93 50 12 46 132 +$EndElements +$Periodic +9 +0 7 4 +1 +7 4 +0 8 1 +1 +8 1 +1 12 1 +3 +28 17 +29 18 +30 19 +1 13 6 +1 +31 26 +1 15 4 +1 +35 25 +1 35 7 +1 +44 27 +1 37 5 +0 +2 32 1 +5 +86 62 +87 63 +83 59 +84 60 +85 61 +2 54 2 +3 +94 64 +95 65 +96 66 +$EndPeriodic +)"; + } + return std::dynamic_pointer_cast<const Mesh<Connectivity<3>>>(GmshReader{filename}.mesh()); +} diff --git a/tests/MeshDataBaseForTests.hpp b/tests/MeshDataBaseForTests.hpp index 589ec9b82f9be6451afd496aab3399c13bb3d718..79f3379f0cbfd51416594aa6015d66aa0b9f861c 100644 --- a/tests/MeshDataBaseForTests.hpp +++ b/tests/MeshDataBaseForTests.hpp @@ -9,10 +9,38 @@ class Connectivity; template <typename ConnectivityT> class Mesh; +#include <array> #include <memory> +#include <string> class MeshDataBaseForTests { + public: + template <size_t Dimension> + class NamedMesh + { + private: + const std::string m_name; + const std::shared_ptr<const Mesh<Connectivity<Dimension>>> m_mesh; + + public: + NamedMesh(const std::string& name, const std::shared_ptr<const Mesh<Connectivity<Dimension>>>& mesh) + : m_name(name), m_mesh(mesh) + {} + + const std::string& + name() const + { + return m_name; + } + + auto + mesh() const + { + return m_mesh; + } + }; + private: explicit MeshDataBaseForTests(); @@ -22,12 +50,47 @@ class MeshDataBaseForTests std::shared_ptr<const Mesh<Connectivity<2>>> m_cartesian_2d_mesh; std::shared_ptr<const Mesh<Connectivity<3>>> m_cartesian_3d_mesh; + std::shared_ptr<const Mesh<Connectivity<1>>> m_unordered_1d_mesh; + std::shared_ptr<const Mesh<Connectivity<2>>> m_hybrid_2d_mesh; + std::shared_ptr<const Mesh<Connectivity<3>>> m_hybrid_3d_mesh; + + std::shared_ptr<const Mesh<Connectivity<1>>> _buildUnordered1dMesh(); + std::shared_ptr<const Mesh<Connectivity<2>>> _buildHybrid2dMesh(); + std::shared_ptr<const Mesh<Connectivity<3>>> _buildHybrid3dMesh(); + public: - std::shared_ptr<const Mesh<Connectivity<1>>> cartesianMesh1D() const; - std::shared_ptr<const Mesh<Connectivity<2>>> cartesianMesh2D() const; - std::shared_ptr<const Mesh<Connectivity<3>>> cartesianMesh3D() const; + std::shared_ptr<const Mesh<Connectivity<1>>> cartesian1DMesh() const; + std::shared_ptr<const Mesh<Connectivity<1>>> unordered1DMesh() const; + + std::shared_ptr<const Mesh<Connectivity<2>>> cartesian2DMesh() const; + std::shared_ptr<const Mesh<Connectivity<2>>> hybrid2DMesh() const; + + std::shared_ptr<const Mesh<Connectivity<3>>> cartesian3DMesh() const; + std::shared_ptr<const Mesh<Connectivity<3>>> hybrid3DMesh() const; static const MeshDataBaseForTests& get(); + + auto + all1DMeshes() const + { + return std::array{NamedMesh{"cartesian 1d mesh", cartesian1DMesh()}, // + NamedMesh{"unordered 1d mesh", unordered1DMesh()}}; + } + + auto + all2DMeshes() const + { + return std::array{NamedMesh{"cartesian 2d mesh", cartesian2DMesh()}, // + NamedMesh{"hybrid 2d mesh", hybrid2DMesh()}}; + } + + auto + all3DMeshes() const + { + return std::array{NamedMesh{"cartesian 3d mesh", cartesian3DMesh()}, // + NamedMesh{std::string("hybrid 3d mesh"), hybrid3DMesh()}}; + } + static void create(); static void destroy(); diff --git a/tests/mpi_test_main.cpp b/tests/mpi_test_main.cpp index 4c94634173799a17519b5d417bfc914a99e2e740..95b26e0a4964472335139a7afc0cdbf8205ff61f 100644 --- a/tests/mpi_test_main.cpp +++ b/tests/mpi_test_main.cpp @@ -2,6 +2,7 @@ #include <Kokkos_Core.hpp> +#include <analysis/QuadratureManager.hpp> #include <language/utils/OperatorRepository.hpp> #include <mesh/DiamondDualConnectivityManager.hpp> #include <mesh/DiamondDualMeshManager.hpp> @@ -27,7 +28,7 @@ main(int argc, char* argv[]) const std::string output_base_name{"mpi_test_rank_"}; - std::filesystem::path parallel_output(std::string{PUGS_BINARY_DIR}); + std::filesystem::path parallel_output = std::filesystem::path{PUGS_BINARY_DIR}.append("tests"); std::filesystem::path gcov_prefix = [&]() -> std::filesystem::path { std::string template_temp_dir = std::filesystem::temp_directory_path() / "pugs_gcov_XXXXXX"; @@ -59,6 +60,7 @@ main(int argc, char* argv[]) SynchronizerManager::create(); RandomEngine::create(); + QuadratureManager::create(); MeshDataManager::create(); DiamondDualConnectivityManager::create(); DiamondDualMeshManager::create(); @@ -71,7 +73,7 @@ main(int argc, char* argv[]) << rang::style::reset << '\n'; for (size_t i_rank = 1; i_rank < parallel::size(); ++i_rank) { - std::filesystem::path parallel_output(std::string{PUGS_BINARY_DIR}); + std::filesystem::path parallel_output = std::filesystem::path{PUGS_BINARY_DIR}.append("tests"); parallel_output /= output_base_name + std::to_string(i_rank); session.config().stream() << " - " << rang::fg::green << parallel_output.parent_path().string() << parallel_output.preferred_separator << rang::style::reset << rang::fgB::green @@ -91,6 +93,7 @@ main(int argc, char* argv[]) DiamondDualMeshManager::destroy(); DiamondDualConnectivityManager::destroy(); MeshDataManager::destroy(); + QuadratureManager::destroy(); RandomEngine::destroy(); SynchronizerManager::destroy(); } diff --git a/tests/test_Array.cpp b/tests/test_Array.cpp index 5b9889f396f6413b4c704e48ffa1497bf6edb8fe..d6382d60699c670033a4ae64cd5970f6dcb86c21 100644 --- a/tests/test_Array.cpp +++ b/tests/test_Array.cpp @@ -1,6 +1,8 @@ #include <catch2/catch_test_macros.hpp> #include <catch2/matchers/catch_matchers_all.hpp> +#include <algebra/TinyMatrix.hpp> +#include <algebra/TinyVector.hpp> #include <utils/Array.hpp> #include <utils/PugsAssert.hpp> #include <utils/Types.hpp> @@ -251,6 +253,72 @@ TEST_CASE("Array", "[utils]") REQUIRE(array_ost.str() == ref_ost.str()); } + SECTION("checking for Array reductions") + { + Array<int> a(10); + a[0] = 13; + a[1] = 1; + a[2] = 8; + a[3] = -3; + a[4] = 23; + a[5] = -1; + a[6] = 13; + a[7] = 0; + a[8] = 12; + a[9] = 9; + + SECTION("Min") + { + REQUIRE(min(a) == -3); + } + + SECTION("Max") + { + REQUIRE(max(a) == 23); + } + + SECTION("Sum") + { + REQUIRE((sum(a) == 75)); + } + + SECTION("TinyVector Sum") + { + using N2 = TinyVector<2, int>; + Array<N2> b(10); + b[0] = {13, 2}; + b[1] = {1, 3}; + b[2] = {8, -2}; + b[3] = {-3, 2}; + b[4] = {23, 4}; + b[5] = {-1, -3}; + b[6] = {13, 17}; + b[7] = {0, 9}; + b[8] = {12, 13}; + b[9] = {9, -17}; + + REQUIRE((sum(b) == N2{75, 28})); + } + + SECTION("TinyMatrix Sum") + { + using N22 = TinyMatrix<2, 2, int>; + Array<N22> b(10); + b[0] = {13, 2, 0, 1}; + b[1] = {1, 3, 6, 3}; + b[2] = {8, -2, -1, 21}; + b[3] = {-3, 2, 5, 12}; + b[4] = {23, 4, 7, 1}; + b[5] = {-1, -3, 33, 11}; + b[6] = {13, 17, 12, 13}; + b[7] = {0, 9, 1, 14}; + b[8] = {12, 13, -3, -71}; + b[9] = {9, -17, 0, 16}; + + REQUIRE((sum(b) == N22{75, 28, 60, 21})); + } + } + #ifndef NDEBUG SECTION("output with signaling NaN") diff --git a/tests/test_ArrayUtils.cpp b/tests/test_ArrayUtils.cpp deleted file mode 100644 index eb976b40df67c640bbe1a376671706835ca4c2e0..0000000000000000000000000000000000000000 --- a/tests/test_ArrayUtils.cpp +++ /dev/null @@ -1,83 +0,0 @@ -#include <catch2/catch_test_macros.hpp> -#include <catch2/matchers/catch_matchers_all.hpp> - -#include <utils/Array.hpp> -#include <utils/ArrayUtils.hpp> -#include <utils/PugsAssert.hpp> - -#include <algebra/TinyMatrix.hpp> -#include <algebra/TinyVector.hpp> - -// clazy:excludeall=non-pod-global-static - -// Instantiate to ensure full coverage is performed -template class Array<int>; - -TEST_CASE("ArrayUtils", "[utils]") -{ - SECTION("checking for Array reductions") - { - Array<int> a(10); - a[0] = 13; - a[1] = 1; - a[2] = 8; - a[3] = -3; - a[4] = 23; - a[5] = -1; - a[6] = 13; - a[7] = 0; - a[8] = 12; - a[9] = 9; - - SECTION("Min") - { - REQUIRE((min(a) == -3)); - } - - SECTION("Max") - { - REQUIRE((max(a) == 23)); - } - - SECTION("Sum") - { - REQUIRE((sum(a) == 75)); - } - - SECTION("TinyVector Sum") - { - using N2 = TinyVector<2, int>; - Array<N2> b(10); - b[0] = {13, 2}; - b[1] = {1, 3}; - b[2] = {8, -2}; - b[3] = {-3, 2}; - b[4] = {23, 4}; - b[5] = {-1, -3}; - b[6] = {13, 17}; - b[7] = {0, 9}; - b[8] = {12, 13}; - b[9] = {9, -17}; - - REQUIRE((sum(b) == N2{75, 28})); - } - - SECTION("TinyMatrix Sum") - { - using N22 = TinyMatrix<2, 2, int>; - Array<N22> b(10); - b[0] = {13, 2, 0, 1}; - b[1] = {1, 3, 6, 3}; - b[2] = {8, -2, -1, 21}; - b[3] = {-3, 2, 5, 12}; - b[4] = {23, 4, 7, 1}; - b[5] = {-1, -3, 33, 11}; - b[6] = {13, 17, 12, 13}; - b[7] = {0, 9, 1, 14}; - b[8] = {12, 13, -3, -71}; - b[9] = {9, -17, 0, 16}; - - REQUIRE((sum(b) == N22{75, 28, 60, 21})); - } - } -} diff --git a/tests/test_BinaryExpressionProcessor_raw.cpp b/tests/test_BinaryExpressionProcessor_raw.cpp index c115c67ca070c0610e5225c022fc527e4cff8a1a..22e32de89c715a5fa8e24a38007e0ab792e9dd19 100644 --- a/tests/test_BinaryExpressionProcessor_raw.cpp +++ b/tests/test_BinaryExpressionProcessor_raw.cpp @@ -3,6 +3,7 @@ #include <language/node_processor/BinaryExpressionProcessor.hpp> #include <language/utils/OFStream.hpp> +#include <utils/pugs_config.hpp> // clazy:excludeall=non-pod-global-static @@ -51,8 +52,8 @@ TEST_CASE("BinaryExpressionProcessor raw operators", "[language]") REQUIRE(BinOp<language::divide_op>{}.eval(2.9, 3) == (2.9 / 3)); { - std::filesystem::path path = std::filesystem::temp_directory_path(); - path.append(std::string{"binary_expression_processor_shift_left_"} + std::to_string(getpid())); + std::filesystem::path path{PUGS_BINARY_DIR}; + path.append("tests").append(std::string{"binary_expression_processor_shift_left_"} + std::to_string(getpid())); std::string filename = path.string(); diff --git a/tests/test_BinaryExpressionProcessor_shift.cpp b/tests/test_BinaryExpressionProcessor_shift.cpp index 082d5fc5e829e11ac14e700e226f07278fca13c8..2f89f1f61c45ddcc137434d28f3196201c1ce866 100644 --- a/tests/test_BinaryExpressionProcessor_shift.cpp +++ b/tests/test_BinaryExpressionProcessor_shift.cpp @@ -2,6 +2,7 @@ #include <catch2/matchers/catch_matchers_all.hpp> #include <test_BinaryExpressionProcessor_utils.hpp> +#include <utils/pugs_config.hpp> #include <fstream> #include <unistd.h> @@ -12,9 +13,8 @@ TEST_CASE("BinaryExpressionProcessor shift", "[language]") { SECTION("<<") { - std::filesystem::path path = std::filesystem::temp_directory_path(); - - path.append(std::string{"binary_expression_processor_"} + std::to_string(getpid())); + std::filesystem::path path{PUGS_BINARY_DIR}; + path.append("tests").append(std::string{"binary_expression_processor_"} + std::to_string(getpid())); std::string filename = path.string(); diff --git a/tests/test_CastArray.cpp b/tests/test_CastArray.cpp index d1c9cad2c1f7d2d39dad4e8fba8764d9b0bd6c2c..0f4a841f1e6bfc270fe789947efeafdccff40ff7 100644 --- a/tests/test_CastArray.cpp +++ b/tests/test_CastArray.cpp @@ -1,7 +1,6 @@ #include <catch2/catch_test_macros.hpp> #include <catch2/matchers/catch_matchers_all.hpp> -#include <utils/ArrayUtils.hpp> #include <utils/CastArray.hpp> // clazy:excludeall=non-pod-global-static diff --git a/tests/test_CellIntegrator.cpp b/tests/test_CellIntegrator.cpp new file mode 100644 index 0000000000000000000000000000000000000000..97bf0b98fa9beaace5bea6bf427b69dbe75548fc --- /dev/null +++ b/tests/test_CellIntegrator.cpp @@ -0,0 +1,934 @@ +#include <catch2/catch_approx.hpp> +#include <catch2/catch_test_macros.hpp> + +#include <analysis/GaussLegendreQuadratureDescriptor.hpp> +#include <analysis/GaussLobattoQuadratureDescriptor.hpp> +#include <analysis/GaussQuadratureDescriptor.hpp> +#include <mesh/DiamondDualMeshManager.hpp> +#include <mesh/ItemValue.hpp> +#include <mesh/Mesh.hpp> +#include <scheme/CellIntegrator.hpp> + +#include <MeshDataBaseForTests.hpp> + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("CellIntegrator", "[scheme]") +{ + SECTION("1D") + { + using R1 = TinyVector<1>; + + const auto mesh = MeshDataBaseForTests::get().unordered1DMesh(); + auto f = [](const R1& x) -> double { return x[0] * x[0] + 1; }; + + Array<const double> int_f_per_cell = [=] { + Array<double> int_f(mesh->numberOfCells()); + auto cell_to_node_matrix = mesh->connectivity().cellToNodeMatrix(); + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { + auto cell_node_list = cell_to_node_matrix[cell_id]; + auto xr = mesh->xr(); + const double x_left = xr[cell_node_list[0]][0]; + const double x_right = xr[cell_node_list[1]][0]; + int_f[cell_id] = 1. / 3 * (x_right * x_right * x_right - x_left * x_left * x_left) + x_right - x_left; + }); + + return int_f; + }(); + + SECTION("direct formula") + { + SECTION("all cells") + { + SECTION("CellValue") + { + CellValue<double> values(mesh->connectivity()); + CellIntegrator::integrateTo([=](const R1 x) { return f(x); }, GaussQuadratureDescriptor(2), *mesh, values); + + double error = 0; + for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++cell_id) { + error += std::abs(int_f_per_cell[cell_id] - values[cell_id]); + } + + REQUIRE(error == Catch::Approx(0).margin(1E-10)); + } + + SECTION("Array") + { + Array<double> values(mesh->numberOfCells()); + + CellIntegrator::integrateTo(f, GaussQuadratureDescriptor(2), *mesh, values); + + double error = 0; + for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++cell_id) { + error += std::abs(int_f_per_cell[cell_id] - values[cell_id]); + } + + REQUIRE(error == Catch::Approx(0).margin(1E-10)); + } + + SECTION("SmallArray") + { + SmallArray<double> values(mesh->numberOfCells()); + CellIntegrator::integrateTo(f, GaussQuadratureDescriptor(2), *mesh, values); + + double error = 0; + for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++cell_id) { + error += std::abs(int_f_per_cell[cell_id] - values[cell_id]); + } + + REQUIRE(error == Catch::Approx(0).margin(1E-10)); + } + } + + SECTION("cell list") + { + SECTION("Array") + { + Array<CellId> cell_list{mesh->numberOfCells() / 2 + mesh->numberOfCells() % 2}; + + { + size_t k = 0; + for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++(++cell_id), ++k) { + cell_list[k] = cell_id; + } + + REQUIRE(k == cell_list.size()); + } + + Array<double> values = CellIntegrator::integrate(f, GaussQuadratureDescriptor(2), *mesh, cell_list); + + double error = 0; + for (size_t i = 0; i < cell_list.size(); ++i) { + error += std::abs(int_f_per_cell[cell_list[i]] - values[i]); + } + + REQUIRE(error == Catch::Approx(0).margin(1E-10)); + } + + SECTION("SmallArray") + { + SmallArray<CellId> cell_list{mesh->numberOfCells() / 2 + mesh->numberOfCells() % 2}; + + { + size_t k = 0; + for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++(++cell_id), ++k) { + cell_list[k] = cell_id; + } + + REQUIRE(k == cell_list.size()); + } + + SmallArray<double> values = CellIntegrator::integrate(f, GaussQuadratureDescriptor(2), *mesh, cell_list); + + double error = 0; + for (size_t i = 0; i < cell_list.size(); ++i) { + error += std::abs(int_f_per_cell[cell_list[i]] - values[i]); + } + + REQUIRE(error == Catch::Approx(0).margin(1E-10)); + } + } + } + + SECTION("tensorial formula") + { + SECTION("all cells") + { + SECTION("CellValue") + { + CellValue<double> values(mesh->connectivity()); + CellIntegrator::integrateTo([=](const R1 x) { return f(x); }, GaussLobattoQuadratureDescriptor(2), *mesh, + values); + + double error = 0; + for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++cell_id) { + error += std::abs(int_f_per_cell[cell_id] - values[cell_id]); + } + + REQUIRE(error == Catch::Approx(0).margin(1E-10)); + } + + SECTION("Array") + { + Array<double> values(mesh->numberOfCells()); + + CellIntegrator::integrateTo(f, GaussLobattoQuadratureDescriptor(2), *mesh, values); + + double error = 0; + for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++cell_id) { + error += std::abs(int_f_per_cell[cell_id] - values[cell_id]); + } + + REQUIRE(error == Catch::Approx(0).margin(1E-10)); + } + + SECTION("SmallArray") + { + SmallArray<double> values(mesh->numberOfCells()); + CellIntegrator::integrateTo(f, GaussLobattoQuadratureDescriptor(2), *mesh, values); + + double error = 0; + for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++cell_id) { + error += std::abs(int_f_per_cell[cell_id] - values[cell_id]); + } + + REQUIRE(error == Catch::Approx(0).margin(1E-10)); + } + } + + SECTION("cell list") + { + SECTION("Array") + { + Array<CellId> cell_list{mesh->numberOfCells() / 2 + mesh->numberOfCells() % 2}; + + { + size_t k = 0; + for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++(++cell_id), ++k) { + cell_list[k] = cell_id; + } + + REQUIRE(k == cell_list.size()); + } + + Array<double> values = CellIntegrator::integrate(f, GaussLobattoQuadratureDescriptor(2), *mesh, cell_list); + + double error = 0; + for (size_t i = 0; i < cell_list.size(); ++i) { + error += std::abs(int_f_per_cell[cell_list[i]] - values[i]); + } + + REQUIRE(error == Catch::Approx(0).margin(1E-10)); + } + + SECTION("SmallArray") + { + SmallArray<CellId> cell_list{mesh->numberOfCells() / 2 + mesh->numberOfCells() % 2}; + + { + size_t k = 0; + for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++(++cell_id), ++k) { + cell_list[k] = cell_id; + } + + REQUIRE(k == cell_list.size()); + } + + SmallArray<double> values = + CellIntegrator::integrate(f, GaussLobattoQuadratureDescriptor(2), *mesh, cell_list); + + double error = 0; + for (size_t i = 0; i < cell_list.size(); ++i) { + error += std::abs(int_f_per_cell[cell_list[i]] - values[i]); + } + + REQUIRE(error == Catch::Approx(0).margin(1E-10)); + } + } + } + } + + SECTION("2D") + { + using R2 = TinyVector<2>; + + const auto mesh = MeshDataBaseForTests::get().hybrid2DMesh(); + + auto f = [](const R2& X) -> double { + const double x = X[0]; + const double y = X[1]; + return x * x + 2 * x * y + 3 * y * y + 2; + }; + + Array<const double> int_f_per_cell = [=] { + Array<double> int_f(mesh->numberOfCells()); + auto cell_to_node_matrix = mesh->connectivity().cellToNodeMatrix(); + auto cell_type = mesh->connectivity().cellType(); + + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { + auto cell_node_list = cell_to_node_matrix[cell_id]; + auto xr = mesh->xr(); + double integral = 0; + + switch (cell_type[cell_id]) { + case CellType::Triangle: { + TriangleTransformation<2> T(xr[cell_node_list[0]], xr[cell_node_list[1]], xr[cell_node_list[2]]); + auto qf = QuadratureManager::instance().getTriangleFormula(GaussQuadratureDescriptor(4)); + + for (size_t i = 0; i < qf.numberOfPoints(); ++i) { + const auto& xi = qf.point(i); + integral += qf.weight(i) * T.jacobianDeterminant() * f(T(xi)); + } + break; + } + case CellType::Quadrangle: { + SquareTransformation<2> T(xr[cell_node_list[0]], xr[cell_node_list[1]], xr[cell_node_list[2]], + xr[cell_node_list[3]]); + auto qf = QuadratureManager::instance().getSquareFormula(GaussQuadratureDescriptor(4)); + + for (size_t i = 0; i < qf.numberOfPoints(); ++i) { + const auto& xi = qf.point(i); + integral += qf.weight(i) * T.jacobianDeterminant(xi) * f(T(xi)); + } + break; + } + default: { + throw UnexpectedError("invalid cell type in 2d"); + } + } + int_f[cell_id] = integral; + }); + + return int_f; + }(); + + SECTION("direct formula") + { + SECTION("all cells") + { + SECTION("CellValue") + { + CellValue<double> values(mesh->connectivity()); + CellIntegrator::integrateTo([=](const R2 x) { return f(x); }, GaussQuadratureDescriptor(2), *mesh, values); + + double error = 0; + for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++cell_id) { + error += std::abs(int_f_per_cell[cell_id] - values[cell_id]); + } + + REQUIRE(error == Catch::Approx(0).margin(1E-10)); + } + + SECTION("Array") + { + Array<double> values(mesh->numberOfCells()); + + CellIntegrator::integrateTo(f, GaussQuadratureDescriptor(2), *mesh, values); + + double error = 0; + for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++cell_id) { + error += std::abs(int_f_per_cell[cell_id] - values[cell_id]); + } + + REQUIRE(error == Catch::Approx(0).margin(1E-10)); + } + + SECTION("SmallArray") + { + SmallArray<double> values(mesh->numberOfCells()); + CellIntegrator::integrateTo(f, GaussQuadratureDescriptor(2), *mesh, values); + + double error = 0; + for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++cell_id) { + error += std::abs(int_f_per_cell[cell_id] - values[cell_id]); + } + + REQUIRE(error == Catch::Approx(0).margin(1E-10)); + } + } + + SECTION("cell list") + { + SECTION("Array") + { + Array<CellId> cell_list{mesh->numberOfCells() / 2 + mesh->numberOfCells() % 2}; + + { + size_t k = 0; + for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++(++cell_id), ++k) { + cell_list[k] = cell_id; + } + + REQUIRE(k == cell_list.size()); + } + + Array<double> values = CellIntegrator::integrate(f, GaussQuadratureDescriptor(2), *mesh, cell_list); + + double error = 0; + for (size_t i = 0; i < cell_list.size(); ++i) { + error += std::abs(int_f_per_cell[cell_list[i]] - values[i]); + } + + REQUIRE(error == Catch::Approx(0).margin(1E-10)); + } + + SECTION("SmallArray") + { + SmallArray<CellId> cell_list{mesh->numberOfCells() / 2 + mesh->numberOfCells() % 2}; + + { + size_t k = 0; + for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++(++cell_id), ++k) { + cell_list[k] = cell_id; + } + + REQUIRE(k == cell_list.size()); + } + + SmallArray<double> values = CellIntegrator::integrate(f, GaussQuadratureDescriptor(2), *mesh, cell_list); + + double error = 0; + for (size_t i = 0; i < cell_list.size(); ++i) { + error += std::abs(int_f_per_cell[cell_list[i]] - values[i]); + } + + REQUIRE(error == Catch::Approx(0).margin(1E-10)); + } + } + } + + SECTION("tensorial formula") + { + SECTION("all cells") + { + SECTION("CellValue") + { + CellValue<double> values(mesh->connectivity()); + CellIntegrator::integrateTo([=](const R2 x) { return f(x); }, GaussLobattoQuadratureDescriptor(2), *mesh, + values); + + double error = 0; + for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++cell_id) { + error += std::abs(int_f_per_cell[cell_id] - values[cell_id]); + } + + REQUIRE(error == Catch::Approx(0).margin(1E-10)); + } + + SECTION("Array") + { + Array<double> values(mesh->numberOfCells()); + + CellIntegrator::integrateTo(f, GaussLobattoQuadratureDescriptor(2), *mesh, values); + + double error = 0; + for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++cell_id) { + error += std::abs(int_f_per_cell[cell_id] - values[cell_id]); + } + + REQUIRE(error == Catch::Approx(0).margin(1E-10)); + } + + SECTION("SmallArray") + { + SmallArray<double> values(mesh->numberOfCells()); + CellIntegrator::integrateTo(f, GaussLobattoQuadratureDescriptor(2), *mesh, values); + + double error = 0; + for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++cell_id) { + error += std::abs(int_f_per_cell[cell_id] - values[cell_id]); + } + + REQUIRE(error == Catch::Approx(0).margin(1E-10)); + } + } + + SECTION("cell list") + { + SECTION("Array") + { + Array<CellId> cell_list{mesh->numberOfCells() / 2 + mesh->numberOfCells() % 2}; + + { + size_t k = 0; + for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++(++cell_id), ++k) { + cell_list[k] = cell_id; + } + + REQUIRE(k == cell_list.size()); + } + + Array<double> values = CellIntegrator::integrate(f, GaussLobattoQuadratureDescriptor(2), *mesh, cell_list); + + double error = 0; + for (size_t i = 0; i < cell_list.size(); ++i) { + error += std::abs(int_f_per_cell[cell_list[i]] - values[i]); + } + + REQUIRE(error == Catch::Approx(0).margin(1E-10)); + } + + SECTION("SmallArray") + { + SmallArray<CellId> cell_list{mesh->numberOfCells() / 2 + mesh->numberOfCells() % 2}; + + { + size_t k = 0; + for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++(++cell_id), ++k) { + cell_list[k] = cell_id; + } + + REQUIRE(k == cell_list.size()); + } + + SmallArray<double> values = + CellIntegrator::integrate(f, GaussLobattoQuadratureDescriptor(2), *mesh, cell_list); + + double error = 0; + for (size_t i = 0; i < cell_list.size(); ++i) { + error += std::abs(int_f_per_cell[cell_list[i]] - values[i]); + } + + REQUIRE(error == Catch::Approx(0).margin(1E-10)); + } + } + } + } + + SECTION("3D") + { + using R3 = TinyVector<3>; + + auto hybrid_mesh = MeshDataBaseForTests::get().hybrid3DMesh(); + + auto f = [](const R3& X) -> double { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return x * x + 2 * x * y + 3 * y * y + 2 * z * z - z + 1; + }; + + std::vector<std::pair<std::string, decltype(hybrid_mesh)>> mesh_list; + mesh_list.push_back(std::make_pair("hybrid mesh", hybrid_mesh)); + mesh_list.push_back( + std::make_pair("diamond mesh", DiamondDualMeshManager::instance().getDiamondDualMesh(hybrid_mesh))); + + for (auto mesh_info : mesh_list) { + auto mesh_name = mesh_info.first; + auto mesh = mesh_info.second; + + SECTION(mesh_name) + { + SECTION("direct formula") + { + Array<const double> int_f_per_cell = [=] { + Array<double> int_f(mesh->numberOfCells()); + auto cell_to_node_matrix = mesh->connectivity().cellToNodeMatrix(); + auto cell_type = mesh->connectivity().cellType(); + + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { + auto cell_node_list = cell_to_node_matrix[cell_id]; + auto xr = mesh->xr(); + double integral = 0; + + switch (cell_type[cell_id]) { + case CellType::Tetrahedron: { + TetrahedronTransformation T(xr[cell_node_list[0]], xr[cell_node_list[1]], xr[cell_node_list[2]], + xr[cell_node_list[3]]); + auto qf = QuadratureManager::instance().getTetrahedronFormula(GaussQuadratureDescriptor(4)); + + for (size_t i = 0; i < qf.numberOfPoints(); ++i) { + const auto& xi = qf.point(i); + integral += qf.weight(i) * T.jacobianDeterminant() * f(T(xi)); + } + break; + } + case CellType::Pyramid: { + PyramidTransformation T(xr[cell_node_list[0]], xr[cell_node_list[1]], xr[cell_node_list[2]], + xr[cell_node_list[3]], xr[cell_node_list[4]]); + auto qf = QuadratureManager::instance().getPyramidFormula(GaussQuadratureDescriptor(4)); + + for (size_t i = 0; i < qf.numberOfPoints(); ++i) { + const auto& xi = qf.point(i); + integral += qf.weight(i) * T.jacobianDeterminant(xi) * f(T(xi)); + } + break; + } + case CellType::Prism: { + PrismTransformation T(xr[cell_node_list[0]], xr[cell_node_list[1]], xr[cell_node_list[2]], + xr[cell_node_list[3]], xr[cell_node_list[4]], xr[cell_node_list[5]]); + auto qf = QuadratureManager::instance().getPrismFormula(GaussQuadratureDescriptor(4)); + + for (size_t i = 0; i < qf.numberOfPoints(); ++i) { + const auto& xi = qf.point(i); + integral += qf.weight(i) * T.jacobianDeterminant(xi) * f(T(xi)); + } + break; + } + case CellType::Hexahedron: { + CubeTransformation T(xr[cell_node_list[0]], xr[cell_node_list[1]], xr[cell_node_list[2]], + xr[cell_node_list[3]], xr[cell_node_list[4]], xr[cell_node_list[5]], + xr[cell_node_list[6]], xr[cell_node_list[7]]); + auto qf = QuadratureManager::instance().getCubeFormula(GaussQuadratureDescriptor(4)); + + for (size_t i = 0; i < qf.numberOfPoints(); ++i) { + const auto& xi = qf.point(i); + integral += qf.weight(i) * T.jacobianDeterminant(xi) * f(T(xi)); + } + break; + } + case CellType::Diamond: { + if (cell_node_list.size() == 5) { + auto qf = QuadratureManager::instance().getTetrahedronFormula(GaussQuadratureDescriptor(4)); + { // top tetrahedron + TetrahedronTransformation T0(xr[cell_node_list[1]], xr[cell_node_list[2]], xr[cell_node_list[3]], + xr[cell_node_list[4]]); + + for (size_t i = 0; i < qf.numberOfPoints(); ++i) { + const auto& xi = qf.point(i); + integral += qf.weight(i) * T0.jacobianDeterminant() * f(T0(xi)); + } + } + { // bottom tetrahedron + TetrahedronTransformation T1(xr[cell_node_list[3]], xr[cell_node_list[2]], xr[cell_node_list[1]], + xr[cell_node_list[0]]); + + for (size_t i = 0; i < qf.numberOfPoints(); ++i) { + const auto& xi = qf.point(i); + integral += qf.weight(i) * T1.jacobianDeterminant() * f(T1(xi)); + } + } + } else if (cell_node_list.size() == 6) { + auto qf = QuadratureManager::instance().getPyramidFormula(GaussQuadratureDescriptor(4)); + { // top pyramid + PyramidTransformation T0(xr[cell_node_list[1]], xr[cell_node_list[2]], xr[cell_node_list[3]], + xr[cell_node_list[4]], xr[cell_node_list[5]]); + + for (size_t i = 0; i < qf.numberOfPoints(); ++i) { + const auto& xi = qf.point(i); + integral += qf.weight(i) * T0.jacobianDeterminant(xi) * f(T0(xi)); + } + } + { // bottom pyramid + PyramidTransformation T1(xr[cell_node_list[4]], xr[cell_node_list[3]], xr[cell_node_list[2]], + xr[cell_node_list[1]], xr[cell_node_list[0]]); + + for (size_t i = 0; i < qf.numberOfPoints(); ++i) { + const auto& xi = qf.point(i); + integral += qf.weight(i) * T1.jacobianDeterminant(xi) * f(T1(xi)); + } + } + } else { + INFO("Diamond cells with more than 6 vertices are not tested"); + REQUIRE(false); + } + break; + } + default: { + INFO("Diamond cells not tested yet"); + REQUIRE(cell_type[cell_id] != CellType::Diamond); + } + } + int_f[cell_id] = integral; + }); + + return int_f; + }(); + + SECTION("all cells") + { + SECTION("CellValue") + { + CellValue<double> values(mesh->connectivity()); + CellIntegrator::integrateTo([=](const R3 x) { return f(x); }, GaussQuadratureDescriptor(4), *mesh, + values); + + double error = 0; + for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++cell_id) { + error += std::abs(int_f_per_cell[cell_id] - values[cell_id]); + } + + REQUIRE(error == 0); + } + + SECTION("Array") + { + Array<double> values(mesh->numberOfCells()); + + CellIntegrator::integrateTo(f, GaussQuadratureDescriptor(4), *mesh, values); + + double error = 0; + for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++cell_id) { + error += std::abs(int_f_per_cell[cell_id] - values[cell_id]); + } + + REQUIRE(error == 0); + } + + SECTION("SmallArray") + { + SmallArray<double> values(mesh->numberOfCells()); + CellIntegrator::integrateTo(f, GaussQuadratureDescriptor(4), *mesh, values); + + double error = 0; + for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++cell_id) { + error += std::abs(int_f_per_cell[cell_id] - values[cell_id]); + } + + REQUIRE(error == 0); + } + } + + SECTION("cell list") + { + SECTION("Array") + { + Array<CellId> cell_list{mesh->numberOfCells() / 2 + mesh->numberOfCells() % 2}; + + { + size_t k = 0; + for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++(++cell_id), ++k) { + cell_list[k] = cell_id; + } + + REQUIRE(k == cell_list.size()); + } + + Array<double> values = CellIntegrator::integrate(f, GaussQuadratureDescriptor(4), *mesh, cell_list); + + double error = 0; + for (size_t i = 0; i < cell_list.size(); ++i) { + error += std::abs(int_f_per_cell[cell_list[i]] - values[i]); + } + + REQUIRE(error == 0); + } + + SECTION("SmallArray") + { + SmallArray<CellId> cell_list{mesh->numberOfCells() / 2 + mesh->numberOfCells() % 2}; + + { + size_t k = 0; + for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++(++cell_id), ++k) { + cell_list[k] = cell_id; + } + + REQUIRE(k == cell_list.size()); + } + + SmallArray<double> values = CellIntegrator::integrate(f, GaussQuadratureDescriptor(4), *mesh, cell_list); + + double error = 0; + for (size_t i = 0; i < cell_list.size(); ++i) { + error += std::abs(int_f_per_cell[cell_list[i]] - values[i]); + } + + REQUIRE(error == 0); + } + } + } + + SECTION("tensorial formula") + { + Array<const double> int_f_per_cell = [=] { + Array<double> int_f(mesh->numberOfCells()); + auto cell_to_node_matrix = mesh->connectivity().cellToNodeMatrix(); + auto cell_type = mesh->connectivity().cellType(); + + auto qf = QuadratureManager::instance().getCubeFormula(GaussLegendreQuadratureDescriptor(4)); + + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { + auto cell_node_list = cell_to_node_matrix[cell_id]; + auto xr = mesh->xr(); + double integral = 0; + + switch (cell_type[cell_id]) { + case CellType::Tetrahedron: { + CubeTransformation T(xr[cell_node_list[0]], xr[cell_node_list[1]], xr[cell_node_list[2]], + xr[cell_node_list[2]], xr[cell_node_list[3]], xr[cell_node_list[3]], + xr[cell_node_list[3]], xr[cell_node_list[3]]); + + for (size_t i = 0; i < qf.numberOfPoints(); ++i) { + const auto& xi = qf.point(i); + integral += qf.weight(i) * T.jacobianDeterminant(xi) * f(T(xi)); + } + break; + } + case CellType::Pyramid: { + CubeTransformation T(xr[cell_node_list[0]], xr[cell_node_list[1]], xr[cell_node_list[2]], + xr[cell_node_list[3]], xr[cell_node_list[4]], xr[cell_node_list[4]], + xr[cell_node_list[4]], xr[cell_node_list[4]]); + + for (size_t i = 0; i < qf.numberOfPoints(); ++i) { + const auto& xi = qf.point(i); + integral += qf.weight(i) * T.jacobianDeterminant(xi) * f(T(xi)); + } + break; + } + case CellType::Prism: { + CubeTransformation T(xr[cell_node_list[0]], xr[cell_node_list[1]], xr[cell_node_list[2]], + xr[cell_node_list[2]], xr[cell_node_list[3]], xr[cell_node_list[4]], + xr[cell_node_list[5]], xr[cell_node_list[5]]); + for (size_t i = 0; i < qf.numberOfPoints(); ++i) { + const auto& xi = qf.point(i); + integral += qf.weight(i) * T.jacobianDeterminant(xi) * f(T(xi)); + } + break; + } + case CellType::Hexahedron: { + CubeTransformation T(xr[cell_node_list[0]], xr[cell_node_list[1]], xr[cell_node_list[2]], + xr[cell_node_list[3]], xr[cell_node_list[4]], xr[cell_node_list[5]], + xr[cell_node_list[6]], xr[cell_node_list[7]]); + + for (size_t i = 0; i < qf.numberOfPoints(); ++i) { + const auto& xi = qf.point(i); + integral += qf.weight(i) * T.jacobianDeterminant(xi) * f(T(xi)); + } + break; + } + case CellType::Diamond: { + if (cell_node_list.size() == 5) { + { // top tetrahedron + CubeTransformation T0(xr[cell_node_list[1]], xr[cell_node_list[2]], xr[cell_node_list[3]], + xr[cell_node_list[3]], xr[cell_node_list[4]], xr[cell_node_list[4]], + xr[cell_node_list[4]], xr[cell_node_list[4]]); + + for (size_t i = 0; i < qf.numberOfPoints(); ++i) { + const auto& xi = qf.point(i); + integral += qf.weight(i) * T0.jacobianDeterminant(xi) * f(T0(xi)); + } + } + { // bottom tetrahedron + CubeTransformation T1(xr[cell_node_list[3]], xr[cell_node_list[2]], xr[cell_node_list[1]], + xr[cell_node_list[1]], xr[cell_node_list[0]], xr[cell_node_list[0]], + xr[cell_node_list[0]], xr[cell_node_list[0]]); + + for (size_t i = 0; i < qf.numberOfPoints(); ++i) { + const auto& xi = qf.point(i); + integral += qf.weight(i) * T1.jacobianDeterminant(xi) * f(T1(xi)); + } + } + } else if (cell_node_list.size() == 6) { + { // top pyramid + CubeTransformation T0(xr[cell_node_list[1]], xr[cell_node_list[2]], xr[cell_node_list[3]], + xr[cell_node_list[4]], xr[cell_node_list[5]], xr[cell_node_list[5]], + xr[cell_node_list[5]], xr[cell_node_list[5]]); + + for (size_t i = 0; i < qf.numberOfPoints(); ++i) { + const auto& xi = qf.point(i); + integral += qf.weight(i) * T0.jacobianDeterminant(xi) * f(T0(xi)); + } + } + { // bottom pyramid + CubeTransformation T1(xr[cell_node_list[4]], xr[cell_node_list[3]], xr[cell_node_list[2]], + xr[cell_node_list[1]], xr[cell_node_list[0]], xr[cell_node_list[0]], + xr[cell_node_list[0]], xr[cell_node_list[0]]); + + for (size_t i = 0; i < qf.numberOfPoints(); ++i) { + const auto& xi = qf.point(i); + integral += qf.weight(i) * T1.jacobianDeterminant(xi) * f(T1(xi)); + } + } + } else { + INFO("Diamond cells with more than 6 vertices are not tested"); + REQUIRE(false); + } + break; + } + default: { + INFO("Diamond cells not tested yet"); + REQUIRE(cell_type[cell_id] != CellType::Diamond); + } + } + int_f[cell_id] = integral; + }); + + return int_f; + }(); + + SECTION("all cells") + { + SECTION("CellValue") + { + CellValue<double> values(mesh->connectivity()); + CellIntegrator::integrateTo([=](const R3 x) { return f(x); }, GaussLegendreQuadratureDescriptor(10), + *mesh, values); + + auto cell_type = mesh->connectivity().cellType(); + double error = 0; + for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++cell_id) { + error += std::abs(int_f_per_cell[cell_id] - values[cell_id]); + } + + REQUIRE(error == Catch::Approx(0).margin(1E-10)); + } + + SECTION("Array") + { + Array<double> values(mesh->numberOfCells()); + + CellIntegrator::integrateTo(f, GaussLobattoQuadratureDescriptor(4), *mesh, values); + + double error = 0; + for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++cell_id) { + error += std::abs(int_f_per_cell[cell_id] - values[cell_id]); + } + + REQUIRE(error == Catch::Approx(0).margin(1E-10)); + } + + SECTION("SmallArray") + { + SmallArray<double> values(mesh->numberOfCells()); + CellIntegrator::integrateTo(f, GaussLobattoQuadratureDescriptor(4), *mesh, values); + + double error = 0; + for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++cell_id) { + error += std::abs(int_f_per_cell[cell_id] - values[cell_id]); + } + + REQUIRE(error == Catch::Approx(0).margin(1E-10)); + } + } + + SECTION("cell list") + { + SECTION("Array") + { + Array<CellId> cell_list{mesh->numberOfCells() / 2 + mesh->numberOfCells() % 2}; + + { + size_t k = 0; + for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++(++cell_id), ++k) { + cell_list[k] = cell_id; + } + + REQUIRE(k == cell_list.size()); + } + + Array<double> values = + CellIntegrator::integrate(f, GaussLobattoQuadratureDescriptor(4), *mesh, cell_list); + + double error = 0; + for (size_t i = 0; i < cell_list.size(); ++i) { + error += std::abs(int_f_per_cell[cell_list[i]] - values[i]); + } + + REQUIRE(error == Catch::Approx(0).margin(1E-10)); + } + + SECTION("SmallArray") + { + SmallArray<CellId> cell_list{mesh->numberOfCells() / 2 + mesh->numberOfCells() % 2}; + + { + size_t k = 0; + for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++(++cell_id), ++k) { + cell_list[k] = cell_id; + } + + REQUIRE(k == cell_list.size()); + } + + SmallArray<double> values = + CellIntegrator::integrate(f, GaussLobattoQuadratureDescriptor(4), *mesh, cell_list); + + double error = 0; + for (size_t i = 0; i < cell_list.size(); ++i) { + error += std::abs(int_f_per_cell[cell_list[i]] - values[i]); + } + + REQUIRE(error == Catch::Approx(0).margin(1E-10)); + } + } + } + } + } + } +} diff --git a/tests/test_CubeGaussQuadrature.cpp b/tests/test_CubeGaussQuadrature.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1db30eb178be24be223f63b5f6a68aa441261909 --- /dev/null +++ b/tests/test_CubeGaussQuadrature.cpp @@ -0,0 +1,509 @@ +#include <catch2/catch_approx.hpp> +#include <catch2/catch_test_macros.hpp> +#include <catch2/matchers/catch_matchers_all.hpp> + +#include <algebra/TinyMatrix.hpp> + +#include <analysis/CubeGaussQuadrature.hpp> +#include <analysis/GaussQuadratureDescriptor.hpp> +#include <analysis/QuadratureManager.hpp> +#include <utils/Exceptions.hpp> + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("CubeGaussQuadrature", "[analysis]") +{ + auto integrate = [](auto f, auto quadrature_formula) { + auto point_list = quadrature_formula.pointList(); + auto weight_list = quadrature_formula.weightList(); + + auto value = weight_list[0] * f(point_list[0]); + for (size_t i = 1; i < weight_list.size(); ++i) { + value += weight_list[i] * f(point_list[i]); + } + + return value; + }; + + auto integrate_on_brick = [](auto f, auto quadrature_formula, const std::array<TinyVector<3>, 4>& tetrahedron) { + const auto& A = tetrahedron[0]; + const auto& B = tetrahedron[1]; + const auto& C = tetrahedron[2]; + const auto& D = tetrahedron[3]; + + TinyMatrix<3> J; + for (size_t i = 0; i < 3; ++i) { + J(i, 0) = 0.5 * (B[i] - A[i]); + J(i, 1) = 0.5 * (C[i] - A[i]); + J(i, 2) = 0.5 * (D[i] - A[i]); + } + TinyVector s = 0.5 * (B + C + D - A); + + auto point_list = quadrature_formula.pointList(); + auto weight_list = quadrature_formula.weightList(); + + auto value = weight_list[0] * f(J * (point_list[0]) + s); + for (size_t i = 1; i < weight_list.size(); ++i) { + value += weight_list[i] * f(J * (point_list[i]) + s); + } + + return det(J) * value; + }; + + auto get_order = [&integrate, &integrate_on_brick](auto f, auto quadrature_formula, const double exact_value) { + using R3 = TinyVector<3>; + + const double int_K_hat = integrate(f, quadrature_formula); + const double int_refined // + = integrate_on_brick(f, quadrature_formula, {R3{-1, -1, -1}, R3{+0, -1, -1}, R3{-1, +0, -1}, R3{-1, -1, +0}}) + + integrate_on_brick(f, quadrature_formula, {R3{+0, -1, -1}, R3{+1, -1, -1}, R3{+0, +0, -1}, R3{+0, -1, +0}}) + + integrate_on_brick(f, quadrature_formula, {R3{-1, +0, -1}, R3{+0, +0, -1}, R3{-1, +1, -1}, R3{-1, +0, +0}}) + + integrate_on_brick(f, quadrature_formula, {R3{+0, +0, -1}, R3{+1, +0, -1}, R3{+0, +1, -1}, R3{+0, +0, +0}}) + + integrate_on_brick(f, quadrature_formula, {R3{-1, -1, +0}, R3{+0, -1, +0}, R3{-1, +0, +0}, R3{-1, -1, +1}}) + + integrate_on_brick(f, quadrature_formula, {R3{+0, -1, +0}, R3{+1, -1, +0}, R3{+0, +0, +0}, R3{+0, -1, +1}}) + + integrate_on_brick(f, quadrature_formula, {R3{-1, +0, +0}, R3{+0, +0, +0}, R3{-1, +1, +0}, R3{-1, +0, +1}}) + + integrate_on_brick(f, quadrature_formula, {R3{+0, +0, +0}, R3{+1, +0, +0}, R3{+0, +1, +0}, R3{+0, +0, +1}}); + + return -std::log((int_refined - exact_value) / (int_K_hat - exact_value)) / std::log(2); + }; + + auto p0 = [](const TinyVector<3>&) { return 4; }; + auto p1 = [](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return 2 * x + 3 * y + z - 1; + }; + auto p2 = [&p1](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p1(X) * (2.5 * x - 3 * y + z + 3); + }; + auto p3 = [&p2](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p2(X) * (3 * x + 2 * y - 3 * z - 1); + }; + auto p4 = [&p3](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p3(X) * (2 * x - 0.5 * y - 1.3 * z + 1); + }; + auto p5 = [&p4](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p4(X) * (-0.1 * x + 1.3 * y - 3 * z + 1); + }; + auto p6 = [&p5](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p5(X) * 7875. / 143443 * (2 * x - y + 4 * z + 1); + }; + auto p7 = [&p6](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p6(X) * (0.7 * x - 2.7 * y + 1.3 * z - 2); + }; + auto p8 = [&p7](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p7(X) * (0.3 * x + 1.2 * y - 0.7 * z + 0.2); + }; + auto p9 = [&p8](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p8(X) * (-0.2 * x - 1.7 * y + 0.4 * z - 0.4); + }; + auto p10 = [&p9](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p9(X) * (0.8 * x + 0.1 * y - 0.7 * z + 0.2); + }; + auto p11 = [&p10](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p10(X) * (-0.6 * x - 0.5 * y + 0.3 * z - 0.1); + }; + auto p12 = [&p11](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p11(X) * (0.4 * x - 0.7 * y - 0.6 * z + 0.7); + }; + auto p13 = [&p12](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p12(X) * (-0.9 * x + 0.3 * y + 0.3 * z - 0.3); + }; + auto p14 = [&p13](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p13(X) * (0.2 * x - 0.7 * y + 0.6 * z + 0.1); + }; + auto p15 = [&p14](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p14(X) * (-0.5 * x - 0.3 * y + 0.7 * z - 0.4); + }; + auto p16 = [&p15](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p15(X) * (0.7 * x + 0.6 * y - 0.1 * z + 0.6); + }; + auto p17 = [&p16](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p16(X) * (-0.6 * x + 0.3 * y + 0.7 * z + 0.8); + }; + auto p18 = [&p17](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p17(X) * (0.1 * x + 0.9 * y - 0.4 * z - 0.3); + }; + auto p19 = [&p18](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p18(X) * (-0.8 * x - 0.3 * y + 0.9 * z + 0.8); + }; + auto p20 = [&p19](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p19(X) * (0.3 * x - 0.7 * y - 0.8 * z + 0.7); + }; + auto p21 = [&p20](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p20(X) * (-0.9 * x + 0.2 * y + 0.5 * z - 0.6); + }; + auto p22 = [&p21](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p21(X) * (0.3 * x - 0.6 * y - 0.7 * z + 0.2); + }; + + SECTION("degree 0 and 1") + { + const QuadratureFormula<3>& l1 = QuadratureManager::instance().getCubeFormula(GaussQuadratureDescriptor(1)); + + REQUIRE(l1.numberOfPoints() == 1); + + REQUIRE(integrate(p0, l1) == Catch::Approx(32)); + REQUIRE(integrate(p1, l1) == Catch::Approx(-8)); + REQUIRE(integrate(p2, l1) != Catch::Approx(-32)); + + REQUIRE(get_order(p2, l1, -32) == Catch::Approx(2)); + } + + SECTION("degree 2 and 3") + { + const QuadratureFormula<3>& l2 = QuadratureManager::instance().getCubeFormula(GaussQuadratureDescriptor(2)); + const QuadratureFormula<3>& l3 = QuadratureManager::instance().getCubeFormula(GaussQuadratureDescriptor(3)); + + REQUIRE(&l2 == &l3); + + REQUIRE(l3.numberOfPoints() == 6); + + REQUIRE(integrate(p0, l3) == Catch::Approx(32)); + REQUIRE(integrate(p1, l3) == Catch::Approx(-8)); + REQUIRE(integrate(p2, l3) == Catch::Approx(-32)); + REQUIRE(integrate(p3, l3) == Catch::Approx(108)); + REQUIRE(integrate(p4, l3) != Catch::Approx(868. / 75)); + + REQUIRE(get_order(p4, l3, 868. / 75) == Catch::Approx(4)); + } + + SECTION("degree 4 and 5") + { + const QuadratureFormula<3>& l4 = QuadratureManager::instance().getCubeFormula(GaussQuadratureDescriptor(4)); + const QuadratureFormula<3>& l5 = QuadratureManager::instance().getCubeFormula(GaussQuadratureDescriptor(5)); + + REQUIRE(&l4 == &l5); + + REQUIRE(l5.numberOfPoints() == 14); + + REQUIRE(integrate(p0, l5) == Catch::Approx(32)); + REQUIRE(integrate(p1, l5) == Catch::Approx(-8)); + REQUIRE(integrate(p2, l5) == Catch::Approx(-32)); + REQUIRE(integrate(p3, l5) == Catch::Approx(108)); + REQUIRE(integrate(p4, l5) == Catch::Approx(868. / 75)); + REQUIRE(integrate(p5, l5) == Catch::Approx(11176. / 225)); + REQUIRE(integrate(p6, l5) != Catch::Approx(-34781. / 430329)); + + REQUIRE(get_order(p6, l5, -34781. / 430329) == Catch::Approx(6)); + } + + SECTION("degree 6 and 7") + { + const QuadratureFormula<3>& l6 = QuadratureManager::instance().getCubeFormula(GaussQuadratureDescriptor(6)); + const QuadratureFormula<3>& l7 = QuadratureManager::instance().getCubeFormula(GaussQuadratureDescriptor(7)); + + REQUIRE(&l6 == &l7); + + REQUIRE(l7.numberOfPoints() == 34); + + REQUIRE(integrate(p0, l7) == Catch::Approx(32)); + REQUIRE(integrate(p1, l7) == Catch::Approx(-8)); + REQUIRE(integrate(p2, l7) == Catch::Approx(-32)); + REQUIRE(integrate(p3, l7) == Catch::Approx(108)); + REQUIRE(integrate(p4, l7) == Catch::Approx(868. / 75)); + REQUIRE(integrate(p5, l7) == Catch::Approx(11176. / 225)); + REQUIRE(integrate(p6, l7) == Catch::Approx(-34781. / 430329)); + REQUIRE(integrate(p7, l7) == Catch::Approx(-37338109. / 4303290)); + REQUIRE(integrate(p8, l7) != Catch::Approx(422437099. / 21516450)); + + REQUIRE(get_order(p8, l7, 422437099. / 21516450) == Catch::Approx(8)); + } + + SECTION("degree 8 and 9") + { + const QuadratureFormula<3>& l8 = QuadratureManager::instance().getCubeFormula(GaussQuadratureDescriptor(8)); + const QuadratureFormula<3>& l9 = QuadratureManager::instance().getCubeFormula(GaussQuadratureDescriptor(9)); + + REQUIRE(&l8 == &l9); + + REQUIRE(l9.numberOfPoints() == 58); + + REQUIRE(integrate(p0, l9) == Catch::Approx(32)); + REQUIRE(integrate(p1, l9) == Catch::Approx(-8)); + REQUIRE(integrate(p2, l9) == Catch::Approx(-32)); + REQUIRE(integrate(p3, l9) == Catch::Approx(108)); + REQUIRE(integrate(p4, l9) == Catch::Approx(868. / 75)); + REQUIRE(integrate(p5, l9) == Catch::Approx(11176. / 225)); + REQUIRE(integrate(p6, l9) == Catch::Approx(-34781. / 430329)); + REQUIRE(integrate(p7, l9) == Catch::Approx(-37338109. / 4303290)); + REQUIRE(integrate(p8, l9) == Catch::Approx(422437099. / 21516450)); + REQUIRE(integrate(p9, l9) == Catch::Approx(-7745999747. / 358607500)); + REQUIRE(integrate(p10, l9) != Catch::Approx(-564286973089. / 14792559375)); + + REQUIRE(get_order(p10, l9, -564286973089. / 14792559375) == Catch::Approx(10)); + } + + SECTION("degree 10 and 11") + { + const QuadratureFormula<3>& l10 = QuadratureManager::instance().getCubeFormula(GaussQuadratureDescriptor(10)); + const QuadratureFormula<3>& l11 = QuadratureManager::instance().getCubeFormula(GaussQuadratureDescriptor(11)); + + REQUIRE(&l10 == &l11); + + REQUIRE(l11.numberOfPoints() == 90); + + REQUIRE(integrate(p0, l11) == Catch::Approx(32)); + REQUIRE(integrate(p1, l11) == Catch::Approx(-8)); + REQUIRE(integrate(p2, l11) == Catch::Approx(-32)); + REQUIRE(integrate(p3, l11) == Catch::Approx(108)); + REQUIRE(integrate(p4, l11) == Catch::Approx(868. / 75)); + REQUIRE(integrate(p5, l11) == Catch::Approx(11176. / 225)); + REQUIRE(integrate(p6, l11) == Catch::Approx(-34781. / 430329)); + REQUIRE(integrate(p7, l11) == Catch::Approx(-37338109. / 4303290)); + REQUIRE(integrate(p8, l11) == Catch::Approx(422437099. / 21516450)); + REQUIRE(integrate(p9, l11) == Catch::Approx(-7745999747. / 358607500)); + REQUIRE(integrate(p10, l11) == Catch::Approx(-564286973089. / 14792559375)); + REQUIRE(integrate(p11, l11) == Catch::Approx(5047102242313. / 59170237500)); + REQUIRE(integrate(p12, l11) != Catch::Approx(41226980237154884. / 504796088671875)); + + REQUIRE(get_order(p12, l11, 41226980237154884. / 504796088671875) == Catch::Approx(12)); + } + + SECTION("degree 12 and 13") + { + const QuadratureFormula<3>& l12 = QuadratureManager::instance().getCubeFormula(GaussQuadratureDescriptor(12)); + const QuadratureFormula<3>& l13 = QuadratureManager::instance().getCubeFormula(GaussQuadratureDescriptor(13)); + + REQUIRE(&l12 == &l13); + + REQUIRE(l13.numberOfPoints() == 154); + + REQUIRE(integrate(p0, l13) == Catch::Approx(32)); + REQUIRE(integrate(p1, l13) == Catch::Approx(-8)); + REQUIRE(integrate(p2, l13) == Catch::Approx(-32)); + REQUIRE(integrate(p3, l13) == Catch::Approx(108)); + REQUIRE(integrate(p4, l13) == Catch::Approx(868. / 75)); + REQUIRE(integrate(p5, l13) == Catch::Approx(11176. / 225)); + REQUIRE(integrate(p6, l13) == Catch::Approx(-34781. / 430329)); + REQUIRE(integrate(p7, l13) == Catch::Approx(-37338109. / 4303290)); + REQUIRE(integrate(p8, l13) == Catch::Approx(422437099. / 21516450)); + REQUIRE(integrate(p9, l13) == Catch::Approx(-7745999747. / 358607500)); + REQUIRE(integrate(p10, l13) == Catch::Approx(-564286973089. / 14792559375)); + REQUIRE(integrate(p11, l13) == Catch::Approx(5047102242313. / 59170237500)); + REQUIRE(integrate(p12, l13) == Catch::Approx(41226980237154884. / 504796088671875)); + REQUIRE(integrate(p13, l13) == Catch::Approx(-2061220959094693133. / 26922458062500000)); + REQUIRE(integrate(p14, l13) != Catch::Approx(9658346476244058223. / 134612290312500000)); + + REQUIRE(get_order(p14, l13, 9658346476244058223. / 134612290312500000) == Catch::Approx(14)); + } + + SECTION("degree 14 and 15") + { + const QuadratureFormula<3>& l14 = QuadratureManager::instance().getCubeFormula(GaussQuadratureDescriptor(14)); + const QuadratureFormula<3>& l15 = QuadratureManager::instance().getCubeFormula(GaussQuadratureDescriptor(15)); + + REQUIRE(&l14 == &l15); + + REQUIRE(l15.numberOfPoints() == 256); + + REQUIRE(integrate(p0, l15) == Catch::Approx(32)); + REQUIRE(integrate(p1, l15) == Catch::Approx(-8)); + REQUIRE(integrate(p2, l15) == Catch::Approx(-32)); + REQUIRE(integrate(p3, l15) == Catch::Approx(108)); + REQUIRE(integrate(p4, l15) == Catch::Approx(868. / 75)); + REQUIRE(integrate(p5, l15) == Catch::Approx(11176. / 225)); + REQUIRE(integrate(p6, l15) == Catch::Approx(-34781. / 430329)); + REQUIRE(integrate(p7, l15) == Catch::Approx(-37338109. / 4303290)); + REQUIRE(integrate(p8, l15) == Catch::Approx(422437099. / 21516450)); + REQUIRE(integrate(p9, l15) == Catch::Approx(-7745999747. / 358607500)); + REQUIRE(integrate(p10, l15) == Catch::Approx(-564286973089. / 14792559375)); + REQUIRE(integrate(p11, l15) == Catch::Approx(5047102242313. / 59170237500)); + REQUIRE(integrate(p12, l15) == Catch::Approx(41226980237154884. / 504796088671875)); + REQUIRE(integrate(p13, l15) == Catch::Approx(-2061220959094693133. / 26922458062500000)); + REQUIRE(integrate(p14, l15) == Catch::Approx(9658346476244058223. / 134612290312500000)); + REQUIRE(integrate(p15, l15) == Catch::Approx(-74949066496612419191. / 673061451562500000.)); + REQUIRE(integrate(p16, l15) != Catch::Approx(-46230170725718969828017. / 228840893531250000000.)); + + REQUIRE(get_order(p16, l15, -46230170725718969828017. / 228840893531250000000.) == Catch::Approx(16)); + } + + SECTION("degree 16 and 17") + { + const QuadratureFormula<3>& l16 = QuadratureManager::instance().getCubeFormula(GaussQuadratureDescriptor(16)); + const QuadratureFormula<3>& l17 = QuadratureManager::instance().getCubeFormula(GaussQuadratureDescriptor(17)); + + REQUIRE(&l16 == &l17); + + REQUIRE(l17.numberOfPoints() == 346); + + REQUIRE(integrate(p0, l17) == Catch::Approx(32)); + REQUIRE(integrate(p1, l17) == Catch::Approx(-8)); + REQUIRE(integrate(p2, l17) == Catch::Approx(-32)); + REQUIRE(integrate(p3, l17) == Catch::Approx(108)); + REQUIRE(integrate(p4, l17) == Catch::Approx(868. / 75)); + REQUIRE(integrate(p5, l17) == Catch::Approx(11176. / 225)); + REQUIRE(integrate(p6, l17) == Catch::Approx(-34781. / 430329)); + REQUIRE(integrate(p7, l17) == Catch::Approx(-37338109. / 4303290)); + REQUIRE(integrate(p8, l17) == Catch::Approx(422437099. / 21516450)); + REQUIRE(integrate(p9, l17) == Catch::Approx(-7745999747. / 358607500)); + REQUIRE(integrate(p10, l17) == Catch::Approx(-564286973089. / 14792559375)); + REQUIRE(integrate(p11, l17) == Catch::Approx(5047102242313. / 59170237500)); + REQUIRE(integrate(p12, l17) == Catch::Approx(41226980237154884. / 504796088671875)); + REQUIRE(integrate(p13, l17) == Catch::Approx(-2061220959094693133. / 26922458062500000)); + REQUIRE(integrate(p14, l17) == Catch::Approx(9658346476244058223. / 134612290312500000)); + REQUIRE(integrate(p15, l17) == Catch::Approx(-74949066496612419191. / 673061451562500000.)); + REQUIRE(integrate(p16, l17) == Catch::Approx(-46230170725718969828017. / 228840893531250000000.)); + REQUIRE(integrate(p17, l17) == Catch::Approx(2946902633453348474221. / 190700744609375000000.)); + REQUIRE(integrate(p18, l17) != Catch::Approx(904723313909284441962799. / 47555998186962890625000.)); + + REQUIRE(get_order(p18, l17, 904723313909284441962799. / 47555998186962890625000.) == Catch::Approx(18)); + } + + SECTION("degree 18 and 19") + { + const QuadratureFormula<3>& l18 = QuadratureManager::instance().getCubeFormula(GaussQuadratureDescriptor(18)); + const QuadratureFormula<3>& l19 = QuadratureManager::instance().getCubeFormula(GaussQuadratureDescriptor(19)); + + REQUIRE(&l18 == &l19); + + REQUIRE(l19.numberOfPoints() == 454); + + REQUIRE(integrate(p0, l19) == Catch::Approx(32)); + REQUIRE(integrate(p1, l19) == Catch::Approx(-8)); + REQUIRE(integrate(p2, l19) == Catch::Approx(-32)); + REQUIRE(integrate(p3, l19) == Catch::Approx(108)); + REQUIRE(integrate(p4, l19) == Catch::Approx(868. / 75)); + REQUIRE(integrate(p5, l19) == Catch::Approx(11176. / 225)); + REQUIRE(integrate(p6, l19) == Catch::Approx(-34781. / 430329)); + REQUIRE(integrate(p7, l19) == Catch::Approx(-37338109. / 4303290)); + REQUIRE(integrate(p8, l19) == Catch::Approx(422437099. / 21516450)); + REQUIRE(integrate(p9, l19) == Catch::Approx(-7745999747. / 358607500)); + REQUIRE(integrate(p10, l19) == Catch::Approx(-564286973089. / 14792559375)); + REQUIRE(integrate(p11, l19) == Catch::Approx(5047102242313. / 59170237500)); + REQUIRE(integrate(p12, l19) == Catch::Approx(41226980237154884. / 504796088671875)); + REQUIRE(integrate(p13, l19) == Catch::Approx(-2061220959094693133. / 26922458062500000)); + REQUIRE(integrate(p14, l19) == Catch::Approx(9658346476244058223. / 134612290312500000)); + REQUIRE(integrate(p15, l19) == Catch::Approx(-74949066496612419191. / 673061451562500000.)); + REQUIRE(integrate(p16, l19) == Catch::Approx(-46230170725718969828017. / 228840893531250000000.)); + REQUIRE(integrate(p17, l19) == Catch::Approx(2946902633453348474221. / 190700744609375000000.)); + REQUIRE(integrate(p18, l19) == Catch::Approx(904723313909284441962799. / 47555998186962890625000.)); + REQUIRE(integrate(p19, l19) == Catch::Approx(-91477977618647751170958517. / 22826879129742187500000000.)); + REQUIRE(integrate(p20, l19) != Catch::Approx(-11898262429946164522483495921. / 836985568090546875000000000.)); + + REQUIRE(get_order(p20, l19, -11898262429946164522483495921. / 836985568090546875000000000.) == Catch::Approx(20)); + } + + SECTION("degree 20 and 21") + { + const QuadratureFormula<3>& l20 = QuadratureManager::instance().getCubeFormula(GaussQuadratureDescriptor(20)); + const QuadratureFormula<3>& l21 = QuadratureManager::instance().getCubeFormula(GaussQuadratureDescriptor(21)); + + REQUIRE(&l20 == &l21); + + REQUIRE(l21.numberOfPoints() == 580); + + REQUIRE(integrate(p0, l21) == Catch::Approx(32)); + REQUIRE(integrate(p1, l21) == Catch::Approx(-8)); + REQUIRE(integrate(p2, l21) == Catch::Approx(-32)); + REQUIRE(integrate(p3, l21) == Catch::Approx(108)); + REQUIRE(integrate(p4, l21) == Catch::Approx(868. / 75)); + REQUIRE(integrate(p5, l21) == Catch::Approx(11176. / 225)); + REQUIRE(integrate(p6, l21) == Catch::Approx(-34781. / 430329)); + REQUIRE(integrate(p7, l21) == Catch::Approx(-37338109. / 4303290)); + REQUIRE(integrate(p8, l21) == Catch::Approx(422437099. / 21516450)); + REQUIRE(integrate(p9, l21) == Catch::Approx(-7745999747. / 358607500)); + REQUIRE(integrate(p10, l21) == Catch::Approx(-564286973089. / 14792559375)); + REQUIRE(integrate(p11, l21) == Catch::Approx(5047102242313. / 59170237500)); + REQUIRE(integrate(p12, l21) == Catch::Approx(41226980237154884. / 504796088671875)); + REQUIRE(integrate(p13, l21) == Catch::Approx(-2061220959094693133. / 26922458062500000)); + REQUIRE(integrate(p14, l21) == Catch::Approx(9658346476244058223. / 134612290312500000)); + REQUIRE(integrate(p15, l21) == Catch::Approx(-74949066496612419191. / 673061451562500000.)); + REQUIRE(integrate(p16, l21) == Catch::Approx(-46230170725718969828017. / 228840893531250000000.)); + REQUIRE(integrate(p17, l21) == Catch::Approx(2946902633453348474221. / 190700744609375000000.)); + REQUIRE(integrate(p18, l21) == Catch::Approx(904723313909284441962799. / 47555998186962890625000.)); + REQUIRE(integrate(p19, l21) == Catch::Approx(-91477977618647751170958517. / 22826879129742187500000000.)); + REQUIRE(integrate(p20, l21) == Catch::Approx(-11898262429946164522483495921. / 836985568090546875000000000.)); + REQUIRE(integrate(p21, l21) == Catch::Approx(7694483338683700814691225463. / 224192562881396484375000000.)); + REQUIRE(integrate(p22, l21) != Catch::Approx(10761048146311587678467825954981. / 481266701652064453125000000000.)); + + REQUIRE(get_order(p22, l21, 10761048146311587678467825954981. / 481266701652064453125000000000.) == + Catch::Approx(22)); + } + + SECTION("max implemented degree") + { + REQUIRE(QuadratureManager::instance().maxCubeDegree(QuadratureType::Gauss) == CubeGaussQuadrature::max_degree); + } + + SECTION("Access functions") + { + const QuadratureFormula<3>& quadrature_formula = + QuadratureManager::instance().getCubeFormula(GaussQuadratureDescriptor(7)); + + auto point_list = quadrature_formula.pointList(); + auto weight_list = quadrature_formula.weightList(); + + REQUIRE(point_list.size() == quadrature_formula.numberOfPoints()); + REQUIRE(weight_list.size() == quadrature_formula.numberOfPoints()); + + for (size_t i = 0; i < quadrature_formula.numberOfPoints(); ++i) { + REQUIRE(&point_list[i] == &quadrature_formula.point(i)); + REQUIRE(&weight_list[i] == &quadrature_formula.weight(i)); + } + } +} diff --git a/tests/test_CubeTransformation.cpp b/tests/test_CubeTransformation.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7d060ccd6faf409fb08813607209da1d9da616b1 --- /dev/null +++ b/tests/test_CubeTransformation.cpp @@ -0,0 +1,298 @@ +#include <catch2/catch_approx.hpp> +#include <catch2/catch_test_macros.hpp> + +#include <analysis/GaussLegendreQuadratureDescriptor.hpp> +#include <analysis/GaussLobattoQuadratureDescriptor.hpp> +#include <analysis/GaussQuadratureDescriptor.hpp> +#include <analysis/QuadratureManager.hpp> +#include <geometry/CubeTransformation.hpp> + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("CubeTransformation", "[geometry]") +{ + using R3 = TinyVector<3>; + + SECTION("invertible transformation") + { + const R3 a_hat = {-1, -1, -1}; + const R3 b_hat = {+1, -1, -1}; + const R3 c_hat = {+1, +1, -1}; + const R3 d_hat = {-1, +1, -1}; + const R3 e_hat = {-1, -1, +1}; + const R3 f_hat = {+1, -1, +1}; + const R3 g_hat = {+1, +1, +1}; + const R3 h_hat = {-1, +1, +1}; + + const R3 m_hat = zero; + + const R3 a = {0, 0, 0}; + const R3 b = {3, 1, 3}; + const R3 c = {2, 5, 2}; + const R3 d = {0, 3, 1}; + const R3 e = {1, 2, 5}; + const R3 f = {3, 1, 7}; + const R3 g = {2, 5, 5}; + const R3 h = {0, 3, 6}; + + const R3 m = 0.125 * (a + b + c + d + e + f + g + h); + + const CubeTransformation t(a, b, c, d, e, f, g, h); + + SECTION("values") + { + REQUIRE(l2Norm(t(a_hat) - a) == Catch::Approx(0)); + REQUIRE(l2Norm(t(b_hat) - b) == Catch::Approx(0)); + REQUIRE(l2Norm(t(c_hat) - c) == Catch::Approx(0)); + REQUIRE(l2Norm(t(d_hat) - d) == Catch::Approx(0)); + REQUIRE(l2Norm(t(e_hat) - e) == Catch::Approx(0)); + REQUIRE(l2Norm(t(f_hat) - f) == Catch::Approx(0)); + REQUIRE(l2Norm(t(g_hat) - g) == Catch::Approx(0)); + REQUIRE(l2Norm(t(h_hat) - h) == Catch::Approx(0)); + + REQUIRE(l2Norm(t(m_hat) - m) == Catch::Approx(0)); + } + + SECTION("Jacobian determinant") + { + SECTION("at points") + { + auto detJ = [](const R3& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + + return -(3 * x * y * y * z + 9 * y * y * z - 6 * x * x * y * z + 6 * x * y * z - 96 * y * z + 14 * x * x * z - + 49 * x * z + 119 * z - 21 * x * y * y + 21 * y * y + 90 * x * y - 10 * y + 40 * x * x - 109 * x - + 491) / + 128; + }; + + REQUIRE(t.jacobianDeterminant(a_hat) == Catch::Approx(detJ(a_hat))); + REQUIRE(t.jacobianDeterminant(b_hat) == Catch::Approx(detJ(b_hat))); + REQUIRE(t.jacobianDeterminant(c_hat) == Catch::Approx(detJ(c_hat))); + REQUIRE(t.jacobianDeterminant(d_hat) == Catch::Approx(detJ(d_hat))); + REQUIRE(t.jacobianDeterminant(e_hat) == Catch::Approx(detJ(e_hat))); + REQUIRE(t.jacobianDeterminant(f_hat) == Catch::Approx(detJ(f_hat))); + REQUIRE(t.jacobianDeterminant(g_hat) == Catch::Approx(detJ(g_hat))); + REQUIRE(t.jacobianDeterminant(h_hat) == Catch::Approx(detJ(h_hat))); + + REQUIRE(t.jacobianDeterminant(m_hat) == Catch::Approx(detJ(m_hat))); + } + + SECTION("Gauss order 3") + { + // The jacobian determinant is of maximal degree 2 in each variable + const QuadratureFormula<3>& gauss = + QuadratureManager::instance().getCubeFormula(GaussLegendreQuadratureDescriptor(2)); + + double volume = 0; + for (size_t i = 0; i < gauss.numberOfPoints(); ++i) { + volume += gauss.weight(i) * t.jacobianDeterminant(gauss.point(i)); + } + + // 353. / 12 is actually the volume of the hexahedron + REQUIRE(volume == Catch::Approx(353. / 12)); + } + + auto p = [](const R3& X) { + const double& x = X[0]; + const double& y = X[1]; + const double& z = X[2]; + + return 2 * x * x + 3 * y * z + z * z + 2 * x - 3 * y + 0.5 * z + 3; + }; + + SECTION("Gauss order 6") + { + // Jacbian determinant is a degree 2 polynomial, so the + // following formula is required to reach exactness + const QuadratureFormula<3>& gauss = QuadratureManager::instance().getCubeFormula(GaussQuadratureDescriptor(6)); + + double integral = 0; + for (size_t i = 0; i < gauss.numberOfPoints(); ++i) { + integral += gauss.weight(i) * t.jacobianDeterminant(gauss.point(i)) * p(t(gauss.point(i))); + } + + REQUIRE(integral == Catch::Approx(488879. / 360)); + } + + SECTION("Gauss-Legendre order 4") + { + // Jacbian determinant is a degree 2 polynomial, so the + // following formula is required to reach exactness + const QuadratureFormula<3>& gauss = + QuadratureManager::instance().getCubeFormula(GaussLegendreQuadratureDescriptor(4)); + + double integral = 0; + for (size_t i = 0; i < gauss.numberOfPoints(); ++i) { + integral += gauss.weight(i) * t.jacobianDeterminant(gauss.point(i)) * p(t(gauss.point(i))); + } + + REQUIRE(integral == Catch::Approx(488879. / 360)); + } + + SECTION("Gauss-Lobatto order 4") + { + // Jacbian determinant is a degree 2 polynomial, so the + // following formula is required to reach exactness + const QuadratureFormula<3>& gauss = + QuadratureManager::instance().getCubeFormula(GaussLobattoQuadratureDescriptor(4)); + + double integral = 0; + for (size_t i = 0; i < gauss.numberOfPoints(); ++i) { + integral += gauss.weight(i) * t.jacobianDeterminant(gauss.point(i)) * p(t(gauss.point(i))); + } + + REQUIRE(integral == Catch::Approx(488879. / 360)); + } + } + } + + SECTION("degenerate to tetrahedron") + { + using R3 = TinyVector<3>; + + const R3 a = {1, 2, 1}; + const R3 b = {3, 1, 3}; + const R3 c = {2, 5, 2}; + const R3 d = {2, 3, 4}; + + const CubeTransformation t(a, b, c, c, d, d, d, d); + + auto p = [](const R3& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return 2 * x * x + 3 * x * y + y * y + 3 * y - z * z + 2 * x * z + 2 * z; + }; + + SECTION("Polynomial Gauss integral") + { + QuadratureFormula<3> qf = QuadratureManager::instance().getCubeFormula(GaussQuadratureDescriptor(6)); + + double sum = 0; + for (size_t i = 0; i < qf.numberOfPoints(); ++i) { + const R3 xi = qf.point(i); + sum += qf.weight(i) * t.jacobianDeterminant(xi) * p(t(xi)); + } + + REQUIRE(sum == Catch::Approx(231. / 2)); + } + + SECTION("Polynomial Gauss-Lobatto integral") + { + QuadratureFormula<3> qf = QuadratureManager::instance().getCubeFormula(GaussLobattoQuadratureDescriptor(4)); + + double sum = 0; + for (size_t i = 0; i < qf.numberOfPoints(); ++i) { + const R3 xi = qf.point(i); + sum += qf.weight(i) * t.jacobianDeterminant(xi) * p(t(xi)); + } + + REQUIRE(sum == Catch::Approx(231. / 2)); + } + + SECTION("Polynomial Gauss-Legendre integral") + { + QuadratureFormula<3> qf = QuadratureManager::instance().getCubeFormula(GaussLegendreQuadratureDescriptor(4)); + + double sum = 0; + for (size_t i = 0; i < qf.numberOfPoints(); ++i) { + const R3 xi = qf.point(i); + sum += qf.weight(i) * t.jacobianDeterminant(xi) * p(t(xi)); + } + + REQUIRE(sum == Catch::Approx(231. / 2)); + } + } + + SECTION("degenerate to prism") + { + const R3 a = {1, 2, 0}; + const R3 b = {3, 1, 3}; + const R3 c = {2, 5, 2}; + const R3 d = {0, 3, 1}; + const R3 e = {1, 2, 5}; + const R3 f = {3, 1, 7}; + + const CubeTransformation t(a, b, c, c, d, e, f, f); + + auto p = [](const R3& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + + return 3 * x * x + 2 * y * y + 3 * z * z + 4 * x + 3 * y + 2 * z + 1; + }; + + SECTION("Polynomial Gauss integral") + { + // 8 is the minimum quadrature rule to integrate the polynomial + // on the prism due to the jacobian determinant expression + const QuadratureFormula<3>& gauss = QuadratureManager::instance().getCubeFormula(GaussQuadratureDescriptor(8)); + + double integral = 0; + for (size_t i = 0; i < gauss.numberOfPoints(); ++i) { + integral += gauss.weight(i) * t.jacobianDeterminant(gauss.point(i)) * p(t(gauss.point(i))); + } + + REQUIRE(integral == Catch::Approx(30377. / 90)); + } + + SECTION("Polynomial Gauss-Legendre integral") + { + const QuadratureFormula<3>& gauss = + QuadratureManager::instance().getCubeFormula(GaussLegendreQuadratureDescriptor(4)); + + double integral = 0; + for (size_t i = 0; i < gauss.numberOfPoints(); ++i) { + integral += gauss.weight(i) * t.jacobianDeterminant(gauss.point(i)) * p(t(gauss.point(i))); + } + + REQUIRE(integral == Catch::Approx(30377. / 90)); + } + + SECTION("Polynomial Gauss-Lobatto integral") + { + const QuadratureFormula<3>& gauss = + QuadratureManager::instance().getCubeFormula(GaussLobattoQuadratureDescriptor(4)); + + double integral = 0; + for (size_t i = 0; i < gauss.numberOfPoints(); ++i) { + integral += gauss.weight(i) * t.jacobianDeterminant(gauss.point(i)) * p(t(gauss.point(i))); + } + + REQUIRE(integral == Catch::Approx(30377. / 90)); + } + } + + SECTION("degenerate to pyramid") + { + const R3 a = {1, 2, 0}; + const R3 b = {3, 1, 3}; + const R3 c = {2, 5, 2}; + const R3 d = {0, 3, 1}; + const R3 e = {1, 2, 5}; + + const CubeTransformation t(a, b, c, d, e, e, e, e); + + auto p = [](const R3& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + + return 3 * x * x + 2 * y * y + 3 * z * z + 4 * x + 3 * y + 2 * z + 1; + }; + + // 4 is the minimum quadrature rule to integrate the polynomial on the pyramid + const QuadratureFormula<3>& gauss = + QuadratureManager::instance().getCubeFormula(GaussLegendreQuadratureDescriptor(20)); + double integral = 0; + for (size_t i = 0; i < gauss.numberOfPoints(); ++i) { + integral += gauss.weight(i) * t.jacobianDeterminant(gauss.point(i)) * p(t(gauss.point(i))); + } + + REQUIRE(integral == Catch::Approx(7238. / 15)); + } +} diff --git a/tests/test_DiscreteFunctionInterpoler.cpp b/tests/test_DiscreteFunctionInterpoler.cpp index d24bae5f065ba88afd225268c425b92f9211bcf5..809ca559ca254cbbb5d90c63f8dcd943a5df23c8 100644 --- a/tests/test_DiscreteFunctionInterpoler.cpp +++ b/tests/test_DiscreteFunctionInterpoler.cpp @@ -43,10 +43,16 @@ TEST_CASE("DiscreteFunctionInterpoler", "[scheme]") { constexpr size_t Dimension = 1; - const auto& mesh_1d = MeshDataBaseForTests::get().cartesianMesh1D(); - auto xj = MeshDataManager::instance().getMeshData(*mesh_1d).xj(); + std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - std::string_view data = R"( + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_1d = named_mesh.mesh(); + + auto xj = MeshDataManager::instance().getMeshData(*mesh_1d).xj(); + + std::string_view data = R"( import math; let B_scalar_non_linear_1d: R^1 -> B, x -> (exp(2 * x[0]) + 3 > 4); let N_scalar_non_linear_1d: R^1 -> N, x -> floor(3 * x[0] * x[0] + 2); @@ -59,274 +65,276 @@ let R1x1_non_linear_1d: R^1 -> R^1x1, x -> (2 * exp(x[0]) * sin(x[0]) + 3); let R2x2_non_linear_1d: R^1 -> R^2x2, x -> (2 * exp(x[0]) * sin(x[0]) + 3, sin(x[0] - 2 * x[0]), 3, x[0] * x[0]); let R3x3_non_linear_1d: R^1 -> R^3x3, x -> (2 * exp(x[0]) * sin(x[0]) + 3, sin(x[0] - 2 * x[0]), 3, x[0] * x[0], -4*x[0], 2*x[0]+1, 3, -6*x[0], exp(x[0])); )"; - TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"}; - - auto ast = ASTBuilder::build(input); - - ASTModulesImporter{*ast}; - ASTNodeTypeCleaner<language::import_instruction>{*ast}; - - ASTSymbolTableBuilder{*ast}; - ASTNodeDataTypeBuilder{*ast}; - - ASTNodeTypeCleaner<language::var_declaration>{*ast}; - ASTNodeTypeCleaner<language::fct_declaration>{*ast}; - ASTNodeExpressionBuilder{*ast}; - - std::shared_ptr<SymbolTable> symbol_table = ast->m_symbol_table; - - TAO_PEGTL_NAMESPACE::position position{TAO_PEGTL_NAMESPACE::internal::iterator{"fixture"}, "fixture"}; - position.byte = data.size(); // ensure that variables are declared at this point - - SECTION("B_scalar_non_linear_1d") - { - auto [i_symbol, found] = symbol_table->find("B_scalar_non_linear_1d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); - - CellValue<double> cell_value{mesh_1d->connectivity()}; - parallel_for( - cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<Dimension>& x = xj[cell_id]; - cell_value[cell_id] = std::exp(2 * x[0]) + 3 > 4; - }); - - DiscreteFunctionInterpoler interpoler(mesh_1d, std::make_shared<DiscreteFunctionDescriptorP0>(), - function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); - - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); - } - - SECTION("N_scalar_non_linear_1d") - { - auto [i_symbol, found] = symbol_table->find("N_scalar_non_linear_1d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); - - CellValue<double> cell_value{mesh_1d->connectivity()}; - parallel_for( - cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<Dimension>& x = xj[cell_id]; - cell_value[cell_id] = std::floor(3 * x[0] * x[0] + 2); - }); - - DiscreteFunctionInterpoler interpoler(mesh_1d, std::make_shared<DiscreteFunctionDescriptorP0>(), - function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); - - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); - } - - SECTION("Z_scalar_non_linear_1d") - { - auto [i_symbol, found] = symbol_table->find("Z_scalar_non_linear_1d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); - - CellValue<double> cell_value{mesh_1d->connectivity()}; - parallel_for( - cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<Dimension>& x = xj[cell_id]; - cell_value[cell_id] = std::floor(std::exp(2 * x[0]) - 1); - }); - - DiscreteFunctionInterpoler interpoler(mesh_1d, std::make_shared<DiscreteFunctionDescriptorP0>(), - function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); - - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); - } - - SECTION("R_scalar_non_linear_1d") - { - auto [i_symbol, found] = symbol_table->find("R_scalar_non_linear_1d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); - - CellValue<double> cell_value{mesh_1d->connectivity()}; - parallel_for( - cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<Dimension>& x = xj[cell_id]; - cell_value[cell_id] = 2 * std::exp(x[0]) + 3; - }); - - DiscreteFunctionInterpoler interpoler(mesh_1d, std::make_shared<DiscreteFunctionDescriptorP0>(), - function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); - - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); - } + TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"}; + + auto ast = ASTBuilder::build(input); + + ASTModulesImporter{*ast}; + ASTNodeTypeCleaner<language::import_instruction>{*ast}; - SECTION("R1_non_linear_1d") - { - using DataType = TinyVector<1>; - - auto [i_symbol, found] = symbol_table->find("R1_non_linear_1d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); - - CellValue<DataType> cell_value{mesh_1d->connectivity()}; - parallel_for( - cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<Dimension>& x = xj[cell_id]; - cell_value[cell_id] = DataType{2 * std::exp(x[0])}; - }); - - DiscreteFunctionInterpoler interpoler(mesh_1d, std::make_shared<DiscreteFunctionDescriptorP0>(), - function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); - - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); - } + ASTSymbolTableBuilder{*ast}; + ASTNodeDataTypeBuilder{*ast}; + + ASTNodeTypeCleaner<language::var_declaration>{*ast}; + ASTNodeTypeCleaner<language::fct_declaration>{*ast}; + ASTNodeExpressionBuilder{*ast}; + + std::shared_ptr<SymbolTable> symbol_table = ast->m_symbol_table; + + TAO_PEGTL_NAMESPACE::position position{TAO_PEGTL_NAMESPACE::internal::iterator{"fixture"}, "fixture"}; + position.byte = data.size(); // ensure that variables are declared at this point - SECTION("R2_non_linear_1d") - { - using DataType = TinyVector<2>; + SECTION("B_scalar_non_linear_1d") + { + auto [i_symbol, found] = symbol_table->find("B_scalar_non_linear_1d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + CellValue<double> cell_value{mesh_1d->connectivity()}; + parallel_for( + cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<Dimension>& x = xj[cell_id]; + cell_value[cell_id] = std::exp(2 * x[0]) + 3 > 4; + }); + + DiscreteFunctionInterpoler interpoler(mesh_1d, std::make_shared<DiscreteFunctionDescriptorP0>(), + function_symbol_id); + std::shared_ptr discrete_function = interpoler.interpolate(); + + REQUIRE(same_cell_value(cell_value, + dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); + } + + SECTION("N_scalar_non_linear_1d") + { + auto [i_symbol, found] = symbol_table->find("N_scalar_non_linear_1d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + CellValue<double> cell_value{mesh_1d->connectivity()}; + parallel_for( + cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<Dimension>& x = xj[cell_id]; + cell_value[cell_id] = std::floor(3 * x[0] * x[0] + 2); + }); + + DiscreteFunctionInterpoler interpoler(mesh_1d, std::make_shared<DiscreteFunctionDescriptorP0>(), + function_symbol_id); + std::shared_ptr discrete_function = interpoler.interpolate(); + + REQUIRE(same_cell_value(cell_value, + dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); + } + + SECTION("Z_scalar_non_linear_1d") + { + auto [i_symbol, found] = symbol_table->find("Z_scalar_non_linear_1d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - auto [i_symbol, found] = symbol_table->find("R2_non_linear_1d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); - - CellValue<DataType> cell_value{mesh_1d->connectivity()}; - parallel_for( - cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<Dimension>& x = xj[cell_id]; - cell_value[cell_id] = DataType{2 * std::exp(x[0]), -3 * x[0]}; - }); - - DiscreteFunctionInterpoler interpoler(mesh_1d, std::make_shared<DiscreteFunctionDescriptorP0>(), - function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); - - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); - } - - SECTION("R3_non_linear_1d") - { - using DataType = TinyVector<3>; - - auto [i_symbol, found] = symbol_table->find("R3_non_linear_1d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); - - CellValue<DataType> cell_value{mesh_1d->connectivity()}; - parallel_for( - cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<Dimension>& x = xj[cell_id]; - cell_value[cell_id] = DataType{2 * std::exp(x[0]) + 3, x[0] - 2, 3}; - }); - - DiscreteFunctionInterpoler interpoler(mesh_1d, std::make_shared<DiscreteFunctionDescriptorP0>(), - function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); - - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); - } - - SECTION("R1x1_non_linear_1d") - { - using DataType = TinyMatrix<1>; - - auto [i_symbol, found] = symbol_table->find("R1x1_non_linear_1d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); - - CellValue<DataType> cell_value{mesh_1d->connectivity()}; - parallel_for( - cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<Dimension>& x = xj[cell_id]; - cell_value[cell_id] = DataType{2 * std::exp(x[0]) * std::sin(x[0]) + 3}; - }); - - DiscreteFunctionInterpoler interpoler(mesh_1d, std::make_shared<DiscreteFunctionDescriptorP0>(), - function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); - - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); - } - - SECTION("R2x2_non_linear_1d") - { - using DataType = TinyMatrix<2>; - - auto [i_symbol, found] = symbol_table->find("R2x2_non_linear_1d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); - - CellValue<DataType> cell_value{mesh_1d->connectivity()}; - parallel_for( - cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<Dimension>& x = xj[cell_id]; - cell_value[cell_id] = - DataType{2 * std::exp(x[0]) * std::sin(x[0]) + 3, std::sin(x[0] - 2 * x[0]), 3, x[0] * x[0]}; - }); - - DiscreteFunctionInterpoler interpoler(mesh_1d, std::make_shared<DiscreteFunctionDescriptorP0>(), - function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); - - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); - } - - SECTION("R3x3_non_linear_1d") - { - using DataType = TinyMatrix<3>; - - auto [i_symbol, found] = symbol_table->find("R3x3_non_linear_1d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); - - CellValue<DataType> cell_value{mesh_1d->connectivity()}; - parallel_for( - cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<Dimension>& x = xj[cell_id]; - cell_value[cell_id] = DataType{2 * exp(x[0]) * std::sin(x[0]) + 3, - std::sin(x[0] - 2 * x[0]), - 3, - x[0] * x[0], - -4 * x[0], - 2 * x[0] + 1, - 3, - -6 * x[0], - std::exp(x[0])}; - }); - - DiscreteFunctionInterpoler interpoler(mesh_1d, std::make_shared<DiscreteFunctionDescriptorP0>(), - function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); - - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + CellValue<double> cell_value{mesh_1d->connectivity()}; + parallel_for( + cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<Dimension>& x = xj[cell_id]; + cell_value[cell_id] = std::floor(std::exp(2 * x[0]) - 1); + }); + + DiscreteFunctionInterpoler interpoler(mesh_1d, std::make_shared<DiscreteFunctionDescriptorP0>(), + function_symbol_id); + std::shared_ptr discrete_function = interpoler.interpolate(); + + REQUIRE(same_cell_value(cell_value, + dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); + } + + SECTION("R_scalar_non_linear_1d") + { + auto [i_symbol, found] = symbol_table->find("R_scalar_non_linear_1d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + CellValue<double> cell_value{mesh_1d->connectivity()}; + parallel_for( + cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<Dimension>& x = xj[cell_id]; + cell_value[cell_id] = 2 * std::exp(x[0]) + 3; + }); + + DiscreteFunctionInterpoler interpoler(mesh_1d, std::make_shared<DiscreteFunctionDescriptorP0>(), + function_symbol_id); + std::shared_ptr discrete_function = interpoler.interpolate(); + + REQUIRE(same_cell_value(cell_value, + dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); + } + + SECTION("R1_non_linear_1d") + { + using DataType = TinyVector<1>; + + auto [i_symbol, found] = symbol_table->find("R1_non_linear_1d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + CellValue<DataType> cell_value{mesh_1d->connectivity()}; + parallel_for( + cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<Dimension>& x = xj[cell_id]; + cell_value[cell_id] = DataType{2 * std::exp(x[0])}; + }); + + DiscreteFunctionInterpoler interpoler(mesh_1d, std::make_shared<DiscreteFunctionDescriptorP0>(), + function_symbol_id); + std::shared_ptr discrete_function = interpoler.interpolate(); + + REQUIRE(same_cell_value(cell_value, + dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + } + + SECTION("R2_non_linear_1d") + { + using DataType = TinyVector<2>; + + auto [i_symbol, found] = symbol_table->find("R2_non_linear_1d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + CellValue<DataType> cell_value{mesh_1d->connectivity()}; + parallel_for( + cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<Dimension>& x = xj[cell_id]; + cell_value[cell_id] = DataType{2 * std::exp(x[0]), -3 * x[0]}; + }); + + DiscreteFunctionInterpoler interpoler(mesh_1d, std::make_shared<DiscreteFunctionDescriptorP0>(), + function_symbol_id); + std::shared_ptr discrete_function = interpoler.interpolate(); + + REQUIRE(same_cell_value(cell_value, + dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + } + + SECTION("R3_non_linear_1d") + { + using DataType = TinyVector<3>; + + auto [i_symbol, found] = symbol_table->find("R3_non_linear_1d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + CellValue<DataType> cell_value{mesh_1d->connectivity()}; + parallel_for( + cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<Dimension>& x = xj[cell_id]; + cell_value[cell_id] = DataType{2 * std::exp(x[0]) + 3, x[0] - 2, 3}; + }); + + DiscreteFunctionInterpoler interpoler(mesh_1d, std::make_shared<DiscreteFunctionDescriptorP0>(), + function_symbol_id); + std::shared_ptr discrete_function = interpoler.interpolate(); + + REQUIRE(same_cell_value(cell_value, + dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + } + + SECTION("R1x1_non_linear_1d") + { + using DataType = TinyMatrix<1>; + + auto [i_symbol, found] = symbol_table->find("R1x1_non_linear_1d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + CellValue<DataType> cell_value{mesh_1d->connectivity()}; + parallel_for( + cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<Dimension>& x = xj[cell_id]; + cell_value[cell_id] = DataType{2 * std::exp(x[0]) * std::sin(x[0]) + 3}; + }); + + DiscreteFunctionInterpoler interpoler(mesh_1d, std::make_shared<DiscreteFunctionDescriptorP0>(), + function_symbol_id); + std::shared_ptr discrete_function = interpoler.interpolate(); + + REQUIRE(same_cell_value(cell_value, + dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + } + + SECTION("R2x2_non_linear_1d") + { + using DataType = TinyMatrix<2>; + + auto [i_symbol, found] = symbol_table->find("R2x2_non_linear_1d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + CellValue<DataType> cell_value{mesh_1d->connectivity()}; + parallel_for( + cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<Dimension>& x = xj[cell_id]; + cell_value[cell_id] = + DataType{2 * std::exp(x[0]) * std::sin(x[0]) + 3, std::sin(x[0] - 2 * x[0]), 3, x[0] * x[0]}; + }); + + DiscreteFunctionInterpoler interpoler(mesh_1d, std::make_shared<DiscreteFunctionDescriptorP0>(), + function_symbol_id); + std::shared_ptr discrete_function = interpoler.interpolate(); + + REQUIRE(same_cell_value(cell_value, + dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + } + + SECTION("R3x3_non_linear_1d") + { + using DataType = TinyMatrix<3>; + + auto [i_symbol, found] = symbol_table->find("R3x3_non_linear_1d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + CellValue<DataType> cell_value{mesh_1d->connectivity()}; + parallel_for( + cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<Dimension>& x = xj[cell_id]; + cell_value[cell_id] = DataType{2 * exp(x[0]) * std::sin(x[0]) + 3, + std::sin(x[0] - 2 * x[0]), + 3, + x[0] * x[0], + -4 * x[0], + 2 * x[0] + 1, + 3, + -6 * x[0], + std::exp(x[0])}; + }); + + DiscreteFunctionInterpoler interpoler(mesh_1d, std::make_shared<DiscreteFunctionDescriptorP0>(), + function_symbol_id); + std::shared_ptr discrete_function = interpoler.interpolate(); + + REQUIRE(same_cell_value(cell_value, + dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + } + } } } @@ -334,10 +342,16 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> (2 * exp(x[0]) * sin(x[0]) + 3, sin(x { constexpr size_t Dimension = 2; - const auto& mesh_2d = MeshDataBaseForTests::get().cartesianMesh2D(); - auto xj = MeshDataManager::instance().getMeshData(*mesh_2d).xj(); + std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - std::string_view data = R"( + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_2d = named_mesh.mesh(); + + auto xj = MeshDataManager::instance().getMeshData(*mesh_2d).xj(); + + std::string_view data = R"( import math; let B_scalar_non_linear_2d: R^2 -> B, x -> (exp(2 * x[0])< 2*x[1]); let N_scalar_non_linear_2d: R^2 -> N, x -> floor(3 * (x[0] + x[1]) * (x[0] + x[1]) + 2); @@ -350,275 +364,277 @@ let R1x1_non_linear_2d: R^2 -> R^1x1, x -> (2 * exp(x[0]) * sin(x[1]) + 3); let R2x2_non_linear_2d: R^2 -> R^2x2, x -> (2 * exp(x[0]) * sin(x[1]) + 3, sin(x[1] - 2 * x[0]), 3, x[1] * x[0]); let R3x3_non_linear_2d: R^2 -> R^3x3, x -> (2 * exp(x[0]) * sin(x[1]) + 3, sin(x[1] - 2 * x[0]), 3, x[1] * x[0], -4*x[1], 2*x[0]+1, 3, -6*x[0], exp(x[1])); )"; - TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"}; - - auto ast = ASTBuilder::build(input); - - ASTModulesImporter{*ast}; - ASTNodeTypeCleaner<language::import_instruction>{*ast}; - - ASTSymbolTableBuilder{*ast}; - ASTNodeDataTypeBuilder{*ast}; - - ASTNodeTypeCleaner<language::var_declaration>{*ast}; - ASTNodeTypeCleaner<language::fct_declaration>{*ast}; - ASTNodeExpressionBuilder{*ast}; - - std::shared_ptr<SymbolTable> symbol_table = ast->m_symbol_table; - - TAO_PEGTL_NAMESPACE::position position{TAO_PEGTL_NAMESPACE::internal::iterator{"fixture"}, "fixture"}; - position.byte = data.size(); // ensure that variables are declared at this point - - SECTION("B_scalar_non_linear_2d") - { - auto [i_symbol, found] = symbol_table->find("B_scalar_non_linear_2d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); - - CellValue<double> cell_value{mesh_2d->connectivity()}; - parallel_for( - cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<Dimension>& x = xj[cell_id]; - cell_value[cell_id] = std::exp(2 * x[0]) < 2 * x[1]; - }); - - DiscreteFunctionInterpoler interpoler(mesh_2d, std::make_shared<DiscreteFunctionDescriptorP0>(), - function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); - - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); - } - - SECTION("N_scalar_non_linear_2d") - { - auto [i_symbol, found] = symbol_table->find("N_scalar_non_linear_2d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); - - CellValue<double> cell_value{mesh_2d->connectivity()}; - parallel_for( - cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<Dimension>& x = xj[cell_id]; - cell_value[cell_id] = std::floor(3 * (x[0] + x[1]) * (x[0] + x[1]) + 2); - }); - - DiscreteFunctionInterpoler interpoler(mesh_2d, std::make_shared<DiscreteFunctionDescriptorP0>(), - function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); - - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); - } - - SECTION("Z_scalar_non_linear_2d") - { - auto [i_symbol, found] = symbol_table->find("Z_scalar_non_linear_2d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); - - CellValue<double> cell_value{mesh_2d->connectivity()}; - parallel_for( - cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<Dimension>& x = xj[cell_id]; - cell_value[cell_id] = std::floor(std::exp(2 * x[0]) - 3 * x[1]); - }); - - DiscreteFunctionInterpoler interpoler(mesh_2d, std::make_shared<DiscreteFunctionDescriptorP0>(), - function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); - - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); - } - - SECTION("R_scalar_non_linear_2d") - { - auto [i_symbol, found] = symbol_table->find("R_scalar_non_linear_2d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); - - CellValue<double> cell_value{mesh_2d->connectivity()}; - parallel_for( - cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<Dimension>& x = xj[cell_id]; - cell_value[cell_id] = 2 * std::exp(x[0]) + 3 * x[1]; - }); - - DiscreteFunctionInterpoler interpoler(mesh_2d, std::make_shared<DiscreteFunctionDescriptorP0>(), - function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); - - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); - } - - SECTION("R1_non_linear_2d") - { - using DataType = TinyVector<1>; + TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"}; + + auto ast = ASTBuilder::build(input); + + ASTModulesImporter{*ast}; + ASTNodeTypeCleaner<language::import_instruction>{*ast}; - auto [i_symbol, found] = symbol_table->find("R1_non_linear_2d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + ASTSymbolTableBuilder{*ast}; + ASTNodeDataTypeBuilder{*ast}; + + ASTNodeTypeCleaner<language::var_declaration>{*ast}; + ASTNodeTypeCleaner<language::fct_declaration>{*ast}; + ASTNodeExpressionBuilder{*ast}; + + std::shared_ptr<SymbolTable> symbol_table = ast->m_symbol_table; + + TAO_PEGTL_NAMESPACE::position position{TAO_PEGTL_NAMESPACE::internal::iterator{"fixture"}, "fixture"}; + position.byte = data.size(); // ensure that variables are declared at this point - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + SECTION("B_scalar_non_linear_2d") + { + auto [i_symbol, found] = symbol_table->find("B_scalar_non_linear_2d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + CellValue<double> cell_value{mesh_2d->connectivity()}; + parallel_for( + cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<Dimension>& x = xj[cell_id]; + cell_value[cell_id] = std::exp(2 * x[0]) < 2 * x[1]; + }); + + DiscreteFunctionInterpoler interpoler(mesh_2d, std::make_shared<DiscreteFunctionDescriptorP0>(), + function_symbol_id); + std::shared_ptr discrete_function = interpoler.interpolate(); + + REQUIRE(same_cell_value(cell_value, + dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); + } + + SECTION("N_scalar_non_linear_2d") + { + auto [i_symbol, found] = symbol_table->find("N_scalar_non_linear_2d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + CellValue<double> cell_value{mesh_2d->connectivity()}; + parallel_for( + cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<Dimension>& x = xj[cell_id]; + cell_value[cell_id] = std::floor(3 * (x[0] + x[1]) * (x[0] + x[1]) + 2); + }); + + DiscreteFunctionInterpoler interpoler(mesh_2d, std::make_shared<DiscreteFunctionDescriptorP0>(), + function_symbol_id); + std::shared_ptr discrete_function = interpoler.interpolate(); + + REQUIRE(same_cell_value(cell_value, + dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); + } + + SECTION("Z_scalar_non_linear_2d") + { + auto [i_symbol, found] = symbol_table->find("Z_scalar_non_linear_2d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - CellValue<DataType> cell_value{mesh_2d->connectivity()}; - parallel_for( - cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<Dimension>& x = xj[cell_id]; - cell_value[cell_id] = DataType{2 * std::exp(x[0])}; - }); - - DiscreteFunctionInterpoler interpoler(mesh_2d, std::make_shared<DiscreteFunctionDescriptorP0>(), - function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); - - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); - } - - SECTION("R2_non_linear_2d") - { - using DataType = TinyVector<2>; - - auto [i_symbol, found] = symbol_table->find("R2_non_linear_2d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); - - CellValue<DataType> cell_value{mesh_2d->connectivity()}; - parallel_for( - cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<Dimension>& x = xj[cell_id]; - cell_value[cell_id] = DataType{2 * std::exp(x[0]), -3 * x[1]}; - }); - - DiscreteFunctionInterpoler interpoler(mesh_2d, std::make_shared<DiscreteFunctionDescriptorP0>(), - function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); - - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); - } - - SECTION("R3_non_linear_2d") - { - using DataType = TinyVector<3>; - - auto [i_symbol, found] = symbol_table->find("R3_non_linear_2d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); - - CellValue<DataType> cell_value{mesh_2d->connectivity()}; - parallel_for( - cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<Dimension>& x = xj[cell_id]; - cell_value[cell_id] = DataType{2 * std::exp(x[0]) + 3, x[1] - 2, 3}; - }); - - DiscreteFunctionInterpoler interpoler(mesh_2d, std::make_shared<DiscreteFunctionDescriptorP0>(), - function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); - - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); - } - - SECTION("R1x1_non_linear_2d") - { - using DataType = TinyMatrix<1>; - - auto [i_symbol, found] = symbol_table->find("R1x1_non_linear_2d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); - - CellValue<DataType> cell_value{mesh_2d->connectivity()}; - parallel_for( - cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<Dimension>& x = xj[cell_id]; - cell_value[cell_id] = DataType{2 * std::exp(x[0]) * std::sin(x[1]) + 3}; - }); - - DiscreteFunctionInterpoler interpoler(mesh_2d, std::make_shared<DiscreteFunctionDescriptorP0>(), - function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); - - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); - } - - SECTION("R2x2_non_linear_2d") - { - using DataType = TinyMatrix<2>; - - auto [i_symbol, found] = symbol_table->find("R2x2_non_linear_2d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); - - CellValue<DataType> cell_value{mesh_2d->connectivity()}; - parallel_for( - cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<Dimension>& x = xj[cell_id]; - cell_value[cell_id] = - DataType{2 * std::exp(x[0]) * std::sin(x[1]) + 3, std::sin(x[1] - 2 * x[0]), 3, x[1] * x[0]}; - }); - - DiscreteFunctionInterpoler interpoler(mesh_2d, std::make_shared<DiscreteFunctionDescriptorP0>(), - function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); - - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); - } - - SECTION("R3x3_non_linear_2d") - { - using DataType = TinyMatrix<3>; - - auto [i_symbol, found] = symbol_table->find("R3x3_non_linear_2d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); - - CellValue<DataType> cell_value{mesh_2d->connectivity()}; - parallel_for( - cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<Dimension>& x = xj[cell_id]; - - cell_value[cell_id] = DataType{2 * std::exp(x[0]) * std::sin(x[1]) + 3, - std::sin(x[1] - 2 * x[0]), - 3, - x[1] * x[0], - -4 * x[1], - 2 * x[0] + 1, - 3, - -6 * x[0], - std::exp(x[1])}; - }); - - DiscreteFunctionInterpoler interpoler(mesh_2d, std::make_shared<DiscreteFunctionDescriptorP0>(), - function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); - - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + CellValue<double> cell_value{mesh_2d->connectivity()}; + parallel_for( + cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<Dimension>& x = xj[cell_id]; + cell_value[cell_id] = std::floor(std::exp(2 * x[0]) - 3 * x[1]); + }); + + DiscreteFunctionInterpoler interpoler(mesh_2d, std::make_shared<DiscreteFunctionDescriptorP0>(), + function_symbol_id); + std::shared_ptr discrete_function = interpoler.interpolate(); + + REQUIRE(same_cell_value(cell_value, + dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); + } + + SECTION("R_scalar_non_linear_2d") + { + auto [i_symbol, found] = symbol_table->find("R_scalar_non_linear_2d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + CellValue<double> cell_value{mesh_2d->connectivity()}; + parallel_for( + cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<Dimension>& x = xj[cell_id]; + cell_value[cell_id] = 2 * std::exp(x[0]) + 3 * x[1]; + }); + + DiscreteFunctionInterpoler interpoler(mesh_2d, std::make_shared<DiscreteFunctionDescriptorP0>(), + function_symbol_id); + std::shared_ptr discrete_function = interpoler.interpolate(); + + REQUIRE(same_cell_value(cell_value, + dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); + } + + SECTION("R1_non_linear_2d") + { + using DataType = TinyVector<1>; + + auto [i_symbol, found] = symbol_table->find("R1_non_linear_2d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + CellValue<DataType> cell_value{mesh_2d->connectivity()}; + parallel_for( + cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<Dimension>& x = xj[cell_id]; + cell_value[cell_id] = DataType{2 * std::exp(x[0])}; + }); + + DiscreteFunctionInterpoler interpoler(mesh_2d, std::make_shared<DiscreteFunctionDescriptorP0>(), + function_symbol_id); + std::shared_ptr discrete_function = interpoler.interpolate(); + + REQUIRE(same_cell_value(cell_value, + dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + } + + SECTION("R2_non_linear_2d") + { + using DataType = TinyVector<2>; + + auto [i_symbol, found] = symbol_table->find("R2_non_linear_2d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + CellValue<DataType> cell_value{mesh_2d->connectivity()}; + parallel_for( + cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<Dimension>& x = xj[cell_id]; + cell_value[cell_id] = DataType{2 * std::exp(x[0]), -3 * x[1]}; + }); + + DiscreteFunctionInterpoler interpoler(mesh_2d, std::make_shared<DiscreteFunctionDescriptorP0>(), + function_symbol_id); + std::shared_ptr discrete_function = interpoler.interpolate(); + + REQUIRE(same_cell_value(cell_value, + dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + } + + SECTION("R3_non_linear_2d") + { + using DataType = TinyVector<3>; + + auto [i_symbol, found] = symbol_table->find("R3_non_linear_2d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + CellValue<DataType> cell_value{mesh_2d->connectivity()}; + parallel_for( + cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<Dimension>& x = xj[cell_id]; + cell_value[cell_id] = DataType{2 * std::exp(x[0]) + 3, x[1] - 2, 3}; + }); + + DiscreteFunctionInterpoler interpoler(mesh_2d, std::make_shared<DiscreteFunctionDescriptorP0>(), + function_symbol_id); + std::shared_ptr discrete_function = interpoler.interpolate(); + + REQUIRE(same_cell_value(cell_value, + dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + } + + SECTION("R1x1_non_linear_2d") + { + using DataType = TinyMatrix<1>; + + auto [i_symbol, found] = symbol_table->find("R1x1_non_linear_2d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + CellValue<DataType> cell_value{mesh_2d->connectivity()}; + parallel_for( + cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<Dimension>& x = xj[cell_id]; + cell_value[cell_id] = DataType{2 * std::exp(x[0]) * std::sin(x[1]) + 3}; + }); + + DiscreteFunctionInterpoler interpoler(mesh_2d, std::make_shared<DiscreteFunctionDescriptorP0>(), + function_symbol_id); + std::shared_ptr discrete_function = interpoler.interpolate(); + + REQUIRE(same_cell_value(cell_value, + dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + } + + SECTION("R2x2_non_linear_2d") + { + using DataType = TinyMatrix<2>; + + auto [i_symbol, found] = symbol_table->find("R2x2_non_linear_2d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + CellValue<DataType> cell_value{mesh_2d->connectivity()}; + parallel_for( + cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<Dimension>& x = xj[cell_id]; + cell_value[cell_id] = + DataType{2 * std::exp(x[0]) * std::sin(x[1]) + 3, std::sin(x[1] - 2 * x[0]), 3, x[1] * x[0]}; + }); + + DiscreteFunctionInterpoler interpoler(mesh_2d, std::make_shared<DiscreteFunctionDescriptorP0>(), + function_symbol_id); + std::shared_ptr discrete_function = interpoler.interpolate(); + + REQUIRE(same_cell_value(cell_value, + dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + } + + SECTION("R3x3_non_linear_2d") + { + using DataType = TinyMatrix<3>; + + auto [i_symbol, found] = symbol_table->find("R3x3_non_linear_2d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + CellValue<DataType> cell_value{mesh_2d->connectivity()}; + parallel_for( + cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<Dimension>& x = xj[cell_id]; + + cell_value[cell_id] = DataType{2 * std::exp(x[0]) * std::sin(x[1]) + 3, + std::sin(x[1] - 2 * x[0]), + 3, + x[1] * x[0], + -4 * x[1], + 2 * x[0] + 1, + 3, + -6 * x[0], + std::exp(x[1])}; + }); + + DiscreteFunctionInterpoler interpoler(mesh_2d, std::make_shared<DiscreteFunctionDescriptorP0>(), + function_symbol_id); + std::shared_ptr discrete_function = interpoler.interpolate(); + + REQUIRE(same_cell_value(cell_value, + dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + } + } } } @@ -626,10 +642,16 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> (2 * exp(x[0]) * sin(x[1]) + 3, sin(x { constexpr size_t Dimension = 3; - const auto& mesh_3d = MeshDataBaseForTests::get().cartesianMesh3D(); - auto xj = MeshDataManager::instance().getMeshData(*mesh_3d).xj(); + std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); + + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_3d = named_mesh.mesh(); + + auto xj = MeshDataManager::instance().getMeshData(*mesh_3d).xj(); - std::string_view data = R"( + std::string_view data = R"( import math; let B_scalar_non_linear_3d: R^3 -> B, x -> (exp(2 * x[0])< 2*x[1]+x[2]); let N_scalar_non_linear_3d: R^3 -> N, x -> floor(3 * (x[0] + x[1]) * (x[0] + x[1]) + x[2] * x[2]); @@ -642,275 +664,277 @@ let R1x1_non_linear_3d: R^3 -> R^1x1, x -> (2 * exp(x[0]) * sin(x[1]) + 3 * x[2] let R2x2_non_linear_3d: R^3 -> R^2x2, x -> (2 * exp(x[0]) * sin(x[1]) + 3, sin(x[2] - 2 * x[0]), 3, x[1] * x[0] - x[2]); let R3x3_non_linear_3d: R^3 -> R^3x3, x -> (2 * exp(x[0]) * sin(x[1]) + 3, sin(x[1] - 2 * x[2]), 3, x[1] * x[2], -4*x[1], 2*x[2]+1, 3, -6*x[2], exp(x[1] + x[2])); )"; - TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"}; - - auto ast = ASTBuilder::build(input); - - ASTModulesImporter{*ast}; - ASTNodeTypeCleaner<language::import_instruction>{*ast}; - - ASTSymbolTableBuilder{*ast}; - ASTNodeDataTypeBuilder{*ast}; + TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"}; + + auto ast = ASTBuilder::build(input); + + ASTModulesImporter{*ast}; + ASTNodeTypeCleaner<language::import_instruction>{*ast}; - ASTNodeTypeCleaner<language::var_declaration>{*ast}; - ASTNodeTypeCleaner<language::fct_declaration>{*ast}; - ASTNodeExpressionBuilder{*ast}; + ASTSymbolTableBuilder{*ast}; + ASTNodeDataTypeBuilder{*ast}; + + ASTNodeTypeCleaner<language::var_declaration>{*ast}; + ASTNodeTypeCleaner<language::fct_declaration>{*ast}; + ASTNodeExpressionBuilder{*ast}; + + std::shared_ptr<SymbolTable> symbol_table = ast->m_symbol_table; + + TAO_PEGTL_NAMESPACE::position position{TAO_PEGTL_NAMESPACE::internal::iterator{"fixture"}, "fixture"}; + position.byte = data.size(); // ensure that variables are declared at this point - std::shared_ptr<SymbolTable> symbol_table = ast->m_symbol_table; + SECTION("B_scalar_non_linear_3d") + { + auto [i_symbol, found] = symbol_table->find("B_scalar_non_linear_3d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + CellValue<double> cell_value{mesh_3d->connectivity()}; + parallel_for( + cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<Dimension>& x = xj[cell_id]; + cell_value[cell_id] = std::exp(2 * x[0]) < 2 * x[1] + x[2]; + }); + + DiscreteFunctionInterpoler interpoler(mesh_3d, std::make_shared<DiscreteFunctionDescriptorP0>(), + function_symbol_id); + std::shared_ptr discrete_function = interpoler.interpolate(); + + REQUIRE(same_cell_value(cell_value, + dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); + } + + SECTION("N_scalar_non_linear_3d") + { + auto [i_symbol, found] = symbol_table->find("N_scalar_non_linear_3d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + CellValue<double> cell_value{mesh_3d->connectivity()}; + parallel_for( + cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<Dimension>& x = xj[cell_id]; + cell_value[cell_id] = std::floor(3 * (x[0] + x[1]) * (x[0] + x[1]) + x[2] * x[2]); + }); + + DiscreteFunctionInterpoler interpoler(mesh_3d, std::make_shared<DiscreteFunctionDescriptorP0>(), + function_symbol_id); + std::shared_ptr discrete_function = interpoler.interpolate(); + + REQUIRE(same_cell_value(cell_value, + dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); + } + + SECTION("Z_scalar_non_linear_3d") + { + auto [i_symbol, found] = symbol_table->find("Z_scalar_non_linear_3d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - TAO_PEGTL_NAMESPACE::position position{TAO_PEGTL_NAMESPACE::internal::iterator{"fixture"}, "fixture"}; - position.byte = data.size(); // ensure that variables are declared at this point - - SECTION("B_scalar_non_linear_3d") - { - auto [i_symbol, found] = symbol_table->find("B_scalar_non_linear_3d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); - - CellValue<double> cell_value{mesh_3d->connectivity()}; - parallel_for( - cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<Dimension>& x = xj[cell_id]; - cell_value[cell_id] = std::exp(2 * x[0]) < 2 * x[1] + x[2]; - }); - - DiscreteFunctionInterpoler interpoler(mesh_3d, std::make_shared<DiscreteFunctionDescriptorP0>(), - function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); - - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); - } - - SECTION("N_scalar_non_linear_3d") - { - auto [i_symbol, found] = symbol_table->find("N_scalar_non_linear_3d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); - - CellValue<double> cell_value{mesh_3d->connectivity()}; - parallel_for( - cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<Dimension>& x = xj[cell_id]; - cell_value[cell_id] = std::floor(3 * (x[0] + x[1]) * (x[0] + x[1]) + x[2] * x[2]); - }); - - DiscreteFunctionInterpoler interpoler(mesh_3d, std::make_shared<DiscreteFunctionDescriptorP0>(), - function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); - - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); - } - - SECTION("Z_scalar_non_linear_3d") - { - auto [i_symbol, found] = symbol_table->find("Z_scalar_non_linear_3d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); - - CellValue<double> cell_value{mesh_3d->connectivity()}; - parallel_for( - cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<Dimension>& x = xj[cell_id]; - cell_value[cell_id] = std::floor(std::exp(2 * x[0]) - 3 * x[1] + x[2]); - }); - - DiscreteFunctionInterpoler interpoler(mesh_3d, std::make_shared<DiscreteFunctionDescriptorP0>(), - function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); - - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); - } - - SECTION("R_scalar_non_linear_3d") - { - auto [i_symbol, found] = symbol_table->find("R_scalar_non_linear_3d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); - - CellValue<double> cell_value{mesh_3d->connectivity()}; - parallel_for( - cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<Dimension>& x = xj[cell_id]; - cell_value[cell_id] = 2 * std::exp(x[0] + x[2]) + 3 * x[1]; - }); - - DiscreteFunctionInterpoler interpoler(mesh_3d, std::make_shared<DiscreteFunctionDescriptorP0>(), - function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); - - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); - } - - SECTION("R1_non_linear_3d") - { - using DataType = TinyVector<1>; - - auto [i_symbol, found] = symbol_table->find("R1_non_linear_3d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); - - CellValue<DataType> cell_value{mesh_3d->connectivity()}; - parallel_for( - cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<Dimension>& x = xj[cell_id]; - cell_value[cell_id] = DataType{2 * std::exp(x[0]) + std::sin(x[1] + x[2])}; - }); - - DiscreteFunctionInterpoler interpoler(mesh_3d, std::make_shared<DiscreteFunctionDescriptorP0>(), - function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); - - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); - } - - SECTION("R2_non_linear_3d") - { - using DataType = TinyVector<2>; - - auto [i_symbol, found] = symbol_table->find("R2_non_linear_3d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); - - CellValue<DataType> cell_value{mesh_3d->connectivity()}; - parallel_for( - cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<Dimension>& x = xj[cell_id]; - cell_value[cell_id] = DataType{2 * std::exp(x[0]), -3 * x[1] * x[2]}; - }); - - DiscreteFunctionInterpoler interpoler(mesh_3d, std::make_shared<DiscreteFunctionDescriptorP0>(), - function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); - - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); - } - - SECTION("R3_non_linear_3d") - { - using DataType = TinyVector<3>; - - auto [i_symbol, found] = symbol_table->find("R3_non_linear_3d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); - - CellValue<DataType> cell_value{mesh_3d->connectivity()}; - parallel_for( - cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<Dimension>& x = xj[cell_id]; - cell_value[cell_id] = DataType{2 * std::exp(x[0]) + 3, x[1] - 2, 3 * x[2]}; - }); - - DiscreteFunctionInterpoler interpoler(mesh_3d, std::make_shared<DiscreteFunctionDescriptorP0>(), - function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); - - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); - } - - SECTION("R1x1_non_linear_3d") - { - using DataType = TinyMatrix<1>; - - auto [i_symbol, found] = symbol_table->find("R1x1_non_linear_3d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); - - CellValue<DataType> cell_value{mesh_3d->connectivity()}; - parallel_for( - cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<Dimension>& x = xj[cell_id]; - cell_value[cell_id] = DataType{2 * std::exp(x[0]) * std::sin(x[1]) + 3 * x[2]}; - }); - - DiscreteFunctionInterpoler interpoler(mesh_3d, std::make_shared<DiscreteFunctionDescriptorP0>(), - function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); - - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); - } - - SECTION("R2x2_non_linear_3d") - { - using DataType = TinyMatrix<2>; - - auto [i_symbol, found] = symbol_table->find("R2x2_non_linear_3d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); - - CellValue<DataType> cell_value{mesh_3d->connectivity()}; - parallel_for( - cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<Dimension>& x = xj[cell_id]; - cell_value[cell_id] = - DataType{2 * std::exp(x[0]) * std::sin(x[1]) + 3, std::sin(x[2] - 2 * x[0]), 3, x[1] * x[0] - x[2]}; - }); - - DiscreteFunctionInterpoler interpoler(mesh_3d, std::make_shared<DiscreteFunctionDescriptorP0>(), - function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); - - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); - } - - SECTION("R3x3_non_linear_3d") - { - using DataType = TinyMatrix<3>; - - auto [i_symbol, found] = symbol_table->find("R3x3_non_linear_3d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); - - CellValue<DataType> cell_value{mesh_3d->connectivity()}; - parallel_for( - cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<Dimension>& x = xj[cell_id]; - - cell_value[cell_id] = DataType{2 * std::exp(x[0]) * std::sin(x[1]) + 3, - std::sin(x[1] - 2 * x[2]), - 3, - x[1] * x[2], - -4 * x[1], - 2 * x[2] + 1, - 3, - -6 * x[2], - std::exp(x[1] + x[2])}; - }); - - DiscreteFunctionInterpoler interpoler(mesh_3d, std::make_shared<DiscreteFunctionDescriptorP0>(), - function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); - - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + CellValue<double> cell_value{mesh_3d->connectivity()}; + parallel_for( + cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<Dimension>& x = xj[cell_id]; + cell_value[cell_id] = std::floor(std::exp(2 * x[0]) - 3 * x[1] + x[2]); + }); + + DiscreteFunctionInterpoler interpoler(mesh_3d, std::make_shared<DiscreteFunctionDescriptorP0>(), + function_symbol_id); + std::shared_ptr discrete_function = interpoler.interpolate(); + + REQUIRE(same_cell_value(cell_value, + dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); + } + + SECTION("R_scalar_non_linear_3d") + { + auto [i_symbol, found] = symbol_table->find("R_scalar_non_linear_3d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + CellValue<double> cell_value{mesh_3d->connectivity()}; + parallel_for( + cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<Dimension>& x = xj[cell_id]; + cell_value[cell_id] = 2 * std::exp(x[0] + x[2]) + 3 * x[1]; + }); + + DiscreteFunctionInterpoler interpoler(mesh_3d, std::make_shared<DiscreteFunctionDescriptorP0>(), + function_symbol_id); + std::shared_ptr discrete_function = interpoler.interpolate(); + + REQUIRE(same_cell_value(cell_value, + dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); + } + + SECTION("R1_non_linear_3d") + { + using DataType = TinyVector<1>; + + auto [i_symbol, found] = symbol_table->find("R1_non_linear_3d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + CellValue<DataType> cell_value{mesh_3d->connectivity()}; + parallel_for( + cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<Dimension>& x = xj[cell_id]; + cell_value[cell_id] = DataType{2 * std::exp(x[0]) + std::sin(x[1] + x[2])}; + }); + + DiscreteFunctionInterpoler interpoler(mesh_3d, std::make_shared<DiscreteFunctionDescriptorP0>(), + function_symbol_id); + std::shared_ptr discrete_function = interpoler.interpolate(); + + REQUIRE(same_cell_value(cell_value, + dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + } + + SECTION("R2_non_linear_3d") + { + using DataType = TinyVector<2>; + + auto [i_symbol, found] = symbol_table->find("R2_non_linear_3d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + CellValue<DataType> cell_value{mesh_3d->connectivity()}; + parallel_for( + cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<Dimension>& x = xj[cell_id]; + cell_value[cell_id] = DataType{2 * std::exp(x[0]), -3 * x[1] * x[2]}; + }); + + DiscreteFunctionInterpoler interpoler(mesh_3d, std::make_shared<DiscreteFunctionDescriptorP0>(), + function_symbol_id); + std::shared_ptr discrete_function = interpoler.interpolate(); + + REQUIRE(same_cell_value(cell_value, + dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + } + + SECTION("R3_non_linear_3d") + { + using DataType = TinyVector<3>; + + auto [i_symbol, found] = symbol_table->find("R3_non_linear_3d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + CellValue<DataType> cell_value{mesh_3d->connectivity()}; + parallel_for( + cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<Dimension>& x = xj[cell_id]; + cell_value[cell_id] = DataType{2 * std::exp(x[0]) + 3, x[1] - 2, 3 * x[2]}; + }); + + DiscreteFunctionInterpoler interpoler(mesh_3d, std::make_shared<DiscreteFunctionDescriptorP0>(), + function_symbol_id); + std::shared_ptr discrete_function = interpoler.interpolate(); + + REQUIRE(same_cell_value(cell_value, + dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + } + + SECTION("R1x1_non_linear_3d") + { + using DataType = TinyMatrix<1>; + + auto [i_symbol, found] = symbol_table->find("R1x1_non_linear_3d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + CellValue<DataType> cell_value{mesh_3d->connectivity()}; + parallel_for( + cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<Dimension>& x = xj[cell_id]; + cell_value[cell_id] = DataType{2 * std::exp(x[0]) * std::sin(x[1]) + 3 * x[2]}; + }); + + DiscreteFunctionInterpoler interpoler(mesh_3d, std::make_shared<DiscreteFunctionDescriptorP0>(), + function_symbol_id); + std::shared_ptr discrete_function = interpoler.interpolate(); + + REQUIRE(same_cell_value(cell_value, + dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + } + + SECTION("R2x2_non_linear_3d") + { + using DataType = TinyMatrix<2>; + + auto [i_symbol, found] = symbol_table->find("R2x2_non_linear_3d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + CellValue<DataType> cell_value{mesh_3d->connectivity()}; + parallel_for( + cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<Dimension>& x = xj[cell_id]; + cell_value[cell_id] = + DataType{2 * std::exp(x[0]) * std::sin(x[1]) + 3, std::sin(x[2] - 2 * x[0]), 3, x[1] * x[0] - x[2]}; + }); + + DiscreteFunctionInterpoler interpoler(mesh_3d, std::make_shared<DiscreteFunctionDescriptorP0>(), + function_symbol_id); + std::shared_ptr discrete_function = interpoler.interpolate(); + + REQUIRE(same_cell_value(cell_value, + dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + } + + SECTION("R3x3_non_linear_3d") + { + using DataType = TinyMatrix<3>; + + auto [i_symbol, found] = symbol_table->find("R3x3_non_linear_3d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + CellValue<DataType> cell_value{mesh_3d->connectivity()}; + parallel_for( + cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<Dimension>& x = xj[cell_id]; + + cell_value[cell_id] = DataType{2 * std::exp(x[0]) * std::sin(x[1]) + 3, + std::sin(x[1] - 2 * x[2]), + 3, + x[1] * x[2], + -4 * x[1], + 2 * x[2] + 1, + 3, + -6 * x[2], + std::exp(x[1] + x[2])}; + }); + + DiscreteFunctionInterpoler interpoler(mesh_3d, std::make_shared<DiscreteFunctionDescriptorP0>(), + function_symbol_id); + std::shared_ptr discrete_function = interpoler.interpolate(); + + REQUIRE(same_cell_value(cell_value, + dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + } + } } } } diff --git a/tests/test_DiscreteFunctionP0.cpp b/tests/test_DiscreteFunctionP0.cpp index f8d7bb6ef78d027287cf7d721299f051ba7c7a98..7073def1e438a3a19df04723ba88349d3bb7d7b1 100644 --- a/tests/test_DiscreteFunctionP0.cpp +++ b/tests/test_DiscreteFunctionP0.cpp @@ -22,128 +22,147 @@ TEST_CASE("DiscreteFunctionP0", "[scheme]") { SECTION("1D") { - std::shared_ptr mesh = MeshDataBaseForTests::get().cartesianMesh1D(); - constexpr size_t Dimension = 1; - DiscreteFunctionP0<Dimension, double> f{mesh}; - REQUIRE(f.dataType() == ASTNodeDataType::double_t); - REQUIRE(f.descriptor().type() == DiscreteFunctionType::P0); + std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); + + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh = named_mesh.mesh(); + DiscreteFunctionP0<Dimension, double> f{mesh}; + REQUIRE(f.dataType() == ASTNodeDataType::double_t); + REQUIRE(f.descriptor().type() == DiscreteFunctionType::P0); - REQUIRE(f.mesh().get() == mesh.get()); + REQUIRE(f.mesh().get() == mesh.get()); - DiscreteFunctionP0 g{f}; - REQUIRE(g.dataType() == ASTNodeDataType::double_t); - REQUIRE(g.descriptor().type() == DiscreteFunctionType::P0); + DiscreteFunctionP0 g{f}; + REQUIRE(g.dataType() == ASTNodeDataType::double_t); + REQUIRE(g.descriptor().type() == DiscreteFunctionType::P0); - CellValue<TinyVector<Dimension>> h_values{mesh->connectivity()}; - h_values.fill(ZeroType{}); + CellValue<TinyVector<Dimension>> h_values{mesh->connectivity()}; + h_values.fill(ZeroType{}); - DiscreteFunctionP0 zero{mesh, [&] { - CellValue<TinyVector<Dimension>> cell_value{mesh->connectivity()}; - cell_value.fill(ZeroType{}); - return cell_value; - }()}; + DiscreteFunctionP0 zero{mesh, [&] { + CellValue<TinyVector<Dimension>> cell_value{mesh->connectivity()}; + cell_value.fill(ZeroType{}); + return cell_value; + }()}; - DiscreteFunctionP0 h{mesh, h_values}; - REQUIRE(same_values(h, zero)); - REQUIRE(same_values(h, h_values)); + DiscreteFunctionP0 h{mesh, h_values}; + REQUIRE(same_values(h, zero)); + REQUIRE(same_values(h, h_values)); - DiscreteFunctionP0<Dimension, TinyVector<Dimension>> shallow_h{mesh}; - shallow_h = h; + DiscreteFunctionP0<Dimension, TinyVector<Dimension>> shallow_h{mesh}; + shallow_h = h; - copy_to(MeshDataManager::instance().getMeshData(*mesh).xj(), h_values); + copy_to(MeshDataManager::instance().getMeshData(*mesh).xj(), h_values); - REQUIRE(same_values(shallow_h, h_values)); - REQUIRE(same_values(h, h_values)); - REQUIRE(not same_values(h, zero)); + REQUIRE(same_values(shallow_h, h_values)); + REQUIRE(same_values(h, h_values)); + REQUIRE(not same_values(h, zero)); - DiscreteFunctionP0 moved_h{std::move(h)}; - REQUIRE(same_values(moved_h, h_values)); + DiscreteFunctionP0 moved_h{std::move(h)}; + REQUIRE(same_values(moved_h, h_values)); + } + } } SECTION("2D") { - std::shared_ptr mesh = MeshDataBaseForTests::get().cartesianMesh2D(); - constexpr size_t Dimension = 2; - DiscreteFunctionP0<Dimension, double> f{mesh}; - REQUIRE(f.dataType() == ASTNodeDataType::double_t); - REQUIRE(f.descriptor().type() == DiscreteFunctionType::P0); + std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); + + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh = named_mesh.mesh(); + DiscreteFunctionP0<Dimension, double> f{mesh}; + REQUIRE(f.dataType() == ASTNodeDataType::double_t); + REQUIRE(f.descriptor().type() == DiscreteFunctionType::P0); - REQUIRE(f.mesh().get() == mesh.get()); + REQUIRE(f.mesh().get() == mesh.get()); - DiscreteFunctionP0 g{f}; - REQUIRE(g.dataType() == ASTNodeDataType::double_t); - REQUIRE(g.descriptor().type() == DiscreteFunctionType::P0); + DiscreteFunctionP0 g{f}; + REQUIRE(g.dataType() == ASTNodeDataType::double_t); + REQUIRE(g.descriptor().type() == DiscreteFunctionType::P0); - CellValue<TinyVector<Dimension>> h_values{mesh->connectivity()}; - h_values.fill(ZeroType{}); + CellValue<TinyVector<Dimension>> h_values{mesh->connectivity()}; + h_values.fill(ZeroType{}); - DiscreteFunctionP0 zero{mesh, [&] { - CellValue<TinyVector<Dimension>> cell_value{mesh->connectivity()}; - cell_value.fill(ZeroType{}); - return cell_value; - }()}; + DiscreteFunctionP0 zero{mesh, [&] { + CellValue<TinyVector<Dimension>> cell_value{mesh->connectivity()}; + cell_value.fill(ZeroType{}); + return cell_value; + }()}; - DiscreteFunctionP0 h{mesh, h_values}; - REQUIRE(same_values(h, zero)); - REQUIRE(same_values(h, h_values)); + DiscreteFunctionP0 h{mesh, h_values}; + REQUIRE(same_values(h, zero)); + REQUIRE(same_values(h, h_values)); - DiscreteFunctionP0<Dimension, TinyVector<Dimension>> shallow_h{mesh}; - shallow_h = h; + DiscreteFunctionP0<Dimension, TinyVector<Dimension>> shallow_h{mesh}; + shallow_h = h; - copy_to(MeshDataManager::instance().getMeshData(*mesh).xj(), h_values); + copy_to(MeshDataManager::instance().getMeshData(*mesh).xj(), h_values); - REQUIRE(same_values(shallow_h, h_values)); - REQUIRE(same_values(h, h_values)); - REQUIRE(not same_values(h, zero)); + REQUIRE(same_values(shallow_h, h_values)); + REQUIRE(same_values(h, h_values)); + REQUIRE(not same_values(h, zero)); - DiscreteFunctionP0 moved_h{std::move(h)}; - REQUIRE(same_values(moved_h, h_values)); + DiscreteFunctionP0 moved_h{std::move(h)}; + REQUIRE(same_values(moved_h, h_values)); + } + } } SECTION("3D") { - std::shared_ptr mesh = MeshDataBaseForTests::get().cartesianMesh3D(); - constexpr size_t Dimension = 3; - DiscreteFunctionP0<Dimension, double> f{mesh}; - REQUIRE(f.dataType() == ASTNodeDataType::double_t); - REQUIRE(f.descriptor().type() == DiscreteFunctionType::P0); + std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); + + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh = named_mesh.mesh(); + + DiscreteFunctionP0<Dimension, double> f{mesh}; + REQUIRE(f.dataType() == ASTNodeDataType::double_t); + REQUIRE(f.descriptor().type() == DiscreteFunctionType::P0); - REQUIRE(f.mesh().get() == mesh.get()); + REQUIRE(f.mesh().get() == mesh.get()); - DiscreteFunctionP0 g{f}; - REQUIRE(g.dataType() == ASTNodeDataType::double_t); - REQUIRE(g.descriptor().type() == DiscreteFunctionType::P0); + DiscreteFunctionP0 g{f}; + REQUIRE(g.dataType() == ASTNodeDataType::double_t); + REQUIRE(g.descriptor().type() == DiscreteFunctionType::P0); - CellValue<TinyVector<Dimension>> h_values{mesh->connectivity()}; - h_values.fill(ZeroType{}); + CellValue<TinyVector<Dimension>> h_values{mesh->connectivity()}; + h_values.fill(ZeroType{}); - DiscreteFunctionP0 zero{mesh, [&] { - CellValue<TinyVector<Dimension>> cell_value{mesh->connectivity()}; - cell_value.fill(ZeroType{}); - return cell_value; - }()}; + DiscreteFunctionP0 zero{mesh, [&] { + CellValue<TinyVector<Dimension>> cell_value{mesh->connectivity()}; + cell_value.fill(ZeroType{}); + return cell_value; + }()}; - DiscreteFunctionP0 h{mesh, h_values}; - REQUIRE(same_values(h, zero)); - REQUIRE(same_values(h, h_values)); + DiscreteFunctionP0 h{mesh, h_values}; + REQUIRE(same_values(h, zero)); + REQUIRE(same_values(h, h_values)); - DiscreteFunctionP0<Dimension, TinyVector<Dimension>> shallow_h{mesh}; - shallow_h = h; + DiscreteFunctionP0<Dimension, TinyVector<Dimension>> shallow_h{mesh}; + shallow_h = h; - copy_to(MeshDataManager::instance().getMeshData(*mesh).xj(), h_values); + copy_to(MeshDataManager::instance().getMeshData(*mesh).xj(), h_values); - REQUIRE(same_values(shallow_h, h_values)); - REQUIRE(same_values(h, h_values)); - REQUIRE(not same_values(h, zero)); + REQUIRE(same_values(shallow_h, h_values)); + REQUIRE(same_values(h, h_values)); + REQUIRE(not same_values(h, zero)); - DiscreteFunctionP0 moved_h{std::move(h)}; - REQUIRE(same_values(moved_h, h_values)); + DiscreteFunctionP0 moved_h{std::move(h)}; + REQUIRE(same_values(moved_h, h_values)); + } + } } } @@ -161,65 +180,89 @@ TEST_CASE("DiscreteFunctionP0", "[scheme]") SECTION("1D") { - std::shared_ptr mesh = MeshDataBaseForTests::get().cartesianMesh1D(); constexpr size_t Dimension = 1; - DiscreteFunctionP0<Dimension, double> f{mesh}; - f.fill(3); + std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); + + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh = named_mesh.mesh(); + + DiscreteFunctionP0<Dimension, double> f{mesh}; + f.fill(3); - REQUIRE(all_values_equal(f, 3)); + REQUIRE(all_values_equal(f, 3)); - DiscreteFunctionP0<Dimension, TinyVector<3>> v{mesh}; - v.fill(TinyVector<3>{1, 2, 3}); + DiscreteFunctionP0<Dimension, TinyVector<3>> v{mesh}; + v.fill(TinyVector<3>{1, 2, 3}); - REQUIRE(all_values_equal(v, TinyVector<3>{1, 2, 3})); + REQUIRE(all_values_equal(v, TinyVector<3>{1, 2, 3})); - DiscreteFunctionP0<Dimension, TinyMatrix<3>> A{mesh}; - A.fill(TinyMatrix<3>{1, 2, 3, 4, 5, 6, 7, 8, 9}); + DiscreteFunctionP0<Dimension, TinyMatrix<3>> A{mesh}; + A.fill(TinyMatrix<3>{1, 2, 3, 4, 5, 6, 7, 8, 9}); - REQUIRE(all_values_equal(A, TinyMatrix<3>{1, 2, 3, 4, 5, 6, 7, 8, 9})); + REQUIRE(all_values_equal(A, TinyMatrix<3>{1, 2, 3, 4, 5, 6, 7, 8, 9})); + } + } } SECTION("2D") { - std::shared_ptr mesh = MeshDataBaseForTests::get().cartesianMesh2D(); constexpr size_t Dimension = 2; - DiscreteFunctionP0<Dimension, double> f{mesh}; - f.fill(3); + std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); + + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh = named_mesh.mesh(); + + DiscreteFunctionP0<Dimension, double> f{mesh}; + f.fill(3); - REQUIRE(all_values_equal(f, 3)); + REQUIRE(all_values_equal(f, 3)); - DiscreteFunctionP0<Dimension, TinyVector<3>> v{mesh}; - v.fill(TinyVector<3>{1, 2, 3}); + DiscreteFunctionP0<Dimension, TinyVector<3>> v{mesh}; + v.fill(TinyVector<3>{1, 2, 3}); - REQUIRE(all_values_equal(v, TinyVector<3>{1, 2, 3})); + REQUIRE(all_values_equal(v, TinyVector<3>{1, 2, 3})); - DiscreteFunctionP0<Dimension, TinyMatrix<3>> A{mesh}; - A.fill(TinyMatrix<3>{1, 2, 3, 4, 5, 6, 7, 8, 9}); + DiscreteFunctionP0<Dimension, TinyMatrix<3>> A{mesh}; + A.fill(TinyMatrix<3>{1, 2, 3, 4, 5, 6, 7, 8, 9}); - REQUIRE(all_values_equal(A, TinyMatrix<3>{1, 2, 3, 4, 5, 6, 7, 8, 9})); + REQUIRE(all_values_equal(A, TinyMatrix<3>{1, 2, 3, 4, 5, 6, 7, 8, 9})); + } + } } SECTION("3D") { - std::shared_ptr mesh = MeshDataBaseForTests::get().cartesianMesh3D(); constexpr size_t Dimension = 3; - DiscreteFunctionP0<Dimension, double> f{mesh}; - f.fill(3); + std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); + + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh = named_mesh.mesh(); + + DiscreteFunctionP0<Dimension, double> f{mesh}; + f.fill(3); - REQUIRE(all_values_equal(f, 3)); + REQUIRE(all_values_equal(f, 3)); - DiscreteFunctionP0<Dimension, TinyVector<3>> v{mesh}; - v.fill(TinyVector<3>{1, 2, 3}); + DiscreteFunctionP0<Dimension, TinyVector<3>> v{mesh}; + v.fill(TinyVector<3>{1, 2, 3}); - REQUIRE(all_values_equal(v, TinyVector<3>{1, 2, 3})); + REQUIRE(all_values_equal(v, TinyVector<3>{1, 2, 3})); - DiscreteFunctionP0<Dimension, TinyMatrix<3>> A{mesh}; - A.fill(TinyMatrix<3>{1, 2, 3, 4, 5, 6, 7, 8, 9}); + DiscreteFunctionP0<Dimension, TinyMatrix<3>> A{mesh}; + A.fill(TinyMatrix<3>{1, 2, 3, 4, 5, 6, 7, 8, 9}); - REQUIRE(all_values_equal(A, TinyMatrix<3>{1, 2, 3, 4, 5, 6, 7, 8, 9})); + REQUIRE(all_values_equal(A, TinyMatrix<3>{1, 2, 3, 4, 5, 6, 7, 8, 9})); + } + } } } @@ -237,286 +280,307 @@ TEST_CASE("DiscreteFunctionP0", "[scheme]") SECTION("1D") { - std::shared_ptr mesh = MeshDataBaseForTests::get().cartesianMesh1D(); - constexpr size_t Dimension = 1; - SECTION("scalar") - { - const size_t value = parallel::rank() + 1; - const size_t zero = 0; + std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); + + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh = named_mesh.mesh(); - DiscreteFunctionP0<Dimension, size_t> f{mesh}; - f.fill(value); + SECTION("scalar") + { + const size_t value = parallel::rank() + 1; + const size_t zero = 0; - REQUIRE(all_values_equal(f, value)); + DiscreteFunctionP0<Dimension, size_t> f{mesh}; + f.fill(value); - DiscreteFunctionP0 g = copy(f); - f.fill(zero); + REQUIRE(all_values_equal(f, value)); - REQUIRE(all_values_equal(f, zero)); - REQUIRE(all_values_equal(g, value)); + DiscreteFunctionP0 g = copy(f); + f.fill(zero); - copy_to(g, f); - g.fill(zero); + REQUIRE(all_values_equal(f, zero)); + REQUIRE(all_values_equal(g, value)); - DiscreteFunctionP0<Dimension, const size_t> h = copy(f); + copy_to(g, f); + g.fill(zero); - REQUIRE(all_values_equal(f, value)); - REQUIRE(all_values_equal(g, zero)); - REQUIRE(all_values_equal(h, value)); + DiscreteFunctionP0<Dimension, const size_t> h = copy(f); - copy_to(h, g); + REQUIRE(all_values_equal(f, value)); + REQUIRE(all_values_equal(g, zero)); + REQUIRE(all_values_equal(h, value)); - REQUIRE(all_values_equal(g, value)); - } + copy_to(h, g); - SECTION("vector") - { - const TinyVector<2, size_t> value{parallel::rank() + 1, 3}; - const TinyVector<2, size_t> zero{ZeroType{}}; - DiscreteFunctionP0<Dimension, TinyVector<2, size_t>> f{mesh}; - f.fill(value); + REQUIRE(all_values_equal(g, value)); + } - REQUIRE(all_values_equal(f, value)); + SECTION("vector") + { + const TinyVector<2, size_t> value{parallel::rank() + 1, 3}; + const TinyVector<2, size_t> zero{ZeroType{}}; + DiscreteFunctionP0<Dimension, TinyVector<2, size_t>> f{mesh}; + f.fill(value); - DiscreteFunctionP0 g = copy(f); - f.fill(zero); + REQUIRE(all_values_equal(f, value)); - REQUIRE(all_values_equal(f, zero)); - REQUIRE(all_values_equal(g, value)); + DiscreteFunctionP0 g = copy(f); + f.fill(zero); - copy_to(g, f); - g.fill(zero); + REQUIRE(all_values_equal(f, zero)); + REQUIRE(all_values_equal(g, value)); - DiscreteFunctionP0<Dimension, const TinyVector<2, size_t>> h = copy(f); + copy_to(g, f); + g.fill(zero); - REQUIRE(all_values_equal(f, value)); - REQUIRE(all_values_equal(g, zero)); - REQUIRE(all_values_equal(h, value)); + DiscreteFunctionP0<Dimension, const TinyVector<2, size_t>> h = copy(f); - copy_to(h, g); + REQUIRE(all_values_equal(f, value)); + REQUIRE(all_values_equal(g, zero)); + REQUIRE(all_values_equal(h, value)); - REQUIRE(all_values_equal(g, value)); - } + copy_to(h, g); - SECTION("matrix") - { - const TinyMatrix<3, 3, size_t> value{1, 2, 3, 4, 5, 6, 7, 8, 9}; - const TinyMatrix<3, 3, size_t> zero{ZeroType{}}; - DiscreteFunctionP0<Dimension, TinyMatrix<3, 3, size_t>> f{mesh}; - f.fill(value); + REQUIRE(all_values_equal(g, value)); + } + + SECTION("matrix") + { + const TinyMatrix<3, 3, size_t> value{1, 2, 3, 4, 5, 6, 7, 8, 9}; + const TinyMatrix<3, 3, size_t> zero{ZeroType{}}; + DiscreteFunctionP0<Dimension, TinyMatrix<3, 3, size_t>> f{mesh}; + f.fill(value); - REQUIRE(all_values_equal(f, value)); + REQUIRE(all_values_equal(f, value)); - DiscreteFunctionP0 g = copy(f); - f.fill(zero); + DiscreteFunctionP0 g = copy(f); + f.fill(zero); - REQUIRE(all_values_equal(f, zero)); - REQUIRE(all_values_equal(g, value)); + REQUIRE(all_values_equal(f, zero)); + REQUIRE(all_values_equal(g, value)); - copy_to(g, f); - g.fill(zero); + copy_to(g, f); + g.fill(zero); - DiscreteFunctionP0<Dimension, const TinyMatrix<3, 3, size_t>> h = copy(f); + DiscreteFunctionP0<Dimension, const TinyMatrix<3, 3, size_t>> h = copy(f); - REQUIRE(all_values_equal(f, value)); - REQUIRE(all_values_equal(g, zero)); - REQUIRE(all_values_equal(h, value)); + REQUIRE(all_values_equal(f, value)); + REQUIRE(all_values_equal(g, zero)); + REQUIRE(all_values_equal(h, value)); - copy_to(h, g); + copy_to(h, g); - REQUIRE(all_values_equal(g, value)); + REQUIRE(all_values_equal(g, value)); + } + } } } SECTION("2D") { - std::shared_ptr mesh = MeshDataBaseForTests::get().cartesianMesh2D(); - constexpr size_t Dimension = 2; - SECTION("scalar") - { - const size_t value = parallel::rank() + 1; - const size_t zero = 0; + std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); + + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh = named_mesh.mesh(); - DiscreteFunctionP0<Dimension, size_t> f{mesh}; - f.fill(value); + SECTION("scalar") + { + const size_t value = parallel::rank() + 1; + const size_t zero = 0; - REQUIRE(all_values_equal(f, value)); + DiscreteFunctionP0<Dimension, size_t> f{mesh}; + f.fill(value); - DiscreteFunctionP0 g = copy(f); - f.fill(zero); + REQUIRE(all_values_equal(f, value)); - REQUIRE(all_values_equal(f, zero)); - REQUIRE(all_values_equal(g, value)); + DiscreteFunctionP0 g = copy(f); + f.fill(zero); - copy_to(g, f); - g.fill(zero); + REQUIRE(all_values_equal(f, zero)); + REQUIRE(all_values_equal(g, value)); - DiscreteFunctionP0<Dimension, const size_t> h = copy(f); + copy_to(g, f); + g.fill(zero); - REQUIRE(all_values_equal(f, value)); - REQUIRE(all_values_equal(g, zero)); - REQUIRE(all_values_equal(h, value)); + DiscreteFunctionP0<Dimension, const size_t> h = copy(f); - copy_to(h, g); + REQUIRE(all_values_equal(f, value)); + REQUIRE(all_values_equal(g, zero)); + REQUIRE(all_values_equal(h, value)); - REQUIRE(all_values_equal(g, value)); - } + copy_to(h, g); - SECTION("vector") - { - const TinyVector<2, size_t> value{parallel::rank() + 1, 3}; - const TinyVector<2, size_t> zero{ZeroType{}}; - DiscreteFunctionP0<Dimension, TinyVector<2, size_t>> f{mesh}; - f.fill(value); + REQUIRE(all_values_equal(g, value)); + } - REQUIRE(all_values_equal(f, value)); + SECTION("vector") + { + const TinyVector<2, size_t> value{parallel::rank() + 1, 3}; + const TinyVector<2, size_t> zero{ZeroType{}}; + DiscreteFunctionP0<Dimension, TinyVector<2, size_t>> f{mesh}; + f.fill(value); - DiscreteFunctionP0 g = copy(f); - f.fill(zero); + REQUIRE(all_values_equal(f, value)); - REQUIRE(all_values_equal(f, zero)); - REQUIRE(all_values_equal(g, value)); + DiscreteFunctionP0 g = copy(f); + f.fill(zero); - copy_to(g, f); - g.fill(zero); + REQUIRE(all_values_equal(f, zero)); + REQUIRE(all_values_equal(g, value)); - DiscreteFunctionP0<Dimension, const TinyVector<2, size_t>> h = copy(f); + copy_to(g, f); + g.fill(zero); - REQUIRE(all_values_equal(f, value)); - REQUIRE(all_values_equal(g, zero)); - REQUIRE(all_values_equal(h, value)); + DiscreteFunctionP0<Dimension, const TinyVector<2, size_t>> h = copy(f); - copy_to(h, g); + REQUIRE(all_values_equal(f, value)); + REQUIRE(all_values_equal(g, zero)); + REQUIRE(all_values_equal(h, value)); - REQUIRE(all_values_equal(g, value)); - } + copy_to(h, g); - SECTION("matrix") - { - const TinyMatrix<3, 3, size_t> value{1, 2, 3, 4, 5, 6, 7, 8, 9}; - const TinyMatrix<3, 3, size_t> zero{ZeroType{}}; - DiscreteFunctionP0<Dimension, TinyMatrix<3, 3, size_t>> f{mesh}; - f.fill(value); + REQUIRE(all_values_equal(g, value)); + } + + SECTION("matrix") + { + const TinyMatrix<3, 3, size_t> value{1, 2, 3, 4, 5, 6, 7, 8, 9}; + const TinyMatrix<3, 3, size_t> zero{ZeroType{}}; + DiscreteFunctionP0<Dimension, TinyMatrix<3, 3, size_t>> f{mesh}; + f.fill(value); - REQUIRE(all_values_equal(f, value)); + REQUIRE(all_values_equal(f, value)); - DiscreteFunctionP0 g = copy(f); - f.fill(zero); + DiscreteFunctionP0 g = copy(f); + f.fill(zero); - REQUIRE(all_values_equal(f, zero)); - REQUIRE(all_values_equal(g, value)); + REQUIRE(all_values_equal(f, zero)); + REQUIRE(all_values_equal(g, value)); - copy_to(g, f); - g.fill(zero); + copy_to(g, f); + g.fill(zero); - DiscreteFunctionP0<Dimension, const TinyMatrix<3, 3, size_t>> h = copy(f); + DiscreteFunctionP0<Dimension, const TinyMatrix<3, 3, size_t>> h = copy(f); - REQUIRE(all_values_equal(f, value)); - REQUIRE(all_values_equal(g, zero)); - REQUIRE(all_values_equal(h, value)); + REQUIRE(all_values_equal(f, value)); + REQUIRE(all_values_equal(g, zero)); + REQUIRE(all_values_equal(h, value)); - copy_to(h, g); + copy_to(h, g); - REQUIRE(all_values_equal(g, value)); + REQUIRE(all_values_equal(g, value)); + } + } } } SECTION("3D") { - std::shared_ptr mesh = MeshDataBaseForTests::get().cartesianMesh3D(); - constexpr size_t Dimension = 3; - SECTION("scalar") - { - const size_t value = parallel::rank() + 1; - const size_t zero = 0; + std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); + + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh = named_mesh.mesh(); - DiscreteFunctionP0<Dimension, size_t> f{mesh}; - f.fill(value); + SECTION("scalar") + { + const size_t value = parallel::rank() + 1; + const size_t zero = 0; - REQUIRE(all_values_equal(f, value)); + DiscreteFunctionP0<Dimension, size_t> f{mesh}; + f.fill(value); - DiscreteFunctionP0 g = copy(f); - f.fill(zero); + REQUIRE(all_values_equal(f, value)); - REQUIRE(all_values_equal(f, zero)); - REQUIRE(all_values_equal(g, value)); + DiscreteFunctionP0 g = copy(f); + f.fill(zero); - copy_to(g, f); - g.fill(zero); + REQUIRE(all_values_equal(f, zero)); + REQUIRE(all_values_equal(g, value)); - DiscreteFunctionP0<Dimension, const size_t> h = copy(f); + copy_to(g, f); + g.fill(zero); - REQUIRE(all_values_equal(f, value)); - REQUIRE(all_values_equal(g, zero)); - REQUIRE(all_values_equal(h, value)); + DiscreteFunctionP0<Dimension, const size_t> h = copy(f); - copy_to(h, g); + REQUIRE(all_values_equal(f, value)); + REQUIRE(all_values_equal(g, zero)); + REQUIRE(all_values_equal(h, value)); - REQUIRE(all_values_equal(g, value)); - } + copy_to(h, g); - SECTION("vector") - { - const TinyVector<2, size_t> value{parallel::rank() + 1, 3}; - const TinyVector<2, size_t> zero{ZeroType{}}; - DiscreteFunctionP0<Dimension, TinyVector<2, size_t>> f{mesh}; - f.fill(value); + REQUIRE(all_values_equal(g, value)); + } - REQUIRE(all_values_equal(f, value)); + SECTION("vector") + { + const TinyVector<2, size_t> value{parallel::rank() + 1, 3}; + const TinyVector<2, size_t> zero{ZeroType{}}; + DiscreteFunctionP0<Dimension, TinyVector<2, size_t>> f{mesh}; + f.fill(value); - DiscreteFunctionP0 g = copy(f); - f.fill(zero); + REQUIRE(all_values_equal(f, value)); - REQUIRE(all_values_equal(f, zero)); - REQUIRE(all_values_equal(g, value)); + DiscreteFunctionP0 g = copy(f); + f.fill(zero); - copy_to(g, f); - g.fill(zero); + REQUIRE(all_values_equal(f, zero)); + REQUIRE(all_values_equal(g, value)); - DiscreteFunctionP0<Dimension, const TinyVector<2, size_t>> h = copy(f); + copy_to(g, f); + g.fill(zero); - REQUIRE(all_values_equal(f, value)); - REQUIRE(all_values_equal(g, zero)); - REQUIRE(all_values_equal(h, value)); + DiscreteFunctionP0<Dimension, const TinyVector<2, size_t>> h = copy(f); - copy_to(h, g); + REQUIRE(all_values_equal(f, value)); + REQUIRE(all_values_equal(g, zero)); + REQUIRE(all_values_equal(h, value)); - REQUIRE(all_values_equal(g, value)); - } + copy_to(h, g); - SECTION("matrix") - { - const TinyMatrix<3, 3, size_t> value{1, 2, 3, 4, 5, 6, 7, 8, 9}; - const TinyMatrix<3, 3, size_t> zero{ZeroType{}}; - DiscreteFunctionP0<Dimension, TinyMatrix<3, 3, size_t>> f{mesh}; - f.fill(value); + REQUIRE(all_values_equal(g, value)); + } + + SECTION("matrix") + { + const TinyMatrix<3, 3, size_t> value{1, 2, 3, 4, 5, 6, 7, 8, 9}; + const TinyMatrix<3, 3, size_t> zero{ZeroType{}}; + DiscreteFunctionP0<Dimension, TinyMatrix<3, 3, size_t>> f{mesh}; + f.fill(value); - REQUIRE(all_values_equal(f, value)); + REQUIRE(all_values_equal(f, value)); - DiscreteFunctionP0 g = copy(f); - f.fill(zero); + DiscreteFunctionP0 g = copy(f); + f.fill(zero); - REQUIRE(all_values_equal(f, zero)); - REQUIRE(all_values_equal(g, value)); + REQUIRE(all_values_equal(f, zero)); + REQUIRE(all_values_equal(g, value)); - copy_to(g, f); - g.fill(zero); + copy_to(g, f); + g.fill(zero); - DiscreteFunctionP0<Dimension, const TinyMatrix<3, 3, size_t>> h = copy(f); + DiscreteFunctionP0<Dimension, const TinyMatrix<3, 3, size_t>> h = copy(f); - REQUIRE(all_values_equal(f, value)); - REQUIRE(all_values_equal(g, zero)); - REQUIRE(all_values_equal(h, value)); + REQUIRE(all_values_equal(f, value)); + REQUIRE(all_values_equal(g, zero)); + REQUIRE(all_values_equal(h, value)); - copy_to(h, g); + copy_to(h, g); - REQUIRE(all_values_equal(g, value)); + REQUIRE(all_values_equal(g, value)); + } + } } } } @@ -525,75 +589,81 @@ TEST_CASE("DiscreteFunctionP0", "[scheme]") { SECTION("1D") { - std::shared_ptr mesh = MeshDataBaseForTests::get().cartesianMesh1D(); - constexpr size_t Dimension = 1; + std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - auto xj = MeshDataManager::instance().getMeshData(*mesh).xj(); - - SECTION("unary minus") - { - SECTION("scalar functions") + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) { - DiscreteFunctionP0<Dimension, double> f{mesh}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - const double x = xj[cell_id][0]; - f[cell_id] = 2 * x + 1; - }); + auto mesh = named_mesh.mesh(); - DiscreteFunctionP0<Dimension, const double> const_f = f; + auto xj = MeshDataManager::instance().getMeshData(*mesh).xj(); - Array<double> minus_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { minus_values[cell_id] = -f[cell_id]; }); + SECTION("unary minus") + { + SECTION("scalar functions") + { + DiscreteFunctionP0<Dimension, double> f{mesh}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + const double x = xj[cell_id][0]; + f[cell_id] = 2 * x + 1; + }); - REQUIRE(same_values(-f, minus_values)); - REQUIRE(same_values(-const_f, minus_values)); - } + DiscreteFunctionP0<Dimension, const double> const_f = f; - SECTION("vector functions") - { - constexpr std::uint64_t VectorDimension = 2; + Array<double> minus_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { minus_values[cell_id] = -f[cell_id]; }); - DiscreteFunctionP0<Dimension, TinyVector<VectorDimension>> f{mesh}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - const double x = xj[cell_id][0]; - const TinyVector<VectorDimension> X{x, 2 - x}; - f[cell_id] = 2 * X + TinyVector<2>{1, 2}; - }); + REQUIRE(same_values(-f, minus_values)); + REQUIRE(same_values(-const_f, minus_values)); + } - DiscreteFunctionP0<Dimension, const TinyVector<VectorDimension>> const_f = f; + SECTION("vector functions") + { + constexpr std::uint64_t VectorDimension = 2; - Array<TinyVector<VectorDimension>> minus_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { minus_values[cell_id] = -f[cell_id]; }); + DiscreteFunctionP0<Dimension, TinyVector<VectorDimension>> f{mesh}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + const double x = xj[cell_id][0]; + const TinyVector<VectorDimension> X{x, 2 - x}; + f[cell_id] = 2 * X + TinyVector<2>{1, 2}; + }); - REQUIRE(same_values(-f, minus_values)); - REQUIRE(same_values(-const_f, minus_values)); - } + DiscreteFunctionP0<Dimension, const TinyVector<VectorDimension>> const_f = f; - SECTION("matrix functions") - { - constexpr std::uint64_t MatrixDimension = 2; + Array<TinyVector<VectorDimension>> minus_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { minus_values[cell_id] = -f[cell_id]; }); - DiscreteFunctionP0<Dimension, TinyMatrix<MatrixDimension>> f{mesh}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - const double x = xj[cell_id][0]; - const TinyMatrix<MatrixDimension> A{x, 2 - x, 2 * x, x * x - 3}; - f[cell_id] = 2 * A + TinyMatrix<2>{1, 2, 3, 4}; - }); + REQUIRE(same_values(-f, minus_values)); + REQUIRE(same_values(-const_f, minus_values)); + } - DiscreteFunctionP0<Dimension, const TinyMatrix<MatrixDimension>> const_f = f; + SECTION("matrix functions") + { + constexpr std::uint64_t MatrixDimension = 2; - Array<TinyMatrix<MatrixDimension>> minus_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { minus_values[cell_id] = -f[cell_id]; }); + DiscreteFunctionP0<Dimension, TinyMatrix<MatrixDimension>> f{mesh}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + const double x = xj[cell_id][0]; + const TinyMatrix<MatrixDimension> A{x, 2 - x, 2 * x, x * x - 3}; + f[cell_id] = 2 * A + TinyMatrix<2>{1, 2, 3, 4}; + }); + + DiscreteFunctionP0<Dimension, const TinyMatrix<MatrixDimension>> const_f = f; + + Array<TinyMatrix<MatrixDimension>> minus_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { minus_values[cell_id] = -f[cell_id]; }); - REQUIRE(same_values(-f, minus_values)); - REQUIRE(same_values(-const_f, minus_values)); + REQUIRE(same_values(-f, minus_values)); + REQUIRE(same_values(-const_f, minus_values)); + } + } } } } @@ -603,2839 +673,2937 @@ TEST_CASE("DiscreteFunctionP0", "[scheme]") { SECTION("1D") { - std::shared_ptr mesh = MeshDataBaseForTests::get().cartesianMesh1D(); - constexpr size_t Dimension = 1; - auto xj = MeshDataManager::instance().getMeshData(*mesh).xj(); + std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - SECTION("inner operators") - { - SECTION("scalar functions") + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) { - DiscreteFunctionP0<Dimension, double> f{mesh}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - const double x = xj[cell_id][0]; - f[cell_id] = 2 * x + 1; - }); + auto mesh = named_mesh.mesh(); - DiscreteFunctionP0<Dimension, double> g{mesh}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - const double x = xj[cell_id][0]; - g[cell_id] = std::abs((x + 1) * (x - 2)) + 1; - }); + auto xj = MeshDataManager::instance().getMeshData(*mesh).xj(); - DiscreteFunctionP0<Dimension, const double> const_f = f; - DiscreteFunctionP0<Dimension, const double> const_g{g}; - - SECTION("sum") + SECTION("inner operators") { - Array<double> sum_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { sum_values[cell_id] = f[cell_id] + g[cell_id]; }); - - REQUIRE(same_values(f + g, sum_values)); - REQUIRE(same_values(const_f + g, sum_values)); - REQUIRE(same_values(f + const_g, sum_values)); - REQUIRE(same_values(const_f + const_g, sum_values)); - } + SECTION("scalar functions") + { + DiscreteFunctionP0<Dimension, double> f{mesh}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + const double x = xj[cell_id][0]; + f[cell_id] = 2 * x + 1; + }); - SECTION("difference") - { - Array<double> difference_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), - PUGS_LAMBDA(CellId cell_id) { difference_values[cell_id] = f[cell_id] - g[cell_id]; }); + DiscreteFunctionP0<Dimension, double> g{mesh}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + const double x = xj[cell_id][0]; + g[cell_id] = std::abs((x + 1) * (x - 2)) + 1; + }); - REQUIRE(same_values(f - g, difference_values)); - REQUIRE(same_values(const_f - g, difference_values)); - REQUIRE(same_values(f - const_g, difference_values)); - REQUIRE(same_values(const_f - const_g, difference_values)); - } + DiscreteFunctionP0<Dimension, const double> const_f = f; + DiscreteFunctionP0<Dimension, const double> const_g{g}; + + SECTION("sum") + { + Array<double> sum_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(CellId cell_id) { sum_values[cell_id] = f[cell_id] + g[cell_id]; }); + + REQUIRE(same_values(f + g, sum_values)); + REQUIRE(same_values(const_f + g, sum_values)); + REQUIRE(same_values(f + const_g, sum_values)); + REQUIRE(same_values(const_f + const_g, sum_values)); + } + + SECTION("difference") + { + Array<double> difference_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(CellId cell_id) { difference_values[cell_id] = f[cell_id] - g[cell_id]; }); + + REQUIRE(same_values(f - g, difference_values)); + REQUIRE(same_values(const_f - g, difference_values)); + REQUIRE(same_values(f - const_g, difference_values)); + REQUIRE(same_values(const_f - const_g, difference_values)); + } + + SECTION("product") + { + Array<double> product_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = f[cell_id] * g[cell_id]; }); + + REQUIRE(same_values(f * g, product_values)); + REQUIRE(same_values(const_f * g, product_values)); + REQUIRE(same_values(f * const_g, product_values)); + REQUIRE(same_values(const_f * const_g, product_values)); + } + + SECTION("ratio") + { + Array<double> ratio_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(CellId cell_id) { ratio_values[cell_id] = f[cell_id] / g[cell_id]; }); + + REQUIRE(same_values(f / g, ratio_values)); + REQUIRE(same_values(const_f / g, ratio_values)); + REQUIRE(same_values(f / const_g, ratio_values)); + REQUIRE(same_values(const_f / const_g, ratio_values)); + } + } + + SECTION("vector functions") + { + constexpr std::uint64_t VectorDimension = 2; + + DiscreteFunctionP0<Dimension, TinyVector<VectorDimension>> f{mesh}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + const double x = xj[cell_id][0]; + const TinyVector<VectorDimension> X{x, 2 - x}; + f[cell_id] = 2 * X + TinyVector<2>{1, 2}; + }); - SECTION("product") - { - Array<double> product_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), - PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = f[cell_id] * g[cell_id]; }); + DiscreteFunctionP0<Dimension, TinyVector<VectorDimension>> g{mesh}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + const double x = xj[cell_id][0]; + const TinyVector<VectorDimension> X{3 * x + 1, 2 + x}; + g[cell_id] = X; + }); - REQUIRE(same_values(f * g, product_values)); - REQUIRE(same_values(const_f * g, product_values)); - REQUIRE(same_values(f * const_g, product_values)); - REQUIRE(same_values(const_f * const_g, product_values)); - } + DiscreteFunctionP0<Dimension, const TinyVector<VectorDimension>> const_f = f; + DiscreteFunctionP0<Dimension, const TinyVector<VectorDimension>> const_g{g}; - SECTION("ratio") - { - Array<double> ratio_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { ratio_values[cell_id] = f[cell_id] / g[cell_id]; }); + SECTION("sum") + { + Array<TinyVector<VectorDimension>> sum_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(CellId cell_id) { sum_values[cell_id] = f[cell_id] + g[cell_id]; }); - REQUIRE(same_values(f / g, ratio_values)); - REQUIRE(same_values(const_f / g, ratio_values)); - REQUIRE(same_values(f / const_g, ratio_values)); - REQUIRE(same_values(const_f / const_g, ratio_values)); - } - } + REQUIRE(same_values(f + g, sum_values)); + REQUIRE(same_values(const_f + g, sum_values)); + REQUIRE(same_values(f + const_g, sum_values)); + REQUIRE(same_values(const_f + const_g, sum_values)); + } - SECTION("vector functions") - { - constexpr std::uint64_t VectorDimension = 2; + SECTION("difference") + { + Array<TinyVector<VectorDimension>> difference_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(CellId cell_id) { difference_values[cell_id] = f[cell_id] - g[cell_id]; }); - DiscreteFunctionP0<Dimension, TinyVector<VectorDimension>> f{mesh}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - const double x = xj[cell_id][0]; - const TinyVector<VectorDimension> X{x, 2 - x}; - f[cell_id] = 2 * X + TinyVector<2>{1, 2}; - }); + REQUIRE(same_values(f - g, difference_values)); + REQUIRE(same_values(const_f - g, difference_values)); + REQUIRE(same_values(f - const_g, difference_values)); + REQUIRE(same_values(const_f - const_g, difference_values)); + } + } - DiscreteFunctionP0<Dimension, TinyVector<VectorDimension>> g{mesh}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - const double x = xj[cell_id][0]; - const TinyVector<VectorDimension> X{3 * x + 1, 2 + x}; - g[cell_id] = X; - }); + SECTION("matrix functions") + { + constexpr std::uint64_t MatrixDimension = 2; - DiscreteFunctionP0<Dimension, const TinyVector<VectorDimension>> const_f = f; - DiscreteFunctionP0<Dimension, const TinyVector<VectorDimension>> const_g{g}; + DiscreteFunctionP0<Dimension, TinyMatrix<MatrixDimension>> f{mesh}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + const double x = xj[cell_id][0]; + const TinyMatrix<MatrixDimension> A{x, 2 - x, 2 * x, x * x - 3}; + f[cell_id] = 2 * A + TinyMatrix<2>{1, 2, 3, 4}; + }); - SECTION("sum") - { - Array<TinyVector<VectorDimension>> sum_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { sum_values[cell_id] = f[cell_id] + g[cell_id]; }); + DiscreteFunctionP0<Dimension, TinyMatrix<MatrixDimension>> g{mesh}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + const double x = xj[cell_id][0]; + const TinyMatrix<MatrixDimension> A{3 * x + 1, 2 + x, 1 - 2 * x, 2 * x * x}; + g[cell_id] = A; + }); - REQUIRE(same_values(f + g, sum_values)); - REQUIRE(same_values(const_f + g, sum_values)); - REQUIRE(same_values(f + const_g, sum_values)); - REQUIRE(same_values(const_f + const_g, sum_values)); + DiscreteFunctionP0<Dimension, const TinyMatrix<MatrixDimension>> const_f = f; + DiscreteFunctionP0<Dimension, const TinyMatrix<MatrixDimension>> const_g{g}; + + SECTION("sum") + { + Array<TinyMatrix<MatrixDimension>> sum_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(CellId cell_id) { sum_values[cell_id] = f[cell_id] + g[cell_id]; }); + + REQUIRE(same_values(f + g, sum_values)); + REQUIRE(same_values(const_f + g, sum_values)); + REQUIRE(same_values(f + const_g, sum_values)); + REQUIRE(same_values(const_f + const_g, sum_values)); + } + + SECTION("difference") + { + Array<TinyMatrix<MatrixDimension>> difference_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(CellId cell_id) { difference_values[cell_id] = f[cell_id] - g[cell_id]; }); + + REQUIRE(same_values(f - g, difference_values)); + REQUIRE(same_values(const_f - g, difference_values)); + REQUIRE(same_values(f - const_g, difference_values)); + REQUIRE(same_values(const_f - const_g, difference_values)); + } + + SECTION("product") + { + Array<TinyMatrix<MatrixDimension>> product_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = f[cell_id] * g[cell_id]; }); + + REQUIRE(same_values(f * g, product_values)); + REQUIRE(same_values(const_f * g, product_values)); + REQUIRE(same_values(f * const_g, product_values)); + REQUIRE(same_values(const_f * const_g, product_values)); + } + } } - SECTION("difference") + SECTION("external operators") { - Array<TinyVector<VectorDimension>> difference_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), - PUGS_LAMBDA(CellId cell_id) { difference_values[cell_id] = f[cell_id] - g[cell_id]; }); + SECTION("scalar functions") + { + DiscreteFunctionP0<Dimension, double> f{mesh}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + const double x = xj[cell_id][0]; + f[cell_id] = std::abs(2 * x) + 1; + }); - REQUIRE(same_values(f - g, difference_values)); - REQUIRE(same_values(const_f - g, difference_values)); - REQUIRE(same_values(f - const_g, difference_values)); - REQUIRE(same_values(const_f - const_g, difference_values)); + const double a = 3; + + DiscreteFunctionP0<Dimension, const double> const_f = f; + + SECTION("sum") + { + { + Array<double> sum_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { sum_values[cell_id] = a + f[cell_id]; }); + + REQUIRE(same_values(a + f, sum_values)); + REQUIRE(same_values(a + const_f, sum_values)); + } + { + Array<double> sum_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { sum_values[cell_id] = f[cell_id] + a; }); + + REQUIRE(same_values(f + a, sum_values)); + REQUIRE(same_values(const_f + a, sum_values)); + } + } + + SECTION("difference") + { + { + Array<double> difference_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(CellId cell_id) { difference_values[cell_id] = a - f[cell_id]; }); + REQUIRE(same_values(a - f, difference_values)); + REQUIRE(same_values(a - const_f, difference_values)); + } + + { + Array<double> difference_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(CellId cell_id) { difference_values[cell_id] = f[cell_id] - a; }); + REQUIRE(same_values(f - a, difference_values)); + REQUIRE(same_values(const_f - a, difference_values)); + } + } + + SECTION("product") + { + { + Array<double> product_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = a * f[cell_id]; }); + + REQUIRE(same_values(a * f, product_values)); + REQUIRE(same_values(a * const_f, product_values)); + } + { + Array<double> product_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = f[cell_id] * a; }); + + REQUIRE(same_values(f * a, product_values)); + REQUIRE(same_values(const_f * a, product_values)); + } + + { + Array<TinyVector<3>> product_values{mesh->numberOfCells()}; + const TinyVector<3> v{1, 2, 3}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = f[cell_id] * v; }); + + REQUIRE(same_values(f * v, product_values)); + REQUIRE(same_values(const_f * v, product_values)); + } + + { + Array<TinyVector<3>> product_values{mesh->numberOfCells()}; + DiscreteFunctionP0<Dimension, TinyVector<3>> v{mesh}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + const double x = xj[cell_id][0]; + v[cell_id] = TinyVector<3>{x, 2 * x, 1 - x}; + }); + + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = f[cell_id] * v[cell_id]; }); + + REQUIRE(same_values(f * v, product_values)); + REQUIRE(same_values(const_f * v, product_values)); + } + + { + Array<TinyMatrix<2>> product_values{mesh->numberOfCells()}; + const TinyMatrix<2> A{1, 2, 3, 4}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = f[cell_id] * A; }); + + REQUIRE(same_values(f * A, product_values)); + REQUIRE(same_values(const_f * A, product_values)); + } + + { + Array<TinyMatrix<2>> product_values{mesh->numberOfCells()}; + DiscreteFunctionP0<Dimension, TinyMatrix<2>> M{mesh}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + const double x = xj[cell_id][0]; + M[cell_id] = TinyMatrix<2>{x, 2 * x, 1 - x, 2 - x * x}; + }); + + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = f[cell_id] * M[cell_id]; }); + + REQUIRE(same_values(f * M, product_values)); + REQUIRE(same_values(const_f * M, product_values)); + } + } + + SECTION("ratio") + { + { + Array<double> ratio_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { ratio_values[cell_id] = a / f[cell_id]; }); + + REQUIRE(same_values(a / f, ratio_values)); + REQUIRE(same_values(a / const_f, ratio_values)); + } + { + Array<double> ratio_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { ratio_values[cell_id] = f[cell_id] / a; }); + + REQUIRE(same_values(f / a, ratio_values)); + REQUIRE(same_values(const_f / a, ratio_values)); + } + } + } + + SECTION("vector functions") + { + constexpr std::uint64_t VectorDimension = 2; + + DiscreteFunctionP0<Dimension, TinyVector<VectorDimension>> f{mesh}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + const double x = xj[cell_id][0]; + const TinyVector<VectorDimension> X{x, 2 - x}; + f[cell_id] = 2 * X + TinyVector<2>{1, 2}; + }); + + DiscreteFunctionP0<Dimension, const TinyVector<VectorDimension>> const_f = f; + + SECTION("sum") + { + const TinyVector<VectorDimension> v{1, 2}; + { + Array<TinyVector<VectorDimension>> sum_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { sum_values[cell_id] = v + f[cell_id]; }); + + REQUIRE(same_values(v + f, sum_values)); + REQUIRE(same_values(v + const_f, sum_values)); + } + { + Array<TinyVector<VectorDimension>> sum_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { sum_values[cell_id] = f[cell_id] + v; }); + + REQUIRE(same_values(f + v, sum_values)); + REQUIRE(same_values(const_f + v, sum_values)); + } + } + + SECTION("difference") + { + const TinyVector<VectorDimension> v{1, 2}; + { + Array<TinyVector<VectorDimension>> difference_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(CellId cell_id) { difference_values[cell_id] = v - f[cell_id]; }); + + REQUIRE(same_values(v - f, difference_values)); + REQUIRE(same_values(v - const_f, difference_values)); + } + { + Array<TinyVector<VectorDimension>> difference_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(CellId cell_id) { difference_values[cell_id] = f[cell_id] - v; }); + + REQUIRE(same_values(f - v, difference_values)); + REQUIRE(same_values(const_f - v, difference_values)); + } + } + + SECTION("product") + { + { + const double a = 2.3; + Array<TinyVector<VectorDimension>> product_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = a * f[cell_id]; }); + + REQUIRE(same_values(a * f, product_values)); + REQUIRE(same_values(a * const_f, product_values)); + } + + { + DiscreteFunctionP0<Dimension, double> a{mesh}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + const double x = xj[cell_id][0]; + a[cell_id] = 2 * x * x - 1; + }); + + Array<TinyVector<VectorDimension>> product_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = a[cell_id] * f[cell_id]; }); + + REQUIRE(same_values(a * f, product_values)); + REQUIRE(same_values(a * const_f, product_values)); + } + + { + const TinyMatrix<VectorDimension> A{1, 2, 3, 4}; + Array<TinyVector<VectorDimension>> product_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = A * f[cell_id]; }); + + REQUIRE(same_values(A * f, product_values)); + REQUIRE(same_values(A * const_f, product_values)); + } + + { + Array<TinyVector<VectorDimension>> product_values{mesh->numberOfCells()}; + DiscreteFunctionP0<Dimension, TinyMatrix<VectorDimension>> M{mesh}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + const double x = xj[cell_id][0]; + M[cell_id] = TinyMatrix<2>{x, 2 * x, 1 - x, 2 - x * x}; + }); + + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = M[cell_id] * f[cell_id]; }); + + REQUIRE(same_values(M * f, product_values)); + REQUIRE(same_values(M * const_f, product_values)); + } + } + } + + SECTION("matrix functions") + { + constexpr std::uint64_t MatrixDimension = 2; + + DiscreteFunctionP0<Dimension, TinyMatrix<MatrixDimension>> f{mesh}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + const double x = xj[cell_id][0]; + const TinyMatrix<MatrixDimension> X{x, 2 - x, x * x, x * 3}; + f[cell_id] = 2 * X + TinyMatrix<2>{1, 2, 3, 4}; + }); + + DiscreteFunctionP0<Dimension, const TinyMatrix<MatrixDimension>> const_f = f; + + SECTION("sum") + { + const TinyMatrix<MatrixDimension> A{1, 2, 3, 4}; + { + Array<TinyMatrix<MatrixDimension>> sum_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { sum_values[cell_id] = A + f[cell_id]; }); + + REQUIRE(same_values(A + f, sum_values)); + REQUIRE(same_values(A + const_f, sum_values)); + } + { + Array<TinyMatrix<MatrixDimension>> sum_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { sum_values[cell_id] = f[cell_id] + A; }); + + REQUIRE(same_values(f + A, sum_values)); + REQUIRE(same_values(const_f + A, sum_values)); + } + } + + SECTION("difference") + { + const TinyMatrix<MatrixDimension> A{1, 2, 3, 4}; + { + Array<TinyMatrix<MatrixDimension>> difference_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(CellId cell_id) { difference_values[cell_id] = A - f[cell_id]; }); + + REQUIRE(same_values(A - f, difference_values)); + REQUIRE(same_values(A - const_f, difference_values)); + } + { + Array<TinyMatrix<MatrixDimension>> difference_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(CellId cell_id) { difference_values[cell_id] = f[cell_id] - A; }); + + REQUIRE(same_values(f - A, difference_values)); + REQUIRE(same_values(const_f - A, difference_values)); + } + } + + SECTION("product") + { + { + const double a = 2.3; + Array<TinyMatrix<MatrixDimension>> product_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = a * f[cell_id]; }); + + REQUIRE(same_values(a * f, product_values)); + REQUIRE(same_values(a * const_f, product_values)); + } + + { + DiscreteFunctionP0<Dimension, double> a{mesh}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + const double x = xj[cell_id][0]; + a[cell_id] = 2 * x * x - 1; + }); + + Array<TinyMatrix<MatrixDimension>> product_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = a[cell_id] * f[cell_id]; }); + + REQUIRE(same_values(a * f, product_values)); + REQUIRE(same_values(a * const_f, product_values)); + } + + { + const TinyMatrix<MatrixDimension> A{1, 2, 3, 4}; + Array<TinyMatrix<MatrixDimension>> product_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = A * f[cell_id]; }); + + REQUIRE(same_values(A * f, product_values)); + REQUIRE(same_values(A * const_f, product_values)); + } + + { + const TinyMatrix<MatrixDimension> A{1, 2, 3, 4}; + Array<TinyMatrix<MatrixDimension>> product_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = f[cell_id] * A; }); + + REQUIRE(same_values(f * A, product_values)); + REQUIRE(same_values(const_f * A, product_values)); + } + } + } } } + } + } - SECTION("matrix functions") - { - constexpr std::uint64_t MatrixDimension = 2; + SECTION("2D") + { + constexpr size_t Dimension = 2; - DiscreteFunctionP0<Dimension, TinyMatrix<MatrixDimension>> f{mesh}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - const double x = xj[cell_id][0]; - const TinyMatrix<MatrixDimension> A{x, 2 - x, 2 * x, x * x - 3}; - f[cell_id] = 2 * A + TinyMatrix<2>{1, 2, 3, 4}; - }); + std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - DiscreteFunctionP0<Dimension, TinyMatrix<MatrixDimension>> g{mesh}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - const double x = xj[cell_id][0]; - const TinyMatrix<MatrixDimension> A{3 * x + 1, 2 + x, 1 - 2 * x, 2 * x * x}; - g[cell_id] = A; - }); + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh = named_mesh.mesh(); - DiscreteFunctionP0<Dimension, const TinyMatrix<MatrixDimension>> const_f = f; - DiscreteFunctionP0<Dimension, const TinyMatrix<MatrixDimension>> const_g{g}; + auto xj = MeshDataManager::instance().getMeshData(*mesh).xj(); - SECTION("sum") + SECTION("inner operators") { - Array<TinyMatrix<MatrixDimension>> sum_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { sum_values[cell_id] = f[cell_id] + g[cell_id]; }); + SECTION("scalar functions") + { + DiscreteFunctionP0<Dimension, double> f{mesh}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + const double x = xj[cell_id][0]; + const double y = xj[cell_id][1]; + f[cell_id] = 2 * x + y + 1; + }); - REQUIRE(same_values(f + g, sum_values)); - REQUIRE(same_values(const_f + g, sum_values)); - REQUIRE(same_values(f + const_g, sum_values)); - REQUIRE(same_values(const_f + const_g, sum_values)); - } + DiscreteFunctionP0<Dimension, double> g{mesh}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + const double x = xj[cell_id][0]; + const double y = xj[cell_id][1]; + g[cell_id] = std::abs((x + 1) * (x - 2) + y * (1 + y)) + 1; + }); - SECTION("difference") - { - Array<TinyMatrix<MatrixDimension>> difference_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), - PUGS_LAMBDA(CellId cell_id) { difference_values[cell_id] = f[cell_id] - g[cell_id]; }); + DiscreteFunctionP0<Dimension, const double> const_f = f; + DiscreteFunctionP0<Dimension, const double> const_g{g}; + + SECTION("sum") + { + Array<double> sum_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(CellId cell_id) { sum_values[cell_id] = f[cell_id] + g[cell_id]; }); + + REQUIRE(same_values(f + g, sum_values)); + REQUIRE(same_values(const_f + g, sum_values)); + REQUIRE(same_values(f + const_g, sum_values)); + REQUIRE(same_values(const_f + const_g, sum_values)); + } + + SECTION("difference") + { + Array<double> difference_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(CellId cell_id) { difference_values[cell_id] = f[cell_id] - g[cell_id]; }); + + REQUIRE(same_values(f - g, difference_values)); + REQUIRE(same_values(const_f - g, difference_values)); + REQUIRE(same_values(f - const_g, difference_values)); + REQUIRE(same_values(const_f - const_g, difference_values)); + } + + SECTION("product") + { + Array<double> product_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = f[cell_id] * g[cell_id]; }); + + REQUIRE(same_values(f * g, product_values)); + REQUIRE(same_values(const_f * g, product_values)); + REQUIRE(same_values(f * const_g, product_values)); + REQUIRE(same_values(const_f * const_g, product_values)); + } + + SECTION("ratio") + { + Array<double> ratio_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(CellId cell_id) { ratio_values[cell_id] = f[cell_id] / g[cell_id]; }); + + REQUIRE(same_values(f / g, ratio_values)); + REQUIRE(same_values(const_f / g, ratio_values)); + REQUIRE(same_values(f / const_g, ratio_values)); + REQUIRE(same_values(const_f / const_g, ratio_values)); + } + } + + SECTION("vector functions") + { + constexpr std::uint64_t VectorDimension = 2; + + DiscreteFunctionP0<Dimension, TinyVector<VectorDimension>> f{mesh}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + const double x = xj[cell_id][0]; + const TinyVector<VectorDimension> X{x, 2 - x}; + f[cell_id] = 2 * X + TinyVector<2>{1, 2}; + }); - REQUIRE(same_values(f - g, difference_values)); - REQUIRE(same_values(const_f - g, difference_values)); - REQUIRE(same_values(f - const_g, difference_values)); - REQUIRE(same_values(const_f - const_g, difference_values)); - } + DiscreteFunctionP0<Dimension, TinyVector<VectorDimension>> g{mesh}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + const double x = xj[cell_id][0]; + const TinyVector<VectorDimension> X{3 * x + 1, 2 + x}; + g[cell_id] = X; + }); - SECTION("product") - { - Array<TinyMatrix<MatrixDimension>> product_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), - PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = f[cell_id] * g[cell_id]; }); + DiscreteFunctionP0<Dimension, const TinyVector<VectorDimension>> const_f = f; + DiscreteFunctionP0<Dimension, const TinyVector<VectorDimension>> const_g{g}; - REQUIRE(same_values(f * g, product_values)); - REQUIRE(same_values(const_f * g, product_values)); - REQUIRE(same_values(f * const_g, product_values)); - REQUIRE(same_values(const_f * const_g, product_values)); - } - } - } + SECTION("sum") + { + Array<TinyVector<VectorDimension>> sum_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(CellId cell_id) { sum_values[cell_id] = f[cell_id] + g[cell_id]; }); - SECTION("external operators") - { - SECTION("scalar functions") - { - DiscreteFunctionP0<Dimension, double> f{mesh}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - const double x = xj[cell_id][0]; - f[cell_id] = std::abs(2 * x) + 1; - }); + REQUIRE(same_values(f + g, sum_values)); + REQUIRE(same_values(const_f + g, sum_values)); + REQUIRE(same_values(f + const_g, sum_values)); + REQUIRE(same_values(const_f + const_g, sum_values)); + } - const double a = 3; + SECTION("difference") + { + Array<TinyVector<VectorDimension>> difference_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(CellId cell_id) { difference_values[cell_id] = f[cell_id] - g[cell_id]; }); - DiscreteFunctionP0<Dimension, const double> const_f = f; + REQUIRE(same_values(f - g, difference_values)); + REQUIRE(same_values(const_f - g, difference_values)); + REQUIRE(same_values(f - const_g, difference_values)); + REQUIRE(same_values(const_f - const_g, difference_values)); + } + } - SECTION("sum") - { + SECTION("matrix functions") { - Array<double> sum_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { sum_values[cell_id] = a + f[cell_id]; }); + constexpr std::uint64_t MatrixDimension = 2; - REQUIRE(same_values(a + f, sum_values)); - REQUIRE(same_values(a + const_f, sum_values)); - } - { - Array<double> sum_values{mesh->numberOfCells()}; + DiscreteFunctionP0<Dimension, TinyMatrix<MatrixDimension>> f{mesh}; parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { sum_values[cell_id] = f[cell_id] + a; }); + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + const double x = xj[cell_id][0]; + const TinyMatrix<MatrixDimension> A{x, 2 - x, 2 * x, x * x - 3}; + f[cell_id] = 2 * A + TinyMatrix<2>{1, 2, 3, 4}; + }); - REQUIRE(same_values(f + a, sum_values)); - REQUIRE(same_values(const_f + a, sum_values)); - } - } - - SECTION("difference") - { - { - Array<double> difference_values{mesh->numberOfCells()}; + DiscreteFunctionP0<Dimension, TinyMatrix<MatrixDimension>> g{mesh}; parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { difference_values[cell_id] = a - f[cell_id]; }); - REQUIRE(same_values(a - f, difference_values)); - REQUIRE(same_values(a - const_f, difference_values)); - } + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + const double x = xj[cell_id][0]; + const TinyMatrix<MatrixDimension> A{3 * x + 1, 2 + x, 1 - 2 * x, 2 * x * x}; + g[cell_id] = A; + }); - { - Array<double> difference_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { difference_values[cell_id] = f[cell_id] - a; }); - REQUIRE(same_values(f - a, difference_values)); - REQUIRE(same_values(const_f - a, difference_values)); + DiscreteFunctionP0<Dimension, const TinyMatrix<MatrixDimension>> const_f = f; + DiscreteFunctionP0<Dimension, const TinyMatrix<MatrixDimension>> const_g{g}; + + SECTION("sum") + { + Array<TinyMatrix<MatrixDimension>> sum_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(CellId cell_id) { sum_values[cell_id] = f[cell_id] + g[cell_id]; }); + + REQUIRE(same_values(f + g, sum_values)); + REQUIRE(same_values(const_f + g, sum_values)); + REQUIRE(same_values(f + const_g, sum_values)); + REQUIRE(same_values(const_f + const_g, sum_values)); + } + + SECTION("difference") + { + Array<TinyMatrix<MatrixDimension>> difference_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(CellId cell_id) { difference_values[cell_id] = f[cell_id] - g[cell_id]; }); + + REQUIRE(same_values(f - g, difference_values)); + REQUIRE(same_values(const_f - g, difference_values)); + REQUIRE(same_values(f - const_g, difference_values)); + REQUIRE(same_values(const_f - const_g, difference_values)); + } + + SECTION("product") + { + Array<TinyMatrix<MatrixDimension>> product_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = f[cell_id] * g[cell_id]; }); + + REQUIRE(same_values(f * g, product_values)); + REQUIRE(same_values(const_f * g, product_values)); + REQUIRE(same_values(f * const_g, product_values)); + REQUIRE(same_values(const_f * const_g, product_values)); + } } } - SECTION("product") + SECTION("external operators") { + SECTION("scalar functions") { - Array<double> product_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = a * f[cell_id]; }); - - REQUIRE(same_values(a * f, product_values)); - REQUIRE(same_values(a * const_f, product_values)); - } - { - Array<double> product_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = f[cell_id] * a; }); - - REQUIRE(same_values(f * a, product_values)); - REQUIRE(same_values(const_f * a, product_values)); - } - - { - Array<TinyVector<3>> product_values{mesh->numberOfCells()}; - const TinyVector<3> v{1, 2, 3}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = f[cell_id] * v; }); - - REQUIRE(same_values(f * v, product_values)); - REQUIRE(same_values(const_f * v, product_values)); - } - - { - Array<TinyVector<3>> product_values{mesh->numberOfCells()}; - DiscreteFunctionP0<Dimension, TinyVector<3>> v{mesh}; + DiscreteFunctionP0<Dimension, double> f{mesh}; parallel_for( mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { const double x = xj[cell_id][0]; - v[cell_id] = TinyVector<3>{x, 2 * x, 1 - x}; + const double y = xj[cell_id][1]; + f[cell_id] = std::abs(2 * x + y) + 1; }); - parallel_for( - mesh->numberOfCells(), - PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = f[cell_id] * v[cell_id]; }); - - REQUIRE(same_values(f * v, product_values)); - REQUIRE(same_values(const_f * v, product_values)); - } - - { - Array<TinyMatrix<2>> product_values{mesh->numberOfCells()}; - const TinyMatrix<2> A{1, 2, 3, 4}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = f[cell_id] * A; }); - - REQUIRE(same_values(f * A, product_values)); - REQUIRE(same_values(const_f * A, product_values)); - } - - { - Array<TinyMatrix<2>> product_values{mesh->numberOfCells()}; - DiscreteFunctionP0<Dimension, TinyMatrix<2>> M{mesh}; + const double a = 3; + + DiscreteFunctionP0<Dimension, const double> const_f = f; + + SECTION("sum") + { + { + Array<double> sum_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { sum_values[cell_id] = a + f[cell_id]; }); + + REQUIRE(same_values(a + f, sum_values)); + REQUIRE(same_values(a + const_f, sum_values)); + } + { + Array<double> sum_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { sum_values[cell_id] = f[cell_id] + a; }); + + REQUIRE(same_values(f + a, sum_values)); + REQUIRE(same_values(const_f + a, sum_values)); + } + } + + SECTION("difference") + { + { + Array<double> difference_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(CellId cell_id) { difference_values[cell_id] = a - f[cell_id]; }); + REQUIRE(same_values(a - f, difference_values)); + REQUIRE(same_values(a - const_f, difference_values)); + } + + { + Array<double> difference_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(CellId cell_id) { difference_values[cell_id] = f[cell_id] - a; }); + REQUIRE(same_values(f - a, difference_values)); + REQUIRE(same_values(const_f - a, difference_values)); + } + } + + SECTION("product") + { + { + Array<double> product_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = a * f[cell_id]; }); + + REQUIRE(same_values(a * f, product_values)); + REQUIRE(same_values(a * const_f, product_values)); + } + { + Array<double> product_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = f[cell_id] * a; }); + + REQUIRE(same_values(f * a, product_values)); + REQUIRE(same_values(const_f * a, product_values)); + } + + { + Array<TinyVector<3>> product_values{mesh->numberOfCells()}; + const TinyVector<3> v{1, 2, 3}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = f[cell_id] * v; }); + + REQUIRE(same_values(f * v, product_values)); + REQUIRE(same_values(const_f * v, product_values)); + } + + { + Array<TinyVector<3>> product_values{mesh->numberOfCells()}; + DiscreteFunctionP0<Dimension, TinyVector<3>> v{mesh}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + const double x = xj[cell_id][0]; + v[cell_id] = TinyVector<3>{x, 2 * x, 1 - x}; + }); + + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = f[cell_id] * v[cell_id]; }); + + REQUIRE(same_values(f * v, product_values)); + REQUIRE(same_values(const_f * v, product_values)); + } + + { + Array<TinyMatrix<2>> product_values{mesh->numberOfCells()}; + const TinyMatrix<2> A{1, 2, 3, 4}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = f[cell_id] * A; }); + + REQUIRE(same_values(f * A, product_values)); + REQUIRE(same_values(const_f * A, product_values)); + } + + { + Array<TinyMatrix<2>> product_values{mesh->numberOfCells()}; + DiscreteFunctionP0<Dimension, TinyMatrix<2>> M{mesh}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + const double x = xj[cell_id][0]; + M[cell_id] = TinyMatrix<2>{x, 2 * x, 1 - x, 2 - x * x}; + }); + + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = f[cell_id] * M[cell_id]; }); + + REQUIRE(same_values(f * M, product_values)); + REQUIRE(same_values(const_f * M, product_values)); + } + } + + SECTION("ratio") + { + { + Array<double> ratio_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { ratio_values[cell_id] = a / f[cell_id]; }); + + REQUIRE(same_values(a / f, ratio_values)); + REQUIRE(same_values(a / const_f, ratio_values)); + } + { + Array<double> ratio_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { ratio_values[cell_id] = f[cell_id] / a; }); + + REQUIRE(same_values(f / a, ratio_values)); + REQUIRE(same_values(const_f / a, ratio_values)); + } + } + } + + SECTION("vector functions") + { + constexpr std::uint64_t VectorDimension = 2; + + DiscreteFunctionP0<Dimension, TinyVector<VectorDimension>> f{mesh}; parallel_for( mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { const double x = xj[cell_id][0]; - M[cell_id] = TinyMatrix<2>{x, 2 * x, 1 - x, 2 - x * x}; + const double y = xj[cell_id][1]; + const TinyVector<VectorDimension> X{x + y, 2 - x * y}; + f[cell_id] = 2 * X + TinyVector<2>{1, 2}; }); + DiscreteFunctionP0<Dimension, const TinyVector<VectorDimension>> const_f = f; + + SECTION("sum") + { + const TinyVector<VectorDimension> v{1, 2}; + { + Array<TinyVector<VectorDimension>> sum_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { sum_values[cell_id] = v + f[cell_id]; }); + + REQUIRE(same_values(v + f, sum_values)); + REQUIRE(same_values(v + const_f, sum_values)); + } + { + Array<TinyVector<VectorDimension>> sum_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { sum_values[cell_id] = f[cell_id] + v; }); + + REQUIRE(same_values(f + v, sum_values)); + REQUIRE(same_values(const_f + v, sum_values)); + } + } + + SECTION("difference") + { + const TinyVector<VectorDimension> v{1, 2}; + { + Array<TinyVector<VectorDimension>> difference_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(CellId cell_id) { difference_values[cell_id] = v - f[cell_id]; }); + + REQUIRE(same_values(v - f, difference_values)); + REQUIRE(same_values(v - const_f, difference_values)); + } + { + Array<TinyVector<VectorDimension>> difference_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(CellId cell_id) { difference_values[cell_id] = f[cell_id] - v; }); + + REQUIRE(same_values(f - v, difference_values)); + REQUIRE(same_values(const_f - v, difference_values)); + } + } + + SECTION("product") + { + { + const double a = 2.3; + Array<TinyVector<VectorDimension>> product_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = a * f[cell_id]; }); + + REQUIRE(same_values(a * f, product_values)); + REQUIRE(same_values(a * const_f, product_values)); + } + + { + DiscreteFunctionP0<Dimension, double> a{mesh}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + const double x = xj[cell_id][0]; + a[cell_id] = 2 * x * x - 1; + }); + + Array<TinyVector<VectorDimension>> product_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = a[cell_id] * f[cell_id]; }); + + REQUIRE(same_values(a * f, product_values)); + REQUIRE(same_values(a * const_f, product_values)); + } + + { + const TinyMatrix<VectorDimension> A{1, 2, 3, 4}; + Array<TinyVector<VectorDimension>> product_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = A * f[cell_id]; }); + + REQUIRE(same_values(A * f, product_values)); + REQUIRE(same_values(A * const_f, product_values)); + } + + { + Array<TinyVector<VectorDimension>> product_values{mesh->numberOfCells()}; + DiscreteFunctionP0<Dimension, TinyMatrix<VectorDimension>> M{mesh}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + const double x = xj[cell_id][0]; + M[cell_id] = TinyMatrix<2>{x, 2 * x, 1 - x, 2 - x * x}; + }); + + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = M[cell_id] * f[cell_id]; }); + + REQUIRE(same_values(M * f, product_values)); + REQUIRE(same_values(M * const_f, product_values)); + } + } + } + + SECTION("matrix functions") + { + constexpr std::uint64_t MatrixDimension = 2; + + DiscreteFunctionP0<Dimension, TinyMatrix<MatrixDimension>> f{mesh}; parallel_for( - mesh->numberOfCells(), - PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = f[cell_id] * M[cell_id]; }); + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + const double x = xj[cell_id][0]; + const double y = xj[cell_id][1]; + const TinyMatrix<MatrixDimension> X{x, 2 - y, x * y, y * 3}; + f[cell_id] = 2 * X + TinyMatrix<2>{1, 2, 3, 4}; + }); - REQUIRE(same_values(f * M, product_values)); - REQUIRE(same_values(const_f * M, product_values)); + DiscreteFunctionP0<Dimension, const TinyMatrix<MatrixDimension>> const_f = f; + + SECTION("sum") + { + const TinyMatrix<MatrixDimension> A{1, 2, 3, 4}; + { + Array<TinyMatrix<MatrixDimension>> sum_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { sum_values[cell_id] = A + f[cell_id]; }); + + REQUIRE(same_values(A + f, sum_values)); + REQUIRE(same_values(A + const_f, sum_values)); + } + { + Array<TinyMatrix<MatrixDimension>> sum_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { sum_values[cell_id] = f[cell_id] + A; }); + + REQUIRE(same_values(f + A, sum_values)); + REQUIRE(same_values(const_f + A, sum_values)); + } + } + + SECTION("difference") + { + const TinyMatrix<MatrixDimension> A{1, 2, 3, 4}; + { + Array<TinyMatrix<MatrixDimension>> difference_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(CellId cell_id) { difference_values[cell_id] = A - f[cell_id]; }); + + REQUIRE(same_values(A - f, difference_values)); + REQUIRE(same_values(A - const_f, difference_values)); + } + { + Array<TinyMatrix<MatrixDimension>> difference_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(CellId cell_id) { difference_values[cell_id] = f[cell_id] - A; }); + + REQUIRE(same_values(f - A, difference_values)); + REQUIRE(same_values(const_f - A, difference_values)); + } + } + + SECTION("product") + { + { + const double a = 2.3; + Array<TinyMatrix<MatrixDimension>> product_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = a * f[cell_id]; }); + + REQUIRE(same_values(a * f, product_values)); + REQUIRE(same_values(a * const_f, product_values)); + } + + { + DiscreteFunctionP0<Dimension, double> a{mesh}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + const double x = xj[cell_id][0]; + a[cell_id] = 2 * x * x - 1; + }); + + Array<TinyMatrix<MatrixDimension>> product_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = a[cell_id] * f[cell_id]; }); + + REQUIRE(same_values(a * f, product_values)); + REQUIRE(same_values(a * const_f, product_values)); + } + + { + const TinyMatrix<MatrixDimension> A{1, 2, 3, 4}; + Array<TinyMatrix<MatrixDimension>> product_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = A * f[cell_id]; }); + + REQUIRE(same_values(A * f, product_values)); + REQUIRE(same_values(A * const_f, product_values)); + } + + { + const TinyMatrix<MatrixDimension> A{1, 2, 3, 4}; + Array<TinyMatrix<MatrixDimension>> product_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = f[cell_id] * A; }); + + REQUIRE(same_values(f * A, product_values)); + REQUIRE(same_values(const_f * A, product_values)); + } + } } } + } + } + } - SECTION("ratio") - { - { - Array<double> ratio_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { ratio_values[cell_id] = a / f[cell_id]; }); - - REQUIRE(same_values(a / f, ratio_values)); - REQUIRE(same_values(a / const_f, ratio_values)); - } - { - Array<double> ratio_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { ratio_values[cell_id] = f[cell_id] / a; }); + SECTION("3D") + { + constexpr size_t Dimension = 3; - REQUIRE(same_values(f / a, ratio_values)); - REQUIRE(same_values(const_f / a, ratio_values)); - } - } - } + std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - SECTION("vector functions") + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) { - constexpr std::uint64_t VectorDimension = 2; - - DiscreteFunctionP0<Dimension, TinyVector<VectorDimension>> f{mesh}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - const double x = xj[cell_id][0]; - const TinyVector<VectorDimension> X{x, 2 - x}; - f[cell_id] = 2 * X + TinyVector<2>{1, 2}; - }); + auto mesh = named_mesh.mesh(); - DiscreteFunctionP0<Dimension, const TinyVector<VectorDimension>> const_f = f; + auto xj = MeshDataManager::instance().getMeshData(*mesh).xj(); - SECTION("sum") + SECTION("inner operators") { - const TinyVector<VectorDimension> v{1, 2}; + SECTION("scalar functions") { - Array<TinyVector<VectorDimension>> sum_values{mesh->numberOfCells()}; + DiscreteFunctionP0<Dimension, double> f{mesh}; parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { sum_values[cell_id] = v + f[cell_id]; }); + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + const double x = xj[cell_id][0]; + const double y = xj[cell_id][1]; + const double z = xj[cell_id][2]; + f[cell_id] = 2 * x + y - z; + }); - REQUIRE(same_values(v + f, sum_values)); - REQUIRE(same_values(v + const_f, sum_values)); - } - { - Array<TinyVector<VectorDimension>> sum_values{mesh->numberOfCells()}; + DiscreteFunctionP0<Dimension, double> g{mesh}; parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { sum_values[cell_id] = f[cell_id] + v; }); - - REQUIRE(same_values(f + v, sum_values)); - REQUIRE(same_values(const_f + v, sum_values)); - } - } + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + const double x = xj[cell_id][0]; + const double y = xj[cell_id][1]; + const double z = xj[cell_id][2]; + g[cell_id] = std::abs((x + 1) * (x - 2) + y * (1 + y) + 2 * z) + 1; + }); - SECTION("difference") - { - const TinyVector<VectorDimension> v{1, 2}; - { - Array<TinyVector<VectorDimension>> difference_values{mesh->numberOfCells()}; + DiscreteFunctionP0<Dimension, const double> const_f = f; + DiscreteFunctionP0<Dimension, const double> const_g{g}; + + SECTION("sum") + { + Array<double> sum_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(CellId cell_id) { sum_values[cell_id] = f[cell_id] + g[cell_id]; }); + + REQUIRE(same_values(f + g, sum_values)); + REQUIRE(same_values(const_f + g, sum_values)); + REQUIRE(same_values(f + const_g, sum_values)); + REQUIRE(same_values(const_f + const_g, sum_values)); + } + + SECTION("difference") + { + Array<double> difference_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(CellId cell_id) { difference_values[cell_id] = f[cell_id] - g[cell_id]; }); + + REQUIRE(same_values(f - g, difference_values)); + REQUIRE(same_values(const_f - g, difference_values)); + REQUIRE(same_values(f - const_g, difference_values)); + REQUIRE(same_values(const_f - const_g, difference_values)); + } + + SECTION("product") + { + Array<double> product_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = f[cell_id] * g[cell_id]; }); + + REQUIRE(same_values(f * g, product_values)); + REQUIRE(same_values(const_f * g, product_values)); + REQUIRE(same_values(f * const_g, product_values)); + REQUIRE(same_values(const_f * const_g, product_values)); + } + + SECTION("ratio") + { + Array<double> ratio_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(CellId cell_id) { ratio_values[cell_id] = f[cell_id] / g[cell_id]; }); + + REQUIRE(same_values(f / g, ratio_values)); + REQUIRE(same_values(const_f / g, ratio_values)); + REQUIRE(same_values(f / const_g, ratio_values)); + REQUIRE(same_values(const_f / const_g, ratio_values)); + } + } + + SECTION("vector functions") + { + constexpr std::uint64_t VectorDimension = 2; + + DiscreteFunctionP0<Dimension, TinyVector<VectorDimension>> f{mesh}; parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { difference_values[cell_id] = v - f[cell_id]; }); + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + const double x = xj[cell_id][0]; + const TinyVector<VectorDimension> X{x, 2 - x}; + f[cell_id] = 2 * X + TinyVector<2>{1, 2}; + }); - REQUIRE(same_values(v - f, difference_values)); - REQUIRE(same_values(v - const_f, difference_values)); - } - { - Array<TinyVector<VectorDimension>> difference_values{mesh->numberOfCells()}; + DiscreteFunctionP0<Dimension, TinyVector<VectorDimension>> g{mesh}; parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { difference_values[cell_id] = f[cell_id] - v; }); + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + const double x = xj[cell_id][0]; + const TinyVector<VectorDimension> X{3 * x + 1, 2 + x}; + g[cell_id] = X; + }); - REQUIRE(same_values(f - v, difference_values)); - REQUIRE(same_values(const_f - v, difference_values)); - } - } + DiscreteFunctionP0<Dimension, const TinyVector<VectorDimension>> const_f = f; + DiscreteFunctionP0<Dimension, const TinyVector<VectorDimension>> const_g{g}; - SECTION("product") - { - { - const double a = 2.3; - Array<TinyVector<VectorDimension>> product_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = a * f[cell_id]; }); + SECTION("sum") + { + Array<TinyVector<VectorDimension>> sum_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(CellId cell_id) { sum_values[cell_id] = f[cell_id] + g[cell_id]; }); + + REQUIRE(same_values(f + g, sum_values)); + REQUIRE(same_values(const_f + g, sum_values)); + REQUIRE(same_values(f + const_g, sum_values)); + REQUIRE(same_values(const_f + const_g, sum_values)); + } - REQUIRE(same_values(a * f, product_values)); - REQUIRE(same_values(a * const_f, product_values)); + SECTION("difference") + { + Array<TinyVector<VectorDimension>> difference_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(CellId cell_id) { difference_values[cell_id] = f[cell_id] - g[cell_id]; }); + + REQUIRE(same_values(f - g, difference_values)); + REQUIRE(same_values(const_f - g, difference_values)); + REQUIRE(same_values(f - const_g, difference_values)); + REQUIRE(same_values(const_f - const_g, difference_values)); + } } + SECTION("matrix functions") { - DiscreteFunctionP0<Dimension, double> a{mesh}; + constexpr std::uint64_t MatrixDimension = 2; + + DiscreteFunctionP0<Dimension, TinyMatrix<MatrixDimension>> f{mesh}; parallel_for( mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { const double x = xj[cell_id][0]; - a[cell_id] = 2 * x * x - 1; + const TinyMatrix<MatrixDimension> A{x, 2 - x, 2 * x, x * x - 3}; + f[cell_id] = 2 * A + TinyMatrix<2>{1, 2, 3, 4}; }); - Array<TinyVector<VectorDimension>> product_values{mesh->numberOfCells()}; + DiscreteFunctionP0<Dimension, TinyMatrix<MatrixDimension>> g{mesh}; parallel_for( - mesh->numberOfCells(), - PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = a[cell_id] * f[cell_id]; }); + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + const double x = xj[cell_id][0]; + const TinyMatrix<MatrixDimension> A{3 * x + 1, 2 + x, 1 - 2 * x, 2 * x * x}; + g[cell_id] = A; + }); - REQUIRE(same_values(a * f, product_values)); - REQUIRE(same_values(a * const_f, product_values)); + DiscreteFunctionP0<Dimension, const TinyMatrix<MatrixDimension>> const_f = f; + DiscreteFunctionP0<Dimension, const TinyMatrix<MatrixDimension>> const_g{g}; + + SECTION("sum") + { + Array<TinyMatrix<MatrixDimension>> sum_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(CellId cell_id) { sum_values[cell_id] = f[cell_id] + g[cell_id]; }); + + REQUIRE(same_values(f + g, sum_values)); + REQUIRE(same_values(const_f + g, sum_values)); + REQUIRE(same_values(f + const_g, sum_values)); + REQUIRE(same_values(const_f + const_g, sum_values)); + } + + SECTION("difference") + { + Array<TinyMatrix<MatrixDimension>> difference_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(CellId cell_id) { difference_values[cell_id] = f[cell_id] - g[cell_id]; }); + + REQUIRE(same_values(f - g, difference_values)); + REQUIRE(same_values(const_f - g, difference_values)); + REQUIRE(same_values(f - const_g, difference_values)); + REQUIRE(same_values(const_f - const_g, difference_values)); + } + + SECTION("product") + { + Array<TinyMatrix<MatrixDimension>> product_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = f[cell_id] * g[cell_id]; }); + + REQUIRE(same_values(f * g, product_values)); + REQUIRE(same_values(const_f * g, product_values)); + REQUIRE(same_values(f * const_g, product_values)); + REQUIRE(same_values(const_f * const_g, product_values)); + } } + } + SECTION("external operators") + { + SECTION("scalar functions") { - const TinyMatrix<VectorDimension> A{1, 2, 3, 4}; - Array<TinyVector<VectorDimension>> product_values{mesh->numberOfCells()}; + DiscreteFunctionP0<Dimension, double> f{mesh}; parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = A * f[cell_id]; }); - - REQUIRE(same_values(A * f, product_values)); - REQUIRE(same_values(A * const_f, product_values)); - } + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + const double x = xj[cell_id][0]; + const double y = xj[cell_id][1]; + const double z = xj[cell_id][2]; + f[cell_id] = std::abs(2 * x + y * z) + 1; + }); - { - Array<TinyVector<VectorDimension>> product_values{mesh->numberOfCells()}; - DiscreteFunctionP0<Dimension, TinyMatrix<VectorDimension>> M{mesh}; + const double a = 3; + + DiscreteFunctionP0<Dimension, const double> const_f = f; + + SECTION("sum") + { + { + Array<double> sum_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { sum_values[cell_id] = a + f[cell_id]; }); + + REQUIRE(same_values(a + f, sum_values)); + REQUIRE(same_values(a + const_f, sum_values)); + } + { + Array<double> sum_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { sum_values[cell_id] = f[cell_id] + a; }); + + REQUIRE(same_values(f + a, sum_values)); + REQUIRE(same_values(const_f + a, sum_values)); + } + } + + SECTION("difference") + { + { + Array<double> difference_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(CellId cell_id) { difference_values[cell_id] = a - f[cell_id]; }); + REQUIRE(same_values(a - f, difference_values)); + REQUIRE(same_values(a - const_f, difference_values)); + } + + { + Array<double> difference_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(CellId cell_id) { difference_values[cell_id] = f[cell_id] - a; }); + REQUIRE(same_values(f - a, difference_values)); + REQUIRE(same_values(const_f - a, difference_values)); + } + } + + SECTION("product") + { + { + Array<double> product_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = a * f[cell_id]; }); + + REQUIRE(same_values(a * f, product_values)); + REQUIRE(same_values(a * const_f, product_values)); + } + { + Array<double> product_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = f[cell_id] * a; }); + + REQUIRE(same_values(f * a, product_values)); + REQUIRE(same_values(const_f * a, product_values)); + } + + { + Array<TinyVector<3>> product_values{mesh->numberOfCells()}; + const TinyVector<3> v{1, 2, 3}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = f[cell_id] * v; }); + + REQUIRE(same_values(f * v, product_values)); + REQUIRE(same_values(const_f * v, product_values)); + } + + { + Array<TinyVector<3>> product_values{mesh->numberOfCells()}; + DiscreteFunctionP0<Dimension, TinyVector<3>> v{mesh}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + const double x = xj[cell_id][0]; + v[cell_id] = TinyVector<3>{x, 2 * x, 1 - x}; + }); + + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = f[cell_id] * v[cell_id]; }); + + REQUIRE(same_values(f * v, product_values)); + REQUIRE(same_values(const_f * v, product_values)); + } + + { + Array<TinyMatrix<2>> product_values{mesh->numberOfCells()}; + const TinyMatrix<2> A{1, 2, 3, 4}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = f[cell_id] * A; }); + + REQUIRE(same_values(f * A, product_values)); + REQUIRE(same_values(const_f * A, product_values)); + } + + { + Array<TinyMatrix<2>> product_values{mesh->numberOfCells()}; + DiscreteFunctionP0<Dimension, TinyMatrix<2>> M{mesh}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + const double x = xj[cell_id][0]; + M[cell_id] = TinyMatrix<2>{x, 2 * x, 1 - x, 2 - x * x}; + }); + + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = f[cell_id] * M[cell_id]; }); + + REQUIRE(same_values(f * M, product_values)); + REQUIRE(same_values(const_f * M, product_values)); + } + } + + SECTION("ratio") + { + { + Array<double> ratio_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { ratio_values[cell_id] = a / f[cell_id]; }); + + REQUIRE(same_values(a / f, ratio_values)); + REQUIRE(same_values(a / const_f, ratio_values)); + } + { + Array<double> ratio_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { ratio_values[cell_id] = f[cell_id] / a; }); + + REQUIRE(same_values(f / a, ratio_values)); + REQUIRE(same_values(const_f / a, ratio_values)); + } + } + } + + SECTION("vector functions") + { + constexpr std::uint64_t VectorDimension = 2; + + DiscreteFunctionP0<Dimension, TinyVector<VectorDimension>> f{mesh}; parallel_for( mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { const double x = xj[cell_id][0]; - M[cell_id] = TinyMatrix<2>{x, 2 * x, 1 - x, 2 - x * x}; + const double y = xj[cell_id][1]; + const double z = xj[cell_id][2]; + const TinyVector<VectorDimension> X{x + y - z, 2 - x * y}; + f[cell_id] = 2 * X + TinyVector<2>{1, 2}; }); + DiscreteFunctionP0<Dimension, const TinyVector<VectorDimension>> const_f = f; + + SECTION("sum") + { + const TinyVector<VectorDimension> v{1, 2}; + { + Array<TinyVector<VectorDimension>> sum_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { sum_values[cell_id] = v + f[cell_id]; }); + + REQUIRE(same_values(v + f, sum_values)); + REQUIRE(same_values(v + const_f, sum_values)); + } + { + Array<TinyVector<VectorDimension>> sum_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { sum_values[cell_id] = f[cell_id] + v; }); + + REQUIRE(same_values(f + v, sum_values)); + REQUIRE(same_values(const_f + v, sum_values)); + } + } + + SECTION("difference") + { + const TinyVector<VectorDimension> v{1, 2}; + { + Array<TinyVector<VectorDimension>> difference_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(CellId cell_id) { difference_values[cell_id] = v - f[cell_id]; }); + + REQUIRE(same_values(v - f, difference_values)); + REQUIRE(same_values(v - const_f, difference_values)); + } + { + Array<TinyVector<VectorDimension>> difference_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(CellId cell_id) { difference_values[cell_id] = f[cell_id] - v; }); + + REQUIRE(same_values(f - v, difference_values)); + REQUIRE(same_values(const_f - v, difference_values)); + } + } + + SECTION("product") + { + { + const double a = 2.3; + Array<TinyVector<VectorDimension>> product_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = a * f[cell_id]; }); + + REQUIRE(same_values(a * f, product_values)); + REQUIRE(same_values(a * const_f, product_values)); + } + + { + DiscreteFunctionP0<Dimension, double> a{mesh}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + const double x = xj[cell_id][0]; + a[cell_id] = 2 * x * x - 1; + }); + + Array<TinyVector<VectorDimension>> product_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = a[cell_id] * f[cell_id]; }); + + REQUIRE(same_values(a * f, product_values)); + REQUIRE(same_values(a * const_f, product_values)); + } + + { + const TinyMatrix<VectorDimension> A{1, 2, 3, 4}; + Array<TinyVector<VectorDimension>> product_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = A * f[cell_id]; }); + + REQUIRE(same_values(A * f, product_values)); + REQUIRE(same_values(A * const_f, product_values)); + } + + { + Array<TinyVector<VectorDimension>> product_values{mesh->numberOfCells()}; + DiscreteFunctionP0<Dimension, TinyMatrix<VectorDimension>> M{mesh}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + const double x = xj[cell_id][0]; + M[cell_id] = TinyMatrix<2>{x, 2 * x, 1 - x, 2 - x * x}; + }); + + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = M[cell_id] * f[cell_id]; }); + + REQUIRE(same_values(M * f, product_values)); + REQUIRE(same_values(M * const_f, product_values)); + } + } + } + + SECTION("matrix functions") + { + constexpr std::uint64_t MatrixDimension = 2; + + DiscreteFunctionP0<Dimension, TinyMatrix<MatrixDimension>> f{mesh}; parallel_for( - mesh->numberOfCells(), - PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = M[cell_id] * f[cell_id]; }); + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + const double x = xj[cell_id][0]; + const double y = xj[cell_id][1]; + const double z = xj[cell_id][2]; + const TinyMatrix<MatrixDimension> X{x, 2 - y, x * y, y * z + 3}; + f[cell_id] = 2 * X + TinyMatrix<2>{1, 2, 3, 4}; + }); - REQUIRE(same_values(M * f, product_values)); - REQUIRE(same_values(M * const_f, product_values)); + DiscreteFunctionP0<Dimension, const TinyMatrix<MatrixDimension>> const_f = f; + + SECTION("sum") + { + const TinyMatrix<MatrixDimension> A{1, 2, 3, 4}; + { + Array<TinyMatrix<MatrixDimension>> sum_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { sum_values[cell_id] = A + f[cell_id]; }); + + REQUIRE(same_values(A + f, sum_values)); + REQUIRE(same_values(A + const_f, sum_values)); + } + { + Array<TinyMatrix<MatrixDimension>> sum_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { sum_values[cell_id] = f[cell_id] + A; }); + + REQUIRE(same_values(f + A, sum_values)); + REQUIRE(same_values(const_f + A, sum_values)); + } + } + + SECTION("difference") + { + const TinyMatrix<MatrixDimension> A{1, 2, 3, 4}; + { + Array<TinyMatrix<MatrixDimension>> difference_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(CellId cell_id) { difference_values[cell_id] = A - f[cell_id]; }); + + REQUIRE(same_values(A - f, difference_values)); + REQUIRE(same_values(A - const_f, difference_values)); + } + { + Array<TinyMatrix<MatrixDimension>> difference_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(CellId cell_id) { difference_values[cell_id] = f[cell_id] - A; }); + + REQUIRE(same_values(f - A, difference_values)); + REQUIRE(same_values(const_f - A, difference_values)); + } + } + + SECTION("product") + { + { + const double a = 2.3; + Array<TinyMatrix<MatrixDimension>> product_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = a * f[cell_id]; }); + + REQUIRE(same_values(a * f, product_values)); + REQUIRE(same_values(a * const_f, product_values)); + } + + { + DiscreteFunctionP0<Dimension, double> a{mesh}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + const double x = xj[cell_id][0]; + a[cell_id] = 2 * x * x - 1; + }); + + Array<TinyMatrix<MatrixDimension>> product_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = a[cell_id] * f[cell_id]; }); + + REQUIRE(same_values(a * f, product_values)); + REQUIRE(same_values(a * const_f, product_values)); + } + + { + const TinyMatrix<MatrixDimension> A{1, 2, 3, 4}; + Array<TinyMatrix<MatrixDimension>> product_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = A * f[cell_id]; }); + + REQUIRE(same_values(A * f, product_values)); + REQUIRE(same_values(A * const_f, product_values)); + } + + { + const TinyMatrix<MatrixDimension> A{1, 2, 3, 4}; + Array<TinyMatrix<MatrixDimension>> product_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = f[cell_id] * A; }); + + REQUIRE(same_values(f * A, product_values)); + REQUIRE(same_values(const_f * A, product_values)); + } + } } } } + } + } + } - SECTION("matrix functions") - { - constexpr std::uint64_t MatrixDimension = 2; + SECTION("math functions") + { +#define CHECK_STD_MATH_FUNCTION(data_expression, FCT) \ + { \ + DiscreteFunctionP0 data = data_expression; \ + DiscreteFunctionP0 result = FCT(data); \ + bool is_same = true; \ + parallel_for(data.cellValues().numberOfItems(), [&](const CellId cell_id) { \ + if (result[cell_id] != std::FCT(data[cell_id])) { \ + is_same = false; \ + } \ + }); \ + REQUIRE(is_same); \ + } - DiscreteFunctionP0<Dimension, TinyMatrix<MatrixDimension>> f{mesh}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - const double x = xj[cell_id][0]; - const TinyMatrix<MatrixDimension> X{x, 2 - x, x * x, x * 3}; - f[cell_id] = 2 * X + TinyMatrix<2>{1, 2, 3, 4}; - }); +#define CHECK_STD_BINARY_MATH_FUNCTION(lhs_expression, rhs_expression, FCT) \ + { \ + DiscreteFunctionP0 lhs = lhs_expression; \ + DiscreteFunctionP0 rhs = rhs_expression; \ + DiscreteFunctionP0 result = FCT(lhs, rhs); \ + using namespace std; \ + bool is_same = true; \ + parallel_for(lhs.cellValues().numberOfItems(), [&](const CellId cell_id) { \ + if (result[cell_id] != FCT(lhs[cell_id], rhs[cell_id])) { \ + is_same = false; \ + } \ + }); \ + REQUIRE(is_same); \ + } - DiscreteFunctionP0<Dimension, const TinyMatrix<MatrixDimension>> const_f = f; +#define CHECK_STD_BINARY_MATH_FUNCTION_WITH_LHS_VALUE(lhs, rhs_expression, FCT) \ + { \ + DiscreteFunctionP0 rhs = rhs_expression; \ + DiscreteFunctionP0 result = FCT(lhs, rhs); \ + bool is_same = true; \ + using namespace std; \ + parallel_for(rhs.cellValues().numberOfItems(), [&](const CellId cell_id) { \ + if (result[cell_id] != FCT(lhs, rhs[cell_id])) { \ + is_same = false; \ + } \ + }); \ + REQUIRE(is_same); \ + } - SECTION("sum") - { - const TinyMatrix<MatrixDimension> A{1, 2, 3, 4}; - { - Array<TinyMatrix<MatrixDimension>> sum_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { sum_values[cell_id] = A + f[cell_id]; }); +#define CHECK_STD_BINARY_MATH_FUNCTION_WITH_RHS_VALUE(lhs_expression, rhs, FCT) \ + { \ + DiscreteFunctionP0 lhs = lhs_expression; \ + DiscreteFunctionP0 result = FCT(lhs, rhs); \ + bool is_same = true; \ + using namespace std; \ + parallel_for(lhs.cellValues().numberOfItems(), [&](const CellId cell_id) { \ + if (result[cell_id] != FCT(lhs[cell_id], rhs)) { \ + is_same = false; \ + } \ + }); \ + REQUIRE(is_same); \ + } - REQUIRE(same_values(A + f, sum_values)); - REQUIRE(same_values(A + const_f, sum_values)); - } - { - Array<TinyMatrix<MatrixDimension>> sum_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { sum_values[cell_id] = f[cell_id] + A; }); + SECTION("1D") + { + constexpr size_t Dimension = 1; + std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - REQUIRE(same_values(f + A, sum_values)); - REQUIRE(same_values(const_f + A, sum_values)); - } - } + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh = named_mesh.mesh(); - SECTION("difference") - { - const TinyMatrix<MatrixDimension> A{1, 2, 3, 4}; - { - Array<TinyMatrix<MatrixDimension>> difference_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { difference_values[cell_id] = A - f[cell_id]; }); + auto xj = MeshDataManager::instance().getMeshData(*mesh).xj(); - REQUIRE(same_values(A - f, difference_values)); - REQUIRE(same_values(A - const_f, difference_values)); - } - { - Array<TinyMatrix<MatrixDimension>> difference_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { difference_values[cell_id] = f[cell_id] - A; }); + DiscreteFunctionP0<Dimension, double> positive_function{mesh}; + + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(const CellId cell_id) { positive_function[cell_id] = 1 + std::abs(xj[cell_id][0]); }); - REQUIRE(same_values(f - A, difference_values)); - REQUIRE(same_values(const_f - A, difference_values)); + const double min_value = min(positive_function); + SECTION("min") + { + double local_min = std::numeric_limits<double>::max(); + for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++cell_id) { + local_min = std::min(local_min, positive_function[cell_id]); } + REQUIRE(min_value == parallel::allReduceMin(local_min)); } - SECTION("product") + const double max_value = max(positive_function); + SECTION("max") { - { - const double a = 2.3; - Array<TinyMatrix<MatrixDimension>> product_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = a * f[cell_id]; }); - - REQUIRE(same_values(a * f, product_values)); - REQUIRE(same_values(a * const_f, product_values)); + double local_max = -std::numeric_limits<double>::max(); + for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++cell_id) { + local_max = std::max(local_max, positive_function[cell_id]); } + REQUIRE(max_value == parallel::allReduceMax(local_max)); + } - { - DiscreteFunctionP0<Dimension, double> a{mesh}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - const double x = xj[cell_id][0]; - a[cell_id] = 2 * x * x - 1; - }); - - Array<TinyMatrix<MatrixDimension>> product_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), - PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = a[cell_id] * f[cell_id]; }); - - REQUIRE(same_values(a * f, product_values)); - REQUIRE(same_values(a * const_f, product_values)); - } + REQUIRE(min_value < max_value); - { - const TinyMatrix<MatrixDimension> A{1, 2, 3, 4}; - Array<TinyMatrix<MatrixDimension>> product_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = A * f[cell_id]; }); + DiscreteFunctionP0 unsigned_function = positive_function - 0.5 * (min_value + max_value); - REQUIRE(same_values(A * f, product_values)); - REQUIRE(same_values(A * const_f, product_values)); - } + SECTION("sqrt") + { + CHECK_STD_MATH_FUNCTION(positive_function, sqrt); + } - { - const TinyMatrix<MatrixDimension> A{1, 2, 3, 4}; - Array<TinyMatrix<MatrixDimension>> product_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = f[cell_id] * A; }); + SECTION("abs") + { + CHECK_STD_MATH_FUNCTION(positive_function, abs); + } - REQUIRE(same_values(f * A, product_values)); - REQUIRE(same_values(const_f * A, product_values)); - } + SECTION("cos") + { + CHECK_STD_MATH_FUNCTION(positive_function, cos); } - } - } - } - SECTION("2D") - { - std::shared_ptr mesh = MeshDataBaseForTests::get().cartesianMesh2D(); + SECTION("sin") + { + CHECK_STD_MATH_FUNCTION(positive_function, sin); + } - constexpr size_t Dimension = 2; + SECTION("tan") + { + CHECK_STD_MATH_FUNCTION(positive_function, tan); + } - auto xj = MeshDataManager::instance().getMeshData(*mesh).xj(); + DiscreteFunctionP0<Dimension, double> unit_function{mesh}; - SECTION("inner operators") - { - SECTION("scalar functions") - { - DiscreteFunctionP0<Dimension, double> f{mesh}; parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - const double x = xj[cell_id][0]; - const double y = xj[cell_id][1]; - f[cell_id] = 2 * x + y + 1; + mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { + unit_function[cell_id] = + (2 * (positive_function[cell_id] - min_value) / (max_value - min_value) - 1) * 0.95; }); - DiscreteFunctionP0<Dimension, double> g{mesh}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - const double x = xj[cell_id][0]; - const double y = xj[cell_id][1]; - g[cell_id] = std::abs((x + 1) * (x - 2) + y * (1 + y)) + 1; - }); + SECTION("acos") + { + CHECK_STD_MATH_FUNCTION(unit_function, acos); + } - DiscreteFunctionP0<Dimension, const double> const_f = f; - DiscreteFunctionP0<Dimension, const double> const_g{g}; + SECTION("asin") + { + CHECK_STD_MATH_FUNCTION(unit_function, asin); + } - SECTION("sum") + SECTION("atan") { - Array<double> sum_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { sum_values[cell_id] = f[cell_id] + g[cell_id]; }); + CHECK_STD_MATH_FUNCTION(unit_function, atan); + } - REQUIRE(same_values(f + g, sum_values)); - REQUIRE(same_values(const_f + g, sum_values)); - REQUIRE(same_values(f + const_g, sum_values)); - REQUIRE(same_values(const_f + const_g, sum_values)); + SECTION("cosh") + { + CHECK_STD_MATH_FUNCTION(positive_function, cosh); } - SECTION("difference") + SECTION("sinh") { - Array<double> difference_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), - PUGS_LAMBDA(CellId cell_id) { difference_values[cell_id] = f[cell_id] - g[cell_id]; }); + CHECK_STD_MATH_FUNCTION(positive_function, sinh); + } - REQUIRE(same_values(f - g, difference_values)); - REQUIRE(same_values(const_f - g, difference_values)); - REQUIRE(same_values(f - const_g, difference_values)); - REQUIRE(same_values(const_f - const_g, difference_values)); + SECTION("tanh") + { + CHECK_STD_MATH_FUNCTION(positive_function, tanh); } - SECTION("product") + SECTION("acosh") { - Array<double> product_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), - PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = f[cell_id] * g[cell_id]; }); + CHECK_STD_MATH_FUNCTION(positive_function, acosh); + } - REQUIRE(same_values(f * g, product_values)); - REQUIRE(same_values(const_f * g, product_values)); - REQUIRE(same_values(f * const_g, product_values)); - REQUIRE(same_values(const_f * const_g, product_values)); + SECTION("asinh") + { + CHECK_STD_MATH_FUNCTION(positive_function, asinh); } - SECTION("ratio") + SECTION("atanh") { - Array<double> ratio_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { ratio_values[cell_id] = f[cell_id] / g[cell_id]; }); + CHECK_STD_MATH_FUNCTION(unit_function, atanh); + } - REQUIRE(same_values(f / g, ratio_values)); - REQUIRE(same_values(const_f / g, ratio_values)); - REQUIRE(same_values(f / const_g, ratio_values)); - REQUIRE(same_values(const_f / const_g, ratio_values)); + SECTION("exp") + { + CHECK_STD_MATH_FUNCTION(positive_function, exp); } - } - SECTION("vector functions") - { - constexpr std::uint64_t VectorDimension = 2; + SECTION("log") + { + CHECK_STD_MATH_FUNCTION(positive_function, log); + } - DiscreteFunctionP0<Dimension, TinyVector<VectorDimension>> f{mesh}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - const double x = xj[cell_id][0]; - const TinyVector<VectorDimension> X{x, 2 - x}; - f[cell_id] = 2 * X + TinyVector<2>{1, 2}; - }); + SECTION("max(uh,hv)") + { + CHECK_STD_BINARY_MATH_FUNCTION(cos(positive_function), sin(positive_function), max); + } - DiscreteFunctionP0<Dimension, TinyVector<VectorDimension>> g{mesh}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - const double x = xj[cell_id][0]; - const TinyVector<VectorDimension> X{3 * x + 1, 2 + x}; - g[cell_id] = X; - }); + SECTION("max(0.2,vh)") + { + CHECK_STD_BINARY_MATH_FUNCTION_WITH_LHS_VALUE(0.2, sin(positive_function), max); + } - DiscreteFunctionP0<Dimension, const TinyVector<VectorDimension>> const_f = f; - DiscreteFunctionP0<Dimension, const TinyVector<VectorDimension>> const_g{g}; + SECTION("max(uh,0.2)") + { + CHECK_STD_BINARY_MATH_FUNCTION_WITH_RHS_VALUE(cos(positive_function), 0.2, max); + } - SECTION("sum") + SECTION("atan2(uh,hv)") { - Array<TinyVector<VectorDimension>> sum_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { sum_values[cell_id] = f[cell_id] + g[cell_id]; }); + CHECK_STD_BINARY_MATH_FUNCTION(positive_function, 2 + positive_function, atan2); + } - REQUIRE(same_values(f + g, sum_values)); - REQUIRE(same_values(const_f + g, sum_values)); - REQUIRE(same_values(f + const_g, sum_values)); - REQUIRE(same_values(const_f + const_g, sum_values)); + SECTION("atan2(0.5,uh)") + { + CHECK_STD_BINARY_MATH_FUNCTION_WITH_LHS_VALUE(0.5, 2 + positive_function, atan2); } - SECTION("difference") + SECTION("atan2(uh,0.2)") { - Array<TinyVector<VectorDimension>> difference_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), - PUGS_LAMBDA(CellId cell_id) { difference_values[cell_id] = f[cell_id] - g[cell_id]; }); + CHECK_STD_BINARY_MATH_FUNCTION_WITH_RHS_VALUE(2 + cos(positive_function), 0.2, atan2); + } - REQUIRE(same_values(f - g, difference_values)); - REQUIRE(same_values(const_f - g, difference_values)); - REQUIRE(same_values(f - const_g, difference_values)); - REQUIRE(same_values(const_f - const_g, difference_values)); + SECTION("pow(uh,hv)") + { + CHECK_STD_BINARY_MATH_FUNCTION(positive_function, 0.5 * positive_function, pow); } - } - SECTION("matrix functions") - { - constexpr std::uint64_t MatrixDimension = 2; + SECTION("pow(uh,0.5)") + { + CHECK_STD_BINARY_MATH_FUNCTION_WITH_LHS_VALUE(0.5, positive_function, pow); + } - DiscreteFunctionP0<Dimension, TinyMatrix<MatrixDimension>> f{mesh}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - const double x = xj[cell_id][0]; - const TinyMatrix<MatrixDimension> A{x, 2 - x, 2 * x, x * x - 3}; - f[cell_id] = 2 * A + TinyMatrix<2>{1, 2, 3, 4}; - }); + SECTION("pow(uh,0.2)") + { + CHECK_STD_BINARY_MATH_FUNCTION_WITH_RHS_VALUE(positive_function, 1.3, pow); + } - DiscreteFunctionP0<Dimension, TinyMatrix<MatrixDimension>> g{mesh}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - const double x = xj[cell_id][0]; - const TinyMatrix<MatrixDimension> A{3 * x + 1, 2 + x, 1 - 2 * x, 2 * x * x}; - g[cell_id] = A; - }); + SECTION("min(uh,hv)") + { + CHECK_STD_BINARY_MATH_FUNCTION(sin(positive_function), cos(positive_function), min); + } - DiscreteFunctionP0<Dimension, const TinyMatrix<MatrixDimension>> const_f = f; - DiscreteFunctionP0<Dimension, const TinyMatrix<MatrixDimension>> const_g{g}; + SECTION("min(uh,0.5)") + { + CHECK_STD_BINARY_MATH_FUNCTION_WITH_LHS_VALUE(0.5, cos(positive_function), min); + } - SECTION("sum") + SECTION("min(uh,0.2)") { - Array<TinyMatrix<MatrixDimension>> sum_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { sum_values[cell_id] = f[cell_id] + g[cell_id]; }); + CHECK_STD_BINARY_MATH_FUNCTION_WITH_RHS_VALUE(sin(positive_function), 0.5, min); + } - REQUIRE(same_values(f + g, sum_values)); - REQUIRE(same_values(const_f + g, sum_values)); - REQUIRE(same_values(f + const_g, sum_values)); - REQUIRE(same_values(const_f + const_g, sum_values)); + SECTION("max(uh,hv)") + { + CHECK_STD_BINARY_MATH_FUNCTION(sin(positive_function), cos(positive_function), max); } - SECTION("difference") + SECTION("min(uh,0.5)") { - Array<TinyMatrix<MatrixDimension>> difference_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), - PUGS_LAMBDA(CellId cell_id) { difference_values[cell_id] = f[cell_id] - g[cell_id]; }); + CHECK_STD_BINARY_MATH_FUNCTION_WITH_LHS_VALUE(0.1, cos(positive_function), max); + } - REQUIRE(same_values(f - g, difference_values)); - REQUIRE(same_values(const_f - g, difference_values)); - REQUIRE(same_values(f - const_g, difference_values)); - REQUIRE(same_values(const_f - const_g, difference_values)); + SECTION("min(uh,0.2)") + { + CHECK_STD_BINARY_MATH_FUNCTION_WITH_RHS_VALUE(sin(positive_function), 0.1, max); } - SECTION("product") + SECTION("dot(uh,hv)") { - Array<TinyMatrix<MatrixDimension>> product_values{mesh->numberOfCells()}; + DiscreteFunctionP0<Dimension, TinyVector<2>> uh{mesh}; parallel_for( - mesh->numberOfCells(), - PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = f[cell_id] * g[cell_id]; }); + mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { + const double x = xj[cell_id][0]; + uh[cell_id] = TinyVector<2>{x + 1, 2 * x - 3}; + }); + + DiscreteFunctionP0<Dimension, TinyVector<2>> vh{mesh}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { + const double x = xj[cell_id][0]; + vh[cell_id] = TinyVector<2>{2.3 * x, 1 - x}; + }); - REQUIRE(same_values(f * g, product_values)); - REQUIRE(same_values(const_f * g, product_values)); - REQUIRE(same_values(f * const_g, product_values)); - REQUIRE(same_values(const_f * const_g, product_values)); + CHECK_STD_BINARY_MATH_FUNCTION(uh, vh, dot); } - } - } - SECTION("external operators") - { - SECTION("scalar functions") - { - DiscreteFunctionP0<Dimension, double> f{mesh}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - const double x = xj[cell_id][0]; - const double y = xj[cell_id][1]; - f[cell_id] = std::abs(2 * x + y) + 1; - }); + SECTION("dot(uh,v)") + { + DiscreteFunctionP0<Dimension, TinyVector<2>> uh{mesh}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { + const double x = xj[cell_id][0]; + uh[cell_id] = TinyVector<2>{x + 1, 2 * x - 3}; + }); - const double a = 3; + const TinyVector<2> v{1, 2}; - DiscreteFunctionP0<Dimension, const double> const_f = f; + CHECK_STD_BINARY_MATH_FUNCTION_WITH_RHS_VALUE(uh, v, dot); + } - SECTION("sum") + SECTION("dot(u,hv)") { - { - Array<double> sum_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { sum_values[cell_id] = a + f[cell_id]; }); + const TinyVector<2> u{3, -2}; - REQUIRE(same_values(a + f, sum_values)); - REQUIRE(same_values(a + const_f, sum_values)); - } - { - Array<double> sum_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { sum_values[cell_id] = f[cell_id] + a; }); + DiscreteFunctionP0<Dimension, TinyVector<2>> vh{mesh}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { + const double x = xj[cell_id][0]; + vh[cell_id] = TinyVector<2>{2.3 * x, 1 - x}; + }); - REQUIRE(same_values(f + a, sum_values)); - REQUIRE(same_values(const_f + a, sum_values)); - } + CHECK_STD_BINARY_MATH_FUNCTION_WITH_LHS_VALUE(u, vh, dot); } - SECTION("difference") + SECTION("scalar sum") { - { - Array<double> difference_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { difference_values[cell_id] = a - f[cell_id]; }); - REQUIRE(same_values(a - f, difference_values)); - REQUIRE(same_values(a - const_f, difference_values)); - } + const CellValue<const double> cell_value = positive_function.cellValues(); - { - Array<double> difference_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { difference_values[cell_id] = f[cell_id] - a; }); - REQUIRE(same_values(f - a, difference_values)); - REQUIRE(same_values(const_f - a, difference_values)); - } + REQUIRE(sum(cell_value) == sum(positive_function)); } - SECTION("product") + SECTION("vector sum") { - { - Array<double> product_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = a * f[cell_id]; }); - - REQUIRE(same_values(a * f, product_values)); - REQUIRE(same_values(a * const_f, product_values)); - } - { - Array<double> product_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = f[cell_id] * a; }); - - REQUIRE(same_values(f * a, product_values)); - REQUIRE(same_values(const_f * a, product_values)); - } + DiscreteFunctionP0<Dimension, TinyVector<2>> uh{mesh}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { + const double x = xj[cell_id][0]; + uh[cell_id] = TinyVector<2>{x + 1, 2 * x - 3}; + }); + const CellValue<const TinyVector<2>> cell_value = uh.cellValues(); - { - Array<TinyVector<3>> product_values{mesh->numberOfCells()}; - const TinyVector<3> v{1, 2, 3}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = f[cell_id] * v; }); + REQUIRE(sum(cell_value) == sum(uh)); + } - REQUIRE(same_values(f * v, product_values)); - REQUIRE(same_values(const_f * v, product_values)); - } + SECTION("matrix sum") + { + DiscreteFunctionP0<Dimension, TinyMatrix<2>> uh{mesh}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { + const double x = xj[cell_id][0]; + uh[cell_id] = TinyMatrix<2>{x + 1, 2 * x - 3, 2 * x, 3 * x - 1}; + }); + const CellValue<const TinyMatrix<2>> cell_value = uh.cellValues(); - { - Array<TinyVector<3>> product_values{mesh->numberOfCells()}; - DiscreteFunctionP0<Dimension, TinyVector<3>> v{mesh}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - const double x = xj[cell_id][0]; - v[cell_id] = TinyVector<3>{x, 2 * x, 1 - x}; - }); + REQUIRE(sum(cell_value) == sum(uh)); + } - parallel_for( - mesh->numberOfCells(), - PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = f[cell_id] * v[cell_id]; }); + SECTION("integrate scalar") + { + const CellValue<const double> cell_volume = MeshDataManager::instance().getMeshData(*mesh).Vj(); - REQUIRE(same_values(f * v, product_values)); - REQUIRE(same_values(const_f * v, product_values)); - } + CellValue<double> cell_value{mesh->connectivity()}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { + cell_value[cell_id] = cell_volume[cell_id] * positive_function[cell_id]; + }); - { - Array<TinyMatrix<2>> product_values{mesh->numberOfCells()}; - const TinyMatrix<2> A{1, 2, 3, 4}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = f[cell_id] * A; }); + REQUIRE(integrate(positive_function) == Catch::Approx(sum(cell_value))); + } - REQUIRE(same_values(f * A, product_values)); - REQUIRE(same_values(const_f * A, product_values)); - } + SECTION("integrate vector") + { + DiscreteFunctionP0<Dimension, TinyVector<2>> uh{mesh}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { + const double x = xj[cell_id][0]; + uh[cell_id] = TinyVector<2>{x + 1, 2 * x - 3}; + }); - { - Array<TinyMatrix<2>> product_values{mesh->numberOfCells()}; - DiscreteFunctionP0<Dimension, TinyMatrix<2>> M{mesh}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - const double x = xj[cell_id][0]; - M[cell_id] = TinyMatrix<2>{x, 2 * x, 1 - x, 2 - x * x}; - }); + const CellValue<const double> cell_volume = MeshDataManager::instance().getMeshData(*mesh).Vj(); - parallel_for( - mesh->numberOfCells(), - PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = f[cell_id] * M[cell_id]; }); + CellValue<TinyVector<2>> cell_value{mesh->connectivity()}; + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(const CellId cell_id) { cell_value[cell_id] = cell_volume[cell_id] * uh[cell_id]; }); - REQUIRE(same_values(f * M, product_values)); - REQUIRE(same_values(const_f * M, product_values)); - } + REQUIRE(integrate(uh)[0] == Catch::Approx(sum(cell_value)[0])); + REQUIRE(integrate(uh)[1] == Catch::Approx(sum(cell_value)[1])); } - SECTION("ratio") + SECTION("integrate matrix") { - { - Array<double> ratio_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { ratio_values[cell_id] = a / f[cell_id]; }); + DiscreteFunctionP0<Dimension, TinyMatrix<2>> uh{mesh}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { + const double x = xj[cell_id][0]; + uh[cell_id] = TinyMatrix<2>{x + 1, 2 * x - 3, 2 * x, 1 - x}; + }); - REQUIRE(same_values(a / f, ratio_values)); - REQUIRE(same_values(a / const_f, ratio_values)); - } - { - Array<double> ratio_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { ratio_values[cell_id] = f[cell_id] / a; }); + const CellValue<const double> cell_volume = MeshDataManager::instance().getMeshData(*mesh).Vj(); - REQUIRE(same_values(f / a, ratio_values)); - REQUIRE(same_values(const_f / a, ratio_values)); - } + CellValue<TinyMatrix<2>> cell_value{mesh->connectivity()}; + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(const CellId cell_id) { cell_value[cell_id] = cell_volume[cell_id] * uh[cell_id]; }); + + REQUIRE(integrate(uh)(0, 0) == Catch::Approx(sum(cell_value)(0, 0))); + REQUIRE(integrate(uh)(0, 1) == Catch::Approx(sum(cell_value)(0, 1))); + REQUIRE(integrate(uh)(1, 0) == Catch::Approx(sum(cell_value)(1, 0))); + REQUIRE(integrate(uh)(1, 1) == Catch::Approx(sum(cell_value)(1, 1))); } } + } + } + + SECTION("2D") + { + constexpr size_t Dimension = 2; - SECTION("vector functions") + std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); + + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) { - constexpr std::uint64_t VectorDimension = 2; + auto mesh = named_mesh.mesh(); - DiscreteFunctionP0<Dimension, TinyVector<VectorDimension>> f{mesh}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - const double x = xj[cell_id][0]; - const double y = xj[cell_id][1]; - const TinyVector<VectorDimension> X{x + y, 2 - x * y}; - f[cell_id] = 2 * X + TinyVector<2>{1, 2}; - }); + auto xj = MeshDataManager::instance().getMeshData(*mesh).xj(); - DiscreteFunctionP0<Dimension, const TinyVector<VectorDimension>> const_f = f; + DiscreteFunctionP0<Dimension, double> positive_function{mesh}; - SECTION("sum") - { - const TinyVector<VectorDimension> v{1, 2}; - { - Array<TinyVector<VectorDimension>> sum_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { sum_values[cell_id] = v + f[cell_id]; }); + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(const CellId cell_id) { positive_function[cell_id] = 1 + std::abs(xj[cell_id][0]); }); - REQUIRE(same_values(v + f, sum_values)); - REQUIRE(same_values(v + const_f, sum_values)); + const double min_value = min(positive_function); + SECTION("min") + { + double local_min = std::numeric_limits<double>::max(); + for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++cell_id) { + local_min = std::min(local_min, positive_function[cell_id]); } - { - Array<TinyVector<VectorDimension>> sum_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { sum_values[cell_id] = f[cell_id] + v; }); + REQUIRE(min_value == parallel::allReduceMin(local_min)); + } - REQUIRE(same_values(f + v, sum_values)); - REQUIRE(same_values(const_f + v, sum_values)); + const double max_value = max(positive_function); + SECTION("max") + { + double local_max = -std::numeric_limits<double>::max(); + for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++cell_id) { + local_max = std::max(local_max, positive_function[cell_id]); } + REQUIRE(max_value == parallel::allReduceMax(local_max)); } - SECTION("difference") - { - const TinyVector<VectorDimension> v{1, 2}; - { - Array<TinyVector<VectorDimension>> difference_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { difference_values[cell_id] = v - f[cell_id]; }); + REQUIRE(min_value < max_value); - REQUIRE(same_values(v - f, difference_values)); - REQUIRE(same_values(v - const_f, difference_values)); - } - { - Array<TinyVector<VectorDimension>> difference_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { difference_values[cell_id] = f[cell_id] - v; }); + DiscreteFunctionP0 unsigned_function = positive_function - 0.5 * (min_value + max_value); - REQUIRE(same_values(f - v, difference_values)); - REQUIRE(same_values(const_f - v, difference_values)); - } + SECTION("sqrt") + { + CHECK_STD_MATH_FUNCTION(positive_function, sqrt); } - SECTION("product") + SECTION("abs") { - { - const double a = 2.3; - Array<TinyVector<VectorDimension>> product_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = a * f[cell_id]; }); + CHECK_STD_MATH_FUNCTION(positive_function, abs); + } - REQUIRE(same_values(a * f, product_values)); - REQUIRE(same_values(a * const_f, product_values)); - } + SECTION("cos") + { + CHECK_STD_MATH_FUNCTION(positive_function, cos); + } - { - DiscreteFunctionP0<Dimension, double> a{mesh}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - const double x = xj[cell_id][0]; - a[cell_id] = 2 * x * x - 1; - }); + SECTION("sin") + { + CHECK_STD_MATH_FUNCTION(positive_function, sin); + } - Array<TinyVector<VectorDimension>> product_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), - PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = a[cell_id] * f[cell_id]; }); + SECTION("tan") + { + CHECK_STD_MATH_FUNCTION(positive_function, tan); + } - REQUIRE(same_values(a * f, product_values)); - REQUIRE(same_values(a * const_f, product_values)); - } + DiscreteFunctionP0<Dimension, double> unit_function{mesh}; - { - const TinyMatrix<VectorDimension> A{1, 2, 3, 4}; - Array<TinyVector<VectorDimension>> product_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = A * f[cell_id]; }); + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { + unit_function[cell_id] = + (2 * (positive_function[cell_id] - min_value) / (max_value - min_value) - 1) * 0.95; + }); - REQUIRE(same_values(A * f, product_values)); - REQUIRE(same_values(A * const_f, product_values)); - } + SECTION("acos") + { + CHECK_STD_MATH_FUNCTION(unit_function, acos); + } - { - Array<TinyVector<VectorDimension>> product_values{mesh->numberOfCells()}; - DiscreteFunctionP0<Dimension, TinyMatrix<VectorDimension>> M{mesh}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - const double x = xj[cell_id][0]; - M[cell_id] = TinyMatrix<2>{x, 2 * x, 1 - x, 2 - x * x}; - }); + SECTION("asin") + { + CHECK_STD_MATH_FUNCTION(unit_function, asin); + } - parallel_for( - mesh->numberOfCells(), - PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = M[cell_id] * f[cell_id]; }); + SECTION("atan") + { + CHECK_STD_MATH_FUNCTION(unit_function, atan); + } - REQUIRE(same_values(M * f, product_values)); - REQUIRE(same_values(M * const_f, product_values)); - } + SECTION("cosh") + { + CHECK_STD_MATH_FUNCTION(positive_function, cosh); } - } - SECTION("matrix functions") - { - constexpr std::uint64_t MatrixDimension = 2; + SECTION("sinh") + { + CHECK_STD_MATH_FUNCTION(positive_function, sinh); + } - DiscreteFunctionP0<Dimension, TinyMatrix<MatrixDimension>> f{mesh}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - const double x = xj[cell_id][0]; - const double y = xj[cell_id][1]; - const TinyMatrix<MatrixDimension> X{x, 2 - y, x * y, y * 3}; - f[cell_id] = 2 * X + TinyMatrix<2>{1, 2, 3, 4}; - }); + SECTION("tanh") + { + CHECK_STD_MATH_FUNCTION(positive_function, tanh); + } - DiscreteFunctionP0<Dimension, const TinyMatrix<MatrixDimension>> const_f = f; + SECTION("acosh") + { + CHECK_STD_MATH_FUNCTION(positive_function, acosh); + } - SECTION("sum") + SECTION("asinh") { - const TinyMatrix<MatrixDimension> A{1, 2, 3, 4}; - { - Array<TinyMatrix<MatrixDimension>> sum_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { sum_values[cell_id] = A + f[cell_id]; }); + CHECK_STD_MATH_FUNCTION(positive_function, asinh); + } - REQUIRE(same_values(A + f, sum_values)); - REQUIRE(same_values(A + const_f, sum_values)); - } - { - Array<TinyMatrix<MatrixDimension>> sum_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { sum_values[cell_id] = f[cell_id] + A; }); + SECTION("atanh") + { + CHECK_STD_MATH_FUNCTION(unit_function, atanh); + } - REQUIRE(same_values(f + A, sum_values)); - REQUIRE(same_values(const_f + A, sum_values)); - } + SECTION("exp") + { + CHECK_STD_MATH_FUNCTION(positive_function, exp); } - SECTION("difference") + SECTION("log") { - const TinyMatrix<MatrixDimension> A{1, 2, 3, 4}; - { - Array<TinyMatrix<MatrixDimension>> difference_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { difference_values[cell_id] = A - f[cell_id]; }); + CHECK_STD_MATH_FUNCTION(positive_function, log); + } - REQUIRE(same_values(A - f, difference_values)); - REQUIRE(same_values(A - const_f, difference_values)); - } - { - Array<TinyMatrix<MatrixDimension>> difference_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { difference_values[cell_id] = f[cell_id] - A; }); + SECTION("max(uh,hv)") + { + CHECK_STD_BINARY_MATH_FUNCTION(cos(positive_function), sin(positive_function), max); + } - REQUIRE(same_values(f - A, difference_values)); - REQUIRE(same_values(const_f - A, difference_values)); - } + SECTION("max(0.2,vh)") + { + CHECK_STD_BINARY_MATH_FUNCTION_WITH_LHS_VALUE(0.2, sin(positive_function), max); } - SECTION("product") + SECTION("max(uh,0.2)") { - { - const double a = 2.3; - Array<TinyMatrix<MatrixDimension>> product_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = a * f[cell_id]; }); + CHECK_STD_BINARY_MATH_FUNCTION_WITH_RHS_VALUE(cos(positive_function), 0.2, max); + } - REQUIRE(same_values(a * f, product_values)); - REQUIRE(same_values(a * const_f, product_values)); - } + SECTION("atan2(uh,hv)") + { + CHECK_STD_BINARY_MATH_FUNCTION(positive_function, 2 + positive_function, atan2); + } - { - DiscreteFunctionP0<Dimension, double> a{mesh}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - const double x = xj[cell_id][0]; - a[cell_id] = 2 * x * x - 1; - }); + SECTION("atan2(0.5,uh)") + { + CHECK_STD_BINARY_MATH_FUNCTION_WITH_LHS_VALUE(0.5, 2 + positive_function, atan2); + } - Array<TinyMatrix<MatrixDimension>> product_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), - PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = a[cell_id] * f[cell_id]; }); + SECTION("atan2(uh,0.2)") + { + CHECK_STD_BINARY_MATH_FUNCTION_WITH_RHS_VALUE(2 + cos(positive_function), 0.2, atan2); + } - REQUIRE(same_values(a * f, product_values)); - REQUIRE(same_values(a * const_f, product_values)); - } + SECTION("pow(uh,hv)") + { + CHECK_STD_BINARY_MATH_FUNCTION(positive_function, 0.5 * positive_function, pow); + } - { - const TinyMatrix<MatrixDimension> A{1, 2, 3, 4}; - Array<TinyMatrix<MatrixDimension>> product_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = A * f[cell_id]; }); + SECTION("pow(uh,0.5)") + { + CHECK_STD_BINARY_MATH_FUNCTION_WITH_LHS_VALUE(0.5, positive_function, pow); + } - REQUIRE(same_values(A * f, product_values)); - REQUIRE(same_values(A * const_f, product_values)); - } + SECTION("pow(uh,0.2)") + { + CHECK_STD_BINARY_MATH_FUNCTION_WITH_RHS_VALUE(positive_function, 1.3, pow); + } - { - const TinyMatrix<MatrixDimension> A{1, 2, 3, 4}; - Array<TinyMatrix<MatrixDimension>> product_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = f[cell_id] * A; }); + SECTION("min(uh,hv)") + { + CHECK_STD_BINARY_MATH_FUNCTION(sin(positive_function), cos(positive_function), min); + } - REQUIRE(same_values(f * A, product_values)); - REQUIRE(same_values(const_f * A, product_values)); - } + SECTION("min(uh,0.5)") + { + CHECK_STD_BINARY_MATH_FUNCTION_WITH_LHS_VALUE(0.5, cos(positive_function), min); } - } - } - } - SECTION("3D") - { - std::shared_ptr mesh = MeshDataBaseForTests::get().cartesianMesh3D(); + SECTION("min(uh,0.2)") + { + CHECK_STD_BINARY_MATH_FUNCTION_WITH_RHS_VALUE(sin(positive_function), 0.5, min); + } - constexpr size_t Dimension = 3; + SECTION("max(uh,hv)") + { + CHECK_STD_BINARY_MATH_FUNCTION(sin(positive_function), cos(positive_function), max); + } - auto xj = MeshDataManager::instance().getMeshData(*mesh).xj(); + SECTION("min(uh,0.5)") + { + CHECK_STD_BINARY_MATH_FUNCTION_WITH_LHS_VALUE(0.1, cos(positive_function), max); + } - SECTION("inner operators") - { - SECTION("scalar functions") - { - DiscreteFunctionP0<Dimension, double> f{mesh}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - const double x = xj[cell_id][0]; - const double y = xj[cell_id][1]; - const double z = xj[cell_id][2]; - f[cell_id] = 2 * x + y - z; - }); + SECTION("min(uh,0.2)") + { + CHECK_STD_BINARY_MATH_FUNCTION_WITH_RHS_VALUE(sin(positive_function), 0.1, max); + } - DiscreteFunctionP0<Dimension, double> g{mesh}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - const double x = xj[cell_id][0]; - const double y = xj[cell_id][1]; - const double z = xj[cell_id][2]; - g[cell_id] = std::abs((x + 1) * (x - 2) + y * (1 + y) + 2 * z) + 1; - }); + SECTION("dot(uh,hv)") + { + DiscreteFunctionP0<Dimension, TinyVector<2>> uh{mesh}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { + const double x = xj[cell_id][0]; + uh[cell_id] = TinyVector<2>{x + 1, 2 * x - 3}; + }); + + DiscreteFunctionP0<Dimension, TinyVector<2>> vh{mesh}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { + const double x = xj[cell_id][0]; + vh[cell_id] = TinyVector<2>{2.3 * x, 1 - x}; + }); - DiscreteFunctionP0<Dimension, const double> const_f = f; - DiscreteFunctionP0<Dimension, const double> const_g{g}; + CHECK_STD_BINARY_MATH_FUNCTION(uh, vh, dot); + } - SECTION("sum") + SECTION("dot(uh,v)") { - Array<double> sum_values{mesh->numberOfCells()}; + DiscreteFunctionP0<Dimension, TinyVector<2>> uh{mesh}; parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { sum_values[cell_id] = f[cell_id] + g[cell_id]; }); + mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { + const double x = xj[cell_id][0]; + uh[cell_id] = TinyVector<2>{x + 1, 2 * x - 3}; + }); - REQUIRE(same_values(f + g, sum_values)); - REQUIRE(same_values(const_f + g, sum_values)); - REQUIRE(same_values(f + const_g, sum_values)); - REQUIRE(same_values(const_f + const_g, sum_values)); + const TinyVector<2> v{1, 2}; + + CHECK_STD_BINARY_MATH_FUNCTION_WITH_RHS_VALUE(uh, v, dot); } - SECTION("difference") + SECTION("dot(u,hv)") { - Array<double> difference_values{mesh->numberOfCells()}; + const TinyVector<2> u{3, -2}; + + DiscreteFunctionP0<Dimension, TinyVector<2>> vh{mesh}; parallel_for( - mesh->numberOfCells(), - PUGS_LAMBDA(CellId cell_id) { difference_values[cell_id] = f[cell_id] - g[cell_id]; }); + mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { + const double x = xj[cell_id][0]; + vh[cell_id] = TinyVector<2>{2.3 * x, 1 - x}; + }); - REQUIRE(same_values(f - g, difference_values)); - REQUIRE(same_values(const_f - g, difference_values)); - REQUIRE(same_values(f - const_g, difference_values)); - REQUIRE(same_values(const_f - const_g, difference_values)); + CHECK_STD_BINARY_MATH_FUNCTION_WITH_LHS_VALUE(u, vh, dot); } - SECTION("product") + SECTION("scalar sum") { - Array<double> product_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), - PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = f[cell_id] * g[cell_id]; }); + const CellValue<const double> cell_value = positive_function.cellValues(); - REQUIRE(same_values(f * g, product_values)); - REQUIRE(same_values(const_f * g, product_values)); - REQUIRE(same_values(f * const_g, product_values)); - REQUIRE(same_values(const_f * const_g, product_values)); + REQUIRE(sum(cell_value) == sum(positive_function)); } - SECTION("ratio") + SECTION("vector sum") { - Array<double> ratio_values{mesh->numberOfCells()}; + DiscreteFunctionP0<Dimension, TinyVector<2>> uh{mesh}; parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { ratio_values[cell_id] = f[cell_id] / g[cell_id]; }); + mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { + const double x = xj[cell_id][0]; + uh[cell_id] = TinyVector<2>{x + 1, 2 * x - 3}; + }); + const CellValue<const TinyVector<2>> cell_value = uh.cellValues(); - REQUIRE(same_values(f / g, ratio_values)); - REQUIRE(same_values(const_f / g, ratio_values)); - REQUIRE(same_values(f / const_g, ratio_values)); - REQUIRE(same_values(const_f / const_g, ratio_values)); + REQUIRE(sum(cell_value) == sum(uh)); } - } - SECTION("vector functions") - { - constexpr std::uint64_t VectorDimension = 2; + SECTION("matrix sum") + { + DiscreteFunctionP0<Dimension, TinyMatrix<2>> uh{mesh}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { + const double x = xj[cell_id][0]; + uh[cell_id] = TinyMatrix<2>{x + 1, 2 * x - 3, 2 * x, 3 * x - 1}; + }); + const CellValue<const TinyMatrix<2>> cell_value = uh.cellValues(); - DiscreteFunctionP0<Dimension, TinyVector<VectorDimension>> f{mesh}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - const double x = xj[cell_id][0]; - const TinyVector<VectorDimension> X{x, 2 - x}; - f[cell_id] = 2 * X + TinyVector<2>{1, 2}; - }); + REQUIRE(sum(cell_value) == sum(uh)); + } - DiscreteFunctionP0<Dimension, TinyVector<VectorDimension>> g{mesh}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - const double x = xj[cell_id][0]; - const TinyVector<VectorDimension> X{3 * x + 1, 2 + x}; - g[cell_id] = X; - }); + SECTION("integrate scalar") + { + const CellValue<const double> cell_volume = MeshDataManager::instance().getMeshData(*mesh).Vj(); + + CellValue<double> cell_value{mesh->connectivity()}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { + cell_value[cell_id] = cell_volume[cell_id] * positive_function[cell_id]; + }); - DiscreteFunctionP0<Dimension, const TinyVector<VectorDimension>> const_f = f; - DiscreteFunctionP0<Dimension, const TinyVector<VectorDimension>> const_g{g}; + REQUIRE(integrate(positive_function) == Catch::Approx(sum(cell_value))); + } - SECTION("sum") + SECTION("integrate vector") { - Array<TinyVector<VectorDimension>> sum_values{mesh->numberOfCells()}; + DiscreteFunctionP0<Dimension, TinyVector<2>> uh{mesh}; parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { sum_values[cell_id] = f[cell_id] + g[cell_id]; }); + mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { + const double x = xj[cell_id][0]; + uh[cell_id] = TinyVector<2>{x + 1, 2 * x - 3}; + }); + + const CellValue<const double> cell_volume = MeshDataManager::instance().getMeshData(*mesh).Vj(); + + CellValue<TinyVector<2>> cell_value{mesh->connectivity()}; + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(const CellId cell_id) { cell_value[cell_id] = cell_volume[cell_id] * uh[cell_id]; }); - REQUIRE(same_values(f + g, sum_values)); - REQUIRE(same_values(const_f + g, sum_values)); - REQUIRE(same_values(f + const_g, sum_values)); - REQUIRE(same_values(const_f + const_g, sum_values)); + REQUIRE(integrate(uh)[0] == Catch::Approx(sum(cell_value)[0])); + REQUIRE(integrate(uh)[1] == Catch::Approx(sum(cell_value)[1])); } - SECTION("difference") + SECTION("integrate matrix") { - Array<TinyVector<VectorDimension>> difference_values{mesh->numberOfCells()}; + DiscreteFunctionP0<Dimension, TinyMatrix<2>> uh{mesh}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { + const double x = xj[cell_id][0]; + uh[cell_id] = TinyMatrix<2>{x + 1, 2 * x - 3, 2 * x, 1 - x}; + }); + + const CellValue<const double> cell_volume = MeshDataManager::instance().getMeshData(*mesh).Vj(); + + CellValue<TinyMatrix<2>> cell_value{mesh->connectivity()}; parallel_for( mesh->numberOfCells(), - PUGS_LAMBDA(CellId cell_id) { difference_values[cell_id] = f[cell_id] - g[cell_id]; }); + PUGS_LAMBDA(const CellId cell_id) { cell_value[cell_id] = cell_volume[cell_id] * uh[cell_id]; }); - REQUIRE(same_values(f - g, difference_values)); - REQUIRE(same_values(const_f - g, difference_values)); - REQUIRE(same_values(f - const_g, difference_values)); - REQUIRE(same_values(const_f - const_g, difference_values)); + REQUIRE(integrate(uh)(0, 0) == Catch::Approx(sum(cell_value)(0, 0))); + REQUIRE(integrate(uh)(0, 1) == Catch::Approx(sum(cell_value)(0, 1))); + REQUIRE(integrate(uh)(1, 0) == Catch::Approx(sum(cell_value)(1, 0))); + REQUIRE(integrate(uh)(1, 1) == Catch::Approx(sum(cell_value)(1, 1))); } } + } + } + + SECTION("3D") + { + constexpr size_t Dimension = 3; + + std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - SECTION("matrix functions") + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) { - constexpr std::uint64_t MatrixDimension = 2; + auto mesh = named_mesh.mesh(); - DiscreteFunctionP0<Dimension, TinyMatrix<MatrixDimension>> f{mesh}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - const double x = xj[cell_id][0]; - const TinyMatrix<MatrixDimension> A{x, 2 - x, 2 * x, x * x - 3}; - f[cell_id] = 2 * A + TinyMatrix<2>{1, 2, 3, 4}; - }); + auto xj = MeshDataManager::instance().getMeshData(*mesh).xj(); + + DiscreteFunctionP0<Dimension, double> positive_function{mesh}; - DiscreteFunctionP0<Dimension, TinyMatrix<MatrixDimension>> g{mesh}; parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - const double x = xj[cell_id][0]; - const TinyMatrix<MatrixDimension> A{3 * x + 1, 2 + x, 1 - 2 * x, 2 * x * x}; - g[cell_id] = A; - }); + mesh->numberOfCells(), + PUGS_LAMBDA(const CellId cell_id) { positive_function[cell_id] = 1 + std::abs(xj[cell_id][0]); }); - DiscreteFunctionP0<Dimension, const TinyMatrix<MatrixDimension>> const_f = f; - DiscreteFunctionP0<Dimension, const TinyMatrix<MatrixDimension>> const_g{g}; + const double min_value = min(positive_function); + SECTION("min") + { + double local_min = std::numeric_limits<double>::max(); + for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++cell_id) { + local_min = std::min(local_min, positive_function[cell_id]); + } + REQUIRE(min_value == parallel::allReduceMin(local_min)); + } - SECTION("sum") + const double max_value = max(positive_function); + SECTION("max") { - Array<TinyMatrix<MatrixDimension>> sum_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { sum_values[cell_id] = f[cell_id] + g[cell_id]; }); + double local_max = -std::numeric_limits<double>::max(); + for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++cell_id) { + local_max = std::max(local_max, positive_function[cell_id]); + } + REQUIRE(max_value == parallel::allReduceMax(local_max)); + } - REQUIRE(same_values(f + g, sum_values)); - REQUIRE(same_values(const_f + g, sum_values)); - REQUIRE(same_values(f + const_g, sum_values)); - REQUIRE(same_values(const_f + const_g, sum_values)); + REQUIRE(min_value < max_value); + + DiscreteFunctionP0 unsigned_function = positive_function - 0.5 * (min_value + max_value); + + SECTION("sqrt") + { + CHECK_STD_MATH_FUNCTION(positive_function, sqrt); } - SECTION("difference") + SECTION("abs") { - Array<TinyMatrix<MatrixDimension>> difference_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), - PUGS_LAMBDA(CellId cell_id) { difference_values[cell_id] = f[cell_id] - g[cell_id]; }); + CHECK_STD_MATH_FUNCTION(positive_function, abs); + } - REQUIRE(same_values(f - g, difference_values)); - REQUIRE(same_values(const_f - g, difference_values)); - REQUIRE(same_values(f - const_g, difference_values)); - REQUIRE(same_values(const_f - const_g, difference_values)); + SECTION("cos") + { + CHECK_STD_MATH_FUNCTION(positive_function, cos); } - SECTION("product") + SECTION("sin") { - Array<TinyMatrix<MatrixDimension>> product_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), - PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = f[cell_id] * g[cell_id]; }); + CHECK_STD_MATH_FUNCTION(positive_function, sin); + } - REQUIRE(same_values(f * g, product_values)); - REQUIRE(same_values(const_f * g, product_values)); - REQUIRE(same_values(f * const_g, product_values)); - REQUIRE(same_values(const_f * const_g, product_values)); + SECTION("tan") + { + CHECK_STD_MATH_FUNCTION(positive_function, tan); } - } - } - SECTION("external operators") - { - SECTION("scalar functions") - { - DiscreteFunctionP0<Dimension, double> f{mesh}; + DiscreteFunctionP0<Dimension, double> unit_function{mesh}; + parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - const double x = xj[cell_id][0]; - const double y = xj[cell_id][1]; - const double z = xj[cell_id][2]; - f[cell_id] = std::abs(2 * x + y * z) + 1; + mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { + unit_function[cell_id] = + (2 * (positive_function[cell_id] - min_value) / (max_value - min_value) - 1) * 0.95; }); - const double a = 3; + SECTION("acos") + { + CHECK_STD_MATH_FUNCTION(unit_function, acos); + } - DiscreteFunctionP0<Dimension, const double> const_f = f; + SECTION("asin") + { + CHECK_STD_MATH_FUNCTION(unit_function, asin); + } - SECTION("sum") + SECTION("atan") { - { - Array<double> sum_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { sum_values[cell_id] = a + f[cell_id]; }); + CHECK_STD_MATH_FUNCTION(unit_function, atan); + } - REQUIRE(same_values(a + f, sum_values)); - REQUIRE(same_values(a + const_f, sum_values)); - } - { - Array<double> sum_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { sum_values[cell_id] = f[cell_id] + a; }); + SECTION("cosh") + { + CHECK_STD_MATH_FUNCTION(positive_function, cosh); + } - REQUIRE(same_values(f + a, sum_values)); - REQUIRE(same_values(const_f + a, sum_values)); - } + SECTION("sinh") + { + CHECK_STD_MATH_FUNCTION(positive_function, sinh); } - SECTION("difference") + SECTION("tanh") { - { - Array<double> difference_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { difference_values[cell_id] = a - f[cell_id]; }); - REQUIRE(same_values(a - f, difference_values)); - REQUIRE(same_values(a - const_f, difference_values)); - } + CHECK_STD_MATH_FUNCTION(positive_function, tanh); + } - { - Array<double> difference_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { difference_values[cell_id] = f[cell_id] - a; }); - REQUIRE(same_values(f - a, difference_values)); - REQUIRE(same_values(const_f - a, difference_values)); - } + SECTION("acosh") + { + CHECK_STD_MATH_FUNCTION(positive_function, acosh); } - SECTION("product") + SECTION("asinh") { - { - Array<double> product_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = a * f[cell_id]; }); + CHECK_STD_MATH_FUNCTION(positive_function, asinh); + } - REQUIRE(same_values(a * f, product_values)); - REQUIRE(same_values(a * const_f, product_values)); - } - { - Array<double> product_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = f[cell_id] * a; }); + SECTION("atanh") + { + CHECK_STD_MATH_FUNCTION(unit_function, atanh); + } - REQUIRE(same_values(f * a, product_values)); - REQUIRE(same_values(const_f * a, product_values)); - } + SECTION("exp") + { + CHECK_STD_MATH_FUNCTION(positive_function, exp); + } - { - Array<TinyVector<3>> product_values{mesh->numberOfCells()}; - const TinyVector<3> v{1, 2, 3}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = f[cell_id] * v; }); + SECTION("log") + { + CHECK_STD_MATH_FUNCTION(positive_function, log); + } - REQUIRE(same_values(f * v, product_values)); - REQUIRE(same_values(const_f * v, product_values)); - } + SECTION("max(uh,hv)") + { + CHECK_STD_BINARY_MATH_FUNCTION(cos(positive_function), sin(positive_function), max); + } - { - Array<TinyVector<3>> product_values{mesh->numberOfCells()}; - DiscreteFunctionP0<Dimension, TinyVector<3>> v{mesh}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - const double x = xj[cell_id][0]; - v[cell_id] = TinyVector<3>{x, 2 * x, 1 - x}; - }); + SECTION("max(0.2,vh)") + { + CHECK_STD_BINARY_MATH_FUNCTION_WITH_LHS_VALUE(0.2, sin(positive_function), max); + } - parallel_for( - mesh->numberOfCells(), - PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = f[cell_id] * v[cell_id]; }); + SECTION("max(uh,0.2)") + { + CHECK_STD_BINARY_MATH_FUNCTION_WITH_RHS_VALUE(cos(positive_function), 0.2, max); + } - REQUIRE(same_values(f * v, product_values)); - REQUIRE(same_values(const_f * v, product_values)); - } + SECTION("atan2(uh,hv)") + { + CHECK_STD_BINARY_MATH_FUNCTION(positive_function, 2 + positive_function, atan2); + } - { - Array<TinyMatrix<2>> product_values{mesh->numberOfCells()}; - const TinyMatrix<2> A{1, 2, 3, 4}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = f[cell_id] * A; }); + SECTION("atan2(0.5,uh)") + { + CHECK_STD_BINARY_MATH_FUNCTION_WITH_LHS_VALUE(0.5, 2 + positive_function, atan2); + } - REQUIRE(same_values(f * A, product_values)); - REQUIRE(same_values(const_f * A, product_values)); - } + SECTION("atan2(uh,0.2)") + { + CHECK_STD_BINARY_MATH_FUNCTION_WITH_RHS_VALUE(2 + cos(positive_function), 0.2, atan2); + } - { - Array<TinyMatrix<2>> product_values{mesh->numberOfCells()}; - DiscreteFunctionP0<Dimension, TinyMatrix<2>> M{mesh}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - const double x = xj[cell_id][0]; - M[cell_id] = TinyMatrix<2>{x, 2 * x, 1 - x, 2 - x * x}; - }); + SECTION("pow(uh,hv)") + { + CHECK_STD_BINARY_MATH_FUNCTION(positive_function, 0.5 * positive_function, pow); + } - parallel_for( - mesh->numberOfCells(), - PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = f[cell_id] * M[cell_id]; }); + SECTION("pow(uh,0.5)") + { + CHECK_STD_BINARY_MATH_FUNCTION_WITH_LHS_VALUE(0.5, positive_function, pow); + } - REQUIRE(same_values(f * M, product_values)); - REQUIRE(same_values(const_f * M, product_values)); - } + SECTION("pow(uh,0.2)") + { + CHECK_STD_BINARY_MATH_FUNCTION_WITH_RHS_VALUE(positive_function, 1.3, pow); } - SECTION("ratio") + SECTION("min(uh,hv)") { - { - Array<double> ratio_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { ratio_values[cell_id] = a / f[cell_id]; }); + CHECK_STD_BINARY_MATH_FUNCTION(sin(positive_function), cos(positive_function), min); + } - REQUIRE(same_values(a / f, ratio_values)); - REQUIRE(same_values(a / const_f, ratio_values)); - } - { - Array<double> ratio_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { ratio_values[cell_id] = f[cell_id] / a; }); + SECTION("min(uh,0.5)") + { + CHECK_STD_BINARY_MATH_FUNCTION_WITH_LHS_VALUE(0.5, cos(positive_function), min); + } - REQUIRE(same_values(f / a, ratio_values)); - REQUIRE(same_values(const_f / a, ratio_values)); - } + SECTION("min(uh,0.2)") + { + CHECK_STD_BINARY_MATH_FUNCTION_WITH_RHS_VALUE(sin(positive_function), 0.5, min); } - } - SECTION("vector functions") - { - constexpr std::uint64_t VectorDimension = 2; + SECTION("max(uh,hv)") + { + CHECK_STD_BINARY_MATH_FUNCTION(sin(positive_function), cos(positive_function), max); + } - DiscreteFunctionP0<Dimension, TinyVector<VectorDimension>> f{mesh}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - const double x = xj[cell_id][0]; - const double y = xj[cell_id][1]; - const double z = xj[cell_id][2]; - const TinyVector<VectorDimension> X{x + y - z, 2 - x * y}; - f[cell_id] = 2 * X + TinyVector<2>{1, 2}; - }); + SECTION("min(uh,0.5)") + { + CHECK_STD_BINARY_MATH_FUNCTION_WITH_LHS_VALUE(0.1, cos(positive_function), max); + } - DiscreteFunctionP0<Dimension, const TinyVector<VectorDimension>> const_f = f; + SECTION("min(uh,0.2)") + { + CHECK_STD_BINARY_MATH_FUNCTION_WITH_RHS_VALUE(sin(positive_function), 0.1, max); + } - SECTION("sum") + SECTION("dot(uh,hv)") { - const TinyVector<VectorDimension> v{1, 2}; - { - Array<TinyVector<VectorDimension>> sum_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { sum_values[cell_id] = v + f[cell_id]; }); + DiscreteFunctionP0<Dimension, TinyVector<2>> uh{mesh}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { + const double x = xj[cell_id][0]; + uh[cell_id] = TinyVector<2>{x + 1, 2 * x - 3}; + }); - REQUIRE(same_values(v + f, sum_values)); - REQUIRE(same_values(v + const_f, sum_values)); - } - { - Array<TinyVector<VectorDimension>> sum_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { sum_values[cell_id] = f[cell_id] + v; }); + DiscreteFunctionP0<Dimension, TinyVector<2>> vh{mesh}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { + const double x = xj[cell_id][0]; + vh[cell_id] = TinyVector<2>{2.3 * x, 1 - x}; + }); - REQUIRE(same_values(f + v, sum_values)); - REQUIRE(same_values(const_f + v, sum_values)); - } + CHECK_STD_BINARY_MATH_FUNCTION(uh, vh, dot); } - SECTION("difference") + SECTION("dot(uh,v)") { - const TinyVector<VectorDimension> v{1, 2}; - { - Array<TinyVector<VectorDimension>> difference_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { difference_values[cell_id] = v - f[cell_id]; }); + DiscreteFunctionP0<Dimension, TinyVector<2>> uh{mesh}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { + const double x = xj[cell_id][0]; + uh[cell_id] = TinyVector<2>{x + 1, 2 * x - 3}; + }); - REQUIRE(same_values(v - f, difference_values)); - REQUIRE(same_values(v - const_f, difference_values)); - } - { - Array<TinyVector<VectorDimension>> difference_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { difference_values[cell_id] = f[cell_id] - v; }); + const TinyVector<2> v{1, 2}; - REQUIRE(same_values(f - v, difference_values)); - REQUIRE(same_values(const_f - v, difference_values)); - } + CHECK_STD_BINARY_MATH_FUNCTION_WITH_RHS_VALUE(uh, v, dot); } - SECTION("product") + SECTION("dot(u,hv)") { - { - const double a = 2.3; - Array<TinyVector<VectorDimension>> product_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = a * f[cell_id]; }); - - REQUIRE(same_values(a * f, product_values)); - REQUIRE(same_values(a * const_f, product_values)); - } + const TinyVector<2> u{3, -2}; - { - DiscreteFunctionP0<Dimension, double> a{mesh}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - const double x = xj[cell_id][0]; - a[cell_id] = 2 * x * x - 1; - }); + DiscreteFunctionP0<Dimension, TinyVector<2>> vh{mesh}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { + const double x = xj[cell_id][0]; + vh[cell_id] = TinyVector<2>{2.3 * x, 1 - x}; + }); - Array<TinyVector<VectorDimension>> product_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), - PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = a[cell_id] * f[cell_id]; }); + CHECK_STD_BINARY_MATH_FUNCTION_WITH_LHS_VALUE(u, vh, dot); + } - REQUIRE(same_values(a * f, product_values)); - REQUIRE(same_values(a * const_f, product_values)); - } + SECTION("scalar sum") + { + const CellValue<const double> cell_value = positive_function.cellValues(); - { - const TinyMatrix<VectorDimension> A{1, 2, 3, 4}; - Array<TinyVector<VectorDimension>> product_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = A * f[cell_id]; }); + REQUIRE(sum(cell_value) == sum(positive_function)); + } - REQUIRE(same_values(A * f, product_values)); - REQUIRE(same_values(A * const_f, product_values)); - } + SECTION("vector sum") + { + DiscreteFunctionP0<Dimension, TinyVector<2>> uh{mesh}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { + const double x = xj[cell_id][0]; + uh[cell_id] = TinyVector<2>{x + 1, 2 * x - 3}; + }); + const CellValue<const TinyVector<2>> cell_value = uh.cellValues(); - { - Array<TinyVector<VectorDimension>> product_values{mesh->numberOfCells()}; - DiscreteFunctionP0<Dimension, TinyMatrix<VectorDimension>> M{mesh}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - const double x = xj[cell_id][0]; - M[cell_id] = TinyMatrix<2>{x, 2 * x, 1 - x, 2 - x * x}; - }); + REQUIRE(sum(cell_value) == sum(uh)); + } - parallel_for( - mesh->numberOfCells(), - PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = M[cell_id] * f[cell_id]; }); + SECTION("matrix sum") + { + DiscreteFunctionP0<Dimension, TinyMatrix<2>> uh{mesh}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { + const double x = xj[cell_id][0]; + uh[cell_id] = TinyMatrix<2>{x + 1, 2 * x - 3, 2 * x, 3 * x - 1}; + }); + const CellValue<const TinyMatrix<2>> cell_value = uh.cellValues(); - REQUIRE(same_values(M * f, product_values)); - REQUIRE(same_values(M * const_f, product_values)); - } + REQUIRE(sum(cell_value) == sum(uh)); } - } - SECTION("matrix functions") - { - constexpr std::uint64_t MatrixDimension = 2; + SECTION("integrate scalar") + { + const CellValue<const double> cell_volume = MeshDataManager::instance().getMeshData(*mesh).Vj(); - DiscreteFunctionP0<Dimension, TinyMatrix<MatrixDimension>> f{mesh}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - const double x = xj[cell_id][0]; - const double y = xj[cell_id][1]; - const double z = xj[cell_id][2]; - const TinyMatrix<MatrixDimension> X{x, 2 - y, x * y, y * z + 3}; - f[cell_id] = 2 * X + TinyMatrix<2>{1, 2, 3, 4}; - }); + CellValue<double> cell_value{mesh->connectivity()}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { + cell_value[cell_id] = cell_volume[cell_id] * positive_function[cell_id]; + }); - DiscreteFunctionP0<Dimension, const TinyMatrix<MatrixDimension>> const_f = f; + REQUIRE(integrate(positive_function) == Catch::Approx(sum(cell_value))); + } - SECTION("sum") + SECTION("integrate vector") { - const TinyMatrix<MatrixDimension> A{1, 2, 3, 4}; - { - Array<TinyMatrix<MatrixDimension>> sum_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { sum_values[cell_id] = A + f[cell_id]; }); + DiscreteFunctionP0<Dimension, TinyVector<2>> uh{mesh}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { + const double x = xj[cell_id][0]; + uh[cell_id] = TinyVector<2>{x + 1, 2 * x - 3}; + }); - REQUIRE(same_values(A + f, sum_values)); - REQUIRE(same_values(A + const_f, sum_values)); - } - { - Array<TinyMatrix<MatrixDimension>> sum_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { sum_values[cell_id] = f[cell_id] + A; }); + const CellValue<const double> cell_volume = MeshDataManager::instance().getMeshData(*mesh).Vj(); - REQUIRE(same_values(f + A, sum_values)); - REQUIRE(same_values(const_f + A, sum_values)); - } + CellValue<TinyVector<2>> cell_value{mesh->connectivity()}; + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(const CellId cell_id) { cell_value[cell_id] = cell_volume[cell_id] * uh[cell_id]; }); + + REQUIRE(integrate(uh)[0] == Catch::Approx(sum(cell_value)[0])); + REQUIRE(integrate(uh)[1] == Catch::Approx(sum(cell_value)[1])); } - SECTION("difference") + SECTION("integrate matrix") { - const TinyMatrix<MatrixDimension> A{1, 2, 3, 4}; - { - Array<TinyMatrix<MatrixDimension>> difference_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { difference_values[cell_id] = A - f[cell_id]; }); + DiscreteFunctionP0<Dimension, TinyMatrix<2>> uh{mesh}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { + const double x = xj[cell_id][0]; + uh[cell_id] = TinyMatrix<2>{x + 1, 2 * x - 3, 2 * x, 1 - x}; + }); - REQUIRE(same_values(A - f, difference_values)); - REQUIRE(same_values(A - const_f, difference_values)); - } - { - Array<TinyMatrix<MatrixDimension>> difference_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { difference_values[cell_id] = f[cell_id] - A; }); + const CellValue<const double> cell_volume = MeshDataManager::instance().getMeshData(*mesh).Vj(); - REQUIRE(same_values(f - A, difference_values)); - REQUIRE(same_values(const_f - A, difference_values)); - } + CellValue<TinyMatrix<2>> cell_value{mesh->connectivity()}; + parallel_for( + mesh->numberOfCells(), + PUGS_LAMBDA(const CellId cell_id) { cell_value[cell_id] = cell_volume[cell_id] * uh[cell_id]; }); + + REQUIRE(integrate(uh)(0, 0) == Catch::Approx(sum(cell_value)(0, 0))); + REQUIRE(integrate(uh)(0, 1) == Catch::Approx(sum(cell_value)(0, 1))); + REQUIRE(integrate(uh)(1, 0) == Catch::Approx(sum(cell_value)(1, 0))); + REQUIRE(integrate(uh)(1, 1) == Catch::Approx(sum(cell_value)(1, 1))); } + } + } + } + } + +#ifndef NDEBUG + SECTION("error") + { + SECTION("different meshes") + { + SECTION("1D") + { + constexpr size_t Dimension = 1; - SECTION("product") + std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); + + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) { - { - const double a = 2.3; - Array<TinyMatrix<MatrixDimension>> product_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = a * f[cell_id]; }); + auto mesh_1 = named_mesh.mesh(); - REQUIRE(same_values(a * f, product_values)); - REQUIRE(same_values(a * const_f, product_values)); - } + std::shared_ptr mesh_2 = + std::make_shared<Mesh<Connectivity<Dimension>>>(mesh_1->shared_connectivity(), mesh_1->xr()); - { - DiscreteFunctionP0<Dimension, double> a{mesh}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - const double x = xj[cell_id][0]; - a[cell_id] = 2 * x * x - 1; - }); + DiscreteFunctionP0<Dimension, double> f1{mesh_1}; + DiscreteFunctionP0<Dimension, double> f2{mesh_2}; - Array<TinyMatrix<MatrixDimension>> product_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), - PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = a[cell_id] * f[cell_id]; }); + REQUIRE_THROWS_AS(f1 = f2, AssertError); + REQUIRE_THROWS_AS(copy_to(f1, f2), AssertError); + REQUIRE_THROWS_AS(f1 + f2, AssertError); + REQUIRE_THROWS_AS(f1 - f2, AssertError); + REQUIRE_THROWS_AS(f1 * f2, AssertError); + REQUIRE_THROWS_AS(f1 / f2, AssertError); + } + } + } - REQUIRE(same_values(a * f, product_values)); - REQUIRE(same_values(a * const_f, product_values)); - } + SECTION("2D") + { + constexpr size_t Dimension = 2; - { - const TinyMatrix<MatrixDimension> A{1, 2, 3, 4}; - Array<TinyMatrix<MatrixDimension>> product_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = A * f[cell_id]; }); + std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - REQUIRE(same_values(A * f, product_values)); - REQUIRE(same_values(A * const_f, product_values)); - } + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_1 = named_mesh.mesh(); - { - const TinyMatrix<MatrixDimension> A{1, 2, 3, 4}; - Array<TinyMatrix<MatrixDimension>> product_values{mesh->numberOfCells()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { product_values[cell_id] = f[cell_id] * A; }); + std::shared_ptr mesh_2 = + std::make_shared<Mesh<Connectivity<Dimension>>>(mesh_1->shared_connectivity(), mesh_1->xr()); - REQUIRE(same_values(f * A, product_values)); - REQUIRE(same_values(const_f * A, product_values)); - } + DiscreteFunctionP0<Dimension, double> f1{mesh_1}; + DiscreteFunctionP0<Dimension, double> f2{mesh_2}; + + REQUIRE_THROWS_AS(f1 = f2, AssertError); + REQUIRE_THROWS_AS(copy_to(f1, f2), AssertError); + REQUIRE_THROWS_AS(f1 + f2, AssertError); + REQUIRE_THROWS_AS(f1 - f2, AssertError); + REQUIRE_THROWS_AS(f1 * f2, AssertError); + REQUIRE_THROWS_AS(f1 / f2, AssertError); } } } - } - } - - SECTION("math functions") - { -#define CHECK_STD_MATH_FUNCTION(data_expression, FCT) \ - { \ - DiscreteFunctionP0 data = data_expression; \ - DiscreteFunctionP0 result = FCT(data); \ - bool is_same = true; \ - parallel_for(data.cellValues().numberOfItems(), [&](const CellId cell_id) { \ - if (result[cell_id] != std::FCT(data[cell_id])) { \ - is_same = false; \ - } \ - }); \ - REQUIRE(is_same); \ - } - -#define CHECK_STD_BINARY_MATH_FUNCTION(lhs_expression, rhs_expression, FCT) \ - { \ - DiscreteFunctionP0 lhs = lhs_expression; \ - DiscreteFunctionP0 rhs = rhs_expression; \ - DiscreteFunctionP0 result = FCT(lhs, rhs); \ - using namespace std; \ - bool is_same = true; \ - parallel_for(lhs.cellValues().numberOfItems(), [&](const CellId cell_id) { \ - if (result[cell_id] != FCT(lhs[cell_id], rhs[cell_id])) { \ - is_same = false; \ - } \ - }); \ - REQUIRE(is_same); \ - } - -#define CHECK_STD_BINARY_MATH_FUNCTION_WITH_LHS_VALUE(lhs, rhs_expression, FCT) \ - { \ - DiscreteFunctionP0 rhs = rhs_expression; \ - DiscreteFunctionP0 result = FCT(lhs, rhs); \ - bool is_same = true; \ - using namespace std; \ - parallel_for(rhs.cellValues().numberOfItems(), [&](const CellId cell_id) { \ - if (result[cell_id] != FCT(lhs, rhs[cell_id])) { \ - is_same = false; \ - } \ - }); \ - REQUIRE(is_same); \ - } - -#define CHECK_STD_BINARY_MATH_FUNCTION_WITH_RHS_VALUE(lhs_expression, rhs, FCT) \ - { \ - DiscreteFunctionP0 lhs = lhs_expression; \ - DiscreteFunctionP0 result = FCT(lhs, rhs); \ - bool is_same = true; \ - using namespace std; \ - parallel_for(lhs.cellValues().numberOfItems(), [&](const CellId cell_id) { \ - if (result[cell_id] != FCT(lhs[cell_id], rhs)) { \ - is_same = false; \ - } \ - }); \ - REQUIRE(is_same); \ - } - - SECTION("1D") - { - std::shared_ptr mesh = MeshDataBaseForTests::get().cartesianMesh1D(); - - constexpr size_t Dimension = 1; - - auto xj = MeshDataManager::instance().getMeshData(*mesh).xj(); - - DiscreteFunctionP0<Dimension, double> positive_function{mesh}; - - parallel_for( - mesh->numberOfCells(), - PUGS_LAMBDA(const CellId cell_id) { positive_function[cell_id] = 1 + std::abs(xj[cell_id][0]); }); - - const double min_value = min(positive_function); - SECTION("min") - { - double local_min = std::numeric_limits<double>::max(); - for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++cell_id) { - local_min = std::min(local_min, positive_function[cell_id]); - } - REQUIRE(min_value == parallel::allReduceMin(local_min)); - } - - const double max_value = max(positive_function); - SECTION("max") - { - double local_max = -std::numeric_limits<double>::max(); - for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++cell_id) { - local_max = std::max(local_max, positive_function[cell_id]); - } - REQUIRE(max_value == parallel::allReduceMax(local_max)); - } - - REQUIRE(min_value < max_value); - - DiscreteFunctionP0 unsigned_function = positive_function - 0.5 * (min_value + max_value); - - SECTION("sqrt") - { - CHECK_STD_MATH_FUNCTION(positive_function, sqrt); - } - - SECTION("abs") - { - CHECK_STD_MATH_FUNCTION(positive_function, abs); - } - - SECTION("cos") - { - CHECK_STD_MATH_FUNCTION(positive_function, cos); - } - - SECTION("sin") - { - CHECK_STD_MATH_FUNCTION(positive_function, sin); - } - - SECTION("tan") - { - CHECK_STD_MATH_FUNCTION(positive_function, tan); - } - - DiscreteFunctionP0<Dimension, double> unit_function{mesh}; - - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { - unit_function[cell_id] = (2 * (positive_function[cell_id] - min_value) / (max_value - min_value) - 1) * 0.95; - }); - - SECTION("acos") - { - CHECK_STD_MATH_FUNCTION(unit_function, acos); - } - - SECTION("asin") - { - CHECK_STD_MATH_FUNCTION(unit_function, asin); - } - - SECTION("atan") - { - CHECK_STD_MATH_FUNCTION(unit_function, atan); - } - - SECTION("cosh") - { - CHECK_STD_MATH_FUNCTION(positive_function, cosh); - } - - SECTION("sinh") - { - CHECK_STD_MATH_FUNCTION(positive_function, sinh); - } - - SECTION("tanh") - { - CHECK_STD_MATH_FUNCTION(positive_function, tanh); - } - - SECTION("acosh") - { - CHECK_STD_MATH_FUNCTION(positive_function, acosh); - } - - SECTION("asinh") - { - CHECK_STD_MATH_FUNCTION(positive_function, asinh); - } - - SECTION("atanh") - { - CHECK_STD_MATH_FUNCTION(unit_function, atanh); - } - - SECTION("exp") - { - CHECK_STD_MATH_FUNCTION(positive_function, exp); - } - - SECTION("log") - { - CHECK_STD_MATH_FUNCTION(positive_function, log); - } - - SECTION("max(uh,hv)") - { - CHECK_STD_BINARY_MATH_FUNCTION(cos(positive_function), sin(positive_function), max); - } - - SECTION("max(0.2,vh)") - { - CHECK_STD_BINARY_MATH_FUNCTION_WITH_LHS_VALUE(0.2, sin(positive_function), max); - } - - SECTION("max(uh,0.2)") - { - CHECK_STD_BINARY_MATH_FUNCTION_WITH_RHS_VALUE(cos(positive_function), 0.2, max); - } - - SECTION("atan2(uh,hv)") - { - CHECK_STD_BINARY_MATH_FUNCTION(positive_function, 2 + positive_function, atan2); - } - - SECTION("atan2(0.5,uh)") - { - CHECK_STD_BINARY_MATH_FUNCTION_WITH_LHS_VALUE(0.5, 2 + positive_function, atan2); - } - - SECTION("atan2(uh,0.2)") - { - CHECK_STD_BINARY_MATH_FUNCTION_WITH_RHS_VALUE(2 + cos(positive_function), 0.2, atan2); - } - - SECTION("pow(uh,hv)") - { - CHECK_STD_BINARY_MATH_FUNCTION(positive_function, 0.5 * positive_function, pow); - } - - SECTION("pow(uh,0.5)") - { - CHECK_STD_BINARY_MATH_FUNCTION_WITH_LHS_VALUE(0.5, positive_function, pow); - } - - SECTION("pow(uh,0.2)") - { - CHECK_STD_BINARY_MATH_FUNCTION_WITH_RHS_VALUE(positive_function, 1.3, pow); - } - - SECTION("min(uh,hv)") - { - CHECK_STD_BINARY_MATH_FUNCTION(sin(positive_function), cos(positive_function), min); - } - - SECTION("min(uh,0.5)") - { - CHECK_STD_BINARY_MATH_FUNCTION_WITH_LHS_VALUE(0.5, cos(positive_function), min); - } - - SECTION("min(uh,0.2)") - { - CHECK_STD_BINARY_MATH_FUNCTION_WITH_RHS_VALUE(sin(positive_function), 0.5, min); - } - - SECTION("max(uh,hv)") - { - CHECK_STD_BINARY_MATH_FUNCTION(sin(positive_function), cos(positive_function), max); - } - - SECTION("min(uh,0.5)") - { - CHECK_STD_BINARY_MATH_FUNCTION_WITH_LHS_VALUE(0.1, cos(positive_function), max); - } - - SECTION("min(uh,0.2)") - { - CHECK_STD_BINARY_MATH_FUNCTION_WITH_RHS_VALUE(sin(positive_function), 0.1, max); - } - - SECTION("dot(uh,hv)") - { - DiscreteFunctionP0<Dimension, TinyVector<2>> uh{mesh}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { - const double x = xj[cell_id][0]; - uh[cell_id] = TinyVector<2>{x + 1, 2 * x - 3}; - }); - - DiscreteFunctionP0<Dimension, TinyVector<2>> vh{mesh}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { - const double x = xj[cell_id][0]; - vh[cell_id] = TinyVector<2>{2.3 * x, 1 - x}; - }); - - CHECK_STD_BINARY_MATH_FUNCTION(uh, vh, dot); - } - - SECTION("dot(uh,v)") - { - DiscreteFunctionP0<Dimension, TinyVector<2>> uh{mesh}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { - const double x = xj[cell_id][0]; - uh[cell_id] = TinyVector<2>{x + 1, 2 * x - 3}; - }); - - const TinyVector<2> v{1, 2}; - - CHECK_STD_BINARY_MATH_FUNCTION_WITH_RHS_VALUE(uh, v, dot); - } - - SECTION("dot(u,hv)") - { - const TinyVector<2> u{3, -2}; - - DiscreteFunctionP0<Dimension, TinyVector<2>> vh{mesh}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { - const double x = xj[cell_id][0]; - vh[cell_id] = TinyVector<2>{2.3 * x, 1 - x}; - }); - - CHECK_STD_BINARY_MATH_FUNCTION_WITH_LHS_VALUE(u, vh, dot); - } - - SECTION("scalar sum") - { - const CellValue<const double> cell_value = positive_function.cellValues(); - - REQUIRE(sum(cell_value) == sum(positive_function)); - } - - SECTION("vector sum") - { - DiscreteFunctionP0<Dimension, TinyVector<2>> uh{mesh}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { - const double x = xj[cell_id][0]; - uh[cell_id] = TinyVector<2>{x + 1, 2 * x - 3}; - }); - const CellValue<const TinyVector<2>> cell_value = uh.cellValues(); - - REQUIRE(sum(cell_value) == sum(uh)); - } - - SECTION("matrix sum") - { - DiscreteFunctionP0<Dimension, TinyMatrix<2>> uh{mesh}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { - const double x = xj[cell_id][0]; - uh[cell_id] = TinyMatrix<2>{x + 1, 2 * x - 3, 2 * x, 3 * x - 1}; - }); - const CellValue<const TinyMatrix<2>> cell_value = uh.cellValues(); - - REQUIRE(sum(cell_value) == sum(uh)); - } - - SECTION("integrate scalar") - { - const CellValue<const double> cell_volume = MeshDataManager::instance().getMeshData(*mesh).Vj(); - - CellValue<double> cell_value{mesh->connectivity()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { - cell_value[cell_id] = cell_volume[cell_id] * positive_function[cell_id]; - }); - - REQUIRE(integrate(positive_function) == Catch::Approx(sum(cell_value))); - } - - SECTION("integrate vector") - { - DiscreteFunctionP0<Dimension, TinyVector<2>> uh{mesh}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { - const double x = xj[cell_id][0]; - uh[cell_id] = TinyVector<2>{x + 1, 2 * x - 3}; - }); - - const CellValue<const double> cell_volume = MeshDataManager::instance().getMeshData(*mesh).Vj(); - - CellValue<TinyVector<2>> cell_value{mesh->connectivity()}; - parallel_for( - mesh->numberOfCells(), - PUGS_LAMBDA(const CellId cell_id) { cell_value[cell_id] = cell_volume[cell_id] * uh[cell_id]; }); - - REQUIRE(integrate(uh)[0] == Catch::Approx(sum(cell_value)[0])); - REQUIRE(integrate(uh)[1] == Catch::Approx(sum(cell_value)[1])); - } - - SECTION("integrate matrix") - { - DiscreteFunctionP0<Dimension, TinyMatrix<2>> uh{mesh}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { - const double x = xj[cell_id][0]; - uh[cell_id] = TinyMatrix<2>{x + 1, 2 * x - 3, 2 * x, 1 - x}; - }); - - const CellValue<const double> cell_volume = MeshDataManager::instance().getMeshData(*mesh).Vj(); - - CellValue<TinyMatrix<2>> cell_value{mesh->connectivity()}; - parallel_for( - mesh->numberOfCells(), - PUGS_LAMBDA(const CellId cell_id) { cell_value[cell_id] = cell_volume[cell_id] * uh[cell_id]; }); - - REQUIRE(integrate(uh)(0, 0) == Catch::Approx(sum(cell_value)(0, 0))); - REQUIRE(integrate(uh)(0, 1) == Catch::Approx(sum(cell_value)(0, 1))); - REQUIRE(integrate(uh)(1, 0) == Catch::Approx(sum(cell_value)(1, 0))); - REQUIRE(integrate(uh)(1, 1) == Catch::Approx(sum(cell_value)(1, 1))); - } - } - - SECTION("2D") - { - std::shared_ptr mesh = MeshDataBaseForTests::get().cartesianMesh2D(); - - constexpr size_t Dimension = 2; - - auto xj = MeshDataManager::instance().getMeshData(*mesh).xj(); - - DiscreteFunctionP0<Dimension, double> positive_function{mesh}; - - parallel_for( - mesh->numberOfCells(), - PUGS_LAMBDA(const CellId cell_id) { positive_function[cell_id] = 1 + std::abs(xj[cell_id][0]); }); - - const double min_value = min(positive_function); - SECTION("min") - { - double local_min = std::numeric_limits<double>::max(); - for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++cell_id) { - local_min = std::min(local_min, positive_function[cell_id]); - } - REQUIRE(min_value == parallel::allReduceMin(local_min)); - } - - const double max_value = max(positive_function); - SECTION("max") - { - double local_max = -std::numeric_limits<double>::max(); - for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++cell_id) { - local_max = std::max(local_max, positive_function[cell_id]); - } - REQUIRE(max_value == parallel::allReduceMax(local_max)); - } - - REQUIRE(min_value < max_value); - - DiscreteFunctionP0 unsigned_function = positive_function - 0.5 * (min_value + max_value); - - SECTION("sqrt") - { - CHECK_STD_MATH_FUNCTION(positive_function, sqrt); - } - - SECTION("abs") - { - CHECK_STD_MATH_FUNCTION(positive_function, abs); - } - - SECTION("cos") - { - CHECK_STD_MATH_FUNCTION(positive_function, cos); - } - - SECTION("sin") - { - CHECK_STD_MATH_FUNCTION(positive_function, sin); - } - - SECTION("tan") - { - CHECK_STD_MATH_FUNCTION(positive_function, tan); - } - - DiscreteFunctionP0<Dimension, double> unit_function{mesh}; - - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { - unit_function[cell_id] = (2 * (positive_function[cell_id] - min_value) / (max_value - min_value) - 1) * 0.95; - }); - - SECTION("acos") - { - CHECK_STD_MATH_FUNCTION(unit_function, acos); - } - - SECTION("asin") - { - CHECK_STD_MATH_FUNCTION(unit_function, asin); - } - - SECTION("atan") - { - CHECK_STD_MATH_FUNCTION(unit_function, atan); - } - - SECTION("cosh") - { - CHECK_STD_MATH_FUNCTION(positive_function, cosh); - } - - SECTION("sinh") - { - CHECK_STD_MATH_FUNCTION(positive_function, sinh); - } - - SECTION("tanh") - { - CHECK_STD_MATH_FUNCTION(positive_function, tanh); - } - - SECTION("acosh") - { - CHECK_STD_MATH_FUNCTION(positive_function, acosh); - } - - SECTION("asinh") - { - CHECK_STD_MATH_FUNCTION(positive_function, asinh); - } - - SECTION("atanh") - { - CHECK_STD_MATH_FUNCTION(unit_function, atanh); - } - - SECTION("exp") - { - CHECK_STD_MATH_FUNCTION(positive_function, exp); - } - SECTION("log") - { - CHECK_STD_MATH_FUNCTION(positive_function, log); - } - - SECTION("max(uh,hv)") - { - CHECK_STD_BINARY_MATH_FUNCTION(cos(positive_function), sin(positive_function), max); - } - - SECTION("max(0.2,vh)") - { - CHECK_STD_BINARY_MATH_FUNCTION_WITH_LHS_VALUE(0.2, sin(positive_function), max); - } - - SECTION("max(uh,0.2)") - { - CHECK_STD_BINARY_MATH_FUNCTION_WITH_RHS_VALUE(cos(positive_function), 0.2, max); - } - - SECTION("atan2(uh,hv)") - { - CHECK_STD_BINARY_MATH_FUNCTION(positive_function, 2 + positive_function, atan2); - } - - SECTION("atan2(0.5,uh)") - { - CHECK_STD_BINARY_MATH_FUNCTION_WITH_LHS_VALUE(0.5, 2 + positive_function, atan2); - } - - SECTION("atan2(uh,0.2)") - { - CHECK_STD_BINARY_MATH_FUNCTION_WITH_RHS_VALUE(2 + cos(positive_function), 0.2, atan2); - } - - SECTION("pow(uh,hv)") - { - CHECK_STD_BINARY_MATH_FUNCTION(positive_function, 0.5 * positive_function, pow); - } - - SECTION("pow(uh,0.5)") - { - CHECK_STD_BINARY_MATH_FUNCTION_WITH_LHS_VALUE(0.5, positive_function, pow); - } - - SECTION("pow(uh,0.2)") - { - CHECK_STD_BINARY_MATH_FUNCTION_WITH_RHS_VALUE(positive_function, 1.3, pow); - } - - SECTION("min(uh,hv)") - { - CHECK_STD_BINARY_MATH_FUNCTION(sin(positive_function), cos(positive_function), min); - } - - SECTION("min(uh,0.5)") - { - CHECK_STD_BINARY_MATH_FUNCTION_WITH_LHS_VALUE(0.5, cos(positive_function), min); - } - - SECTION("min(uh,0.2)") - { - CHECK_STD_BINARY_MATH_FUNCTION_WITH_RHS_VALUE(sin(positive_function), 0.5, min); - } - - SECTION("max(uh,hv)") - { - CHECK_STD_BINARY_MATH_FUNCTION(sin(positive_function), cos(positive_function), max); - } - - SECTION("min(uh,0.5)") - { - CHECK_STD_BINARY_MATH_FUNCTION_WITH_LHS_VALUE(0.1, cos(positive_function), max); - } - - SECTION("min(uh,0.2)") - { - CHECK_STD_BINARY_MATH_FUNCTION_WITH_RHS_VALUE(sin(positive_function), 0.1, max); - } - - SECTION("dot(uh,hv)") - { - DiscreteFunctionP0<Dimension, TinyVector<2>> uh{mesh}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { - const double x = xj[cell_id][0]; - uh[cell_id] = TinyVector<2>{x + 1, 2 * x - 3}; - }); - - DiscreteFunctionP0<Dimension, TinyVector<2>> vh{mesh}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { - const double x = xj[cell_id][0]; - vh[cell_id] = TinyVector<2>{2.3 * x, 1 - x}; - }); - - CHECK_STD_BINARY_MATH_FUNCTION(uh, vh, dot); - } - - SECTION("dot(uh,v)") - { - DiscreteFunctionP0<Dimension, TinyVector<2>> uh{mesh}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { - const double x = xj[cell_id][0]; - uh[cell_id] = TinyVector<2>{x + 1, 2 * x - 3}; - }); - - const TinyVector<2> v{1, 2}; - - CHECK_STD_BINARY_MATH_FUNCTION_WITH_RHS_VALUE(uh, v, dot); - } - - SECTION("dot(u,hv)") - { - const TinyVector<2> u{3, -2}; - - DiscreteFunctionP0<Dimension, TinyVector<2>> vh{mesh}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { - const double x = xj[cell_id][0]; - vh[cell_id] = TinyVector<2>{2.3 * x, 1 - x}; - }); - - CHECK_STD_BINARY_MATH_FUNCTION_WITH_LHS_VALUE(u, vh, dot); - } - - SECTION("scalar sum") - { - const CellValue<const double> cell_value = positive_function.cellValues(); - - REQUIRE(sum(cell_value) == sum(positive_function)); - } - - SECTION("vector sum") - { - DiscreteFunctionP0<Dimension, TinyVector<2>> uh{mesh}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { - const double x = xj[cell_id][0]; - uh[cell_id] = TinyVector<2>{x + 1, 2 * x - 3}; - }); - const CellValue<const TinyVector<2>> cell_value = uh.cellValues(); - - REQUIRE(sum(cell_value) == sum(uh)); - } - - SECTION("matrix sum") - { - DiscreteFunctionP0<Dimension, TinyMatrix<2>> uh{mesh}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { - const double x = xj[cell_id][0]; - uh[cell_id] = TinyMatrix<2>{x + 1, 2 * x - 3, 2 * x, 3 * x - 1}; - }); - const CellValue<const TinyMatrix<2>> cell_value = uh.cellValues(); - - REQUIRE(sum(cell_value) == sum(uh)); - } - - SECTION("integrate scalar") - { - const CellValue<const double> cell_volume = MeshDataManager::instance().getMeshData(*mesh).Vj(); - - CellValue<double> cell_value{mesh->connectivity()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { - cell_value[cell_id] = cell_volume[cell_id] * positive_function[cell_id]; - }); - - REQUIRE(integrate(positive_function) == Catch::Approx(sum(cell_value))); - } - - SECTION("integrate vector") - { - DiscreteFunctionP0<Dimension, TinyVector<2>> uh{mesh}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { - const double x = xj[cell_id][0]; - uh[cell_id] = TinyVector<2>{x + 1, 2 * x - 3}; - }); - - const CellValue<const double> cell_volume = MeshDataManager::instance().getMeshData(*mesh).Vj(); - - CellValue<TinyVector<2>> cell_value{mesh->connectivity()}; - parallel_for( - mesh->numberOfCells(), - PUGS_LAMBDA(const CellId cell_id) { cell_value[cell_id] = cell_volume[cell_id] * uh[cell_id]; }); - - REQUIRE(integrate(uh)[0] == Catch::Approx(sum(cell_value)[0])); - REQUIRE(integrate(uh)[1] == Catch::Approx(sum(cell_value)[1])); - } - - SECTION("integrate matrix") + SECTION("3D") { - DiscreteFunctionP0<Dimension, TinyMatrix<2>> uh{mesh}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { - const double x = xj[cell_id][0]; - uh[cell_id] = TinyMatrix<2>{x + 1, 2 * x - 3, 2 * x, 1 - x}; - }); - - const CellValue<const double> cell_volume = MeshDataManager::instance().getMeshData(*mesh).Vj(); - - CellValue<TinyMatrix<2>> cell_value{mesh->connectivity()}; - parallel_for( - mesh->numberOfCells(), - PUGS_LAMBDA(const CellId cell_id) { cell_value[cell_id] = cell_volume[cell_id] * uh[cell_id]; }); - - REQUIRE(integrate(uh)(0, 0) == Catch::Approx(sum(cell_value)(0, 0))); - REQUIRE(integrate(uh)(0, 1) == Catch::Approx(sum(cell_value)(0, 1))); - REQUIRE(integrate(uh)(1, 0) == Catch::Approx(sum(cell_value)(1, 0))); - REQUIRE(integrate(uh)(1, 1) == Catch::Approx(sum(cell_value)(1, 1))); - } - } - - SECTION("3D") - { - std::shared_ptr mesh = MeshDataBaseForTests::get().cartesianMesh3D(); - - constexpr size_t Dimension = 3; + constexpr size_t Dimension = 3; - auto xj = MeshDataManager::instance().getMeshData(*mesh).xj(); + std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - DiscreteFunctionP0<Dimension, double> positive_function{mesh}; + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_1 = named_mesh.mesh(); - parallel_for( - mesh->numberOfCells(), - PUGS_LAMBDA(const CellId cell_id) { positive_function[cell_id] = 1 + std::abs(xj[cell_id][0]); }); + std::shared_ptr mesh_2 = + std::make_shared<Mesh<Connectivity<Dimension>>>(mesh_1->shared_connectivity(), mesh_1->xr()); - const double min_value = min(positive_function); - SECTION("min") - { - double local_min = std::numeric_limits<double>::max(); - for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++cell_id) { - local_min = std::min(local_min, positive_function[cell_id]); - } - REQUIRE(min_value == parallel::allReduceMin(local_min)); - } + DiscreteFunctionP0<Dimension, double> f1{mesh_1}; + DiscreteFunctionP0<Dimension, double> f2{mesh_2}; - const double max_value = max(positive_function); - SECTION("max") - { - double local_max = -std::numeric_limits<double>::max(); - for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++cell_id) { - local_max = std::max(local_max, positive_function[cell_id]); + REQUIRE_THROWS_AS(f1 = f2, AssertError); + REQUIRE_THROWS_AS(copy_to(f1, f2), AssertError); + REQUIRE_THROWS_AS(f1 + f2, AssertError); + REQUIRE_THROWS_AS(f1 - f2, AssertError); + REQUIRE_THROWS_AS(f1 * f2, AssertError); + REQUIRE_THROWS_AS(f1 / f2, AssertError); + } } - REQUIRE(max_value == parallel::allReduceMax(local_max)); - } - - REQUIRE(min_value < max_value); - - DiscreteFunctionP0 unsigned_function = positive_function - 0.5 * (min_value + max_value); - - SECTION("sqrt") - { - CHECK_STD_MATH_FUNCTION(positive_function, sqrt); - } - - SECTION("abs") - { - CHECK_STD_MATH_FUNCTION(positive_function, abs); - } - - SECTION("cos") - { - CHECK_STD_MATH_FUNCTION(positive_function, cos); - } - - SECTION("sin") - { - CHECK_STD_MATH_FUNCTION(positive_function, sin); - } - - SECTION("tan") - { - CHECK_STD_MATH_FUNCTION(positive_function, tan); - } - - DiscreteFunctionP0<Dimension, double> unit_function{mesh}; - - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { - unit_function[cell_id] = (2 * (positive_function[cell_id] - min_value) / (max_value - min_value) - 1) * 0.95; - }); - - SECTION("acos") - { - CHECK_STD_MATH_FUNCTION(unit_function, acos); - } - - SECTION("asin") - { - CHECK_STD_MATH_FUNCTION(unit_function, asin); - } - - SECTION("atan") - { - CHECK_STD_MATH_FUNCTION(unit_function, atan); - } - - SECTION("cosh") - { - CHECK_STD_MATH_FUNCTION(positive_function, cosh); - } - - SECTION("sinh") - { - CHECK_STD_MATH_FUNCTION(positive_function, sinh); - } - - SECTION("tanh") - { - CHECK_STD_MATH_FUNCTION(positive_function, tanh); - } - - SECTION("acosh") - { - CHECK_STD_MATH_FUNCTION(positive_function, acosh); - } - - SECTION("asinh") - { - CHECK_STD_MATH_FUNCTION(positive_function, asinh); - } - - SECTION("atanh") - { - CHECK_STD_MATH_FUNCTION(unit_function, atanh); - } - - SECTION("exp") - { - CHECK_STD_MATH_FUNCTION(positive_function, exp); - } - - SECTION("log") - { - CHECK_STD_MATH_FUNCTION(positive_function, log); - } - - SECTION("max(uh,hv)") - { - CHECK_STD_BINARY_MATH_FUNCTION(cos(positive_function), sin(positive_function), max); - } - - SECTION("max(0.2,vh)") - { - CHECK_STD_BINARY_MATH_FUNCTION_WITH_LHS_VALUE(0.2, sin(positive_function), max); - } - - SECTION("max(uh,0.2)") - { - CHECK_STD_BINARY_MATH_FUNCTION_WITH_RHS_VALUE(cos(positive_function), 0.2, max); - } - - SECTION("atan2(uh,hv)") - { - CHECK_STD_BINARY_MATH_FUNCTION(positive_function, 2 + positive_function, atan2); - } - - SECTION("atan2(0.5,uh)") - { - CHECK_STD_BINARY_MATH_FUNCTION_WITH_LHS_VALUE(0.5, 2 + positive_function, atan2); - } - - SECTION("atan2(uh,0.2)") - { - CHECK_STD_BINARY_MATH_FUNCTION_WITH_RHS_VALUE(2 + cos(positive_function), 0.2, atan2); - } - - SECTION("pow(uh,hv)") - { - CHECK_STD_BINARY_MATH_FUNCTION(positive_function, 0.5 * positive_function, pow); - } - - SECTION("pow(uh,0.5)") - { - CHECK_STD_BINARY_MATH_FUNCTION_WITH_LHS_VALUE(0.5, positive_function, pow); - } - - SECTION("pow(uh,0.2)") - { - CHECK_STD_BINARY_MATH_FUNCTION_WITH_RHS_VALUE(positive_function, 1.3, pow); - } - - SECTION("min(uh,hv)") - { - CHECK_STD_BINARY_MATH_FUNCTION(sin(positive_function), cos(positive_function), min); - } - - SECTION("min(uh,0.5)") - { - CHECK_STD_BINARY_MATH_FUNCTION_WITH_LHS_VALUE(0.5, cos(positive_function), min); - } - - SECTION("min(uh,0.2)") - { - CHECK_STD_BINARY_MATH_FUNCTION_WITH_RHS_VALUE(sin(positive_function), 0.5, min); - } - - SECTION("max(uh,hv)") - { - CHECK_STD_BINARY_MATH_FUNCTION(sin(positive_function), cos(positive_function), max); - } - - SECTION("min(uh,0.5)") - { - CHECK_STD_BINARY_MATH_FUNCTION_WITH_LHS_VALUE(0.1, cos(positive_function), max); - } - - SECTION("min(uh,0.2)") - { - CHECK_STD_BINARY_MATH_FUNCTION_WITH_RHS_VALUE(sin(positive_function), 0.1, max); - } - - SECTION("dot(uh,hv)") - { - DiscreteFunctionP0<Dimension, TinyVector<2>> uh{mesh}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { - const double x = xj[cell_id][0]; - uh[cell_id] = TinyVector<2>{x + 1, 2 * x - 3}; - }); - - DiscreteFunctionP0<Dimension, TinyVector<2>> vh{mesh}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { - const double x = xj[cell_id][0]; - vh[cell_id] = TinyVector<2>{2.3 * x, 1 - x}; - }); - - CHECK_STD_BINARY_MATH_FUNCTION(uh, vh, dot); - } - - SECTION("dot(uh,v)") - { - DiscreteFunctionP0<Dimension, TinyVector<2>> uh{mesh}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { - const double x = xj[cell_id][0]; - uh[cell_id] = TinyVector<2>{x + 1, 2 * x - 3}; - }); - - const TinyVector<2> v{1, 2}; - - CHECK_STD_BINARY_MATH_FUNCTION_WITH_RHS_VALUE(uh, v, dot); - } - - SECTION("dot(u,hv)") - { - const TinyVector<2> u{3, -2}; - - DiscreteFunctionP0<Dimension, TinyVector<2>> vh{mesh}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { - const double x = xj[cell_id][0]; - vh[cell_id] = TinyVector<2>{2.3 * x, 1 - x}; - }); - - CHECK_STD_BINARY_MATH_FUNCTION_WITH_LHS_VALUE(u, vh, dot); - } - - SECTION("scalar sum") - { - const CellValue<const double> cell_value = positive_function.cellValues(); - - REQUIRE(sum(cell_value) == sum(positive_function)); - } - - SECTION("vector sum") - { - DiscreteFunctionP0<Dimension, TinyVector<2>> uh{mesh}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { - const double x = xj[cell_id][0]; - uh[cell_id] = TinyVector<2>{x + 1, 2 * x - 3}; - }); - const CellValue<const TinyVector<2>> cell_value = uh.cellValues(); - - REQUIRE(sum(cell_value) == sum(uh)); - } - - SECTION("matrix sum") - { - DiscreteFunctionP0<Dimension, TinyMatrix<2>> uh{mesh}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { - const double x = xj[cell_id][0]; - uh[cell_id] = TinyMatrix<2>{x + 1, 2 * x - 3, 2 * x, 3 * x - 1}; - }); - const CellValue<const TinyMatrix<2>> cell_value = uh.cellValues(); - - REQUIRE(sum(cell_value) == sum(uh)); - } - - SECTION("integrate scalar") - { - const CellValue<const double> cell_volume = MeshDataManager::instance().getMeshData(*mesh).Vj(); - - CellValue<double> cell_value{mesh->connectivity()}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { - cell_value[cell_id] = cell_volume[cell_id] * positive_function[cell_id]; - }); - - REQUIRE(integrate(positive_function) == Catch::Approx(sum(cell_value))); - } - - SECTION("integrate vector") - { - DiscreteFunctionP0<Dimension, TinyVector<2>> uh{mesh}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { - const double x = xj[cell_id][0]; - uh[cell_id] = TinyVector<2>{x + 1, 2 * x - 3}; - }); - - const CellValue<const double> cell_volume = MeshDataManager::instance().getMeshData(*mesh).Vj(); - - CellValue<TinyVector<2>> cell_value{mesh->connectivity()}; - parallel_for( - mesh->numberOfCells(), - PUGS_LAMBDA(const CellId cell_id) { cell_value[cell_id] = cell_volume[cell_id] * uh[cell_id]; }); - - REQUIRE(integrate(uh)[0] == Catch::Approx(sum(cell_value)[0])); - REQUIRE(integrate(uh)[1] == Catch::Approx(sum(cell_value)[1])); - } - - SECTION("integrate matrix") - { - DiscreteFunctionP0<Dimension, TinyMatrix<2>> uh{mesh}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { - const double x = xj[cell_id][0]; - uh[cell_id] = TinyMatrix<2>{x + 1, 2 * x - 3, 2 * x, 1 - x}; - }); - - const CellValue<const double> cell_volume = MeshDataManager::instance().getMeshData(*mesh).Vj(); - - CellValue<TinyMatrix<2>> cell_value{mesh->connectivity()}; - parallel_for( - mesh->numberOfCells(), - PUGS_LAMBDA(const CellId cell_id) { cell_value[cell_id] = cell_volume[cell_id] * uh[cell_id]; }); - - REQUIRE(integrate(uh)(0, 0) == Catch::Approx(sum(cell_value)(0, 0))); - REQUIRE(integrate(uh)(0, 1) == Catch::Approx(sum(cell_value)(0, 1))); - REQUIRE(integrate(uh)(1, 0) == Catch::Approx(sum(cell_value)(1, 0))); - REQUIRE(integrate(uh)(1, 1) == Catch::Approx(sum(cell_value)(1, 1))); - } - } - } - -#ifndef NDEBUG - SECTION("error") - { - SECTION("different meshes") - { - SECTION("1D") - { - constexpr size_t Dimension = 1; - - std::shared_ptr mesh_1 = MeshDataBaseForTests::get().cartesianMesh1D(); - std::shared_ptr mesh_2 = - std::make_shared<Mesh<Connectivity<Dimension>>>(mesh_1->shared_connectivity(), mesh_1->xr()); - - DiscreteFunctionP0<Dimension, double> f1{mesh_1}; - DiscreteFunctionP0<Dimension, double> f2{mesh_2}; - - REQUIRE_THROWS_AS(f1 = f2, AssertError); - REQUIRE_THROWS_AS(copy_to(f1, f2), AssertError); - REQUIRE_THROWS_AS(f1 + f2, AssertError); - REQUIRE_THROWS_AS(f1 - f2, AssertError); - REQUIRE_THROWS_AS(f1 * f2, AssertError); - REQUIRE_THROWS_AS(f1 / f2, AssertError); - } - - SECTION("2D") - { - constexpr size_t Dimension = 2; - - std::shared_ptr mesh_1 = MeshDataBaseForTests::get().cartesianMesh2D(); - std::shared_ptr mesh_2 = - std::make_shared<Mesh<Connectivity<Dimension>>>(mesh_1->shared_connectivity(), mesh_1->xr()); - - DiscreteFunctionP0<Dimension, double> f1{mesh_1}; - DiscreteFunctionP0<Dimension, double> f2{mesh_2}; - - REQUIRE_THROWS_AS(f1 = f2, AssertError); - REQUIRE_THROWS_AS(copy_to(f1, f2), AssertError); - REQUIRE_THROWS_AS(f1 + f2, AssertError); - REQUIRE_THROWS_AS(f1 - f2, AssertError); - REQUIRE_THROWS_AS(f1 * f2, AssertError); - REQUIRE_THROWS_AS(f1 / f2, AssertError); - } - - SECTION("3D") - { - constexpr size_t Dimension = 3; - - std::shared_ptr mesh_1 = MeshDataBaseForTests::get().cartesianMesh3D(); - std::shared_ptr mesh_2 = - std::make_shared<Mesh<Connectivity<Dimension>>>(mesh_1->shared_connectivity(), mesh_1->xr()); - - DiscreteFunctionP0<Dimension, double> f1{mesh_1}; - DiscreteFunctionP0<Dimension, double> f2{mesh_2}; - - REQUIRE_THROWS_AS(f1 = f2, AssertError); - REQUIRE_THROWS_AS(copy_to(f1, f2), AssertError); - REQUIRE_THROWS_AS(f1 + f2, AssertError); - REQUIRE_THROWS_AS(f1 - f2, AssertError); - REQUIRE_THROWS_AS(f1 * f2, AssertError); - REQUIRE_THROWS_AS(f1 / f2, AssertError); } } } diff --git a/tests/test_DiscreteFunctionP0Vector.cpp b/tests/test_DiscreteFunctionP0Vector.cpp index c004ba5732c41dce1af56d3074b9c038b3a1bf8c..6e351c404a7b5f57d7b39e5a3f70d43cf62a5635 100644 --- a/tests/test_DiscreteFunctionP0Vector.cpp +++ b/tests/test_DiscreteFunctionP0Vector.cpp @@ -27,123 +27,144 @@ TEST_CASE("DiscreteFunctionP0Vector", "[scheme]") { const size_t size = 3; - std::shared_ptr mesh = MeshDataBaseForTests::get().cartesianMesh1D(); constexpr size_t Dimension = 1; - DiscreteFunctionP0Vector<Dimension, double> f{mesh, size}; - REQUIRE(f.dataType() == ASTNodeDataType::double_t); - REQUIRE(f.descriptor().type() == DiscreteFunctionType::P0Vector); - REQUIRE(f.size() == size); + std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - REQUIRE(f.mesh().get() == mesh.get()); + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh = named_mesh.mesh(); + DiscreteFunctionP0Vector<Dimension, double> f{mesh, size}; + REQUIRE(f.dataType() == ASTNodeDataType::double_t); + REQUIRE(f.descriptor().type() == DiscreteFunctionType::P0Vector); + REQUIRE(f.size() == size); - DiscreteFunctionP0Vector g{f}; - REQUIRE(g.dataType() == ASTNodeDataType::double_t); - REQUIRE(g.descriptor().type() == DiscreteFunctionType::P0Vector); - REQUIRE(g.size() == size); + REQUIRE(f.mesh().get() == mesh.get()); - CellArray<double> h_arrays{mesh->connectivity(), size}; - h_arrays.fill(0); + DiscreteFunctionP0Vector g{f}; + REQUIRE(g.dataType() == ASTNodeDataType::double_t); + REQUIRE(g.descriptor().type() == DiscreteFunctionType::P0Vector); + REQUIRE(g.size() == size); - DiscreteFunctionP0Vector zero{mesh, [&] { - CellArray<double> cell_array{mesh->connectivity(), size}; - cell_array.fill(0); - return cell_array; - }()}; + CellArray<double> h_arrays{mesh->connectivity(), size}; + h_arrays.fill(0); - DiscreteFunctionP0Vector h{mesh, h_arrays}; - REQUIRE(same_values(h, zero)); - REQUIRE(same_values(h, h_arrays)); + DiscreteFunctionP0Vector zero{mesh, [&] { + CellArray<double> cell_array{mesh->connectivity(), size}; + cell_array.fill(0); + return cell_array; + }()}; - h_arrays.fill(1); + DiscreteFunctionP0Vector h{mesh, h_arrays}; + REQUIRE(same_values(h, zero)); + REQUIRE(same_values(h, h_arrays)); - REQUIRE(same_values(h, h_arrays)); - REQUIRE(not same_values(h, zero)); + h_arrays.fill(1); - DiscreteFunctionP0Vector moved_h{std::move(h)}; - REQUIRE(same_values(moved_h, h_arrays)); + REQUIRE(same_values(h, h_arrays)); + REQUIRE(not same_values(h, zero)); + + DiscreteFunctionP0Vector moved_h{std::move(h)}; + REQUIRE(same_values(moved_h, h_arrays)); + } + } } SECTION("2D") { const size_t size = 3; - std::shared_ptr mesh = MeshDataBaseForTests::get().cartesianMesh2D(); constexpr size_t Dimension = 2; - DiscreteFunctionP0Vector<Dimension, double> f{mesh, size}; - REQUIRE(f.dataType() == ASTNodeDataType::double_t); - REQUIRE(f.descriptor().type() == DiscreteFunctionType::P0Vector); - REQUIRE(f.size() == size); + std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - REQUIRE(f.mesh().get() == mesh.get()); + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh = named_mesh.mesh(); + DiscreteFunctionP0Vector<Dimension, double> f{mesh, size}; + REQUIRE(f.dataType() == ASTNodeDataType::double_t); + REQUIRE(f.descriptor().type() == DiscreteFunctionType::P0Vector); + REQUIRE(f.size() == size); - DiscreteFunctionP0Vector g{f}; - REQUIRE(g.dataType() == ASTNodeDataType::double_t); - REQUIRE(g.descriptor().type() == DiscreteFunctionType::P0Vector); - REQUIRE(g.size() == size); + REQUIRE(f.mesh().get() == mesh.get()); - CellArray<double> h_arrays{mesh->connectivity(), size}; - h_arrays.fill(0); + DiscreteFunctionP0Vector g{f}; + REQUIRE(g.dataType() == ASTNodeDataType::double_t); + REQUIRE(g.descriptor().type() == DiscreteFunctionType::P0Vector); + REQUIRE(g.size() == size); - DiscreteFunctionP0Vector zero{mesh, [&] { - CellArray<double> cell_array{mesh->connectivity(), size}; - cell_array.fill(0); - return cell_array; - }()}; + CellArray<double> h_arrays{mesh->connectivity(), size}; + h_arrays.fill(0); - DiscreteFunctionP0Vector h{mesh, h_arrays}; - REQUIRE(same_values(h, zero)); - REQUIRE(same_values(h, h_arrays)); + DiscreteFunctionP0Vector zero{mesh, [&] { + CellArray<double> cell_array{mesh->connectivity(), size}; + cell_array.fill(0); + return cell_array; + }()}; - h_arrays.fill(1); + DiscreteFunctionP0Vector h{mesh, h_arrays}; + REQUIRE(same_values(h, zero)); + REQUIRE(same_values(h, h_arrays)); - REQUIRE(same_values(h, h_arrays)); - REQUIRE(not same_values(h, zero)); + h_arrays.fill(1); - DiscreteFunctionP0Vector moved_h{std::move(h)}; - REQUIRE(same_values(moved_h, h_arrays)); + REQUIRE(same_values(h, h_arrays)); + REQUIRE(not same_values(h, zero)); + + DiscreteFunctionP0Vector moved_h{std::move(h)}; + REQUIRE(same_values(moved_h, h_arrays)); + } + } } SECTION("3D") { const size_t size = 2; - std::shared_ptr mesh = MeshDataBaseForTests::get().cartesianMesh3D(); constexpr size_t Dimension = 3; - DiscreteFunctionP0Vector<Dimension, double> f{mesh, size}; - REQUIRE(f.dataType() == ASTNodeDataType::double_t); - REQUIRE(f.descriptor().type() == DiscreteFunctionType::P0Vector); - REQUIRE(f.size() == size); + std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); + + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh = named_mesh.mesh(); + DiscreteFunctionP0Vector<Dimension, double> f{mesh, size}; + REQUIRE(f.dataType() == ASTNodeDataType::double_t); + REQUIRE(f.descriptor().type() == DiscreteFunctionType::P0Vector); + REQUIRE(f.size() == size); - REQUIRE(f.mesh().get() == mesh.get()); + REQUIRE(f.mesh().get() == mesh.get()); - DiscreteFunctionP0Vector g{f}; - REQUIRE(g.dataType() == ASTNodeDataType::double_t); - REQUIRE(g.descriptor().type() == DiscreteFunctionType::P0Vector); - REQUIRE(g.size() == size); + DiscreteFunctionP0Vector g{f}; + REQUIRE(g.dataType() == ASTNodeDataType::double_t); + REQUIRE(g.descriptor().type() == DiscreteFunctionType::P0Vector); + REQUIRE(g.size() == size); - CellArray<double> h_arrays{mesh->connectivity(), size}; - h_arrays.fill(0); + CellArray<double> h_arrays{mesh->connectivity(), size}; + h_arrays.fill(0); - DiscreteFunctionP0Vector zero{mesh, [&] { - CellArray<double> cell_array{mesh->connectivity(), size}; - cell_array.fill(0); - return cell_array; - }()}; + DiscreteFunctionP0Vector zero{mesh, [&] { + CellArray<double> cell_array{mesh->connectivity(), size}; + cell_array.fill(0); + return cell_array; + }()}; - DiscreteFunctionP0Vector h{mesh, h_arrays}; - REQUIRE(same_values(h, zero)); - REQUIRE(same_values(h, h_arrays)); + DiscreteFunctionP0Vector h{mesh, h_arrays}; + REQUIRE(same_values(h, zero)); + REQUIRE(same_values(h, h_arrays)); - h_arrays.fill(1); + h_arrays.fill(1); - REQUIRE(same_values(h, h_arrays)); - REQUIRE(not same_values(h, zero)); + REQUIRE(same_values(h, h_arrays)); + REQUIRE(not same_values(h, zero)); - DiscreteFunctionP0Vector moved_h{std::move(h)}; - REQUIRE(same_values(moved_h, h_arrays)); + DiscreteFunctionP0Vector moved_h{std::move(h)}; + REQUIRE(same_values(moved_h, h_arrays)); + } + } } } @@ -166,39 +187,60 @@ TEST_CASE("DiscreteFunctionP0Vector", "[scheme]") { const size_t size = 3; - std::shared_ptr mesh = MeshDataBaseForTests::get().cartesianMesh1D(); - constexpr size_t Dimension = 1; + std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - DiscreteFunctionP0Vector<Dimension, double> f{mesh, size}; - f.fill(3); + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh = named_mesh.mesh(); + constexpr size_t Dimension = 1; + + DiscreteFunctionP0Vector<Dimension, double> f{mesh, size}; + f.fill(3); - REQUIRE(all_values_equal(f, 3)); + REQUIRE(all_values_equal(f, 3)); + } + } } SECTION("2D") { const size_t size = 3; - std::shared_ptr mesh = MeshDataBaseForTests::get().cartesianMesh2D(); constexpr size_t Dimension = 2; - DiscreteFunctionP0Vector<Dimension, double> f{mesh, size}; - f.fill(2.3); + std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); + + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh = named_mesh.mesh(); + DiscreteFunctionP0Vector<Dimension, double> f{mesh, size}; + f.fill(2.3); - REQUIRE(all_values_equal(f, 2.3)); + REQUIRE(all_values_equal(f, 2.3)); + } + } } SECTION("3D") { const size_t size = 2; - std::shared_ptr mesh = MeshDataBaseForTests::get().cartesianMesh3D(); constexpr size_t Dimension = 3; - DiscreteFunctionP0Vector<Dimension, double> f{mesh, size}; - f.fill(3.2); + std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); + + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh = named_mesh.mesh(); + DiscreteFunctionP0Vector<Dimension, double> f{mesh, size}; + f.fill(3.2); - REQUIRE(all_values_equal(f, 3.2)); + REQUIRE(all_values_equal(f, 3.2)); + } + } } } @@ -220,623 +262,688 @@ TEST_CASE("DiscreteFunctionP0Vector", "[scheme]") SECTION("1D") { - std::shared_ptr mesh = MeshDataBaseForTests::get().cartesianMesh1D(); - constexpr size_t Dimension = 1; - const size_t size = 3; - const size_t value = parallel::rank() + 1; - const size_t zero = 0; + std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); + + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh = named_mesh.mesh(); + + const size_t size = 3; + const size_t value = parallel::rank() + 1; + const size_t zero = 0; - DiscreteFunctionP0Vector<Dimension, size_t> f{mesh, size}; - f.fill(value); + DiscreteFunctionP0Vector<Dimension, size_t> f{mesh, size}; + f.fill(value); - REQUIRE(all_values_equal(f, value)); + REQUIRE(all_values_equal(f, value)); - DiscreteFunctionP0Vector g = copy(f); - f.fill(zero); + DiscreteFunctionP0Vector g = copy(f); + f.fill(zero); - REQUIRE(all_values_equal(f, zero)); - REQUIRE(all_values_equal(g, value)); + REQUIRE(all_values_equal(f, zero)); + REQUIRE(all_values_equal(g, value)); - copy_to(g, f); - g.fill(zero); + copy_to(g, f); + g.fill(zero); - DiscreteFunctionP0Vector<Dimension, const size_t> h = copy(f); + DiscreteFunctionP0Vector<Dimension, const size_t> h = copy(f); - DiscreteFunctionP0Vector<Dimension, size_t> shallow_g{mesh, size}; - shallow_g = g; + DiscreteFunctionP0Vector<Dimension, size_t> shallow_g{mesh, size}; + shallow_g = g; - REQUIRE(all_values_equal(f, value)); - REQUIRE(all_values_equal(g, zero)); - REQUIRE(all_values_equal(shallow_g, zero)); - REQUIRE(all_values_equal(h, value)); + REQUIRE(all_values_equal(f, value)); + REQUIRE(all_values_equal(g, zero)); + REQUIRE(all_values_equal(shallow_g, zero)); + REQUIRE(all_values_equal(h, value)); - copy_to(h, g); + copy_to(h, g); - REQUIRE(all_values_equal(g, value)); - REQUIRE(all_values_equal(shallow_g, value)); + REQUIRE(all_values_equal(g, value)); + REQUIRE(all_values_equal(shallow_g, value)); + } + } } SECTION("2D") { - std::shared_ptr mesh = MeshDataBaseForTests::get().cartesianMesh2D(); - constexpr size_t Dimension = 2; + std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); + + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh = named_mesh.mesh(); - const size_t size = 3; - const size_t value = parallel::rank() + 1; - const size_t zero = 0; + const size_t size = 3; + const size_t value = parallel::rank() + 1; + const size_t zero = 0; - DiscreteFunctionP0Vector<Dimension, size_t> f{mesh, size}; - f.fill(value); + DiscreteFunctionP0Vector<Dimension, size_t> f{mesh, size}; + f.fill(value); - REQUIRE(all_values_equal(f, value)); + REQUIRE(all_values_equal(f, value)); - DiscreteFunctionP0Vector g = copy(f); - f.fill(zero); + DiscreteFunctionP0Vector g = copy(f); + f.fill(zero); - REQUIRE(all_values_equal(f, zero)); - REQUIRE(all_values_equal(g, value)); + REQUIRE(all_values_equal(f, zero)); + REQUIRE(all_values_equal(g, value)); - copy_to(g, f); - g.fill(zero); + copy_to(g, f); + g.fill(zero); - DiscreteFunctionP0Vector<Dimension, const size_t> h = copy(f); + DiscreteFunctionP0Vector<Dimension, const size_t> h = copy(f); - DiscreteFunctionP0Vector<Dimension, size_t> shallow_g{mesh, size}; - shallow_g = g; + DiscreteFunctionP0Vector<Dimension, size_t> shallow_g{mesh, size}; + shallow_g = g; - REQUIRE(all_values_equal(f, value)); - REQUIRE(all_values_equal(g, zero)); - REQUIRE(all_values_equal(shallow_g, zero)); - REQUIRE(all_values_equal(h, value)); + REQUIRE(all_values_equal(f, value)); + REQUIRE(all_values_equal(g, zero)); + REQUIRE(all_values_equal(shallow_g, zero)); + REQUIRE(all_values_equal(h, value)); - copy_to(h, g); + copy_to(h, g); - REQUIRE(all_values_equal(g, value)); - REQUIRE(all_values_equal(shallow_g, value)); + REQUIRE(all_values_equal(g, value)); + REQUIRE(all_values_equal(shallow_g, value)); + } + } } SECTION("3D") { - std::shared_ptr mesh = MeshDataBaseForTests::get().cartesianMesh3D(); - constexpr size_t Dimension = 3; - const size_t size = 3; - const size_t value = parallel::rank() + 1; - const size_t zero = 0; - - DiscreteFunctionP0Vector<Dimension, size_t> f{mesh, size}; - f.fill(value); - - REQUIRE(all_values_equal(f, value)); - - DiscreteFunctionP0Vector g = copy(f); - f.fill(zero); - - REQUIRE(all_values_equal(f, zero)); - REQUIRE(all_values_equal(g, value)); - - copy_to(g, f); - g.fill(zero); - - DiscreteFunctionP0Vector<Dimension, const size_t> h = copy(f); + std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - DiscreteFunctionP0Vector<Dimension, size_t> shallow_g{mesh, size}; - shallow_g = g; - - REQUIRE(all_values_equal(f, value)); - REQUIRE(all_values_equal(g, zero)); - REQUIRE(all_values_equal(h, value)); - - copy_to(h, g); - - REQUIRE(all_values_equal(g, value)); - REQUIRE(all_values_equal(shallow_g, value)); - } - } - - SECTION("unary operators") - { - SECTION("1D") - { - const size_t size = 3; - std::shared_ptr mesh = MeshDataBaseForTests::get().cartesianMesh1D(); - - constexpr size_t Dimension = 1; - - auto xj = MeshDataManager::instance().getMeshData(*mesh).xj(); + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh = named_mesh.mesh(); - SECTION("unary minus") - { - DiscreteFunctionP0Vector<Dimension, double> f{mesh, size}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - const double x = xj[cell_id][0]; - for (size_t i = 0; i < size; ++i) { - f[cell_id][i] = 2 * x + i; - } - }); + const size_t size = 3; + const size_t value = parallel::rank() + 1; + const size_t zero = 0; - DiscreteFunctionP0Vector<Dimension, const double> const_f = f; + DiscreteFunctionP0Vector<Dimension, size_t> f{mesh, size}; + f.fill(value); - Table<double> minus_values{mesh->numberOfCells(), size}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - for (size_t i = 0; i < size; ++i) { - minus_values[cell_id][i] = -f[cell_id][i]; - } - }); + REQUIRE(all_values_equal(f, value)); - REQUIRE(same_values(-f, minus_values)); - REQUIRE(same_values(-const_f, minus_values)); - } - } + DiscreteFunctionP0Vector g = copy(f); + f.fill(zero); - SECTION("2D") - { - const size_t size = 3; - std::shared_ptr mesh = MeshDataBaseForTests::get().cartesianMesh2D(); + REQUIRE(all_values_equal(f, zero)); + REQUIRE(all_values_equal(g, value)); - constexpr size_t Dimension = 2; + copy_to(g, f); + g.fill(zero); - auto xj = MeshDataManager::instance().getMeshData(*mesh).xj(); - - SECTION("unary minus") - { - DiscreteFunctionP0Vector<Dimension, double> f{mesh, size}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - const double x = xj[cell_id][0]; - const double y = xj[cell_id][1]; - for (size_t i = 0; i < size; ++i) { - f[cell_id][i] = 2 * x + i * y; - } - }); + DiscreteFunctionP0Vector<Dimension, const size_t> h = copy(f); - DiscreteFunctionP0Vector<Dimension, const double> const_f = f; + DiscreteFunctionP0Vector<Dimension, size_t> shallow_g{mesh, size}; + shallow_g = g; - Table<double> minus_values{mesh->numberOfCells(), size}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - for (size_t i = 0; i < size; ++i) { - minus_values[cell_id][i] = -f[cell_id][i]; - } - }); + REQUIRE(all_values_equal(f, value)); + REQUIRE(all_values_equal(g, zero)); + REQUIRE(all_values_equal(h, value)); - REQUIRE(same_values(-f, minus_values)); - REQUIRE(same_values(-const_f, minus_values)); - } - } + copy_to(h, g); - SECTION("3D") - { - const size_t size = 2; - std::shared_ptr mesh = MeshDataBaseForTests::get().cartesianMesh3D(); - - constexpr size_t Dimension = 3; - - auto xj = MeshDataManager::instance().getMeshData(*mesh).xj(); - - SECTION("unary minus") - { - DiscreteFunctionP0Vector<Dimension, double> f{mesh, size}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - const double x = xj[cell_id][0]; - const double y = xj[cell_id][1]; - const double z = xj[cell_id][2]; - for (size_t i = 0; i < size; ++i) { - f[cell_id][i] = 2 * x + i * y - z; - } - }); - - DiscreteFunctionP0Vector<Dimension, const double> const_f = f; - - Table<double> minus_values{mesh->numberOfCells(), size}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - for (size_t i = 0; i < size; ++i) { - minus_values[cell_id][i] = -f[cell_id][i]; - } - }); - - REQUIRE(same_values(-f, minus_values)); - REQUIRE(same_values(-const_f, minus_values)); + REQUIRE(all_values_equal(g, value)); + REQUIRE(all_values_equal(shallow_g, value)); + } } } } - SECTION("binary operators") + SECTION("unary operators") { SECTION("1D") { const size_t size = 3; - std::shared_ptr mesh = MeshDataBaseForTests::get().cartesianMesh1D(); - constexpr size_t Dimension = 1; - auto xj = MeshDataManager::instance().getMeshData(*mesh).xj(); + std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - SECTION("inner operators") - { - SECTION("scalar functions") + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) { - DiscreteFunctionP0Vector<Dimension, double> f{mesh, size}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - const double x = xj[cell_id][0]; - f[cell_id][0] = 2 * x + 1; - f[cell_id][1] = x * x - 1; - f[cell_id][2] = 2 + x; - }); - - DiscreteFunctionP0Vector<Dimension, double> g{mesh, size}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - const double x = xj[cell_id][0]; - g[cell_id][0] = (x + 1) * (x - 2) + 1; - g[cell_id][1] = 3 * (x + 2) - 1; - g[cell_id][2] = (x + 3) * 5; - }); - - DiscreteFunctionP0Vector<Dimension, const double> const_f = f; - DiscreteFunctionP0Vector<Dimension, const double> const_g{g}; - - SECTION("sum") + auto mesh = named_mesh.mesh(); + + auto xj = MeshDataManager::instance().getMeshData(*mesh).xj(); + + SECTION("unary minus") { - Table<double> sum_values{mesh->numberOfCells(), size}; + DiscreteFunctionP0Vector<Dimension, double> f{mesh, size}; parallel_for( mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + const double x = xj[cell_id][0]; for (size_t i = 0; i < size; ++i) { - sum_values[cell_id][i] = f[cell_id][i] + g[cell_id][i]; + f[cell_id][i] = 2 * x + i; } }); - REQUIRE(same_values(f + g, sum_values)); - REQUIRE(same_values(const_f + g, sum_values)); - REQUIRE(same_values(f + const_g, sum_values)); - REQUIRE(same_values(const_f + const_g, sum_values)); - } + DiscreteFunctionP0Vector<Dimension, const double> const_f = f; - SECTION("difference") - { - Table<double> difference_values{mesh->numberOfCells(), size}; + Table<double> minus_values{mesh->numberOfCells(), size}; parallel_for( mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { for (size_t i = 0; i < size; ++i) { - difference_values[cell_id][i] = f[cell_id][i] - g[cell_id][i]; + minus_values[cell_id][i] = -f[cell_id][i]; } }); - REQUIRE(same_values(f - g, difference_values)); - REQUIRE(same_values(const_f - g, difference_values)); - REQUIRE(same_values(f - const_g, difference_values)); - REQUIRE(same_values(const_f - const_g, difference_values)); + REQUIRE(same_values(-f, minus_values)); + REQUIRE(same_values(-const_f, minus_values)); } } } + } - SECTION("external operators") - { - DiscreteFunctionP0Vector<Dimension, double> f{mesh, size}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - const double x = xj[cell_id][0]; - for (size_t i = 0; i < size; ++i) { - f[cell_id][i] = std::abs(2 * x) + i; - } - }); + SECTION("2D") + { + const size_t size = 3; + + constexpr size_t Dimension = 2; - DiscreteFunctionP0Vector<Dimension, const double> const_f = f; + std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - SECTION("product") + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) { - SECTION("scalar lhs") - { - const double a = 3.2; - Table<double> product_values{mesh->numberOfCells(), size}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - for (size_t i = 0; i < size; ++i) { - product_values[cell_id][i] = a * f[cell_id][i]; - } - }); + auto mesh = named_mesh.mesh(); - REQUIRE(same_values(a * f, product_values)); - REQUIRE(same_values(a * const_f, product_values)); - } + auto xj = MeshDataManager::instance().getMeshData(*mesh).xj(); - SECTION("DiscreteFunctionP0 lhs") + SECTION("unary minus") { - DiscreteFunctionP0<Dimension, double> a{mesh}; + DiscreteFunctionP0Vector<Dimension, double> f{mesh, size}; parallel_for( mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { const double x = xj[cell_id][0]; - a[cell_id] = 2 * x + 1; + const double y = xj[cell_id][1]; + for (size_t i = 0; i < size; ++i) { + f[cell_id][i] = 2 * x + i * y; + } }); - Table<double> product_values{mesh->numberOfCells(), size}; + DiscreteFunctionP0Vector<Dimension, const double> const_f = f; + + Table<double> minus_values{mesh->numberOfCells(), size}; parallel_for( mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { for (size_t i = 0; i < size; ++i) { - product_values[cell_id][i] = a[cell_id] * f[cell_id][i]; + minus_values[cell_id][i] = -f[cell_id][i]; } }); - REQUIRE(same_values(a * f, product_values)); - REQUIRE(same_values(a * const_f, product_values)); - - DiscreteFunctionP0<Dimension, const double> const_a = a; - REQUIRE(same_values(const_a * f, product_values)); - REQUIRE(same_values(const_a * const_f, product_values)); + REQUIRE(same_values(-f, minus_values)); + REQUIRE(same_values(-const_f, minus_values)); } } } } - SECTION("2D") + SECTION("3D") { - const size_t size = 3; - - std::shared_ptr mesh = MeshDataBaseForTests::get().cartesianMesh2D(); + const size_t size = 2; - constexpr size_t Dimension = 2; + constexpr size_t Dimension = 3; - auto xj = MeshDataManager::instance().getMeshData(*mesh).xj(); + std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - SECTION("inner operators") - { - SECTION("scalar functions") + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) { - DiscreteFunctionP0Vector<Dimension, double> f{mesh, size}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - const double x = xj[cell_id][0]; - const double y = xj[cell_id][1]; - f[cell_id][0] = 2 * x + 1; - f[cell_id][1] = x * x - y; - f[cell_id][2] = 2 + x * y; - }); - - DiscreteFunctionP0Vector<Dimension, double> g{mesh, size}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - const double x = xj[cell_id][0]; - const double y = xj[cell_id][1]; - g[cell_id][0] = (x + 1) * (y - 2) + 1; - g[cell_id][1] = 3 * (x + 2) - y; - g[cell_id][2] = (x + 3) + 5 * y; - }); - - DiscreteFunctionP0Vector<Dimension, const double> const_f = f; - DiscreteFunctionP0Vector<Dimension, const double> const_g{g}; - - SECTION("sum") + auto mesh = named_mesh.mesh(); + + auto xj = MeshDataManager::instance().getMeshData(*mesh).xj(); + + SECTION("unary minus") { - Table<double> sum_values{mesh->numberOfCells(), size}; + DiscreteFunctionP0Vector<Dimension, double> f{mesh, size}; parallel_for( mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + const double x = xj[cell_id][0]; + const double y = xj[cell_id][1]; + const double z = xj[cell_id][2]; for (size_t i = 0; i < size; ++i) { - sum_values[cell_id][i] = f[cell_id][i] + g[cell_id][i]; + f[cell_id][i] = 2 * x + i * y - z; } }); - REQUIRE(same_values(f + g, sum_values)); - REQUIRE(same_values(const_f + g, sum_values)); - REQUIRE(same_values(f + const_g, sum_values)); - REQUIRE(same_values(const_f + const_g, sum_values)); - } + DiscreteFunctionP0Vector<Dimension, const double> const_f = f; - SECTION("difference") - { - Table<double> difference_values{mesh->numberOfCells(), size}; + Table<double> minus_values{mesh->numberOfCells(), size}; parallel_for( mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { for (size_t i = 0; i < size; ++i) { - difference_values[cell_id][i] = f[cell_id][i] - g[cell_id][i]; + minus_values[cell_id][i] = -f[cell_id][i]; } }); - REQUIRE(same_values(f - g, difference_values)); - REQUIRE(same_values(const_f - g, difference_values)); - REQUIRE(same_values(f - const_g, difference_values)); - REQUIRE(same_values(const_f - const_g, difference_values)); + REQUIRE(same_values(-f, minus_values)); + REQUIRE(same_values(-const_f, minus_values)); } } } + } + } - SECTION("external operators") - { - DiscreteFunctionP0Vector<Dimension, double> f{mesh, size}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - const double x = xj[cell_id][0]; - const double y = xj[cell_id][1]; - for (size_t i = 0; i < size; ++i) { - f[cell_id][i] = std::abs(2 * x) + i * y; - } - }); + SECTION("binary operators") + { + SECTION("1D") + { + const size_t size = 3; + + constexpr size_t Dimension = 1; - DiscreteFunctionP0Vector<Dimension, const double> const_f = f; + std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - SECTION("product") + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) { - SECTION("scalar lhs") - { - const double a = 3.2; - Table<double> product_values{mesh->numberOfCells(), size}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - for (size_t i = 0; i < size; ++i) { - product_values[cell_id][i] = a * f[cell_id][i]; - } - }); + auto mesh = named_mesh.mesh(); - REQUIRE(same_values(a * f, product_values)); - REQUIRE(same_values(a * const_f, product_values)); + auto xj = MeshDataManager::instance().getMeshData(*mesh).xj(); + + SECTION("inner operators") + { + SECTION("scalar functions") + { + DiscreteFunctionP0Vector<Dimension, double> f{mesh, size}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + const double x = xj[cell_id][0]; + f[cell_id][0] = 2 * x + 1; + f[cell_id][1] = x * x - 1; + f[cell_id][2] = 2 + x; + }); + + DiscreteFunctionP0Vector<Dimension, double> g{mesh, size}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + const double x = xj[cell_id][0]; + g[cell_id][0] = (x + 1) * (x - 2) + 1; + g[cell_id][1] = 3 * (x + 2) - 1; + g[cell_id][2] = (x + 3) * 5; + }); + + DiscreteFunctionP0Vector<Dimension, const double> const_f = f; + DiscreteFunctionP0Vector<Dimension, const double> const_g{g}; + + SECTION("sum") + { + Table<double> sum_values{mesh->numberOfCells(), size}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + for (size_t i = 0; i < size; ++i) { + sum_values[cell_id][i] = f[cell_id][i] + g[cell_id][i]; + } + }); + + REQUIRE(same_values(f + g, sum_values)); + REQUIRE(same_values(const_f + g, sum_values)); + REQUIRE(same_values(f + const_g, sum_values)); + REQUIRE(same_values(const_f + const_g, sum_values)); + } + + SECTION("difference") + { + Table<double> difference_values{mesh->numberOfCells(), size}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + for (size_t i = 0; i < size; ++i) { + difference_values[cell_id][i] = f[cell_id][i] - g[cell_id][i]; + } + }); + + REQUIRE(same_values(f - g, difference_values)); + REQUIRE(same_values(const_f - g, difference_values)); + REQUIRE(same_values(f - const_g, difference_values)); + REQUIRE(same_values(const_f - const_g, difference_values)); + } + } } - SECTION("DiscreteFunctionP0 lhs") + SECTION("external operators") { - DiscreteFunctionP0<Dimension, double> a{mesh}; + DiscreteFunctionP0Vector<Dimension, double> f{mesh, size}; parallel_for( mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { const double x = xj[cell_id][0]; - const double y = xj[cell_id][1]; - a[cell_id] = 2 * x + 1 - y; - }); - - Table<double> product_values{mesh->numberOfCells(), size}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { for (size_t i = 0; i < size; ++i) { - product_values[cell_id][i] = a[cell_id] * f[cell_id][i]; + f[cell_id][i] = std::abs(2 * x) + i; } }); - REQUIRE(same_values(a * f, product_values)); - REQUIRE(same_values(a * const_f, product_values)); - - DiscreteFunctionP0<Dimension, const double> const_a = a; - REQUIRE(same_values(const_a * f, product_values)); - REQUIRE(same_values(const_a * const_f, product_values)); + DiscreteFunctionP0Vector<Dimension, const double> const_f = f; + + SECTION("product") + { + SECTION("scalar lhs") + { + const double a = 3.2; + Table<double> product_values{mesh->numberOfCells(), size}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + for (size_t i = 0; i < size; ++i) { + product_values[cell_id][i] = a * f[cell_id][i]; + } + }); + + REQUIRE(same_values(a * f, product_values)); + REQUIRE(same_values(a * const_f, product_values)); + } + + SECTION("DiscreteFunctionP0 lhs") + { + DiscreteFunctionP0<Dimension, double> a{mesh}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + const double x = xj[cell_id][0]; + a[cell_id] = 2 * x + 1; + }); + + Table<double> product_values{mesh->numberOfCells(), size}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + for (size_t i = 0; i < size; ++i) { + product_values[cell_id][i] = a[cell_id] * f[cell_id][i]; + } + }); + + REQUIRE(same_values(a * f, product_values)); + REQUIRE(same_values(a * const_f, product_values)); + + DiscreteFunctionP0<Dimension, const double> const_a = a; + REQUIRE(same_values(const_a * f, product_values)); + REQUIRE(same_values(const_a * const_f, product_values)); + } + } } } } } - SECTION("3D") + SECTION("2D") { - const size_t size = 2; - - std::shared_ptr mesh = MeshDataBaseForTests::get().cartesianMesh3D(); + const size_t size = 3; - constexpr size_t Dimension = 3; + constexpr size_t Dimension = 2; - auto xj = MeshDataManager::instance().getMeshData(*mesh).xj(); + std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - SECTION("inner operators") - { - SECTION("scalar functions") + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) { - DiscreteFunctionP0Vector<Dimension, double> f{mesh, size}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - const double x = xj[cell_id][0]; - const double y = xj[cell_id][1]; - const double z = xj[cell_id][2]; - f[cell_id][0] = 2 * x * z + 1; - f[cell_id][1] = x * z - y; - }); - - DiscreteFunctionP0Vector<Dimension, double> g{mesh, size}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - const double x = xj[cell_id][0]; - const double y = xj[cell_id][1]; - const double z = xj[cell_id][2]; - g[cell_id][0] = (x + 1) * (y - 2) + 1 - z; - g[cell_id][1] = 3 * (x + 2) - y * z; - }); - - DiscreteFunctionP0Vector<Dimension, const double> const_f = f; - DiscreteFunctionP0Vector<Dimension, const double> const_g{g}; - - SECTION("sum") - { - Table<double> sum_values{mesh->numberOfCells(), size}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - for (size_t i = 0; i < size; ++i) { - sum_values[cell_id][i] = f[cell_id][i] + g[cell_id][i]; - } - }); + auto mesh = named_mesh.mesh(); + + auto xj = MeshDataManager::instance().getMeshData(*mesh).xj(); - REQUIRE(same_values(f + g, sum_values)); - REQUIRE(same_values(const_f + g, sum_values)); - REQUIRE(same_values(f + const_g, sum_values)); - REQUIRE(same_values(const_f + const_g, sum_values)); + SECTION("inner operators") + { + SECTION("scalar functions") + { + DiscreteFunctionP0Vector<Dimension, double> f{mesh, size}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + const double x = xj[cell_id][0]; + const double y = xj[cell_id][1]; + f[cell_id][0] = 2 * x + 1; + f[cell_id][1] = x * x - y; + f[cell_id][2] = 2 + x * y; + }); + + DiscreteFunctionP0Vector<Dimension, double> g{mesh, size}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + const double x = xj[cell_id][0]; + const double y = xj[cell_id][1]; + g[cell_id][0] = (x + 1) * (y - 2) + 1; + g[cell_id][1] = 3 * (x + 2) - y; + g[cell_id][2] = (x + 3) + 5 * y; + }); + + DiscreteFunctionP0Vector<Dimension, const double> const_f = f; + DiscreteFunctionP0Vector<Dimension, const double> const_g{g}; + + SECTION("sum") + { + Table<double> sum_values{mesh->numberOfCells(), size}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + for (size_t i = 0; i < size; ++i) { + sum_values[cell_id][i] = f[cell_id][i] + g[cell_id][i]; + } + }); + + REQUIRE(same_values(f + g, sum_values)); + REQUIRE(same_values(const_f + g, sum_values)); + REQUIRE(same_values(f + const_g, sum_values)); + REQUIRE(same_values(const_f + const_g, sum_values)); + } + + SECTION("difference") + { + Table<double> difference_values{mesh->numberOfCells(), size}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + for (size_t i = 0; i < size; ++i) { + difference_values[cell_id][i] = f[cell_id][i] - g[cell_id][i]; + } + }); + + REQUIRE(same_values(f - g, difference_values)); + REQUIRE(same_values(const_f - g, difference_values)); + REQUIRE(same_values(f - const_g, difference_values)); + REQUIRE(same_values(const_f - const_g, difference_values)); + } + } } - SECTION("difference") + SECTION("external operators") { - Table<double> difference_values{mesh->numberOfCells(), size}; + DiscreteFunctionP0Vector<Dimension, double> f{mesh, size}; parallel_for( mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + const double x = xj[cell_id][0]; + const double y = xj[cell_id][1]; for (size_t i = 0; i < size; ++i) { - difference_values[cell_id][i] = f[cell_id][i] - g[cell_id][i]; + f[cell_id][i] = std::abs(2 * x) + i * y; } }); - REQUIRE(same_values(f - g, difference_values)); - REQUIRE(same_values(const_f - g, difference_values)); - REQUIRE(same_values(f - const_g, difference_values)); - REQUIRE(same_values(const_f - const_g, difference_values)); + DiscreteFunctionP0Vector<Dimension, const double> const_f = f; + + SECTION("product") + { + SECTION("scalar lhs") + { + const double a = 3.2; + Table<double> product_values{mesh->numberOfCells(), size}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + for (size_t i = 0; i < size; ++i) { + product_values[cell_id][i] = a * f[cell_id][i]; + } + }); + + REQUIRE(same_values(a * f, product_values)); + REQUIRE(same_values(a * const_f, product_values)); + } + + SECTION("DiscreteFunctionP0 lhs") + { + DiscreteFunctionP0<Dimension, double> a{mesh}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + const double x = xj[cell_id][0]; + const double y = xj[cell_id][1]; + a[cell_id] = 2 * x + 1 - y; + }); + + Table<double> product_values{mesh->numberOfCells(), size}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + for (size_t i = 0; i < size; ++i) { + product_values[cell_id][i] = a[cell_id] * f[cell_id][i]; + } + }); + + REQUIRE(same_values(a * f, product_values)); + REQUIRE(same_values(a * const_f, product_values)); + + DiscreteFunctionP0<Dimension, const double> const_a = a; + REQUIRE(same_values(const_a * f, product_values)); + REQUIRE(same_values(const_a * const_f, product_values)); + } + } } } } + } - SECTION("external operators") - { - DiscreteFunctionP0Vector<Dimension, double> f{mesh, size}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - const double x = xj[cell_id][0]; - const double y = xj[cell_id][1]; - const double z = xj[cell_id][2]; - for (size_t i = 0; i < size; ++i) { - f[cell_id][i] = std::abs(2 * x) + i * y + z; - } - }); + SECTION("3D") + { + const size_t size = 2; + + constexpr size_t Dimension = 3; - DiscreteFunctionP0Vector<Dimension, const double> const_f = f; + std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - SECTION("product") + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) { - SECTION("scalar lhs") - { - const double a = 3.2; - Table<double> product_values{mesh->numberOfCells(), size}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - for (size_t i = 0; i < size; ++i) { - product_values[cell_id][i] = a * f[cell_id][i]; - } - }); + auto mesh = named_mesh.mesh(); - REQUIRE(same_values(a * f, product_values)); - REQUIRE(same_values(a * const_f, product_values)); + auto xj = MeshDataManager::instance().getMeshData(*mesh).xj(); + + SECTION("inner operators") + { + SECTION("scalar functions") + { + DiscreteFunctionP0Vector<Dimension, double> f{mesh, size}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + const double x = xj[cell_id][0]; + const double y = xj[cell_id][1]; + const double z = xj[cell_id][2]; + f[cell_id][0] = 2 * x * z + 1; + f[cell_id][1] = x * z - y; + }); + + DiscreteFunctionP0Vector<Dimension, double> g{mesh, size}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + const double x = xj[cell_id][0]; + const double y = xj[cell_id][1]; + const double z = xj[cell_id][2]; + g[cell_id][0] = (x + 1) * (y - 2) + 1 - z; + g[cell_id][1] = 3 * (x + 2) - y * z; + }); + + DiscreteFunctionP0Vector<Dimension, const double> const_f = f; + DiscreteFunctionP0Vector<Dimension, const double> const_g{g}; + + SECTION("sum") + { + Table<double> sum_values{mesh->numberOfCells(), size}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + for (size_t i = 0; i < size; ++i) { + sum_values[cell_id][i] = f[cell_id][i] + g[cell_id][i]; + } + }); + + REQUIRE(same_values(f + g, sum_values)); + REQUIRE(same_values(const_f + g, sum_values)); + REQUIRE(same_values(f + const_g, sum_values)); + REQUIRE(same_values(const_f + const_g, sum_values)); + } + + SECTION("difference") + { + Table<double> difference_values{mesh->numberOfCells(), size}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + for (size_t i = 0; i < size; ++i) { + difference_values[cell_id][i] = f[cell_id][i] - g[cell_id][i]; + } + }); + + REQUIRE(same_values(f - g, difference_values)); + REQUIRE(same_values(const_f - g, difference_values)); + REQUIRE(same_values(f - const_g, difference_values)); + REQUIRE(same_values(const_f - const_g, difference_values)); + } + } } - SECTION("DiscreteFunctionP0 lhs") + SECTION("external operators") { - DiscreteFunctionP0<Dimension, double> a{mesh}; + DiscreteFunctionP0Vector<Dimension, double> f{mesh, size}; parallel_for( mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { const double x = xj[cell_id][0]; const double y = xj[cell_id][1]; const double z = xj[cell_id][2]; - a[cell_id] = 2 * x + 1 - y * z; - }); - - Table<double> product_values{mesh->numberOfCells(), size}; - parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { for (size_t i = 0; i < size; ++i) { - product_values[cell_id][i] = a[cell_id] * f[cell_id][i]; + f[cell_id][i] = std::abs(2 * x) + i * y + z; } }); - REQUIRE(same_values(a * f, product_values)); - REQUIRE(same_values(a * const_f, product_values)); - - DiscreteFunctionP0<Dimension, const double> const_a = a; - REQUIRE(same_values(const_a * f, product_values)); - REQUIRE(same_values(const_a * const_f, product_values)); + DiscreteFunctionP0Vector<Dimension, const double> const_f = f; + + SECTION("product") + { + SECTION("scalar lhs") + { + const double a = 3.2; + Table<double> product_values{mesh->numberOfCells(), size}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + for (size_t i = 0; i < size; ++i) { + product_values[cell_id][i] = a * f[cell_id][i]; + } + }); + + REQUIRE(same_values(a * f, product_values)); + REQUIRE(same_values(a * const_f, product_values)); + } + + SECTION("DiscreteFunctionP0 lhs") + { + DiscreteFunctionP0<Dimension, double> a{mesh}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + const double x = xj[cell_id][0]; + const double y = xj[cell_id][1]; + const double z = xj[cell_id][2]; + a[cell_id] = 2 * x + 1 - y * z; + }); + + Table<double> product_values{mesh->numberOfCells(), size}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + for (size_t i = 0; i < size; ++i) { + product_values[cell_id][i] = a[cell_id] * f[cell_id][i]; + } + }); + + REQUIRE(same_values(a * f, product_values)); + REQUIRE(same_values(a * const_f, product_values)); + + DiscreteFunctionP0<Dimension, const double> const_a = a; + REQUIRE(same_values(const_a * f, product_values)); + REQUIRE(same_values(const_a * const_f, product_values)); + } + } } } } diff --git a/tests/test_DiscreteFunctionUtils.cpp b/tests/test_DiscreteFunctionUtils.cpp index 6587fcba0e201539552e78f4550523b9dbe277eb..3783a19c99cb67066565c507abfeca6ce0f5d61f 100644 --- a/tests/test_DiscreteFunctionUtils.cpp +++ b/tests/test_DiscreteFunctionUtils.cpp @@ -16,144 +16,152 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]") { constexpr size_t Dimension = 1; - std::shared_ptr mesh = MeshDataBaseForTests::get().cartesianMesh1D(); - std::shared_ptr mesh_copy = - std::make_shared<std::decay_t<decltype(*mesh)>>(mesh->shared_connectivity(), mesh->xr()); + std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - SECTION("common mesh") - { - std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh); - std::shared_ptr vh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh); - std::shared_ptr wh = std::make_shared<DiscreteFunctionP0<Dimension, TinyVector<2>>>(mesh); + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh = named_mesh.mesh(); - std::shared_ptr qh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh_copy); + std::shared_ptr mesh_copy = + std::make_shared<std::decay_t<decltype(*mesh)>>(mesh->shared_connectivity(), mesh->xr()); - REQUIRE(getCommonMesh({uh, vh, wh}).get() == mesh.get()); - REQUIRE(getCommonMesh({uh, vh, wh, qh}).use_count() == 0); - } + SECTION("common mesh") + { + std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh); + std::shared_ptr vh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh); + std::shared_ptr wh = std::make_shared<DiscreteFunctionP0<Dimension, TinyVector<2>>>(mesh); - SECTION("check discretization type") - { - std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh); - std::shared_ptr vh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh); - - std::shared_ptr qh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh_copy); - - std::shared_ptr Uh = std::make_shared<DiscreteFunctionP0Vector<Dimension, double>>(mesh, 3); - std::shared_ptr Vh = std::make_shared<DiscreteFunctionP0Vector<Dimension, double>>(mesh, 3); - - REQUIRE(checkDiscretizationType({uh}, DiscreteFunctionType::P0)); - REQUIRE(checkDiscretizationType({uh, vh, qh}, DiscreteFunctionType::P0)); - REQUIRE(not checkDiscretizationType({uh}, DiscreteFunctionType::P0Vector)); - REQUIRE(not checkDiscretizationType({uh, vh, qh}, DiscreteFunctionType::P0Vector)); - REQUIRE(checkDiscretizationType({Uh}, DiscreteFunctionType::P0Vector)); - REQUIRE(checkDiscretizationType({Uh, Vh}, DiscreteFunctionType::P0Vector)); - REQUIRE(not checkDiscretizationType({Uh, Vh}, DiscreteFunctionType::P0)); - REQUIRE(not checkDiscretizationType({Uh}, DiscreteFunctionType::P0)); - } + std::shared_ptr qh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh_copy); - SECTION("scalar function shallow copy") - { - std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh); - std::shared_ptr vh = shallowCopy(mesh, uh); + REQUIRE(getCommonMesh({uh, vh, wh}).get() == mesh.get()); + REQUIRE(getCommonMesh({uh, vh, wh, qh}).use_count() == 0); + } - REQUIRE(uh == vh); + SECTION("check discretization type") + { + std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh); + std::shared_ptr vh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh); - std::shared_ptr wh = shallowCopy(mesh_copy, uh); + std::shared_ptr qh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh_copy); - REQUIRE(uh != wh); - REQUIRE(&(uh->cellValues()[CellId{0}]) == - &(dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*wh).cellValues()[CellId{0}])); - } + std::shared_ptr Uh = std::make_shared<DiscreteFunctionP0Vector<Dimension, double>>(mesh, 3); + std::shared_ptr Vh = std::make_shared<DiscreteFunctionP0Vector<Dimension, double>>(mesh, 3); - SECTION("R^1 function shallow copy") - { - using DataType = TinyVector<1>; - std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh); - std::shared_ptr vh = shallowCopy(mesh, uh); + REQUIRE(checkDiscretizationType({uh}, DiscreteFunctionType::P0)); + REQUIRE(checkDiscretizationType({uh, vh, qh}, DiscreteFunctionType::P0)); + REQUIRE(not checkDiscretizationType({uh}, DiscreteFunctionType::P0Vector)); + REQUIRE(not checkDiscretizationType({uh, vh, qh}, DiscreteFunctionType::P0Vector)); + REQUIRE(checkDiscretizationType({Uh}, DiscreteFunctionType::P0Vector)); + REQUIRE(checkDiscretizationType({Uh, Vh}, DiscreteFunctionType::P0Vector)); + REQUIRE(not checkDiscretizationType({Uh, Vh}, DiscreteFunctionType::P0)); + REQUIRE(not checkDiscretizationType({Uh}, DiscreteFunctionType::P0)); + } - REQUIRE(uh == vh); + SECTION("scalar function shallow copy") + { + std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh); + std::shared_ptr vh = shallowCopy(mesh, uh); - std::shared_ptr wh = shallowCopy(mesh_copy, uh); + REQUIRE(uh == vh); - REQUIRE(uh != wh); - REQUIRE(&(uh->cellValues()[CellId{0}]) == - &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}])); - } + std::shared_ptr wh = shallowCopy(mesh_copy, uh); - SECTION("R^2 function shallow copy") - { - using DataType = TinyVector<2>; - std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh); - std::shared_ptr vh = shallowCopy(mesh, uh); + REQUIRE(uh != wh); + REQUIRE(&(uh->cellValues()[CellId{0}]) == + &(dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*wh).cellValues()[CellId{0}])); + } - REQUIRE(uh == vh); + SECTION("R^1 function shallow copy") + { + using DataType = TinyVector<1>; + std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh); + std::shared_ptr vh = shallowCopy(mesh, uh); - std::shared_ptr wh = shallowCopy(mesh_copy, uh); + REQUIRE(uh == vh); - REQUIRE(uh != wh); - REQUIRE(&(uh->cellValues()[CellId{0}]) == - &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}])); - } + std::shared_ptr wh = shallowCopy(mesh_copy, uh); - SECTION("R^3 function shallow copy") - { - using DataType = TinyVector<3>; - std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh); - std::shared_ptr vh = shallowCopy(mesh, uh); + REQUIRE(uh != wh); + REQUIRE(&(uh->cellValues()[CellId{0}]) == + &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}])); + } - REQUIRE(uh == vh); + SECTION("R^2 function shallow copy") + { + using DataType = TinyVector<2>; + std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh); + std::shared_ptr vh = shallowCopy(mesh, uh); - std::shared_ptr wh = shallowCopy(mesh_copy, uh); + REQUIRE(uh == vh); - REQUIRE(uh != wh); - REQUIRE(&(uh->cellValues()[CellId{0}]) == - &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}])); - } + std::shared_ptr wh = shallowCopy(mesh_copy, uh); - SECTION("R^1x1 function shallow copy") - { - using DataType = TinyMatrix<1>; - std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh); - std::shared_ptr vh = shallowCopy(mesh, uh); + REQUIRE(uh != wh); + REQUIRE(&(uh->cellValues()[CellId{0}]) == + &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}])); + } - REQUIRE(uh == vh); + SECTION("R^3 function shallow copy") + { + using DataType = TinyVector<3>; + std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh); + std::shared_ptr vh = shallowCopy(mesh, uh); - std::shared_ptr wh = shallowCopy(mesh_copy, uh); + REQUIRE(uh == vh); - REQUIRE(uh != wh); - REQUIRE(&(uh->cellValues()[CellId{0}]) == - &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}])); - } + std::shared_ptr wh = shallowCopy(mesh_copy, uh); - SECTION("R^2x2 function shallow copy") - { - using DataType = TinyMatrix<2>; - std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh); - std::shared_ptr vh = shallowCopy(mesh, uh); + REQUIRE(uh != wh); + REQUIRE(&(uh->cellValues()[CellId{0}]) == + &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}])); + } - REQUIRE(uh == vh); + SECTION("R^1x1 function shallow copy") + { + using DataType = TinyMatrix<1>; + std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh); + std::shared_ptr vh = shallowCopy(mesh, uh); - std::shared_ptr wh = shallowCopy(mesh_copy, uh); + REQUIRE(uh == vh); - REQUIRE(uh != wh); - REQUIRE(&(uh->cellValues()[CellId{0}]) == - &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}])); - } + std::shared_ptr wh = shallowCopy(mesh_copy, uh); - SECTION("R^3x3 function shallow copy") - { - using DataType = TinyMatrix<3>; - std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh); - std::shared_ptr vh = shallowCopy(mesh, uh); + REQUIRE(uh != wh); + REQUIRE(&(uh->cellValues()[CellId{0}]) == + &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}])); + } - REQUIRE(uh == vh); + SECTION("R^2x2 function shallow copy") + { + using DataType = TinyMatrix<2>; + std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh); + std::shared_ptr vh = shallowCopy(mesh, uh); - std::shared_ptr wh = shallowCopy(mesh_copy, uh); + REQUIRE(uh == vh); - REQUIRE(uh != wh); - REQUIRE(&(uh->cellValues()[CellId{0}]) == - &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}])); + std::shared_ptr wh = shallowCopy(mesh_copy, uh); + + REQUIRE(uh != wh); + REQUIRE(&(uh->cellValues()[CellId{0}]) == + &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}])); + } + + SECTION("R^3x3 function shallow copy") + { + using DataType = TinyMatrix<3>; + std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh); + std::shared_ptr vh = shallowCopy(mesh, uh); + + REQUIRE(uh == vh); + + std::shared_ptr wh = shallowCopy(mesh_copy, uh); + + REQUIRE(uh != wh); + REQUIRE(&(uh->cellValues()[CellId{0}]) == + &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}])); + } + } } } @@ -161,144 +169,152 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]") { constexpr size_t Dimension = 2; - std::shared_ptr mesh = MeshDataBaseForTests::get().cartesianMesh2D(); - std::shared_ptr mesh_copy = - std::make_shared<std::decay_t<decltype(*mesh)>>(mesh->shared_connectivity(), mesh->xr()); + std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - SECTION("common mesh") - { - std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh); - std::shared_ptr vh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh); - std::shared_ptr wh = std::make_shared<DiscreteFunctionP0<Dimension, TinyVector<2>>>(mesh); + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh = named_mesh.mesh(); - std::shared_ptr qh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh_copy); + std::shared_ptr mesh_copy = + std::make_shared<std::decay_t<decltype(*mesh)>>(mesh->shared_connectivity(), mesh->xr()); - REQUIRE(getCommonMesh({uh, vh, wh}).get() == mesh.get()); - REQUIRE(getCommonMesh({uh, vh, wh, qh}).use_count() == 0); - } + SECTION("common mesh") + { + std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh); + std::shared_ptr vh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh); + std::shared_ptr wh = std::make_shared<DiscreteFunctionP0<Dimension, TinyVector<2>>>(mesh); - SECTION("check discretization type") - { - std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh); - std::shared_ptr vh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh); - - std::shared_ptr qh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh_copy); - - std::shared_ptr Uh = std::make_shared<DiscreteFunctionP0Vector<Dimension, double>>(mesh, 3); - std::shared_ptr Vh = std::make_shared<DiscreteFunctionP0Vector<Dimension, double>>(mesh, 3); - - REQUIRE(checkDiscretizationType({uh}, DiscreteFunctionType::P0)); - REQUIRE(checkDiscretizationType({uh, vh, qh}, DiscreteFunctionType::P0)); - REQUIRE(not checkDiscretizationType({uh}, DiscreteFunctionType::P0Vector)); - REQUIRE(not checkDiscretizationType({uh, vh, qh}, DiscreteFunctionType::P0Vector)); - REQUIRE(checkDiscretizationType({Uh}, DiscreteFunctionType::P0Vector)); - REQUIRE(checkDiscretizationType({Uh, Vh}, DiscreteFunctionType::P0Vector)); - REQUIRE(not checkDiscretizationType({Uh, Vh}, DiscreteFunctionType::P0)); - REQUIRE(not checkDiscretizationType({Uh}, DiscreteFunctionType::P0)); - } + std::shared_ptr qh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh_copy); - SECTION("scalar function shallow copy") - { - std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh); - std::shared_ptr vh = shallowCopy(mesh, uh); + REQUIRE(getCommonMesh({uh, vh, wh}).get() == mesh.get()); + REQUIRE(getCommonMesh({uh, vh, wh, qh}).use_count() == 0); + } - REQUIRE(uh == vh); + SECTION("check discretization type") + { + std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh); + std::shared_ptr vh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh); - std::shared_ptr wh = shallowCopy(mesh_copy, uh); + std::shared_ptr qh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh_copy); - REQUIRE(uh != wh); - REQUIRE(&(uh->cellValues()[CellId{0}]) == - &(dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*wh).cellValues()[CellId{0}])); - } + std::shared_ptr Uh = std::make_shared<DiscreteFunctionP0Vector<Dimension, double>>(mesh, 3); + std::shared_ptr Vh = std::make_shared<DiscreteFunctionP0Vector<Dimension, double>>(mesh, 3); - SECTION("R^1 function shallow copy") - { - using DataType = TinyVector<1>; - std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh); - std::shared_ptr vh = shallowCopy(mesh, uh); + REQUIRE(checkDiscretizationType({uh}, DiscreteFunctionType::P0)); + REQUIRE(checkDiscretizationType({uh, vh, qh}, DiscreteFunctionType::P0)); + REQUIRE(not checkDiscretizationType({uh}, DiscreteFunctionType::P0Vector)); + REQUIRE(not checkDiscretizationType({uh, vh, qh}, DiscreteFunctionType::P0Vector)); + REQUIRE(checkDiscretizationType({Uh}, DiscreteFunctionType::P0Vector)); + REQUIRE(checkDiscretizationType({Uh, Vh}, DiscreteFunctionType::P0Vector)); + REQUIRE(not checkDiscretizationType({Uh, Vh}, DiscreteFunctionType::P0)); + REQUIRE(not checkDiscretizationType({Uh}, DiscreteFunctionType::P0)); + } - REQUIRE(uh == vh); + SECTION("scalar function shallow copy") + { + std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh); + std::shared_ptr vh = shallowCopy(mesh, uh); - std::shared_ptr wh = shallowCopy(mesh_copy, uh); + REQUIRE(uh == vh); - REQUIRE(uh != wh); - REQUIRE(&(uh->cellValues()[CellId{0}]) == - &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}])); - } + std::shared_ptr wh = shallowCopy(mesh_copy, uh); - SECTION("R^2 function shallow copy") - { - using DataType = TinyVector<2>; - std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh); - std::shared_ptr vh = shallowCopy(mesh, uh); + REQUIRE(uh != wh); + REQUIRE(&(uh->cellValues()[CellId{0}]) == + &(dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*wh).cellValues()[CellId{0}])); + } - REQUIRE(uh == vh); + SECTION("R^1 function shallow copy") + { + using DataType = TinyVector<1>; + std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh); + std::shared_ptr vh = shallowCopy(mesh, uh); - std::shared_ptr wh = shallowCopy(mesh_copy, uh); + REQUIRE(uh == vh); - REQUIRE(uh != wh); - REQUIRE(&(uh->cellValues()[CellId{0}]) == - &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}])); - } + std::shared_ptr wh = shallowCopy(mesh_copy, uh); - SECTION("R^3 function shallow copy") - { - using DataType = TinyVector<3>; - std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh); - std::shared_ptr vh = shallowCopy(mesh, uh); + REQUIRE(uh != wh); + REQUIRE(&(uh->cellValues()[CellId{0}]) == + &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}])); + } - REQUIRE(uh == vh); + SECTION("R^2 function shallow copy") + { + using DataType = TinyVector<2>; + std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh); + std::shared_ptr vh = shallowCopy(mesh, uh); - std::shared_ptr wh = shallowCopy(mesh_copy, uh); + REQUIRE(uh == vh); - REQUIRE(uh != wh); - REQUIRE(&(uh->cellValues()[CellId{0}]) == - &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}])); - } + std::shared_ptr wh = shallowCopy(mesh_copy, uh); - SECTION("R^1x1 function shallow copy") - { - using DataType = TinyMatrix<1>; - std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh); - std::shared_ptr vh = shallowCopy(mesh, uh); + REQUIRE(uh != wh); + REQUIRE(&(uh->cellValues()[CellId{0}]) == + &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}])); + } - REQUIRE(uh == vh); + SECTION("R^3 function shallow copy") + { + using DataType = TinyVector<3>; + std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh); + std::shared_ptr vh = shallowCopy(mesh, uh); - std::shared_ptr wh = shallowCopy(mesh_copy, uh); + REQUIRE(uh == vh); - REQUIRE(uh != wh); - REQUIRE(&(uh->cellValues()[CellId{0}]) == - &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}])); - } + std::shared_ptr wh = shallowCopy(mesh_copy, uh); - SECTION("R^2x2 function shallow copy") - { - using DataType = TinyMatrix<2>; - std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh); - std::shared_ptr vh = shallowCopy(mesh, uh); + REQUIRE(uh != wh); + REQUIRE(&(uh->cellValues()[CellId{0}]) == + &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}])); + } - REQUIRE(uh == vh); + SECTION("R^1x1 function shallow copy") + { + using DataType = TinyMatrix<1>; + std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh); + std::shared_ptr vh = shallowCopy(mesh, uh); - std::shared_ptr wh = shallowCopy(mesh_copy, uh); + REQUIRE(uh == vh); - REQUIRE(uh != wh); - REQUIRE(&(uh->cellValues()[CellId{0}]) == - &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}])); - } + std::shared_ptr wh = shallowCopy(mesh_copy, uh); - SECTION("R^3x3 function shallow copy") - { - using DataType = TinyMatrix<3>; - std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh); - std::shared_ptr vh = shallowCopy(mesh, uh); + REQUIRE(uh != wh); + REQUIRE(&(uh->cellValues()[CellId{0}]) == + &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}])); + } + + SECTION("R^2x2 function shallow copy") + { + using DataType = TinyMatrix<2>; + std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh); + std::shared_ptr vh = shallowCopy(mesh, uh); + + REQUIRE(uh == vh); + + std::shared_ptr wh = shallowCopy(mesh_copy, uh); + + REQUIRE(uh != wh); + REQUIRE(&(uh->cellValues()[CellId{0}]) == + &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}])); + } - REQUIRE(uh == vh); + SECTION("R^3x3 function shallow copy") + { + using DataType = TinyMatrix<3>; + std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh); + std::shared_ptr vh = shallowCopy(mesh, uh); - std::shared_ptr wh = shallowCopy(mesh_copy, uh); + REQUIRE(uh == vh); - REQUIRE(uh != wh); - REQUIRE(&(uh->cellValues()[CellId{0}]) == - &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}])); + std::shared_ptr wh = shallowCopy(mesh_copy, uh); + + REQUIRE(uh != wh); + REQUIRE(&(uh->cellValues()[CellId{0}]) == + &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}])); + } + } } } @@ -306,144 +322,152 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]") { constexpr size_t Dimension = 3; - std::shared_ptr mesh = MeshDataBaseForTests::get().cartesianMesh3D(); - std::shared_ptr mesh_copy = - std::make_shared<std::decay_t<decltype(*mesh)>>(mesh->shared_connectivity(), mesh->xr()); + std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - SECTION("common mesh") - { - std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh); - std::shared_ptr vh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh); - std::shared_ptr wh = std::make_shared<DiscreteFunctionP0<Dimension, TinyVector<2>>>(mesh); + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh = named_mesh.mesh(); - std::shared_ptr qh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh_copy); + std::shared_ptr mesh_copy = + std::make_shared<std::decay_t<decltype(*mesh)>>(mesh->shared_connectivity(), mesh->xr()); - REQUIRE(getCommonMesh({uh, vh, wh}).get() == mesh.get()); - REQUIRE(getCommonMesh({uh, vh, wh, qh}).use_count() == 0); - } + SECTION("common mesh") + { + std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh); + std::shared_ptr vh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh); + std::shared_ptr wh = std::make_shared<DiscreteFunctionP0<Dimension, TinyVector<2>>>(mesh); - SECTION("check discretization type") - { - std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh); - std::shared_ptr vh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh); - - std::shared_ptr qh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh_copy); - - std::shared_ptr Uh = std::make_shared<DiscreteFunctionP0Vector<Dimension, double>>(mesh, 3); - std::shared_ptr Vh = std::make_shared<DiscreteFunctionP0Vector<Dimension, double>>(mesh, 3); - - REQUIRE(checkDiscretizationType({uh}, DiscreteFunctionType::P0)); - REQUIRE(checkDiscretizationType({uh, vh, qh}, DiscreteFunctionType::P0)); - REQUIRE(not checkDiscretizationType({uh}, DiscreteFunctionType::P0Vector)); - REQUIRE(not checkDiscretizationType({uh, vh, qh}, DiscreteFunctionType::P0Vector)); - REQUIRE(checkDiscretizationType({Uh}, DiscreteFunctionType::P0Vector)); - REQUIRE(checkDiscretizationType({Uh, Vh}, DiscreteFunctionType::P0Vector)); - REQUIRE(not checkDiscretizationType({Uh, Vh}, DiscreteFunctionType::P0)); - REQUIRE(not checkDiscretizationType({Uh}, DiscreteFunctionType::P0)); - } + std::shared_ptr qh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh_copy); - SECTION("scalar function shallow copy") - { - std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh); - std::shared_ptr vh = shallowCopy(mesh, uh); + REQUIRE(getCommonMesh({uh, vh, wh}).get() == mesh.get()); + REQUIRE(getCommonMesh({uh, vh, wh, qh}).use_count() == 0); + } - REQUIRE(uh == vh); + SECTION("check discretization type") + { + std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh); + std::shared_ptr vh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh); - std::shared_ptr wh = shallowCopy(mesh_copy, uh); + std::shared_ptr qh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh_copy); - REQUIRE(uh != wh); - REQUIRE(&(uh->cellValues()[CellId{0}]) == - &(dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*wh).cellValues()[CellId{0}])); - } + std::shared_ptr Uh = std::make_shared<DiscreteFunctionP0Vector<Dimension, double>>(mesh, 3); + std::shared_ptr Vh = std::make_shared<DiscreteFunctionP0Vector<Dimension, double>>(mesh, 3); - SECTION("R^1 function shallow copy") - { - using DataType = TinyVector<1>; - std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh); - std::shared_ptr vh = shallowCopy(mesh, uh); + REQUIRE(checkDiscretizationType({uh}, DiscreteFunctionType::P0)); + REQUIRE(checkDiscretizationType({uh, vh, qh}, DiscreteFunctionType::P0)); + REQUIRE(not checkDiscretizationType({uh}, DiscreteFunctionType::P0Vector)); + REQUIRE(not checkDiscretizationType({uh, vh, qh}, DiscreteFunctionType::P0Vector)); + REQUIRE(checkDiscretizationType({Uh}, DiscreteFunctionType::P0Vector)); + REQUIRE(checkDiscretizationType({Uh, Vh}, DiscreteFunctionType::P0Vector)); + REQUIRE(not checkDiscretizationType({Uh, Vh}, DiscreteFunctionType::P0)); + REQUIRE(not checkDiscretizationType({Uh}, DiscreteFunctionType::P0)); + } - REQUIRE(uh == vh); + SECTION("scalar function shallow copy") + { + std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh); + std::shared_ptr vh = shallowCopy(mesh, uh); - std::shared_ptr wh = shallowCopy(mesh_copy, uh); + REQUIRE(uh == vh); - REQUIRE(uh != wh); - REQUIRE(&(uh->cellValues()[CellId{0}]) == - &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}])); - } + std::shared_ptr wh = shallowCopy(mesh_copy, uh); - SECTION("R^2 function shallow copy") - { - using DataType = TinyVector<2>; - std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh); - std::shared_ptr vh = shallowCopy(mesh, uh); + REQUIRE(uh != wh); + REQUIRE(&(uh->cellValues()[CellId{0}]) == + &(dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*wh).cellValues()[CellId{0}])); + } - REQUIRE(uh == vh); + SECTION("R^1 function shallow copy") + { + using DataType = TinyVector<1>; + std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh); + std::shared_ptr vh = shallowCopy(mesh, uh); - std::shared_ptr wh = shallowCopy(mesh_copy, uh); + REQUIRE(uh == vh); - REQUIRE(uh != wh); - REQUIRE(&(uh->cellValues()[CellId{0}]) == - &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}])); - } + std::shared_ptr wh = shallowCopy(mesh_copy, uh); - SECTION("R^3 function shallow copy") - { - using DataType = TinyVector<3>; - std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh); - std::shared_ptr vh = shallowCopy(mesh, uh); + REQUIRE(uh != wh); + REQUIRE(&(uh->cellValues()[CellId{0}]) == + &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}])); + } - REQUIRE(uh == vh); + SECTION("R^2 function shallow copy") + { + using DataType = TinyVector<2>; + std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh); + std::shared_ptr vh = shallowCopy(mesh, uh); - std::shared_ptr wh = shallowCopy(mesh_copy, uh); + REQUIRE(uh == vh); - REQUIRE(uh != wh); - REQUIRE(&(uh->cellValues()[CellId{0}]) == - &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}])); - } + std::shared_ptr wh = shallowCopy(mesh_copy, uh); - SECTION("R^1x1 function shallow copy") - { - using DataType = TinyMatrix<1>; - std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh); - std::shared_ptr vh = shallowCopy(mesh, uh); + REQUIRE(uh != wh); + REQUIRE(&(uh->cellValues()[CellId{0}]) == + &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}])); + } - REQUIRE(uh == vh); + SECTION("R^3 function shallow copy") + { + using DataType = TinyVector<3>; + std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh); + std::shared_ptr vh = shallowCopy(mesh, uh); - std::shared_ptr wh = shallowCopy(mesh_copy, uh); + REQUIRE(uh == vh); - REQUIRE(uh != wh); - REQUIRE(&(uh->cellValues()[CellId{0}]) == - &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}])); - } + std::shared_ptr wh = shallowCopy(mesh_copy, uh); - SECTION("R^2x2 function shallow copy") - { - using DataType = TinyMatrix<2>; - std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh); - std::shared_ptr vh = shallowCopy(mesh, uh); + REQUIRE(uh != wh); + REQUIRE(&(uh->cellValues()[CellId{0}]) == + &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}])); + } - REQUIRE(uh == vh); + SECTION("R^1x1 function shallow copy") + { + using DataType = TinyMatrix<1>; + std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh); + std::shared_ptr vh = shallowCopy(mesh, uh); - std::shared_ptr wh = shallowCopy(mesh_copy, uh); + REQUIRE(uh == vh); - REQUIRE(uh != wh); - REQUIRE(&(uh->cellValues()[CellId{0}]) == - &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}])); - } + std::shared_ptr wh = shallowCopy(mesh_copy, uh); - SECTION("R^3x3 function shallow copy") - { - using DataType = TinyMatrix<3>; - std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh); - std::shared_ptr vh = shallowCopy(mesh, uh); + REQUIRE(uh != wh); + REQUIRE(&(uh->cellValues()[CellId{0}]) == + &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}])); + } + + SECTION("R^2x2 function shallow copy") + { + using DataType = TinyMatrix<2>; + std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh); + std::shared_ptr vh = shallowCopy(mesh, uh); + + REQUIRE(uh == vh); + + std::shared_ptr wh = shallowCopy(mesh_copy, uh); - REQUIRE(uh == vh); + REQUIRE(uh != wh); + REQUIRE(&(uh->cellValues()[CellId{0}]) == + &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}])); + } - std::shared_ptr wh = shallowCopy(mesh_copy, uh); + SECTION("R^3x3 function shallow copy") + { + using DataType = TinyMatrix<3>; + std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh); + std::shared_ptr vh = shallowCopy(mesh, uh); - REQUIRE(uh != wh); - REQUIRE(&(uh->cellValues()[CellId{0}]) == - &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}])); + REQUIRE(uh == vh); + + std::shared_ptr wh = shallowCopy(mesh_copy, uh); + + REQUIRE(uh != wh); + REQUIRE(&(uh->cellValues()[CellId{0}]) == + &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}])); + } + } } } @@ -453,21 +477,29 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]") { constexpr size_t Dimension = 1; - std::shared_ptr mesh = MeshDataBaseForTests::get().cartesianMesh1D(); - std::shared_ptr other_mesh = - CartesianMeshBuilder{TinyVector<1>{-1}, TinyVector<1>{3}, TinyVector<1, size_t>{19}}.mesh(); + std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); + + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh = named_mesh.mesh(); + + std::shared_ptr other_mesh = + CartesianMeshBuilder{TinyVector<1>{-1}, TinyVector<1>{3}, TinyVector<1, size_t>{19}}.mesh(); - std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh); + std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh); - REQUIRE_THROWS_WITH(shallowCopy(other_mesh, uh), "error: cannot shallow copy when connectivity changes"); + REQUIRE_THROWS_WITH(shallowCopy(other_mesh, uh), "error: cannot shallow copy when connectivity changes"); + } + } } SECTION("incompatible mesh dimension") { constexpr size_t Dimension = 1; - std::shared_ptr mesh_1d = MeshDataBaseForTests::get().cartesianMesh1D(); - std::shared_ptr mesh_2d = MeshDataBaseForTests::get().cartesianMesh2D(); + std::shared_ptr mesh_1d = MeshDataBaseForTests::get().cartesian1DMesh(); + std::shared_ptr mesh_2d = MeshDataBaseForTests::get().cartesian2DMesh(); std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh_1d); diff --git a/tests/test_DiscreteFunctionVectorInterpoler.cpp b/tests/test_DiscreteFunctionVectorInterpoler.cpp index 6a1a5a94b55302aa36fbd85b7d6e7b1522a4ef6b..692dd8c6c18ad85f87f5c85dcc41a6bcb0838312 100644 --- a/tests/test_DiscreteFunctionVectorInterpoler.cpp +++ b/tests/test_DiscreteFunctionVectorInterpoler.cpp @@ -53,296 +53,338 @@ TEST_CASE("DiscreteFunctionVectorInterpoler", "[scheme]") { constexpr size_t Dimension = 1; - const auto& mesh_1d = MeshDataBaseForTests::get().cartesianMesh1D(); - auto xj = MeshDataManager::instance().getMeshData(*mesh_1d).xj(); + std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - std::string_view data = R"( + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_1d = named_mesh.mesh(); + + auto xj = MeshDataManager::instance().getMeshData(*mesh_1d).xj(); + + std::string_view data = R"( import math; let B_scalar_non_linear_1d: R^1 -> B, x -> (exp(2 * x[0]) + 3 > 4); let N_scalar_non_linear_1d: R^1 -> N, x -> floor(3 * x[0] * x[0] + 2); let Z_scalar_non_linear_1d: R^1 -> Z, x -> floor(exp(2 * x[0]) - 1); let R_scalar_non_linear_1d: R^1 -> R, x -> 2 * exp(x[0]) + 3; )"; - TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"}; - - auto ast = ASTBuilder::build(input); - - ASTModulesImporter{*ast}; - ASTNodeTypeCleaner<language::import_instruction>{*ast}; - - ASTSymbolTableBuilder{*ast}; - ASTNodeDataTypeBuilder{*ast}; - - ASTNodeTypeCleaner<language::var_declaration>{*ast}; - ASTNodeTypeCleaner<language::fct_declaration>{*ast}; - ASTNodeExpressionBuilder{*ast}; - - TAO_PEGTL_NAMESPACE::position position{TAO_PEGTL_NAMESPACE::internal::iterator{"fixture"}, "fixture"}; - position.byte = data.size(); // ensure that variables are declared at this point - - std::shared_ptr<SymbolTable> symbol_table = ast->m_symbol_table; - - std::vector<FunctionSymbolId> function_id_list; - register_function(position, symbol_table, "B_scalar_non_linear_1d", function_id_list); - register_function(position, symbol_table, "N_scalar_non_linear_1d", function_id_list); - register_function(position, symbol_table, "Z_scalar_non_linear_1d", function_id_list); - register_function(position, symbol_table, "R_scalar_non_linear_1d", function_id_list); - - DiscreteFunctionVectorInterpoler interpoler(mesh_1d, std::make_shared<DiscreteFunctionDescriptorP0Vector>(), - function_id_list); - std::shared_ptr discrete_function = interpoler.interpolate(); - - size_t i = 0; - - { - CellValue<double> cell_value{mesh_1d->connectivity()}; - parallel_for( - cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<Dimension>& x = xj[cell_id]; - cell_value[cell_id] = std::exp(2 * x[0]) + 3 > 4; - }); - - REQUIRE(same_cell_value(cell_value, i++, - dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); - } - - { - CellValue<double> cell_value{mesh_1d->connectivity()}; - parallel_for( - cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<Dimension>& x = xj[cell_id]; - cell_value[cell_id] = std::floor(3 * x[0] * x[0] + 2); - }); - - REQUIRE(same_cell_value(cell_value, i++, - dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); - } - - { - CellValue<double> cell_value{mesh_1d->connectivity()}; - parallel_for( - cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<Dimension>& x = xj[cell_id]; - cell_value[cell_id] = std::floor(std::exp(2 * x[0]) - 1); - }); - - REQUIRE(same_cell_value(cell_value, i++, - dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); - } - - { - CellValue<double> cell_value{mesh_1d->connectivity()}; - parallel_for( - cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<Dimension>& x = xj[cell_id]; - cell_value[cell_id] = 2 * std::exp(x[0]) + 3; - }); - - REQUIRE(same_cell_value(cell_value, i++, - dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); + TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"}; + + auto ast = ASTBuilder::build(input); + + ASTModulesImporter{*ast}; + ASTNodeTypeCleaner<language::import_instruction>{*ast}; + + ASTSymbolTableBuilder{*ast}; + ASTNodeDataTypeBuilder{*ast}; + + ASTNodeTypeCleaner<language::var_declaration>{*ast}; + ASTNodeTypeCleaner<language::fct_declaration>{*ast}; + ASTNodeExpressionBuilder{*ast}; + + TAO_PEGTL_NAMESPACE::position position{TAO_PEGTL_NAMESPACE::internal::iterator{"fixture"}, "fixture"}; + position.byte = data.size(); // ensure that variables are declared at this point + + std::shared_ptr<SymbolTable> symbol_table = ast->m_symbol_table; + + std::vector<FunctionSymbolId> function_id_list; + register_function(position, symbol_table, "B_scalar_non_linear_1d", function_id_list); + register_function(position, symbol_table, "N_scalar_non_linear_1d", function_id_list); + register_function(position, symbol_table, "Z_scalar_non_linear_1d", function_id_list); + register_function(position, symbol_table, "R_scalar_non_linear_1d", function_id_list); + + DiscreteFunctionVectorInterpoler interpoler(mesh_1d, std::make_shared<DiscreteFunctionDescriptorP0Vector>(), + function_id_list); + std::shared_ptr discrete_function = interpoler.interpolate(); + + size_t i = 0; + + { + CellValue<double> cell_value{mesh_1d->connectivity()}; + parallel_for( + cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<Dimension>& x = xj[cell_id]; + cell_value[cell_id] = std::exp(2 * x[0]) + 3 > 4; + }); + + REQUIRE( + same_cell_value(cell_value, i++, + dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); + } + + { + CellValue<double> cell_value{mesh_1d->connectivity()}; + parallel_for( + cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<Dimension>& x = xj[cell_id]; + cell_value[cell_id] = std::floor(3 * x[0] * x[0] + 2); + }); + + REQUIRE( + same_cell_value(cell_value, i++, + dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); + } + + { + CellValue<double> cell_value{mesh_1d->connectivity()}; + parallel_for( + cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<Dimension>& x = xj[cell_id]; + cell_value[cell_id] = std::floor(std::exp(2 * x[0]) - 1); + }); + + REQUIRE( + same_cell_value(cell_value, i++, + dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); + } + + { + CellValue<double> cell_value{mesh_1d->connectivity()}; + parallel_for( + cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<Dimension>& x = xj[cell_id]; + cell_value[cell_id] = 2 * std::exp(x[0]) + 3; + }); + + REQUIRE( + same_cell_value(cell_value, i++, + dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); + } + + REQUIRE(i == function_id_list.size()); + } } - - REQUIRE(i == function_id_list.size()); } SECTION("2D") { constexpr size_t Dimension = 2; - const auto& mesh_2d = MeshDataBaseForTests::get().cartesianMesh2D(); - auto xj = MeshDataManager::instance().getMeshData(*mesh_2d).xj(); + std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); + + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_2d = named_mesh.mesh(); - std::string_view data = R"( + auto xj = MeshDataManager::instance().getMeshData(*mesh_2d).xj(); + + std::string_view data = R"( import math; let B_scalar_non_linear_2d: R^2 -> B, x -> (exp(2 * x[0]) + 3 > 4); let N_scalar_non_linear_2d: R^2 -> N, x -> floor(3 * (x[0] * x[1]) * (x[0] * x[1]) + 2); let Z_scalar_non_linear_2d: R^2 -> Z, x -> floor(exp(2 * x[1]) - 1); let R_scalar_non_linear_2d: R^2 -> R, x -> 2 * exp(x[0] + x[1]) + 3; )"; - TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"}; - - auto ast = ASTBuilder::build(input); - - ASTModulesImporter{*ast}; - ASTNodeTypeCleaner<language::import_instruction>{*ast}; - - ASTSymbolTableBuilder{*ast}; - ASTNodeDataTypeBuilder{*ast}; - - ASTNodeTypeCleaner<language::var_declaration>{*ast}; - ASTNodeTypeCleaner<language::fct_declaration>{*ast}; - ASTNodeExpressionBuilder{*ast}; - - TAO_PEGTL_NAMESPACE::position position{TAO_PEGTL_NAMESPACE::internal::iterator{"fixture"}, "fixture"}; - position.byte = data.size(); // ensure that variables are declared at this point - - std::shared_ptr<SymbolTable> symbol_table = ast->m_symbol_table; - - std::vector<FunctionSymbolId> function_id_list; - register_function(position, symbol_table, "B_scalar_non_linear_2d", function_id_list); - register_function(position, symbol_table, "N_scalar_non_linear_2d", function_id_list); - register_function(position, symbol_table, "Z_scalar_non_linear_2d", function_id_list); - register_function(position, symbol_table, "R_scalar_non_linear_2d", function_id_list); - - DiscreteFunctionVectorInterpoler interpoler(mesh_2d, std::make_shared<DiscreteFunctionDescriptorP0Vector>(), - function_id_list); - std::shared_ptr discrete_function = interpoler.interpolate(); - - size_t i = 0; - - { - CellValue<double> cell_value{mesh_2d->connectivity()}; - parallel_for( - cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<Dimension>& x = xj[cell_id]; - cell_value[cell_id] = std::exp(2 * x[0]) + 3 > 4; - }); - - REQUIRE(same_cell_value(cell_value, i++, - dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); - } - - { - CellValue<double> cell_value{mesh_2d->connectivity()}; - parallel_for( - cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<Dimension>& x = xj[cell_id]; - cell_value[cell_id] = std::floor(3 * (x[0] * x[1]) * (x[0] * x[1]) + 2); - }); - - REQUIRE(same_cell_value(cell_value, i++, - dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); - } - - { - CellValue<double> cell_value{mesh_2d->connectivity()}; - parallel_for( - cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<Dimension>& x = xj[cell_id]; - cell_value[cell_id] = std::floor(std::exp(2 * x[1]) - 1); - }); - - REQUIRE(same_cell_value(cell_value, i++, - dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); - } - - { - CellValue<double> cell_value{mesh_2d->connectivity()}; - parallel_for( - cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<Dimension>& x = xj[cell_id]; - cell_value[cell_id] = 2 * std::exp(x[0] + x[1]) + 3; - }); - - REQUIRE(same_cell_value(cell_value, i++, - dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); + TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"}; + + auto ast = ASTBuilder::build(input); + + ASTModulesImporter{*ast}; + ASTNodeTypeCleaner<language::import_instruction>{*ast}; + + ASTSymbolTableBuilder{*ast}; + ASTNodeDataTypeBuilder{*ast}; + + ASTNodeTypeCleaner<language::var_declaration>{*ast}; + ASTNodeTypeCleaner<language::fct_declaration>{*ast}; + ASTNodeExpressionBuilder{*ast}; + + TAO_PEGTL_NAMESPACE::position position{TAO_PEGTL_NAMESPACE::internal::iterator{"fixture"}, "fixture"}; + position.byte = data.size(); // ensure that variables are declared at this point + + std::shared_ptr<SymbolTable> symbol_table = ast->m_symbol_table; + + std::vector<FunctionSymbolId> function_id_list; + register_function(position, symbol_table, "B_scalar_non_linear_2d", function_id_list); + register_function(position, symbol_table, "N_scalar_non_linear_2d", function_id_list); + register_function(position, symbol_table, "Z_scalar_non_linear_2d", function_id_list); + register_function(position, symbol_table, "R_scalar_non_linear_2d", function_id_list); + + DiscreteFunctionVectorInterpoler interpoler(mesh_2d, std::make_shared<DiscreteFunctionDescriptorP0Vector>(), + function_id_list); + std::shared_ptr discrete_function = interpoler.interpolate(); + + size_t i = 0; + + { + CellValue<double> cell_value{mesh_2d->connectivity()}; + parallel_for( + cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<Dimension>& x = xj[cell_id]; + cell_value[cell_id] = std::exp(2 * x[0]) + 3 > 4; + }); + + REQUIRE( + same_cell_value(cell_value, i++, + dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); + } + + { + CellValue<double> cell_value{mesh_2d->connectivity()}; + parallel_for( + cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<Dimension>& x = xj[cell_id]; + cell_value[cell_id] = std::floor(3 * (x[0] * x[1]) * (x[0] * x[1]) + 2); + }); + + REQUIRE( + same_cell_value(cell_value, i++, + dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); + } + + { + CellValue<double> cell_value{mesh_2d->connectivity()}; + parallel_for( + cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<Dimension>& x = xj[cell_id]; + cell_value[cell_id] = std::floor(std::exp(2 * x[1]) - 1); + }); + + REQUIRE( + same_cell_value(cell_value, i++, + dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); + } + + { + CellValue<double> cell_value{mesh_2d->connectivity()}; + parallel_for( + cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<Dimension>& x = xj[cell_id]; + cell_value[cell_id] = 2 * std::exp(x[0] + x[1]) + 3; + }); + + REQUIRE( + same_cell_value(cell_value, i++, + dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); + } + + REQUIRE(i == function_id_list.size()); + } } - - REQUIRE(i == function_id_list.size()); } SECTION("3D") { constexpr size_t Dimension = 3; - const auto& mesh_3d = MeshDataBaseForTests::get().cartesianMesh3D(); - auto xj = MeshDataManager::instance().getMeshData(*mesh_3d).xj(); + std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); + + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_3d = named_mesh.mesh(); - std::string_view data = R"( + auto xj = MeshDataManager::instance().getMeshData(*mesh_3d).xj(); + + std::string_view data = R"( import math; let B_scalar_non_linear_3d: R^3 -> B, x -> (exp(2 * x[0] + x[2]) + 3 > 4); let N_scalar_non_linear_3d: R^3 -> N, x -> floor(3 * (x[0] * x[1]) * (x[0] * x[1]) + 2); let Z_scalar_non_linear_3d: R^3 -> Z, x -> floor(exp(2 * x[1]) - x[2]); let R_scalar_non_linear_3d: R^3 -> R, x -> 2 * exp(x[0] + x[1]) + 3 * x[2]; )"; - TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"}; - - auto ast = ASTBuilder::build(input); - - ASTModulesImporter{*ast}; - ASTNodeTypeCleaner<language::import_instruction>{*ast}; - - ASTSymbolTableBuilder{*ast}; - ASTNodeDataTypeBuilder{*ast}; - - ASTNodeTypeCleaner<language::var_declaration>{*ast}; - ASTNodeTypeCleaner<language::fct_declaration>{*ast}; - ASTNodeExpressionBuilder{*ast}; - - TAO_PEGTL_NAMESPACE::position position{TAO_PEGTL_NAMESPACE::internal::iterator{"fixture"}, "fixture"}; - position.byte = data.size(); // ensure that variables are declared at this point - - std::shared_ptr<SymbolTable> symbol_table = ast->m_symbol_table; - - std::vector<FunctionSymbolId> function_id_list; - register_function(position, symbol_table, "B_scalar_non_linear_3d", function_id_list); - register_function(position, symbol_table, "N_scalar_non_linear_3d", function_id_list); - register_function(position, symbol_table, "Z_scalar_non_linear_3d", function_id_list); - register_function(position, symbol_table, "R_scalar_non_linear_3d", function_id_list); - - DiscreteFunctionVectorInterpoler interpoler(mesh_3d, std::make_shared<DiscreteFunctionDescriptorP0Vector>(), - function_id_list); - std::shared_ptr discrete_function = interpoler.interpolate(); - - size_t i = 0; - - { - CellValue<double> cell_value{mesh_3d->connectivity()}; - parallel_for( - cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<Dimension>& x = xj[cell_id]; - cell_value[cell_id] = std::exp(2 * x[0] + x[2]) + 3 > 4; - }); - - REQUIRE(same_cell_value(cell_value, i++, - dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); - } - - { - CellValue<double> cell_value{mesh_3d->connectivity()}; - parallel_for( - cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<Dimension>& x = xj[cell_id]; - cell_value[cell_id] = std::floor(3 * (x[0] * x[1]) * (x[0] * x[1]) + 2); - }); - - REQUIRE(same_cell_value(cell_value, i++, - dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); - } - - { - CellValue<double> cell_value{mesh_3d->connectivity()}; - parallel_for( - cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<Dimension>& x = xj[cell_id]; - cell_value[cell_id] = std::floor(std::exp(2 * x[1]) - x[2]); - }); - - REQUIRE(same_cell_value(cell_value, i++, - dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); - } - - { - CellValue<double> cell_value{mesh_3d->connectivity()}; - parallel_for( - cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<Dimension>& x = xj[cell_id]; - cell_value[cell_id] = 2 * std::exp(x[0] + x[1]) + 3 * x[2]; - }); - - REQUIRE(same_cell_value(cell_value, i++, - dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); + TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"}; + + auto ast = ASTBuilder::build(input); + + ASTModulesImporter{*ast}; + ASTNodeTypeCleaner<language::import_instruction>{*ast}; + + ASTSymbolTableBuilder{*ast}; + ASTNodeDataTypeBuilder{*ast}; + + ASTNodeTypeCleaner<language::var_declaration>{*ast}; + ASTNodeTypeCleaner<language::fct_declaration>{*ast}; + ASTNodeExpressionBuilder{*ast}; + + TAO_PEGTL_NAMESPACE::position position{TAO_PEGTL_NAMESPACE::internal::iterator{"fixture"}, "fixture"}; + position.byte = data.size(); // ensure that variables are declared at this point + + std::shared_ptr<SymbolTable> symbol_table = ast->m_symbol_table; + + std::vector<FunctionSymbolId> function_id_list; + register_function(position, symbol_table, "B_scalar_non_linear_3d", function_id_list); + register_function(position, symbol_table, "N_scalar_non_linear_3d", function_id_list); + register_function(position, symbol_table, "Z_scalar_non_linear_3d", function_id_list); + register_function(position, symbol_table, "R_scalar_non_linear_3d", function_id_list); + + DiscreteFunctionVectorInterpoler interpoler(mesh_3d, std::make_shared<DiscreteFunctionDescriptorP0Vector>(), + function_id_list); + std::shared_ptr discrete_function = interpoler.interpolate(); + + size_t i = 0; + + { + CellValue<double> cell_value{mesh_3d->connectivity()}; + parallel_for( + cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<Dimension>& x = xj[cell_id]; + cell_value[cell_id] = std::exp(2 * x[0] + x[2]) + 3 > 4; + }); + + REQUIRE( + same_cell_value(cell_value, i++, + dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); + } + + { + CellValue<double> cell_value{mesh_3d->connectivity()}; + parallel_for( + cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<Dimension>& x = xj[cell_id]; + cell_value[cell_id] = std::floor(3 * (x[0] * x[1]) * (x[0] * x[1]) + 2); + }); + + REQUIRE( + same_cell_value(cell_value, i++, + dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); + } + + { + CellValue<double> cell_value{mesh_3d->connectivity()}; + parallel_for( + cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<Dimension>& x = xj[cell_id]; + cell_value[cell_id] = std::floor(std::exp(2 * x[1]) - x[2]); + }); + + REQUIRE( + same_cell_value(cell_value, i++, + dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); + } + + { + CellValue<double> cell_value{mesh_3d->connectivity()}; + parallel_for( + cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<Dimension>& x = xj[cell_id]; + cell_value[cell_id] = 2 * std::exp(x[0] + x[1]) + 3 * x[2]; + }); + + REQUIRE( + same_cell_value(cell_value, i++, + dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); + } + + REQUIRE(i == function_id_list.size()); + } } - - REQUIRE(i == function_id_list.size()); } SECTION("errors") { - const auto& mesh_3d = MeshDataBaseForTests::get().cartesianMesh3D(); - auto xj = MeshDataManager::instance().getMeshData(*mesh_3d).xj(); + std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); + + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_3d = named_mesh.mesh(); - std::string_view data = R"( + auto xj = MeshDataManager::instance().getMeshData(*mesh_3d).xj(); + + std::string_view data = R"( import math; let B_scalar_non_linear_2d: R^2 -> B, x -> (exp(2 * x[0] + x[1]) + 3 > 4); let N_scalar_non_linear_1d: R^1 -> N, x -> floor(3 * x[0] * x[0] + 2); @@ -350,65 +392,67 @@ let Z_scalar_non_linear_3d: R^3 -> Z, x -> floor(exp(2 * x[1]) - x[2]); let R_scalar_non_linear_3d: R^3 -> R, x -> 2 * exp(x[0] + x[1]) + 3 * x[2]; let R2_scalar_non_linear_3d: R^3 -> R^2, x -> (2 * exp(x[0] + x[1]) + 3 * x[2], x[0] - x[1]); )"; - TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"}; + TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"}; - auto ast = ASTBuilder::build(input); + auto ast = ASTBuilder::build(input); - ASTModulesImporter{*ast}; - ASTNodeTypeCleaner<language::import_instruction>{*ast}; + ASTModulesImporter{*ast}; + ASTNodeTypeCleaner<language::import_instruction>{*ast}; - ASTSymbolTableBuilder{*ast}; - ASTNodeDataTypeBuilder{*ast}; + ASTSymbolTableBuilder{*ast}; + ASTNodeDataTypeBuilder{*ast}; - ASTNodeTypeCleaner<language::var_declaration>{*ast}; - ASTNodeTypeCleaner<language::fct_declaration>{*ast}; - ASTNodeExpressionBuilder{*ast}; + ASTNodeTypeCleaner<language::var_declaration>{*ast}; + ASTNodeTypeCleaner<language::fct_declaration>{*ast}; + ASTNodeExpressionBuilder{*ast}; - TAO_PEGTL_NAMESPACE::position position{TAO_PEGTL_NAMESPACE::internal::iterator{"fixture"}, "fixture"}; - position.byte = data.size(); // ensure that variables are declared at this point + TAO_PEGTL_NAMESPACE::position position{TAO_PEGTL_NAMESPACE::internal::iterator{"fixture"}, "fixture"}; + position.byte = data.size(); // ensure that variables are declared at this point - std::shared_ptr<SymbolTable> symbol_table = ast->m_symbol_table; + std::shared_ptr<SymbolTable> symbol_table = ast->m_symbol_table; - SECTION("invalid function type") - { - std::vector<FunctionSymbolId> function_id_list; - register_function(position, symbol_table, "B_scalar_non_linear_2d", function_id_list); - register_function(position, symbol_table, "N_scalar_non_linear_1d", function_id_list); - register_function(position, symbol_table, "Z_scalar_non_linear_3d", function_id_list); - register_function(position, symbol_table, "R_scalar_non_linear_3d", function_id_list); + SECTION("invalid function type") + { + std::vector<FunctionSymbolId> function_id_list; + register_function(position, symbol_table, "B_scalar_non_linear_2d", function_id_list); + register_function(position, symbol_table, "N_scalar_non_linear_1d", function_id_list); + register_function(position, symbol_table, "Z_scalar_non_linear_3d", function_id_list); + register_function(position, symbol_table, "R_scalar_non_linear_3d", function_id_list); - DiscreteFunctionVectorInterpoler interpoler(mesh_3d, std::make_shared<DiscreteFunctionDescriptorP0Vector>(), - function_id_list); + DiscreteFunctionVectorInterpoler interpoler(mesh_3d, std::make_shared<DiscreteFunctionDescriptorP0Vector>(), + function_id_list); - const std::string error_msg = R"(error: invalid function type + const std::string error_msg = R"(error: invalid function type note: expecting R^3 -> R note: provided function B_scalar_non_linear_2d: R^2 -> B)"; - REQUIRE_THROWS_WITH(interpoler.interpolate(), error_msg); - } + REQUIRE_THROWS_WITH(interpoler.interpolate(), error_msg); + } - SECTION("invalid value type") - { - std::vector<FunctionSymbolId> function_id_list; - register_function(position, symbol_table, "Z_scalar_non_linear_3d", function_id_list); - register_function(position, symbol_table, "R_scalar_non_linear_3d", function_id_list); - register_function(position, symbol_table, "R2_scalar_non_linear_3d", function_id_list); + SECTION("invalid value type") + { + std::vector<FunctionSymbolId> function_id_list; + register_function(position, symbol_table, "Z_scalar_non_linear_3d", function_id_list); + register_function(position, symbol_table, "R_scalar_non_linear_3d", function_id_list); + register_function(position, symbol_table, "R2_scalar_non_linear_3d", function_id_list); - DiscreteFunctionVectorInterpoler interpoler(mesh_3d, std::make_shared<DiscreteFunctionDescriptorP0Vector>(), - function_id_list); + DiscreteFunctionVectorInterpoler interpoler(mesh_3d, std::make_shared<DiscreteFunctionDescriptorP0Vector>(), + function_id_list); - const std::string error_msg = R"(error: vector functions require scalar value type. + const std::string error_msg = R"(error: vector functions require scalar value type. Invalid interpolation value type: R^2)"; - REQUIRE_THROWS_WITH(interpoler.interpolate(), error_msg); - } + REQUIRE_THROWS_WITH(interpoler.interpolate(), error_msg); + } - SECTION("invalid discrete function type") - { - const std::string error_msg = "error: invalid discrete function type for vector interpolation"; + SECTION("invalid discrete function type") + { + const std::string error_msg = "error: invalid discrete function type for vector interpolation"; - DiscreteFunctionVectorInterpoler interpoler{mesh_3d, std::make_shared<DiscreteFunctionDescriptorP0>(), {}}; - REQUIRE_THROWS_WITH(interpoler.interpolate(), error_msg); + DiscreteFunctionVectorInterpoler interpoler{mesh_3d, std::make_shared<DiscreteFunctionDescriptorP0>(), {}}; + REQUIRE_THROWS_WITH(interpoler.interpolate(), error_msg); + } + } } } } diff --git a/tests/test_EdgeIntegrator.cpp b/tests/test_EdgeIntegrator.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0cd2feb9d0765407ee9e6346b91ca768dbe53722 --- /dev/null +++ b/tests/test_EdgeIntegrator.cpp @@ -0,0 +1,261 @@ +#include <catch2/catch_approx.hpp> +#include <catch2/catch_test_macros.hpp> + +#include <analysis/GaussLegendreQuadratureDescriptor.hpp> +#include <analysis/GaussLobattoQuadratureDescriptor.hpp> +#include <analysis/GaussQuadratureDescriptor.hpp> +#include <mesh/DiamondDualMeshManager.hpp> +#include <mesh/ItemValue.hpp> +#include <mesh/Mesh.hpp> +#include <scheme/EdgeIntegrator.hpp> + +#include <MeshDataBaseForTests.hpp> + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("EdgeIntegrator", "[scheme]") +{ + SECTION("3D") + { + using R3 = TinyVector<3>; + + auto hybrid_mesh = MeshDataBaseForTests::get().hybrid3DMesh(); + + auto f = [](const R3& X) -> double { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return x * x + 2 * x * y + 3 * y * y + 2 * z * z - z + 1; + }; + + std::vector<std::pair<std::string, decltype(hybrid_mesh)>> mesh_list; + mesh_list.push_back(std::make_pair("hybrid mesh", hybrid_mesh)); + mesh_list.push_back( + std::make_pair("diamond mesh", DiamondDualMeshManager::instance().getDiamondDualMesh(hybrid_mesh))); + + for (auto mesh_info : mesh_list) { + auto mesh_name = mesh_info.first; + auto mesh = mesh_info.second; + + Array<const double> int_f_per_edge = [=] { + Array<double> int_f(mesh->numberOfEdges()); + auto edge_to_node_matrix = mesh->connectivity().edgeToNodeMatrix(); + + parallel_for( + mesh->numberOfEdges(), PUGS_LAMBDA(const EdgeId edge_id) { + auto edge_node_list = edge_to_node_matrix[edge_id]; + auto xr = mesh->xr(); + double integral = 0; + + LineTransformation<3> T(xr[edge_node_list[0]], xr[edge_node_list[1]]); + auto qf = QuadratureManager::instance().getLineFormula(GaussQuadratureDescriptor(2)); + for (size_t i = 0; i < qf.numberOfPoints(); ++i) { + const auto& xi = qf.point(i); + integral += qf.weight(i) * T.velocityNorm() * f(T(xi)); + } + + int_f[edge_id] = integral; + }); + + return int_f; + }(); + + SECTION(mesh_name) + { + SECTION("direct formula") + { + SECTION("all edges") + { + SECTION("EdgeValue") + { + EdgeValue<double> values(mesh->connectivity()); + EdgeIntegrator::integrateTo([=](const R3 x) { return f(x); }, GaussQuadratureDescriptor(4), *mesh, + values); + + double error = 0; + for (EdgeId edge_id = 0; edge_id < mesh->numberOfEdges(); ++edge_id) { + error += std::abs(int_f_per_edge[edge_id] - values[edge_id]); + } + + REQUIRE(error == Catch::Approx(0).margin(1E-10)); + } + + SECTION("Array") + { + Array<double> values(mesh->numberOfEdges()); + + EdgeIntegrator::integrateTo(f, GaussQuadratureDescriptor(4), *mesh, values); + + double error = 0; + for (EdgeId edge_id = 0; edge_id < mesh->numberOfEdges(); ++edge_id) { + error += std::abs(int_f_per_edge[edge_id] - values[edge_id]); + } + + REQUIRE(error == Catch::Approx(0).margin(1E-10)); + } + + SECTION("SmallArray") + { + SmallArray<double> values(mesh->numberOfEdges()); + EdgeIntegrator::integrateTo(f, GaussQuadratureDescriptor(4), *mesh, values); + + double error = 0; + for (EdgeId edge_id = 0; edge_id < mesh->numberOfEdges(); ++edge_id) { + error += std::abs(int_f_per_edge[edge_id] - values[edge_id]); + } + + REQUIRE(error == Catch::Approx(0).margin(1E-10)); + } + } + + SECTION("edge list") + { + SECTION("Array") + { + Array<EdgeId> edge_list{mesh->numberOfEdges() / 2 + mesh->numberOfEdges() % 2}; + + { + size_t k = 0; + for (EdgeId edge_id = 0; edge_id < mesh->numberOfEdges(); ++(++edge_id), ++k) { + edge_list[k] = edge_id; + } + + REQUIRE(k == edge_list.size()); + } + + Array<double> values = EdgeIntegrator::integrate(f, GaussQuadratureDescriptor(4), *mesh, edge_list); + + double error = 0; + for (size_t i = 0; i < edge_list.size(); ++i) { + error += std::abs(int_f_per_edge[edge_list[i]] - values[i]); + } + + REQUIRE(error == Catch::Approx(0).margin(1E-10)); + } + + SECTION("SmallArray") + { + SmallArray<EdgeId> edge_list{mesh->numberOfEdges() / 2 + mesh->numberOfEdges() % 2}; + + { + size_t k = 0; + for (EdgeId edge_id = 0; edge_id < mesh->numberOfEdges(); ++(++edge_id), ++k) { + edge_list[k] = edge_id; + } + + REQUIRE(k == edge_list.size()); + } + + SmallArray<double> values = EdgeIntegrator::integrate(f, GaussQuadratureDescriptor(4), *mesh, edge_list); + + double error = 0; + for (size_t i = 0; i < edge_list.size(); ++i) { + error += std::abs(int_f_per_edge[edge_list[i]] - values[i]); + } + + REQUIRE(error == Catch::Approx(0).margin(1E-10)); + } + } + } + + SECTION("tensorial formula") + { + SECTION("all edges") + { + SECTION("EdgeValue") + { + EdgeValue<double> values(mesh->connectivity()); + EdgeIntegrator::integrateTo([=](const R3 x) { return f(x); }, GaussLegendreQuadratureDescriptor(10), + *mesh, values); + + double error = 0; + for (EdgeId edge_id = 0; edge_id < mesh->numberOfEdges(); ++edge_id) { + error += std::abs(int_f_per_edge[edge_id] - values[edge_id]); + } + + REQUIRE(error == Catch::Approx(0).margin(1E-10)); + } + + SECTION("Array") + { + Array<double> values(mesh->numberOfEdges()); + + EdgeIntegrator::integrateTo(f, GaussLobattoQuadratureDescriptor(4), *mesh, values); + + double error = 0; + for (EdgeId edge_id = 0; edge_id < mesh->numberOfEdges(); ++edge_id) { + error += std::abs(int_f_per_edge[edge_id] - values[edge_id]); + } + + REQUIRE(error == Catch::Approx(0).margin(1E-10)); + } + + SECTION("SmallArray") + { + SmallArray<double> values(mesh->numberOfEdges()); + EdgeIntegrator::integrateTo(f, GaussLobattoQuadratureDescriptor(4), *mesh, values); + + double error = 0; + for (EdgeId edge_id = 0; edge_id < mesh->numberOfEdges(); ++edge_id) { + error += std::abs(int_f_per_edge[edge_id] - values[edge_id]); + } + + REQUIRE(error == Catch::Approx(0).margin(1E-10)); + } + } + + SECTION("edge list") + { + SECTION("Array") + { + Array<EdgeId> edge_list{mesh->numberOfEdges() / 2 + mesh->numberOfEdges() % 2}; + + { + size_t k = 0; + for (EdgeId edge_id = 0; edge_id < mesh->numberOfEdges(); ++(++edge_id), ++k) { + edge_list[k] = edge_id; + } + + REQUIRE(k == edge_list.size()); + } + + Array<double> values = + EdgeIntegrator::integrate(f, GaussLobattoQuadratureDescriptor(4), *mesh, edge_list); + + double error = 0; + for (size_t i = 0; i < edge_list.size(); ++i) { + error += std::abs(int_f_per_edge[edge_list[i]] - values[i]); + } + + REQUIRE(error == Catch::Approx(0).margin(1E-10)); + } + + SECTION("SmallArray") + { + SmallArray<EdgeId> edge_list{mesh->numberOfEdges() / 2 + mesh->numberOfEdges() % 2}; + + { + size_t k = 0; + for (EdgeId edge_id = 0; edge_id < mesh->numberOfEdges(); ++(++edge_id), ++k) { + edge_list[k] = edge_id; + } + + REQUIRE(k == edge_list.size()); + } + + SmallArray<double> values = + EdgeIntegrator::integrate(f, GaussLobattoQuadratureDescriptor(4), *mesh, edge_list); + + double error = 0; + for (size_t i = 0; i < edge_list.size(); ++i) { + error += std::abs(int_f_per_edge[edge_list[i]] - values[i]); + } + + REQUIRE(error == Catch::Approx(0).margin(1E-10)); + } + } + } + } + } + } +} diff --git a/tests/test_EmbeddedIDiscreteFunctionMathFunctions.cpp b/tests/test_EmbeddedIDiscreteFunctionMathFunctions.cpp index d41be6566f5bcbc1205c5561abf474f02780b6af..251424f6a7340244b6ac60879cc85653b3115351 100644 --- a/tests/test_EmbeddedIDiscreteFunctionMathFunctions.cpp +++ b/tests/test_EmbeddedIDiscreteFunctionMathFunctions.cpp @@ -109,494 +109,506 @@ TEST_CASE("EmbeddedIDiscreteFunctionMathFunctions", "[scheme]") using Rd = TinyVector<Dimension>; - std::shared_ptr mesh = MeshDataBaseForTests::get().cartesianMesh1D(); - - std::shared_ptr other_mesh = - std::make_shared<Mesh<Connectivity<Dimension>>>(mesh->shared_connectivity(), mesh->xr()); - - CellValue<const Rd> xj = MeshDataManager::instance().getMeshData(*mesh).xj(); - - CellValue<double> values = [=] { - CellValue<double> build_values{mesh->connectivity()}; - parallel_for( - build_values.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 0.2 + std::cos(l2Norm(xj[cell_id])); }); - return build_values; - }(); - - CellValue<double> positive_values = [=] { - CellValue<double> build_values{mesh->connectivity()}; - parallel_for( - build_values.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 2 + std::sin(l2Norm(xj[cell_id])); }); - return build_values; - }(); - - CellValue<double> bounded_values = [=] { - CellValue<double> build_values{mesh->connectivity()}; - parallel_for( - build_values.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 0.9 * std::sin(l2Norm(xj[cell_id])); }); - return build_values; - }(); - - std::shared_ptr p_u = std::make_shared<const DiscreteFunctionP0<Dimension, double>>(mesh, values); - std::shared_ptr p_other_mesh_u = std::make_shared<const DiscreteFunctionP0<Dimension, double>>(other_mesh, values); - std::shared_ptr p_positive_u = std::make_shared<const DiscreteFunctionP0<Dimension, double>>(mesh, positive_values); - std::shared_ptr p_bounded_u = std::make_shared<const DiscreteFunctionP0<Dimension, double>>(mesh, bounded_values); - - std::shared_ptr p_R1_u = [=] { - CellValue<TinyVector<1>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { uj[cell_id][0] = 2 * xj[cell_id][0] + 1; }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<1>>>(mesh, uj); - }(); - - std::shared_ptr p_R1_v = [=] { - CellValue<TinyVector<1>> vj{mesh->connectivity()}; - parallel_for( - vj.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { vj[cell_id][0] = xj[cell_id][0] * xj[cell_id][0] + 1; }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<1>>>(mesh, vj); - }(); - - std::shared_ptr p_other_mesh_R1_u = - std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<1>>>(other_mesh, p_R1_u->cellValues()); - - constexpr auto to_2d = [&](const TinyVector<Dimension>& x) -> TinyVector<2> { - if constexpr (Dimension == 1) { - return {x[0], 1 + x[0] * x[0]}; - } else if constexpr (Dimension == 2) { - return {x[0], x[1]}; - } else if constexpr (Dimension == 3) { - return {x[0], x[1] + x[2]}; - } - }; - - std::shared_ptr p_R2_u = [=] { - CellValue<TinyVector<2>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<2> x = to_2d(xj[cell_id]); - uj[cell_id] = {2 * x[0] + 1, 1 - x[1]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<2>>>(mesh, uj); - }(); - - std::shared_ptr p_R2_v = [=] { - CellValue<TinyVector<2>> vj{mesh->connectivity()}; - parallel_for( - vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<2> x = to_2d(xj[cell_id]); - vj[cell_id] = {x[0] * x[1] + 1, 2 * x[1]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<2>>>(mesh, vj); - }(); - - std::shared_ptr p_other_mesh_R2_u = - std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<2>>>(other_mesh, p_R2_u->cellValues()); - - constexpr auto to_3d = [&](const TinyVector<Dimension>& x) -> TinyVector<3> { - if constexpr (Dimension == 1) { - return {x[0], 1 + x[0] * x[0], 2 - x[0]}; - } else if constexpr (Dimension == 2) { - return {x[0], x[1], x[0] + x[1]}; - } else if constexpr (Dimension == 3) { - return {x[0], x[1], x[2]}; - } - }; - - std::shared_ptr p_R3_u = [=] { - CellValue<TinyVector<3>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - uj[cell_id] = {2 * x[0] + 1, 1 - x[1] * x[2], x[0] + x[2]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<3>>>(mesh, uj); - }(); - - std::shared_ptr p_R3_v = [=] { - CellValue<TinyVector<3>> vj{mesh->connectivity()}; - parallel_for( - vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - vj[cell_id] = {x[0] * x[1] + 1, 2 * x[1], x[2] * x[0]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<3>>>(mesh, vj); - }(); - - std::shared_ptr p_other_mesh_R3_u = - std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<3>>>(other_mesh, p_R3_u->cellValues()); - - std::shared_ptr p_R1x1_u = [=] { - CellValue<TinyMatrix<1>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { uj[cell_id] = {2 * xj[cell_id][0] + 1}; }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<1>>>(mesh, uj); - }(); - - std::shared_ptr p_R2x2_u = [=] { - CellValue<TinyMatrix<2>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<2> x = to_2d(xj[cell_id]); - - uj[cell_id] = {2 * x[0] + 1, 1 - x[1], // - 2 * x[1], -x[0]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<2>>>(mesh, uj); - }(); - - std::shared_ptr p_R3x3_u = [=] { - CellValue<TinyMatrix<3>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - - uj[cell_id] = {2 * x[0] + 1, 1 - x[1], 3, // - 2 * x[1], -x[0], x[0] - x[1], // - 3 * x[2] - x[1], x[1] - 2 * x[2], x[2] - x[0]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<3>>>(mesh, uj); - }(); - - std::shared_ptr p_Vector3_u = [=] { - CellArray<double> uj_vector{mesh->connectivity(), 3}; - parallel_for( - uj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - uj_vector[cell_id][0] = 2 * x[0] + 1; - uj_vector[cell_id][1] = 1 - x[1] * x[2]; - uj_vector[cell_id][2] = x[0] + x[2]; - }); - - return std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(mesh, uj_vector); - }(); - - std::shared_ptr p_Vector3_v = [=] { - CellArray<double> vj_vector{mesh->connectivity(), 3}; - parallel_for( - vj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - vj_vector[cell_id][0] = x[0] * x[1] + 1; - vj_vector[cell_id][1] = 2 * x[1]; - vj_vector[cell_id][2] = x[2] * x[0]; - }); - - return std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(mesh, vj_vector); - }(); - - std::shared_ptr p_Vector2_w = [=] { - CellArray<double> wj_vector{mesh->connectivity(), 2}; - parallel_for( - wj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - wj_vector[cell_id][0] = x[0] + x[1] * 2; - wj_vector[cell_id][1] = x[0] * x[1]; - }); - - return std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(mesh, wj_vector); - }(); - - SECTION("sqrt Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_positive_u, sqrt); - REQUIRE_THROWS_WITH(sqrt(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } + std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - SECTION("abs Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, abs); - REQUIRE_THROWS_WITH(abs(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh = named_mesh.mesh(); + + std::shared_ptr other_mesh = + std::make_shared<Mesh<Connectivity<Dimension>>>(mesh->shared_connectivity(), mesh->xr()); + + CellValue<const Rd> xj = MeshDataManager::instance().getMeshData(*mesh).xj(); + + CellValue<double> values = [=] { + CellValue<double> build_values{mesh->connectivity()}; + parallel_for( + build_values.numberOfItems(), + PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 0.2 + std::cos(l2Norm(xj[cell_id])); }); + return build_values; + }(); + + CellValue<double> positive_values = [=] { + CellValue<double> build_values{mesh->connectivity()}; + parallel_for( + build_values.numberOfItems(), + PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 2 + std::sin(l2Norm(xj[cell_id])); }); + return build_values; + }(); + + CellValue<double> bounded_values = [=] { + CellValue<double> build_values{mesh->connectivity()}; + parallel_for( + build_values.numberOfItems(), + PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 0.9 * std::sin(l2Norm(xj[cell_id])); }); + return build_values; + }(); + + std::shared_ptr p_u = std::make_shared<const DiscreteFunctionP0<Dimension, double>>(mesh, values); + std::shared_ptr p_other_mesh_u = + std::make_shared<const DiscreteFunctionP0<Dimension, double>>(other_mesh, values); + std::shared_ptr p_positive_u = + std::make_shared<const DiscreteFunctionP0<Dimension, double>>(mesh, positive_values); + std::shared_ptr p_bounded_u = + std::make_shared<const DiscreteFunctionP0<Dimension, double>>(mesh, bounded_values); + + std::shared_ptr p_R1_u = [=] { + CellValue<TinyVector<1>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { uj[cell_id][0] = 2 * xj[cell_id][0] + 1; }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<1>>>(mesh, uj); + }(); + + std::shared_ptr p_R1_v = [=] { + CellValue<TinyVector<1>> vj{mesh->connectivity()}; + parallel_for( + vj.numberOfItems(), + PUGS_LAMBDA(const CellId cell_id) { vj[cell_id][0] = xj[cell_id][0] * xj[cell_id][0] + 1; }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<1>>>(mesh, vj); + }(); + + std::shared_ptr p_other_mesh_R1_u = + std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<1>>>(other_mesh, p_R1_u->cellValues()); + + constexpr auto to_2d = [&](const TinyVector<Dimension>& x) -> TinyVector<2> { + if constexpr (Dimension == 1) { + return {x[0], 1 + x[0] * x[0]}; + } else if constexpr (Dimension == 2) { + return {x[0], x[1]}; + } else if constexpr (Dimension == 3) { + return {x[0], x[1] + x[2]}; + } + }; + + std::shared_ptr p_R2_u = [=] { + CellValue<TinyVector<2>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<2> x = to_2d(xj[cell_id]); + uj[cell_id] = {2 * x[0] + 1, 1 - x[1]}; + }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<2>>>(mesh, uj); + }(); + + std::shared_ptr p_R2_v = [=] { + CellValue<TinyVector<2>> vj{mesh->connectivity()}; + parallel_for( + vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<2> x = to_2d(xj[cell_id]); + vj[cell_id] = {x[0] * x[1] + 1, 2 * x[1]}; + }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<2>>>(mesh, vj); + }(); + + std::shared_ptr p_other_mesh_R2_u = + std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<2>>>(other_mesh, p_R2_u->cellValues()); + + constexpr auto to_3d = [&](const TinyVector<Dimension>& x) -> TinyVector<3> { + if constexpr (Dimension == 1) { + return {x[0], 1 + x[0] * x[0], 2 - x[0]}; + } else if constexpr (Dimension == 2) { + return {x[0], x[1], x[0] + x[1]}; + } else if constexpr (Dimension == 3) { + return {x[0], x[1], x[2]}; + } + }; + + std::shared_ptr p_R3_u = [=] { + CellValue<TinyVector<3>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + uj[cell_id] = {2 * x[0] + 1, 1 - x[1] * x[2], x[0] + x[2]}; + }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<3>>>(mesh, uj); + }(); + + std::shared_ptr p_R3_v = [=] { + CellValue<TinyVector<3>> vj{mesh->connectivity()}; + parallel_for( + vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + vj[cell_id] = {x[0] * x[1] + 1, 2 * x[1], x[2] * x[0]}; + }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<3>>>(mesh, vj); + }(); + + std::shared_ptr p_other_mesh_R3_u = + std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<3>>>(other_mesh, p_R3_u->cellValues()); + + std::shared_ptr p_R1x1_u = [=] { + CellValue<TinyMatrix<1>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { uj[cell_id] = {2 * xj[cell_id][0] + 1}; }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<1>>>(mesh, uj); + }(); + + std::shared_ptr p_R2x2_u = [=] { + CellValue<TinyMatrix<2>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<2> x = to_2d(xj[cell_id]); + + uj[cell_id] = {2 * x[0] + 1, 1 - x[1], // + 2 * x[1], -x[0]}; + }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<2>>>(mesh, uj); + }(); + + std::shared_ptr p_R3x3_u = [=] { + CellValue<TinyMatrix<3>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + + uj[cell_id] = {2 * x[0] + 1, 1 - x[1], 3, // + 2 * x[1], -x[0], x[0] - x[1], // + 3 * x[2] - x[1], x[1] - 2 * x[2], x[2] - x[0]}; + }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<3>>>(mesh, uj); + }(); + + std::shared_ptr p_Vector3_u = [=] { + CellArray<double> uj_vector{mesh->connectivity(), 3}; + parallel_for( + uj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + uj_vector[cell_id][0] = 2 * x[0] + 1; + uj_vector[cell_id][1] = 1 - x[1] * x[2]; + uj_vector[cell_id][2] = x[0] + x[2]; + }); + + return std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(mesh, uj_vector); + }(); + + std::shared_ptr p_Vector3_v = [=] { + CellArray<double> vj_vector{mesh->connectivity(), 3}; + parallel_for( + vj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + vj_vector[cell_id][0] = x[0] * x[1] + 1; + vj_vector[cell_id][1] = 2 * x[1]; + vj_vector[cell_id][2] = x[2] * x[0]; + }); + + return std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(mesh, vj_vector); + }(); + + std::shared_ptr p_Vector2_w = [=] { + CellArray<double> wj_vector{mesh->connectivity(), 2}; + parallel_for( + wj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + wj_vector[cell_id][0] = x[0] + x[1] * 2; + wj_vector[cell_id][1] = x[0] * x[1]; + }); + + return std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(mesh, wj_vector); + }(); + + SECTION("sqrt Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_positive_u, sqrt); + REQUIRE_THROWS_WITH(sqrt(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } - SECTION("sin Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, sin); - REQUIRE_THROWS_WITH(sin(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } + SECTION("abs Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, abs); + REQUIRE_THROWS_WITH(abs(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } - SECTION("cos Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, cos); - REQUIRE_THROWS_WITH(cos(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } + SECTION("sin Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, sin); + REQUIRE_THROWS_WITH(sin(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } - SECTION("tan Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, tan); - REQUIRE_THROWS_WITH(tan(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } + SECTION("cos Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, cos); + REQUIRE_THROWS_WITH(cos(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } - SECTION("asin Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_bounded_u, asin); - REQUIRE_THROWS_WITH(asin(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } + SECTION("tan Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, tan); + REQUIRE_THROWS_WITH(tan(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } - SECTION("acos Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_bounded_u, acos); - REQUIRE_THROWS_WITH(acos(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } + SECTION("asin Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_bounded_u, asin); + REQUIRE_THROWS_WITH(asin(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } - SECTION("atan Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_bounded_u, atan); - REQUIRE_THROWS_WITH(atan(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } + SECTION("acos Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_bounded_u, acos); + REQUIRE_THROWS_WITH(acos(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } - SECTION("sinh Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, sinh); - REQUIRE_THROWS_WITH(sinh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } + SECTION("atan Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_bounded_u, atan); + REQUIRE_THROWS_WITH(atan(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } - SECTION("cosh Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, cosh); - REQUIRE_THROWS_WITH(cosh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } + SECTION("sinh Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, sinh); + REQUIRE_THROWS_WITH(sinh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } - SECTION("tanh Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, tanh); - REQUIRE_THROWS_WITH(tanh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } + SECTION("cosh Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, cosh); + REQUIRE_THROWS_WITH(cosh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } - SECTION("asinh Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_positive_u, asinh); - REQUIRE_THROWS_WITH(asinh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } + SECTION("tanh Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, tanh); + REQUIRE_THROWS_WITH(tanh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } - SECTION("acosh Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_positive_u, acosh); - REQUIRE_THROWS_WITH(acosh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } + SECTION("asinh Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_positive_u, asinh); + REQUIRE_THROWS_WITH(asinh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } - SECTION("atanh Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_bounded_u, atanh); - REQUIRE_THROWS_WITH(atanh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } + SECTION("acosh Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_positive_u, acosh); + REQUIRE_THROWS_WITH(acosh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } - SECTION("exp Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, exp); - REQUIRE_THROWS_WITH(exp(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } + SECTION("atanh Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_bounded_u, atanh); + REQUIRE_THROWS_WITH(atanh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } - SECTION("log Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_positive_u, log); - REQUIRE_THROWS_WITH(log(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } + SECTION("exp Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, exp); + REQUIRE_THROWS_WITH(exp(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } - SECTION("atan2 Vh*Vh -> Vh") - { - CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_positive_u, p_bounded_u, atan2); - REQUIRE_THROWS_WITH(atan2(p_u, p_R1_u), "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(atan2(p_R1_u, p_u), "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R)"); - REQUIRE_THROWS_WITH(atan2(p_u, p_other_mesh_u), "error: operands are defined on different meshes"); - } + SECTION("log Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_positive_u, log); + REQUIRE_THROWS_WITH(log(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } - SECTION("atan2 Vh*R -> Vh") - { - CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_u, 3.6, atan2); - REQUIRE_THROWS_WITH(atan2(p_R1_u, 2.1), "error: incompatible operand types Vh(P0:R^1) and R"); - } + SECTION("atan2 Vh*Vh -> Vh") + { + CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_positive_u, p_bounded_u, atan2); + REQUIRE_THROWS_WITH(atan2(p_u, p_R1_u), "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(atan2(p_R1_u, p_u), "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R)"); + REQUIRE_THROWS_WITH(atan2(p_u, p_other_mesh_u), "error: operands are defined on different meshes"); + } - SECTION("atan2 R*Vh -> Vh") - { - CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION(2.4, p_u, atan2); - REQUIRE_THROWS_WITH(atan2(2.1, p_R1_u), "error: incompatible operand types R and Vh(P0:R^1)"); - } + SECTION("atan2 Vh*R -> Vh") + { + CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_u, 3.6, atan2); + REQUIRE_THROWS_WITH(atan2(p_R1_u, 2.1), "error: incompatible operand types Vh(P0:R^1) and R"); + } - SECTION("min Vh*Vh -> Vh") - { - CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_u, p_bounded_u, min); - REQUIRE_THROWS_WITH(::min(p_u, p_other_mesh_u), "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(::min(p_u, p_R1_u), "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(::min(p_R1_u, p_u), "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R)"); - } + SECTION("atan2 R*Vh -> Vh") + { + CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION(2.4, p_u, atan2); + REQUIRE_THROWS_WITH(atan2(2.1, p_R1_u), "error: incompatible operand types R and Vh(P0:R^1)"); + } - SECTION("min Vh*R -> Vh") - { - CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_u, 1.2, min); - REQUIRE_THROWS_WITH(min(p_R1_u, 2.1), "error: incompatible operand types Vh(P0:R^1) and R"); - } + SECTION("min Vh*Vh -> Vh") + { + CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_u, p_bounded_u, min); + REQUIRE_THROWS_WITH(::min(p_u, p_other_mesh_u), "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(::min(p_u, p_R1_u), "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(::min(p_R1_u, p_u), "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R)"); + } - SECTION("min R*Vh -> Vh") - { - CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION(0.4, p_u, min); - REQUIRE_THROWS_WITH(min(3.1, p_R1_u), "error: incompatible operand types R and Vh(P0:R^1)"); - } + SECTION("min Vh*R -> Vh") + { + CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_u, 1.2, min); + REQUIRE_THROWS_WITH(min(p_R1_u, 2.1), "error: incompatible operand types Vh(P0:R^1) and R"); + } - SECTION("min Vh -> R") - { - REQUIRE(min(std::shared_ptr<const IDiscreteFunction>{p_u}) == min(p_u->cellValues())); - REQUIRE_THROWS_WITH(min(std::shared_ptr<const IDiscreteFunction>{p_R1_u}), - "error: invalid operand type Vh(P0:R^1)"); - } + SECTION("min R*Vh -> Vh") + { + CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION(0.4, p_u, min); + REQUIRE_THROWS_WITH(min(3.1, p_R1_u), "error: incompatible operand types R and Vh(P0:R^1)"); + } - SECTION("max Vh*Vh -> Vh") - { - CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_u, p_bounded_u, max); - REQUIRE_THROWS_WITH(::max(p_u, p_other_mesh_u), "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(::max(p_u, p_R1_u), "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(::max(p_R1_u, p_u), "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R)"); - } + SECTION("min Vh -> R") + { + REQUIRE(min(std::shared_ptr<const IDiscreteFunction>{p_u}) == min(p_u->cellValues())); + REQUIRE_THROWS_WITH(min(std::shared_ptr<const IDiscreteFunction>{p_R1_u}), + "error: invalid operand type Vh(P0:R^1)"); + } - SECTION("max Vh*R -> Vh") - { - CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_u, 1.2, max); - REQUIRE_THROWS_WITH(max(p_R1_u, 2.1), "error: incompatible operand types Vh(P0:R^1) and R"); - } + SECTION("max Vh*Vh -> Vh") + { + CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_u, p_bounded_u, max); + REQUIRE_THROWS_WITH(::max(p_u, p_other_mesh_u), "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(::max(p_u, p_R1_u), "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(::max(p_R1_u, p_u), "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R)"); + } - SECTION("max Vh -> R") - { - REQUIRE(max(std::shared_ptr<const IDiscreteFunction>{p_u}) == max(p_u->cellValues())); - REQUIRE_THROWS_WITH(max(std::shared_ptr<const IDiscreteFunction>{p_R1_u}), - "error: invalid operand type Vh(P0:R^1)"); - } + SECTION("max Vh*R -> Vh") + { + CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_u, 1.2, max); + REQUIRE_THROWS_WITH(max(p_R1_u, 2.1), "error: incompatible operand types Vh(P0:R^1) and R"); + } - SECTION("max R*Vh -> Vh") - { - CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION(0.4, p_u, max); - REQUIRE_THROWS_WITH(max(3.1, p_R1_u), "error: incompatible operand types R and Vh(P0:R^1)"); - } + SECTION("max Vh -> R") + { + REQUIRE(max(std::shared_ptr<const IDiscreteFunction>{p_u}) == max(p_u->cellValues())); + REQUIRE_THROWS_WITH(max(std::shared_ptr<const IDiscreteFunction>{p_R1_u}), + "error: invalid operand type Vh(P0:R^1)"); + } - SECTION("pow Vh*Vh -> Vh") - { - CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_positive_u, p_bounded_u, pow); - REQUIRE_THROWS_WITH(pow(p_u, p_other_mesh_u), "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(pow(p_u, p_R1_u), "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(pow(p_R1_u, p_u), "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R)"); - } + SECTION("max R*Vh -> Vh") + { + CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION(0.4, p_u, max); + REQUIRE_THROWS_WITH(max(3.1, p_R1_u), "error: incompatible operand types R and Vh(P0:R^1)"); + } - SECTION("pow Vh*R -> Vh") - { - CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_positive_u, 3.3, pow); - REQUIRE_THROWS_WITH(pow(p_R1_u, 3.1), "error: incompatible operand types Vh(P0:R^1) and R"); - } + SECTION("pow Vh*Vh -> Vh") + { + CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_positive_u, p_bounded_u, pow); + REQUIRE_THROWS_WITH(pow(p_u, p_other_mesh_u), "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(pow(p_u, p_R1_u), "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(pow(p_R1_u, p_u), "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R)"); + } - SECTION("pow R*Vh -> Vh") - { - CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION(2.1, p_u, pow); - REQUIRE_THROWS_WITH(pow(3.1, p_R1_u), "error: incompatible operand types R and Vh(P0:R^1)"); - } + SECTION("pow Vh*R -> Vh") + { + CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_positive_u, 3.3, pow); + REQUIRE_THROWS_WITH(pow(p_R1_u, 3.1), "error: incompatible operand types Vh(P0:R^1) and R"); + } - SECTION("dot Vh*Vh -> Vh") - { - CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_R1_u, p_R1_v, dot); - CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_R2_u, p_R2_v, dot); - CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_R3_u, p_R3_v, dot); + SECTION("pow R*Vh -> Vh") + { + CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION(2.1, p_u, pow); + REQUIRE_THROWS_WITH(pow(3.1, p_R1_u), "error: incompatible operand types R and Vh(P0:R^1)"); + } - { - auto p_UV = dot(p_Vector3_u, p_Vector3_v); - REQUIRE(p_UV.use_count() == 1); + SECTION("dot Vh*Vh -> Vh") + { + CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_R1_u, p_R1_v, dot); + CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_R2_u, p_R2_v, dot); + CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_R3_u, p_R3_v, dot); - auto UV = dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*p_UV); - auto direct_UV = dot(*p_Vector3_u, *p_Vector3_v); + { + auto p_UV = dot(p_Vector3_u, p_Vector3_v); + REQUIRE(p_UV.use_count() == 1); - bool is_same = true; - for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++cell_id) { - if (UV[cell_id] != direct_UV[cell_id]) { - is_same = false; - break; - } - } + auto UV = dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*p_UV); + auto direct_UV = dot(*p_Vector3_u, *p_Vector3_v); - REQUIRE(is_same); - } + bool is_same = true; + for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++cell_id) { + if (UV[cell_id] != direct_UV[cell_id]) { + is_same = false; + break; + } + } - REQUIRE_THROWS_WITH(dot(p_R1_u, p_other_mesh_R1_u), "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(dot(p_R2_u, p_other_mesh_R2_u), "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(dot(p_R3_u, p_other_mesh_R3_u), "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(dot(p_R1_u, p_R3_u), "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R^3)"); - REQUIRE_THROWS_WITH(dot(p_Vector3_u, p_Vector2_w), "error: operands have different dimension"); - } + REQUIRE(is_same); + } - SECTION("dot Vh*Rd -> Vh") - { - CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_R1_u, (TinyVector<1>{3}), dot); - CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_R2_u, (TinyVector<2>{-6, 2}), dot); - CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_R3_u, (TinyVector<3>{-1, 5, 2}), dot); - REQUIRE_THROWS_WITH(dot(p_R1_u, (TinyVector<2>{-6, 2})), "error: incompatible operand types Vh(P0:R^1) and R^2"); - REQUIRE_THROWS_WITH(dot(p_R2_u, (TinyVector<3>{-1, 5, 2})), - "error: incompatible operand types Vh(P0:R^2) and R^3"); - REQUIRE_THROWS_WITH(dot(p_R3_u, (TinyVector<1>{-1})), "error: incompatible operand types Vh(P0:R^3) and R^1"); - } + REQUIRE_THROWS_WITH(dot(p_R1_u, p_other_mesh_R1_u), "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(dot(p_R2_u, p_other_mesh_R2_u), "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(dot(p_R3_u, p_other_mesh_R3_u), "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(dot(p_R1_u, p_R3_u), "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R^3)"); + REQUIRE_THROWS_WITH(dot(p_Vector3_u, p_Vector2_w), "error: operands have different dimension"); + } - SECTION("dot Rd*Vh -> Vh") - { - CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION((TinyVector<1>{3}), p_R1_u, dot); - CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION((TinyVector<2>{-6, 2}), p_R2_u, dot); - CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION((TinyVector<3>{-1, 5, 2}), p_R3_u, dot); - REQUIRE_THROWS_WITH(dot((TinyVector<2>{-6, 2}), p_R1_u), "error: incompatible operand types R^2 and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(dot((TinyVector<3>{-1, 5, 2}), p_R2_u), - "error: incompatible operand types R^3 and Vh(P0:R^2)"); - REQUIRE_THROWS_WITH(dot((TinyVector<1>{-1}), p_R3_u), "error: incompatible operand types R^1 and Vh(P0:R^3)"); - } + SECTION("dot Vh*Rd -> Vh") + { + CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_R1_u, (TinyVector<1>{3}), dot); + CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_R2_u, (TinyVector<2>{-6, 2}), dot); + CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_R3_u, (TinyVector<3>{-1, 5, 2}), dot); + REQUIRE_THROWS_WITH(dot(p_R1_u, (TinyVector<2>{-6, 2})), + "error: incompatible operand types Vh(P0:R^1) and R^2"); + REQUIRE_THROWS_WITH(dot(p_R2_u, (TinyVector<3>{-1, 5, 2})), + "error: incompatible operand types Vh(P0:R^2) and R^3"); + REQUIRE_THROWS_WITH(dot(p_R3_u, (TinyVector<1>{-1})), "error: incompatible operand types Vh(P0:R^3) and R^1"); + } - SECTION("sum_of_R* Vh -> R*") - { - REQUIRE(sum_of<double>(p_u) == sum(p_u->cellValues())); - REQUIRE(sum_of<TinyVector<1>>(p_R1_u) == sum(p_R1_u->cellValues())); - REQUIRE(sum_of<TinyVector<2>>(p_R2_u) == sum(p_R2_u->cellValues())); - REQUIRE(sum_of<TinyVector<3>>(p_R3_u) == sum(p_R3_u->cellValues())); - REQUIRE(sum_of<TinyMatrix<1>>(p_R1x1_u) == sum(p_R1x1_u->cellValues())); - REQUIRE(sum_of<TinyMatrix<2>>(p_R2x2_u) == sum(p_R2x2_u->cellValues())); - REQUIRE(sum_of<TinyMatrix<3>>(p_R3x3_u) == sum(p_R3x3_u->cellValues())); - - REQUIRE_THROWS_WITH(sum_of<TinyVector<1>>(p_u), "error: invalid operand type Vh(P0:R)"); - REQUIRE_THROWS_WITH(sum_of<double>(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(sum_of<double>(p_R2_u), "error: invalid operand type Vh(P0:R^2)"); - REQUIRE_THROWS_WITH(sum_of<double>(p_R3_u), "error: invalid operand type Vh(P0:R^3)"); - REQUIRE_THROWS_WITH(sum_of<double>(p_R1x1_u), "error: invalid operand type Vh(P0:R^1x1)"); - REQUIRE_THROWS_WITH(sum_of<double>(p_R2x2_u), "error: invalid operand type Vh(P0:R^2x2)"); - REQUIRE_THROWS_WITH(sum_of<double>(p_R3x3_u), "error: invalid operand type Vh(P0:R^3x3)"); - } + SECTION("dot Rd*Vh -> Vh") + { + CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION((TinyVector<1>{3}), p_R1_u, dot); + CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION((TinyVector<2>{-6, 2}), p_R2_u, dot); + CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION((TinyVector<3>{-1, 5, 2}), p_R3_u, dot); + REQUIRE_THROWS_WITH(dot((TinyVector<2>{-6, 2}), p_R1_u), + "error: incompatible operand types R^2 and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(dot((TinyVector<3>{-1, 5, 2}), p_R2_u), + "error: incompatible operand types R^3 and Vh(P0:R^2)"); + REQUIRE_THROWS_WITH(dot((TinyVector<1>{-1}), p_R3_u), "error: incompatible operand types R^1 and Vh(P0:R^3)"); + } - SECTION("integral_of_R* Vh -> R*") - { - auto integrate_locally = [&](const auto& cell_values) { - const auto& Vj = MeshDataManager::instance().getMeshData(*mesh).Vj(); - using DataType = decltype(double{} * cell_values[CellId{0}]); - CellValue<DataType> local_integral{mesh->connectivity()}; - parallel_for( - local_integral.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { local_integral[cell_id] = Vj[cell_id] * cell_values[cell_id]; }); - return local_integral; - }; - - REQUIRE(integral_of<double>(p_u) == sum(integrate_locally(p_u->cellValues()))); - REQUIRE(integral_of<TinyVector<1>>(p_R1_u) == sum(integrate_locally(p_R1_u->cellValues()))); - REQUIRE(integral_of<TinyVector<2>>(p_R2_u) == sum(integrate_locally(p_R2_u->cellValues()))); - REQUIRE(integral_of<TinyVector<3>>(p_R3_u) == sum(integrate_locally(p_R3_u->cellValues()))); - REQUIRE(integral_of<TinyMatrix<1>>(p_R1x1_u) == sum(integrate_locally(p_R1x1_u->cellValues()))); - REQUIRE(integral_of<TinyMatrix<2>>(p_R2x2_u) == sum(integrate_locally(p_R2x2_u->cellValues()))); - REQUIRE(integral_of<TinyMatrix<3>>(p_R3x3_u) == sum(integrate_locally(p_R3x3_u->cellValues()))); - - REQUIRE_THROWS_WITH(integral_of<TinyVector<1>>(p_u), "error: invalid operand type Vh(P0:R)"); - REQUIRE_THROWS_WITH(integral_of<double>(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(integral_of<double>(p_R2_u), "error: invalid operand type Vh(P0:R^2)"); - REQUIRE_THROWS_WITH(integral_of<double>(p_R3_u), "error: invalid operand type Vh(P0:R^3)"); - REQUIRE_THROWS_WITH(integral_of<double>(p_R1x1_u), "error: invalid operand type Vh(P0:R^1x1)"); - REQUIRE_THROWS_WITH(integral_of<double>(p_R2x2_u), "error: invalid operand type Vh(P0:R^2x2)"); - REQUIRE_THROWS_WITH(integral_of<double>(p_R3x3_u), "error: invalid operand type Vh(P0:R^3x3)"); + SECTION("sum_of_R* Vh -> R*") + { + REQUIRE(sum_of<double>(p_u) == sum(p_u->cellValues())); + REQUIRE(sum_of<TinyVector<1>>(p_R1_u) == sum(p_R1_u->cellValues())); + REQUIRE(sum_of<TinyVector<2>>(p_R2_u) == sum(p_R2_u->cellValues())); + REQUIRE(sum_of<TinyVector<3>>(p_R3_u) == sum(p_R3_u->cellValues())); + REQUIRE(sum_of<TinyMatrix<1>>(p_R1x1_u) == sum(p_R1x1_u->cellValues())); + REQUIRE(sum_of<TinyMatrix<2>>(p_R2x2_u) == sum(p_R2x2_u->cellValues())); + REQUIRE(sum_of<TinyMatrix<3>>(p_R3x3_u) == sum(p_R3x3_u->cellValues())); + + REQUIRE_THROWS_WITH(sum_of<TinyVector<1>>(p_u), "error: invalid operand type Vh(P0:R)"); + REQUIRE_THROWS_WITH(sum_of<double>(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(sum_of<double>(p_R2_u), "error: invalid operand type Vh(P0:R^2)"); + REQUIRE_THROWS_WITH(sum_of<double>(p_R3_u), "error: invalid operand type Vh(P0:R^3)"); + REQUIRE_THROWS_WITH(sum_of<double>(p_R1x1_u), "error: invalid operand type Vh(P0:R^1x1)"); + REQUIRE_THROWS_WITH(sum_of<double>(p_R2x2_u), "error: invalid operand type Vh(P0:R^2x2)"); + REQUIRE_THROWS_WITH(sum_of<double>(p_R3x3_u), "error: invalid operand type Vh(P0:R^3x3)"); + } + + SECTION("integral_of_R* Vh -> R*") + { + auto integrate_locally = [&](const auto& cell_values) { + const auto& Vj = MeshDataManager::instance().getMeshData(*mesh).Vj(); + using DataType = decltype(double{} * cell_values[CellId{0}]); + CellValue<DataType> local_integral{mesh->connectivity()}; + parallel_for( + local_integral.numberOfItems(), + PUGS_LAMBDA(const CellId cell_id) { local_integral[cell_id] = Vj[cell_id] * cell_values[cell_id]; }); + return local_integral; + }; + + REQUIRE(integral_of<double>(p_u) == sum(integrate_locally(p_u->cellValues()))); + REQUIRE(integral_of<TinyVector<1>>(p_R1_u) == sum(integrate_locally(p_R1_u->cellValues()))); + REQUIRE(integral_of<TinyVector<2>>(p_R2_u) == sum(integrate_locally(p_R2_u->cellValues()))); + REQUIRE(integral_of<TinyVector<3>>(p_R3_u) == sum(integrate_locally(p_R3_u->cellValues()))); + REQUIRE(integral_of<TinyMatrix<1>>(p_R1x1_u) == sum(integrate_locally(p_R1x1_u->cellValues()))); + REQUIRE(integral_of<TinyMatrix<2>>(p_R2x2_u) == sum(integrate_locally(p_R2x2_u->cellValues()))); + REQUIRE(integral_of<TinyMatrix<3>>(p_R3x3_u) == sum(integrate_locally(p_R3x3_u->cellValues()))); + + REQUIRE_THROWS_WITH(integral_of<TinyVector<1>>(p_u), "error: invalid operand type Vh(P0:R)"); + REQUIRE_THROWS_WITH(integral_of<double>(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(integral_of<double>(p_R2_u), "error: invalid operand type Vh(P0:R^2)"); + REQUIRE_THROWS_WITH(integral_of<double>(p_R3_u), "error: invalid operand type Vh(P0:R^3)"); + REQUIRE_THROWS_WITH(integral_of<double>(p_R1x1_u), "error: invalid operand type Vh(P0:R^1x1)"); + REQUIRE_THROWS_WITH(integral_of<double>(p_R2x2_u), "error: invalid operand type Vh(P0:R^2x2)"); + REQUIRE_THROWS_WITH(integral_of<double>(p_R3x3_u), "error: invalid operand type Vh(P0:R^3x3)"); + } + } } } @@ -606,494 +618,506 @@ TEST_CASE("EmbeddedIDiscreteFunctionMathFunctions", "[scheme]") using Rd = TinyVector<Dimension>; - std::shared_ptr mesh = MeshDataBaseForTests::get().cartesianMesh2D(); - - std::shared_ptr other_mesh = - std::make_shared<Mesh<Connectivity<Dimension>>>(mesh->shared_connectivity(), mesh->xr()); - - CellValue<const Rd> xj = MeshDataManager::instance().getMeshData(*mesh).xj(); - - CellValue<double> values = [=] { - CellValue<double> build_values{mesh->connectivity()}; - parallel_for( - build_values.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 0.2 + std::cos(l2Norm(xj[cell_id])); }); - return build_values; - }(); - - CellValue<double> positive_values = [=] { - CellValue<double> build_values{mesh->connectivity()}; - parallel_for( - build_values.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 2 + std::sin(l2Norm(xj[cell_id])); }); - return build_values; - }(); - - CellValue<double> bounded_values = [=] { - CellValue<double> build_values{mesh->connectivity()}; - parallel_for( - build_values.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 0.9 * std::sin(l2Norm(xj[cell_id])); }); - return build_values; - }(); - - std::shared_ptr p_u = std::make_shared<const DiscreteFunctionP0<Dimension, double>>(mesh, values); - std::shared_ptr p_other_mesh_u = std::make_shared<const DiscreteFunctionP0<Dimension, double>>(other_mesh, values); - std::shared_ptr p_positive_u = std::make_shared<const DiscreteFunctionP0<Dimension, double>>(mesh, positive_values); - std::shared_ptr p_bounded_u = std::make_shared<const DiscreteFunctionP0<Dimension, double>>(mesh, bounded_values); - - std::shared_ptr p_R1_u = [=] { - CellValue<TinyVector<1>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { uj[cell_id][0] = 2 * xj[cell_id][0] + 1; }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<1>>>(mesh, uj); - }(); - - std::shared_ptr p_R1_v = [=] { - CellValue<TinyVector<1>> vj{mesh->connectivity()}; - parallel_for( - vj.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { vj[cell_id][0] = xj[cell_id][0] * xj[cell_id][0] + 1; }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<1>>>(mesh, vj); - }(); - - std::shared_ptr p_other_mesh_R1_u = - std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<1>>>(other_mesh, p_R1_u->cellValues()); - - constexpr auto to_2d = [&](const TinyVector<Dimension>& x) -> TinyVector<2> { - if constexpr (Dimension == 1) { - return {x[0], 1 + x[0] * x[0]}; - } else if constexpr (Dimension == 2) { - return {x[0], x[1]}; - } else if constexpr (Dimension == 3) { - return {x[0], x[1] + x[2]}; - } - }; - - std::shared_ptr p_R2_u = [=] { - CellValue<TinyVector<2>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<2> x = to_2d(xj[cell_id]); - uj[cell_id] = {2 * x[0] + 1, 1 - x[1]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<2>>>(mesh, uj); - }(); - - std::shared_ptr p_R2_v = [=] { - CellValue<TinyVector<2>> vj{mesh->connectivity()}; - parallel_for( - vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<2> x = to_2d(xj[cell_id]); - vj[cell_id] = {x[0] * x[1] + 1, 2 * x[1]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<2>>>(mesh, vj); - }(); - - std::shared_ptr p_other_mesh_R2_u = - std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<2>>>(other_mesh, p_R2_u->cellValues()); - - constexpr auto to_3d = [&](const TinyVector<Dimension>& x) -> TinyVector<3> { - if constexpr (Dimension == 1) { - return {x[0], 1 + x[0] * x[0], 2 - x[0]}; - } else if constexpr (Dimension == 2) { - return {x[0], x[1], x[0] + x[1]}; - } else if constexpr (Dimension == 3) { - return {x[0], x[1], x[2]}; - } - }; - - std::shared_ptr p_R3_u = [=] { - CellValue<TinyVector<3>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - uj[cell_id] = {2 * x[0] + 1, 1 - x[1] * x[2], x[0] + x[2]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<3>>>(mesh, uj); - }(); - - std::shared_ptr p_R3_v = [=] { - CellValue<TinyVector<3>> vj{mesh->connectivity()}; - parallel_for( - vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - vj[cell_id] = {x[0] * x[1] + 1, 2 * x[1], x[2] * x[0]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<3>>>(mesh, vj); - }(); - - std::shared_ptr p_other_mesh_R3_u = - std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<3>>>(other_mesh, p_R3_u->cellValues()); - - std::shared_ptr p_R1x1_u = [=] { - CellValue<TinyMatrix<1>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { uj[cell_id] = {2 * xj[cell_id][0] + 1}; }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<1>>>(mesh, uj); - }(); - - std::shared_ptr p_R2x2_u = [=] { - CellValue<TinyMatrix<2>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<2> x = to_2d(xj[cell_id]); - - uj[cell_id] = {2 * x[0] + 1, 1 - x[1], // - 2 * x[1], -x[0]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<2>>>(mesh, uj); - }(); - - std::shared_ptr p_R3x3_u = [=] { - CellValue<TinyMatrix<3>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - - uj[cell_id] = {2 * x[0] + 1, 1 - x[1], 3, // - 2 * x[1], -x[0], x[0] - x[1], // - 3 * x[2] - x[1], x[1] - 2 * x[2], x[2] - x[0]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<3>>>(mesh, uj); - }(); - - std::shared_ptr p_Vector3_u = [=] { - CellArray<double> uj_vector{mesh->connectivity(), 3}; - parallel_for( - uj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - uj_vector[cell_id][0] = 2 * x[0] + 1; - uj_vector[cell_id][1] = 1 - x[1] * x[2]; - uj_vector[cell_id][2] = x[0] + x[2]; - }); - - return std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(mesh, uj_vector); - }(); - - std::shared_ptr p_Vector3_v = [=] { - CellArray<double> vj_vector{mesh->connectivity(), 3}; - parallel_for( - vj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - vj_vector[cell_id][0] = x[0] * x[1] + 1; - vj_vector[cell_id][1] = 2 * x[1]; - vj_vector[cell_id][2] = x[2] * x[0]; - }); - - return std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(mesh, vj_vector); - }(); - - std::shared_ptr p_Vector2_w = [=] { - CellArray<double> wj_vector{mesh->connectivity(), 2}; - parallel_for( - wj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - wj_vector[cell_id][0] = x[0] + x[1] * 2; - wj_vector[cell_id][1] = x[0] * x[1]; - }); - - return std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(mesh, wj_vector); - }(); - - SECTION("sqrt Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_positive_u, sqrt); - REQUIRE_THROWS_WITH(sqrt(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } + std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - SECTION("abs Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, abs); - REQUIRE_THROWS_WITH(abs(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh = named_mesh.mesh(); + + std::shared_ptr other_mesh = + std::make_shared<Mesh<Connectivity<Dimension>>>(mesh->shared_connectivity(), mesh->xr()); + + CellValue<const Rd> xj = MeshDataManager::instance().getMeshData(*mesh).xj(); + + CellValue<double> values = [=] { + CellValue<double> build_values{mesh->connectivity()}; + parallel_for( + build_values.numberOfItems(), + PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 0.2 + std::cos(l2Norm(xj[cell_id])); }); + return build_values; + }(); + + CellValue<double> positive_values = [=] { + CellValue<double> build_values{mesh->connectivity()}; + parallel_for( + build_values.numberOfItems(), + PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 2 + std::sin(l2Norm(xj[cell_id])); }); + return build_values; + }(); + + CellValue<double> bounded_values = [=] { + CellValue<double> build_values{mesh->connectivity()}; + parallel_for( + build_values.numberOfItems(), + PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 0.9 * std::sin(l2Norm(xj[cell_id])); }); + return build_values; + }(); + + std::shared_ptr p_u = std::make_shared<const DiscreteFunctionP0<Dimension, double>>(mesh, values); + std::shared_ptr p_other_mesh_u = + std::make_shared<const DiscreteFunctionP0<Dimension, double>>(other_mesh, values); + std::shared_ptr p_positive_u = + std::make_shared<const DiscreteFunctionP0<Dimension, double>>(mesh, positive_values); + std::shared_ptr p_bounded_u = + std::make_shared<const DiscreteFunctionP0<Dimension, double>>(mesh, bounded_values); + + std::shared_ptr p_R1_u = [=] { + CellValue<TinyVector<1>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { uj[cell_id][0] = 2 * xj[cell_id][0] + 1; }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<1>>>(mesh, uj); + }(); + + std::shared_ptr p_R1_v = [=] { + CellValue<TinyVector<1>> vj{mesh->connectivity()}; + parallel_for( + vj.numberOfItems(), + PUGS_LAMBDA(const CellId cell_id) { vj[cell_id][0] = xj[cell_id][0] * xj[cell_id][0] + 1; }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<1>>>(mesh, vj); + }(); + + std::shared_ptr p_other_mesh_R1_u = + std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<1>>>(other_mesh, p_R1_u->cellValues()); + + constexpr auto to_2d = [&](const TinyVector<Dimension>& x) -> TinyVector<2> { + if constexpr (Dimension == 1) { + return {x[0], 1 + x[0] * x[0]}; + } else if constexpr (Dimension == 2) { + return {x[0], x[1]}; + } else if constexpr (Dimension == 3) { + return {x[0], x[1] + x[2]}; + } + }; + + std::shared_ptr p_R2_u = [=] { + CellValue<TinyVector<2>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<2> x = to_2d(xj[cell_id]); + uj[cell_id] = {2 * x[0] + 1, 1 - x[1]}; + }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<2>>>(mesh, uj); + }(); + + std::shared_ptr p_R2_v = [=] { + CellValue<TinyVector<2>> vj{mesh->connectivity()}; + parallel_for( + vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<2> x = to_2d(xj[cell_id]); + vj[cell_id] = {x[0] * x[1] + 1, 2 * x[1]}; + }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<2>>>(mesh, vj); + }(); + + std::shared_ptr p_other_mesh_R2_u = + std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<2>>>(other_mesh, p_R2_u->cellValues()); + + constexpr auto to_3d = [&](const TinyVector<Dimension>& x) -> TinyVector<3> { + if constexpr (Dimension == 1) { + return {x[0], 1 + x[0] * x[0], 2 - x[0]}; + } else if constexpr (Dimension == 2) { + return {x[0], x[1], x[0] + x[1]}; + } else if constexpr (Dimension == 3) { + return {x[0], x[1], x[2]}; + } + }; + + std::shared_ptr p_R3_u = [=] { + CellValue<TinyVector<3>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + uj[cell_id] = {2 * x[0] + 1, 1 - x[1] * x[2], x[0] + x[2]}; + }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<3>>>(mesh, uj); + }(); + + std::shared_ptr p_R3_v = [=] { + CellValue<TinyVector<3>> vj{mesh->connectivity()}; + parallel_for( + vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + vj[cell_id] = {x[0] * x[1] + 1, 2 * x[1], x[2] * x[0]}; + }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<3>>>(mesh, vj); + }(); + + std::shared_ptr p_other_mesh_R3_u = + std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<3>>>(other_mesh, p_R3_u->cellValues()); + + std::shared_ptr p_R1x1_u = [=] { + CellValue<TinyMatrix<1>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { uj[cell_id] = {2 * xj[cell_id][0] + 1}; }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<1>>>(mesh, uj); + }(); + + std::shared_ptr p_R2x2_u = [=] { + CellValue<TinyMatrix<2>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<2> x = to_2d(xj[cell_id]); + + uj[cell_id] = {2 * x[0] + 1, 1 - x[1], // + 2 * x[1], -x[0]}; + }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<2>>>(mesh, uj); + }(); + + std::shared_ptr p_R3x3_u = [=] { + CellValue<TinyMatrix<3>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + + uj[cell_id] = {2 * x[0] + 1, 1 - x[1], 3, // + 2 * x[1], -x[0], x[0] - x[1], // + 3 * x[2] - x[1], x[1] - 2 * x[2], x[2] - x[0]}; + }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<3>>>(mesh, uj); + }(); + + std::shared_ptr p_Vector3_u = [=] { + CellArray<double> uj_vector{mesh->connectivity(), 3}; + parallel_for( + uj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + uj_vector[cell_id][0] = 2 * x[0] + 1; + uj_vector[cell_id][1] = 1 - x[1] * x[2]; + uj_vector[cell_id][2] = x[0] + x[2]; + }); + + return std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(mesh, uj_vector); + }(); + + std::shared_ptr p_Vector3_v = [=] { + CellArray<double> vj_vector{mesh->connectivity(), 3}; + parallel_for( + vj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + vj_vector[cell_id][0] = x[0] * x[1] + 1; + vj_vector[cell_id][1] = 2 * x[1]; + vj_vector[cell_id][2] = x[2] * x[0]; + }); + + return std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(mesh, vj_vector); + }(); + + std::shared_ptr p_Vector2_w = [=] { + CellArray<double> wj_vector{mesh->connectivity(), 2}; + parallel_for( + wj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + wj_vector[cell_id][0] = x[0] + x[1] * 2; + wj_vector[cell_id][1] = x[0] * x[1]; + }); + + return std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(mesh, wj_vector); + }(); + + SECTION("sqrt Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_positive_u, sqrt); + REQUIRE_THROWS_WITH(sqrt(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } - SECTION("sin Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, sin); - REQUIRE_THROWS_WITH(sin(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } + SECTION("abs Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, abs); + REQUIRE_THROWS_WITH(abs(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } - SECTION("cos Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, cos); - REQUIRE_THROWS_WITH(cos(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } + SECTION("sin Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, sin); + REQUIRE_THROWS_WITH(sin(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } - SECTION("tan Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, tan); - REQUIRE_THROWS_WITH(tan(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } + SECTION("cos Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, cos); + REQUIRE_THROWS_WITH(cos(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } - SECTION("asin Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_bounded_u, asin); - REQUIRE_THROWS_WITH(asin(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } + SECTION("tan Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, tan); + REQUIRE_THROWS_WITH(tan(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } - SECTION("acos Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_bounded_u, acos); - REQUIRE_THROWS_WITH(acos(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } + SECTION("asin Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_bounded_u, asin); + REQUIRE_THROWS_WITH(asin(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } - SECTION("atan Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_bounded_u, atan); - REQUIRE_THROWS_WITH(atan(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } + SECTION("acos Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_bounded_u, acos); + REQUIRE_THROWS_WITH(acos(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } - SECTION("sinh Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, sinh); - REQUIRE_THROWS_WITH(sinh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } + SECTION("atan Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_bounded_u, atan); + REQUIRE_THROWS_WITH(atan(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } - SECTION("cosh Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, cosh); - REQUIRE_THROWS_WITH(cosh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } + SECTION("sinh Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, sinh); + REQUIRE_THROWS_WITH(sinh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } - SECTION("tanh Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, tanh); - REQUIRE_THROWS_WITH(tanh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } + SECTION("cosh Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, cosh); + REQUIRE_THROWS_WITH(cosh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } - SECTION("asinh Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_positive_u, asinh); - REQUIRE_THROWS_WITH(asinh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } + SECTION("tanh Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, tanh); + REQUIRE_THROWS_WITH(tanh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } - SECTION("acosh Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_positive_u, acosh); - REQUIRE_THROWS_WITH(acosh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } + SECTION("asinh Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_positive_u, asinh); + REQUIRE_THROWS_WITH(asinh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } - SECTION("atanh Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_bounded_u, atanh); - REQUIRE_THROWS_WITH(atanh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } + SECTION("acosh Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_positive_u, acosh); + REQUIRE_THROWS_WITH(acosh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } - SECTION("exp Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, exp); - REQUIRE_THROWS_WITH(exp(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } + SECTION("atanh Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_bounded_u, atanh); + REQUIRE_THROWS_WITH(atanh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } - SECTION("log Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_positive_u, log); - REQUIRE_THROWS_WITH(log(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } + SECTION("exp Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, exp); + REQUIRE_THROWS_WITH(exp(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } - SECTION("atan2 Vh*Vh -> Vh") - { - CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_positive_u, p_bounded_u, atan2); - REQUIRE_THROWS_WITH(atan2(p_u, p_R1_u), "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(atan2(p_R1_u, p_u), "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R)"); - REQUIRE_THROWS_WITH(atan2(p_u, p_other_mesh_u), "error: operands are defined on different meshes"); - } + SECTION("log Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_positive_u, log); + REQUIRE_THROWS_WITH(log(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } - SECTION("atan2 Vh*R -> Vh") - { - CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_u, 3.6, atan2); - REQUIRE_THROWS_WITH(atan2(p_R1_u, 2.1), "error: incompatible operand types Vh(P0:R^1) and R"); - } + SECTION("atan2 Vh*Vh -> Vh") + { + CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_positive_u, p_bounded_u, atan2); + REQUIRE_THROWS_WITH(atan2(p_u, p_R1_u), "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(atan2(p_R1_u, p_u), "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R)"); + REQUIRE_THROWS_WITH(atan2(p_u, p_other_mesh_u), "error: operands are defined on different meshes"); + } - SECTION("atan2 R*Vh -> Vh") - { - CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION(2.4, p_u, atan2); - REQUIRE_THROWS_WITH(atan2(2.1, p_R1_u), "error: incompatible operand types R and Vh(P0:R^1)"); - } + SECTION("atan2 Vh*R -> Vh") + { + CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_u, 3.6, atan2); + REQUIRE_THROWS_WITH(atan2(p_R1_u, 2.1), "error: incompatible operand types Vh(P0:R^1) and R"); + } - SECTION("min Vh*Vh -> Vh") - { - CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_u, p_bounded_u, min); - REQUIRE_THROWS_WITH(::min(p_u, p_other_mesh_u), "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(::min(p_u, p_R1_u), "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(::min(p_R1_u, p_u), "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R)"); - } + SECTION("atan2 R*Vh -> Vh") + { + CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION(2.4, p_u, atan2); + REQUIRE_THROWS_WITH(atan2(2.1, p_R1_u), "error: incompatible operand types R and Vh(P0:R^1)"); + } - SECTION("min Vh*R -> Vh") - { - CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_u, 1.2, min); - REQUIRE_THROWS_WITH(min(p_R1_u, 2.1), "error: incompatible operand types Vh(P0:R^1) and R"); - } + SECTION("min Vh*Vh -> Vh") + { + CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_u, p_bounded_u, min); + REQUIRE_THROWS_WITH(::min(p_u, p_other_mesh_u), "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(::min(p_u, p_R1_u), "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(::min(p_R1_u, p_u), "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R)"); + } - SECTION("min R*Vh -> Vh") - { - CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION(0.4, p_u, min); - REQUIRE_THROWS_WITH(min(3.1, p_R1_u), "error: incompatible operand types R and Vh(P0:R^1)"); - } + SECTION("min Vh*R -> Vh") + { + CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_u, 1.2, min); + REQUIRE_THROWS_WITH(min(p_R1_u, 2.1), "error: incompatible operand types Vh(P0:R^1) and R"); + } - SECTION("min Vh -> R") - { - REQUIRE(min(std::shared_ptr<const IDiscreteFunction>{p_u}) == min(p_u->cellValues())); - REQUIRE_THROWS_WITH(min(std::shared_ptr<const IDiscreteFunction>{p_R1_u}), - "error: invalid operand type Vh(P0:R^1)"); - } + SECTION("min R*Vh -> Vh") + { + CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION(0.4, p_u, min); + REQUIRE_THROWS_WITH(min(3.1, p_R1_u), "error: incompatible operand types R and Vh(P0:R^1)"); + } - SECTION("max Vh*Vh -> Vh") - { - CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_u, p_bounded_u, max); - REQUIRE_THROWS_WITH(::max(p_u, p_other_mesh_u), "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(::max(p_u, p_R1_u), "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(::max(p_R1_u, p_u), "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R)"); - } + SECTION("min Vh -> R") + { + REQUIRE(min(std::shared_ptr<const IDiscreteFunction>{p_u}) == min(p_u->cellValues())); + REQUIRE_THROWS_WITH(min(std::shared_ptr<const IDiscreteFunction>{p_R1_u}), + "error: invalid operand type Vh(P0:R^1)"); + } - SECTION("max Vh*R -> Vh") - { - CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_u, 1.2, max); - REQUIRE_THROWS_WITH(max(p_R1_u, 2.1), "error: incompatible operand types Vh(P0:R^1) and R"); - } + SECTION("max Vh*Vh -> Vh") + { + CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_u, p_bounded_u, max); + REQUIRE_THROWS_WITH(::max(p_u, p_other_mesh_u), "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(::max(p_u, p_R1_u), "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(::max(p_R1_u, p_u), "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R)"); + } - SECTION("max Vh -> R") - { - REQUIRE(max(std::shared_ptr<const IDiscreteFunction>{p_u}) == max(p_u->cellValues())); - REQUIRE_THROWS_WITH(max(std::shared_ptr<const IDiscreteFunction>{p_R1_u}), - "error: invalid operand type Vh(P0:R^1)"); - } + SECTION("max Vh*R -> Vh") + { + CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_u, 1.2, max); + REQUIRE_THROWS_WITH(max(p_R1_u, 2.1), "error: incompatible operand types Vh(P0:R^1) and R"); + } - SECTION("max R*Vh -> Vh") - { - CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION(0.4, p_u, max); - REQUIRE_THROWS_WITH(max(3.1, p_R1_u), "error: incompatible operand types R and Vh(P0:R^1)"); - } + SECTION("max Vh -> R") + { + REQUIRE(max(std::shared_ptr<const IDiscreteFunction>{p_u}) == max(p_u->cellValues())); + REQUIRE_THROWS_WITH(max(std::shared_ptr<const IDiscreteFunction>{p_R1_u}), + "error: invalid operand type Vh(P0:R^1)"); + } - SECTION("pow Vh*Vh -> Vh") - { - CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_positive_u, p_bounded_u, pow); - REQUIRE_THROWS_WITH(pow(p_u, p_other_mesh_u), "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(pow(p_u, p_R1_u), "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(pow(p_R1_u, p_u), "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R)"); - } + SECTION("max R*Vh -> Vh") + { + CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION(0.4, p_u, max); + REQUIRE_THROWS_WITH(max(3.1, p_R1_u), "error: incompatible operand types R and Vh(P0:R^1)"); + } - SECTION("pow Vh*R -> Vh") - { - CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_positive_u, 3.3, pow); - REQUIRE_THROWS_WITH(pow(p_R1_u, 3.1), "error: incompatible operand types Vh(P0:R^1) and R"); - } + SECTION("pow Vh*Vh -> Vh") + { + CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_positive_u, p_bounded_u, pow); + REQUIRE_THROWS_WITH(pow(p_u, p_other_mesh_u), "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(pow(p_u, p_R1_u), "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(pow(p_R1_u, p_u), "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R)"); + } - SECTION("pow R*Vh -> Vh") - { - CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION(2.1, p_u, pow); - REQUIRE_THROWS_WITH(pow(3.1, p_R1_u), "error: incompatible operand types R and Vh(P0:R^1)"); - } + SECTION("pow Vh*R -> Vh") + { + CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_positive_u, 3.3, pow); + REQUIRE_THROWS_WITH(pow(p_R1_u, 3.1), "error: incompatible operand types Vh(P0:R^1) and R"); + } - SECTION("dot Vh*Vh -> Vh") - { - CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_R1_u, p_R1_v, dot); - CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_R2_u, p_R2_v, dot); - CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_R3_u, p_R3_v, dot); + SECTION("pow R*Vh -> Vh") + { + CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION(2.1, p_u, pow); + REQUIRE_THROWS_WITH(pow(3.1, p_R1_u), "error: incompatible operand types R and Vh(P0:R^1)"); + } - { - auto p_UV = dot(p_Vector3_u, p_Vector3_v); - REQUIRE(p_UV.use_count() == 1); + SECTION("dot Vh*Vh -> Vh") + { + CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_R1_u, p_R1_v, dot); + CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_R2_u, p_R2_v, dot); + CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_R3_u, p_R3_v, dot); - auto UV = dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*p_UV); - auto direct_UV = dot(*p_Vector3_u, *p_Vector3_v); + { + auto p_UV = dot(p_Vector3_u, p_Vector3_v); + REQUIRE(p_UV.use_count() == 1); - bool is_same = true; - for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++cell_id) { - if (UV[cell_id] != direct_UV[cell_id]) { - is_same = false; - break; - } - } + auto UV = dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*p_UV); + auto direct_UV = dot(*p_Vector3_u, *p_Vector3_v); - REQUIRE(is_same); - } + bool is_same = true; + for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++cell_id) { + if (UV[cell_id] != direct_UV[cell_id]) { + is_same = false; + break; + } + } - REQUIRE_THROWS_WITH(dot(p_R1_u, p_other_mesh_R1_u), "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(dot(p_R2_u, p_other_mesh_R2_u), "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(dot(p_R3_u, p_other_mesh_R3_u), "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(dot(p_R1_u, p_R3_u), "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R^3)"); - REQUIRE_THROWS_WITH(dot(p_Vector3_u, p_Vector2_w), "error: operands have different dimension"); - } + REQUIRE(is_same); + } - SECTION("dot Vh*Rd -> Vh") - { - CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_R1_u, (TinyVector<1>{3}), dot); - CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_R2_u, (TinyVector<2>{-6, 2}), dot); - CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_R3_u, (TinyVector<3>{-1, 5, 2}), dot); - REQUIRE_THROWS_WITH(dot(p_R1_u, (TinyVector<2>{-6, 2})), "error: incompatible operand types Vh(P0:R^1) and R^2"); - REQUIRE_THROWS_WITH(dot(p_R2_u, (TinyVector<3>{-1, 5, 2})), - "error: incompatible operand types Vh(P0:R^2) and R^3"); - REQUIRE_THROWS_WITH(dot(p_R3_u, (TinyVector<1>{-1})), "error: incompatible operand types Vh(P0:R^3) and R^1"); - } + REQUIRE_THROWS_WITH(dot(p_R1_u, p_other_mesh_R1_u), "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(dot(p_R2_u, p_other_mesh_R2_u), "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(dot(p_R3_u, p_other_mesh_R3_u), "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(dot(p_R1_u, p_R3_u), "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R^3)"); + REQUIRE_THROWS_WITH(dot(p_Vector3_u, p_Vector2_w), "error: operands have different dimension"); + } - SECTION("dot Rd*Vh -> Vh") - { - CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION((TinyVector<1>{3}), p_R1_u, dot); - CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION((TinyVector<2>{-6, 2}), p_R2_u, dot); - CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION((TinyVector<3>{-1, 5, 2}), p_R3_u, dot); - REQUIRE_THROWS_WITH(dot((TinyVector<2>{-6, 2}), p_R1_u), "error: incompatible operand types R^2 and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(dot((TinyVector<3>{-1, 5, 2}), p_R2_u), - "error: incompatible operand types R^3 and Vh(P0:R^2)"); - REQUIRE_THROWS_WITH(dot((TinyVector<1>{-1}), p_R3_u), "error: incompatible operand types R^1 and Vh(P0:R^3)"); - } + SECTION("dot Vh*Rd -> Vh") + { + CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_R1_u, (TinyVector<1>{3}), dot); + CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_R2_u, (TinyVector<2>{-6, 2}), dot); + CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_R3_u, (TinyVector<3>{-1, 5, 2}), dot); + REQUIRE_THROWS_WITH(dot(p_R1_u, (TinyVector<2>{-6, 2})), + "error: incompatible operand types Vh(P0:R^1) and R^2"); + REQUIRE_THROWS_WITH(dot(p_R2_u, (TinyVector<3>{-1, 5, 2})), + "error: incompatible operand types Vh(P0:R^2) and R^3"); + REQUIRE_THROWS_WITH(dot(p_R3_u, (TinyVector<1>{-1})), "error: incompatible operand types Vh(P0:R^3) and R^1"); + } - SECTION("sum_of_R* Vh -> R*") - { - REQUIRE(sum_of<double>(p_u) == sum(p_u->cellValues())); - REQUIRE(sum_of<TinyVector<1>>(p_R1_u) == sum(p_R1_u->cellValues())); - REQUIRE(sum_of<TinyVector<2>>(p_R2_u) == sum(p_R2_u->cellValues())); - REQUIRE(sum_of<TinyVector<3>>(p_R3_u) == sum(p_R3_u->cellValues())); - REQUIRE(sum_of<TinyMatrix<1>>(p_R1x1_u) == sum(p_R1x1_u->cellValues())); - REQUIRE(sum_of<TinyMatrix<2>>(p_R2x2_u) == sum(p_R2x2_u->cellValues())); - REQUIRE(sum_of<TinyMatrix<3>>(p_R3x3_u) == sum(p_R3x3_u->cellValues())); - - REQUIRE_THROWS_WITH(sum_of<TinyVector<1>>(p_u), "error: invalid operand type Vh(P0:R)"); - REQUIRE_THROWS_WITH(sum_of<double>(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(sum_of<double>(p_R2_u), "error: invalid operand type Vh(P0:R^2)"); - REQUIRE_THROWS_WITH(sum_of<double>(p_R3_u), "error: invalid operand type Vh(P0:R^3)"); - REQUIRE_THROWS_WITH(sum_of<double>(p_R1x1_u), "error: invalid operand type Vh(P0:R^1x1)"); - REQUIRE_THROWS_WITH(sum_of<double>(p_R2x2_u), "error: invalid operand type Vh(P0:R^2x2)"); - REQUIRE_THROWS_WITH(sum_of<double>(p_R3x3_u), "error: invalid operand type Vh(P0:R^3x3)"); - } + SECTION("dot Rd*Vh -> Vh") + { + CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION((TinyVector<1>{3}), p_R1_u, dot); + CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION((TinyVector<2>{-6, 2}), p_R2_u, dot); + CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION((TinyVector<3>{-1, 5, 2}), p_R3_u, dot); + REQUIRE_THROWS_WITH(dot((TinyVector<2>{-6, 2}), p_R1_u), + "error: incompatible operand types R^2 and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(dot((TinyVector<3>{-1, 5, 2}), p_R2_u), + "error: incompatible operand types R^3 and Vh(P0:R^2)"); + REQUIRE_THROWS_WITH(dot((TinyVector<1>{-1}), p_R3_u), "error: incompatible operand types R^1 and Vh(P0:R^3)"); + } + + SECTION("sum_of_R* Vh -> R*") + { + REQUIRE(sum_of<double>(p_u) == sum(p_u->cellValues())); + REQUIRE(sum_of<TinyVector<1>>(p_R1_u) == sum(p_R1_u->cellValues())); + REQUIRE(sum_of<TinyVector<2>>(p_R2_u) == sum(p_R2_u->cellValues())); + REQUIRE(sum_of<TinyVector<3>>(p_R3_u) == sum(p_R3_u->cellValues())); + REQUIRE(sum_of<TinyMatrix<1>>(p_R1x1_u) == sum(p_R1x1_u->cellValues())); + REQUIRE(sum_of<TinyMatrix<2>>(p_R2x2_u) == sum(p_R2x2_u->cellValues())); + REQUIRE(sum_of<TinyMatrix<3>>(p_R3x3_u) == sum(p_R3x3_u->cellValues())); + + REQUIRE_THROWS_WITH(sum_of<TinyVector<1>>(p_u), "error: invalid operand type Vh(P0:R)"); + REQUIRE_THROWS_WITH(sum_of<double>(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(sum_of<double>(p_R2_u), "error: invalid operand type Vh(P0:R^2)"); + REQUIRE_THROWS_WITH(sum_of<double>(p_R3_u), "error: invalid operand type Vh(P0:R^3)"); + REQUIRE_THROWS_WITH(sum_of<double>(p_R1x1_u), "error: invalid operand type Vh(P0:R^1x1)"); + REQUIRE_THROWS_WITH(sum_of<double>(p_R2x2_u), "error: invalid operand type Vh(P0:R^2x2)"); + REQUIRE_THROWS_WITH(sum_of<double>(p_R3x3_u), "error: invalid operand type Vh(P0:R^3x3)"); + } - SECTION("integral_of_R* Vh -> R*") - { - auto integrate_locally = [&](const auto& cell_values) { - const auto& Vj = MeshDataManager::instance().getMeshData(*mesh).Vj(); - using DataType = decltype(double{} * cell_values[CellId{0}]); - CellValue<DataType> local_integral{mesh->connectivity()}; - parallel_for( - local_integral.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { local_integral[cell_id] = Vj[cell_id] * cell_values[cell_id]; }); - return local_integral; - }; - - REQUIRE(integral_of<double>(p_u) == sum(integrate_locally(p_u->cellValues()))); - REQUIRE(integral_of<TinyVector<1>>(p_R1_u) == sum(integrate_locally(p_R1_u->cellValues()))); - REQUIRE(integral_of<TinyVector<2>>(p_R2_u) == sum(integrate_locally(p_R2_u->cellValues()))); - REQUIRE(integral_of<TinyVector<3>>(p_R3_u) == sum(integrate_locally(p_R3_u->cellValues()))); - REQUIRE(integral_of<TinyMatrix<1>>(p_R1x1_u) == sum(integrate_locally(p_R1x1_u->cellValues()))); - REQUIRE(integral_of<TinyMatrix<2>>(p_R2x2_u) == sum(integrate_locally(p_R2x2_u->cellValues()))); - REQUIRE(integral_of<TinyMatrix<3>>(p_R3x3_u) == sum(integrate_locally(p_R3x3_u->cellValues()))); - - REQUIRE_THROWS_WITH(integral_of<TinyVector<1>>(p_u), "error: invalid operand type Vh(P0:R)"); - REQUIRE_THROWS_WITH(integral_of<double>(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(integral_of<double>(p_R2_u), "error: invalid operand type Vh(P0:R^2)"); - REQUIRE_THROWS_WITH(integral_of<double>(p_R3_u), "error: invalid operand type Vh(P0:R^3)"); - REQUIRE_THROWS_WITH(integral_of<double>(p_R1x1_u), "error: invalid operand type Vh(P0:R^1x1)"); - REQUIRE_THROWS_WITH(integral_of<double>(p_R2x2_u), "error: invalid operand type Vh(P0:R^2x2)"); - REQUIRE_THROWS_WITH(integral_of<double>(p_R3x3_u), "error: invalid operand type Vh(P0:R^3x3)"); + SECTION("integral_of_R* Vh -> R*") + { + auto integrate_locally = [&](const auto& cell_values) { + const auto& Vj = MeshDataManager::instance().getMeshData(*mesh).Vj(); + using DataType = decltype(double{} * cell_values[CellId{0}]); + CellValue<DataType> local_integral{mesh->connectivity()}; + parallel_for( + local_integral.numberOfItems(), + PUGS_LAMBDA(const CellId cell_id) { local_integral[cell_id] = Vj[cell_id] * cell_values[cell_id]; }); + return local_integral; + }; + + REQUIRE(integral_of<double>(p_u) == sum(integrate_locally(p_u->cellValues()))); + REQUIRE(integral_of<TinyVector<1>>(p_R1_u) == sum(integrate_locally(p_R1_u->cellValues()))); + REQUIRE(integral_of<TinyVector<2>>(p_R2_u) == sum(integrate_locally(p_R2_u->cellValues()))); + REQUIRE(integral_of<TinyVector<3>>(p_R3_u) == sum(integrate_locally(p_R3_u->cellValues()))); + REQUIRE(integral_of<TinyMatrix<1>>(p_R1x1_u) == sum(integrate_locally(p_R1x1_u->cellValues()))); + REQUIRE(integral_of<TinyMatrix<2>>(p_R2x2_u) == sum(integrate_locally(p_R2x2_u->cellValues()))); + REQUIRE(integral_of<TinyMatrix<3>>(p_R3x3_u) == sum(integrate_locally(p_R3x3_u->cellValues()))); + + REQUIRE_THROWS_WITH(integral_of<TinyVector<1>>(p_u), "error: invalid operand type Vh(P0:R)"); + REQUIRE_THROWS_WITH(integral_of<double>(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(integral_of<double>(p_R2_u), "error: invalid operand type Vh(P0:R^2)"); + REQUIRE_THROWS_WITH(integral_of<double>(p_R3_u), "error: invalid operand type Vh(P0:R^3)"); + REQUIRE_THROWS_WITH(integral_of<double>(p_R1x1_u), "error: invalid operand type Vh(P0:R^1x1)"); + REQUIRE_THROWS_WITH(integral_of<double>(p_R2x2_u), "error: invalid operand type Vh(P0:R^2x2)"); + REQUIRE_THROWS_WITH(integral_of<double>(p_R3x3_u), "error: invalid operand type Vh(P0:R^3x3)"); + } + } } } @@ -1103,494 +1127,506 @@ TEST_CASE("EmbeddedIDiscreteFunctionMathFunctions", "[scheme]") using Rd = TinyVector<Dimension>; - std::shared_ptr mesh = MeshDataBaseForTests::get().cartesianMesh3D(); - - std::shared_ptr other_mesh = - std::make_shared<Mesh<Connectivity<Dimension>>>(mesh->shared_connectivity(), mesh->xr()); - - CellValue<const Rd> xj = MeshDataManager::instance().getMeshData(*mesh).xj(); - - CellValue<double> values = [=] { - CellValue<double> build_values{mesh->connectivity()}; - parallel_for( - build_values.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 0.2 + std::cos(l2Norm(xj[cell_id])); }); - return build_values; - }(); - - CellValue<double> positive_values = [=] { - CellValue<double> build_values{mesh->connectivity()}; - parallel_for( - build_values.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 2 + std::sin(l2Norm(xj[cell_id])); }); - return build_values; - }(); - - CellValue<double> bounded_values = [=] { - CellValue<double> build_values{mesh->connectivity()}; - parallel_for( - build_values.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 0.9 * std::sin(l2Norm(xj[cell_id])); }); - return build_values; - }(); - - std::shared_ptr p_u = std::make_shared<const DiscreteFunctionP0<Dimension, double>>(mesh, values); - std::shared_ptr p_other_mesh_u = std::make_shared<const DiscreteFunctionP0<Dimension, double>>(other_mesh, values); - std::shared_ptr p_positive_u = std::make_shared<const DiscreteFunctionP0<Dimension, double>>(mesh, positive_values); - std::shared_ptr p_bounded_u = std::make_shared<const DiscreteFunctionP0<Dimension, double>>(mesh, bounded_values); - - std::shared_ptr p_R1_u = [=] { - CellValue<TinyVector<1>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { uj[cell_id][0] = 2 * xj[cell_id][0] + 1; }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<1>>>(mesh, uj); - }(); - - std::shared_ptr p_R1_v = [=] { - CellValue<TinyVector<1>> vj{mesh->connectivity()}; - parallel_for( - vj.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { vj[cell_id][0] = xj[cell_id][0] * xj[cell_id][0] + 1; }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<1>>>(mesh, vj); - }(); - - std::shared_ptr p_other_mesh_R1_u = - std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<1>>>(other_mesh, p_R1_u->cellValues()); - - constexpr auto to_2d = [&](const TinyVector<Dimension>& x) -> TinyVector<2> { - if constexpr (Dimension == 1) { - return {x[0], 1 + x[0] * x[0]}; - } else if constexpr (Dimension == 2) { - return {x[0], x[1]}; - } else if constexpr (Dimension == 3) { - return {x[0], x[1] + x[2]}; - } - }; - - std::shared_ptr p_R2_u = [=] { - CellValue<TinyVector<2>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<2> x = to_2d(xj[cell_id]); - uj[cell_id] = {2 * x[0] + 1, 1 - x[1]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<2>>>(mesh, uj); - }(); - - std::shared_ptr p_R2_v = [=] { - CellValue<TinyVector<2>> vj{mesh->connectivity()}; - parallel_for( - vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<2> x = to_2d(xj[cell_id]); - vj[cell_id] = {x[0] * x[1] + 1, 2 * x[1]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<2>>>(mesh, vj); - }(); - - std::shared_ptr p_other_mesh_R2_u = - std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<2>>>(other_mesh, p_R2_u->cellValues()); - - constexpr auto to_3d = [&](const TinyVector<Dimension>& x) -> TinyVector<3> { - if constexpr (Dimension == 1) { - return {x[0], 1 + x[0] * x[0], 2 - x[0]}; - } else if constexpr (Dimension == 2) { - return {x[0], x[1], x[0] + x[1]}; - } else if constexpr (Dimension == 3) { - return {x[0], x[1], x[2]}; - } - }; - - std::shared_ptr p_R3_u = [=] { - CellValue<TinyVector<3>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - uj[cell_id] = {2 * x[0] + 1, 1 - x[1] * x[2], x[0] + x[2]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<3>>>(mesh, uj); - }(); - - std::shared_ptr p_R3_v = [=] { - CellValue<TinyVector<3>> vj{mesh->connectivity()}; - parallel_for( - vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - vj[cell_id] = {x[0] * x[1] + 1, 2 * x[1], x[2] * x[0]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<3>>>(mesh, vj); - }(); - - std::shared_ptr p_other_mesh_R3_u = - std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<3>>>(other_mesh, p_R3_u->cellValues()); - - std::shared_ptr p_R1x1_u = [=] { - CellValue<TinyMatrix<1>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { uj[cell_id] = {2 * xj[cell_id][0] + 1}; }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<1>>>(mesh, uj); - }(); - - std::shared_ptr p_R2x2_u = [=] { - CellValue<TinyMatrix<2>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<2> x = to_2d(xj[cell_id]); - - uj[cell_id] = {2 * x[0] + 1, 1 - x[1], // - 2 * x[1], -x[0]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<2>>>(mesh, uj); - }(); - - std::shared_ptr p_R3x3_u = [=] { - CellValue<TinyMatrix<3>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - - uj[cell_id] = {2 * x[0] + 1, 1 - x[1], 3, // - 2 * x[1], -x[0], x[0] - x[1], // - 3 * x[2] - x[1], x[1] - 2 * x[2], x[2] - x[0]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<3>>>(mesh, uj); - }(); - - std::shared_ptr p_Vector3_u = [=] { - CellArray<double> uj_vector{mesh->connectivity(), 3}; - parallel_for( - uj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - uj_vector[cell_id][0] = 2 * x[0] + 1; - uj_vector[cell_id][1] = 1 - x[1] * x[2]; - uj_vector[cell_id][2] = x[0] + x[2]; - }); - - return std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(mesh, uj_vector); - }(); - - std::shared_ptr p_Vector3_v = [=] { - CellArray<double> vj_vector{mesh->connectivity(), 3}; - parallel_for( - vj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - vj_vector[cell_id][0] = x[0] * x[1] + 1; - vj_vector[cell_id][1] = 2 * x[1]; - vj_vector[cell_id][2] = x[2] * x[0]; - }); - - return std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(mesh, vj_vector); - }(); - - std::shared_ptr p_Vector2_w = [=] { - CellArray<double> wj_vector{mesh->connectivity(), 2}; - parallel_for( - wj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - wj_vector[cell_id][0] = x[0] + x[1] * 2; - wj_vector[cell_id][1] = x[0] * x[1]; - }); - - return std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(mesh, wj_vector); - }(); - - SECTION("sqrt Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_positive_u, sqrt); - REQUIRE_THROWS_WITH(sqrt(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } + std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - SECTION("abs Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, abs); - REQUIRE_THROWS_WITH(abs(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh = named_mesh.mesh(); + + std::shared_ptr other_mesh = + std::make_shared<Mesh<Connectivity<Dimension>>>(mesh->shared_connectivity(), mesh->xr()); + + CellValue<const Rd> xj = MeshDataManager::instance().getMeshData(*mesh).xj(); + + CellValue<double> values = [=] { + CellValue<double> build_values{mesh->connectivity()}; + parallel_for( + build_values.numberOfItems(), + PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 0.2 + std::cos(l2Norm(xj[cell_id])); }); + return build_values; + }(); + + CellValue<double> positive_values = [=] { + CellValue<double> build_values{mesh->connectivity()}; + parallel_for( + build_values.numberOfItems(), + PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 2 + std::sin(l2Norm(xj[cell_id])); }); + return build_values; + }(); + + CellValue<double> bounded_values = [=] { + CellValue<double> build_values{mesh->connectivity()}; + parallel_for( + build_values.numberOfItems(), + PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 0.9 * std::sin(l2Norm(xj[cell_id])); }); + return build_values; + }(); + + std::shared_ptr p_u = std::make_shared<const DiscreteFunctionP0<Dimension, double>>(mesh, values); + std::shared_ptr p_other_mesh_u = + std::make_shared<const DiscreteFunctionP0<Dimension, double>>(other_mesh, values); + std::shared_ptr p_positive_u = + std::make_shared<const DiscreteFunctionP0<Dimension, double>>(mesh, positive_values); + std::shared_ptr p_bounded_u = + std::make_shared<const DiscreteFunctionP0<Dimension, double>>(mesh, bounded_values); + + std::shared_ptr p_R1_u = [=] { + CellValue<TinyVector<1>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { uj[cell_id][0] = 2 * xj[cell_id][0] + 1; }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<1>>>(mesh, uj); + }(); + + std::shared_ptr p_R1_v = [=] { + CellValue<TinyVector<1>> vj{mesh->connectivity()}; + parallel_for( + vj.numberOfItems(), + PUGS_LAMBDA(const CellId cell_id) { vj[cell_id][0] = xj[cell_id][0] * xj[cell_id][0] + 1; }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<1>>>(mesh, vj); + }(); + + std::shared_ptr p_other_mesh_R1_u = + std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<1>>>(other_mesh, p_R1_u->cellValues()); + + constexpr auto to_2d = [&](const TinyVector<Dimension>& x) -> TinyVector<2> { + if constexpr (Dimension == 1) { + return {x[0], 1 + x[0] * x[0]}; + } else if constexpr (Dimension == 2) { + return {x[0], x[1]}; + } else if constexpr (Dimension == 3) { + return {x[0], x[1] + x[2]}; + } + }; + + std::shared_ptr p_R2_u = [=] { + CellValue<TinyVector<2>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<2> x = to_2d(xj[cell_id]); + uj[cell_id] = {2 * x[0] + 1, 1 - x[1]}; + }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<2>>>(mesh, uj); + }(); + + std::shared_ptr p_R2_v = [=] { + CellValue<TinyVector<2>> vj{mesh->connectivity()}; + parallel_for( + vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<2> x = to_2d(xj[cell_id]); + vj[cell_id] = {x[0] * x[1] + 1, 2 * x[1]}; + }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<2>>>(mesh, vj); + }(); + + std::shared_ptr p_other_mesh_R2_u = + std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<2>>>(other_mesh, p_R2_u->cellValues()); + + constexpr auto to_3d = [&](const TinyVector<Dimension>& x) -> TinyVector<3> { + if constexpr (Dimension == 1) { + return {x[0], 1 + x[0] * x[0], 2 - x[0]}; + } else if constexpr (Dimension == 2) { + return {x[0], x[1], x[0] + x[1]}; + } else if constexpr (Dimension == 3) { + return {x[0], x[1], x[2]}; + } + }; + + std::shared_ptr p_R3_u = [=] { + CellValue<TinyVector<3>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + uj[cell_id] = {2 * x[0] + 1, 1 - x[1] * x[2], x[0] + x[2]}; + }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<3>>>(mesh, uj); + }(); + + std::shared_ptr p_R3_v = [=] { + CellValue<TinyVector<3>> vj{mesh->connectivity()}; + parallel_for( + vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + vj[cell_id] = {x[0] * x[1] + 1, 2 * x[1], x[2] * x[0]}; + }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<3>>>(mesh, vj); + }(); + + std::shared_ptr p_other_mesh_R3_u = + std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<3>>>(other_mesh, p_R3_u->cellValues()); + + std::shared_ptr p_R1x1_u = [=] { + CellValue<TinyMatrix<1>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { uj[cell_id] = {2 * xj[cell_id][0] + 1}; }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<1>>>(mesh, uj); + }(); + + std::shared_ptr p_R2x2_u = [=] { + CellValue<TinyMatrix<2>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<2> x = to_2d(xj[cell_id]); + + uj[cell_id] = {2 * x[0] + 1, 1 - x[1], // + 2 * x[1], -x[0]}; + }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<2>>>(mesh, uj); + }(); + + std::shared_ptr p_R3x3_u = [=] { + CellValue<TinyMatrix<3>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + + uj[cell_id] = {2 * x[0] + 1, 1 - x[1], 3, // + 2 * x[1], -x[0], x[0] - x[1], // + 3 * x[2] - x[1], x[1] - 2 * x[2], x[2] - x[0]}; + }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<3>>>(mesh, uj); + }(); + + std::shared_ptr p_Vector3_u = [=] { + CellArray<double> uj_vector{mesh->connectivity(), 3}; + parallel_for( + uj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + uj_vector[cell_id][0] = 2 * x[0] + 1; + uj_vector[cell_id][1] = 1 - x[1] * x[2]; + uj_vector[cell_id][2] = x[0] + x[2]; + }); + + return std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(mesh, uj_vector); + }(); + + std::shared_ptr p_Vector3_v = [=] { + CellArray<double> vj_vector{mesh->connectivity(), 3}; + parallel_for( + vj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + vj_vector[cell_id][0] = x[0] * x[1] + 1; + vj_vector[cell_id][1] = 2 * x[1]; + vj_vector[cell_id][2] = x[2] * x[0]; + }); + + return std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(mesh, vj_vector); + }(); + + std::shared_ptr p_Vector2_w = [=] { + CellArray<double> wj_vector{mesh->connectivity(), 2}; + parallel_for( + wj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + wj_vector[cell_id][0] = x[0] + x[1] * 2; + wj_vector[cell_id][1] = x[0] * x[1]; + }); + + return std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(mesh, wj_vector); + }(); + + SECTION("sqrt Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_positive_u, sqrt); + REQUIRE_THROWS_WITH(sqrt(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } - SECTION("sin Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, sin); - REQUIRE_THROWS_WITH(sin(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } + SECTION("abs Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, abs); + REQUIRE_THROWS_WITH(abs(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } - SECTION("cos Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, cos); - REQUIRE_THROWS_WITH(cos(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } + SECTION("sin Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, sin); + REQUIRE_THROWS_WITH(sin(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } - SECTION("tan Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, tan); - REQUIRE_THROWS_WITH(tan(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } + SECTION("cos Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, cos); + REQUIRE_THROWS_WITH(cos(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } - SECTION("asin Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_bounded_u, asin); - REQUIRE_THROWS_WITH(asin(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } + SECTION("tan Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, tan); + REQUIRE_THROWS_WITH(tan(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } - SECTION("acos Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_bounded_u, acos); - REQUIRE_THROWS_WITH(acos(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } + SECTION("asin Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_bounded_u, asin); + REQUIRE_THROWS_WITH(asin(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } - SECTION("atan Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_bounded_u, atan); - REQUIRE_THROWS_WITH(atan(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } + SECTION("acos Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_bounded_u, acos); + REQUIRE_THROWS_WITH(acos(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } - SECTION("sinh Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, sinh); - REQUIRE_THROWS_WITH(sinh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } + SECTION("atan Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_bounded_u, atan); + REQUIRE_THROWS_WITH(atan(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } - SECTION("cosh Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, cosh); - REQUIRE_THROWS_WITH(cosh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } + SECTION("sinh Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, sinh); + REQUIRE_THROWS_WITH(sinh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } - SECTION("tanh Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, tanh); - REQUIRE_THROWS_WITH(tanh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } + SECTION("cosh Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, cosh); + REQUIRE_THROWS_WITH(cosh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } - SECTION("asinh Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_positive_u, asinh); - REQUIRE_THROWS_WITH(asinh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } + SECTION("tanh Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, tanh); + REQUIRE_THROWS_WITH(tanh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } - SECTION("acosh Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_positive_u, acosh); - REQUIRE_THROWS_WITH(acosh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } + SECTION("asinh Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_positive_u, asinh); + REQUIRE_THROWS_WITH(asinh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } - SECTION("atanh Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_bounded_u, atanh); - REQUIRE_THROWS_WITH(atanh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } + SECTION("acosh Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_positive_u, acosh); + REQUIRE_THROWS_WITH(acosh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } - SECTION("exp Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, exp); - REQUIRE_THROWS_WITH(exp(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } + SECTION("atanh Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_bounded_u, atanh); + REQUIRE_THROWS_WITH(atanh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } - SECTION("log Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_positive_u, log); - REQUIRE_THROWS_WITH(log(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } + SECTION("exp Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, exp); + REQUIRE_THROWS_WITH(exp(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } - SECTION("atan2 Vh*Vh -> Vh") - { - CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_positive_u, p_bounded_u, atan2); - REQUIRE_THROWS_WITH(atan2(p_u, p_R1_u), "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(atan2(p_R1_u, p_u), "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R)"); - REQUIRE_THROWS_WITH(atan2(p_u, p_other_mesh_u), "error: operands are defined on different meshes"); - } + SECTION("log Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_positive_u, log); + REQUIRE_THROWS_WITH(log(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } - SECTION("atan2 Vh*R -> Vh") - { - CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_u, 3.6, atan2); - REQUIRE_THROWS_WITH(atan2(p_R1_u, 2.1), "error: incompatible operand types Vh(P0:R^1) and R"); - } + SECTION("atan2 Vh*Vh -> Vh") + { + CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_positive_u, p_bounded_u, atan2); + REQUIRE_THROWS_WITH(atan2(p_u, p_R1_u), "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(atan2(p_R1_u, p_u), "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R)"); + REQUIRE_THROWS_WITH(atan2(p_u, p_other_mesh_u), "error: operands are defined on different meshes"); + } - SECTION("atan2 R*Vh -> Vh") - { - CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION(2.4, p_u, atan2); - REQUIRE_THROWS_WITH(atan2(2.1, p_R1_u), "error: incompatible operand types R and Vh(P0:R^1)"); - } + SECTION("atan2 Vh*R -> Vh") + { + CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_u, 3.6, atan2); + REQUIRE_THROWS_WITH(atan2(p_R1_u, 2.1), "error: incompatible operand types Vh(P0:R^1) and R"); + } - SECTION("min Vh*Vh -> Vh") - { - CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_u, p_bounded_u, min); - REQUIRE_THROWS_WITH(::min(p_u, p_other_mesh_u), "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(::min(p_u, p_R1_u), "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(::min(p_R1_u, p_u), "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R)"); - } + SECTION("atan2 R*Vh -> Vh") + { + CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION(2.4, p_u, atan2); + REQUIRE_THROWS_WITH(atan2(2.1, p_R1_u), "error: incompatible operand types R and Vh(P0:R^1)"); + } - SECTION("min Vh*R -> Vh") - { - CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_u, 1.2, min); - REQUIRE_THROWS_WITH(min(p_R1_u, 2.1), "error: incompatible operand types Vh(P0:R^1) and R"); - } + SECTION("min Vh*Vh -> Vh") + { + CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_u, p_bounded_u, min); + REQUIRE_THROWS_WITH(::min(p_u, p_other_mesh_u), "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(::min(p_u, p_R1_u), "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(::min(p_R1_u, p_u), "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R)"); + } - SECTION("min R*Vh -> Vh") - { - CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION(0.4, p_u, min); - REQUIRE_THROWS_WITH(min(3.1, p_R1_u), "error: incompatible operand types R and Vh(P0:R^1)"); - } + SECTION("min Vh*R -> Vh") + { + CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_u, 1.2, min); + REQUIRE_THROWS_WITH(min(p_R1_u, 2.1), "error: incompatible operand types Vh(P0:R^1) and R"); + } - SECTION("min Vh -> R") - { - REQUIRE(min(std::shared_ptr<const IDiscreteFunction>{p_u}) == min(p_u->cellValues())); - REQUIRE_THROWS_WITH(min(std::shared_ptr<const IDiscreteFunction>{p_R1_u}), - "error: invalid operand type Vh(P0:R^1)"); - } + SECTION("min R*Vh -> Vh") + { + CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION(0.4, p_u, min); + REQUIRE_THROWS_WITH(min(3.1, p_R1_u), "error: incompatible operand types R and Vh(P0:R^1)"); + } - SECTION("max Vh*Vh -> Vh") - { - CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_u, p_bounded_u, max); - REQUIRE_THROWS_WITH(::max(p_u, p_other_mesh_u), "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(::max(p_u, p_R1_u), "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(::max(p_R1_u, p_u), "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R)"); - } + SECTION("min Vh -> R") + { + REQUIRE(min(std::shared_ptr<const IDiscreteFunction>{p_u}) == min(p_u->cellValues())); + REQUIRE_THROWS_WITH(min(std::shared_ptr<const IDiscreteFunction>{p_R1_u}), + "error: invalid operand type Vh(P0:R^1)"); + } - SECTION("max Vh*R -> Vh") - { - CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_u, 1.2, max); - REQUIRE_THROWS_WITH(max(p_R1_u, 2.1), "error: incompatible operand types Vh(P0:R^1) and R"); - } + SECTION("max Vh*Vh -> Vh") + { + CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_u, p_bounded_u, max); + REQUIRE_THROWS_WITH(::max(p_u, p_other_mesh_u), "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(::max(p_u, p_R1_u), "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(::max(p_R1_u, p_u), "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R)"); + } - SECTION("max Vh -> R") - { - REQUIRE(max(std::shared_ptr<const IDiscreteFunction>{p_u}) == max(p_u->cellValues())); - REQUIRE_THROWS_WITH(max(std::shared_ptr<const IDiscreteFunction>{p_R1_u}), - "error: invalid operand type Vh(P0:R^1)"); - } + SECTION("max Vh*R -> Vh") + { + CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_u, 1.2, max); + REQUIRE_THROWS_WITH(max(p_R1_u, 2.1), "error: incompatible operand types Vh(P0:R^1) and R"); + } - SECTION("max R*Vh -> Vh") - { - CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION(0.4, p_u, max); - REQUIRE_THROWS_WITH(max(3.1, p_R1_u), "error: incompatible operand types R and Vh(P0:R^1)"); - } + SECTION("max Vh -> R") + { + REQUIRE(max(std::shared_ptr<const IDiscreteFunction>{p_u}) == max(p_u->cellValues())); + REQUIRE_THROWS_WITH(max(std::shared_ptr<const IDiscreteFunction>{p_R1_u}), + "error: invalid operand type Vh(P0:R^1)"); + } - SECTION("pow Vh*Vh -> Vh") - { - CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_positive_u, p_bounded_u, pow); - REQUIRE_THROWS_WITH(pow(p_u, p_other_mesh_u), "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(pow(p_u, p_R1_u), "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(pow(p_R1_u, p_u), "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R)"); - } + SECTION("max R*Vh -> Vh") + { + CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION(0.4, p_u, max); + REQUIRE_THROWS_WITH(max(3.1, p_R1_u), "error: incompatible operand types R and Vh(P0:R^1)"); + } - SECTION("pow Vh*R -> Vh") - { - CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_positive_u, 3.3, pow); - REQUIRE_THROWS_WITH(pow(p_R1_u, 3.1), "error: incompatible operand types Vh(P0:R^1) and R"); - } + SECTION("pow Vh*Vh -> Vh") + { + CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_positive_u, p_bounded_u, pow); + REQUIRE_THROWS_WITH(pow(p_u, p_other_mesh_u), "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(pow(p_u, p_R1_u), "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(pow(p_R1_u, p_u), "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R)"); + } - SECTION("pow R*Vh -> Vh") - { - CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION(2.1, p_u, pow); - REQUIRE_THROWS_WITH(pow(3.1, p_R1_u), "error: incompatible operand types R and Vh(P0:R^1)"); - } + SECTION("pow Vh*R -> Vh") + { + CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_positive_u, 3.3, pow); + REQUIRE_THROWS_WITH(pow(p_R1_u, 3.1), "error: incompatible operand types Vh(P0:R^1) and R"); + } - SECTION("dot Vh*Vh -> Vh") - { - CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_R1_u, p_R1_v, dot); - CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_R2_u, p_R2_v, dot); - CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_R3_u, p_R3_v, dot); + SECTION("pow R*Vh -> Vh") + { + CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION(2.1, p_u, pow); + REQUIRE_THROWS_WITH(pow(3.1, p_R1_u), "error: incompatible operand types R and Vh(P0:R^1)"); + } - { - auto p_UV = dot(p_Vector3_u, p_Vector3_v); - REQUIRE(p_UV.use_count() == 1); + SECTION("dot Vh*Vh -> Vh") + { + CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_R1_u, p_R1_v, dot); + CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_R2_u, p_R2_v, dot); + CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_R3_u, p_R3_v, dot); - auto UV = dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*p_UV); - auto direct_UV = dot(*p_Vector3_u, *p_Vector3_v); + { + auto p_UV = dot(p_Vector3_u, p_Vector3_v); + REQUIRE(p_UV.use_count() == 1); - bool is_same = true; - for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++cell_id) { - if (UV[cell_id] != direct_UV[cell_id]) { - is_same = false; - break; - } - } + auto UV = dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*p_UV); + auto direct_UV = dot(*p_Vector3_u, *p_Vector3_v); - REQUIRE(is_same); - } + bool is_same = true; + for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++cell_id) { + if (UV[cell_id] != direct_UV[cell_id]) { + is_same = false; + break; + } + } - REQUIRE_THROWS_WITH(dot(p_R1_u, p_other_mesh_R1_u), "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(dot(p_R2_u, p_other_mesh_R2_u), "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(dot(p_R3_u, p_other_mesh_R3_u), "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(dot(p_R1_u, p_R3_u), "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R^3)"); - REQUIRE_THROWS_WITH(dot(p_Vector3_u, p_Vector2_w), "error: operands have different dimension"); - } + REQUIRE(is_same); + } - SECTION("dot Vh*Rd -> Vh") - { - CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_R1_u, (TinyVector<1>{3}), dot); - CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_R2_u, (TinyVector<2>{-6, 2}), dot); - CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_R3_u, (TinyVector<3>{-1, 5, 2}), dot); - REQUIRE_THROWS_WITH(dot(p_R1_u, (TinyVector<2>{-6, 2})), "error: incompatible operand types Vh(P0:R^1) and R^2"); - REQUIRE_THROWS_WITH(dot(p_R2_u, (TinyVector<3>{-1, 5, 2})), - "error: incompatible operand types Vh(P0:R^2) and R^3"); - REQUIRE_THROWS_WITH(dot(p_R3_u, (TinyVector<1>{-1})), "error: incompatible operand types Vh(P0:R^3) and R^1"); - } + REQUIRE_THROWS_WITH(dot(p_R1_u, p_other_mesh_R1_u), "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(dot(p_R2_u, p_other_mesh_R2_u), "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(dot(p_R3_u, p_other_mesh_R3_u), "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(dot(p_R1_u, p_R3_u), "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R^3)"); + REQUIRE_THROWS_WITH(dot(p_Vector3_u, p_Vector2_w), "error: operands have different dimension"); + } - SECTION("dot Rd*Vh -> Vh") - { - CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION((TinyVector<1>{3}), p_R1_u, dot); - CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION((TinyVector<2>{-6, 2}), p_R2_u, dot); - CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION((TinyVector<3>{-1, 5, 2}), p_R3_u, dot); - REQUIRE_THROWS_WITH(dot((TinyVector<2>{-6, 2}), p_R1_u), "error: incompatible operand types R^2 and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(dot((TinyVector<3>{-1, 5, 2}), p_R2_u), - "error: incompatible operand types R^3 and Vh(P0:R^2)"); - REQUIRE_THROWS_WITH(dot((TinyVector<1>{-1}), p_R3_u), "error: incompatible operand types R^1 and Vh(P0:R^3)"); - } + SECTION("dot Vh*Rd -> Vh") + { + CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_R1_u, (TinyVector<1>{3}), dot); + CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_R2_u, (TinyVector<2>{-6, 2}), dot); + CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_R3_u, (TinyVector<3>{-1, 5, 2}), dot); + REQUIRE_THROWS_WITH(dot(p_R1_u, (TinyVector<2>{-6, 2})), + "error: incompatible operand types Vh(P0:R^1) and R^2"); + REQUIRE_THROWS_WITH(dot(p_R2_u, (TinyVector<3>{-1, 5, 2})), + "error: incompatible operand types Vh(P0:R^2) and R^3"); + REQUIRE_THROWS_WITH(dot(p_R3_u, (TinyVector<1>{-1})), "error: incompatible operand types Vh(P0:R^3) and R^1"); + } - SECTION("sum_of_R* Vh -> R*") - { - REQUIRE(sum_of<double>(p_u) == sum(p_u->cellValues())); - REQUIRE(sum_of<TinyVector<1>>(p_R1_u) == sum(p_R1_u->cellValues())); - REQUIRE(sum_of<TinyVector<2>>(p_R2_u) == sum(p_R2_u->cellValues())); - REQUIRE(sum_of<TinyVector<3>>(p_R3_u) == sum(p_R3_u->cellValues())); - REQUIRE(sum_of<TinyMatrix<1>>(p_R1x1_u) == sum(p_R1x1_u->cellValues())); - REQUIRE(sum_of<TinyMatrix<2>>(p_R2x2_u) == sum(p_R2x2_u->cellValues())); - REQUIRE(sum_of<TinyMatrix<3>>(p_R3x3_u) == sum(p_R3x3_u->cellValues())); - - REQUIRE_THROWS_WITH(sum_of<TinyVector<1>>(p_u), "error: invalid operand type Vh(P0:R)"); - REQUIRE_THROWS_WITH(sum_of<double>(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(sum_of<double>(p_R2_u), "error: invalid operand type Vh(P0:R^2)"); - REQUIRE_THROWS_WITH(sum_of<double>(p_R3_u), "error: invalid operand type Vh(P0:R^3)"); - REQUIRE_THROWS_WITH(sum_of<double>(p_R1x1_u), "error: invalid operand type Vh(P0:R^1x1)"); - REQUIRE_THROWS_WITH(sum_of<double>(p_R2x2_u), "error: invalid operand type Vh(P0:R^2x2)"); - REQUIRE_THROWS_WITH(sum_of<double>(p_R3x3_u), "error: invalid operand type Vh(P0:R^3x3)"); - } + SECTION("dot Rd*Vh -> Vh") + { + CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION((TinyVector<1>{3}), p_R1_u, dot); + CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION((TinyVector<2>{-6, 2}), p_R2_u, dot); + CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION((TinyVector<3>{-1, 5, 2}), p_R3_u, dot); + REQUIRE_THROWS_WITH(dot((TinyVector<2>{-6, 2}), p_R1_u), + "error: incompatible operand types R^2 and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(dot((TinyVector<3>{-1, 5, 2}), p_R2_u), + "error: incompatible operand types R^3 and Vh(P0:R^2)"); + REQUIRE_THROWS_WITH(dot((TinyVector<1>{-1}), p_R3_u), "error: incompatible operand types R^1 and Vh(P0:R^3)"); + } - SECTION("integral_of_R* Vh -> R*") - { - auto integrate_locally = [&](const auto& cell_values) { - const auto& Vj = MeshDataManager::instance().getMeshData(*mesh).Vj(); - using DataType = decltype(double{} * cell_values[CellId{0}]); - CellValue<DataType> local_integral{mesh->connectivity()}; - parallel_for( - local_integral.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { local_integral[cell_id] = Vj[cell_id] * cell_values[cell_id]; }); - return local_integral; - }; - - REQUIRE(integral_of<double>(p_u) == sum(integrate_locally(p_u->cellValues()))); - REQUIRE(integral_of<TinyVector<1>>(p_R1_u) == sum(integrate_locally(p_R1_u->cellValues()))); - REQUIRE(integral_of<TinyVector<2>>(p_R2_u) == sum(integrate_locally(p_R2_u->cellValues()))); - REQUIRE(integral_of<TinyVector<3>>(p_R3_u) == sum(integrate_locally(p_R3_u->cellValues()))); - REQUIRE(integral_of<TinyMatrix<1>>(p_R1x1_u) == sum(integrate_locally(p_R1x1_u->cellValues()))); - REQUIRE(integral_of<TinyMatrix<2>>(p_R2x2_u) == sum(integrate_locally(p_R2x2_u->cellValues()))); - REQUIRE(integral_of<TinyMatrix<3>>(p_R3x3_u) == sum(integrate_locally(p_R3x3_u->cellValues()))); - - REQUIRE_THROWS_WITH(integral_of<TinyVector<1>>(p_u), "error: invalid operand type Vh(P0:R)"); - REQUIRE_THROWS_WITH(integral_of<double>(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(integral_of<double>(p_R2_u), "error: invalid operand type Vh(P0:R^2)"); - REQUIRE_THROWS_WITH(integral_of<double>(p_R3_u), "error: invalid operand type Vh(P0:R^3)"); - REQUIRE_THROWS_WITH(integral_of<double>(p_R1x1_u), "error: invalid operand type Vh(P0:R^1x1)"); - REQUIRE_THROWS_WITH(integral_of<double>(p_R2x2_u), "error: invalid operand type Vh(P0:R^2x2)"); - REQUIRE_THROWS_WITH(integral_of<double>(p_R3x3_u), "error: invalid operand type Vh(P0:R^3x3)"); + SECTION("sum_of_R* Vh -> R*") + { + REQUIRE(sum_of<double>(p_u) == sum(p_u->cellValues())); + REQUIRE(sum_of<TinyVector<1>>(p_R1_u) == sum(p_R1_u->cellValues())); + REQUIRE(sum_of<TinyVector<2>>(p_R2_u) == sum(p_R2_u->cellValues())); + REQUIRE(sum_of<TinyVector<3>>(p_R3_u) == sum(p_R3_u->cellValues())); + REQUIRE(sum_of<TinyMatrix<1>>(p_R1x1_u) == sum(p_R1x1_u->cellValues())); + REQUIRE(sum_of<TinyMatrix<2>>(p_R2x2_u) == sum(p_R2x2_u->cellValues())); + REQUIRE(sum_of<TinyMatrix<3>>(p_R3x3_u) == sum(p_R3x3_u->cellValues())); + + REQUIRE_THROWS_WITH(sum_of<TinyVector<1>>(p_u), "error: invalid operand type Vh(P0:R)"); + REQUIRE_THROWS_WITH(sum_of<double>(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(sum_of<double>(p_R2_u), "error: invalid operand type Vh(P0:R^2)"); + REQUIRE_THROWS_WITH(sum_of<double>(p_R3_u), "error: invalid operand type Vh(P0:R^3)"); + REQUIRE_THROWS_WITH(sum_of<double>(p_R1x1_u), "error: invalid operand type Vh(P0:R^1x1)"); + REQUIRE_THROWS_WITH(sum_of<double>(p_R2x2_u), "error: invalid operand type Vh(P0:R^2x2)"); + REQUIRE_THROWS_WITH(sum_of<double>(p_R3x3_u), "error: invalid operand type Vh(P0:R^3x3)"); + } + + SECTION("integral_of_R* Vh -> R*") + { + auto integrate_locally = [&](const auto& cell_values) { + const auto& Vj = MeshDataManager::instance().getMeshData(*mesh).Vj(); + using DataType = decltype(double{} * cell_values[CellId{0}]); + CellValue<DataType> local_integral{mesh->connectivity()}; + parallel_for( + local_integral.numberOfItems(), + PUGS_LAMBDA(const CellId cell_id) { local_integral[cell_id] = Vj[cell_id] * cell_values[cell_id]; }); + return local_integral; + }; + + REQUIRE(integral_of<double>(p_u) == sum(integrate_locally(p_u->cellValues()))); + REQUIRE(integral_of<TinyVector<1>>(p_R1_u) == sum(integrate_locally(p_R1_u->cellValues()))); + REQUIRE(integral_of<TinyVector<2>>(p_R2_u) == sum(integrate_locally(p_R2_u->cellValues()))); + REQUIRE(integral_of<TinyVector<3>>(p_R3_u) == sum(integrate_locally(p_R3_u->cellValues()))); + REQUIRE(integral_of<TinyMatrix<1>>(p_R1x1_u) == sum(integrate_locally(p_R1x1_u->cellValues()))); + REQUIRE(integral_of<TinyMatrix<2>>(p_R2x2_u) == sum(integrate_locally(p_R2x2_u->cellValues()))); + REQUIRE(integral_of<TinyMatrix<3>>(p_R3x3_u) == sum(integrate_locally(p_R3x3_u->cellValues()))); + + REQUIRE_THROWS_WITH(integral_of<TinyVector<1>>(p_u), "error: invalid operand type Vh(P0:R)"); + REQUIRE_THROWS_WITH(integral_of<double>(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(integral_of<double>(p_R2_u), "error: invalid operand type Vh(P0:R^2)"); + REQUIRE_THROWS_WITH(integral_of<double>(p_R3_u), "error: invalid operand type Vh(P0:R^3)"); + REQUIRE_THROWS_WITH(integral_of<double>(p_R1x1_u), "error: invalid operand type Vh(P0:R^1x1)"); + REQUIRE_THROWS_WITH(integral_of<double>(p_R2x2_u), "error: invalid operand type Vh(P0:R^2x2)"); + REQUIRE_THROWS_WITH(integral_of<double>(p_R3x3_u), "error: invalid operand type Vh(P0:R^3x3)"); + } + } } } } diff --git a/tests/test_EmbeddedIDiscreteFunctionOperators.cpp b/tests/test_EmbeddedIDiscreteFunctionOperators.cpp index 5232e8fe8d05aca29d5d56440071c0718a206627..5d91447d90147537c3428addfea8c2710defed84 100644 --- a/tests/test_EmbeddedIDiscreteFunctionOperators.cpp +++ b/tests/test_EmbeddedIDiscreteFunctionOperators.cpp @@ -185,6 +185,10 @@ REQUIRE(is_same); \ } +#ifdef __clang__ +#pragma clang optimize off +#endif // __clang__ + TEST_CASE("EmbeddedIDiscreteFunctionOperators", "[scheme]") { SECTION("binary operators") @@ -195,668 +199,693 @@ TEST_CASE("EmbeddedIDiscreteFunctionOperators", "[scheme]") using Rd = TinyVector<Dimension>; - std::shared_ptr mesh = MeshDataBaseForTests::get().cartesianMesh1D(); - - std::shared_ptr other_mesh = - std::make_shared<Mesh<Connectivity<Dimension>>>(mesh->shared_connectivity(), mesh->xr()); - - CellValue<const Rd> xj = MeshDataManager::instance().getMeshData(*mesh).xj(); - - CellValue<double> u_R_values = [=] { - CellValue<double> build_values{mesh->connectivity()}; - parallel_for( - build_values.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 0.2 + std::cos(l2Norm(xj[cell_id])); }); - return build_values; - }(); - - CellValue<double> v_R_values = [=] { - CellValue<double> build_values{mesh->connectivity()}; - parallel_for( - build_values.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 0.6 + std::sin(l2Norm(xj[cell_id])); }); - return build_values; - }(); - - std::shared_ptr p_R_u = std::make_shared<const DiscreteFunctionP0<Dimension, double>>(mesh, u_R_values); - std::shared_ptr p_other_mesh_R_u = - std::make_shared<const DiscreteFunctionP0<Dimension, double>>(other_mesh, u_R_values); - std::shared_ptr p_R_v = std::make_shared<const DiscreteFunctionP0<Dimension, double>>(mesh, v_R_values); - - std::shared_ptr p_R1_u = [=] { - CellValue<TinyVector<1>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { uj[cell_id][0] = 2 * xj[cell_id][0] + 1; }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<1>>>(mesh, uj); - }(); - - std::shared_ptr p_R1_v = [=] { - CellValue<TinyVector<1>> vj{mesh->connectivity()}; - parallel_for( - vj.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { vj[cell_id][0] = xj[cell_id][0] * xj[cell_id][0] + 1; }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<1>>>(mesh, vj); - }(); - - std::shared_ptr p_other_mesh_R1_u = - std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<1>>>(other_mesh, p_R1_u->cellValues()); - - constexpr auto to_2d = [&](const TinyVector<Dimension>& x) -> TinyVector<2> { - if constexpr (Dimension == 1) { - return {x[0], 1 + x[0] * x[0]}; - } else if constexpr (Dimension == 2) { - return {x[0], x[1]}; - } else if constexpr (Dimension == 3) { - return {x[0], x[1] + x[2]}; - } - }; - - std::shared_ptr p_R2_u = [=] { - CellValue<TinyVector<2>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<2> x = to_2d(xj[cell_id]); - uj[cell_id] = {2 * x[0] + 1, 1 - x[1]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<2>>>(mesh, uj); - }(); - - std::shared_ptr p_R2_v = [=] { - CellValue<TinyVector<2>> vj{mesh->connectivity()}; - parallel_for( - vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<2> x = to_2d(xj[cell_id]); - vj[cell_id] = {x[0] * x[1] + 1, 2 * x[1]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<2>>>(mesh, vj); - }(); - - std::shared_ptr p_other_mesh_R2_u = - std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<2>>>(other_mesh, p_R2_u->cellValues()); - - constexpr auto to_3d = [&](const TinyVector<Dimension>& x) -> TinyVector<3> { - if constexpr (Dimension == 1) { - return {x[0], 1 + x[0] * x[0], 2 - x[0]}; - } else if constexpr (Dimension == 2) { - return {x[0], x[1], x[0] + x[1]}; - } else if constexpr (Dimension == 3) { - return {x[0], x[1], x[2]}; - } - }; - - std::shared_ptr p_R3_u = [=] { - CellValue<TinyVector<3>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - uj[cell_id] = {2 * x[0] + 1, 1 - x[1] * x[2], x[0] + x[2]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<3>>>(mesh, uj); - }(); - - std::shared_ptr p_R3_v = [=] { - CellValue<TinyVector<3>> vj{mesh->connectivity()}; - parallel_for( - vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - vj[cell_id] = {x[0] * x[1] + 1, 2 * x[1], x[2] * x[0]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<3>>>(mesh, vj); - }(); - - std::shared_ptr p_other_mesh_R3_u = - std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<3>>>(other_mesh, p_R3_u->cellValues()); - - std::shared_ptr p_R1x1_u = [=] { - CellValue<TinyMatrix<1>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { uj[cell_id] = {2 * xj[cell_id][0] + 1}; }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<1>>>(mesh, uj); - }(); - - std::shared_ptr p_other_mesh_R1x1_u = - std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<1>>>(other_mesh, p_R1x1_u->cellValues()); - - std::shared_ptr p_R1x1_v = [=] { - CellValue<TinyMatrix<1>> vj{mesh->connectivity()}; - parallel_for( - vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { vj[cell_id] = {0.3 - xj[cell_id][0]}; }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<1>>>(mesh, vj); - }(); - - std::shared_ptr p_R2x2_u = [=] { - CellValue<TinyMatrix<2>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<2> x = to_2d(xj[cell_id]); - - uj[cell_id] = {2 * x[0] + 1, 1 - x[1], // - 2 * x[1], -x[0]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<2>>>(mesh, uj); - }(); - - std::shared_ptr p_other_mesh_R2x2_u = - std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<2>>>(other_mesh, p_R2x2_u->cellValues()); - - std::shared_ptr p_R2x2_v = [=] { - CellValue<TinyMatrix<2>> vj{mesh->connectivity()}; - parallel_for( - vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<2> x = to_2d(xj[cell_id]); - - vj[cell_id] = {x[0] + 0.3, 1 - x[1] - x[0], // - 2 * x[1] + x[0], x[1] - x[0]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<2>>>(mesh, vj); - }(); - - std::shared_ptr p_R3x3_u = [=] { - CellValue<TinyMatrix<3>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - - uj[cell_id] = {2 * x[0] + 1, 1 - x[1], 3, // - 2 * x[1], -x[0], x[0] - x[1], // - 3 * x[2] - x[1], x[1] - 2 * x[2], x[2] - x[0]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<3>>>(mesh, uj); - }(); - - std::shared_ptr p_other_mesh_R3x3_u = - std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<3>>>(other_mesh, p_R3x3_u->cellValues()); - - std::shared_ptr p_R3x3_v = [=] { - CellValue<TinyMatrix<3>> vj{mesh->connectivity()}; - parallel_for( - vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - - vj[cell_id] = {0.2 * x[0] + 1, 2 + x[1], 3 - x[2], // - 2.3 * x[2], x[1] - x[0], x[2] - x[1], // - 2 * x[2] + x[0], x[1] + 0.2 * x[2], x[2] - 2 * x[0]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<3>>>(mesh, vj); - }(); - - std::shared_ptr p_Vector3_u = [=] { - CellArray<double> uj_vector{mesh->connectivity(), 3}; - parallel_for( - uj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - uj_vector[cell_id][0] = 2 * x[0] + 1; - uj_vector[cell_id][1] = 1 - x[1] * x[2]; - uj_vector[cell_id][2] = x[0] + x[2]; - }); - - return std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(mesh, uj_vector); - }(); - - std::shared_ptr p_other_mesh_Vector3_u = - std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(other_mesh, p_Vector3_u->cellArrays()); - - std::shared_ptr p_Vector3_v = [=] { - CellArray<double> vj_vector{mesh->connectivity(), 3}; - parallel_for( - vj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - vj_vector[cell_id][0] = x[0] * x[1] + 1; - vj_vector[cell_id][1] = 2 * x[1]; - vj_vector[cell_id][2] = x[2] * x[0]; - }); - - return std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(mesh, vj_vector); - }(); - - std::shared_ptr p_Vector2_w = [=] { - CellArray<double> wj_vector{mesh->connectivity(), 2}; - parallel_for( - wj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - wj_vector[cell_id][0] = x[0] + x[1] * 2; - wj_vector[cell_id][1] = x[0] * x[1]; - }); - - return std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(mesh, wj_vector); - }(); - - SECTION("sum") - { - SECTION("Vh + Vh -> Vh") - { - CHECK_SCALAR_VH2_TO_VH(p_R_u, +, p_R_v); - - CHECK_SCALAR_VH2_TO_VH(p_R1_u, +, p_R1_v); - CHECK_SCALAR_VH2_TO_VH(p_R2_u, +, p_R2_v); - CHECK_SCALAR_VH2_TO_VH(p_R3_u, +, p_R3_v); - - CHECK_SCALAR_VH2_TO_VH(p_R1x1_u, +, p_R1x1_v); - CHECK_SCALAR_VH2_TO_VH(p_R2x2_u, +, p_R2x2_v); - CHECK_SCALAR_VH2_TO_VH(p_R3x3_u, +, p_R3x3_v); - - CHECK_VECTOR_VH2_TO_VH(p_Vector3_u, +, p_Vector3_v); - - REQUIRE_THROWS_WITH(p_R_u + p_R1_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(p_R2_u + p_R1_v, "error: incompatible operand types Vh(P0:R^2) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(p_R3_u + p_R1x1_v, "error: incompatible operand types Vh(P0:R^3) and Vh(P0:R^1x1)"); - REQUIRE_THROWS_WITH(p_R_u + p_R2x2_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^2x2)"); - REQUIRE_THROWS_WITH(p_R_u + p_R2x2_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^2x2)"); - REQUIRE_THROWS_WITH(p_Vector3_u + p_R_v, "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R)"); - REQUIRE_THROWS_WITH(p_Vector3_u + p_Vector2_w, "error: Vh(P0Vector:R) spaces have different sizes"); - - REQUIRE_THROWS_WITH(p_R_u + p_other_mesh_R_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R1_u + p_other_mesh_R1_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R2_u + p_other_mesh_R2_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R3_u + p_other_mesh_R3_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R1x1_u + p_other_mesh_R1x1_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R2x2_u + p_other_mesh_R2x2_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R3x3_u + p_other_mesh_R3x3_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_Vector3_u + p_other_mesh_Vector3_u, "error: operands are defined on different meshes"); - } - - SECTION("Vh + X -> Vh") - { - CHECK_SCALAR_VHxX_TO_VH(p_R_u, +, bool{true}); - CHECK_SCALAR_VHxX_TO_VH(p_R_u, +, uint64_t{1}); - CHECK_SCALAR_VHxX_TO_VH(p_R_u, +, int64_t{2}); - CHECK_SCALAR_VHxX_TO_VH(p_R_u, +, double{1.3}); - - CHECK_SCALAR_VHxX_TO_VH(p_R1_u, +, (TinyVector<1>{1.3})); - CHECK_SCALAR_VHxX_TO_VH(p_R2_u, +, (TinyVector<2>{1.2, 2.3})); - CHECK_SCALAR_VHxX_TO_VH(p_R3_u, +, (TinyVector<3>{3.2, 7.1, 5.2})); - - CHECK_SCALAR_VHxX_TO_VH(p_R1x1_u, +, (TinyMatrix<1>{1.3})); - CHECK_SCALAR_VHxX_TO_VH(p_R2x2_u, +, (TinyMatrix<2>{1.2, 2.3, 4.2, 5.1})); - CHECK_SCALAR_VHxX_TO_VH(p_R3x3_u, +, - (TinyMatrix<3>{3.2, 7.1, 5.2, // - 4.7, 2.3, 7.1, // - 9.7, 3.2, 6.8})); - - REQUIRE_THROWS_WITH(p_R_u + (TinyVector<1>{1}), "error: incompatible operand types Vh(P0:R) and R^1"); - REQUIRE_THROWS_WITH(p_R_u + (TinyVector<2>{1, 2}), "error: incompatible operand types Vh(P0:R) and R^2"); - REQUIRE_THROWS_WITH(p_R_u + (TinyVector<3>{2, 3, 2}), "error: incompatible operand types Vh(P0:R) and R^3"); - REQUIRE_THROWS_WITH(p_R_u + (TinyMatrix<1>{2}), "error: incompatible operand types Vh(P0:R) and R^1x1"); - REQUIRE_THROWS_WITH(p_R_u + (TinyMatrix<2>{2, 3, 1, 4}), - "error: incompatible operand types Vh(P0:R) and R^2x2"); - REQUIRE_THROWS_WITH(p_R_u + (TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}), - "error: incompatible operand types Vh(P0:R) and R^3x3"); - - REQUIRE_THROWS_WITH(p_Vector3_u + (double{1}), "error: incompatible operand types Vh(P0Vector:R) and R"); - REQUIRE_THROWS_WITH(p_Vector3_u + (TinyVector<1>{1}), - "error: incompatible operand types Vh(P0Vector:R) and R^1"); - REQUIRE_THROWS_WITH(p_Vector3_u + (TinyVector<2>{1, 2}), - "error: incompatible operand types Vh(P0Vector:R) and R^2"); - } - - SECTION("X + Vh -> Vh") - { - CHECK_SCALAR_XxVH_TO_VH(bool{true}, +, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(uint64_t{1}, +, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(int64_t{2}, +, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(double{1.3}, +, p_R_u); - - CHECK_SCALAR_XxVH_TO_VH((TinyVector<1>{1.3}), +, p_R1_u); - CHECK_SCALAR_XxVH_TO_VH((TinyVector<2>{1.2, 2.3}), +, p_R2_u); - CHECK_SCALAR_XxVH_TO_VH((TinyVector<3>{3.2, 7.1, 5.2}), +, p_R3_u); - - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<1>{1.3}), +, p_R1x1_u); - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<2>{1.2, 2.3, 4.2, 5.1}), +, p_R2x2_u); - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<3>{3.2, 7.1, 5.2, // - 4.7, 2.3, 7.1, // - 9.7, 3.2, 6.8}), - +, p_R3x3_u); - - REQUIRE_THROWS_WITH((TinyVector<1>{1}) + p_R_u, "error: incompatible operand types R^1 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyVector<2>{1, 2}) + p_R_u, "error: incompatible operand types R^2 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyVector<3>{2, 3, 2}) + p_R_u, "error: incompatible operand types R^3 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) + p_R_u, "error: incompatible operand types R^1x1 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) + p_R_u, - "error: incompatible operand types R^2x2 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) + p_R_u, - "error: incompatible operand types R^3x3 and Vh(P0:R)"); - - REQUIRE_THROWS_WITH((double{1}) + p_Vector3_u, "error: incompatible operand types R and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH((TinyVector<1>{1}) + p_Vector3_u, - "error: incompatible operand types R^1 and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH((TinyVector<2>{1, 2}) + p_Vector3_u, - "error: incompatible operand types R^2 and Vh(P0Vector:R)"); - } - } - - SECTION("difference") - { - SECTION("Vh - Vh -> Vh") - { - CHECK_SCALAR_VH2_TO_VH(p_R_u, -, p_R_v); - - CHECK_SCALAR_VH2_TO_VH(p_R1_u, -, p_R1_v); - CHECK_SCALAR_VH2_TO_VH(p_R2_u, -, p_R2_v); - CHECK_SCALAR_VH2_TO_VH(p_R3_u, -, p_R3_v); - - CHECK_SCALAR_VH2_TO_VH(p_R1x1_u, -, p_R1x1_v); - CHECK_SCALAR_VH2_TO_VH(p_R2x2_u, -, p_R2x2_v); - CHECK_SCALAR_VH2_TO_VH(p_R3x3_u, -, p_R3x3_v); - - CHECK_VECTOR_VH2_TO_VH(p_Vector3_u, -, p_Vector3_v); - - REQUIRE_THROWS_WITH(p_R_u - p_R1_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(p_R2_u - p_R1_v, "error: incompatible operand types Vh(P0:R^2) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(p_R3_u - p_R1x1_v, "error: incompatible operand types Vh(P0:R^3) and Vh(P0:R^1x1)"); - REQUIRE_THROWS_WITH(p_R_u - p_R2x2_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^2x2)"); - REQUIRE_THROWS_WITH(p_Vector3_u - p_R_v, "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R)"); - REQUIRE_THROWS_WITH(p_Vector3_u - p_Vector2_w, "error: Vh(P0Vector:R) spaces have different sizes"); - - REQUIRE_THROWS_WITH(p_R_u - p_other_mesh_R_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R1_u - p_other_mesh_R1_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R2_u - p_other_mesh_R2_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R3_u - p_other_mesh_R3_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R1x1_u - p_other_mesh_R1x1_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R2x2_u - p_other_mesh_R2x2_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R3x3_u - p_other_mesh_R3x3_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_Vector3_u - p_other_mesh_Vector3_u, "error: operands are defined on different meshes"); - } + std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - SECTION("Vh - X -> Vh") + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) { - CHECK_SCALAR_VHxX_TO_VH(p_R_u, -, bool{true}); - CHECK_SCALAR_VHxX_TO_VH(p_R_u, -, uint64_t{1}); - CHECK_SCALAR_VHxX_TO_VH(p_R_u, -, int64_t{2}); - CHECK_SCALAR_VHxX_TO_VH(p_R_u, -, double{1.3}); - - CHECK_SCALAR_VHxX_TO_VH(p_R1_u, -, (TinyVector<1>{1.3})); - CHECK_SCALAR_VHxX_TO_VH(p_R2_u, -, (TinyVector<2>{1.2, 2.3})); - CHECK_SCALAR_VHxX_TO_VH(p_R3_u, -, (TinyVector<3>{3.2, 7.1, 5.2})); - - CHECK_SCALAR_VHxX_TO_VH(p_R1x1_u, -, (TinyMatrix<1>{1.3})); - CHECK_SCALAR_VHxX_TO_VH(p_R2x2_u, -, (TinyMatrix<2>{1.2, 2.3, 4.2, 5.1})); - CHECK_SCALAR_VHxX_TO_VH(p_R3x3_u, -, - (TinyMatrix<3>{3.2, 7.1, 5.2, // - 4.7, 2.3, 7.1, // - 9.7, 3.2, 6.8})); - - REQUIRE_THROWS_WITH(p_R_u - (TinyVector<1>{1}), "error: incompatible operand types Vh(P0:R) and R^1"); - REQUIRE_THROWS_WITH(p_R_u - (TinyVector<2>{1, 2}), "error: incompatible operand types Vh(P0:R) and R^2"); - REQUIRE_THROWS_WITH(p_R_u - (TinyVector<3>{2, 3, 2}), "error: incompatible operand types Vh(P0:R) and R^3"); - REQUIRE_THROWS_WITH(p_R_u - (TinyMatrix<1>{2}), "error: incompatible operand types Vh(P0:R) and R^1x1"); - REQUIRE_THROWS_WITH(p_R_u - (TinyMatrix<2>{2, 3, 1, 4}), - "error: incompatible operand types Vh(P0:R) and R^2x2"); - REQUIRE_THROWS_WITH(p_R_u - (TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}), - "error: incompatible operand types Vh(P0:R) and R^3x3"); - - REQUIRE_THROWS_WITH(p_Vector3_u - (double{1}), "error: incompatible operand types Vh(P0Vector:R) and R"); - REQUIRE_THROWS_WITH(p_Vector3_u - (TinyVector<1>{1}), - "error: incompatible operand types Vh(P0Vector:R) and R^1"); - REQUIRE_THROWS_WITH(p_Vector3_u - (TinyVector<2>{1, 2}), - "error: incompatible operand types Vh(P0Vector:R) and R^2"); - } - - SECTION("X - Vh -> Vh") - { - CHECK_SCALAR_XxVH_TO_VH(bool{true}, -, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(uint64_t{1}, -, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(int64_t{2}, -, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(double{1.3}, -, p_R_u); - - CHECK_SCALAR_XxVH_TO_VH((TinyVector<1>{1.3}), -, p_R1_u); - CHECK_SCALAR_XxVH_TO_VH((TinyVector<2>{1.2, 2.3}), -, p_R2_u); - CHECK_SCALAR_XxVH_TO_VH((TinyVector<3>{3.2, 7.1, 5.2}), -, p_R3_u); - - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<1>{1.3}), -, p_R1x1_u); - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<2>{1.2, 2.3, 4.2, 5.1}), -, p_R2x2_u); - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<3>{3.2, 7.1, 5.2, // - 4.7, 2.3, 7.1, // - 9.7, 3.2, 6.8}), - -, p_R3x3_u); - - REQUIRE_THROWS_WITH((TinyVector<1>{1}) - p_R_u, "error: incompatible operand types R^1 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyVector<2>{1, 2}) - p_R_u, "error: incompatible operand types R^2 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyVector<3>{2, 3, 2}) - p_R_u, "error: incompatible operand types R^3 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) - p_R_u, "error: incompatible operand types R^1x1 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) - p_R_u, - "error: incompatible operand types R^2x2 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) - p_R_u, - "error: incompatible operand types R^3x3 and Vh(P0:R)"); - - REQUIRE_THROWS_WITH((double{1}) - p_Vector3_u, "error: incompatible operand types R and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH((TinyVector<1>{1}) - p_Vector3_u, - "error: incompatible operand types R^1 and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH((TinyVector<2>{1, 2}) - p_Vector3_u, - "error: incompatible operand types R^2 and Vh(P0Vector:R)"); - } - } - - SECTION("product") - { - SECTION("Vh * Vh -> Vh") - { - CHECK_SCALAR_VH2_TO_VH(p_R_u, *, p_R_v); - - CHECK_SCALAR_VH2_TO_VH(p_R1x1_u, *, p_R1x1_v); - CHECK_SCALAR_VH2_TO_VH(p_R2x2_u, *, p_R2x2_v); - CHECK_SCALAR_VH2_TO_VH(p_R3x3_u, *, p_R3x3_v); - - CHECK_SCALAR_VH2_TO_VH(p_R_u, *, p_R1_v); - CHECK_SCALAR_VH2_TO_VH(p_R_u, *, p_R2_v); - CHECK_SCALAR_VH2_TO_VH(p_R_u, *, p_R3_v); + auto mesh = named_mesh.mesh(); + + std::shared_ptr other_mesh = + std::make_shared<Mesh<Connectivity<Dimension>>>(mesh->shared_connectivity(), mesh->xr()); + + CellValue<const Rd> xj = MeshDataManager::instance().getMeshData(*mesh).xj(); + + CellValue<double> u_R_values = [=] { + CellValue<double> build_values{mesh->connectivity()}; + parallel_for( + build_values.numberOfItems(), + PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 0.2 + std::cos(l2Norm(xj[cell_id])); }); + return build_values; + }(); + + CellValue<double> v_R_values = [=] { + CellValue<double> build_values{mesh->connectivity()}; + parallel_for( + build_values.numberOfItems(), + PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 0.6 + std::sin(l2Norm(xj[cell_id])); }); + return build_values; + }(); + + std::shared_ptr p_R_u = std::make_shared<const DiscreteFunctionP0<Dimension, double>>(mesh, u_R_values); + std::shared_ptr p_other_mesh_R_u = + std::make_shared<const DiscreteFunctionP0<Dimension, double>>(other_mesh, u_R_values); + std::shared_ptr p_R_v = std::make_shared<const DiscreteFunctionP0<Dimension, double>>(mesh, v_R_values); + + std::shared_ptr p_R1_u = [=] { + CellValue<TinyVector<1>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { uj[cell_id][0] = 2 * xj[cell_id][0] + 1; }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<1>>>(mesh, uj); + }(); + + std::shared_ptr p_R1_v = [=] { + CellValue<TinyVector<1>> vj{mesh->connectivity()}; + parallel_for( + vj.numberOfItems(), + PUGS_LAMBDA(const CellId cell_id) { vj[cell_id][0] = xj[cell_id][0] * xj[cell_id][0] + 1; }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<1>>>(mesh, vj); + }(); + + std::shared_ptr p_other_mesh_R1_u = + std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<1>>>(other_mesh, p_R1_u->cellValues()); + + constexpr auto to_2d = [&](const TinyVector<Dimension>& x) -> TinyVector<2> { + if constexpr (Dimension == 1) { + return {x[0], 1 + x[0] * x[0]}; + } else if constexpr (Dimension == 2) { + return {x[0], x[1]}; + } else if constexpr (Dimension == 3) { + return {x[0], x[1] + x[2]}; + } + }; + + std::shared_ptr p_R2_u = [=] { + CellValue<TinyVector<2>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<2> x = to_2d(xj[cell_id]); + uj[cell_id] = {2 * x[0] + 1, 1 - x[1]}; + }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<2>>>(mesh, uj); + }(); + + std::shared_ptr p_R2_v = [=] { + CellValue<TinyVector<2>> vj{mesh->connectivity()}; + parallel_for( + vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<2> x = to_2d(xj[cell_id]); + vj[cell_id] = {x[0] * x[1] + 1, 2 * x[1]}; + }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<2>>>(mesh, vj); + }(); + + std::shared_ptr p_other_mesh_R2_u = + std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<2>>>(other_mesh, p_R2_u->cellValues()); + + constexpr auto to_3d = [&](const TinyVector<Dimension>& x) -> TinyVector<3> { + if constexpr (Dimension == 1) { + return {x[0], 1 + x[0] * x[0], 2 - x[0]}; + } else if constexpr (Dimension == 2) { + return {x[0], x[1], x[0] + x[1]}; + } else if constexpr (Dimension == 3) { + return {x[0], x[1], x[2]}; + } + }; + + std::shared_ptr p_R3_u = [=] { + CellValue<TinyVector<3>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + uj[cell_id] = {2 * x[0] + 1, 1 - x[1] * x[2], x[0] + x[2]}; + }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<3>>>(mesh, uj); + }(); + + std::shared_ptr p_R3_v = [=] { + CellValue<TinyVector<3>> vj{mesh->connectivity()}; + parallel_for( + vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + vj[cell_id] = {x[0] * x[1] + 1, 2 * x[1], x[2] * x[0]}; + }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<3>>>(mesh, vj); + }(); + + std::shared_ptr p_other_mesh_R3_u = + std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<3>>>(other_mesh, p_R3_u->cellValues()); + + std::shared_ptr p_R1x1_u = [=] { + CellValue<TinyMatrix<1>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { uj[cell_id] = {2 * xj[cell_id][0] + 1}; }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<1>>>(mesh, uj); + }(); + + std::shared_ptr p_other_mesh_R1x1_u = + std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<1>>>(other_mesh, p_R1x1_u->cellValues()); + + std::shared_ptr p_R1x1_v = [=] { + CellValue<TinyMatrix<1>> vj{mesh->connectivity()}; + parallel_for( + vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { vj[cell_id] = {0.3 - xj[cell_id][0]}; }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<1>>>(mesh, vj); + }(); + + std::shared_ptr p_R2x2_u = [=] { + CellValue<TinyMatrix<2>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<2> x = to_2d(xj[cell_id]); + + uj[cell_id] = {2 * x[0] + 1, 1 - x[1], // + 2 * x[1], -x[0]}; + }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<2>>>(mesh, uj); + }(); + + std::shared_ptr p_other_mesh_R2x2_u = + std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<2>>>(other_mesh, p_R2x2_u->cellValues()); + + std::shared_ptr p_R2x2_v = [=] { + CellValue<TinyMatrix<2>> vj{mesh->connectivity()}; + parallel_for( + vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<2> x = to_2d(xj[cell_id]); + + vj[cell_id] = {x[0] + 0.3, 1 - x[1] - x[0], // + 2 * x[1] + x[0], x[1] - x[0]}; + }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<2>>>(mesh, vj); + }(); + + std::shared_ptr p_R3x3_u = [=] { + CellValue<TinyMatrix<3>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + + uj[cell_id] = {2 * x[0] + 1, 1 - x[1], 3, // + 2 * x[1], -x[0], x[0] - x[1], // + 3 * x[2] - x[1], x[1] - 2 * x[2], x[2] - x[0]}; + }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<3>>>(mesh, uj); + }(); + + std::shared_ptr p_other_mesh_R3x3_u = + std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<3>>>(other_mesh, p_R3x3_u->cellValues()); + + std::shared_ptr p_R3x3_v = [=] { + CellValue<TinyMatrix<3>> vj{mesh->connectivity()}; + parallel_for( + vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + + vj[cell_id] = {0.2 * x[0] + 1, 2 + x[1], 3 - x[2], // + 2.3 * x[2], x[1] - x[0], x[2] - x[1], // + 2 * x[2] + x[0], x[1] + 0.2 * x[2], x[2] - 2 * x[0]}; + }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<3>>>(mesh, vj); + }(); + + std::shared_ptr p_Vector3_u = [=] { + CellArray<double> uj_vector{mesh->connectivity(), 3}; + parallel_for( + uj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + uj_vector[cell_id][0] = 2 * x[0] + 1; + uj_vector[cell_id][1] = 1 - x[1] * x[2]; + uj_vector[cell_id][2] = x[0] + x[2]; + }); + + return std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(mesh, uj_vector); + }(); + + std::shared_ptr p_other_mesh_Vector3_u = + std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(other_mesh, p_Vector3_u->cellArrays()); + + std::shared_ptr p_Vector3_v = [=] { + CellArray<double> vj_vector{mesh->connectivity(), 3}; + parallel_for( + vj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + vj_vector[cell_id][0] = x[0] * x[1] + 1; + vj_vector[cell_id][1] = 2 * x[1]; + vj_vector[cell_id][2] = x[2] * x[0]; + }); + + return std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(mesh, vj_vector); + }(); + + std::shared_ptr p_Vector2_w = [=] { + CellArray<double> wj_vector{mesh->connectivity(), 2}; + parallel_for( + wj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + wj_vector[cell_id][0] = x[0] + x[1] * 2; + wj_vector[cell_id][1] = x[0] * x[1]; + }); + + return std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(mesh, wj_vector); + }(); + + SECTION("sum") + { + SECTION("Vh + Vh -> Vh") + { + CHECK_SCALAR_VH2_TO_VH(p_R_u, +, p_R_v); + + CHECK_SCALAR_VH2_TO_VH(p_R1_u, +, p_R1_v); + CHECK_SCALAR_VH2_TO_VH(p_R2_u, +, p_R2_v); + CHECK_SCALAR_VH2_TO_VH(p_R3_u, +, p_R3_v); + + CHECK_SCALAR_VH2_TO_VH(p_R1x1_u, +, p_R1x1_v); + CHECK_SCALAR_VH2_TO_VH(p_R2x2_u, +, p_R2x2_v); + CHECK_SCALAR_VH2_TO_VH(p_R3x3_u, +, p_R3x3_v); + + CHECK_VECTOR_VH2_TO_VH(p_Vector3_u, +, p_Vector3_v); + + REQUIRE_THROWS_WITH(p_R_u + p_R1_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(p_R2_u + p_R1_v, "error: incompatible operand types Vh(P0:R^2) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(p_R3_u + p_R1x1_v, "error: incompatible operand types Vh(P0:R^3) and Vh(P0:R^1x1)"); + REQUIRE_THROWS_WITH(p_R_u + p_R2x2_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^2x2)"); + REQUIRE_THROWS_WITH(p_R_u + p_R2x2_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^2x2)"); + REQUIRE_THROWS_WITH(p_Vector3_u + p_R_v, "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R)"); + REQUIRE_THROWS_WITH(p_Vector3_u + p_Vector2_w, "error: Vh(P0Vector:R) spaces have different sizes"); + + REQUIRE_THROWS_WITH(p_R_u + p_other_mesh_R_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R1_u + p_other_mesh_R1_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R2_u + p_other_mesh_R2_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R3_u + p_other_mesh_R3_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R1x1_u + p_other_mesh_R1x1_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R2x2_u + p_other_mesh_R2x2_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R3x3_u + p_other_mesh_R3x3_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_Vector3_u + p_other_mesh_Vector3_u, + "error: operands are defined on different meshes"); + } - CHECK_SCALAR_VH2_TO_VH(p_R_u, *, p_R1x1_v); - CHECK_SCALAR_VH2_TO_VH(p_R_u, *, p_R2x2_v); - CHECK_SCALAR_VH2_TO_VH(p_R_u, *, p_R3x3_v); + SECTION("Vh + X -> Vh") + { + CHECK_SCALAR_VHxX_TO_VH(p_R_u, +, bool{true}); + CHECK_SCALAR_VHxX_TO_VH(p_R_u, +, uint64_t{1}); + CHECK_SCALAR_VHxX_TO_VH(p_R_u, +, int64_t{2}); + CHECK_SCALAR_VHxX_TO_VH(p_R_u, +, double{1.3}); + + CHECK_SCALAR_VHxX_TO_VH(p_R1_u, +, (TinyVector<1>{1.3})); + CHECK_SCALAR_VHxX_TO_VH(p_R2_u, +, (TinyVector<2>{1.2, 2.3})); + CHECK_SCALAR_VHxX_TO_VH(p_R3_u, +, (TinyVector<3>{3.2, 7.1, 5.2})); + + CHECK_SCALAR_VHxX_TO_VH(p_R1x1_u, +, (TinyMatrix<1>{1.3})); + CHECK_SCALAR_VHxX_TO_VH(p_R2x2_u, +, (TinyMatrix<2>{1.2, 2.3, 4.2, 5.1})); + CHECK_SCALAR_VHxX_TO_VH(p_R3x3_u, +, + (TinyMatrix<3>{3.2, 7.1, 5.2, // + 4.7, 2.3, 7.1, // + 9.7, 3.2, 6.8})); + + REQUIRE_THROWS_WITH(p_R_u + (TinyVector<1>{1}), "error: incompatible operand types Vh(P0:R) and R^1"); + REQUIRE_THROWS_WITH(p_R_u + (TinyVector<2>{1, 2}), "error: incompatible operand types Vh(P0:R) and R^2"); + REQUIRE_THROWS_WITH(p_R_u + (TinyVector<3>{2, 3, 2}), + "error: incompatible operand types Vh(P0:R) and R^3"); + REQUIRE_THROWS_WITH(p_R_u + (TinyMatrix<1>{2}), "error: incompatible operand types Vh(P0:R) and R^1x1"); + REQUIRE_THROWS_WITH(p_R_u + (TinyMatrix<2>{2, 3, 1, 4}), + "error: incompatible operand types Vh(P0:R) and R^2x2"); + REQUIRE_THROWS_WITH(p_R_u + (TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}), + "error: incompatible operand types Vh(P0:R) and R^3x3"); + + REQUIRE_THROWS_WITH(p_Vector3_u + (double{1}), "error: incompatible operand types Vh(P0Vector:R) and R"); + REQUIRE_THROWS_WITH(p_Vector3_u + (TinyVector<1>{1}), + "error: incompatible operand types Vh(P0Vector:R) and R^1"); + REQUIRE_THROWS_WITH(p_Vector3_u + (TinyVector<2>{1, 2}), + "error: incompatible operand types Vh(P0Vector:R) and R^2"); + } - CHECK_SCALAR_VH2_TO_VH(p_R1x1_u, *, p_R1_v); - CHECK_SCALAR_VH2_TO_VH(p_R2x2_u, *, p_R2_v); - CHECK_SCALAR_VH2_TO_VH(p_R3x3_u, *, p_R3_v); + SECTION("X + Vh -> Vh") + { + CHECK_SCALAR_XxVH_TO_VH(bool{true}, +, p_R_u); + CHECK_SCALAR_XxVH_TO_VH(uint64_t{1}, +, p_R_u); + CHECK_SCALAR_XxVH_TO_VH(int64_t{2}, +, p_R_u); + CHECK_SCALAR_XxVH_TO_VH(double{1.3}, +, p_R_u); + + CHECK_SCALAR_XxVH_TO_VH((TinyVector<1>{1.3}), +, p_R1_u); + CHECK_SCALAR_XxVH_TO_VH((TinyVector<2>{1.2, 2.3}), +, p_R2_u); + CHECK_SCALAR_XxVH_TO_VH((TinyVector<3>{3.2, 7.1, 5.2}), +, p_R3_u); + + CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<1>{1.3}), +, p_R1x1_u); + CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<2>{1.2, 2.3, 4.2, 5.1}), +, p_R2x2_u); + CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<3>{3.2, 7.1, 5.2, // + 4.7, 2.3, 7.1, // + 9.7, 3.2, 6.8}), + +, p_R3x3_u); + + REQUIRE_THROWS_WITH((TinyVector<1>{1}) + p_R_u, "error: incompatible operand types R^1 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyVector<2>{1, 2}) + p_R_u, "error: incompatible operand types R^2 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyVector<3>{2, 3, 2}) + p_R_u, + "error: incompatible operand types R^3 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) + p_R_u, "error: incompatible operand types R^1x1 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) + p_R_u, + "error: incompatible operand types R^2x2 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) + p_R_u, + "error: incompatible operand types R^3x3 and Vh(P0:R)"); + + REQUIRE_THROWS_WITH((double{1}) + p_Vector3_u, "error: incompatible operand types R and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH((TinyVector<1>{1}) + p_Vector3_u, + "error: incompatible operand types R^1 and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH((TinyVector<2>{1, 2}) + p_Vector3_u, + "error: incompatible operand types R^2 and Vh(P0Vector:R)"); + } + } + SECTION("difference") { - std::shared_ptr p_fuv = p_R_u * p_Vector3_v; + SECTION("Vh - Vh -> Vh") + { + CHECK_SCALAR_VH2_TO_VH(p_R_u, -, p_R_v); + + CHECK_SCALAR_VH2_TO_VH(p_R1_u, -, p_R1_v); + CHECK_SCALAR_VH2_TO_VH(p_R2_u, -, p_R2_v); + CHECK_SCALAR_VH2_TO_VH(p_R3_u, -, p_R3_v); + + CHECK_SCALAR_VH2_TO_VH(p_R1x1_u, -, p_R1x1_v); + CHECK_SCALAR_VH2_TO_VH(p_R2x2_u, -, p_R2x2_v); + CHECK_SCALAR_VH2_TO_VH(p_R3x3_u, -, p_R3x3_v); + + CHECK_VECTOR_VH2_TO_VH(p_Vector3_u, -, p_Vector3_v); + + REQUIRE_THROWS_WITH(p_R_u - p_R1_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(p_R2_u - p_R1_v, "error: incompatible operand types Vh(P0:R^2) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(p_R3_u - p_R1x1_v, "error: incompatible operand types Vh(P0:R^3) and Vh(P0:R^1x1)"); + REQUIRE_THROWS_WITH(p_R_u - p_R2x2_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^2x2)"); + REQUIRE_THROWS_WITH(p_Vector3_u - p_R_v, "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R)"); + REQUIRE_THROWS_WITH(p_Vector3_u - p_Vector2_w, "error: Vh(P0Vector:R) spaces have different sizes"); + + REQUIRE_THROWS_WITH(p_R_u - p_other_mesh_R_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R1_u - p_other_mesh_R1_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R2_u - p_other_mesh_R2_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R3_u - p_other_mesh_R3_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R1x1_u - p_other_mesh_R1x1_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R2x2_u - p_other_mesh_R2x2_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R3x3_u - p_other_mesh_R3x3_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_Vector3_u - p_other_mesh_Vector3_u, + "error: operands are defined on different meshes"); + } - REQUIRE(p_fuv.use_count() > 0); - REQUIRE_NOTHROW(dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*p_fuv)); + SECTION("Vh - X -> Vh") + { + CHECK_SCALAR_VHxX_TO_VH(p_R_u, -, bool{true}); + CHECK_SCALAR_VHxX_TO_VH(p_R_u, -, uint64_t{1}); + CHECK_SCALAR_VHxX_TO_VH(p_R_u, -, int64_t{2}); + CHECK_SCALAR_VHxX_TO_VH(p_R_u, -, double{1.3}); + + CHECK_SCALAR_VHxX_TO_VH(p_R1_u, -, (TinyVector<1>{1.3})); + CHECK_SCALAR_VHxX_TO_VH(p_R2_u, -, (TinyVector<2>{1.2, 2.3})); + CHECK_SCALAR_VHxX_TO_VH(p_R3_u, -, (TinyVector<3>{3.2, 7.1, 5.2})); + + CHECK_SCALAR_VHxX_TO_VH(p_R1x1_u, -, (TinyMatrix<1>{1.3})); + CHECK_SCALAR_VHxX_TO_VH(p_R2x2_u, -, (TinyMatrix<2>{1.2, 2.3, 4.2, 5.1})); + CHECK_SCALAR_VHxX_TO_VH(p_R3x3_u, -, + (TinyMatrix<3>{3.2, 7.1, 5.2, // + 4.7, 2.3, 7.1, // + 9.7, 3.2, 6.8})); + + REQUIRE_THROWS_WITH(p_R_u - (TinyVector<1>{1}), "error: incompatible operand types Vh(P0:R) and R^1"); + REQUIRE_THROWS_WITH(p_R_u - (TinyVector<2>{1, 2}), "error: incompatible operand types Vh(P0:R) and R^2"); + REQUIRE_THROWS_WITH(p_R_u - (TinyVector<3>{2, 3, 2}), + "error: incompatible operand types Vh(P0:R) and R^3"); + REQUIRE_THROWS_WITH(p_R_u - (TinyMatrix<1>{2}), "error: incompatible operand types Vh(P0:R) and R^1x1"); + REQUIRE_THROWS_WITH(p_R_u - (TinyMatrix<2>{2, 3, 1, 4}), + "error: incompatible operand types Vh(P0:R) and R^2x2"); + REQUIRE_THROWS_WITH(p_R_u - (TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}), + "error: incompatible operand types Vh(P0:R) and R^3x3"); + + REQUIRE_THROWS_WITH(p_Vector3_u - (double{1}), "error: incompatible operand types Vh(P0Vector:R) and R"); + REQUIRE_THROWS_WITH(p_Vector3_u - (TinyVector<1>{1}), + "error: incompatible operand types Vh(P0Vector:R) and R^1"); + REQUIRE_THROWS_WITH(p_Vector3_u - (TinyVector<2>{1, 2}), + "error: incompatible operand types Vh(P0Vector:R) and R^2"); + } - const auto& fuv = dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*p_fuv); + SECTION("X - Vh -> Vh") + { + CHECK_SCALAR_XxVH_TO_VH(bool{true}, -, p_R_u); + CHECK_SCALAR_XxVH_TO_VH(uint64_t{1}, -, p_R_u); + CHECK_SCALAR_XxVH_TO_VH(int64_t{2}, -, p_R_u); + CHECK_SCALAR_XxVH_TO_VH(double{1.3}, -, p_R_u); + + CHECK_SCALAR_XxVH_TO_VH((TinyVector<1>{1.3}), -, p_R1_u); + CHECK_SCALAR_XxVH_TO_VH((TinyVector<2>{1.2, 2.3}), -, p_R2_u); + CHECK_SCALAR_XxVH_TO_VH((TinyVector<3>{3.2, 7.1, 5.2}), -, p_R3_u); + + CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<1>{1.3}), -, p_R1x1_u); + CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<2>{1.2, 2.3, 4.2, 5.1}), -, p_R2x2_u); + CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<3>{3.2, 7.1, 5.2, // + 4.7, 2.3, 7.1, // + 9.7, 3.2, 6.8}), + -, p_R3x3_u); + + REQUIRE_THROWS_WITH((TinyVector<1>{1}) - p_R_u, "error: incompatible operand types R^1 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyVector<2>{1, 2}) - p_R_u, "error: incompatible operand types R^2 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyVector<3>{2, 3, 2}) - p_R_u, + "error: incompatible operand types R^3 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) - p_R_u, "error: incompatible operand types R^1x1 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) - p_R_u, + "error: incompatible operand types R^2x2 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) - p_R_u, + "error: incompatible operand types R^3x3 and Vh(P0:R)"); + + REQUIRE_THROWS_WITH((double{1}) - p_Vector3_u, "error: incompatible operand types R and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH((TinyVector<1>{1}) - p_Vector3_u, + "error: incompatible operand types R^1 and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH((TinyVector<2>{1, 2}) - p_Vector3_u, + "error: incompatible operand types R^2 and Vh(P0Vector:R)"); + } + } - auto lhs_values = p_R_u->cellValues(); - auto rhs_arrays = p_Vector3_v->cellArrays(); - bool is_same = true; - for (CellId cell_id = 0; cell_id < lhs_values.numberOfItems(); ++cell_id) { - for (size_t i = 0; i < fuv.size(); ++i) { - if (fuv[cell_id][i] != (lhs_values[cell_id] * rhs_arrays[cell_id][i])) { - is_same = false; - break; + SECTION("product") + { + SECTION("Vh * Vh -> Vh") + { + CHECK_SCALAR_VH2_TO_VH(p_R_u, *, p_R_v); + + CHECK_SCALAR_VH2_TO_VH(p_R1x1_u, *, p_R1x1_v); + CHECK_SCALAR_VH2_TO_VH(p_R2x2_u, *, p_R2x2_v); + CHECK_SCALAR_VH2_TO_VH(p_R3x3_u, *, p_R3x3_v); + + CHECK_SCALAR_VH2_TO_VH(p_R_u, *, p_R1_v); + CHECK_SCALAR_VH2_TO_VH(p_R_u, *, p_R2_v); + CHECK_SCALAR_VH2_TO_VH(p_R_u, *, p_R3_v); + + CHECK_SCALAR_VH2_TO_VH(p_R_u, *, p_R1x1_v); + CHECK_SCALAR_VH2_TO_VH(p_R_u, *, p_R2x2_v); + CHECK_SCALAR_VH2_TO_VH(p_R_u, *, p_R3x3_v); + + CHECK_SCALAR_VH2_TO_VH(p_R1x1_u, *, p_R1_v); + CHECK_SCALAR_VH2_TO_VH(p_R2x2_u, *, p_R2_v); + CHECK_SCALAR_VH2_TO_VH(p_R3x3_u, *, p_R3_v); + + { + std::shared_ptr p_fuv = p_R_u * p_Vector3_v; + + REQUIRE(p_fuv.use_count() > 0); + REQUIRE_NOTHROW(dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*p_fuv)); + + const auto& fuv = dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*p_fuv); + + auto lhs_values = p_R_u->cellValues(); + auto rhs_arrays = p_Vector3_v->cellArrays(); + bool is_same = true; + for (CellId cell_id = 0; cell_id < lhs_values.numberOfItems(); ++cell_id) { + for (size_t i = 0; i < fuv.size(); ++i) { + if (fuv[cell_id][i] != (lhs_values[cell_id] * rhs_arrays[cell_id][i])) { + is_same = false; + break; + } + } } - } - } - REQUIRE(is_same); - } + REQUIRE(is_same); + } - REQUIRE_THROWS_WITH(p_R1_u * p_R1_v, "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(p_R2_u * p_R1_v, "error: incompatible operand types Vh(P0:R^2) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(p_R3_u * p_R1x1_v, "error: incompatible operand types Vh(P0:R^3) and Vh(P0:R^1x1)"); - REQUIRE_THROWS_WITH(p_R1_u * p_R2x2_v, "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R^2x2)"); - - REQUIRE_THROWS_WITH(p_R1x1_u * p_R2x2_v, "error: incompatible operand types Vh(P0:R^1x1) and Vh(P0:R^2x2)"); - REQUIRE_THROWS_WITH(p_R2x2_u * p_R3x3_v, "error: incompatible operand types Vh(P0:R^2x2) and Vh(P0:R^3x3)"); - REQUIRE_THROWS_WITH(p_R3x3_u * p_R1x1_v, "error: incompatible operand types Vh(P0:R^3x3) and Vh(P0:R^1x1)"); - - REQUIRE_THROWS_WITH(p_R1x1_u * p_R2_v, "error: incompatible operand types Vh(P0:R^1x1) and Vh(P0:R^2)"); - REQUIRE_THROWS_WITH(p_R2x2_u * p_R3_v, "error: incompatible operand types Vh(P0:R^2x2) and Vh(P0:R^3)"); - REQUIRE_THROWS_WITH(p_R3x3_u * p_R1_v, "error: incompatible operand types Vh(P0:R^3x3) and Vh(P0:R^1)"); - - REQUIRE_THROWS_WITH(p_R1_u * p_Vector3_v, "error: incompatible operand types Vh(P0:R^1) and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH(p_R2_u * p_Vector3_v, "error: incompatible operand types Vh(P0:R^2) and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH(p_R3_u * p_Vector3_v, "error: incompatible operand types Vh(P0:R^3) and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH(p_R1x1_u * p_Vector3_v, - "error: incompatible operand types Vh(P0:R^1x1) and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH(p_R2x2_u * p_Vector3_v, - "error: incompatible operand types Vh(P0:R^2x2) and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH(p_R3x3_u * p_Vector3_v, - "error: incompatible operand types Vh(P0:R^3x3) and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH(p_Vector3_u * p_Vector3_v, - "error: incompatible operand types Vh(P0Vector:R) and Vh(P0Vector:R)"); - - REQUIRE_THROWS_WITH(p_Vector3_v * p_R_u, "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R)"); - REQUIRE_THROWS_WITH(p_Vector3_v * p_R1_u, "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(p_Vector3_v * p_R2_u, "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^2)"); - REQUIRE_THROWS_WITH(p_Vector3_v * p_R3_u, "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^3)"); - REQUIRE_THROWS_WITH(p_Vector3_v * p_R1x1_u, - "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^1x1)"); - REQUIRE_THROWS_WITH(p_Vector3_v * p_R2x2_u, - "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^2x2)"); - REQUIRE_THROWS_WITH(p_Vector3_v * p_R3x3_u, - "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^3x3)"); - - REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R1_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R2_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R3_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R1x1_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R2x2_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R3x3_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R1x1_u * p_other_mesh_R1_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R2x2_u * p_other_mesh_R2_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R3x3_u * p_other_mesh_R3_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_Vector3_u, "error: operands are defined on different meshes"); - } + REQUIRE_THROWS_WITH(p_R1_u * p_R1_v, "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(p_R2_u * p_R1_v, "error: incompatible operand types Vh(P0:R^2) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(p_R3_u * p_R1x1_v, "error: incompatible operand types Vh(P0:R^3) and Vh(P0:R^1x1)"); + REQUIRE_THROWS_WITH(p_R1_u * p_R2x2_v, "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R^2x2)"); + + REQUIRE_THROWS_WITH(p_R1x1_u * p_R2x2_v, + "error: incompatible operand types Vh(P0:R^1x1) and Vh(P0:R^2x2)"); + REQUIRE_THROWS_WITH(p_R2x2_u * p_R3x3_v, + "error: incompatible operand types Vh(P0:R^2x2) and Vh(P0:R^3x3)"); + REQUIRE_THROWS_WITH(p_R3x3_u * p_R1x1_v, + "error: incompatible operand types Vh(P0:R^3x3) and Vh(P0:R^1x1)"); + + REQUIRE_THROWS_WITH(p_R1x1_u * p_R2_v, "error: incompatible operand types Vh(P0:R^1x1) and Vh(P0:R^2)"); + REQUIRE_THROWS_WITH(p_R2x2_u * p_R3_v, "error: incompatible operand types Vh(P0:R^2x2) and Vh(P0:R^3)"); + REQUIRE_THROWS_WITH(p_R3x3_u * p_R1_v, "error: incompatible operand types Vh(P0:R^3x3) and Vh(P0:R^1)"); + + REQUIRE_THROWS_WITH(p_R1_u * p_Vector3_v, + "error: incompatible operand types Vh(P0:R^1) and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH(p_R2_u * p_Vector3_v, + "error: incompatible operand types Vh(P0:R^2) and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH(p_R3_u * p_Vector3_v, + "error: incompatible operand types Vh(P0:R^3) and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH(p_R1x1_u * p_Vector3_v, + "error: incompatible operand types Vh(P0:R^1x1) and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH(p_R2x2_u * p_Vector3_v, + "error: incompatible operand types Vh(P0:R^2x2) and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH(p_R3x3_u * p_Vector3_v, + "error: incompatible operand types Vh(P0:R^3x3) and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH(p_Vector3_u * p_Vector3_v, + "error: incompatible operand types Vh(P0Vector:R) and Vh(P0Vector:R)"); + + REQUIRE_THROWS_WITH(p_Vector3_v * p_R_u, "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R)"); + REQUIRE_THROWS_WITH(p_Vector3_v * p_R1_u, + "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(p_Vector3_v * p_R2_u, + "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^2)"); + REQUIRE_THROWS_WITH(p_Vector3_v * p_R3_u, + "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^3)"); + REQUIRE_THROWS_WITH(p_Vector3_v * p_R1x1_u, + "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^1x1)"); + REQUIRE_THROWS_WITH(p_Vector3_v * p_R2x2_u, + "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^2x2)"); + REQUIRE_THROWS_WITH(p_Vector3_v * p_R3x3_u, + "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^3x3)"); + + REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R1_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R2_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R3_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R1x1_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R2x2_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R3x3_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R1x1_u * p_other_mesh_R1_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R2x2_u * p_other_mesh_R2_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R3x3_u * p_other_mesh_R3_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_Vector3_u, "error: operands are defined on different meshes"); + } - SECTION("Vh * X -> Vh") - { - CHECK_SCALAR_VHxX_TO_VH(p_R_u, *, bool{true}); - CHECK_SCALAR_VHxX_TO_VH(p_R_u, *, uint64_t{1}); - CHECK_SCALAR_VHxX_TO_VH(p_R_u, *, int64_t{2}); - CHECK_SCALAR_VHxX_TO_VH(p_R_u, *, double{1.3}); - - CHECK_SCALAR_VHxX_TO_VH(p_R1x1_u, *, (TinyMatrix<1>{1.3})); - CHECK_SCALAR_VHxX_TO_VH(p_R2x2_u, *, (TinyMatrix<2>{1.2, 2.3, 4.2, 5.1})); - CHECK_SCALAR_VHxX_TO_VH(p_R3x3_u, *, - (TinyMatrix<3>{3.2, 7.1, 5.2, // - 4.7, 2.3, 7.1, // - 9.7, 3.2, 6.8})); - - REQUIRE_THROWS_WITH(p_R1_u * (TinyVector<1>{1}), "error: incompatible operand types Vh(P0:R^1) and R^1"); - REQUIRE_THROWS_WITH(p_R2_u * (TinyVector<2>{1, 2}), "error: incompatible operand types Vh(P0:R^2) and R^2"); - REQUIRE_THROWS_WITH(p_R3_u * (TinyVector<3>{2, 3, 2}), - "error: incompatible operand types Vh(P0:R^3) and R^3"); - REQUIRE_THROWS_WITH(p_R1_u * (TinyMatrix<1>{2}), "error: incompatible operand types Vh(P0:R^1) and R^1x1"); - REQUIRE_THROWS_WITH(p_R2_u * (TinyMatrix<2>{2, 3, 1, 4}), - "error: incompatible operand types Vh(P0:R^2) and R^2x2"); - REQUIRE_THROWS_WITH(p_R3_u * (TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}), - "error: incompatible operand types Vh(P0:R^3) and R^3x3"); - REQUIRE_THROWS_WITH(p_R2x2_u * (TinyMatrix<1>{2}), - "error: incompatible operand types Vh(P0:R^2x2) and R^1x1"); - REQUIRE_THROWS_WITH(p_R1x1_u * (TinyMatrix<2>{2, 3, 1, 4}), - "error: incompatible operand types Vh(P0:R^1x1) and R^2x2"); - REQUIRE_THROWS_WITH(p_R2x2_u * (TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}), - "error: incompatible operand types Vh(P0:R^2x2) and R^3x3"); - - REQUIRE_THROWS_WITH(p_Vector3_u * (TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}), - "error: incompatible operand types Vh(P0Vector:R) and R^3x3"); - REQUIRE_THROWS_WITH(p_Vector3_u * (double{2}), "error: incompatible operand types Vh(P0Vector:R) and R"); - } + SECTION("Vh * X -> Vh") + { + CHECK_SCALAR_VHxX_TO_VH(p_R_u, *, bool{true}); + CHECK_SCALAR_VHxX_TO_VH(p_R_u, *, uint64_t{1}); + CHECK_SCALAR_VHxX_TO_VH(p_R_u, *, int64_t{2}); + CHECK_SCALAR_VHxX_TO_VH(p_R_u, *, double{1.3}); + + CHECK_SCALAR_VHxX_TO_VH(p_R1x1_u, *, (TinyMatrix<1>{1.3})); + CHECK_SCALAR_VHxX_TO_VH(p_R2x2_u, *, (TinyMatrix<2>{1.2, 2.3, 4.2, 5.1})); + CHECK_SCALAR_VHxX_TO_VH(p_R3x3_u, *, + (TinyMatrix<3>{3.2, 7.1, 5.2, // + 4.7, 2.3, 7.1, // + 9.7, 3.2, 6.8})); + + REQUIRE_THROWS_WITH(p_R1_u * (TinyVector<1>{1}), "error: incompatible operand types Vh(P0:R^1) and R^1"); + REQUIRE_THROWS_WITH(p_R2_u * (TinyVector<2>{1, 2}), + "error: incompatible operand types Vh(P0:R^2) and R^2"); + REQUIRE_THROWS_WITH(p_R3_u * (TinyVector<3>{2, 3, 2}), + "error: incompatible operand types Vh(P0:R^3) and R^3"); + REQUIRE_THROWS_WITH(p_R1_u * (TinyMatrix<1>{2}), + "error: incompatible operand types Vh(P0:R^1) and R^1x1"); + REQUIRE_THROWS_WITH(p_R2_u * (TinyMatrix<2>{2, 3, 1, 4}), + "error: incompatible operand types Vh(P0:R^2) and R^2x2"); + REQUIRE_THROWS_WITH(p_R3_u * (TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}), + "error: incompatible operand types Vh(P0:R^3) and R^3x3"); + REQUIRE_THROWS_WITH(p_R2x2_u * (TinyMatrix<1>{2}), + "error: incompatible operand types Vh(P0:R^2x2) and R^1x1"); + REQUIRE_THROWS_WITH(p_R1x1_u * (TinyMatrix<2>{2, 3, 1, 4}), + "error: incompatible operand types Vh(P0:R^1x1) and R^2x2"); + REQUIRE_THROWS_WITH(p_R2x2_u * (TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}), + "error: incompatible operand types Vh(P0:R^2x2) and R^3x3"); + + REQUIRE_THROWS_WITH(p_Vector3_u * (TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}), + "error: incompatible operand types Vh(P0Vector:R) and R^3x3"); + REQUIRE_THROWS_WITH(p_Vector3_u * (double{2}), "error: incompatible operand types Vh(P0Vector:R) and R"); + } - SECTION("X * Vh -> Vh") - { - CHECK_SCALAR_XxVH_TO_VH(bool{true}, *, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(uint64_t{1}, *, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(int64_t{2}, *, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(double{1.3}, *, p_R_u); - - CHECK_SCALAR_XxVH_TO_VH(bool{true}, *, p_R1x1_u); - CHECK_SCALAR_XxVH_TO_VH(uint64_t{1}, *, p_R1x1_u); - CHECK_SCALAR_XxVH_TO_VH(int64_t{2}, *, p_R1x1_u); - CHECK_SCALAR_XxVH_TO_VH(double{1.3}, *, p_R1x1_u); - - CHECK_SCALAR_XxVH_TO_VH(bool{true}, *, p_R2x2_u); - CHECK_SCALAR_XxVH_TO_VH(uint64_t{1}, *, p_R2x2_u); - CHECK_SCALAR_XxVH_TO_VH(int64_t{2}, *, p_R2x2_u); - CHECK_SCALAR_XxVH_TO_VH(double{1.3}, *, p_R2x2_u); - - CHECK_SCALAR_XxVH_TO_VH(bool{true}, *, p_R3x3_u); - CHECK_SCALAR_XxVH_TO_VH(uint64_t{1}, *, p_R3x3_u); - CHECK_SCALAR_XxVH_TO_VH(int64_t{2}, *, p_R3x3_u); - CHECK_SCALAR_XxVH_TO_VH(double{1.3}, *, p_R3x3_u); - - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<1>{1.3}), *, p_R1_u); - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<2>{1.2, 2.3, 4.2, 5.1}), *, p_R2_u); - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<3>{3.2, 7.1, 5.2, // + SECTION("X * Vh -> Vh") + { + CHECK_SCALAR_XxVH_TO_VH(bool{true}, *, p_R_u); + CHECK_SCALAR_XxVH_TO_VH(uint64_t{1}, *, p_R_u); + CHECK_SCALAR_XxVH_TO_VH(int64_t{2}, *, p_R_u); + CHECK_SCALAR_XxVH_TO_VH(double{1.3}, *, p_R_u); + + CHECK_SCALAR_XxVH_TO_VH(bool{true}, *, p_R1x1_u); + CHECK_SCALAR_XxVH_TO_VH(uint64_t{1}, *, p_R1x1_u); + CHECK_SCALAR_XxVH_TO_VH(int64_t{2}, *, p_R1x1_u); + CHECK_SCALAR_XxVH_TO_VH(double{1.3}, *, p_R1x1_u); + + CHECK_SCALAR_XxVH_TO_VH(bool{true}, *, p_R2x2_u); + CHECK_SCALAR_XxVH_TO_VH(uint64_t{1}, *, p_R2x2_u); + CHECK_SCALAR_XxVH_TO_VH(int64_t{2}, *, p_R2x2_u); + CHECK_SCALAR_XxVH_TO_VH(double{1.3}, *, p_R2x2_u); + + CHECK_SCALAR_XxVH_TO_VH(bool{true}, *, p_R3x3_u); + CHECK_SCALAR_XxVH_TO_VH(uint64_t{1}, *, p_R3x3_u); + CHECK_SCALAR_XxVH_TO_VH(int64_t{2}, *, p_R3x3_u); + CHECK_SCALAR_XxVH_TO_VH(double{1.3}, *, p_R3x3_u); + + CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<1>{1.3}), *, p_R1_u); + CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<2>{1.2, 2.3, 4.2, 5.1}), *, p_R2_u); + CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<3>{3.2, 7.1, 5.2, // 4.7, 2.3, 7.1, // 9.7, 3.2, 6.8}), *, p_R3_u); - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<1>{1.3}), *, p_R1x1_u); - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<2>{1.2, 2.3, 4.2, 5.1}), *, p_R2x2_u); - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<3>{3.2, 7.1, 5.2, // + CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<1>{1.3}), *, p_R1x1_u); + CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<2>{1.2, 2.3, 4.2, 5.1}), *, p_R2x2_u); + CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<3>{3.2, 7.1, 5.2, // 4.7, 2.3, 7.1, // 9.7, 3.2, 6.8}), *, p_R3x3_u); - CHECK_VECTOR_XxVH_TO_VH(bool{true}, *, p_Vector3_u); - CHECK_VECTOR_XxVH_TO_VH(uint64_t{1}, *, p_Vector3_u); - CHECK_VECTOR_XxVH_TO_VH(int64_t{2}, *, p_Vector3_u); - CHECK_VECTOR_XxVH_TO_VH(double{1.3}, *, p_Vector3_u); - - REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) * p_R_u, "error: incompatible operand types R^1x1 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) * p_R_u, - "error: incompatible operand types R^2x2 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) * p_R_u, - "error: incompatible operand types R^3x3 and Vh(P0:R)"); - - REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) * p_R2_u, "error: incompatible operand types R^1x1 and Vh(P0:R^2)"); - REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) * p_R3_u, - "error: incompatible operand types R^2x2 and Vh(P0:R^3)"); - REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) * p_R2_u, - "error: incompatible operand types R^3x3 and Vh(P0:R^2)"); - REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) * p_R1_u, - "error: incompatible operand types R^3x3 and Vh(P0:R^1)"); - - REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) * p_R2x2_u, - "error: incompatible operand types R^1x1 and Vh(P0:R^2x2)"); - REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) * p_R3x3_u, - "error: incompatible operand types R^2x2 and Vh(P0:R^3x3)"); - REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) * p_R2x2_u, - "error: incompatible operand types R^3x3 and Vh(P0:R^2x2)"); - REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) * p_R1x1_u, - "error: incompatible operand types R^2x2 and Vh(P0:R^1x1)"); - - REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) * p_Vector3_u, - "error: incompatible operand types R^3x3 and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) * p_Vector3_u, - "error: incompatible operand types R^1x1 and Vh(P0Vector:R)"); - } - } + CHECK_VECTOR_XxVH_TO_VH(bool{true}, *, p_Vector3_u); + CHECK_VECTOR_XxVH_TO_VH(uint64_t{1}, *, p_Vector3_u); + CHECK_VECTOR_XxVH_TO_VH(int64_t{2}, *, p_Vector3_u); + CHECK_VECTOR_XxVH_TO_VH(double{1.3}, *, p_Vector3_u); + + REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) * p_R_u, "error: incompatible operand types R^1x1 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) * p_R_u, + "error: incompatible operand types R^2x2 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) * p_R_u, + "error: incompatible operand types R^3x3 and Vh(P0:R)"); + + REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) * p_R2_u, + "error: incompatible operand types R^1x1 and Vh(P0:R^2)"); + REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) * p_R3_u, + "error: incompatible operand types R^2x2 and Vh(P0:R^3)"); + REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) * p_R2_u, + "error: incompatible operand types R^3x3 and Vh(P0:R^2)"); + REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) * p_R1_u, + "error: incompatible operand types R^3x3 and Vh(P0:R^1)"); + + REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) * p_R2x2_u, + "error: incompatible operand types R^1x1 and Vh(P0:R^2x2)"); + REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) * p_R3x3_u, + "error: incompatible operand types R^2x2 and Vh(P0:R^3x3)"); + REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) * p_R2x2_u, + "error: incompatible operand types R^3x3 and Vh(P0:R^2x2)"); + REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) * p_R1x1_u, + "error: incompatible operand types R^2x2 and Vh(P0:R^1x1)"); + + REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) * p_Vector3_u, + "error: incompatible operand types R^3x3 and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) * p_Vector3_u, + "error: incompatible operand types R^1x1 and Vh(P0Vector:R)"); + } + } - SECTION("ratio") - { - SECTION("Vh / Vh -> Vh") - { - CHECK_SCALAR_VH2_TO_VH(p_R_u, /, p_R_v); + SECTION("ratio") + { + SECTION("Vh / Vh -> Vh") + { + CHECK_SCALAR_VH2_TO_VH(p_R_u, /, p_R_v); - REQUIRE_THROWS_WITH(p_R_u / p_R1_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(p_R2_u / p_R1_v, "error: incompatible operand types Vh(P0:R^2) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(p_R3_u / p_R1x1_v, "error: incompatible operand types Vh(P0:R^3) and Vh(P0:R^1x1)"); - REQUIRE_THROWS_WITH(p_R_u / p_R2x2_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^2x2)"); + REQUIRE_THROWS_WITH(p_R_u / p_R1_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(p_R2_u / p_R1_v, "error: incompatible operand types Vh(P0:R^2) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(p_R3_u / p_R1x1_v, "error: incompatible operand types Vh(P0:R^3) and Vh(P0:R^1x1)"); + REQUIRE_THROWS_WITH(p_R_u / p_R2x2_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^2x2)"); - REQUIRE_THROWS_WITH(p_R_u / p_other_mesh_R_u, "error: operands are defined on different meshes"); - } + REQUIRE_THROWS_WITH(p_R_u / p_other_mesh_R_u, "error: operands are defined on different meshes"); + } - SECTION("X / Vh -> Vh") - { - CHECK_SCALAR_XxVH_TO_VH(bool{true}, /, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(uint64_t{1}, /, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(int64_t{2}, /, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(double{1.3}, /, p_R_u); + SECTION("X / Vh -> Vh") + { + CHECK_SCALAR_XxVH_TO_VH(bool{true}, /, p_R_u); + CHECK_SCALAR_XxVH_TO_VH(uint64_t{1}, /, p_R_u); + CHECK_SCALAR_XxVH_TO_VH(int64_t{2}, /, p_R_u); + CHECK_SCALAR_XxVH_TO_VH(double{1.3}, /, p_R_u); + } + } } } } @@ -867,668 +896,693 @@ TEST_CASE("EmbeddedIDiscreteFunctionOperators", "[scheme]") using Rd = TinyVector<Dimension>; - std::shared_ptr mesh = MeshDataBaseForTests::get().cartesianMesh2D(); - - std::shared_ptr other_mesh = - std::make_shared<Mesh<Connectivity<Dimension>>>(mesh->shared_connectivity(), mesh->xr()); - - CellValue<const Rd> xj = MeshDataManager::instance().getMeshData(*mesh).xj(); - - CellValue<double> u_R_values = [=] { - CellValue<double> build_values{mesh->connectivity()}; - parallel_for( - build_values.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 0.2 + std::cos(l2Norm(xj[cell_id])); }); - return build_values; - }(); - - CellValue<double> v_R_values = [=] { - CellValue<double> build_values{mesh->connectivity()}; - parallel_for( - build_values.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 0.6 + std::sin(l2Norm(xj[cell_id])); }); - return build_values; - }(); - - std::shared_ptr p_R_u = std::make_shared<const DiscreteFunctionP0<Dimension, double>>(mesh, u_R_values); - std::shared_ptr p_other_mesh_R_u = - std::make_shared<const DiscreteFunctionP0<Dimension, double>>(other_mesh, u_R_values); - std::shared_ptr p_R_v = std::make_shared<const DiscreteFunctionP0<Dimension, double>>(mesh, v_R_values); - - std::shared_ptr p_R1_u = [=] { - CellValue<TinyVector<1>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { uj[cell_id][0] = 2 * xj[cell_id][0] + 1; }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<1>>>(mesh, uj); - }(); - - std::shared_ptr p_R1_v = [=] { - CellValue<TinyVector<1>> vj{mesh->connectivity()}; - parallel_for( - vj.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { vj[cell_id][0] = xj[cell_id][0] * xj[cell_id][0] + 1; }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<1>>>(mesh, vj); - }(); - - std::shared_ptr p_other_mesh_R1_u = - std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<1>>>(other_mesh, p_R1_u->cellValues()); - - constexpr auto to_2d = [&](const TinyVector<Dimension>& x) -> TinyVector<2> { - if constexpr (Dimension == 1) { - return {x[0], 1 + x[0] * x[0]}; - } else if constexpr (Dimension == 2) { - return {x[0], x[1]}; - } else if constexpr (Dimension == 3) { - return {x[0], x[1] + x[2]}; - } - }; - - std::shared_ptr p_R2_u = [=] { - CellValue<TinyVector<2>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<2> x = to_2d(xj[cell_id]); - uj[cell_id] = {2 * x[0] + 1, 1 - x[1]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<2>>>(mesh, uj); - }(); - - std::shared_ptr p_R2_v = [=] { - CellValue<TinyVector<2>> vj{mesh->connectivity()}; - parallel_for( - vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<2> x = to_2d(xj[cell_id]); - vj[cell_id] = {x[0] * x[1] + 1, 2 * x[1]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<2>>>(mesh, vj); - }(); - - std::shared_ptr p_other_mesh_R2_u = - std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<2>>>(other_mesh, p_R2_u->cellValues()); - - constexpr auto to_3d = [&](const TinyVector<Dimension>& x) -> TinyVector<3> { - if constexpr (Dimension == 1) { - return {x[0], 1 + x[0] * x[0], 2 - x[0]}; - } else if constexpr (Dimension == 2) { - return {x[0], x[1], x[0] + x[1]}; - } else if constexpr (Dimension == 3) { - return {x[0], x[1], x[2]}; - } - }; - - std::shared_ptr p_R3_u = [=] { - CellValue<TinyVector<3>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - uj[cell_id] = {2 * x[0] + 1, 1 - x[1] * x[2], x[0] + x[2]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<3>>>(mesh, uj); - }(); - - std::shared_ptr p_R3_v = [=] { - CellValue<TinyVector<3>> vj{mesh->connectivity()}; - parallel_for( - vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - vj[cell_id] = {x[0] * x[1] + 1, 2 * x[1], x[2] * x[0]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<3>>>(mesh, vj); - }(); - - std::shared_ptr p_other_mesh_R3_u = - std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<3>>>(other_mesh, p_R3_u->cellValues()); - - std::shared_ptr p_R1x1_u = [=] { - CellValue<TinyMatrix<1>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { uj[cell_id] = {2 * xj[cell_id][0] + 1}; }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<1>>>(mesh, uj); - }(); - - std::shared_ptr p_other_mesh_R1x1_u = - std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<1>>>(other_mesh, p_R1x1_u->cellValues()); - - std::shared_ptr p_R1x1_v = [=] { - CellValue<TinyMatrix<1>> vj{mesh->connectivity()}; - parallel_for( - vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { vj[cell_id] = {0.3 - xj[cell_id][0]}; }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<1>>>(mesh, vj); - }(); - - std::shared_ptr p_R2x2_u = [=] { - CellValue<TinyMatrix<2>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<2> x = to_2d(xj[cell_id]); - - uj[cell_id] = {2 * x[0] + 1, 1 - x[1], // - 2 * x[1], -x[0]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<2>>>(mesh, uj); - }(); - - std::shared_ptr p_other_mesh_R2x2_u = - std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<2>>>(other_mesh, p_R2x2_u->cellValues()); - - std::shared_ptr p_R2x2_v = [=] { - CellValue<TinyMatrix<2>> vj{mesh->connectivity()}; - parallel_for( - vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<2> x = to_2d(xj[cell_id]); - - vj[cell_id] = {x[0] + 0.3, 1 - x[1] - x[0], // - 2 * x[1] + x[0], x[1] - x[0]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<2>>>(mesh, vj); - }(); - - std::shared_ptr p_R3x3_u = [=] { - CellValue<TinyMatrix<3>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - - uj[cell_id] = {2 * x[0] + 1, 1 - x[1], 3, // - 2 * x[1], -x[0], x[0] - x[1], // - 3 * x[2] - x[1], x[1] - 2 * x[2], x[2] - x[0]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<3>>>(mesh, uj); - }(); - - std::shared_ptr p_other_mesh_R3x3_u = - std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<3>>>(other_mesh, p_R3x3_u->cellValues()); - - std::shared_ptr p_R3x3_v = [=] { - CellValue<TinyMatrix<3>> vj{mesh->connectivity()}; - parallel_for( - vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - - vj[cell_id] = {0.2 * x[0] + 1, 2 + x[1], 3 - x[2], // - 2.3 * x[2], x[1] - x[0], x[2] - x[1], // - 2 * x[2] + x[0], x[1] + 0.2 * x[2], x[2] - 2 * x[0]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<3>>>(mesh, vj); - }(); - - std::shared_ptr p_Vector3_u = [=] { - CellArray<double> uj_vector{mesh->connectivity(), 3}; - parallel_for( - uj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - uj_vector[cell_id][0] = 2 * x[0] + 1; - uj_vector[cell_id][1] = 1 - x[1] * x[2]; - uj_vector[cell_id][2] = x[0] + x[2]; - }); - - return std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(mesh, uj_vector); - }(); - - std::shared_ptr p_other_mesh_Vector3_u = - std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(other_mesh, p_Vector3_u->cellArrays()); - - std::shared_ptr p_Vector3_v = [=] { - CellArray<double> vj_vector{mesh->connectivity(), 3}; - parallel_for( - vj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - vj_vector[cell_id][0] = x[0] * x[1] + 1; - vj_vector[cell_id][1] = 2 * x[1]; - vj_vector[cell_id][2] = x[2] * x[0]; - }); - - return std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(mesh, vj_vector); - }(); - - std::shared_ptr p_Vector2_w = [=] { - CellArray<double> wj_vector{mesh->connectivity(), 2}; - parallel_for( - wj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - wj_vector[cell_id][0] = x[0] + x[1] * 2; - wj_vector[cell_id][1] = x[0] * x[1]; - }); - - return std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(mesh, wj_vector); - }(); - - SECTION("sum") - { - SECTION("Vh + Vh -> Vh") - { - CHECK_SCALAR_VH2_TO_VH(p_R_u, +, p_R_v); - - CHECK_SCALAR_VH2_TO_VH(p_R1_u, +, p_R1_v); - CHECK_SCALAR_VH2_TO_VH(p_R2_u, +, p_R2_v); - CHECK_SCALAR_VH2_TO_VH(p_R3_u, +, p_R3_v); - - CHECK_SCALAR_VH2_TO_VH(p_R1x1_u, +, p_R1x1_v); - CHECK_SCALAR_VH2_TO_VH(p_R2x2_u, +, p_R2x2_v); - CHECK_SCALAR_VH2_TO_VH(p_R3x3_u, +, p_R3x3_v); - - CHECK_VECTOR_VH2_TO_VH(p_Vector3_u, +, p_Vector3_v); - - REQUIRE_THROWS_WITH(p_R_u + p_R1_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(p_R2_u + p_R1_v, "error: incompatible operand types Vh(P0:R^2) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(p_R3_u + p_R1x1_v, "error: incompatible operand types Vh(P0:R^3) and Vh(P0:R^1x1)"); - REQUIRE_THROWS_WITH(p_R_u + p_R2x2_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^2x2)"); - REQUIRE_THROWS_WITH(p_R_u + p_R2x2_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^2x2)"); - REQUIRE_THROWS_WITH(p_Vector3_u + p_R_v, "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R)"); - REQUIRE_THROWS_WITH(p_Vector3_u + p_Vector2_w, "error: Vh(P0Vector:R) spaces have different sizes"); - - REQUIRE_THROWS_WITH(p_R_u + p_other_mesh_R_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R1_u + p_other_mesh_R1_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R2_u + p_other_mesh_R2_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R3_u + p_other_mesh_R3_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R1x1_u + p_other_mesh_R1x1_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R2x2_u + p_other_mesh_R2x2_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R3x3_u + p_other_mesh_R3x3_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_Vector3_u + p_other_mesh_Vector3_u, "error: operands are defined on different meshes"); - } - - SECTION("Vh + X -> Vh") - { - CHECK_SCALAR_VHxX_TO_VH(p_R_u, +, bool{true}); - CHECK_SCALAR_VHxX_TO_VH(p_R_u, +, uint64_t{1}); - CHECK_SCALAR_VHxX_TO_VH(p_R_u, +, int64_t{2}); - CHECK_SCALAR_VHxX_TO_VH(p_R_u, +, double{1.3}); - - CHECK_SCALAR_VHxX_TO_VH(p_R1_u, +, (TinyVector<1>{1.3})); - CHECK_SCALAR_VHxX_TO_VH(p_R2_u, +, (TinyVector<2>{1.2, 2.3})); - CHECK_SCALAR_VHxX_TO_VH(p_R3_u, +, (TinyVector<3>{3.2, 7.1, 5.2})); - - CHECK_SCALAR_VHxX_TO_VH(p_R1x1_u, +, (TinyMatrix<1>{1.3})); - CHECK_SCALAR_VHxX_TO_VH(p_R2x2_u, +, (TinyMatrix<2>{1.2, 2.3, 4.2, 5.1})); - CHECK_SCALAR_VHxX_TO_VH(p_R3x3_u, +, - (TinyMatrix<3>{3.2, 7.1, 5.2, // - 4.7, 2.3, 7.1, // - 9.7, 3.2, 6.8})); - - REQUIRE_THROWS_WITH(p_R_u + (TinyVector<1>{1}), "error: incompatible operand types Vh(P0:R) and R^1"); - REQUIRE_THROWS_WITH(p_R_u + (TinyVector<2>{1, 2}), "error: incompatible operand types Vh(P0:R) and R^2"); - REQUIRE_THROWS_WITH(p_R_u + (TinyVector<3>{2, 3, 2}), "error: incompatible operand types Vh(P0:R) and R^3"); - REQUIRE_THROWS_WITH(p_R_u + (TinyMatrix<1>{2}), "error: incompatible operand types Vh(P0:R) and R^1x1"); - REQUIRE_THROWS_WITH(p_R_u + (TinyMatrix<2>{2, 3, 1, 4}), - "error: incompatible operand types Vh(P0:R) and R^2x2"); - REQUIRE_THROWS_WITH(p_R_u + (TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}), - "error: incompatible operand types Vh(P0:R) and R^3x3"); - - REQUIRE_THROWS_WITH(p_Vector3_u + (double{1}), "error: incompatible operand types Vh(P0Vector:R) and R"); - REQUIRE_THROWS_WITH(p_Vector3_u + (TinyVector<1>{1}), - "error: incompatible operand types Vh(P0Vector:R) and R^1"); - REQUIRE_THROWS_WITH(p_Vector3_u + (TinyVector<2>{1, 2}), - "error: incompatible operand types Vh(P0Vector:R) and R^2"); - } - - SECTION("X + Vh -> Vh") - { - CHECK_SCALAR_XxVH_TO_VH(bool{true}, +, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(uint64_t{1}, +, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(int64_t{2}, +, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(double{1.3}, +, p_R_u); - - CHECK_SCALAR_XxVH_TO_VH((TinyVector<1>{1.3}), +, p_R1_u); - CHECK_SCALAR_XxVH_TO_VH((TinyVector<2>{1.2, 2.3}), +, p_R2_u); - CHECK_SCALAR_XxVH_TO_VH((TinyVector<3>{3.2, 7.1, 5.2}), +, p_R3_u); - - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<1>{1.3}), +, p_R1x1_u); - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<2>{1.2, 2.3, 4.2, 5.1}), +, p_R2x2_u); - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<3>{3.2, 7.1, 5.2, // - 4.7, 2.3, 7.1, // - 9.7, 3.2, 6.8}), - +, p_R3x3_u); - - REQUIRE_THROWS_WITH((TinyVector<1>{1}) + p_R_u, "error: incompatible operand types R^1 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyVector<2>{1, 2}) + p_R_u, "error: incompatible operand types R^2 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyVector<3>{2, 3, 2}) + p_R_u, "error: incompatible operand types R^3 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) + p_R_u, "error: incompatible operand types R^1x1 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) + p_R_u, - "error: incompatible operand types R^2x2 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) + p_R_u, - "error: incompatible operand types R^3x3 and Vh(P0:R)"); - - REQUIRE_THROWS_WITH((double{1}) + p_Vector3_u, "error: incompatible operand types R and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH((TinyVector<1>{1}) + p_Vector3_u, - "error: incompatible operand types R^1 and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH((TinyVector<2>{1, 2}) + p_Vector3_u, - "error: incompatible operand types R^2 and Vh(P0Vector:R)"); - } - } - - SECTION("difference") - { - SECTION("Vh - Vh -> Vh") - { - CHECK_SCALAR_VH2_TO_VH(p_R_u, -, p_R_v); - - CHECK_SCALAR_VH2_TO_VH(p_R1_u, -, p_R1_v); - CHECK_SCALAR_VH2_TO_VH(p_R2_u, -, p_R2_v); - CHECK_SCALAR_VH2_TO_VH(p_R3_u, -, p_R3_v); - - CHECK_SCALAR_VH2_TO_VH(p_R1x1_u, -, p_R1x1_v); - CHECK_SCALAR_VH2_TO_VH(p_R2x2_u, -, p_R2x2_v); - CHECK_SCALAR_VH2_TO_VH(p_R3x3_u, -, p_R3x3_v); - - CHECK_VECTOR_VH2_TO_VH(p_Vector3_u, -, p_Vector3_v); - - REQUIRE_THROWS_WITH(p_R_u - p_R1_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(p_R2_u - p_R1_v, "error: incompatible operand types Vh(P0:R^2) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(p_R3_u - p_R1x1_v, "error: incompatible operand types Vh(P0:R^3) and Vh(P0:R^1x1)"); - REQUIRE_THROWS_WITH(p_R_u - p_R2x2_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^2x2)"); - REQUIRE_THROWS_WITH(p_Vector3_u - p_R_v, "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R)"); - REQUIRE_THROWS_WITH(p_Vector3_u - p_Vector2_w, "error: Vh(P0Vector:R) spaces have different sizes"); - - REQUIRE_THROWS_WITH(p_R_u - p_other_mesh_R_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R1_u - p_other_mesh_R1_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R2_u - p_other_mesh_R2_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R3_u - p_other_mesh_R3_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R1x1_u - p_other_mesh_R1x1_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R2x2_u - p_other_mesh_R2x2_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R3x3_u - p_other_mesh_R3x3_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_Vector3_u - p_other_mesh_Vector3_u, "error: operands are defined on different meshes"); - } - - SECTION("Vh - X -> Vh") - { - CHECK_SCALAR_VHxX_TO_VH(p_R_u, -, bool{true}); - CHECK_SCALAR_VHxX_TO_VH(p_R_u, -, uint64_t{1}); - CHECK_SCALAR_VHxX_TO_VH(p_R_u, -, int64_t{2}); - CHECK_SCALAR_VHxX_TO_VH(p_R_u, -, double{1.3}); - - CHECK_SCALAR_VHxX_TO_VH(p_R1_u, -, (TinyVector<1>{1.3})); - CHECK_SCALAR_VHxX_TO_VH(p_R2_u, -, (TinyVector<2>{1.2, 2.3})); - CHECK_SCALAR_VHxX_TO_VH(p_R3_u, -, (TinyVector<3>{3.2, 7.1, 5.2})); - - CHECK_SCALAR_VHxX_TO_VH(p_R1x1_u, -, (TinyMatrix<1>{1.3})); - CHECK_SCALAR_VHxX_TO_VH(p_R2x2_u, -, (TinyMatrix<2>{1.2, 2.3, 4.2, 5.1})); - CHECK_SCALAR_VHxX_TO_VH(p_R3x3_u, -, - (TinyMatrix<3>{3.2, 7.1, 5.2, // - 4.7, 2.3, 7.1, // - 9.7, 3.2, 6.8})); - - REQUIRE_THROWS_WITH(p_R_u - (TinyVector<1>{1}), "error: incompatible operand types Vh(P0:R) and R^1"); - REQUIRE_THROWS_WITH(p_R_u - (TinyVector<2>{1, 2}), "error: incompatible operand types Vh(P0:R) and R^2"); - REQUIRE_THROWS_WITH(p_R_u - (TinyVector<3>{2, 3, 2}), "error: incompatible operand types Vh(P0:R) and R^3"); - REQUIRE_THROWS_WITH(p_R_u - (TinyMatrix<1>{2}), "error: incompatible operand types Vh(P0:R) and R^1x1"); - REQUIRE_THROWS_WITH(p_R_u - (TinyMatrix<2>{2, 3, 1, 4}), - "error: incompatible operand types Vh(P0:R) and R^2x2"); - REQUIRE_THROWS_WITH(p_R_u - (TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}), - "error: incompatible operand types Vh(P0:R) and R^3x3"); - - REQUIRE_THROWS_WITH(p_Vector3_u - (double{1}), "error: incompatible operand types Vh(P0Vector:R) and R"); - REQUIRE_THROWS_WITH(p_Vector3_u - (TinyVector<1>{1}), - "error: incompatible operand types Vh(P0Vector:R) and R^1"); - REQUIRE_THROWS_WITH(p_Vector3_u - (TinyVector<2>{1, 2}), - "error: incompatible operand types Vh(P0Vector:R) and R^2"); - } - - SECTION("X - Vh -> Vh") - { - CHECK_SCALAR_XxVH_TO_VH(bool{true}, -, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(uint64_t{1}, -, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(int64_t{2}, -, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(double{1.3}, -, p_R_u); - - CHECK_SCALAR_XxVH_TO_VH((TinyVector<1>{1.3}), -, p_R1_u); - CHECK_SCALAR_XxVH_TO_VH((TinyVector<2>{1.2, 2.3}), -, p_R2_u); - CHECK_SCALAR_XxVH_TO_VH((TinyVector<3>{3.2, 7.1, 5.2}), -, p_R3_u); - - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<1>{1.3}), -, p_R1x1_u); - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<2>{1.2, 2.3, 4.2, 5.1}), -, p_R2x2_u); - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<3>{3.2, 7.1, 5.2, // - 4.7, 2.3, 7.1, // - 9.7, 3.2, 6.8}), - -, p_R3x3_u); - - REQUIRE_THROWS_WITH((TinyVector<1>{1}) - p_R_u, "error: incompatible operand types R^1 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyVector<2>{1, 2}) - p_R_u, "error: incompatible operand types R^2 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyVector<3>{2, 3, 2}) - p_R_u, "error: incompatible operand types R^3 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) - p_R_u, "error: incompatible operand types R^1x1 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) - p_R_u, - "error: incompatible operand types R^2x2 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) - p_R_u, - "error: incompatible operand types R^3x3 and Vh(P0:R)"); - - REQUIRE_THROWS_WITH((double{1}) - p_Vector3_u, "error: incompatible operand types R and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH((TinyVector<1>{1}) - p_Vector3_u, - "error: incompatible operand types R^1 and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH((TinyVector<2>{1, 2}) - p_Vector3_u, - "error: incompatible operand types R^2 and Vh(P0Vector:R)"); - } - } + std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - SECTION("product") - { - SECTION("Vh * Vh -> Vh") + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) { - CHECK_SCALAR_VH2_TO_VH(p_R_u, *, p_R_v); - - CHECK_SCALAR_VH2_TO_VH(p_R1x1_u, *, p_R1x1_v); - CHECK_SCALAR_VH2_TO_VH(p_R2x2_u, *, p_R2x2_v); - CHECK_SCALAR_VH2_TO_VH(p_R3x3_u, *, p_R3x3_v); - - CHECK_SCALAR_VH2_TO_VH(p_R_u, *, p_R1_v); - CHECK_SCALAR_VH2_TO_VH(p_R_u, *, p_R2_v); - CHECK_SCALAR_VH2_TO_VH(p_R_u, *, p_R3_v); + auto mesh = named_mesh.mesh(); + + std::shared_ptr other_mesh = + std::make_shared<Mesh<Connectivity<Dimension>>>(mesh->shared_connectivity(), mesh->xr()); + + CellValue<const Rd> xj = MeshDataManager::instance().getMeshData(*mesh).xj(); + + CellValue<double> u_R_values = [=] { + CellValue<double> build_values{mesh->connectivity()}; + parallel_for( + build_values.numberOfItems(), + PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 0.2 + std::cos(l2Norm(xj[cell_id])); }); + return build_values; + }(); + + CellValue<double> v_R_values = [=] { + CellValue<double> build_values{mesh->connectivity()}; + parallel_for( + build_values.numberOfItems(), + PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 0.6 + std::sin(l2Norm(xj[cell_id])); }); + return build_values; + }(); + + std::shared_ptr p_R_u = std::make_shared<const DiscreteFunctionP0<Dimension, double>>(mesh, u_R_values); + std::shared_ptr p_other_mesh_R_u = + std::make_shared<const DiscreteFunctionP0<Dimension, double>>(other_mesh, u_R_values); + std::shared_ptr p_R_v = std::make_shared<const DiscreteFunctionP0<Dimension, double>>(mesh, v_R_values); + + std::shared_ptr p_R1_u = [=] { + CellValue<TinyVector<1>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { uj[cell_id][0] = 2 * xj[cell_id][0] + 1; }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<1>>>(mesh, uj); + }(); + + std::shared_ptr p_R1_v = [=] { + CellValue<TinyVector<1>> vj{mesh->connectivity()}; + parallel_for( + vj.numberOfItems(), + PUGS_LAMBDA(const CellId cell_id) { vj[cell_id][0] = xj[cell_id][0] * xj[cell_id][0] + 1; }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<1>>>(mesh, vj); + }(); + + std::shared_ptr p_other_mesh_R1_u = + std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<1>>>(other_mesh, p_R1_u->cellValues()); + + constexpr auto to_2d = [&](const TinyVector<Dimension>& x) -> TinyVector<2> { + if constexpr (Dimension == 1) { + return {x[0], 1 + x[0] * x[0]}; + } else if constexpr (Dimension == 2) { + return {x[0], x[1]}; + } else if constexpr (Dimension == 3) { + return {x[0], x[1] + x[2]}; + } + }; + + std::shared_ptr p_R2_u = [=] { + CellValue<TinyVector<2>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<2> x = to_2d(xj[cell_id]); + uj[cell_id] = {2 * x[0] + 1, 1 - x[1]}; + }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<2>>>(mesh, uj); + }(); + + std::shared_ptr p_R2_v = [=] { + CellValue<TinyVector<2>> vj{mesh->connectivity()}; + parallel_for( + vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<2> x = to_2d(xj[cell_id]); + vj[cell_id] = {x[0] * x[1] + 1, 2 * x[1]}; + }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<2>>>(mesh, vj); + }(); + + std::shared_ptr p_other_mesh_R2_u = + std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<2>>>(other_mesh, p_R2_u->cellValues()); + + constexpr auto to_3d = [&](const TinyVector<Dimension>& x) -> TinyVector<3> { + if constexpr (Dimension == 1) { + return {x[0], 1 + x[0] * x[0], 2 - x[0]}; + } else if constexpr (Dimension == 2) { + return {x[0], x[1], x[0] + x[1]}; + } else if constexpr (Dimension == 3) { + return {x[0], x[1], x[2]}; + } + }; + + std::shared_ptr p_R3_u = [=] { + CellValue<TinyVector<3>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + uj[cell_id] = {2 * x[0] + 1, 1 - x[1] * x[2], x[0] + x[2]}; + }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<3>>>(mesh, uj); + }(); + + std::shared_ptr p_R3_v = [=] { + CellValue<TinyVector<3>> vj{mesh->connectivity()}; + parallel_for( + vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + vj[cell_id] = {x[0] * x[1] + 1, 2 * x[1], x[2] * x[0]}; + }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<3>>>(mesh, vj); + }(); + + std::shared_ptr p_other_mesh_R3_u = + std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<3>>>(other_mesh, p_R3_u->cellValues()); + + std::shared_ptr p_R1x1_u = [=] { + CellValue<TinyMatrix<1>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { uj[cell_id] = {2 * xj[cell_id][0] + 1}; }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<1>>>(mesh, uj); + }(); + + std::shared_ptr p_other_mesh_R1x1_u = + std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<1>>>(other_mesh, p_R1x1_u->cellValues()); + + std::shared_ptr p_R1x1_v = [=] { + CellValue<TinyMatrix<1>> vj{mesh->connectivity()}; + parallel_for( + vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { vj[cell_id] = {0.3 - xj[cell_id][0]}; }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<1>>>(mesh, vj); + }(); + + std::shared_ptr p_R2x2_u = [=] { + CellValue<TinyMatrix<2>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<2> x = to_2d(xj[cell_id]); + + uj[cell_id] = {2 * x[0] + 1, 1 - x[1], // + 2 * x[1], -x[0]}; + }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<2>>>(mesh, uj); + }(); + + std::shared_ptr p_other_mesh_R2x2_u = + std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<2>>>(other_mesh, p_R2x2_u->cellValues()); + + std::shared_ptr p_R2x2_v = [=] { + CellValue<TinyMatrix<2>> vj{mesh->connectivity()}; + parallel_for( + vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<2> x = to_2d(xj[cell_id]); + + vj[cell_id] = {x[0] + 0.3, 1 - x[1] - x[0], // + 2 * x[1] + x[0], x[1] - x[0]}; + }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<2>>>(mesh, vj); + }(); + + std::shared_ptr p_R3x3_u = [=] { + CellValue<TinyMatrix<3>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + + uj[cell_id] = {2 * x[0] + 1, 1 - x[1], 3, // + 2 * x[1], -x[0], x[0] - x[1], // + 3 * x[2] - x[1], x[1] - 2 * x[2], x[2] - x[0]}; + }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<3>>>(mesh, uj); + }(); + + std::shared_ptr p_other_mesh_R3x3_u = + std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<3>>>(other_mesh, p_R3x3_u->cellValues()); + + std::shared_ptr p_R3x3_v = [=] { + CellValue<TinyMatrix<3>> vj{mesh->connectivity()}; + parallel_for( + vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + + vj[cell_id] = {0.2 * x[0] + 1, 2 + x[1], 3 - x[2], // + 2.3 * x[2], x[1] - x[0], x[2] - x[1], // + 2 * x[2] + x[0], x[1] + 0.2 * x[2], x[2] - 2 * x[0]}; + }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<3>>>(mesh, vj); + }(); + + std::shared_ptr p_Vector3_u = [=] { + CellArray<double> uj_vector{mesh->connectivity(), 3}; + parallel_for( + uj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + uj_vector[cell_id][0] = 2 * x[0] + 1; + uj_vector[cell_id][1] = 1 - x[1] * x[2]; + uj_vector[cell_id][2] = x[0] + x[2]; + }); + + return std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(mesh, uj_vector); + }(); + + std::shared_ptr p_other_mesh_Vector3_u = + std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(other_mesh, p_Vector3_u->cellArrays()); + + std::shared_ptr p_Vector3_v = [=] { + CellArray<double> vj_vector{mesh->connectivity(), 3}; + parallel_for( + vj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + vj_vector[cell_id][0] = x[0] * x[1] + 1; + vj_vector[cell_id][1] = 2 * x[1]; + vj_vector[cell_id][2] = x[2] * x[0]; + }); + + return std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(mesh, vj_vector); + }(); + + std::shared_ptr p_Vector2_w = [=] { + CellArray<double> wj_vector{mesh->connectivity(), 2}; + parallel_for( + wj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + wj_vector[cell_id][0] = x[0] + x[1] * 2; + wj_vector[cell_id][1] = x[0] * x[1]; + }); + + return std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(mesh, wj_vector); + }(); + + SECTION("sum") + { + SECTION("Vh + Vh -> Vh") + { + CHECK_SCALAR_VH2_TO_VH(p_R_u, +, p_R_v); + + CHECK_SCALAR_VH2_TO_VH(p_R1_u, +, p_R1_v); + CHECK_SCALAR_VH2_TO_VH(p_R2_u, +, p_R2_v); + CHECK_SCALAR_VH2_TO_VH(p_R3_u, +, p_R3_v); + + CHECK_SCALAR_VH2_TO_VH(p_R1x1_u, +, p_R1x1_v); + CHECK_SCALAR_VH2_TO_VH(p_R2x2_u, +, p_R2x2_v); + CHECK_SCALAR_VH2_TO_VH(p_R3x3_u, +, p_R3x3_v); + + CHECK_VECTOR_VH2_TO_VH(p_Vector3_u, +, p_Vector3_v); + + REQUIRE_THROWS_WITH(p_R_u + p_R1_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(p_R2_u + p_R1_v, "error: incompatible operand types Vh(P0:R^2) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(p_R3_u + p_R1x1_v, "error: incompatible operand types Vh(P0:R^3) and Vh(P0:R^1x1)"); + REQUIRE_THROWS_WITH(p_R_u + p_R2x2_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^2x2)"); + REQUIRE_THROWS_WITH(p_R_u + p_R2x2_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^2x2)"); + REQUIRE_THROWS_WITH(p_Vector3_u + p_R_v, "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R)"); + REQUIRE_THROWS_WITH(p_Vector3_u + p_Vector2_w, "error: Vh(P0Vector:R) spaces have different sizes"); + + REQUIRE_THROWS_WITH(p_R_u + p_other_mesh_R_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R1_u + p_other_mesh_R1_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R2_u + p_other_mesh_R2_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R3_u + p_other_mesh_R3_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R1x1_u + p_other_mesh_R1x1_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R2x2_u + p_other_mesh_R2x2_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R3x3_u + p_other_mesh_R3x3_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_Vector3_u + p_other_mesh_Vector3_u, + "error: operands are defined on different meshes"); + } - CHECK_SCALAR_VH2_TO_VH(p_R_u, *, p_R1x1_v); - CHECK_SCALAR_VH2_TO_VH(p_R_u, *, p_R2x2_v); - CHECK_SCALAR_VH2_TO_VH(p_R_u, *, p_R3x3_v); + SECTION("Vh + X -> Vh") + { + CHECK_SCALAR_VHxX_TO_VH(p_R_u, +, bool{true}); + CHECK_SCALAR_VHxX_TO_VH(p_R_u, +, uint64_t{1}); + CHECK_SCALAR_VHxX_TO_VH(p_R_u, +, int64_t{2}); + CHECK_SCALAR_VHxX_TO_VH(p_R_u, +, double{1.3}); + + CHECK_SCALAR_VHxX_TO_VH(p_R1_u, +, (TinyVector<1>{1.3})); + CHECK_SCALAR_VHxX_TO_VH(p_R2_u, +, (TinyVector<2>{1.2, 2.3})); + CHECK_SCALAR_VHxX_TO_VH(p_R3_u, +, (TinyVector<3>{3.2, 7.1, 5.2})); + + CHECK_SCALAR_VHxX_TO_VH(p_R1x1_u, +, (TinyMatrix<1>{1.3})); + CHECK_SCALAR_VHxX_TO_VH(p_R2x2_u, +, (TinyMatrix<2>{1.2, 2.3, 4.2, 5.1})); + CHECK_SCALAR_VHxX_TO_VH(p_R3x3_u, +, + (TinyMatrix<3>{3.2, 7.1, 5.2, // + 4.7, 2.3, 7.1, // + 9.7, 3.2, 6.8})); + + REQUIRE_THROWS_WITH(p_R_u + (TinyVector<1>{1}), "error: incompatible operand types Vh(P0:R) and R^1"); + REQUIRE_THROWS_WITH(p_R_u + (TinyVector<2>{1, 2}), "error: incompatible operand types Vh(P0:R) and R^2"); + REQUIRE_THROWS_WITH(p_R_u + (TinyVector<3>{2, 3, 2}), + "error: incompatible operand types Vh(P0:R) and R^3"); + REQUIRE_THROWS_WITH(p_R_u + (TinyMatrix<1>{2}), "error: incompatible operand types Vh(P0:R) and R^1x1"); + REQUIRE_THROWS_WITH(p_R_u + (TinyMatrix<2>{2, 3, 1, 4}), + "error: incompatible operand types Vh(P0:R) and R^2x2"); + REQUIRE_THROWS_WITH(p_R_u + (TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}), + "error: incompatible operand types Vh(P0:R) and R^3x3"); + + REQUIRE_THROWS_WITH(p_Vector3_u + (double{1}), "error: incompatible operand types Vh(P0Vector:R) and R"); + REQUIRE_THROWS_WITH(p_Vector3_u + (TinyVector<1>{1}), + "error: incompatible operand types Vh(P0Vector:R) and R^1"); + REQUIRE_THROWS_WITH(p_Vector3_u + (TinyVector<2>{1, 2}), + "error: incompatible operand types Vh(P0Vector:R) and R^2"); + } - CHECK_SCALAR_VH2_TO_VH(p_R1x1_u, *, p_R1_v); - CHECK_SCALAR_VH2_TO_VH(p_R2x2_u, *, p_R2_v); - CHECK_SCALAR_VH2_TO_VH(p_R3x3_u, *, p_R3_v); + SECTION("X + Vh -> Vh") + { + CHECK_SCALAR_XxVH_TO_VH(bool{true}, +, p_R_u); + CHECK_SCALAR_XxVH_TO_VH(uint64_t{1}, +, p_R_u); + CHECK_SCALAR_XxVH_TO_VH(int64_t{2}, +, p_R_u); + CHECK_SCALAR_XxVH_TO_VH(double{1.3}, +, p_R_u); + + CHECK_SCALAR_XxVH_TO_VH((TinyVector<1>{1.3}), +, p_R1_u); + CHECK_SCALAR_XxVH_TO_VH((TinyVector<2>{1.2, 2.3}), +, p_R2_u); + CHECK_SCALAR_XxVH_TO_VH((TinyVector<3>{3.2, 7.1, 5.2}), +, p_R3_u); + + CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<1>{1.3}), +, p_R1x1_u); + CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<2>{1.2, 2.3, 4.2, 5.1}), +, p_R2x2_u); + CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<3>{3.2, 7.1, 5.2, // + 4.7, 2.3, 7.1, // + 9.7, 3.2, 6.8}), + +, p_R3x3_u); + + REQUIRE_THROWS_WITH((TinyVector<1>{1}) + p_R_u, "error: incompatible operand types R^1 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyVector<2>{1, 2}) + p_R_u, "error: incompatible operand types R^2 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyVector<3>{2, 3, 2}) + p_R_u, + "error: incompatible operand types R^3 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) + p_R_u, "error: incompatible operand types R^1x1 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) + p_R_u, + "error: incompatible operand types R^2x2 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) + p_R_u, + "error: incompatible operand types R^3x3 and Vh(P0:R)"); + + REQUIRE_THROWS_WITH((double{1}) + p_Vector3_u, "error: incompatible operand types R and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH((TinyVector<1>{1}) + p_Vector3_u, + "error: incompatible operand types R^1 and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH((TinyVector<2>{1, 2}) + p_Vector3_u, + "error: incompatible operand types R^2 and Vh(P0Vector:R)"); + } + } + SECTION("difference") { - std::shared_ptr p_fuv = p_R_u * p_Vector3_v; + SECTION("Vh - Vh -> Vh") + { + CHECK_SCALAR_VH2_TO_VH(p_R_u, -, p_R_v); + + CHECK_SCALAR_VH2_TO_VH(p_R1_u, -, p_R1_v); + CHECK_SCALAR_VH2_TO_VH(p_R2_u, -, p_R2_v); + CHECK_SCALAR_VH2_TO_VH(p_R3_u, -, p_R3_v); + + CHECK_SCALAR_VH2_TO_VH(p_R1x1_u, -, p_R1x1_v); + CHECK_SCALAR_VH2_TO_VH(p_R2x2_u, -, p_R2x2_v); + CHECK_SCALAR_VH2_TO_VH(p_R3x3_u, -, p_R3x3_v); + + CHECK_VECTOR_VH2_TO_VH(p_Vector3_u, -, p_Vector3_v); + + REQUIRE_THROWS_WITH(p_R_u - p_R1_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(p_R2_u - p_R1_v, "error: incompatible operand types Vh(P0:R^2) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(p_R3_u - p_R1x1_v, "error: incompatible operand types Vh(P0:R^3) and Vh(P0:R^1x1)"); + REQUIRE_THROWS_WITH(p_R_u - p_R2x2_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^2x2)"); + REQUIRE_THROWS_WITH(p_Vector3_u - p_R_v, "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R)"); + REQUIRE_THROWS_WITH(p_Vector3_u - p_Vector2_w, "error: Vh(P0Vector:R) spaces have different sizes"); + + REQUIRE_THROWS_WITH(p_R_u - p_other_mesh_R_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R1_u - p_other_mesh_R1_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R2_u - p_other_mesh_R2_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R3_u - p_other_mesh_R3_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R1x1_u - p_other_mesh_R1x1_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R2x2_u - p_other_mesh_R2x2_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R3x3_u - p_other_mesh_R3x3_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_Vector3_u - p_other_mesh_Vector3_u, + "error: operands are defined on different meshes"); + } - REQUIRE(p_fuv.use_count() > 0); - REQUIRE_NOTHROW(dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*p_fuv)); + SECTION("Vh - X -> Vh") + { + CHECK_SCALAR_VHxX_TO_VH(p_R_u, -, bool{true}); + CHECK_SCALAR_VHxX_TO_VH(p_R_u, -, uint64_t{1}); + CHECK_SCALAR_VHxX_TO_VH(p_R_u, -, int64_t{2}); + CHECK_SCALAR_VHxX_TO_VH(p_R_u, -, double{1.3}); + + CHECK_SCALAR_VHxX_TO_VH(p_R1_u, -, (TinyVector<1>{1.3})); + CHECK_SCALAR_VHxX_TO_VH(p_R2_u, -, (TinyVector<2>{1.2, 2.3})); + CHECK_SCALAR_VHxX_TO_VH(p_R3_u, -, (TinyVector<3>{3.2, 7.1, 5.2})); + + CHECK_SCALAR_VHxX_TO_VH(p_R1x1_u, -, (TinyMatrix<1>{1.3})); + CHECK_SCALAR_VHxX_TO_VH(p_R2x2_u, -, (TinyMatrix<2>{1.2, 2.3, 4.2, 5.1})); + CHECK_SCALAR_VHxX_TO_VH(p_R3x3_u, -, + (TinyMatrix<3>{3.2, 7.1, 5.2, // + 4.7, 2.3, 7.1, // + 9.7, 3.2, 6.8})); + + REQUIRE_THROWS_WITH(p_R_u - (TinyVector<1>{1}), "error: incompatible operand types Vh(P0:R) and R^1"); + REQUIRE_THROWS_WITH(p_R_u - (TinyVector<2>{1, 2}), "error: incompatible operand types Vh(P0:R) and R^2"); + REQUIRE_THROWS_WITH(p_R_u - (TinyVector<3>{2, 3, 2}), + "error: incompatible operand types Vh(P0:R) and R^3"); + REQUIRE_THROWS_WITH(p_R_u - (TinyMatrix<1>{2}), "error: incompatible operand types Vh(P0:R) and R^1x1"); + REQUIRE_THROWS_WITH(p_R_u - (TinyMatrix<2>{2, 3, 1, 4}), + "error: incompatible operand types Vh(P0:R) and R^2x2"); + REQUIRE_THROWS_WITH(p_R_u - (TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}), + "error: incompatible operand types Vh(P0:R) and R^3x3"); + + REQUIRE_THROWS_WITH(p_Vector3_u - (double{1}), "error: incompatible operand types Vh(P0Vector:R) and R"); + REQUIRE_THROWS_WITH(p_Vector3_u - (TinyVector<1>{1}), + "error: incompatible operand types Vh(P0Vector:R) and R^1"); + REQUIRE_THROWS_WITH(p_Vector3_u - (TinyVector<2>{1, 2}), + "error: incompatible operand types Vh(P0Vector:R) and R^2"); + } - const auto& fuv = dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*p_fuv); + SECTION("X - Vh -> Vh") + { + CHECK_SCALAR_XxVH_TO_VH(bool{true}, -, p_R_u); + CHECK_SCALAR_XxVH_TO_VH(uint64_t{1}, -, p_R_u); + CHECK_SCALAR_XxVH_TO_VH(int64_t{2}, -, p_R_u); + CHECK_SCALAR_XxVH_TO_VH(double{1.3}, -, p_R_u); + + CHECK_SCALAR_XxVH_TO_VH((TinyVector<1>{1.3}), -, p_R1_u); + CHECK_SCALAR_XxVH_TO_VH((TinyVector<2>{1.2, 2.3}), -, p_R2_u); + CHECK_SCALAR_XxVH_TO_VH((TinyVector<3>{3.2, 7.1, 5.2}), -, p_R3_u); + + CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<1>{1.3}), -, p_R1x1_u); + CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<2>{1.2, 2.3, 4.2, 5.1}), -, p_R2x2_u); + CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<3>{3.2, 7.1, 5.2, // + 4.7, 2.3, 7.1, // + 9.7, 3.2, 6.8}), + -, p_R3x3_u); + + REQUIRE_THROWS_WITH((TinyVector<1>{1}) - p_R_u, "error: incompatible operand types R^1 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyVector<2>{1, 2}) - p_R_u, "error: incompatible operand types R^2 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyVector<3>{2, 3, 2}) - p_R_u, + "error: incompatible operand types R^3 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) - p_R_u, "error: incompatible operand types R^1x1 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) - p_R_u, + "error: incompatible operand types R^2x2 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) - p_R_u, + "error: incompatible operand types R^3x3 and Vh(P0:R)"); + + REQUIRE_THROWS_WITH((double{1}) - p_Vector3_u, "error: incompatible operand types R and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH((TinyVector<1>{1}) - p_Vector3_u, + "error: incompatible operand types R^1 and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH((TinyVector<2>{1, 2}) - p_Vector3_u, + "error: incompatible operand types R^2 and Vh(P0Vector:R)"); + } + } - auto lhs_values = p_R_u->cellValues(); - auto rhs_arrays = p_Vector3_v->cellArrays(); - bool is_same = true; - for (CellId cell_id = 0; cell_id < lhs_values.numberOfItems(); ++cell_id) { - for (size_t i = 0; i < fuv.size(); ++i) { - if (fuv[cell_id][i] != (lhs_values[cell_id] * rhs_arrays[cell_id][i])) { - is_same = false; - break; + SECTION("product") + { + SECTION("Vh * Vh -> Vh") + { + CHECK_SCALAR_VH2_TO_VH(p_R_u, *, p_R_v); + + CHECK_SCALAR_VH2_TO_VH(p_R1x1_u, *, p_R1x1_v); + CHECK_SCALAR_VH2_TO_VH(p_R2x2_u, *, p_R2x2_v); + CHECK_SCALAR_VH2_TO_VH(p_R3x3_u, *, p_R3x3_v); + + CHECK_SCALAR_VH2_TO_VH(p_R_u, *, p_R1_v); + CHECK_SCALAR_VH2_TO_VH(p_R_u, *, p_R2_v); + CHECK_SCALAR_VH2_TO_VH(p_R_u, *, p_R3_v); + + CHECK_SCALAR_VH2_TO_VH(p_R_u, *, p_R1x1_v); + CHECK_SCALAR_VH2_TO_VH(p_R_u, *, p_R2x2_v); + CHECK_SCALAR_VH2_TO_VH(p_R_u, *, p_R3x3_v); + + CHECK_SCALAR_VH2_TO_VH(p_R1x1_u, *, p_R1_v); + CHECK_SCALAR_VH2_TO_VH(p_R2x2_u, *, p_R2_v); + CHECK_SCALAR_VH2_TO_VH(p_R3x3_u, *, p_R3_v); + + { + std::shared_ptr p_fuv = p_R_u * p_Vector3_v; + + REQUIRE(p_fuv.use_count() > 0); + REQUIRE_NOTHROW(dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*p_fuv)); + + const auto& fuv = dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*p_fuv); + + auto lhs_values = p_R_u->cellValues(); + auto rhs_arrays = p_Vector3_v->cellArrays(); + bool is_same = true; + for (CellId cell_id = 0; cell_id < lhs_values.numberOfItems(); ++cell_id) { + for (size_t i = 0; i < fuv.size(); ++i) { + if (fuv[cell_id][i] != (lhs_values[cell_id] * rhs_arrays[cell_id][i])) { + is_same = false; + break; + } + } } - } - } - REQUIRE(is_same); - } + REQUIRE(is_same); + } - REQUIRE_THROWS_WITH(p_R1_u * p_R1_v, "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(p_R2_u * p_R1_v, "error: incompatible operand types Vh(P0:R^2) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(p_R3_u * p_R1x1_v, "error: incompatible operand types Vh(P0:R^3) and Vh(P0:R^1x1)"); - REQUIRE_THROWS_WITH(p_R1_u * p_R2x2_v, "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R^2x2)"); - - REQUIRE_THROWS_WITH(p_R1x1_u * p_R2x2_v, "error: incompatible operand types Vh(P0:R^1x1) and Vh(P0:R^2x2)"); - REQUIRE_THROWS_WITH(p_R2x2_u * p_R3x3_v, "error: incompatible operand types Vh(P0:R^2x2) and Vh(P0:R^3x3)"); - REQUIRE_THROWS_WITH(p_R3x3_u * p_R1x1_v, "error: incompatible operand types Vh(P0:R^3x3) and Vh(P0:R^1x1)"); - - REQUIRE_THROWS_WITH(p_R1x1_u * p_R2_v, "error: incompatible operand types Vh(P0:R^1x1) and Vh(P0:R^2)"); - REQUIRE_THROWS_WITH(p_R2x2_u * p_R3_v, "error: incompatible operand types Vh(P0:R^2x2) and Vh(P0:R^3)"); - REQUIRE_THROWS_WITH(p_R3x3_u * p_R1_v, "error: incompatible operand types Vh(P0:R^3x3) and Vh(P0:R^1)"); - - REQUIRE_THROWS_WITH(p_R1_u * p_Vector3_v, "error: incompatible operand types Vh(P0:R^1) and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH(p_R2_u * p_Vector3_v, "error: incompatible operand types Vh(P0:R^2) and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH(p_R3_u * p_Vector3_v, "error: incompatible operand types Vh(P0:R^3) and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH(p_R1x1_u * p_Vector3_v, - "error: incompatible operand types Vh(P0:R^1x1) and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH(p_R2x2_u * p_Vector3_v, - "error: incompatible operand types Vh(P0:R^2x2) and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH(p_R3x3_u * p_Vector3_v, - "error: incompatible operand types Vh(P0:R^3x3) and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH(p_Vector3_u * p_Vector3_v, - "error: incompatible operand types Vh(P0Vector:R) and Vh(P0Vector:R)"); - - REQUIRE_THROWS_WITH(p_Vector3_v * p_R_u, "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R)"); - REQUIRE_THROWS_WITH(p_Vector3_v * p_R1_u, "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(p_Vector3_v * p_R2_u, "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^2)"); - REQUIRE_THROWS_WITH(p_Vector3_v * p_R3_u, "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^3)"); - REQUIRE_THROWS_WITH(p_Vector3_v * p_R1x1_u, - "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^1x1)"); - REQUIRE_THROWS_WITH(p_Vector3_v * p_R2x2_u, - "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^2x2)"); - REQUIRE_THROWS_WITH(p_Vector3_v * p_R3x3_u, - "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^3x3)"); - - REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R1_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R2_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R3_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R1x1_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R2x2_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R3x3_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R1x1_u * p_other_mesh_R1_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R2x2_u * p_other_mesh_R2_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R3x3_u * p_other_mesh_R3_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_Vector3_u, "error: operands are defined on different meshes"); - } + REQUIRE_THROWS_WITH(p_R1_u * p_R1_v, "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(p_R2_u * p_R1_v, "error: incompatible operand types Vh(P0:R^2) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(p_R3_u * p_R1x1_v, "error: incompatible operand types Vh(P0:R^3) and Vh(P0:R^1x1)"); + REQUIRE_THROWS_WITH(p_R1_u * p_R2x2_v, "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R^2x2)"); + + REQUIRE_THROWS_WITH(p_R1x1_u * p_R2x2_v, + "error: incompatible operand types Vh(P0:R^1x1) and Vh(P0:R^2x2)"); + REQUIRE_THROWS_WITH(p_R2x2_u * p_R3x3_v, + "error: incompatible operand types Vh(P0:R^2x2) and Vh(P0:R^3x3)"); + REQUIRE_THROWS_WITH(p_R3x3_u * p_R1x1_v, + "error: incompatible operand types Vh(P0:R^3x3) and Vh(P0:R^1x1)"); + + REQUIRE_THROWS_WITH(p_R1x1_u * p_R2_v, "error: incompatible operand types Vh(P0:R^1x1) and Vh(P0:R^2)"); + REQUIRE_THROWS_WITH(p_R2x2_u * p_R3_v, "error: incompatible operand types Vh(P0:R^2x2) and Vh(P0:R^3)"); + REQUIRE_THROWS_WITH(p_R3x3_u * p_R1_v, "error: incompatible operand types Vh(P0:R^3x3) and Vh(P0:R^1)"); + + REQUIRE_THROWS_WITH(p_R1_u * p_Vector3_v, + "error: incompatible operand types Vh(P0:R^1) and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH(p_R2_u * p_Vector3_v, + "error: incompatible operand types Vh(P0:R^2) and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH(p_R3_u * p_Vector3_v, + "error: incompatible operand types Vh(P0:R^3) and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH(p_R1x1_u * p_Vector3_v, + "error: incompatible operand types Vh(P0:R^1x1) and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH(p_R2x2_u * p_Vector3_v, + "error: incompatible operand types Vh(P0:R^2x2) and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH(p_R3x3_u * p_Vector3_v, + "error: incompatible operand types Vh(P0:R^3x3) and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH(p_Vector3_u * p_Vector3_v, + "error: incompatible operand types Vh(P0Vector:R) and Vh(P0Vector:R)"); + + REQUIRE_THROWS_WITH(p_Vector3_v * p_R_u, "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R)"); + REQUIRE_THROWS_WITH(p_Vector3_v * p_R1_u, + "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(p_Vector3_v * p_R2_u, + "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^2)"); + REQUIRE_THROWS_WITH(p_Vector3_v * p_R3_u, + "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^3)"); + REQUIRE_THROWS_WITH(p_Vector3_v * p_R1x1_u, + "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^1x1)"); + REQUIRE_THROWS_WITH(p_Vector3_v * p_R2x2_u, + "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^2x2)"); + REQUIRE_THROWS_WITH(p_Vector3_v * p_R3x3_u, + "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^3x3)"); + + REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R1_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R2_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R3_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R1x1_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R2x2_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R3x3_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R1x1_u * p_other_mesh_R1_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R2x2_u * p_other_mesh_R2_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R3x3_u * p_other_mesh_R3_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_Vector3_u, "error: operands are defined on different meshes"); + } - SECTION("Vh * X -> Vh") - { - CHECK_SCALAR_VHxX_TO_VH(p_R_u, *, bool{true}); - CHECK_SCALAR_VHxX_TO_VH(p_R_u, *, uint64_t{1}); - CHECK_SCALAR_VHxX_TO_VH(p_R_u, *, int64_t{2}); - CHECK_SCALAR_VHxX_TO_VH(p_R_u, *, double{1.3}); - - CHECK_SCALAR_VHxX_TO_VH(p_R1x1_u, *, (TinyMatrix<1>{1.3})); - CHECK_SCALAR_VHxX_TO_VH(p_R2x2_u, *, (TinyMatrix<2>{1.2, 2.3, 4.2, 5.1})); - CHECK_SCALAR_VHxX_TO_VH(p_R3x3_u, *, - (TinyMatrix<3>{3.2, 7.1, 5.2, // - 4.7, 2.3, 7.1, // - 9.7, 3.2, 6.8})); - - REQUIRE_THROWS_WITH(p_R1_u * (TinyVector<1>{1}), "error: incompatible operand types Vh(P0:R^1) and R^1"); - REQUIRE_THROWS_WITH(p_R2_u * (TinyVector<2>{1, 2}), "error: incompatible operand types Vh(P0:R^2) and R^2"); - REQUIRE_THROWS_WITH(p_R3_u * (TinyVector<3>{2, 3, 2}), - "error: incompatible operand types Vh(P0:R^3) and R^3"); - REQUIRE_THROWS_WITH(p_R1_u * (TinyMatrix<1>{2}), "error: incompatible operand types Vh(P0:R^1) and R^1x1"); - REQUIRE_THROWS_WITH(p_R2_u * (TinyMatrix<2>{2, 3, 1, 4}), - "error: incompatible operand types Vh(P0:R^2) and R^2x2"); - REQUIRE_THROWS_WITH(p_R3_u * (TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}), - "error: incompatible operand types Vh(P0:R^3) and R^3x3"); - REQUIRE_THROWS_WITH(p_R2x2_u * (TinyMatrix<1>{2}), - "error: incompatible operand types Vh(P0:R^2x2) and R^1x1"); - REQUIRE_THROWS_WITH(p_R1x1_u * (TinyMatrix<2>{2, 3, 1, 4}), - "error: incompatible operand types Vh(P0:R^1x1) and R^2x2"); - REQUIRE_THROWS_WITH(p_R2x2_u * (TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}), - "error: incompatible operand types Vh(P0:R^2x2) and R^3x3"); - - REQUIRE_THROWS_WITH(p_Vector3_u * (TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}), - "error: incompatible operand types Vh(P0Vector:R) and R^3x3"); - REQUIRE_THROWS_WITH(p_Vector3_u * (double{2}), "error: incompatible operand types Vh(P0Vector:R) and R"); - } + SECTION("Vh * X -> Vh") + { + CHECK_SCALAR_VHxX_TO_VH(p_R_u, *, bool{true}); + CHECK_SCALAR_VHxX_TO_VH(p_R_u, *, uint64_t{1}); + CHECK_SCALAR_VHxX_TO_VH(p_R_u, *, int64_t{2}); + CHECK_SCALAR_VHxX_TO_VH(p_R_u, *, double{1.3}); + + CHECK_SCALAR_VHxX_TO_VH(p_R1x1_u, *, (TinyMatrix<1>{1.3})); + CHECK_SCALAR_VHxX_TO_VH(p_R2x2_u, *, (TinyMatrix<2>{1.2, 2.3, 4.2, 5.1})); + CHECK_SCALAR_VHxX_TO_VH(p_R3x3_u, *, + (TinyMatrix<3>{3.2, 7.1, 5.2, // + 4.7, 2.3, 7.1, // + 9.7, 3.2, 6.8})); + + REQUIRE_THROWS_WITH(p_R1_u * (TinyVector<1>{1}), "error: incompatible operand types Vh(P0:R^1) and R^1"); + REQUIRE_THROWS_WITH(p_R2_u * (TinyVector<2>{1, 2}), + "error: incompatible operand types Vh(P0:R^2) and R^2"); + REQUIRE_THROWS_WITH(p_R3_u * (TinyVector<3>{2, 3, 2}), + "error: incompatible operand types Vh(P0:R^3) and R^3"); + REQUIRE_THROWS_WITH(p_R1_u * (TinyMatrix<1>{2}), + "error: incompatible operand types Vh(P0:R^1) and R^1x1"); + REQUIRE_THROWS_WITH(p_R2_u * (TinyMatrix<2>{2, 3, 1, 4}), + "error: incompatible operand types Vh(P0:R^2) and R^2x2"); + REQUIRE_THROWS_WITH(p_R3_u * (TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}), + "error: incompatible operand types Vh(P0:R^3) and R^3x3"); + REQUIRE_THROWS_WITH(p_R2x2_u * (TinyMatrix<1>{2}), + "error: incompatible operand types Vh(P0:R^2x2) and R^1x1"); + REQUIRE_THROWS_WITH(p_R1x1_u * (TinyMatrix<2>{2, 3, 1, 4}), + "error: incompatible operand types Vh(P0:R^1x1) and R^2x2"); + REQUIRE_THROWS_WITH(p_R2x2_u * (TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}), + "error: incompatible operand types Vh(P0:R^2x2) and R^3x3"); + + REQUIRE_THROWS_WITH(p_Vector3_u * (TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}), + "error: incompatible operand types Vh(P0Vector:R) and R^3x3"); + REQUIRE_THROWS_WITH(p_Vector3_u * (double{2}), "error: incompatible operand types Vh(P0Vector:R) and R"); + } - SECTION("X * Vh -> Vh") - { - CHECK_SCALAR_XxVH_TO_VH(bool{true}, *, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(uint64_t{1}, *, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(int64_t{2}, *, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(double{1.3}, *, p_R_u); - - CHECK_SCALAR_XxVH_TO_VH(bool{true}, *, p_R1x1_u); - CHECK_SCALAR_XxVH_TO_VH(uint64_t{1}, *, p_R1x1_u); - CHECK_SCALAR_XxVH_TO_VH(int64_t{2}, *, p_R1x1_u); - CHECK_SCALAR_XxVH_TO_VH(double{1.3}, *, p_R1x1_u); - - CHECK_SCALAR_XxVH_TO_VH(bool{true}, *, p_R2x2_u); - CHECK_SCALAR_XxVH_TO_VH(uint64_t{1}, *, p_R2x2_u); - CHECK_SCALAR_XxVH_TO_VH(int64_t{2}, *, p_R2x2_u); - CHECK_SCALAR_XxVH_TO_VH(double{1.3}, *, p_R2x2_u); - - CHECK_SCALAR_XxVH_TO_VH(bool{true}, *, p_R3x3_u); - CHECK_SCALAR_XxVH_TO_VH(uint64_t{1}, *, p_R3x3_u); - CHECK_SCALAR_XxVH_TO_VH(int64_t{2}, *, p_R3x3_u); - CHECK_SCALAR_XxVH_TO_VH(double{1.3}, *, p_R3x3_u); - - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<1>{1.3}), *, p_R1_u); - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<2>{1.2, 2.3, 4.2, 5.1}), *, p_R2_u); - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<3>{3.2, 7.1, 5.2, // + SECTION("X * Vh -> Vh") + { + CHECK_SCALAR_XxVH_TO_VH(bool{true}, *, p_R_u); + CHECK_SCALAR_XxVH_TO_VH(uint64_t{1}, *, p_R_u); + CHECK_SCALAR_XxVH_TO_VH(int64_t{2}, *, p_R_u); + CHECK_SCALAR_XxVH_TO_VH(double{1.3}, *, p_R_u); + + CHECK_SCALAR_XxVH_TO_VH(bool{true}, *, p_R1x1_u); + CHECK_SCALAR_XxVH_TO_VH(uint64_t{1}, *, p_R1x1_u); + CHECK_SCALAR_XxVH_TO_VH(int64_t{2}, *, p_R1x1_u); + CHECK_SCALAR_XxVH_TO_VH(double{1.3}, *, p_R1x1_u); + + CHECK_SCALAR_XxVH_TO_VH(bool{true}, *, p_R2x2_u); + CHECK_SCALAR_XxVH_TO_VH(uint64_t{1}, *, p_R2x2_u); + CHECK_SCALAR_XxVH_TO_VH(int64_t{2}, *, p_R2x2_u); + CHECK_SCALAR_XxVH_TO_VH(double{1.3}, *, p_R2x2_u); + + CHECK_SCALAR_XxVH_TO_VH(bool{true}, *, p_R3x3_u); + CHECK_SCALAR_XxVH_TO_VH(uint64_t{1}, *, p_R3x3_u); + CHECK_SCALAR_XxVH_TO_VH(int64_t{2}, *, p_R3x3_u); + CHECK_SCALAR_XxVH_TO_VH(double{1.3}, *, p_R3x3_u); + + CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<1>{1.3}), *, p_R1_u); + CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<2>{1.2, 2.3, 4.2, 5.1}), *, p_R2_u); + CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<3>{3.2, 7.1, 5.2, // 4.7, 2.3, 7.1, // 9.7, 3.2, 6.8}), *, p_R3_u); - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<1>{1.3}), *, p_R1x1_u); - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<2>{1.2, 2.3, 4.2, 5.1}), *, p_R2x2_u); - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<3>{3.2, 7.1, 5.2, // + CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<1>{1.3}), *, p_R1x1_u); + CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<2>{1.2, 2.3, 4.2, 5.1}), *, p_R2x2_u); + CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<3>{3.2, 7.1, 5.2, // 4.7, 2.3, 7.1, // 9.7, 3.2, 6.8}), *, p_R3x3_u); - CHECK_VECTOR_XxVH_TO_VH(bool{true}, *, p_Vector3_u); - CHECK_VECTOR_XxVH_TO_VH(uint64_t{1}, *, p_Vector3_u); - CHECK_VECTOR_XxVH_TO_VH(int64_t{2}, *, p_Vector3_u); - CHECK_VECTOR_XxVH_TO_VH(double{1.3}, *, p_Vector3_u); - - REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) * p_R_u, "error: incompatible operand types R^1x1 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) * p_R_u, - "error: incompatible operand types R^2x2 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) * p_R_u, - "error: incompatible operand types R^3x3 and Vh(P0:R)"); - - REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) * p_R2_u, "error: incompatible operand types R^1x1 and Vh(P0:R^2)"); - REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) * p_R3_u, - "error: incompatible operand types R^2x2 and Vh(P0:R^3)"); - REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) * p_R2_u, - "error: incompatible operand types R^3x3 and Vh(P0:R^2)"); - REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) * p_R1_u, - "error: incompatible operand types R^3x3 and Vh(P0:R^1)"); - - REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) * p_R2x2_u, - "error: incompatible operand types R^1x1 and Vh(P0:R^2x2)"); - REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) * p_R3x3_u, - "error: incompatible operand types R^2x2 and Vh(P0:R^3x3)"); - REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) * p_R2x2_u, - "error: incompatible operand types R^3x3 and Vh(P0:R^2x2)"); - REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) * p_R1x1_u, - "error: incompatible operand types R^2x2 and Vh(P0:R^1x1)"); - - REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) * p_Vector3_u, - "error: incompatible operand types R^3x3 and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) * p_Vector3_u, - "error: incompatible operand types R^1x1 and Vh(P0Vector:R)"); - } - } + CHECK_VECTOR_XxVH_TO_VH(bool{true}, *, p_Vector3_u); + CHECK_VECTOR_XxVH_TO_VH(uint64_t{1}, *, p_Vector3_u); + CHECK_VECTOR_XxVH_TO_VH(int64_t{2}, *, p_Vector3_u); + CHECK_VECTOR_XxVH_TO_VH(double{1.3}, *, p_Vector3_u); + + REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) * p_R_u, "error: incompatible operand types R^1x1 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) * p_R_u, + "error: incompatible operand types R^2x2 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) * p_R_u, + "error: incompatible operand types R^3x3 and Vh(P0:R)"); + + REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) * p_R2_u, + "error: incompatible operand types R^1x1 and Vh(P0:R^2)"); + REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) * p_R3_u, + "error: incompatible operand types R^2x2 and Vh(P0:R^3)"); + REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) * p_R2_u, + "error: incompatible operand types R^3x3 and Vh(P0:R^2)"); + REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) * p_R1_u, + "error: incompatible operand types R^3x3 and Vh(P0:R^1)"); + + REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) * p_R2x2_u, + "error: incompatible operand types R^1x1 and Vh(P0:R^2x2)"); + REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) * p_R3x3_u, + "error: incompatible operand types R^2x2 and Vh(P0:R^3x3)"); + REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) * p_R2x2_u, + "error: incompatible operand types R^3x3 and Vh(P0:R^2x2)"); + REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) * p_R1x1_u, + "error: incompatible operand types R^2x2 and Vh(P0:R^1x1)"); + + REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) * p_Vector3_u, + "error: incompatible operand types R^3x3 and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) * p_Vector3_u, + "error: incompatible operand types R^1x1 and Vh(P0Vector:R)"); + } + } - SECTION("ratio") - { - SECTION("Vh / Vh -> Vh") - { - CHECK_SCALAR_VH2_TO_VH(p_R_u, /, p_R_v); + SECTION("ratio") + { + SECTION("Vh / Vh -> Vh") + { + CHECK_SCALAR_VH2_TO_VH(p_R_u, /, p_R_v); - REQUIRE_THROWS_WITH(p_R_u / p_R1_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(p_R2_u / p_R1_v, "error: incompatible operand types Vh(P0:R^2) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(p_R3_u / p_R1x1_v, "error: incompatible operand types Vh(P0:R^3) and Vh(P0:R^1x1)"); - REQUIRE_THROWS_WITH(p_R_u / p_R2x2_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^2x2)"); + REQUIRE_THROWS_WITH(p_R_u / p_R1_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(p_R2_u / p_R1_v, "error: incompatible operand types Vh(P0:R^2) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(p_R3_u / p_R1x1_v, "error: incompatible operand types Vh(P0:R^3) and Vh(P0:R^1x1)"); + REQUIRE_THROWS_WITH(p_R_u / p_R2x2_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^2x2)"); - REQUIRE_THROWS_WITH(p_R_u / p_other_mesh_R_u, "error: operands are defined on different meshes"); - } + REQUIRE_THROWS_WITH(p_R_u / p_other_mesh_R_u, "error: operands are defined on different meshes"); + } - SECTION("X / Vh -> Vh") - { - CHECK_SCALAR_XxVH_TO_VH(bool{true}, /, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(uint64_t{1}, /, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(int64_t{2}, /, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(double{1.3}, /, p_R_u); + SECTION("X / Vh -> Vh") + { + CHECK_SCALAR_XxVH_TO_VH(bool{true}, /, p_R_u); + CHECK_SCALAR_XxVH_TO_VH(uint64_t{1}, /, p_R_u); + CHECK_SCALAR_XxVH_TO_VH(int64_t{2}, /, p_R_u); + CHECK_SCALAR_XxVH_TO_VH(double{1.3}, /, p_R_u); + } + } } } } @@ -1539,668 +1593,693 @@ TEST_CASE("EmbeddedIDiscreteFunctionOperators", "[scheme]") using Rd = TinyVector<Dimension>; - std::shared_ptr mesh = MeshDataBaseForTests::get().cartesianMesh3D(); - - std::shared_ptr other_mesh = - std::make_shared<Mesh<Connectivity<Dimension>>>(mesh->shared_connectivity(), mesh->xr()); - - CellValue<const Rd> xj = MeshDataManager::instance().getMeshData(*mesh).xj(); - - CellValue<double> u_R_values = [=] { - CellValue<double> build_values{mesh->connectivity()}; - parallel_for( - build_values.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 0.2 + std::cos(l2Norm(xj[cell_id])); }); - return build_values; - }(); - - CellValue<double> v_R_values = [=] { - CellValue<double> build_values{mesh->connectivity()}; - parallel_for( - build_values.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 0.6 + std::sin(l2Norm(xj[cell_id])); }); - return build_values; - }(); - - std::shared_ptr p_R_u = std::make_shared<const DiscreteFunctionP0<Dimension, double>>(mesh, u_R_values); - std::shared_ptr p_other_mesh_R_u = - std::make_shared<const DiscreteFunctionP0<Dimension, double>>(other_mesh, u_R_values); - std::shared_ptr p_R_v = std::make_shared<const DiscreteFunctionP0<Dimension, double>>(mesh, v_R_values); - - std::shared_ptr p_R1_u = [=] { - CellValue<TinyVector<1>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { uj[cell_id][0] = 2 * xj[cell_id][0] + 1; }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<1>>>(mesh, uj); - }(); - - std::shared_ptr p_R1_v = [=] { - CellValue<TinyVector<1>> vj{mesh->connectivity()}; - parallel_for( - vj.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { vj[cell_id][0] = xj[cell_id][0] * xj[cell_id][0] + 1; }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<1>>>(mesh, vj); - }(); - - std::shared_ptr p_other_mesh_R1_u = - std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<1>>>(other_mesh, p_R1_u->cellValues()); - - constexpr auto to_2d = [&](const TinyVector<Dimension>& x) -> TinyVector<2> { - if constexpr (Dimension == 1) { - return {x[0], 1 + x[0] * x[0]}; - } else if constexpr (Dimension == 2) { - return {x[0], x[1]}; - } else if constexpr (Dimension == 3) { - return {x[0], x[1] + x[2]}; - } - }; - - std::shared_ptr p_R2_u = [=] { - CellValue<TinyVector<2>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<2> x = to_2d(xj[cell_id]); - uj[cell_id] = {2 * x[0] + 1, 1 - x[1]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<2>>>(mesh, uj); - }(); - - std::shared_ptr p_R2_v = [=] { - CellValue<TinyVector<2>> vj{mesh->connectivity()}; - parallel_for( - vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<2> x = to_2d(xj[cell_id]); - vj[cell_id] = {x[0] * x[1] + 1, 2 * x[1]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<2>>>(mesh, vj); - }(); - - std::shared_ptr p_other_mesh_R2_u = - std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<2>>>(other_mesh, p_R2_u->cellValues()); - - constexpr auto to_3d = [&](const TinyVector<Dimension>& x) -> TinyVector<3> { - if constexpr (Dimension == 1) { - return {x[0], 1 + x[0] * x[0], 2 - x[0]}; - } else if constexpr (Dimension == 2) { - return {x[0], x[1], x[0] + x[1]}; - } else if constexpr (Dimension == 3) { - return {x[0], x[1], x[2]}; - } - }; - - std::shared_ptr p_R3_u = [=] { - CellValue<TinyVector<3>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - uj[cell_id] = {2 * x[0] + 1, 1 - x[1] * x[2], x[0] + x[2]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<3>>>(mesh, uj); - }(); - - std::shared_ptr p_R3_v = [=] { - CellValue<TinyVector<3>> vj{mesh->connectivity()}; - parallel_for( - vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - vj[cell_id] = {x[0] * x[1] + 1, 2 * x[1], x[2] * x[0]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<3>>>(mesh, vj); - }(); - - std::shared_ptr p_other_mesh_R3_u = - std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<3>>>(other_mesh, p_R3_u->cellValues()); - - std::shared_ptr p_R1x1_u = [=] { - CellValue<TinyMatrix<1>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { uj[cell_id] = {2 * xj[cell_id][0] + 1}; }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<1>>>(mesh, uj); - }(); - - std::shared_ptr p_other_mesh_R1x1_u = - std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<1>>>(other_mesh, p_R1x1_u->cellValues()); - - std::shared_ptr p_R1x1_v = [=] { - CellValue<TinyMatrix<1>> vj{mesh->connectivity()}; - parallel_for( - vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { vj[cell_id] = {0.3 - xj[cell_id][0]}; }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<1>>>(mesh, vj); - }(); - - std::shared_ptr p_R2x2_u = [=] { - CellValue<TinyMatrix<2>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<2> x = to_2d(xj[cell_id]); - - uj[cell_id] = {2 * x[0] + 1, 1 - x[1], // - 2 * x[1], -x[0]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<2>>>(mesh, uj); - }(); - - std::shared_ptr p_other_mesh_R2x2_u = - std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<2>>>(other_mesh, p_R2x2_u->cellValues()); - - std::shared_ptr p_R2x2_v = [=] { - CellValue<TinyMatrix<2>> vj{mesh->connectivity()}; - parallel_for( - vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<2> x = to_2d(xj[cell_id]); - - vj[cell_id] = {x[0] + 0.3, 1 - x[1] - x[0], // - 2 * x[1] + x[0], x[1] - x[0]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<2>>>(mesh, vj); - }(); - - std::shared_ptr p_R3x3_u = [=] { - CellValue<TinyMatrix<3>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - - uj[cell_id] = {2 * x[0] + 1, 1 - x[1], 3, // - 2 * x[1], -x[0], x[0] - x[1], // - 3 * x[2] - x[1], x[1] - 2 * x[2], x[2] - x[0]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<3>>>(mesh, uj); - }(); - - std::shared_ptr p_other_mesh_R3x3_u = - std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<3>>>(other_mesh, p_R3x3_u->cellValues()); - - std::shared_ptr p_R3x3_v = [=] { - CellValue<TinyMatrix<3>> vj{mesh->connectivity()}; - parallel_for( - vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - - vj[cell_id] = {0.2 * x[0] + 1, 2 + x[1], 3 - x[2], // - 2.3 * x[2], x[1] - x[0], x[2] - x[1], // - 2 * x[2] + x[0], x[1] + 0.2 * x[2], x[2] - 2 * x[0]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<3>>>(mesh, vj); - }(); - - std::shared_ptr p_Vector3_u = [=] { - CellArray<double> uj_vector{mesh->connectivity(), 3}; - parallel_for( - uj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - uj_vector[cell_id][0] = 2 * x[0] + 1; - uj_vector[cell_id][1] = 1 - x[1] * x[2]; - uj_vector[cell_id][2] = x[0] + x[2]; - }); - - return std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(mesh, uj_vector); - }(); - - std::shared_ptr p_other_mesh_Vector3_u = - std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(other_mesh, p_Vector3_u->cellArrays()); - - std::shared_ptr p_Vector3_v = [=] { - CellArray<double> vj_vector{mesh->connectivity(), 3}; - parallel_for( - vj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - vj_vector[cell_id][0] = x[0] * x[1] + 1; - vj_vector[cell_id][1] = 2 * x[1]; - vj_vector[cell_id][2] = x[2] * x[0]; - }); - - return std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(mesh, vj_vector); - }(); - - std::shared_ptr p_Vector2_w = [=] { - CellArray<double> wj_vector{mesh->connectivity(), 2}; - parallel_for( - wj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - wj_vector[cell_id][0] = x[0] + x[1] * 2; - wj_vector[cell_id][1] = x[0] * x[1]; - }); - - return std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(mesh, wj_vector); - }(); - - SECTION("sum") - { - SECTION("Vh + Vh -> Vh") - { - CHECK_SCALAR_VH2_TO_VH(p_R_u, +, p_R_v); - - CHECK_SCALAR_VH2_TO_VH(p_R1_u, +, p_R1_v); - CHECK_SCALAR_VH2_TO_VH(p_R2_u, +, p_R2_v); - CHECK_SCALAR_VH2_TO_VH(p_R3_u, +, p_R3_v); - - CHECK_SCALAR_VH2_TO_VH(p_R1x1_u, +, p_R1x1_v); - CHECK_SCALAR_VH2_TO_VH(p_R2x2_u, +, p_R2x2_v); - CHECK_SCALAR_VH2_TO_VH(p_R3x3_u, +, p_R3x3_v); - - CHECK_VECTOR_VH2_TO_VH(p_Vector3_u, +, p_Vector3_v); - - REQUIRE_THROWS_WITH(p_R_u + p_R1_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(p_R2_u + p_R1_v, "error: incompatible operand types Vh(P0:R^2) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(p_R3_u + p_R1x1_v, "error: incompatible operand types Vh(P0:R^3) and Vh(P0:R^1x1)"); - REQUIRE_THROWS_WITH(p_R_u + p_R2x2_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^2x2)"); - REQUIRE_THROWS_WITH(p_R_u + p_R2x2_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^2x2)"); - REQUIRE_THROWS_WITH(p_Vector3_u + p_R_v, "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R)"); - REQUIRE_THROWS_WITH(p_Vector3_u + p_Vector2_w, "error: Vh(P0Vector:R) spaces have different sizes"); - - REQUIRE_THROWS_WITH(p_R_u + p_other_mesh_R_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R1_u + p_other_mesh_R1_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R2_u + p_other_mesh_R2_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R3_u + p_other_mesh_R3_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R1x1_u + p_other_mesh_R1x1_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R2x2_u + p_other_mesh_R2x2_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R3x3_u + p_other_mesh_R3x3_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_Vector3_u + p_other_mesh_Vector3_u, "error: operands are defined on different meshes"); - } - - SECTION("Vh + X -> Vh") - { - CHECK_SCALAR_VHxX_TO_VH(p_R_u, +, bool{true}); - CHECK_SCALAR_VHxX_TO_VH(p_R_u, +, uint64_t{1}); - CHECK_SCALAR_VHxX_TO_VH(p_R_u, +, int64_t{2}); - CHECK_SCALAR_VHxX_TO_VH(p_R_u, +, double{1.3}); - - CHECK_SCALAR_VHxX_TO_VH(p_R1_u, +, (TinyVector<1>{1.3})); - CHECK_SCALAR_VHxX_TO_VH(p_R2_u, +, (TinyVector<2>{1.2, 2.3})); - CHECK_SCALAR_VHxX_TO_VH(p_R3_u, +, (TinyVector<3>{3.2, 7.1, 5.2})); - - CHECK_SCALAR_VHxX_TO_VH(p_R1x1_u, +, (TinyMatrix<1>{1.3})); - CHECK_SCALAR_VHxX_TO_VH(p_R2x2_u, +, (TinyMatrix<2>{1.2, 2.3, 4.2, 5.1})); - CHECK_SCALAR_VHxX_TO_VH(p_R3x3_u, +, - (TinyMatrix<3>{3.2, 7.1, 5.2, // - 4.7, 2.3, 7.1, // - 9.7, 3.2, 6.8})); - - REQUIRE_THROWS_WITH(p_R_u + (TinyVector<1>{1}), "error: incompatible operand types Vh(P0:R) and R^1"); - REQUIRE_THROWS_WITH(p_R_u + (TinyVector<2>{1, 2}), "error: incompatible operand types Vh(P0:R) and R^2"); - REQUIRE_THROWS_WITH(p_R_u + (TinyVector<3>{2, 3, 2}), "error: incompatible operand types Vh(P0:R) and R^3"); - REQUIRE_THROWS_WITH(p_R_u + (TinyMatrix<1>{2}), "error: incompatible operand types Vh(P0:R) and R^1x1"); - REQUIRE_THROWS_WITH(p_R_u + (TinyMatrix<2>{2, 3, 1, 4}), - "error: incompatible operand types Vh(P0:R) and R^2x2"); - REQUIRE_THROWS_WITH(p_R_u + (TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}), - "error: incompatible operand types Vh(P0:R) and R^3x3"); - - REQUIRE_THROWS_WITH(p_Vector3_u + (double{1}), "error: incompatible operand types Vh(P0Vector:R) and R"); - REQUIRE_THROWS_WITH(p_Vector3_u + (TinyVector<1>{1}), - "error: incompatible operand types Vh(P0Vector:R) and R^1"); - REQUIRE_THROWS_WITH(p_Vector3_u + (TinyVector<2>{1, 2}), - "error: incompatible operand types Vh(P0Vector:R) and R^2"); - } - - SECTION("X + Vh -> Vh") - { - CHECK_SCALAR_XxVH_TO_VH(bool{true}, +, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(uint64_t{1}, +, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(int64_t{2}, +, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(double{1.3}, +, p_R_u); - - CHECK_SCALAR_XxVH_TO_VH((TinyVector<1>{1.3}), +, p_R1_u); - CHECK_SCALAR_XxVH_TO_VH((TinyVector<2>{1.2, 2.3}), +, p_R2_u); - CHECK_SCALAR_XxVH_TO_VH((TinyVector<3>{3.2, 7.1, 5.2}), +, p_R3_u); - - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<1>{1.3}), +, p_R1x1_u); - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<2>{1.2, 2.3, 4.2, 5.1}), +, p_R2x2_u); - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<3>{3.2, 7.1, 5.2, // - 4.7, 2.3, 7.1, // - 9.7, 3.2, 6.8}), - +, p_R3x3_u); - - REQUIRE_THROWS_WITH((TinyVector<1>{1}) + p_R_u, "error: incompatible operand types R^1 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyVector<2>{1, 2}) + p_R_u, "error: incompatible operand types R^2 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyVector<3>{2, 3, 2}) + p_R_u, "error: incompatible operand types R^3 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) + p_R_u, "error: incompatible operand types R^1x1 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) + p_R_u, - "error: incompatible operand types R^2x2 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) + p_R_u, - "error: incompatible operand types R^3x3 and Vh(P0:R)"); - - REQUIRE_THROWS_WITH((double{1}) + p_Vector3_u, "error: incompatible operand types R and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH((TinyVector<1>{1}) + p_Vector3_u, - "error: incompatible operand types R^1 and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH((TinyVector<2>{1, 2}) + p_Vector3_u, - "error: incompatible operand types R^2 and Vh(P0Vector:R)"); - } - } - - SECTION("difference") - { - SECTION("Vh - Vh -> Vh") - { - CHECK_SCALAR_VH2_TO_VH(p_R_u, -, p_R_v); - - CHECK_SCALAR_VH2_TO_VH(p_R1_u, -, p_R1_v); - CHECK_SCALAR_VH2_TO_VH(p_R2_u, -, p_R2_v); - CHECK_SCALAR_VH2_TO_VH(p_R3_u, -, p_R3_v); - - CHECK_SCALAR_VH2_TO_VH(p_R1x1_u, -, p_R1x1_v); - CHECK_SCALAR_VH2_TO_VH(p_R2x2_u, -, p_R2x2_v); - CHECK_SCALAR_VH2_TO_VH(p_R3x3_u, -, p_R3x3_v); - - CHECK_VECTOR_VH2_TO_VH(p_Vector3_u, -, p_Vector3_v); - - REQUIRE_THROWS_WITH(p_R_u - p_R1_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(p_R2_u - p_R1_v, "error: incompatible operand types Vh(P0:R^2) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(p_R3_u - p_R1x1_v, "error: incompatible operand types Vh(P0:R^3) and Vh(P0:R^1x1)"); - REQUIRE_THROWS_WITH(p_R_u - p_R2x2_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^2x2)"); - REQUIRE_THROWS_WITH(p_Vector3_u - p_R_v, "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R)"); - REQUIRE_THROWS_WITH(p_Vector3_u - p_Vector2_w, "error: Vh(P0Vector:R) spaces have different sizes"); - - REQUIRE_THROWS_WITH(p_R_u - p_other_mesh_R_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R1_u - p_other_mesh_R1_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R2_u - p_other_mesh_R2_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R3_u - p_other_mesh_R3_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R1x1_u - p_other_mesh_R1x1_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R2x2_u - p_other_mesh_R2x2_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R3x3_u - p_other_mesh_R3x3_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_Vector3_u - p_other_mesh_Vector3_u, "error: operands are defined on different meshes"); - } - - SECTION("Vh - X -> Vh") - { - CHECK_SCALAR_VHxX_TO_VH(p_R_u, -, bool{true}); - CHECK_SCALAR_VHxX_TO_VH(p_R_u, -, uint64_t{1}); - CHECK_SCALAR_VHxX_TO_VH(p_R_u, -, int64_t{2}); - CHECK_SCALAR_VHxX_TO_VH(p_R_u, -, double{1.3}); - - CHECK_SCALAR_VHxX_TO_VH(p_R1_u, -, (TinyVector<1>{1.3})); - CHECK_SCALAR_VHxX_TO_VH(p_R2_u, -, (TinyVector<2>{1.2, 2.3})); - CHECK_SCALAR_VHxX_TO_VH(p_R3_u, -, (TinyVector<3>{3.2, 7.1, 5.2})); - - CHECK_SCALAR_VHxX_TO_VH(p_R1x1_u, -, (TinyMatrix<1>{1.3})); - CHECK_SCALAR_VHxX_TO_VH(p_R2x2_u, -, (TinyMatrix<2>{1.2, 2.3, 4.2, 5.1})); - CHECK_SCALAR_VHxX_TO_VH(p_R3x3_u, -, - (TinyMatrix<3>{3.2, 7.1, 5.2, // - 4.7, 2.3, 7.1, // - 9.7, 3.2, 6.8})); - - REQUIRE_THROWS_WITH(p_R_u - (TinyVector<1>{1}), "error: incompatible operand types Vh(P0:R) and R^1"); - REQUIRE_THROWS_WITH(p_R_u - (TinyVector<2>{1, 2}), "error: incompatible operand types Vh(P0:R) and R^2"); - REQUIRE_THROWS_WITH(p_R_u - (TinyVector<3>{2, 3, 2}), "error: incompatible operand types Vh(P0:R) and R^3"); - REQUIRE_THROWS_WITH(p_R_u - (TinyMatrix<1>{2}), "error: incompatible operand types Vh(P0:R) and R^1x1"); - REQUIRE_THROWS_WITH(p_R_u - (TinyMatrix<2>{2, 3, 1, 4}), - "error: incompatible operand types Vh(P0:R) and R^2x2"); - REQUIRE_THROWS_WITH(p_R_u - (TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}), - "error: incompatible operand types Vh(P0:R) and R^3x3"); - - REQUIRE_THROWS_WITH(p_Vector3_u - (double{1}), "error: incompatible operand types Vh(P0Vector:R) and R"); - REQUIRE_THROWS_WITH(p_Vector3_u - (TinyVector<1>{1}), - "error: incompatible operand types Vh(P0Vector:R) and R^1"); - REQUIRE_THROWS_WITH(p_Vector3_u - (TinyVector<2>{1, 2}), - "error: incompatible operand types Vh(P0Vector:R) and R^2"); - } - - SECTION("X - Vh -> Vh") - { - CHECK_SCALAR_XxVH_TO_VH(bool{true}, -, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(uint64_t{1}, -, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(int64_t{2}, -, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(double{1.3}, -, p_R_u); - - CHECK_SCALAR_XxVH_TO_VH((TinyVector<1>{1.3}), -, p_R1_u); - CHECK_SCALAR_XxVH_TO_VH((TinyVector<2>{1.2, 2.3}), -, p_R2_u); - CHECK_SCALAR_XxVH_TO_VH((TinyVector<3>{3.2, 7.1, 5.2}), -, p_R3_u); - - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<1>{1.3}), -, p_R1x1_u); - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<2>{1.2, 2.3, 4.2, 5.1}), -, p_R2x2_u); - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<3>{3.2, 7.1, 5.2, // - 4.7, 2.3, 7.1, // - 9.7, 3.2, 6.8}), - -, p_R3x3_u); - - REQUIRE_THROWS_WITH((TinyVector<1>{1}) - p_R_u, "error: incompatible operand types R^1 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyVector<2>{1, 2}) - p_R_u, "error: incompatible operand types R^2 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyVector<3>{2, 3, 2}) - p_R_u, "error: incompatible operand types R^3 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) - p_R_u, "error: incompatible operand types R^1x1 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) - p_R_u, - "error: incompatible operand types R^2x2 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) - p_R_u, - "error: incompatible operand types R^3x3 and Vh(P0:R)"); - - REQUIRE_THROWS_WITH((double{1}) - p_Vector3_u, "error: incompatible operand types R and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH((TinyVector<1>{1}) - p_Vector3_u, - "error: incompatible operand types R^1 and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH((TinyVector<2>{1, 2}) - p_Vector3_u, - "error: incompatible operand types R^2 and Vh(P0Vector:R)"); - } - } + std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - SECTION("product") - { - SECTION("Vh * Vh -> Vh") + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) { - CHECK_SCALAR_VH2_TO_VH(p_R_u, *, p_R_v); - - CHECK_SCALAR_VH2_TO_VH(p_R1x1_u, *, p_R1x1_v); - CHECK_SCALAR_VH2_TO_VH(p_R2x2_u, *, p_R2x2_v); - CHECK_SCALAR_VH2_TO_VH(p_R3x3_u, *, p_R3x3_v); - - CHECK_SCALAR_VH2_TO_VH(p_R_u, *, p_R1_v); - CHECK_SCALAR_VH2_TO_VH(p_R_u, *, p_R2_v); - CHECK_SCALAR_VH2_TO_VH(p_R_u, *, p_R3_v); + auto mesh = named_mesh.mesh(); + + std::shared_ptr other_mesh = + std::make_shared<Mesh<Connectivity<Dimension>>>(mesh->shared_connectivity(), mesh->xr()); + + CellValue<const Rd> xj = MeshDataManager::instance().getMeshData(*mesh).xj(); + + CellValue<double> u_R_values = [=] { + CellValue<double> build_values{mesh->connectivity()}; + parallel_for( + build_values.numberOfItems(), + PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 0.2 + std::cos(l2Norm(xj[cell_id])); }); + return build_values; + }(); + + CellValue<double> v_R_values = [=] { + CellValue<double> build_values{mesh->connectivity()}; + parallel_for( + build_values.numberOfItems(), + PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 0.6 + std::sin(l2Norm(xj[cell_id])); }); + return build_values; + }(); + + std::shared_ptr p_R_u = std::make_shared<const DiscreteFunctionP0<Dimension, double>>(mesh, u_R_values); + std::shared_ptr p_other_mesh_R_u = + std::make_shared<const DiscreteFunctionP0<Dimension, double>>(other_mesh, u_R_values); + std::shared_ptr p_R_v = std::make_shared<const DiscreteFunctionP0<Dimension, double>>(mesh, v_R_values); + + std::shared_ptr p_R1_u = [=] { + CellValue<TinyVector<1>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { uj[cell_id][0] = 2 * xj[cell_id][0] + 1; }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<1>>>(mesh, uj); + }(); + + std::shared_ptr p_R1_v = [=] { + CellValue<TinyVector<1>> vj{mesh->connectivity()}; + parallel_for( + vj.numberOfItems(), + PUGS_LAMBDA(const CellId cell_id) { vj[cell_id][0] = xj[cell_id][0] * xj[cell_id][0] + 1; }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<1>>>(mesh, vj); + }(); + + std::shared_ptr p_other_mesh_R1_u = + std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<1>>>(other_mesh, p_R1_u->cellValues()); + + constexpr auto to_2d = [&](const TinyVector<Dimension>& x) -> TinyVector<2> { + if constexpr (Dimension == 1) { + return {x[0], 1 + x[0] * x[0]}; + } else if constexpr (Dimension == 2) { + return {x[0], x[1]}; + } else if constexpr (Dimension == 3) { + return {x[0], x[1] + x[2]}; + } + }; + + std::shared_ptr p_R2_u = [=] { + CellValue<TinyVector<2>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<2> x = to_2d(xj[cell_id]); + uj[cell_id] = {2 * x[0] + 1, 1 - x[1]}; + }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<2>>>(mesh, uj); + }(); + + std::shared_ptr p_R2_v = [=] { + CellValue<TinyVector<2>> vj{mesh->connectivity()}; + parallel_for( + vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<2> x = to_2d(xj[cell_id]); + vj[cell_id] = {x[0] * x[1] + 1, 2 * x[1]}; + }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<2>>>(mesh, vj); + }(); + + std::shared_ptr p_other_mesh_R2_u = + std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<2>>>(other_mesh, p_R2_u->cellValues()); + + constexpr auto to_3d = [&](const TinyVector<Dimension>& x) -> TinyVector<3> { + if constexpr (Dimension == 1) { + return {x[0], 1 + x[0] * x[0], 2 - x[0]}; + } else if constexpr (Dimension == 2) { + return {x[0], x[1], x[0] + x[1]}; + } else if constexpr (Dimension == 3) { + return {x[0], x[1], x[2]}; + } + }; + + std::shared_ptr p_R3_u = [=] { + CellValue<TinyVector<3>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + uj[cell_id] = {2 * x[0] + 1, 1 - x[1] * x[2], x[0] + x[2]}; + }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<3>>>(mesh, uj); + }(); + + std::shared_ptr p_R3_v = [=] { + CellValue<TinyVector<3>> vj{mesh->connectivity()}; + parallel_for( + vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + vj[cell_id] = {x[0] * x[1] + 1, 2 * x[1], x[2] * x[0]}; + }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<3>>>(mesh, vj); + }(); + + std::shared_ptr p_other_mesh_R3_u = + std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<3>>>(other_mesh, p_R3_u->cellValues()); + + std::shared_ptr p_R1x1_u = [=] { + CellValue<TinyMatrix<1>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { uj[cell_id] = {2 * xj[cell_id][0] + 1}; }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<1>>>(mesh, uj); + }(); + + std::shared_ptr p_other_mesh_R1x1_u = + std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<1>>>(other_mesh, p_R1x1_u->cellValues()); + + std::shared_ptr p_R1x1_v = [=] { + CellValue<TinyMatrix<1>> vj{mesh->connectivity()}; + parallel_for( + vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { vj[cell_id] = {0.3 - xj[cell_id][0]}; }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<1>>>(mesh, vj); + }(); + + std::shared_ptr p_R2x2_u = [=] { + CellValue<TinyMatrix<2>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<2> x = to_2d(xj[cell_id]); + + uj[cell_id] = {2 * x[0] + 1, 1 - x[1], // + 2 * x[1], -x[0]}; + }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<2>>>(mesh, uj); + }(); + + std::shared_ptr p_other_mesh_R2x2_u = + std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<2>>>(other_mesh, p_R2x2_u->cellValues()); + + std::shared_ptr p_R2x2_v = [=] { + CellValue<TinyMatrix<2>> vj{mesh->connectivity()}; + parallel_for( + vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<2> x = to_2d(xj[cell_id]); + + vj[cell_id] = {x[0] + 0.3, 1 - x[1] - x[0], // + 2 * x[1] + x[0], x[1] - x[0]}; + }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<2>>>(mesh, vj); + }(); + + std::shared_ptr p_R3x3_u = [=] { + CellValue<TinyMatrix<3>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + + uj[cell_id] = {2 * x[0] + 1, 1 - x[1], 3, // + 2 * x[1], -x[0], x[0] - x[1], // + 3 * x[2] - x[1], x[1] - 2 * x[2], x[2] - x[0]}; + }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<3>>>(mesh, uj); + }(); + + std::shared_ptr p_other_mesh_R3x3_u = + std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<3>>>(other_mesh, p_R3x3_u->cellValues()); + + std::shared_ptr p_R3x3_v = [=] { + CellValue<TinyMatrix<3>> vj{mesh->connectivity()}; + parallel_for( + vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + + vj[cell_id] = {0.2 * x[0] + 1, 2 + x[1], 3 - x[2], // + 2.3 * x[2], x[1] - x[0], x[2] - x[1], // + 2 * x[2] + x[0], x[1] + 0.2 * x[2], x[2] - 2 * x[0]}; + }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<3>>>(mesh, vj); + }(); + + std::shared_ptr p_Vector3_u = [=] { + CellArray<double> uj_vector{mesh->connectivity(), 3}; + parallel_for( + uj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + uj_vector[cell_id][0] = 2 * x[0] + 1; + uj_vector[cell_id][1] = 1 - x[1] * x[2]; + uj_vector[cell_id][2] = x[0] + x[2]; + }); + + return std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(mesh, uj_vector); + }(); + + std::shared_ptr p_other_mesh_Vector3_u = + std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(other_mesh, p_Vector3_u->cellArrays()); + + std::shared_ptr p_Vector3_v = [=] { + CellArray<double> vj_vector{mesh->connectivity(), 3}; + parallel_for( + vj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + vj_vector[cell_id][0] = x[0] * x[1] + 1; + vj_vector[cell_id][1] = 2 * x[1]; + vj_vector[cell_id][2] = x[2] * x[0]; + }); + + return std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(mesh, vj_vector); + }(); + + std::shared_ptr p_Vector2_w = [=] { + CellArray<double> wj_vector{mesh->connectivity(), 2}; + parallel_for( + wj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + wj_vector[cell_id][0] = x[0] + x[1] * 2; + wj_vector[cell_id][1] = x[0] * x[1]; + }); + + return std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(mesh, wj_vector); + }(); + + SECTION("sum") + { + SECTION("Vh + Vh -> Vh") + { + CHECK_SCALAR_VH2_TO_VH(p_R_u, +, p_R_v); + + CHECK_SCALAR_VH2_TO_VH(p_R1_u, +, p_R1_v); + CHECK_SCALAR_VH2_TO_VH(p_R2_u, +, p_R2_v); + CHECK_SCALAR_VH2_TO_VH(p_R3_u, +, p_R3_v); + + CHECK_SCALAR_VH2_TO_VH(p_R1x1_u, +, p_R1x1_v); + CHECK_SCALAR_VH2_TO_VH(p_R2x2_u, +, p_R2x2_v); + CHECK_SCALAR_VH2_TO_VH(p_R3x3_u, +, p_R3x3_v); + + CHECK_VECTOR_VH2_TO_VH(p_Vector3_u, +, p_Vector3_v); + + REQUIRE_THROWS_WITH(p_R_u + p_R1_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(p_R2_u + p_R1_v, "error: incompatible operand types Vh(P0:R^2) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(p_R3_u + p_R1x1_v, "error: incompatible operand types Vh(P0:R^3) and Vh(P0:R^1x1)"); + REQUIRE_THROWS_WITH(p_R_u + p_R2x2_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^2x2)"); + REQUIRE_THROWS_WITH(p_R_u + p_R2x2_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^2x2)"); + REQUIRE_THROWS_WITH(p_Vector3_u + p_R_v, "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R)"); + REQUIRE_THROWS_WITH(p_Vector3_u + p_Vector2_w, "error: Vh(P0Vector:R) spaces have different sizes"); + + REQUIRE_THROWS_WITH(p_R_u + p_other_mesh_R_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R1_u + p_other_mesh_R1_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R2_u + p_other_mesh_R2_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R3_u + p_other_mesh_R3_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R1x1_u + p_other_mesh_R1x1_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R2x2_u + p_other_mesh_R2x2_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R3x3_u + p_other_mesh_R3x3_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_Vector3_u + p_other_mesh_Vector3_u, + "error: operands are defined on different meshes"); + } - CHECK_SCALAR_VH2_TO_VH(p_R_u, *, p_R1x1_v); - CHECK_SCALAR_VH2_TO_VH(p_R_u, *, p_R2x2_v); - CHECK_SCALAR_VH2_TO_VH(p_R_u, *, p_R3x3_v); + SECTION("Vh + X -> Vh") + { + CHECK_SCALAR_VHxX_TO_VH(p_R_u, +, bool{true}); + CHECK_SCALAR_VHxX_TO_VH(p_R_u, +, uint64_t{1}); + CHECK_SCALAR_VHxX_TO_VH(p_R_u, +, int64_t{2}); + CHECK_SCALAR_VHxX_TO_VH(p_R_u, +, double{1.3}); + + CHECK_SCALAR_VHxX_TO_VH(p_R1_u, +, (TinyVector<1>{1.3})); + CHECK_SCALAR_VHxX_TO_VH(p_R2_u, +, (TinyVector<2>{1.2, 2.3})); + CHECK_SCALAR_VHxX_TO_VH(p_R3_u, +, (TinyVector<3>{3.2, 7.1, 5.2})); + + CHECK_SCALAR_VHxX_TO_VH(p_R1x1_u, +, (TinyMatrix<1>{1.3})); + CHECK_SCALAR_VHxX_TO_VH(p_R2x2_u, +, (TinyMatrix<2>{1.2, 2.3, 4.2, 5.1})); + CHECK_SCALAR_VHxX_TO_VH(p_R3x3_u, +, + (TinyMatrix<3>{3.2, 7.1, 5.2, // + 4.7, 2.3, 7.1, // + 9.7, 3.2, 6.8})); + + REQUIRE_THROWS_WITH(p_R_u + (TinyVector<1>{1}), "error: incompatible operand types Vh(P0:R) and R^1"); + REQUIRE_THROWS_WITH(p_R_u + (TinyVector<2>{1, 2}), "error: incompatible operand types Vh(P0:R) and R^2"); + REQUIRE_THROWS_WITH(p_R_u + (TinyVector<3>{2, 3, 2}), + "error: incompatible operand types Vh(P0:R) and R^3"); + REQUIRE_THROWS_WITH(p_R_u + (TinyMatrix<1>{2}), "error: incompatible operand types Vh(P0:R) and R^1x1"); + REQUIRE_THROWS_WITH(p_R_u + (TinyMatrix<2>{2, 3, 1, 4}), + "error: incompatible operand types Vh(P0:R) and R^2x2"); + REQUIRE_THROWS_WITH(p_R_u + (TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}), + "error: incompatible operand types Vh(P0:R) and R^3x3"); + + REQUIRE_THROWS_WITH(p_Vector3_u + (double{1}), "error: incompatible operand types Vh(P0Vector:R) and R"); + REQUIRE_THROWS_WITH(p_Vector3_u + (TinyVector<1>{1}), + "error: incompatible operand types Vh(P0Vector:R) and R^1"); + REQUIRE_THROWS_WITH(p_Vector3_u + (TinyVector<2>{1, 2}), + "error: incompatible operand types Vh(P0Vector:R) and R^2"); + } - CHECK_SCALAR_VH2_TO_VH(p_R1x1_u, *, p_R1_v); - CHECK_SCALAR_VH2_TO_VH(p_R2x2_u, *, p_R2_v); - CHECK_SCALAR_VH2_TO_VH(p_R3x3_u, *, p_R3_v); + SECTION("X + Vh -> Vh") + { + CHECK_SCALAR_XxVH_TO_VH(bool{true}, +, p_R_u); + CHECK_SCALAR_XxVH_TO_VH(uint64_t{1}, +, p_R_u); + CHECK_SCALAR_XxVH_TO_VH(int64_t{2}, +, p_R_u); + CHECK_SCALAR_XxVH_TO_VH(double{1.3}, +, p_R_u); + + CHECK_SCALAR_XxVH_TO_VH((TinyVector<1>{1.3}), +, p_R1_u); + CHECK_SCALAR_XxVH_TO_VH((TinyVector<2>{1.2, 2.3}), +, p_R2_u); + CHECK_SCALAR_XxVH_TO_VH((TinyVector<3>{3.2, 7.1, 5.2}), +, p_R3_u); + + CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<1>{1.3}), +, p_R1x1_u); + CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<2>{1.2, 2.3, 4.2, 5.1}), +, p_R2x2_u); + CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<3>{3.2, 7.1, 5.2, // + 4.7, 2.3, 7.1, // + 9.7, 3.2, 6.8}), + +, p_R3x3_u); + + REQUIRE_THROWS_WITH((TinyVector<1>{1}) + p_R_u, "error: incompatible operand types R^1 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyVector<2>{1, 2}) + p_R_u, "error: incompatible operand types R^2 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyVector<3>{2, 3, 2}) + p_R_u, + "error: incompatible operand types R^3 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) + p_R_u, "error: incompatible operand types R^1x1 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) + p_R_u, + "error: incompatible operand types R^2x2 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) + p_R_u, + "error: incompatible operand types R^3x3 and Vh(P0:R)"); + + REQUIRE_THROWS_WITH((double{1}) + p_Vector3_u, "error: incompatible operand types R and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH((TinyVector<1>{1}) + p_Vector3_u, + "error: incompatible operand types R^1 and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH((TinyVector<2>{1, 2}) + p_Vector3_u, + "error: incompatible operand types R^2 and Vh(P0Vector:R)"); + } + } + SECTION("difference") { - std::shared_ptr p_fuv = p_R_u * p_Vector3_v; + SECTION("Vh - Vh -> Vh") + { + CHECK_SCALAR_VH2_TO_VH(p_R_u, -, p_R_v); + + CHECK_SCALAR_VH2_TO_VH(p_R1_u, -, p_R1_v); + CHECK_SCALAR_VH2_TO_VH(p_R2_u, -, p_R2_v); + CHECK_SCALAR_VH2_TO_VH(p_R3_u, -, p_R3_v); + + CHECK_SCALAR_VH2_TO_VH(p_R1x1_u, -, p_R1x1_v); + CHECK_SCALAR_VH2_TO_VH(p_R2x2_u, -, p_R2x2_v); + CHECK_SCALAR_VH2_TO_VH(p_R3x3_u, -, p_R3x3_v); + + CHECK_VECTOR_VH2_TO_VH(p_Vector3_u, -, p_Vector3_v); + + REQUIRE_THROWS_WITH(p_R_u - p_R1_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(p_R2_u - p_R1_v, "error: incompatible operand types Vh(P0:R^2) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(p_R3_u - p_R1x1_v, "error: incompatible operand types Vh(P0:R^3) and Vh(P0:R^1x1)"); + REQUIRE_THROWS_WITH(p_R_u - p_R2x2_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^2x2)"); + REQUIRE_THROWS_WITH(p_Vector3_u - p_R_v, "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R)"); + REQUIRE_THROWS_WITH(p_Vector3_u - p_Vector2_w, "error: Vh(P0Vector:R) spaces have different sizes"); + + REQUIRE_THROWS_WITH(p_R_u - p_other_mesh_R_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R1_u - p_other_mesh_R1_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R2_u - p_other_mesh_R2_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R3_u - p_other_mesh_R3_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R1x1_u - p_other_mesh_R1x1_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R2x2_u - p_other_mesh_R2x2_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R3x3_u - p_other_mesh_R3x3_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_Vector3_u - p_other_mesh_Vector3_u, + "error: operands are defined on different meshes"); + } - REQUIRE(p_fuv.use_count() > 0); - REQUIRE_NOTHROW(dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*p_fuv)); + SECTION("Vh - X -> Vh") + { + CHECK_SCALAR_VHxX_TO_VH(p_R_u, -, bool{true}); + CHECK_SCALAR_VHxX_TO_VH(p_R_u, -, uint64_t{1}); + CHECK_SCALAR_VHxX_TO_VH(p_R_u, -, int64_t{2}); + CHECK_SCALAR_VHxX_TO_VH(p_R_u, -, double{1.3}); + + CHECK_SCALAR_VHxX_TO_VH(p_R1_u, -, (TinyVector<1>{1.3})); + CHECK_SCALAR_VHxX_TO_VH(p_R2_u, -, (TinyVector<2>{1.2, 2.3})); + CHECK_SCALAR_VHxX_TO_VH(p_R3_u, -, (TinyVector<3>{3.2, 7.1, 5.2})); + + CHECK_SCALAR_VHxX_TO_VH(p_R1x1_u, -, (TinyMatrix<1>{1.3})); + CHECK_SCALAR_VHxX_TO_VH(p_R2x2_u, -, (TinyMatrix<2>{1.2, 2.3, 4.2, 5.1})); + CHECK_SCALAR_VHxX_TO_VH(p_R3x3_u, -, + (TinyMatrix<3>{3.2, 7.1, 5.2, // + 4.7, 2.3, 7.1, // + 9.7, 3.2, 6.8})); + + REQUIRE_THROWS_WITH(p_R_u - (TinyVector<1>{1}), "error: incompatible operand types Vh(P0:R) and R^1"); + REQUIRE_THROWS_WITH(p_R_u - (TinyVector<2>{1, 2}), "error: incompatible operand types Vh(P0:R) and R^2"); + REQUIRE_THROWS_WITH(p_R_u - (TinyVector<3>{2, 3, 2}), + "error: incompatible operand types Vh(P0:R) and R^3"); + REQUIRE_THROWS_WITH(p_R_u - (TinyMatrix<1>{2}), "error: incompatible operand types Vh(P0:R) and R^1x1"); + REQUIRE_THROWS_WITH(p_R_u - (TinyMatrix<2>{2, 3, 1, 4}), + "error: incompatible operand types Vh(P0:R) and R^2x2"); + REQUIRE_THROWS_WITH(p_R_u - (TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}), + "error: incompatible operand types Vh(P0:R) and R^3x3"); + + REQUIRE_THROWS_WITH(p_Vector3_u - (double{1}), "error: incompatible operand types Vh(P0Vector:R) and R"); + REQUIRE_THROWS_WITH(p_Vector3_u - (TinyVector<1>{1}), + "error: incompatible operand types Vh(P0Vector:R) and R^1"); + REQUIRE_THROWS_WITH(p_Vector3_u - (TinyVector<2>{1, 2}), + "error: incompatible operand types Vh(P0Vector:R) and R^2"); + } - const auto& fuv = dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*p_fuv); + SECTION("X - Vh -> Vh") + { + CHECK_SCALAR_XxVH_TO_VH(bool{true}, -, p_R_u); + CHECK_SCALAR_XxVH_TO_VH(uint64_t{1}, -, p_R_u); + CHECK_SCALAR_XxVH_TO_VH(int64_t{2}, -, p_R_u); + CHECK_SCALAR_XxVH_TO_VH(double{1.3}, -, p_R_u); + + CHECK_SCALAR_XxVH_TO_VH((TinyVector<1>{1.3}), -, p_R1_u); + CHECK_SCALAR_XxVH_TO_VH((TinyVector<2>{1.2, 2.3}), -, p_R2_u); + CHECK_SCALAR_XxVH_TO_VH((TinyVector<3>{3.2, 7.1, 5.2}), -, p_R3_u); + + CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<1>{1.3}), -, p_R1x1_u); + CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<2>{1.2, 2.3, 4.2, 5.1}), -, p_R2x2_u); + CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<3>{3.2, 7.1, 5.2, // + 4.7, 2.3, 7.1, // + 9.7, 3.2, 6.8}), + -, p_R3x3_u); + + REQUIRE_THROWS_WITH((TinyVector<1>{1}) - p_R_u, "error: incompatible operand types R^1 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyVector<2>{1, 2}) - p_R_u, "error: incompatible operand types R^2 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyVector<3>{2, 3, 2}) - p_R_u, + "error: incompatible operand types R^3 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) - p_R_u, "error: incompatible operand types R^1x1 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) - p_R_u, + "error: incompatible operand types R^2x2 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) - p_R_u, + "error: incompatible operand types R^3x3 and Vh(P0:R)"); + + REQUIRE_THROWS_WITH((double{1}) - p_Vector3_u, "error: incompatible operand types R and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH((TinyVector<1>{1}) - p_Vector3_u, + "error: incompatible operand types R^1 and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH((TinyVector<2>{1, 2}) - p_Vector3_u, + "error: incompatible operand types R^2 and Vh(P0Vector:R)"); + } + } - auto lhs_values = p_R_u->cellValues(); - auto rhs_arrays = p_Vector3_v->cellArrays(); - bool is_same = true; - for (CellId cell_id = 0; cell_id < lhs_values.numberOfItems(); ++cell_id) { - for (size_t i = 0; i < fuv.size(); ++i) { - if (fuv[cell_id][i] != (lhs_values[cell_id] * rhs_arrays[cell_id][i])) { - is_same = false; - break; + SECTION("product") + { + SECTION("Vh * Vh -> Vh") + { + CHECK_SCALAR_VH2_TO_VH(p_R_u, *, p_R_v); + + CHECK_SCALAR_VH2_TO_VH(p_R1x1_u, *, p_R1x1_v); + CHECK_SCALAR_VH2_TO_VH(p_R2x2_u, *, p_R2x2_v); + CHECK_SCALAR_VH2_TO_VH(p_R3x3_u, *, p_R3x3_v); + + CHECK_SCALAR_VH2_TO_VH(p_R_u, *, p_R1_v); + CHECK_SCALAR_VH2_TO_VH(p_R_u, *, p_R2_v); + CHECK_SCALAR_VH2_TO_VH(p_R_u, *, p_R3_v); + + CHECK_SCALAR_VH2_TO_VH(p_R_u, *, p_R1x1_v); + CHECK_SCALAR_VH2_TO_VH(p_R_u, *, p_R2x2_v); + CHECK_SCALAR_VH2_TO_VH(p_R_u, *, p_R3x3_v); + + CHECK_SCALAR_VH2_TO_VH(p_R1x1_u, *, p_R1_v); + CHECK_SCALAR_VH2_TO_VH(p_R2x2_u, *, p_R2_v); + CHECK_SCALAR_VH2_TO_VH(p_R3x3_u, *, p_R3_v); + + { + std::shared_ptr p_fuv = p_R_u * p_Vector3_v; + + REQUIRE(p_fuv.use_count() > 0); + REQUIRE_NOTHROW(dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*p_fuv)); + + const auto& fuv = dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*p_fuv); + + auto lhs_values = p_R_u->cellValues(); + auto rhs_arrays = p_Vector3_v->cellArrays(); + bool is_same = true; + for (CellId cell_id = 0; cell_id < lhs_values.numberOfItems(); ++cell_id) { + for (size_t i = 0; i < fuv.size(); ++i) { + if (fuv[cell_id][i] != (lhs_values[cell_id] * rhs_arrays[cell_id][i])) { + is_same = false; + break; + } + } } - } - } - REQUIRE(is_same); - } + REQUIRE(is_same); + } - REQUIRE_THROWS_WITH(p_R1_u * p_R1_v, "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(p_R2_u * p_R1_v, "error: incompatible operand types Vh(P0:R^2) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(p_R3_u * p_R1x1_v, "error: incompatible operand types Vh(P0:R^3) and Vh(P0:R^1x1)"); - REQUIRE_THROWS_WITH(p_R1_u * p_R2x2_v, "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R^2x2)"); - - REQUIRE_THROWS_WITH(p_R1x1_u * p_R2x2_v, "error: incompatible operand types Vh(P0:R^1x1) and Vh(P0:R^2x2)"); - REQUIRE_THROWS_WITH(p_R2x2_u * p_R3x3_v, "error: incompatible operand types Vh(P0:R^2x2) and Vh(P0:R^3x3)"); - REQUIRE_THROWS_WITH(p_R3x3_u * p_R1x1_v, "error: incompatible operand types Vh(P0:R^3x3) and Vh(P0:R^1x1)"); - - REQUIRE_THROWS_WITH(p_R1x1_u * p_R2_v, "error: incompatible operand types Vh(P0:R^1x1) and Vh(P0:R^2)"); - REQUIRE_THROWS_WITH(p_R2x2_u * p_R3_v, "error: incompatible operand types Vh(P0:R^2x2) and Vh(P0:R^3)"); - REQUIRE_THROWS_WITH(p_R3x3_u * p_R1_v, "error: incompatible operand types Vh(P0:R^3x3) and Vh(P0:R^1)"); - - REQUIRE_THROWS_WITH(p_R1_u * p_Vector3_v, "error: incompatible operand types Vh(P0:R^1) and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH(p_R2_u * p_Vector3_v, "error: incompatible operand types Vh(P0:R^2) and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH(p_R3_u * p_Vector3_v, "error: incompatible operand types Vh(P0:R^3) and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH(p_R1x1_u * p_Vector3_v, - "error: incompatible operand types Vh(P0:R^1x1) and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH(p_R2x2_u * p_Vector3_v, - "error: incompatible operand types Vh(P0:R^2x2) and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH(p_R3x3_u * p_Vector3_v, - "error: incompatible operand types Vh(P0:R^3x3) and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH(p_Vector3_u * p_Vector3_v, - "error: incompatible operand types Vh(P0Vector:R) and Vh(P0Vector:R)"); - - REQUIRE_THROWS_WITH(p_Vector3_v * p_R_u, "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R)"); - REQUIRE_THROWS_WITH(p_Vector3_v * p_R1_u, "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(p_Vector3_v * p_R2_u, "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^2)"); - REQUIRE_THROWS_WITH(p_Vector3_v * p_R3_u, "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^3)"); - REQUIRE_THROWS_WITH(p_Vector3_v * p_R1x1_u, - "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^1x1)"); - REQUIRE_THROWS_WITH(p_Vector3_v * p_R2x2_u, - "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^2x2)"); - REQUIRE_THROWS_WITH(p_Vector3_v * p_R3x3_u, - "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^3x3)"); - - REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R1_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R2_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R3_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R1x1_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R2x2_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R3x3_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R1x1_u * p_other_mesh_R1_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R2x2_u * p_other_mesh_R2_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R3x3_u * p_other_mesh_R3_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_Vector3_u, "error: operands are defined on different meshes"); - } + REQUIRE_THROWS_WITH(p_R1_u * p_R1_v, "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(p_R2_u * p_R1_v, "error: incompatible operand types Vh(P0:R^2) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(p_R3_u * p_R1x1_v, "error: incompatible operand types Vh(P0:R^3) and Vh(P0:R^1x1)"); + REQUIRE_THROWS_WITH(p_R1_u * p_R2x2_v, "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R^2x2)"); + + REQUIRE_THROWS_WITH(p_R1x1_u * p_R2x2_v, + "error: incompatible operand types Vh(P0:R^1x1) and Vh(P0:R^2x2)"); + REQUIRE_THROWS_WITH(p_R2x2_u * p_R3x3_v, + "error: incompatible operand types Vh(P0:R^2x2) and Vh(P0:R^3x3)"); + REQUIRE_THROWS_WITH(p_R3x3_u * p_R1x1_v, + "error: incompatible operand types Vh(P0:R^3x3) and Vh(P0:R^1x1)"); + + REQUIRE_THROWS_WITH(p_R1x1_u * p_R2_v, "error: incompatible operand types Vh(P0:R^1x1) and Vh(P0:R^2)"); + REQUIRE_THROWS_WITH(p_R2x2_u * p_R3_v, "error: incompatible operand types Vh(P0:R^2x2) and Vh(P0:R^3)"); + REQUIRE_THROWS_WITH(p_R3x3_u * p_R1_v, "error: incompatible operand types Vh(P0:R^3x3) and Vh(P0:R^1)"); + + REQUIRE_THROWS_WITH(p_R1_u * p_Vector3_v, + "error: incompatible operand types Vh(P0:R^1) and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH(p_R2_u * p_Vector3_v, + "error: incompatible operand types Vh(P0:R^2) and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH(p_R3_u * p_Vector3_v, + "error: incompatible operand types Vh(P0:R^3) and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH(p_R1x1_u * p_Vector3_v, + "error: incompatible operand types Vh(P0:R^1x1) and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH(p_R2x2_u * p_Vector3_v, + "error: incompatible operand types Vh(P0:R^2x2) and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH(p_R3x3_u * p_Vector3_v, + "error: incompatible operand types Vh(P0:R^3x3) and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH(p_Vector3_u * p_Vector3_v, + "error: incompatible operand types Vh(P0Vector:R) and Vh(P0Vector:R)"); + + REQUIRE_THROWS_WITH(p_Vector3_v * p_R_u, "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R)"); + REQUIRE_THROWS_WITH(p_Vector3_v * p_R1_u, + "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(p_Vector3_v * p_R2_u, + "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^2)"); + REQUIRE_THROWS_WITH(p_Vector3_v * p_R3_u, + "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^3)"); + REQUIRE_THROWS_WITH(p_Vector3_v * p_R1x1_u, + "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^1x1)"); + REQUIRE_THROWS_WITH(p_Vector3_v * p_R2x2_u, + "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^2x2)"); + REQUIRE_THROWS_WITH(p_Vector3_v * p_R3x3_u, + "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^3x3)"); + + REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R1_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R2_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R3_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R1x1_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R2x2_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R3x3_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R1x1_u * p_other_mesh_R1_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R2x2_u * p_other_mesh_R2_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R3x3_u * p_other_mesh_R3_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_Vector3_u, "error: operands are defined on different meshes"); + } - SECTION("Vh * X -> Vh") - { - CHECK_SCALAR_VHxX_TO_VH(p_R_u, *, bool{true}); - CHECK_SCALAR_VHxX_TO_VH(p_R_u, *, uint64_t{1}); - CHECK_SCALAR_VHxX_TO_VH(p_R_u, *, int64_t{2}); - CHECK_SCALAR_VHxX_TO_VH(p_R_u, *, double{1.3}); - - CHECK_SCALAR_VHxX_TO_VH(p_R1x1_u, *, (TinyMatrix<1>{1.3})); - CHECK_SCALAR_VHxX_TO_VH(p_R2x2_u, *, (TinyMatrix<2>{1.2, 2.3, 4.2, 5.1})); - CHECK_SCALAR_VHxX_TO_VH(p_R3x3_u, *, - (TinyMatrix<3>{3.2, 7.1, 5.2, // - 4.7, 2.3, 7.1, // - 9.7, 3.2, 6.8})); - - REQUIRE_THROWS_WITH(p_R1_u * (TinyVector<1>{1}), "error: incompatible operand types Vh(P0:R^1) and R^1"); - REQUIRE_THROWS_WITH(p_R2_u * (TinyVector<2>{1, 2}), "error: incompatible operand types Vh(P0:R^2) and R^2"); - REQUIRE_THROWS_WITH(p_R3_u * (TinyVector<3>{2, 3, 2}), - "error: incompatible operand types Vh(P0:R^3) and R^3"); - REQUIRE_THROWS_WITH(p_R1_u * (TinyMatrix<1>{2}), "error: incompatible operand types Vh(P0:R^1) and R^1x1"); - REQUIRE_THROWS_WITH(p_R2_u * (TinyMatrix<2>{2, 3, 1, 4}), - "error: incompatible operand types Vh(P0:R^2) and R^2x2"); - REQUIRE_THROWS_WITH(p_R3_u * (TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}), - "error: incompatible operand types Vh(P0:R^3) and R^3x3"); - REQUIRE_THROWS_WITH(p_R2x2_u * (TinyMatrix<1>{2}), - "error: incompatible operand types Vh(P0:R^2x2) and R^1x1"); - REQUIRE_THROWS_WITH(p_R1x1_u * (TinyMatrix<2>{2, 3, 1, 4}), - "error: incompatible operand types Vh(P0:R^1x1) and R^2x2"); - REQUIRE_THROWS_WITH(p_R2x2_u * (TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}), - "error: incompatible operand types Vh(P0:R^2x2) and R^3x3"); - - REQUIRE_THROWS_WITH(p_Vector3_u * (TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}), - "error: incompatible operand types Vh(P0Vector:R) and R^3x3"); - REQUIRE_THROWS_WITH(p_Vector3_u * (double{2}), "error: incompatible operand types Vh(P0Vector:R) and R"); - } + SECTION("Vh * X -> Vh") + { + CHECK_SCALAR_VHxX_TO_VH(p_R_u, *, bool{true}); + CHECK_SCALAR_VHxX_TO_VH(p_R_u, *, uint64_t{1}); + CHECK_SCALAR_VHxX_TO_VH(p_R_u, *, int64_t{2}); + CHECK_SCALAR_VHxX_TO_VH(p_R_u, *, double{1.3}); + + CHECK_SCALAR_VHxX_TO_VH(p_R1x1_u, *, (TinyMatrix<1>{1.3})); + CHECK_SCALAR_VHxX_TO_VH(p_R2x2_u, *, (TinyMatrix<2>{1.2, 2.3, 4.2, 5.1})); + CHECK_SCALAR_VHxX_TO_VH(p_R3x3_u, *, + (TinyMatrix<3>{3.2, 7.1, 5.2, // + 4.7, 2.3, 7.1, // + 9.7, 3.2, 6.8})); + + REQUIRE_THROWS_WITH(p_R1_u * (TinyVector<1>{1}), "error: incompatible operand types Vh(P0:R^1) and R^1"); + REQUIRE_THROWS_WITH(p_R2_u * (TinyVector<2>{1, 2}), + "error: incompatible operand types Vh(P0:R^2) and R^2"); + REQUIRE_THROWS_WITH(p_R3_u * (TinyVector<3>{2, 3, 2}), + "error: incompatible operand types Vh(P0:R^3) and R^3"); + REQUIRE_THROWS_WITH(p_R1_u * (TinyMatrix<1>{2}), + "error: incompatible operand types Vh(P0:R^1) and R^1x1"); + REQUIRE_THROWS_WITH(p_R2_u * (TinyMatrix<2>{2, 3, 1, 4}), + "error: incompatible operand types Vh(P0:R^2) and R^2x2"); + REQUIRE_THROWS_WITH(p_R3_u * (TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}), + "error: incompatible operand types Vh(P0:R^3) and R^3x3"); + REQUIRE_THROWS_WITH(p_R2x2_u * (TinyMatrix<1>{2}), + "error: incompatible operand types Vh(P0:R^2x2) and R^1x1"); + REQUIRE_THROWS_WITH(p_R1x1_u * (TinyMatrix<2>{2, 3, 1, 4}), + "error: incompatible operand types Vh(P0:R^1x1) and R^2x2"); + REQUIRE_THROWS_WITH(p_R2x2_u * (TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}), + "error: incompatible operand types Vh(P0:R^2x2) and R^3x3"); + + REQUIRE_THROWS_WITH(p_Vector3_u * (TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}), + "error: incompatible operand types Vh(P0Vector:R) and R^3x3"); + REQUIRE_THROWS_WITH(p_Vector3_u * (double{2}), "error: incompatible operand types Vh(P0Vector:R) and R"); + } - SECTION("X * Vh -> Vh") - { - CHECK_SCALAR_XxVH_TO_VH(bool{true}, *, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(uint64_t{1}, *, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(int64_t{2}, *, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(double{1.3}, *, p_R_u); - - CHECK_SCALAR_XxVH_TO_VH(bool{true}, *, p_R1x1_u); - CHECK_SCALAR_XxVH_TO_VH(uint64_t{1}, *, p_R1x1_u); - CHECK_SCALAR_XxVH_TO_VH(int64_t{2}, *, p_R1x1_u); - CHECK_SCALAR_XxVH_TO_VH(double{1.3}, *, p_R1x1_u); - - CHECK_SCALAR_XxVH_TO_VH(bool{true}, *, p_R2x2_u); - CHECK_SCALAR_XxVH_TO_VH(uint64_t{1}, *, p_R2x2_u); - CHECK_SCALAR_XxVH_TO_VH(int64_t{2}, *, p_R2x2_u); - CHECK_SCALAR_XxVH_TO_VH(double{1.3}, *, p_R2x2_u); - - CHECK_SCALAR_XxVH_TO_VH(bool{true}, *, p_R3x3_u); - CHECK_SCALAR_XxVH_TO_VH(uint64_t{1}, *, p_R3x3_u); - CHECK_SCALAR_XxVH_TO_VH(int64_t{2}, *, p_R3x3_u); - CHECK_SCALAR_XxVH_TO_VH(double{1.3}, *, p_R3x3_u); - - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<1>{1.3}), *, p_R1_u); - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<2>{1.2, 2.3, 4.2, 5.1}), *, p_R2_u); - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<3>{3.2, 7.1, 5.2, // + SECTION("X * Vh -> Vh") + { + CHECK_SCALAR_XxVH_TO_VH(bool{true}, *, p_R_u); + CHECK_SCALAR_XxVH_TO_VH(uint64_t{1}, *, p_R_u); + CHECK_SCALAR_XxVH_TO_VH(int64_t{2}, *, p_R_u); + CHECK_SCALAR_XxVH_TO_VH(double{1.3}, *, p_R_u); + + CHECK_SCALAR_XxVH_TO_VH(bool{true}, *, p_R1x1_u); + CHECK_SCALAR_XxVH_TO_VH(uint64_t{1}, *, p_R1x1_u); + CHECK_SCALAR_XxVH_TO_VH(int64_t{2}, *, p_R1x1_u); + CHECK_SCALAR_XxVH_TO_VH(double{1.3}, *, p_R1x1_u); + + CHECK_SCALAR_XxVH_TO_VH(bool{true}, *, p_R2x2_u); + CHECK_SCALAR_XxVH_TO_VH(uint64_t{1}, *, p_R2x2_u); + CHECK_SCALAR_XxVH_TO_VH(int64_t{2}, *, p_R2x2_u); + CHECK_SCALAR_XxVH_TO_VH(double{1.3}, *, p_R2x2_u); + + CHECK_SCALAR_XxVH_TO_VH(bool{true}, *, p_R3x3_u); + CHECK_SCALAR_XxVH_TO_VH(uint64_t{1}, *, p_R3x3_u); + CHECK_SCALAR_XxVH_TO_VH(int64_t{2}, *, p_R3x3_u); + CHECK_SCALAR_XxVH_TO_VH(double{1.3}, *, p_R3x3_u); + + CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<1>{1.3}), *, p_R1_u); + CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<2>{1.2, 2.3, 4.2, 5.1}), *, p_R2_u); + CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<3>{3.2, 7.1, 5.2, // 4.7, 2.3, 7.1, // 9.7, 3.2, 6.8}), *, p_R3_u); - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<1>{1.3}), *, p_R1x1_u); - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<2>{1.2, 2.3, 4.2, 5.1}), *, p_R2x2_u); - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<3>{3.2, 7.1, 5.2, // + CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<1>{1.3}), *, p_R1x1_u); + CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<2>{1.2, 2.3, 4.2, 5.1}), *, p_R2x2_u); + CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<3>{3.2, 7.1, 5.2, // 4.7, 2.3, 7.1, // 9.7, 3.2, 6.8}), *, p_R3x3_u); - CHECK_VECTOR_XxVH_TO_VH(bool{true}, *, p_Vector3_u); - CHECK_VECTOR_XxVH_TO_VH(uint64_t{1}, *, p_Vector3_u); - CHECK_VECTOR_XxVH_TO_VH(int64_t{2}, *, p_Vector3_u); - CHECK_VECTOR_XxVH_TO_VH(double{1.3}, *, p_Vector3_u); - - REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) * p_R_u, "error: incompatible operand types R^1x1 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) * p_R_u, - "error: incompatible operand types R^2x2 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) * p_R_u, - "error: incompatible operand types R^3x3 and Vh(P0:R)"); - - REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) * p_R2_u, "error: incompatible operand types R^1x1 and Vh(P0:R^2)"); - REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) * p_R3_u, - "error: incompatible operand types R^2x2 and Vh(P0:R^3)"); - REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) * p_R2_u, - "error: incompatible operand types R^3x3 and Vh(P0:R^2)"); - REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) * p_R1_u, - "error: incompatible operand types R^3x3 and Vh(P0:R^1)"); - - REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) * p_R2x2_u, - "error: incompatible operand types R^1x1 and Vh(P0:R^2x2)"); - REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) * p_R3x3_u, - "error: incompatible operand types R^2x2 and Vh(P0:R^3x3)"); - REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) * p_R2x2_u, - "error: incompatible operand types R^3x3 and Vh(P0:R^2x2)"); - REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) * p_R1x1_u, - "error: incompatible operand types R^2x2 and Vh(P0:R^1x1)"); - - REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) * p_Vector3_u, - "error: incompatible operand types R^3x3 and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) * p_Vector3_u, - "error: incompatible operand types R^1x1 and Vh(P0Vector:R)"); - } - } + CHECK_VECTOR_XxVH_TO_VH(bool{true}, *, p_Vector3_u); + CHECK_VECTOR_XxVH_TO_VH(uint64_t{1}, *, p_Vector3_u); + CHECK_VECTOR_XxVH_TO_VH(int64_t{2}, *, p_Vector3_u); + CHECK_VECTOR_XxVH_TO_VH(double{1.3}, *, p_Vector3_u); + + REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) * p_R_u, "error: incompatible operand types R^1x1 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) * p_R_u, + "error: incompatible operand types R^2x2 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) * p_R_u, + "error: incompatible operand types R^3x3 and Vh(P0:R)"); + + REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) * p_R2_u, + "error: incompatible operand types R^1x1 and Vh(P0:R^2)"); + REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) * p_R3_u, + "error: incompatible operand types R^2x2 and Vh(P0:R^3)"); + REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) * p_R2_u, + "error: incompatible operand types R^3x3 and Vh(P0:R^2)"); + REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) * p_R1_u, + "error: incompatible operand types R^3x3 and Vh(P0:R^1)"); + + REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) * p_R2x2_u, + "error: incompatible operand types R^1x1 and Vh(P0:R^2x2)"); + REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) * p_R3x3_u, + "error: incompatible operand types R^2x2 and Vh(P0:R^3x3)"); + REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) * p_R2x2_u, + "error: incompatible operand types R^3x3 and Vh(P0:R^2x2)"); + REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) * p_R1x1_u, + "error: incompatible operand types R^2x2 and Vh(P0:R^1x1)"); + + REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) * p_Vector3_u, + "error: incompatible operand types R^3x3 and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) * p_Vector3_u, + "error: incompatible operand types R^1x1 and Vh(P0Vector:R)"); + } + } - SECTION("ratio") - { - SECTION("Vh / Vh -> Vh") - { - CHECK_SCALAR_VH2_TO_VH(p_R_u, /, p_R_v); + SECTION("ratio") + { + SECTION("Vh / Vh -> Vh") + { + CHECK_SCALAR_VH2_TO_VH(p_R_u, /, p_R_v); - REQUIRE_THROWS_WITH(p_R_u / p_R1_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(p_R2_u / p_R1_v, "error: incompatible operand types Vh(P0:R^2) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(p_R3_u / p_R1x1_v, "error: incompatible operand types Vh(P0:R^3) and Vh(P0:R^1x1)"); - REQUIRE_THROWS_WITH(p_R_u / p_R2x2_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^2x2)"); + REQUIRE_THROWS_WITH(p_R_u / p_R1_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(p_R2_u / p_R1_v, "error: incompatible operand types Vh(P0:R^2) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(p_R3_u / p_R1x1_v, "error: incompatible operand types Vh(P0:R^3) and Vh(P0:R^1x1)"); + REQUIRE_THROWS_WITH(p_R_u / p_R2x2_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^2x2)"); - REQUIRE_THROWS_WITH(p_R_u / p_other_mesh_R_u, "error: operands are defined on different meshes"); - } + REQUIRE_THROWS_WITH(p_R_u / p_other_mesh_R_u, "error: operands are defined on different meshes"); + } - SECTION("X / Vh -> Vh") - { - CHECK_SCALAR_XxVH_TO_VH(bool{true}, /, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(uint64_t{1}, /, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(int64_t{2}, /, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(double{1.3}, /, p_R_u); + SECTION("X / Vh -> Vh") + { + CHECK_SCALAR_XxVH_TO_VH(bool{true}, /, p_R_u); + CHECK_SCALAR_XxVH_TO_VH(uint64_t{1}, /, p_R_u); + CHECK_SCALAR_XxVH_TO_VH(int64_t{2}, /, p_R_u); + CHECK_SCALAR_XxVH_TO_VH(double{1.3}, /, p_R_u); + } + } } } } @@ -2214,133 +2293,140 @@ TEST_CASE("EmbeddedIDiscreteFunctionOperators", "[scheme]") using Rd = TinyVector<Dimension>; - std::shared_ptr mesh = MeshDataBaseForTests::get().cartesianMesh1D(); - - CellValue<const Rd> xj = MeshDataManager::instance().getMeshData(*mesh).xj(); - - CellValue<double> u_R_values = [=] { - CellValue<double> build_values{mesh->connectivity()}; - parallel_for( - build_values.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 0.2 + std::cos(l2Norm(xj[cell_id])); }); - return build_values; - }(); - - std::shared_ptr p_R_u = std::make_shared<const DiscreteFunctionP0<Dimension, double>>(mesh, u_R_values); + std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - std::shared_ptr p_R1_u = [=] { - CellValue<TinyVector<1>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { uj[cell_id][0] = 2 * xj[cell_id][0] + 1; }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<1>>>(mesh, uj); - }(); - - constexpr auto to_2d = [&](const TinyVector<Dimension>& x) -> TinyVector<2> { - if constexpr (Dimension == 1) { - return {x[0], 1 + x[0] * x[0]}; - } else if constexpr (Dimension == 2) { - return {x[0], x[1]}; - } else if constexpr (Dimension == 3) { - return {x[0], x[1] + x[2]}; - } - }; - - std::shared_ptr p_R2_u = [=] { - CellValue<TinyVector<2>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<2> x = to_2d(xj[cell_id]); - uj[cell_id] = {2 * x[0] + 1, 1 - x[1]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<2>>>(mesh, uj); - }(); - - constexpr auto to_3d = [&](const TinyVector<Dimension>& x) -> TinyVector<3> { - if constexpr (Dimension == 1) { - return {x[0], 1 + x[0] * x[0], 2 - x[0]}; - } else if constexpr (Dimension == 2) { - return {x[0], x[1], x[0] + x[1]}; - } else if constexpr (Dimension == 3) { - return {x[0], x[1], x[2]}; - } - }; - - std::shared_ptr p_R3_u = [=] { - CellValue<TinyVector<3>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - uj[cell_id] = {2 * x[0] + 1, 1 - x[1] * x[2], x[0] + x[2]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<3>>>(mesh, uj); - }(); - - std::shared_ptr p_R1x1_u = [=] { - CellValue<TinyMatrix<1>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { uj[cell_id] = {2 * xj[cell_id][0] + 1}; }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<1>>>(mesh, uj); - }(); - - std::shared_ptr p_R2x2_u = [=] { - CellValue<TinyMatrix<2>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<2> x = to_2d(xj[cell_id]); - - uj[cell_id] = {2 * x[0] + 1, 1 - x[1], // - 2 * x[1], -x[0]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<2>>>(mesh, uj); - }(); - - std::shared_ptr p_R3x3_u = [=] { - CellValue<TinyMatrix<3>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - - uj[cell_id] = {2 * x[0] + 1, 1 - x[1], 3, // - 2 * x[1], -x[0], x[0] - x[1], // - 3 * x[2] - x[1], x[1] - 2 * x[2], x[2] - x[0]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<3>>>(mesh, uj); - }(); - - std::shared_ptr p_Vector3_u = [=] { - CellArray<double> uj_vector{mesh->connectivity(), 3}; - parallel_for( - uj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - uj_vector[cell_id][0] = 2 * x[0] + 1; - uj_vector[cell_id][1] = 1 - x[1] * x[2]; - uj_vector[cell_id][2] = x[0] + x[2]; - }); - - return std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(mesh, uj_vector); - }(); - - SECTION("unary minus") - { - SECTION("- Vh -> Vh") + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) { - CHECK_SCALAR_VH_TO_VH(-, p_R_u); + auto mesh = named_mesh.mesh(); + + CellValue<const Rd> xj = MeshDataManager::instance().getMeshData(*mesh).xj(); + + CellValue<double> u_R_values = [=] { + CellValue<double> build_values{mesh->connectivity()}; + parallel_for( + build_values.numberOfItems(), + PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 0.2 + std::cos(l2Norm(xj[cell_id])); }); + return build_values; + }(); + + std::shared_ptr p_R_u = std::make_shared<const DiscreteFunctionP0<Dimension, double>>(mesh, u_R_values); + + std::shared_ptr p_R1_u = [=] { + CellValue<TinyVector<1>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { uj[cell_id][0] = 2 * xj[cell_id][0] + 1; }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<1>>>(mesh, uj); + }(); + + constexpr auto to_2d = [&](const TinyVector<Dimension>& x) -> TinyVector<2> { + if constexpr (Dimension == 1) { + return {x[0], 1 + x[0] * x[0]}; + } else if constexpr (Dimension == 2) { + return {x[0], x[1]}; + } else if constexpr (Dimension == 3) { + return {x[0], x[1] + x[2]}; + } + }; + + std::shared_ptr p_R2_u = [=] { + CellValue<TinyVector<2>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<2> x = to_2d(xj[cell_id]); + uj[cell_id] = {2 * x[0] + 1, 1 - x[1]}; + }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<2>>>(mesh, uj); + }(); + + constexpr auto to_3d = [&](const TinyVector<Dimension>& x) -> TinyVector<3> { + if constexpr (Dimension == 1) { + return {x[0], 1 + x[0] * x[0], 2 - x[0]}; + } else if constexpr (Dimension == 2) { + return {x[0], x[1], x[0] + x[1]}; + } else if constexpr (Dimension == 3) { + return {x[0], x[1], x[2]}; + } + }; + + std::shared_ptr p_R3_u = [=] { + CellValue<TinyVector<3>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + uj[cell_id] = {2 * x[0] + 1, 1 - x[1] * x[2], x[0] + x[2]}; + }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<3>>>(mesh, uj); + }(); + + std::shared_ptr p_R1x1_u = [=] { + CellValue<TinyMatrix<1>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { uj[cell_id] = {2 * xj[cell_id][0] + 1}; }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<1>>>(mesh, uj); + }(); + + std::shared_ptr p_R2x2_u = [=] { + CellValue<TinyMatrix<2>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<2> x = to_2d(xj[cell_id]); + + uj[cell_id] = {2 * x[0] + 1, 1 - x[1], // + 2 * x[1], -x[0]}; + }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<2>>>(mesh, uj); + }(); + + std::shared_ptr p_R3x3_u = [=] { + CellValue<TinyMatrix<3>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + + uj[cell_id] = {2 * x[0] + 1, 1 - x[1], 3, // + 2 * x[1], -x[0], x[0] - x[1], // + 3 * x[2] - x[1], x[1] - 2 * x[2], x[2] - x[0]}; + }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<3>>>(mesh, uj); + }(); + + std::shared_ptr p_Vector3_u = [=] { + CellArray<double> uj_vector{mesh->connectivity(), 3}; + parallel_for( + uj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + uj_vector[cell_id][0] = 2 * x[0] + 1; + uj_vector[cell_id][1] = 1 - x[1] * x[2]; + uj_vector[cell_id][2] = x[0] + x[2]; + }); + + return std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(mesh, uj_vector); + }(); + + SECTION("unary minus") + { + SECTION("- Vh -> Vh") + { + CHECK_SCALAR_VH_TO_VH(-, p_R_u); - CHECK_SCALAR_VH_TO_VH(-, p_R1_u); - CHECK_SCALAR_VH_TO_VH(-, p_R2_u); - CHECK_SCALAR_VH_TO_VH(-, p_R3_u); + CHECK_SCALAR_VH_TO_VH(-, p_R1_u); + CHECK_SCALAR_VH_TO_VH(-, p_R2_u); + CHECK_SCALAR_VH_TO_VH(-, p_R3_u); - CHECK_SCALAR_VH_TO_VH(-, p_R1x1_u); - CHECK_SCALAR_VH_TO_VH(-, p_R2x2_u); - CHECK_SCALAR_VH_TO_VH(-, p_R3x3_u); + CHECK_SCALAR_VH_TO_VH(-, p_R1x1_u); + CHECK_SCALAR_VH_TO_VH(-, p_R2x2_u); + CHECK_SCALAR_VH_TO_VH(-, p_R3x3_u); - CHECK_VECTOR_VH_TO_VH(-, p_Vector3_u); + CHECK_VECTOR_VH_TO_VH(-, p_Vector3_u); + } + } } } } @@ -2351,133 +2437,140 @@ TEST_CASE("EmbeddedIDiscreteFunctionOperators", "[scheme]") using Rd = TinyVector<Dimension>; - std::shared_ptr mesh = MeshDataBaseForTests::get().cartesianMesh2D(); + std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - CellValue<const Rd> xj = MeshDataManager::instance().getMeshData(*mesh).xj(); - - CellValue<double> u_R_values = [=] { - CellValue<double> build_values{mesh->connectivity()}; - parallel_for( - build_values.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 0.2 + std::cos(l2Norm(xj[cell_id])); }); - return build_values; - }(); - - std::shared_ptr p_R_u = std::make_shared<const DiscreteFunctionP0<Dimension, double>>(mesh, u_R_values); - - std::shared_ptr p_R1_u = [=] { - CellValue<TinyVector<1>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { uj[cell_id][0] = 2 * xj[cell_id][0] + 1; }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<1>>>(mesh, uj); - }(); - - constexpr auto to_2d = [&](const TinyVector<Dimension>& x) -> TinyVector<2> { - if constexpr (Dimension == 1) { - return {x[0], 1 + x[0] * x[0]}; - } else if constexpr (Dimension == 2) { - return {x[0], x[1]}; - } else if constexpr (Dimension == 3) { - return {x[0], x[1] + x[2]}; - } - }; - - std::shared_ptr p_R2_u = [=] { - CellValue<TinyVector<2>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<2> x = to_2d(xj[cell_id]); - uj[cell_id] = {2 * x[0] + 1, 1 - x[1]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<2>>>(mesh, uj); - }(); - - constexpr auto to_3d = [&](const TinyVector<Dimension>& x) -> TinyVector<3> { - if constexpr (Dimension == 1) { - return {x[0], 1 + x[0] * x[0], 2 - x[0]}; - } else if constexpr (Dimension == 2) { - return {x[0], x[1], x[0] + x[1]}; - } else if constexpr (Dimension == 3) { - return {x[0], x[1], x[2]}; - } - }; - - std::shared_ptr p_R3_u = [=] { - CellValue<TinyVector<3>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - uj[cell_id] = {2 * x[0] + 1, 1 - x[1] * x[2], x[0] + x[2]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<3>>>(mesh, uj); - }(); - - std::shared_ptr p_R1x1_u = [=] { - CellValue<TinyMatrix<1>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { uj[cell_id] = {2 * xj[cell_id][0] + 1}; }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<1>>>(mesh, uj); - }(); - - std::shared_ptr p_R2x2_u = [=] { - CellValue<TinyMatrix<2>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<2> x = to_2d(xj[cell_id]); - - uj[cell_id] = {2 * x[0] + 1, 1 - x[1], // - 2 * x[1], -x[0]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<2>>>(mesh, uj); - }(); - - std::shared_ptr p_R3x3_u = [=] { - CellValue<TinyMatrix<3>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - - uj[cell_id] = {2 * x[0] + 1, 1 - x[1], 3, // - 2 * x[1], -x[0], x[0] - x[1], // - 3 * x[2] - x[1], x[1] - 2 * x[2], x[2] - x[0]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<3>>>(mesh, uj); - }(); - - std::shared_ptr p_Vector3_u = [=] { - CellArray<double> uj_vector{mesh->connectivity(), 3}; - parallel_for( - uj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - uj_vector[cell_id][0] = 2 * x[0] + 1; - uj_vector[cell_id][1] = 1 - x[1] * x[2]; - uj_vector[cell_id][2] = x[0] + x[2]; - }); - - return std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(mesh, uj_vector); - }(); - - SECTION("unary minus") - { - SECTION("- Vh -> Vh") + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) { - CHECK_SCALAR_VH_TO_VH(-, p_R_u); + auto mesh = named_mesh.mesh(); + + CellValue<const Rd> xj = MeshDataManager::instance().getMeshData(*mesh).xj(); + + CellValue<double> u_R_values = [=] { + CellValue<double> build_values{mesh->connectivity()}; + parallel_for( + build_values.numberOfItems(), + PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 0.2 + std::cos(l2Norm(xj[cell_id])); }); + return build_values; + }(); + + std::shared_ptr p_R_u = std::make_shared<const DiscreteFunctionP0<Dimension, double>>(mesh, u_R_values); + + std::shared_ptr p_R1_u = [=] { + CellValue<TinyVector<1>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { uj[cell_id][0] = 2 * xj[cell_id][0] + 1; }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<1>>>(mesh, uj); + }(); + + constexpr auto to_2d = [&](const TinyVector<Dimension>& x) -> TinyVector<2> { + if constexpr (Dimension == 1) { + return {x[0], 1 + x[0] * x[0]}; + } else if constexpr (Dimension == 2) { + return {x[0], x[1]}; + } else if constexpr (Dimension == 3) { + return {x[0], x[1] + x[2]}; + } + }; + + std::shared_ptr p_R2_u = [=] { + CellValue<TinyVector<2>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<2> x = to_2d(xj[cell_id]); + uj[cell_id] = {2 * x[0] + 1, 1 - x[1]}; + }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<2>>>(mesh, uj); + }(); + + constexpr auto to_3d = [&](const TinyVector<Dimension>& x) -> TinyVector<3> { + if constexpr (Dimension == 1) { + return {x[0], 1 + x[0] * x[0], 2 - x[0]}; + } else if constexpr (Dimension == 2) { + return {x[0], x[1], x[0] + x[1]}; + } else if constexpr (Dimension == 3) { + return {x[0], x[1], x[2]}; + } + }; + + std::shared_ptr p_R3_u = [=] { + CellValue<TinyVector<3>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + uj[cell_id] = {2 * x[0] + 1, 1 - x[1] * x[2], x[0] + x[2]}; + }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<3>>>(mesh, uj); + }(); + + std::shared_ptr p_R1x1_u = [=] { + CellValue<TinyMatrix<1>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { uj[cell_id] = {2 * xj[cell_id][0] + 1}; }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<1>>>(mesh, uj); + }(); + + std::shared_ptr p_R2x2_u = [=] { + CellValue<TinyMatrix<2>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<2> x = to_2d(xj[cell_id]); + + uj[cell_id] = {2 * x[0] + 1, 1 - x[1], // + 2 * x[1], -x[0]}; + }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<2>>>(mesh, uj); + }(); + + std::shared_ptr p_R3x3_u = [=] { + CellValue<TinyMatrix<3>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + + uj[cell_id] = {2 * x[0] + 1, 1 - x[1], 3, // + 2 * x[1], -x[0], x[0] - x[1], // + 3 * x[2] - x[1], x[1] - 2 * x[2], x[2] - x[0]}; + }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<3>>>(mesh, uj); + }(); + + std::shared_ptr p_Vector3_u = [=] { + CellArray<double> uj_vector{mesh->connectivity(), 3}; + parallel_for( + uj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + uj_vector[cell_id][0] = 2 * x[0] + 1; + uj_vector[cell_id][1] = 1 - x[1] * x[2]; + uj_vector[cell_id][2] = x[0] + x[2]; + }); + + return std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(mesh, uj_vector); + }(); + + SECTION("unary minus") + { + SECTION("- Vh -> Vh") + { + CHECK_SCALAR_VH_TO_VH(-, p_R_u); - CHECK_SCALAR_VH_TO_VH(-, p_R1_u); - CHECK_SCALAR_VH_TO_VH(-, p_R2_u); - CHECK_SCALAR_VH_TO_VH(-, p_R3_u); + CHECK_SCALAR_VH_TO_VH(-, p_R1_u); + CHECK_SCALAR_VH_TO_VH(-, p_R2_u); + CHECK_SCALAR_VH_TO_VH(-, p_R3_u); - CHECK_SCALAR_VH_TO_VH(-, p_R1x1_u); - CHECK_SCALAR_VH_TO_VH(-, p_R2x2_u); - CHECK_SCALAR_VH_TO_VH(-, p_R3x3_u); + CHECK_SCALAR_VH_TO_VH(-, p_R1x1_u); + CHECK_SCALAR_VH_TO_VH(-, p_R2x2_u); + CHECK_SCALAR_VH_TO_VH(-, p_R3x3_u); - CHECK_VECTOR_VH_TO_VH(-, p_Vector3_u); + CHECK_VECTOR_VH_TO_VH(-, p_Vector3_u); + } + } } } } @@ -2488,135 +2581,146 @@ TEST_CASE("EmbeddedIDiscreteFunctionOperators", "[scheme]") using Rd = TinyVector<Dimension>; - std::shared_ptr mesh = MeshDataBaseForTests::get().cartesianMesh3D(); - - CellValue<const Rd> xj = MeshDataManager::instance().getMeshData(*mesh).xj(); + std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - CellValue<double> u_R_values = [=] { - CellValue<double> build_values{mesh->connectivity()}; - parallel_for( - build_values.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 0.2 + std::cos(l2Norm(xj[cell_id])); }); - return build_values; - }(); - - std::shared_ptr p_R_u = std::make_shared<const DiscreteFunctionP0<Dimension, double>>(mesh, u_R_values); - - std::shared_ptr p_R1_u = [=] { - CellValue<TinyVector<1>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { uj[cell_id][0] = 2 * xj[cell_id][0] + 1; }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<1>>>(mesh, uj); - }(); - - constexpr auto to_2d = [&](const TinyVector<Dimension>& x) -> TinyVector<2> { - if constexpr (Dimension == 1) { - return {x[0], 1 + x[0] * x[0]}; - } else if constexpr (Dimension == 2) { - return {x[0], x[1]}; - } else if constexpr (Dimension == 3) { - return {x[0], x[1] + x[2]}; - } - }; - - std::shared_ptr p_R2_u = [=] { - CellValue<TinyVector<2>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<2> x = to_2d(xj[cell_id]); - uj[cell_id] = {2 * x[0] + 1, 1 - x[1]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<2>>>(mesh, uj); - }(); - - constexpr auto to_3d = [&](const TinyVector<Dimension>& x) -> TinyVector<3> { - if constexpr (Dimension == 1) { - return {x[0], 1 + x[0] * x[0], 2 - x[0]}; - } else if constexpr (Dimension == 2) { - return {x[0], x[1], x[0] + x[1]}; - } else if constexpr (Dimension == 3) { - return {x[0], x[1], x[2]}; - } - }; - - std::shared_ptr p_R3_u = [=] { - CellValue<TinyVector<3>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - uj[cell_id] = {2 * x[0] + 1, 1 - x[1] * x[2], x[0] + x[2]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<3>>>(mesh, uj); - }(); - - std::shared_ptr p_R1x1_u = [=] { - CellValue<TinyMatrix<1>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { uj[cell_id] = {2 * xj[cell_id][0] + 1}; }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<1>>>(mesh, uj); - }(); - - std::shared_ptr p_R2x2_u = [=] { - CellValue<TinyMatrix<2>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<2> x = to_2d(xj[cell_id]); - - uj[cell_id] = {2 * x[0] + 1, 1 - x[1], // - 2 * x[1], -x[0]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<2>>>(mesh, uj); - }(); - - std::shared_ptr p_R3x3_u = [=] { - CellValue<TinyMatrix<3>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - - uj[cell_id] = {2 * x[0] + 1, 1 - x[1], 3, // - 2 * x[1], -x[0], x[0] - x[1], // - 3 * x[2] - x[1], x[1] - 2 * x[2], x[2] - x[0]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<3>>>(mesh, uj); - }(); - - std::shared_ptr p_Vector3_u = [=] { - CellArray<double> uj_vector{mesh->connectivity(), 3}; - parallel_for( - uj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - uj_vector[cell_id][0] = 2 * x[0] + 1; - uj_vector[cell_id][1] = 1 - x[1] * x[2]; - uj_vector[cell_id][2] = x[0] + x[2]; - }); - - return std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(mesh, uj_vector); - }(); - - SECTION("unary minus") - { - SECTION("- Vh -> Vh") + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) { - CHECK_SCALAR_VH_TO_VH(-, p_R_u); + auto mesh = named_mesh.mesh(); + + CellValue<const Rd> xj = MeshDataManager::instance().getMeshData(*mesh).xj(); + + CellValue<double> u_R_values = [=] { + CellValue<double> build_values{mesh->connectivity()}; + parallel_for( + build_values.numberOfItems(), + PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 0.2 + std::cos(l2Norm(xj[cell_id])); }); + return build_values; + }(); + + std::shared_ptr p_R_u = std::make_shared<const DiscreteFunctionP0<Dimension, double>>(mesh, u_R_values); + + std::shared_ptr p_R1_u = [=] { + CellValue<TinyVector<1>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { uj[cell_id][0] = 2 * xj[cell_id][0] + 1; }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<1>>>(mesh, uj); + }(); + + constexpr auto to_2d = [&](const TinyVector<Dimension>& x) -> TinyVector<2> { + if constexpr (Dimension == 1) { + return {x[0], 1 + x[0] * x[0]}; + } else if constexpr (Dimension == 2) { + return {x[0], x[1]}; + } else if constexpr (Dimension == 3) { + return {x[0], x[1] + x[2]}; + } + }; + + std::shared_ptr p_R2_u = [=] { + CellValue<TinyVector<2>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<2> x = to_2d(xj[cell_id]); + uj[cell_id] = {2 * x[0] + 1, 1 - x[1]}; + }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<2>>>(mesh, uj); + }(); + + constexpr auto to_3d = [&](const TinyVector<Dimension>& x) -> TinyVector<3> { + if constexpr (Dimension == 1) { + return {x[0], 1 + x[0] * x[0], 2 - x[0]}; + } else if constexpr (Dimension == 2) { + return {x[0], x[1], x[0] + x[1]}; + } else if constexpr (Dimension == 3) { + return {x[0], x[1], x[2]}; + } + }; + + std::shared_ptr p_R3_u = [=] { + CellValue<TinyVector<3>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + uj[cell_id] = {2 * x[0] + 1, 1 - x[1] * x[2], x[0] + x[2]}; + }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<3>>>(mesh, uj); + }(); + + std::shared_ptr p_R1x1_u = [=] { + CellValue<TinyMatrix<1>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { uj[cell_id] = {2 * xj[cell_id][0] + 1}; }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<1>>>(mesh, uj); + }(); + + std::shared_ptr p_R2x2_u = [=] { + CellValue<TinyMatrix<2>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<2> x = to_2d(xj[cell_id]); + + uj[cell_id] = {2 * x[0] + 1, 1 - x[1], // + 2 * x[1], -x[0]}; + }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<2>>>(mesh, uj); + }(); + + std::shared_ptr p_R3x3_u = [=] { + CellValue<TinyMatrix<3>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + + uj[cell_id] = {2 * x[0] + 1, 1 - x[1], 3, // + 2 * x[1], -x[0], x[0] - x[1], // + 3 * x[2] - x[1], x[1] - 2 * x[2], x[2] - x[0]}; + }); + + return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<3>>>(mesh, uj); + }(); + + std::shared_ptr p_Vector3_u = [=] { + CellArray<double> uj_vector{mesh->connectivity(), 3}; + parallel_for( + uj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + uj_vector[cell_id][0] = 2 * x[0] + 1; + uj_vector[cell_id][1] = 1 - x[1] * x[2]; + uj_vector[cell_id][2] = x[0] + x[2]; + }); + + return std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(mesh, uj_vector); + }(); + + SECTION("unary minus") + { + SECTION("- Vh -> Vh") + { + CHECK_SCALAR_VH_TO_VH(-, p_R_u); - CHECK_SCALAR_VH_TO_VH(-, p_R1_u); - CHECK_SCALAR_VH_TO_VH(-, p_R2_u); - CHECK_SCALAR_VH_TO_VH(-, p_R3_u); + CHECK_SCALAR_VH_TO_VH(-, p_R1_u); + CHECK_SCALAR_VH_TO_VH(-, p_R2_u); + CHECK_SCALAR_VH_TO_VH(-, p_R3_u); - CHECK_SCALAR_VH_TO_VH(-, p_R1x1_u); - CHECK_SCALAR_VH_TO_VH(-, p_R2x2_u); - CHECK_SCALAR_VH_TO_VH(-, p_R3x3_u); + CHECK_SCALAR_VH_TO_VH(-, p_R1x1_u); + CHECK_SCALAR_VH_TO_VH(-, p_R2x2_u); + CHECK_SCALAR_VH_TO_VH(-, p_R3x3_u); - CHECK_VECTOR_VH_TO_VH(-, p_Vector3_u); + CHECK_VECTOR_VH_TO_VH(-, p_Vector3_u); + } + } } } } } } + +#ifdef __clang__ +#pragma clang optimize on +#endif // __clang__ diff --git a/tests/test_EmbeddedIDiscreteFunctionUtils.cpp b/tests/test_EmbeddedIDiscreteFunctionUtils.cpp index 0ded74fd6b5764bfb67917a48a1a24ab8b1db873..e7d0e8eea200cb115be60a2ba789999155cf5fab 100644 --- a/tests/test_EmbeddedIDiscreteFunctionUtils.cpp +++ b/tests/test_EmbeddedIDiscreteFunctionUtils.cpp @@ -29,28 +29,46 @@ TEST_CASE("EmbeddedIDiscreteFunctionUtils", "[language]") SECTION("discrete P0 function") { - std::shared_ptr mesh_1d = MeshDataBaseForTests::get().cartesianMesh1D(); - - REQUIRE(EmbeddedIDiscreteFunctionUtils::getOperandTypeName(DiscreteFunctionP0<1, double>{mesh_1d}) == "Vh(P0:R)"); - - REQUIRE(EmbeddedIDiscreteFunctionUtils::getOperandTypeName(DiscreteFunctionP0<1, R1>{mesh_1d}) == "Vh(P0:R^1)"); - REQUIRE(EmbeddedIDiscreteFunctionUtils::getOperandTypeName(DiscreteFunctionP0<1, R2>{mesh_1d}) == "Vh(P0:R^2)"); - REQUIRE(EmbeddedIDiscreteFunctionUtils::getOperandTypeName(DiscreteFunctionP0<1, R3>{mesh_1d}) == "Vh(P0:R^3)"); - - REQUIRE(EmbeddedIDiscreteFunctionUtils::getOperandTypeName(DiscreteFunctionP0<1, R1x1>{mesh_1d}) == - "Vh(P0:R^1x1)"); - REQUIRE(EmbeddedIDiscreteFunctionUtils::getOperandTypeName(DiscreteFunctionP0<1, R2x2>{mesh_1d}) == - "Vh(P0:R^2x2)"); - REQUIRE(EmbeddedIDiscreteFunctionUtils::getOperandTypeName(DiscreteFunctionP0<1, R3x3>{mesh_1d}) == - "Vh(P0:R^3x3)"); + std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); + + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_1d = named_mesh.mesh(); + + REQUIRE(EmbeddedIDiscreteFunctionUtils::getOperandTypeName(DiscreteFunctionP0<1, double>{mesh_1d}) == + "Vh(P0:R)"); + + REQUIRE(EmbeddedIDiscreteFunctionUtils::getOperandTypeName(DiscreteFunctionP0<1, R1>{mesh_1d}) == + "Vh(P0:R^1)"); + REQUIRE(EmbeddedIDiscreteFunctionUtils::getOperandTypeName(DiscreteFunctionP0<1, R2>{mesh_1d}) == + "Vh(P0:R^2)"); + REQUIRE(EmbeddedIDiscreteFunctionUtils::getOperandTypeName(DiscreteFunctionP0<1, R3>{mesh_1d}) == + "Vh(P0:R^3)"); + + REQUIRE(EmbeddedIDiscreteFunctionUtils::getOperandTypeName(DiscreteFunctionP0<1, R1x1>{mesh_1d}) == + "Vh(P0:R^1x1)"); + REQUIRE(EmbeddedIDiscreteFunctionUtils::getOperandTypeName(DiscreteFunctionP0<1, R2x2>{mesh_1d}) == + "Vh(P0:R^2x2)"); + REQUIRE(EmbeddedIDiscreteFunctionUtils::getOperandTypeName(DiscreteFunctionP0<1, R3x3>{mesh_1d}) == + "Vh(P0:R^3x3)"); + } + } } SECTION("discrete P0Vector function") { - std::shared_ptr mesh_1d = MeshDataBaseForTests::get().cartesianMesh1D(); + std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); + + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_1d = named_mesh.mesh(); - REQUIRE(EmbeddedIDiscreteFunctionUtils::getOperandTypeName(DiscreteFunctionP0Vector<1, double>{mesh_1d, 2}) == - "Vh(P0Vector:R)"); + REQUIRE(EmbeddedIDiscreteFunctionUtils::getOperandTypeName(DiscreteFunctionP0Vector<1, double>{mesh_1d, 2}) == + "Vh(P0Vector:R)"); + } + } } } @@ -58,59 +76,83 @@ TEST_CASE("EmbeddedIDiscreteFunctionUtils", "[language]") { SECTION("from shared_ptr") { - std::shared_ptr mesh_1d = MeshDataBaseForTests::get().cartesianMesh1D(); - - REQUIRE( - EmbeddedIDiscreteFunctionUtils::isSameDiscretization(std::make_shared<DiscreteFunctionP0<1, double>>(mesh_1d), - std::make_shared<DiscreteFunctionP0<1, double>>(mesh_1d))); - - REQUIRE(not EmbeddedIDiscreteFunctionUtils:: - isSameDiscretization(std::make_shared<DiscreteFunctionP0<1, double>>(mesh_1d), - std::make_shared<DiscreteFunctionP0Vector<1, double>>(mesh_1d, 1))); + std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); + + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_1d = named_mesh.mesh(); + + REQUIRE(EmbeddedIDiscreteFunctionUtils::isSameDiscretization(std::make_shared<DiscreteFunctionP0<1, double>>( + mesh_1d), + std::make_shared<DiscreteFunctionP0<1, double>>( + mesh_1d))); + + REQUIRE(not EmbeddedIDiscreteFunctionUtils:: + isSameDiscretization(std::make_shared<DiscreteFunctionP0<1, double>>(mesh_1d), + std::make_shared<DiscreteFunctionP0Vector<1, double>>(mesh_1d, 1))); + } + } } SECTION("from value") { - std::shared_ptr mesh_1d = MeshDataBaseForTests::get().cartesianMesh1D(); + std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - REQUIRE(EmbeddedIDiscreteFunctionUtils::isSameDiscretization(DiscreteFunctionP0<1, double>{mesh_1d}, - DiscreteFunctionP0<1, double>{mesh_1d})); + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_1d = named_mesh.mesh(); - REQUIRE(EmbeddedIDiscreteFunctionUtils::isSameDiscretization(DiscreteFunctionP0<1, R1>{mesh_1d}, - DiscreteFunctionP0<1, R1>{mesh_1d})); + REQUIRE(EmbeddedIDiscreteFunctionUtils::isSameDiscretization(DiscreteFunctionP0<1, double>{mesh_1d}, + DiscreteFunctionP0<1, double>{mesh_1d})); - REQUIRE(EmbeddedIDiscreteFunctionUtils::isSameDiscretization(DiscreteFunctionP0<1, R2>{mesh_1d}, - DiscreteFunctionP0<1, R2>{mesh_1d})); + REQUIRE(EmbeddedIDiscreteFunctionUtils::isSameDiscretization(DiscreteFunctionP0<1, R1>{mesh_1d}, + DiscreteFunctionP0<1, R1>{mesh_1d})); - REQUIRE(EmbeddedIDiscreteFunctionUtils::isSameDiscretization(DiscreteFunctionP0<1, R3>{mesh_1d}, - DiscreteFunctionP0<1, R3>{mesh_1d})); + REQUIRE(EmbeddedIDiscreteFunctionUtils::isSameDiscretization(DiscreteFunctionP0<1, R2>{mesh_1d}, + DiscreteFunctionP0<1, R2>{mesh_1d})); - REQUIRE(EmbeddedIDiscreteFunctionUtils::isSameDiscretization(DiscreteFunctionP0<1, R1x1>{mesh_1d}, - DiscreteFunctionP0<1, R1x1>{mesh_1d})); + REQUIRE(EmbeddedIDiscreteFunctionUtils::isSameDiscretization(DiscreteFunctionP0<1, R3>{mesh_1d}, + DiscreteFunctionP0<1, R3>{mesh_1d})); - REQUIRE(EmbeddedIDiscreteFunctionUtils::isSameDiscretization(DiscreteFunctionP0<1, R2x2>{mesh_1d}, - DiscreteFunctionP0<1, R2x2>{mesh_1d})); + REQUIRE(EmbeddedIDiscreteFunctionUtils::isSameDiscretization(DiscreteFunctionP0<1, R1x1>{mesh_1d}, + DiscreteFunctionP0<1, R1x1>{mesh_1d})); - REQUIRE(EmbeddedIDiscreteFunctionUtils::isSameDiscretization(DiscreteFunctionP0<1, R3x3>{mesh_1d}, - DiscreteFunctionP0<1, R3x3>{mesh_1d})); + REQUIRE(EmbeddedIDiscreteFunctionUtils::isSameDiscretization(DiscreteFunctionP0<1, R2x2>{mesh_1d}, + DiscreteFunctionP0<1, R2x2>{mesh_1d})); - REQUIRE(not EmbeddedIDiscreteFunctionUtils::isSameDiscretization(DiscreteFunctionP0<1, double>{mesh_1d}, - DiscreteFunctionP0<1, R1>{mesh_1d})); + REQUIRE(EmbeddedIDiscreteFunctionUtils::isSameDiscretization(DiscreteFunctionP0<1, R3x3>{mesh_1d}, + DiscreteFunctionP0<1, R3x3>{mesh_1d})); - REQUIRE(not EmbeddedIDiscreteFunctionUtils::isSameDiscretization(DiscreteFunctionP0<1, R2>{mesh_1d}, - DiscreteFunctionP0<1, R2x2>{mesh_1d})); + REQUIRE(not EmbeddedIDiscreteFunctionUtils::isSameDiscretization(DiscreteFunctionP0<1, double>{mesh_1d}, + DiscreteFunctionP0<1, R1>{mesh_1d})); - REQUIRE(not EmbeddedIDiscreteFunctionUtils::isSameDiscretization(DiscreteFunctionP0<1, R3x3>{mesh_1d}, - DiscreteFunctionP0<1, R2x2>{mesh_1d})); + REQUIRE(not EmbeddedIDiscreteFunctionUtils::isSameDiscretization(DiscreteFunctionP0<1, R2>{mesh_1d}, + DiscreteFunctionP0<1, R2x2>{mesh_1d})); + + REQUIRE(not EmbeddedIDiscreteFunctionUtils::isSameDiscretization(DiscreteFunctionP0<1, R3x3>{mesh_1d}, + DiscreteFunctionP0<1, R2x2>{mesh_1d})); + } + } } SECTION("invalid data type") { - std::shared_ptr mesh_1d = MeshDataBaseForTests::get().cartesianMesh1D(); - - REQUIRE_THROWS_WITH(EmbeddedIDiscreteFunctionUtils::isSameDiscretization(DiscreteFunctionP0<1, int64_t>{mesh_1d}, - DiscreteFunctionP0<1, int64_t>{mesh_1d}), - "unexpected error: invalid data type Vh(P0:Z)"); + std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); + + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_1d = named_mesh.mesh(); + + REQUIRE_THROWS_WITH(EmbeddedIDiscreteFunctionUtils::isSameDiscretization(DiscreteFunctionP0<1, + int64_t>{mesh_1d}, + DiscreteFunctionP0<1, int64_t>{ + mesh_1d}), + "unexpected error: invalid data type Vh(P0:Z)"); + } + } } } diff --git a/tests/test_FaceIntegrator.cpp b/tests/test_FaceIntegrator.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9dee9c032b48db4ad51c362b5f47681613039fb5 --- /dev/null +++ b/tests/test_FaceIntegrator.cpp @@ -0,0 +1,506 @@ +#include <catch2/catch_approx.hpp> +#include <catch2/catch_test_macros.hpp> + +#include <analysis/GaussLegendreQuadratureDescriptor.hpp> +#include <analysis/GaussLobattoQuadratureDescriptor.hpp> +#include <analysis/GaussQuadratureDescriptor.hpp> +#include <mesh/DiamondDualMeshManager.hpp> +#include <mesh/ItemValue.hpp> +#include <mesh/Mesh.hpp> +#include <scheme/FaceIntegrator.hpp> + +#include <MeshDataBaseForTests.hpp> + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("FaceIntegrator", "[scheme]") +{ + SECTION("2D") + { + using R2 = TinyVector<2>; + + const auto mesh = MeshDataBaseForTests::get().hybrid2DMesh(); + + auto f = [](const R2& X) -> double { + const double x = X[0]; + const double y = X[1]; + return x * x + 2 * x * y + 3 * y * y + 2; + }; + + Array<const double> int_f_per_face = [=] { + Array<double> int_f(mesh->numberOfFaces()); + auto face_to_node_matrix = mesh->connectivity().faceToNodeMatrix(); + + parallel_for( + mesh->numberOfFaces(), PUGS_LAMBDA(const FaceId face_id) { + auto face_node_list = face_to_node_matrix[face_id]; + auto xr = mesh->xr(); + double integral = 0; + LineTransformation<2> T(xr[face_node_list[0]], xr[face_node_list[1]]); + auto qf = QuadratureManager::instance().getLineFormula(GaussQuadratureDescriptor(2)); + + for (size_t i = 0; i < qf.numberOfPoints(); ++i) { + const auto& xi = qf.point(i); + integral += qf.weight(i) * T.velocityNorm() * f(T(xi)); + } + + int_f[face_id] = integral; + }); + + return int_f; + }(); + + SECTION("direct formula") + { + SECTION("all faces") + { + SECTION("FaceValue") + { + FaceValue<double> values(mesh->connectivity()); + FaceIntegrator::integrateTo([=](const R2 x) { return f(x); }, GaussQuadratureDescriptor(2), *mesh, values); + + double error = 0; + for (FaceId face_id = 0; face_id < mesh->numberOfFaces(); ++face_id) { + error += std::abs(int_f_per_face[face_id] - values[face_id]); + } + + REQUIRE(error == Catch::Approx(0).margin(1E-10)); + } + + SECTION("Array") + { + Array<double> values(mesh->numberOfFaces()); + + FaceIntegrator::integrateTo(f, GaussQuadratureDescriptor(2), *mesh, values); + + double error = 0; + for (FaceId face_id = 0; face_id < mesh->numberOfFaces(); ++face_id) { + error += std::abs(int_f_per_face[face_id] - values[face_id]); + } + + REQUIRE(error == Catch::Approx(0).margin(1E-10)); + } + + SECTION("SmallArray") + { + SmallArray<double> values(mesh->numberOfFaces()); + FaceIntegrator::integrateTo(f, GaussQuadratureDescriptor(2), *mesh, values); + + double error = 0; + for (FaceId face_id = 0; face_id < mesh->numberOfFaces(); ++face_id) { + error += std::abs(int_f_per_face[face_id] - values[face_id]); + } + + REQUIRE(error == Catch::Approx(0).margin(1E-10)); + } + } + + SECTION("face list") + { + SECTION("Array") + { + Array<FaceId> face_list{mesh->numberOfFaces() / 2 + mesh->numberOfFaces() % 2}; + + { + size_t k = 0; + for (FaceId face_id = 0; face_id < mesh->numberOfFaces(); ++(++face_id), ++k) { + face_list[k] = face_id; + } + + REQUIRE(k == face_list.size()); + } + + Array<double> values = FaceIntegrator::integrate(f, GaussQuadratureDescriptor(2), *mesh, face_list); + + double error = 0; + for (size_t i = 0; i < face_list.size(); ++i) { + error += std::abs(int_f_per_face[face_list[i]] - values[i]); + } + + REQUIRE(error == Catch::Approx(0).margin(1E-10)); + } + + SECTION("SmallArray") + { + SmallArray<FaceId> face_list{mesh->numberOfFaces() / 2 + mesh->numberOfFaces() % 2}; + + { + size_t k = 0; + for (FaceId face_id = 0; face_id < mesh->numberOfFaces(); ++(++face_id), ++k) { + face_list[k] = face_id; + } + + REQUIRE(k == face_list.size()); + } + + SmallArray<double> values = FaceIntegrator::integrate(f, GaussQuadratureDescriptor(2), *mesh, face_list); + + double error = 0; + for (size_t i = 0; i < face_list.size(); ++i) { + error += std::abs(int_f_per_face[face_list[i]] - values[i]); + } + + REQUIRE(error == Catch::Approx(0).margin(1E-10)); + } + } + } + + SECTION("tensorial formula") + { + SECTION("all faces") + { + SECTION("FaceValue") + { + FaceValue<double> values(mesh->connectivity()); + FaceIntegrator::integrateTo([=](const R2 x) { return f(x); }, GaussLobattoQuadratureDescriptor(2), *mesh, + values); + + double error = 0; + for (FaceId face_id = 0; face_id < mesh->numberOfFaces(); ++face_id) { + error += std::abs(int_f_per_face[face_id] - values[face_id]); + } + + REQUIRE(error == Catch::Approx(0).margin(1E-10)); + } + + SECTION("Array") + { + Array<double> values(mesh->numberOfFaces()); + + FaceIntegrator::integrateTo(f, GaussLobattoQuadratureDescriptor(2), *mesh, values); + + double error = 0; + for (FaceId face_id = 0; face_id < mesh->numberOfFaces(); ++face_id) { + error += std::abs(int_f_per_face[face_id] - values[face_id]); + } + + REQUIRE(error == Catch::Approx(0).margin(1E-10)); + } + + SECTION("SmallArray") + { + SmallArray<double> values(mesh->numberOfFaces()); + FaceIntegrator::integrateTo(f, GaussLobattoQuadratureDescriptor(2), *mesh, values); + + double error = 0; + for (FaceId face_id = 0; face_id < mesh->numberOfFaces(); ++face_id) { + error += std::abs(int_f_per_face[face_id] - values[face_id]); + } + + REQUIRE(error == Catch::Approx(0).margin(1E-10)); + } + } + + SECTION("face list") + { + SECTION("Array") + { + Array<FaceId> face_list{mesh->numberOfFaces() / 2 + mesh->numberOfFaces() % 2}; + + { + size_t k = 0; + for (FaceId face_id = 0; face_id < mesh->numberOfFaces(); ++(++face_id), ++k) { + face_list[k] = face_id; + } + + REQUIRE(k == face_list.size()); + } + + Array<double> values = FaceIntegrator::integrate(f, GaussLobattoQuadratureDescriptor(2), *mesh, face_list); + + double error = 0; + for (size_t i = 0; i < face_list.size(); ++i) { + error += std::abs(int_f_per_face[face_list[i]] - values[i]); + } + + REQUIRE(error == Catch::Approx(0).margin(1E-10)); + } + + SECTION("SmallArray") + { + SmallArray<FaceId> face_list{mesh->numberOfFaces() / 2 + mesh->numberOfFaces() % 2}; + + { + size_t k = 0; + for (FaceId face_id = 0; face_id < mesh->numberOfFaces(); ++(++face_id), ++k) { + face_list[k] = face_id; + } + + REQUIRE(k == face_list.size()); + } + + SmallArray<double> values = + FaceIntegrator::integrate(f, GaussLobattoQuadratureDescriptor(2), *mesh, face_list); + + double error = 0; + for (size_t i = 0; i < face_list.size(); ++i) { + error += std::abs(int_f_per_face[face_list[i]] - values[i]); + } + + REQUIRE(error == Catch::Approx(0).margin(1E-10)); + } + } + } + } + + SECTION("3D") + { + using R3 = TinyVector<3>; + + auto hybrid_mesh = MeshDataBaseForTests::get().hybrid3DMesh(); + + auto f = [](const R3& X) -> double { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return x * x + 2 * x * y + 3 * y * y + 2 * z * z - z + 1; + }; + + std::vector<std::pair<std::string, decltype(hybrid_mesh)>> mesh_list; + mesh_list.push_back(std::make_pair("hybrid mesh", hybrid_mesh)); + mesh_list.push_back( + std::make_pair("diamond mesh", DiamondDualMeshManager::instance().getDiamondDualMesh(hybrid_mesh))); + + for (auto mesh_info : mesh_list) { + auto mesh_name = mesh_info.first; + auto mesh = mesh_info.second; + + Array<const double> int_f_per_face = [=] { + Array<double> int_f(mesh->numberOfFaces()); + auto face_to_node_matrix = mesh->connectivity().faceToNodeMatrix(); + + parallel_for( + mesh->numberOfFaces(), PUGS_LAMBDA(const FaceId face_id) { + auto face_node_list = face_to_node_matrix[face_id]; + auto xr = mesh->xr(); + double integral = 0; + + switch (face_node_list.size()) { + case 3: { + TriangleTransformation<3> T(xr[face_node_list[0]], xr[face_node_list[1]], xr[face_node_list[2]]); + auto qf = QuadratureManager::instance().getTriangleFormula(GaussQuadratureDescriptor(2)); + for (size_t i = 0; i < qf.numberOfPoints(); ++i) { + const auto& xi = qf.point(i); + integral += qf.weight(i) * T.areaVariationNorm() * f(T(xi)); + } + break; + } + case 4: { + SquareTransformation<3> T(xr[face_node_list[0]], xr[face_node_list[1]], xr[face_node_list[2]], + xr[face_node_list[3]]); + auto qf = QuadratureManager::instance().getSquareFormula(GaussQuadratureDescriptor(2)); + for (size_t i = 0; i < qf.numberOfPoints(); ++i) { + const auto& xi = qf.point(i); + integral += qf.weight(i) * T.areaVariationNorm(xi) * f(T(xi)); + } + break; + } + default: { + throw UnexpectedError("invalid face (node number must be 3 or 4)"); + } + } + int_f[face_id] = integral; + }); + + return int_f; + }(); + + SECTION(mesh_name) + { + SECTION("direct formula") + { + SECTION("all faces") + { + SECTION("FaceValue") + { + FaceValue<double> values(mesh->connectivity()); + FaceIntegrator::integrateTo([=](const R3 x) { return f(x); }, GaussQuadratureDescriptor(4), *mesh, + values); + + double error = 0; + for (FaceId face_id = 0; face_id < mesh->numberOfFaces(); ++face_id) { + error += std::abs(int_f_per_face[face_id] - values[face_id]); + } + + REQUIRE(error == Catch::Approx(0).margin(1E-10)); + } + + SECTION("Array") + { + Array<double> values(mesh->numberOfFaces()); + + FaceIntegrator::integrateTo(f, GaussQuadratureDescriptor(4), *mesh, values); + + double error = 0; + for (FaceId face_id = 0; face_id < mesh->numberOfFaces(); ++face_id) { + error += std::abs(int_f_per_face[face_id] - values[face_id]); + } + + REQUIRE(error == Catch::Approx(0).margin(1E-10)); + } + + SECTION("SmallArray") + { + SmallArray<double> values(mesh->numberOfFaces()); + FaceIntegrator::integrateTo(f, GaussQuadratureDescriptor(4), *mesh, values); + + double error = 0; + for (FaceId face_id = 0; face_id < mesh->numberOfFaces(); ++face_id) { + error += std::abs(int_f_per_face[face_id] - values[face_id]); + } + + REQUIRE(error == Catch::Approx(0).margin(1E-10)); + } + } + + SECTION("face list") + { + SECTION("Array") + { + Array<FaceId> face_list{mesh->numberOfFaces() / 2 + mesh->numberOfFaces() % 2}; + + { + size_t k = 0; + for (FaceId face_id = 0; face_id < mesh->numberOfFaces(); ++(++face_id), ++k) { + face_list[k] = face_id; + } + + REQUIRE(k == face_list.size()); + } + + Array<double> values = FaceIntegrator::integrate(f, GaussQuadratureDescriptor(4), *mesh, face_list); + + double error = 0; + for (size_t i = 0; i < face_list.size(); ++i) { + error += std::abs(int_f_per_face[face_list[i]] - values[i]); + } + + REQUIRE(error == Catch::Approx(0).margin(1E-10)); + } + + SECTION("SmallArray") + { + SmallArray<FaceId> face_list{mesh->numberOfFaces() / 2 + mesh->numberOfFaces() % 2}; + + { + size_t k = 0; + for (FaceId face_id = 0; face_id < mesh->numberOfFaces(); ++(++face_id), ++k) { + face_list[k] = face_id; + } + + REQUIRE(k == face_list.size()); + } + + SmallArray<double> values = FaceIntegrator::integrate(f, GaussQuadratureDescriptor(4), *mesh, face_list); + + double error = 0; + for (size_t i = 0; i < face_list.size(); ++i) { + error += std::abs(int_f_per_face[face_list[i]] - values[i]); + } + + REQUIRE(error == Catch::Approx(0).margin(1E-10)); + } + } + } + + SECTION("tensorial formula") + { + SECTION("all faces") + { + SECTION("FaceValue") + { + FaceValue<double> values(mesh->connectivity()); + FaceIntegrator::integrateTo([=](const R3 x) { return f(x); }, GaussLegendreQuadratureDescriptor(10), + *mesh, values); + + double error = 0; + for (FaceId face_id = 0; face_id < mesh->numberOfFaces(); ++face_id) { + error += std::abs(int_f_per_face[face_id] - values[face_id]); + } + + REQUIRE(error == Catch::Approx(0).margin(1E-10)); + } + + SECTION("Array") + { + Array<double> values(mesh->numberOfFaces()); + + FaceIntegrator::integrateTo(f, GaussLobattoQuadratureDescriptor(4), *mesh, values); + + double error = 0; + for (FaceId face_id = 0; face_id < mesh->numberOfFaces(); ++face_id) { + error += std::abs(int_f_per_face[face_id] - values[face_id]); + } + + REQUIRE(error == Catch::Approx(0).margin(1E-10)); + } + + SECTION("SmallArray") + { + SmallArray<double> values(mesh->numberOfFaces()); + FaceIntegrator::integrateTo(f, GaussLobattoQuadratureDescriptor(4), *mesh, values); + + double error = 0; + for (FaceId face_id = 0; face_id < mesh->numberOfFaces(); ++face_id) { + error += std::abs(int_f_per_face[face_id] - values[face_id]); + } + + REQUIRE(error == Catch::Approx(0).margin(1E-10)); + } + } + + SECTION("face list") + { + SECTION("Array") + { + Array<FaceId> face_list{mesh->numberOfFaces() / 2 + mesh->numberOfFaces() % 2}; + + { + size_t k = 0; + for (FaceId face_id = 0; face_id < mesh->numberOfFaces(); ++(++face_id), ++k) { + face_list[k] = face_id; + } + + REQUIRE(k == face_list.size()); + } + + Array<double> values = + FaceIntegrator::integrate(f, GaussLobattoQuadratureDescriptor(4), *mesh, face_list); + + double error = 0; + for (size_t i = 0; i < face_list.size(); ++i) { + error += std::abs(int_f_per_face[face_list[i]] - values[i]); + } + + REQUIRE(error == Catch::Approx(0).margin(1E-10)); + } + + SECTION("SmallArray") + { + SmallArray<FaceId> face_list{mesh->numberOfFaces() / 2 + mesh->numberOfFaces() % 2}; + + { + size_t k = 0; + for (FaceId face_id = 0; face_id < mesh->numberOfFaces(); ++(++face_id), ++k) { + face_list[k] = face_id; + } + + REQUIRE(k == face_list.size()); + } + + SmallArray<double> values = + FaceIntegrator::integrate(f, GaussLobattoQuadratureDescriptor(4), *mesh, face_list); + + double error = 0; + for (size_t i = 0; i < face_list.size(); ++i) { + error += std::abs(int_f_per_face[face_list[i]] - values[i]); + } + + REQUIRE(error == Catch::Approx(0).margin(1E-10)); + } + } + } + } + } + } +} diff --git a/tests/test_InterpolateItemArray.cpp b/tests/test_InterpolateItemArray.cpp index 5e0bbd962bd9c24165956b9e17a223f80a187055..2974e01d8732d35702b32493f0cb810932de2df2 100644 --- a/tests/test_InterpolateItemArray.cpp +++ b/tests/test_InterpolateItemArray.cpp @@ -46,195 +46,219 @@ TEST_CASE("InterpolateItemArray", "[language]") { constexpr size_t Dimension = 1; - const auto& mesh_1d = MeshDataBaseForTests::get().cartesianMesh1D(); - auto xj = MeshDataManager::instance().getMeshData(*mesh_1d).xj(); + std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - std::string_view data = R"( + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_1d = named_mesh.mesh(); + + auto xj = MeshDataManager::instance().getMeshData(*mesh_1d).xj(); + + std::string_view data = R"( import math; let scalar_affine_1d: R^1 -> R, x -> 2*x[0] + 2; let scalar_non_linear_1d: R^1 -> R, x -> 2 * exp(x[0]) + 3; )"; - TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"}; + TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"}; - auto ast = ASTBuilder::build(input); + auto ast = ASTBuilder::build(input); - ASTModulesImporter{*ast}; - ASTNodeTypeCleaner<language::import_instruction>{*ast}; + ASTModulesImporter{*ast}; + ASTNodeTypeCleaner<language::import_instruction>{*ast}; - ASTSymbolTableBuilder{*ast}; - ASTNodeDataTypeBuilder{*ast}; + ASTSymbolTableBuilder{*ast}; + ASTNodeDataTypeBuilder{*ast}; - ASTNodeTypeCleaner<language::var_declaration>{*ast}; - ASTNodeTypeCleaner<language::fct_declaration>{*ast}; - ASTNodeExpressionBuilder{*ast}; + ASTNodeTypeCleaner<language::var_declaration>{*ast}; + ASTNodeTypeCleaner<language::fct_declaration>{*ast}; + ASTNodeExpressionBuilder{*ast}; - std::shared_ptr<SymbolTable> symbol_table = ast->m_symbol_table; + std::shared_ptr<SymbolTable> symbol_table = ast->m_symbol_table; - TAO_PEGTL_NAMESPACE::position position{TAO_PEGTL_NAMESPACE::internal::iterator{"fixture"}, "fixture"}; - position.byte = data.size(); // ensure that variables are declared at this point + TAO_PEGTL_NAMESPACE::position position{TAO_PEGTL_NAMESPACE::internal::iterator{"fixture"}, "fixture"}; + position.byte = data.size(); // ensure that variables are declared at this point - std::vector<FunctionSymbolId> function_symbol_id_list; + std::vector<FunctionSymbolId> function_symbol_id_list; - { - auto [i_symbol, found] = symbol_table->find("scalar_affine_1d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + { + auto [i_symbol, found] = symbol_table->find("scalar_affine_1d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - function_symbol_id_list.push_back( - FunctionSymbolId(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table)); - } + function_symbol_id_list.push_back( + FunctionSymbolId(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table)); + } - { - auto [i_symbol, found] = symbol_table->find("scalar_non_linear_1d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + { + auto [i_symbol, found] = symbol_table->find("scalar_non_linear_1d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - function_symbol_id_list.push_back( - FunctionSymbolId(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table)); - } + function_symbol_id_list.push_back( + FunctionSymbolId(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table)); + } - CellArray<double> cell_array{mesh_1d->connectivity(), 2}; - parallel_for( - cell_array.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<Dimension>& x = xj[cell_id]; - cell_array[cell_id][0] = 2 * x[0] + 2; - cell_array[cell_id][1] = 2 * exp(x[0]) + 3; - }); + CellArray<double> cell_array{mesh_1d->connectivity(), 2}; + parallel_for( + cell_array.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<Dimension>& x = xj[cell_id]; + cell_array[cell_id][0] = 2 * x[0] + 2; + cell_array[cell_id][1] = 2 * exp(x[0]) + 3; + }); - CellArray<const double> interpolate_array = - InterpolateItemArray<double(TinyVector<Dimension>)>::interpolate(function_symbol_id_list, xj); + CellArray<const double> interpolate_array = + InterpolateItemArray<double(TinyVector<Dimension>)>::interpolate(function_symbol_id_list, xj); - REQUIRE(same_cell_array(cell_array, interpolate_array)); + REQUIRE(same_cell_array(cell_array, interpolate_array)); + } + } } SECTION("2D") { constexpr size_t Dimension = 2; - const auto& mesh_2d = MeshDataBaseForTests::get().cartesianMesh2D(); - auto xj = MeshDataManager::instance().getMeshData(*mesh_2d).xj(); + std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); + + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_2d = named_mesh.mesh(); - std::string_view data = R"( + auto xj = MeshDataManager::instance().getMeshData(*mesh_2d).xj(); + + std::string_view data = R"( import math; let scalar_affine_2d: R^2 -> R, x -> 2*x[0] + 3*x[1] + 2; let scalar_non_linear_2d: R^2 -> R, x -> 2*exp(x[0])*sin(x[1])+3; )"; - TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"}; + TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"}; - auto ast = ASTBuilder::build(input); + auto ast = ASTBuilder::build(input); - ASTModulesImporter{*ast}; - ASTNodeTypeCleaner<language::import_instruction>{*ast}; + ASTModulesImporter{*ast}; + ASTNodeTypeCleaner<language::import_instruction>{*ast}; - ASTSymbolTableBuilder{*ast}; - ASTNodeDataTypeBuilder{*ast}; + ASTSymbolTableBuilder{*ast}; + ASTNodeDataTypeBuilder{*ast}; - ASTNodeTypeCleaner<language::var_declaration>{*ast}; - ASTNodeTypeCleaner<language::fct_declaration>{*ast}; - ASTNodeExpressionBuilder{*ast}; + ASTNodeTypeCleaner<language::var_declaration>{*ast}; + ASTNodeTypeCleaner<language::fct_declaration>{*ast}; + ASTNodeExpressionBuilder{*ast}; - std::shared_ptr<SymbolTable> symbol_table = ast->m_symbol_table; + std::shared_ptr<SymbolTable> symbol_table = ast->m_symbol_table; - TAO_PEGTL_NAMESPACE::position position{TAO_PEGTL_NAMESPACE::internal::iterator{"fixture"}, "fixture"}; - position.byte = data.size(); // ensure that variables are declared at this point + TAO_PEGTL_NAMESPACE::position position{TAO_PEGTL_NAMESPACE::internal::iterator{"fixture"}, "fixture"}; + position.byte = data.size(); // ensure that variables are declared at this point - std::vector<FunctionSymbolId> function_symbol_id_list; + std::vector<FunctionSymbolId> function_symbol_id_list; - { - auto [i_symbol, found] = symbol_table->find("scalar_affine_2d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + { + auto [i_symbol, found] = symbol_table->find("scalar_affine_2d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - function_symbol_id_list.push_back( - FunctionSymbolId(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table)); - } + function_symbol_id_list.push_back( + FunctionSymbolId(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table)); + } - { - auto [i_symbol, found] = symbol_table->find("scalar_non_linear_2d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + { + auto [i_symbol, found] = symbol_table->find("scalar_non_linear_2d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - function_symbol_id_list.push_back( - FunctionSymbolId(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table)); - } + function_symbol_id_list.push_back( + FunctionSymbolId(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table)); + } - CellArray<double> cell_array{mesh_2d->connectivity(), 2}; - parallel_for( - cell_array.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<Dimension>& x = xj[cell_id]; - cell_array[cell_id][0] = 2 * x[0] + 3 * x[1] + 2; - cell_array[cell_id][1] = 2 * exp(x[0]) * sin(x[1]) + 3; - }); + CellArray<double> cell_array{mesh_2d->connectivity(), 2}; + parallel_for( + cell_array.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<Dimension>& x = xj[cell_id]; + cell_array[cell_id][0] = 2 * x[0] + 3 * x[1] + 2; + cell_array[cell_id][1] = 2 * exp(x[0]) * sin(x[1]) + 3; + }); - CellArray<const double> interpolate_array = - InterpolateItemArray<double(TinyVector<Dimension>)>::interpolate(function_symbol_id_list, xj); + CellArray<const double> interpolate_array = + InterpolateItemArray<double(TinyVector<Dimension>)>::interpolate(function_symbol_id_list, xj); - REQUIRE(same_cell_array(cell_array, interpolate_array)); + REQUIRE(same_cell_array(cell_array, interpolate_array)); + } + } } SECTION("3D") { constexpr size_t Dimension = 3; - const auto& mesh_3d = MeshDataBaseForTests::get().cartesianMesh3D(); - auto xj = MeshDataManager::instance().getMeshData(*mesh_3d).xj(); + std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); + + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_3d = named_mesh.mesh(); + + auto xj = MeshDataManager::instance().getMeshData(*mesh_3d).xj(); - std::string_view data = R"( + std::string_view data = R"( import math; let scalar_affine_3d: R^3 -> R, x -> 2 * x[0] + 3 * x[1] + 2 * x[2] - 1; let scalar_non_linear_3d: R^3 -> R, x -> 2 * exp(x[0]) * sin(x[1]) * x[2] + 3; )"; - TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"}; + TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"}; - auto ast = ASTBuilder::build(input); + auto ast = ASTBuilder::build(input); - ASTModulesImporter{*ast}; - ASTNodeTypeCleaner<language::import_instruction>{*ast}; + ASTModulesImporter{*ast}; + ASTNodeTypeCleaner<language::import_instruction>{*ast}; - ASTSymbolTableBuilder{*ast}; - ASTNodeDataTypeBuilder{*ast}; + ASTSymbolTableBuilder{*ast}; + ASTNodeDataTypeBuilder{*ast}; - ASTNodeTypeCleaner<language::var_declaration>{*ast}; - ASTNodeTypeCleaner<language::fct_declaration>{*ast}; - ASTNodeExpressionBuilder{*ast}; + ASTNodeTypeCleaner<language::var_declaration>{*ast}; + ASTNodeTypeCleaner<language::fct_declaration>{*ast}; + ASTNodeExpressionBuilder{*ast}; - std::shared_ptr<SymbolTable> symbol_table = ast->m_symbol_table; + std::shared_ptr<SymbolTable> symbol_table = ast->m_symbol_table; - TAO_PEGTL_NAMESPACE::position position{TAO_PEGTL_NAMESPACE::internal::iterator{"fixture"}, "fixture"}; - position.byte = data.size(); // ensure that variables are declared at this point + TAO_PEGTL_NAMESPACE::position position{TAO_PEGTL_NAMESPACE::internal::iterator{"fixture"}, "fixture"}; + position.byte = data.size(); // ensure that variables are declared at this point - std::vector<FunctionSymbolId> function_symbol_id_list; + std::vector<FunctionSymbolId> function_symbol_id_list; - { - auto [i_symbol, found] = symbol_table->find("scalar_affine_3d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + { + auto [i_symbol, found] = symbol_table->find("scalar_affine_3d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - function_symbol_id_list.push_back( - FunctionSymbolId(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table)); - } + function_symbol_id_list.push_back( + FunctionSymbolId(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table)); + } - { - auto [i_symbol, found] = symbol_table->find("scalar_non_linear_3d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + { + auto [i_symbol, found] = symbol_table->find("scalar_non_linear_3d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - function_symbol_id_list.push_back( - FunctionSymbolId(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table)); - } + function_symbol_id_list.push_back( + FunctionSymbolId(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table)); + } - CellArray<double> cell_array{mesh_3d->connectivity(), 2}; - parallel_for( - cell_array.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<Dimension>& x = xj[cell_id]; - cell_array[cell_id][0] = 2 * x[0] + 3 * x[1] + 2 * x[2] - 1; - cell_array[cell_id][1] = 2 * exp(x[0]) * sin(x[1]) * x[2] + 3; - }); + CellArray<double> cell_array{mesh_3d->connectivity(), 2}; + parallel_for( + cell_array.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<Dimension>& x = xj[cell_id]; + cell_array[cell_id][0] = 2 * x[0] + 3 * x[1] + 2 * x[2] - 1; + cell_array[cell_id][1] = 2 * exp(x[0]) * sin(x[1]) * x[2] + 3; + }); - CellArray<const double> interpolate_array = - InterpolateItemArray<double(TinyVector<Dimension>)>::interpolate(function_symbol_id_list, xj); + CellArray<const double> interpolate_array = + InterpolateItemArray<double(TinyVector<Dimension>)>::interpolate(function_symbol_id_list, xj); - REQUIRE(same_cell_array(cell_array, interpolate_array)); + REQUIRE(same_cell_array(cell_array, interpolate_array)); + } + } } } @@ -255,213 +279,237 @@ let scalar_non_linear_3d: R^3 -> R, x -> 2 * exp(x[0]) * sin(x[1]) * x[2] + 3; { constexpr size_t Dimension = 1; - const auto& mesh_1d = MeshDataBaseForTests::get().cartesianMesh1D(); - auto xj = MeshDataManager::instance().getMeshData(*mesh_1d).xj(); + std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - Array<const CellId> cell_id_list = [&] { - Array<CellId> cell_ids{mesh_1d->numberOfCells() / 2}; - for (size_t i_cell = 0; i_cell < cell_ids.size(); ++i_cell) { - cell_ids[i_cell] = static_cast<CellId>(2 * i_cell); - } - return cell_ids; - }(); + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_1d = named_mesh.mesh(); + + auto xj = MeshDataManager::instance().getMeshData(*mesh_1d).xj(); + + Array<const CellId> cell_id_list = [&] { + Array<CellId> cell_ids{mesh_1d->numberOfCells() / 2}; + for (size_t i_cell = 0; i_cell < cell_ids.size(); ++i_cell) { + cell_ids[i_cell] = static_cast<CellId>(2 * i_cell); + } + return cell_ids; + }(); - std::string_view data = R"( + std::string_view data = R"( import math; let scalar_affine_1d: R^1 -> R, x -> 2*x[0] + 2; let scalar_non_linear_1d: R^1 -> R, x -> 2 * exp(x[0]) + 3; )"; - TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"}; + TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"}; - auto ast = ASTBuilder::build(input); + auto ast = ASTBuilder::build(input); - ASTModulesImporter{*ast}; - ASTNodeTypeCleaner<language::import_instruction>{*ast}; + ASTModulesImporter{*ast}; + ASTNodeTypeCleaner<language::import_instruction>{*ast}; - ASTSymbolTableBuilder{*ast}; - ASTNodeDataTypeBuilder{*ast}; + ASTSymbolTableBuilder{*ast}; + ASTNodeDataTypeBuilder{*ast}; - ASTNodeTypeCleaner<language::var_declaration>{*ast}; - ASTNodeTypeCleaner<language::fct_declaration>{*ast}; - ASTNodeExpressionBuilder{*ast}; + ASTNodeTypeCleaner<language::var_declaration>{*ast}; + ASTNodeTypeCleaner<language::fct_declaration>{*ast}; + ASTNodeExpressionBuilder{*ast}; - std::shared_ptr<SymbolTable> symbol_table = ast->m_symbol_table; + std::shared_ptr<SymbolTable> symbol_table = ast->m_symbol_table; - TAO_PEGTL_NAMESPACE::position position{TAO_PEGTL_NAMESPACE::internal::iterator{"fixture"}, "fixture"}; - position.byte = data.size(); // ensure that variables are declared at this point + TAO_PEGTL_NAMESPACE::position position{TAO_PEGTL_NAMESPACE::internal::iterator{"fixture"}, "fixture"}; + position.byte = data.size(); // ensure that variables are declared at this point - std::vector<FunctionSymbolId> function_symbol_id_list; + std::vector<FunctionSymbolId> function_symbol_id_list; - { - auto [i_symbol, found] = symbol_table->find("scalar_affine_1d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + { + auto [i_symbol, found] = symbol_table->find("scalar_affine_1d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - function_symbol_id_list.push_back( - FunctionSymbolId(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table)); - } + function_symbol_id_list.push_back( + FunctionSymbolId(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table)); + } - { - auto [i_symbol, found] = symbol_table->find("scalar_non_linear_1d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + { + auto [i_symbol, found] = symbol_table->find("scalar_non_linear_1d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - function_symbol_id_list.push_back( - FunctionSymbolId(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table)); - } + function_symbol_id_list.push_back( + FunctionSymbolId(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table)); + } - Table<double> cell_array{cell_id_list.size(), 2}; - parallel_for( - cell_id_list.size(), PUGS_LAMBDA(const size_t i) { - const TinyVector<Dimension>& x = xj[cell_id_list[i]]; - cell_array[i][0] = 2 * x[0] + 2; - cell_array[i][1] = 2 * exp(x[0]) + 3; - }); + Table<double> cell_array{cell_id_list.size(), 2}; + parallel_for( + cell_id_list.size(), PUGS_LAMBDA(const size_t i) { + const TinyVector<Dimension>& x = xj[cell_id_list[i]]; + cell_array[i][0] = 2 * x[0] + 2; + cell_array[i][1] = 2 * exp(x[0]) + 3; + }); - Table<const double> interpolate_array = - InterpolateItemArray<double(TinyVector<Dimension>)>::interpolate(function_symbol_id_list, xj, cell_id_list); + Table<const double> interpolate_array = + InterpolateItemArray<double(TinyVector<Dimension>)>::interpolate(function_symbol_id_list, xj, cell_id_list); - REQUIRE(same_cell_value(cell_array, interpolate_array)); + REQUIRE(same_cell_value(cell_array, interpolate_array)); + } + } } SECTION("2D") { constexpr size_t Dimension = 2; - const auto& mesh_2d = MeshDataBaseForTests::get().cartesianMesh2D(); - auto xj = MeshDataManager::instance().getMeshData(*mesh_2d).xj(); + std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - Array<CellId> cell_id_list{mesh_2d->numberOfCells() / 2}; - for (size_t i_cell = 0; i_cell < cell_id_list.size(); ++i_cell) { - cell_id_list[i_cell] = static_cast<CellId>(2 * i_cell); - } + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_2d = named_mesh.mesh(); - std::string_view data = R"( + auto xj = MeshDataManager::instance().getMeshData(*mesh_2d).xj(); + + Array<CellId> cell_id_list{mesh_2d->numberOfCells() / 2}; + for (size_t i_cell = 0; i_cell < cell_id_list.size(); ++i_cell) { + cell_id_list[i_cell] = static_cast<CellId>(2 * i_cell); + } + + std::string_view data = R"( import math; let scalar_affine_2d: R^2 -> R, x -> 2*x[0] + 3*x[1] + 2; let scalar_non_linear_2d: R^2 -> R, x -> 2*exp(x[0])*sin(x[1])+3; )"; - TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"}; + TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"}; - auto ast = ASTBuilder::build(input); + auto ast = ASTBuilder::build(input); - ASTModulesImporter{*ast}; - ASTNodeTypeCleaner<language::import_instruction>{*ast}; + ASTModulesImporter{*ast}; + ASTNodeTypeCleaner<language::import_instruction>{*ast}; - ASTSymbolTableBuilder{*ast}; - ASTNodeDataTypeBuilder{*ast}; + ASTSymbolTableBuilder{*ast}; + ASTNodeDataTypeBuilder{*ast}; - ASTNodeTypeCleaner<language::var_declaration>{*ast}; - ASTNodeTypeCleaner<language::fct_declaration>{*ast}; - ASTNodeExpressionBuilder{*ast}; + ASTNodeTypeCleaner<language::var_declaration>{*ast}; + ASTNodeTypeCleaner<language::fct_declaration>{*ast}; + ASTNodeExpressionBuilder{*ast}; - std::shared_ptr<SymbolTable> symbol_table = ast->m_symbol_table; + std::shared_ptr<SymbolTable> symbol_table = ast->m_symbol_table; - TAO_PEGTL_NAMESPACE::position position{TAO_PEGTL_NAMESPACE::internal::iterator{"fixture"}, "fixture"}; - position.byte = data.size(); // ensure that variables are declared at this point + TAO_PEGTL_NAMESPACE::position position{TAO_PEGTL_NAMESPACE::internal::iterator{"fixture"}, "fixture"}; + position.byte = data.size(); // ensure that variables are declared at this point - std::vector<FunctionSymbolId> function_symbol_id_list; + std::vector<FunctionSymbolId> function_symbol_id_list; - { - auto [i_symbol, found] = symbol_table->find("scalar_affine_2d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + { + auto [i_symbol, found] = symbol_table->find("scalar_affine_2d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - function_symbol_id_list.push_back( - FunctionSymbolId(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table)); - } + function_symbol_id_list.push_back( + FunctionSymbolId(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table)); + } - { - auto [i_symbol, found] = symbol_table->find("scalar_non_linear_2d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + { + auto [i_symbol, found] = symbol_table->find("scalar_non_linear_2d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - function_symbol_id_list.push_back( - FunctionSymbolId(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table)); - } + function_symbol_id_list.push_back( + FunctionSymbolId(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table)); + } - Table<double> cell_array{cell_id_list.size(), 2}; - parallel_for( - cell_id_list.size(), PUGS_LAMBDA(const size_t i) { - const TinyVector<Dimension>& x = xj[cell_id_list[i]]; - cell_array[i][0] = 2 * x[0] + 3 * x[1] + 2; - cell_array[i][1] = 2 * exp(x[0]) * sin(x[1]) + 3; - }); + Table<double> cell_array{cell_id_list.size(), 2}; + parallel_for( + cell_id_list.size(), PUGS_LAMBDA(const size_t i) { + const TinyVector<Dimension>& x = xj[cell_id_list[i]]; + cell_array[i][0] = 2 * x[0] + 3 * x[1] + 2; + cell_array[i][1] = 2 * exp(x[0]) * sin(x[1]) + 3; + }); - Table<const double> interpolate_array = - InterpolateItemArray<double(TinyVector<Dimension>)>::interpolate(function_symbol_id_list, xj, cell_id_list); + Table<const double> interpolate_array = + InterpolateItemArray<double(TinyVector<Dimension>)>::interpolate(function_symbol_id_list, xj, cell_id_list); - REQUIRE(same_cell_value(cell_array, interpolate_array)); + REQUIRE(same_cell_value(cell_array, interpolate_array)); + } + } } SECTION("3D") { constexpr size_t Dimension = 3; - const auto& mesh_3d = MeshDataBaseForTests::get().cartesianMesh3D(); - auto xj = MeshDataManager::instance().getMeshData(*mesh_3d).xj(); + std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - Array<CellId> cell_id_list{mesh_3d->numberOfCells() / 2}; - for (size_t i_cell = 0; i_cell < cell_id_list.size(); ++i_cell) { - cell_id_list[i_cell] = static_cast<CellId>(2 * i_cell); - } + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_3d = named_mesh.mesh(); + + auto xj = MeshDataManager::instance().getMeshData(*mesh_3d).xj(); + + Array<CellId> cell_id_list{mesh_3d->numberOfCells() / 2}; + for (size_t i_cell = 0; i_cell < cell_id_list.size(); ++i_cell) { + cell_id_list[i_cell] = static_cast<CellId>(2 * i_cell); + } - std::string_view data = R"( + std::string_view data = R"( import math; let scalar_affine_3d: R^3 -> R, x -> 2 * x[0] + 3 * x[1] + 2 * x[2] - 1; let scalar_non_linear_3d: R^3 -> R, x -> 2 * exp(x[0]) * sin(x[1]) * x[2] + 3; )"; - TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"}; + TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"}; - auto ast = ASTBuilder::build(input); + auto ast = ASTBuilder::build(input); - ASTModulesImporter{*ast}; - ASTNodeTypeCleaner<language::import_instruction>{*ast}; + ASTModulesImporter{*ast}; + ASTNodeTypeCleaner<language::import_instruction>{*ast}; - ASTSymbolTableBuilder{*ast}; - ASTNodeDataTypeBuilder{*ast}; + ASTSymbolTableBuilder{*ast}; + ASTNodeDataTypeBuilder{*ast}; - ASTNodeTypeCleaner<language::var_declaration>{*ast}; - ASTNodeTypeCleaner<language::fct_declaration>{*ast}; - ASTNodeExpressionBuilder{*ast}; + ASTNodeTypeCleaner<language::var_declaration>{*ast}; + ASTNodeTypeCleaner<language::fct_declaration>{*ast}; + ASTNodeExpressionBuilder{*ast}; - std::shared_ptr<SymbolTable> symbol_table = ast->m_symbol_table; + std::shared_ptr<SymbolTable> symbol_table = ast->m_symbol_table; - TAO_PEGTL_NAMESPACE::position position{TAO_PEGTL_NAMESPACE::internal::iterator{"fixture"}, "fixture"}; - position.byte = data.size(); // ensure that variables are declared at this point + TAO_PEGTL_NAMESPACE::position position{TAO_PEGTL_NAMESPACE::internal::iterator{"fixture"}, "fixture"}; + position.byte = data.size(); // ensure that variables are declared at this point - std::vector<FunctionSymbolId> function_symbol_id_list; + std::vector<FunctionSymbolId> function_symbol_id_list; - { - auto [i_symbol, found] = symbol_table->find("scalar_affine_3d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + { + auto [i_symbol, found] = symbol_table->find("scalar_affine_3d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - function_symbol_id_list.push_back( - FunctionSymbolId(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table)); - } + function_symbol_id_list.push_back( + FunctionSymbolId(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table)); + } - { - auto [i_symbol, found] = symbol_table->find("scalar_non_linear_3d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + { + auto [i_symbol, found] = symbol_table->find("scalar_non_linear_3d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - function_symbol_id_list.push_back( - FunctionSymbolId(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table)); - } + function_symbol_id_list.push_back( + FunctionSymbolId(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table)); + } - Table<double> cell_array{cell_id_list.size(), 2}; - parallel_for( - cell_id_list.size(), PUGS_LAMBDA(const size_t i) { - const TinyVector<Dimension>& x = xj[cell_id_list[i]]; - cell_array[i][0] = 2 * x[0] + 3 * x[1] + 2 * x[2] - 1; - cell_array[i][1] = 2 * exp(x[0]) * sin(x[1]) * x[2] + 3; - }); + Table<double> cell_array{cell_id_list.size(), 2}; + parallel_for( + cell_id_list.size(), PUGS_LAMBDA(const size_t i) { + const TinyVector<Dimension>& x = xj[cell_id_list[i]]; + cell_array[i][0] = 2 * x[0] + 3 * x[1] + 2 * x[2] - 1; + cell_array[i][1] = 2 * exp(x[0]) * sin(x[1]) * x[2] + 3; + }); - Table<const double> interpolate_array = - InterpolateItemArray<double(TinyVector<Dimension>)>::interpolate(function_symbol_id_list, xj, cell_id_list); + Table<const double> interpolate_array = + InterpolateItemArray<double(TinyVector<Dimension>)>::interpolate(function_symbol_id_list, xj, cell_id_list); - REQUIRE(same_cell_value(cell_array, interpolate_array)); + REQUIRE(same_cell_value(cell_array, interpolate_array)); + } + } } } } diff --git a/tests/test_InterpolateItemValue.cpp b/tests/test_InterpolateItemValue.cpp index fa786632c10660c9197842196440ae383a489edd..fabbda2560ac969e6305586041f531d0b348a0f8 100644 --- a/tests/test_InterpolateItemValue.cpp +++ b/tests/test_InterpolateItemValue.cpp @@ -43,10 +43,16 @@ TEST_CASE("InterpolateItemValue", "[language]") { constexpr size_t Dimension = 1; - const auto& mesh_1d = MeshDataBaseForTests::get().cartesianMesh1D(); - auto xj = MeshDataManager::instance().getMeshData(*mesh_1d).xj(); + std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - std::string_view data = R"( + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_1d = named_mesh.mesh(); + + auto xj = MeshDataManager::instance().getMeshData(*mesh_1d).xj(); + + std::string_view data = R"( import math; let scalar_affine_1d: R^1 -> R, x -> 2*x[0] + 2; let scalar_non_linear_1d: R^1 -> R, x -> 2 * exp(x[0]) + 3; @@ -55,149 +61,152 @@ let R3_non_linear_1d: R^1 -> R^3, x -> (2 * exp(x[0]) + 3, x[0] - 2, 3); let R2x2_affine_1d: R^1 -> R^2x2, x -> (2 * x[0] + 3 + 2, 3 * x[0], 2 * x[0], 2); let R2x2_non_linear_1d: R^1 -> R^2x2, x -> (2 * exp(x[0]) * sin(x[0]) + 3, sin(x[0] - 2 * x[0]), 3, x[0] * x[0]); )"; - TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"}; - - auto ast = ASTBuilder::build(input); - - ASTModulesImporter{*ast}; - ASTNodeTypeCleaner<language::import_instruction>{*ast}; - - ASTSymbolTableBuilder{*ast}; - ASTNodeDataTypeBuilder{*ast}; - - ASTNodeTypeCleaner<language::var_declaration>{*ast}; - ASTNodeTypeCleaner<language::fct_declaration>{*ast}; - ASTNodeExpressionBuilder{*ast}; + TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"}; - std::shared_ptr<SymbolTable> symbol_table = ast->m_symbol_table; + auto ast = ASTBuilder::build(input); - TAO_PEGTL_NAMESPACE::position position{TAO_PEGTL_NAMESPACE::internal::iterator{"fixture"}, "fixture"}; - position.byte = data.size(); // ensure that variables are declared at this point - - SECTION("scalar_affine_1d") - { - auto [i_symbol, found] = symbol_table->find("scalar_affine_1d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); - - CellValue<double> cell_value{mesh_1d->connectivity()}; - parallel_for( - cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<Dimension>& x = xj[cell_id]; - cell_value[cell_id] = 2 * x[0] + 2; - }); - - CellValue<const double> interpolate_value = - InterpolateItemValue<double(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj); - - REQUIRE(same_cell_value(cell_value, interpolate_value)); - } + ASTModulesImporter{*ast}; + ASTNodeTypeCleaner<language::import_instruction>{*ast}; - SECTION("scalar_non_linear_1d") - { - auto [i_symbol, found] = symbol_table->find("scalar_non_linear_1d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + ASTSymbolTableBuilder{*ast}; + ASTNodeDataTypeBuilder{*ast}; - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + ASTNodeTypeCleaner<language::var_declaration>{*ast}; + ASTNodeTypeCleaner<language::fct_declaration>{*ast}; + ASTNodeExpressionBuilder{*ast}; - CellValue<double> cell_value{mesh_1d->connectivity()}; - parallel_for( - cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<Dimension>& x = xj[cell_id]; - cell_value[cell_id] = 2 * exp(x[0]) + 3; - }); + std::shared_ptr<SymbolTable> symbol_table = ast->m_symbol_table; - CellValue<const double> interpolate_value = - InterpolateItemValue<double(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj); + TAO_PEGTL_NAMESPACE::position position{TAO_PEGTL_NAMESPACE::internal::iterator{"fixture"}, "fixture"}; + position.byte = data.size(); // ensure that variables are declared at this point - REQUIRE(same_cell_value(cell_value, interpolate_value)); - } + SECTION("scalar_affine_1d") + { + auto [i_symbol, found] = symbol_table->find("scalar_affine_1d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - SECTION("R3_affine_1d") - { - auto [i_symbol, found] = symbol_table->find("R3_affine_1d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + CellValue<double> cell_value{mesh_1d->connectivity()}; + parallel_for( + cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<Dimension>& x = xj[cell_id]; + cell_value[cell_id] = 2 * x[0] + 2; + }); - CellValue<TinyVector<3>> cell_value{mesh_1d->connectivity()}; - parallel_for( - cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<Dimension>& x = xj[cell_id]; - cell_value[cell_id] = TinyVector<3>{2 * x[0] + 2, 3 * x[0], 2}; - }); + CellValue<const double> interpolate_value = + InterpolateItemValue<double(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj); - CellValue<const TinyVector<3>> interpolate_value = - InterpolateItemValue<TinyVector<3>(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj); + REQUIRE(same_cell_value(cell_value, interpolate_value)); + } - REQUIRE(same_cell_value(cell_value, interpolate_value)); - } + SECTION("scalar_non_linear_1d") + { + auto [i_symbol, found] = symbol_table->find("scalar_non_linear_1d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - SECTION("R3_non_linear_1d") - { - auto [i_symbol, found] = symbol_table->find("R3_non_linear_1d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + CellValue<double> cell_value{mesh_1d->connectivity()}; + parallel_for( + cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<Dimension>& x = xj[cell_id]; + cell_value[cell_id] = 2 * exp(x[0]) + 3; + }); - CellValue<TinyVector<3>> cell_value{mesh_1d->connectivity()}; - parallel_for( - cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<Dimension>& x = xj[cell_id]; - cell_value[cell_id] = TinyVector<3>{2 * exp(x[0]) + 3, x[0] - 2, 3}; - }); + CellValue<const double> interpolate_value = + InterpolateItemValue<double(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj); - CellValue<const TinyVector<3>> interpolate_value = - InterpolateItemValue<TinyVector<3>(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj); + REQUIRE(same_cell_value(cell_value, interpolate_value)); + } - REQUIRE(same_cell_value(cell_value, interpolate_value)); - } + SECTION("R3_affine_1d") + { + auto [i_symbol, found] = symbol_table->find("R3_affine_1d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - SECTION("R2x2_affine_1d") - { - auto [i_symbol, found] = symbol_table->find("R2x2_affine_1d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + CellValue<TinyVector<3>> cell_value{mesh_1d->connectivity()}; + parallel_for( + cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<Dimension>& x = xj[cell_id]; + cell_value[cell_id] = TinyVector<3>{2 * x[0] + 2, 3 * x[0], 2}; + }); - CellValue<TinyMatrix<2>> cell_value{mesh_1d->connectivity()}; - parallel_for( - cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<Dimension>& x = xj[cell_id]; - cell_value[cell_id] = TinyMatrix<2>{2 * x[0] + 3 + 2, 3 * x[0], 2 * x[0], 2}; - }); + CellValue<const TinyVector<3>> interpolate_value = + InterpolateItemValue<TinyVector<3>(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj); - CellValue<const TinyMatrix<2>> interpolate_value = - InterpolateItemValue<TinyMatrix<2>(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj); + REQUIRE(same_cell_value(cell_value, interpolate_value)); + } - REQUIRE(same_cell_value(cell_value, interpolate_value)); - } + SECTION("R3_non_linear_1d") + { + auto [i_symbol, found] = symbol_table->find("R3_non_linear_1d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - SECTION("R2x2_non_linear_1d") - { - auto [i_symbol, found] = symbol_table->find("R2x2_non_linear_1d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + CellValue<TinyVector<3>> cell_value{mesh_1d->connectivity()}; + parallel_for( + cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<Dimension>& x = xj[cell_id]; + cell_value[cell_id] = TinyVector<3>{2 * exp(x[0]) + 3, x[0] - 2, 3}; + }); - CellValue<TinyMatrix<2>> cell_value{mesh_1d->connectivity()}; - parallel_for( - cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<Dimension>& x = xj[cell_id]; - cell_value[cell_id] = TinyMatrix<2>{2 * exp(x[0]) * sin(x[0]) + 3, sin(x[0] - 2 * x[0]), 3, x[0] * x[0]}; - }); + CellValue<const TinyVector<3>> interpolate_value = + InterpolateItemValue<TinyVector<3>(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj); - CellValue<const TinyMatrix<2>> interpolate_value = - InterpolateItemValue<TinyMatrix<2>(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj); + REQUIRE(same_cell_value(cell_value, interpolate_value)); + } - REQUIRE(same_cell_value(cell_value, interpolate_value)); + SECTION("R2x2_affine_1d") + { + auto [i_symbol, found] = symbol_table->find("R2x2_affine_1d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + CellValue<TinyMatrix<2>> cell_value{mesh_1d->connectivity()}; + parallel_for( + cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<Dimension>& x = xj[cell_id]; + cell_value[cell_id] = TinyMatrix<2>{2 * x[0] + 3 + 2, 3 * x[0], 2 * x[0], 2}; + }); + + CellValue<const TinyMatrix<2>> interpolate_value = + InterpolateItemValue<TinyMatrix<2>(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj); + + REQUIRE(same_cell_value(cell_value, interpolate_value)); + } + + SECTION("R2x2_non_linear_1d") + { + auto [i_symbol, found] = symbol_table->find("R2x2_non_linear_1d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + CellValue<TinyMatrix<2>> cell_value{mesh_1d->connectivity()}; + parallel_for( + cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<Dimension>& x = xj[cell_id]; + cell_value[cell_id] = + TinyMatrix<2>{2 * exp(x[0]) * sin(x[0]) + 3, sin(x[0] - 2 * x[0]), 3, x[0] * x[0]}; + }); + + CellValue<const TinyMatrix<2>> interpolate_value = + InterpolateItemValue<TinyMatrix<2>(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj); + + REQUIRE(same_cell_value(cell_value, interpolate_value)); + } + } } } @@ -205,10 +214,16 @@ let R2x2_non_linear_1d: R^1 -> R^2x2, x -> (2 * exp(x[0]) * sin(x[0]) + 3, sin(x { constexpr size_t Dimension = 2; - const auto& mesh_2d = MeshDataBaseForTests::get().cartesianMesh2D(); - auto xj = MeshDataManager::instance().getMeshData(*mesh_2d).xj(); + std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); + + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_2d = named_mesh.mesh(); - std::string_view data = R"( + auto xj = MeshDataManager::instance().getMeshData(*mesh_2d).xj(); + + std::string_view data = R"( import math; let scalar_affine_2d: R^2 -> R, x -> 2*x[0] + 3*x[1] + 2; let scalar_non_linear_2d: R^2 -> R, x -> 2*exp(x[0])*sin(x[1])+3; @@ -217,143 +232,146 @@ let R3_non_linear_2d: R^2 -> R^3, x -> (2*exp(x[0])*sin(x[1])+3, x[0]-2*x[1], 3) let R2x2_affine_2d: R^2 -> R^2x2, x -> (2 * x[0] + 3 * x[1] + 2, 3 * x[0] + x[1], 2 * x[0] + x[1], 2); let R2x2_non_linear_2d: R^2 -> R^2x2, x -> (2*exp(x[0])*sin(x[1])+3, sin(x[0]-2*x[1]), 3, x[0]*x[1]); )"; - TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"}; - - auto ast = ASTBuilder::build(input); - - ASTModulesImporter{*ast}; - ASTNodeTypeCleaner<language::import_instruction>{*ast}; - - ASTSymbolTableBuilder{*ast}; - ASTNodeDataTypeBuilder{*ast}; - - ASTNodeTypeCleaner<language::var_declaration>{*ast}; - ASTNodeTypeCleaner<language::fct_declaration>{*ast}; - ASTNodeExpressionBuilder{*ast}; - - std::shared_ptr<SymbolTable> symbol_table = ast->m_symbol_table; - - TAO_PEGTL_NAMESPACE::position position{TAO_PEGTL_NAMESPACE::internal::iterator{"fixture"}, "fixture"}; - position.byte = data.size(); // ensure that variables are declared at this point - - SECTION("scalar_affine_2d") - { - auto [i_symbol, found] = symbol_table->find("scalar_affine_2d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); - - CellValue<double> cell_value{mesh_2d->connectivity()}; - parallel_for( - cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<Dimension>& x = xj[cell_id]; - cell_value[cell_id] = 2 * x[0] + 3 * x[1] + 2; - }); - CellValue<const double> interpolate_value = - InterpolateItemValue<double(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj); - - REQUIRE(same_cell_value(cell_value, interpolate_value)); - } - - SECTION("scalar_non_linear_2d") - { - auto [i_symbol, found] = symbol_table->find("scalar_non_linear_2d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); - - CellValue<double> cell_value{mesh_2d->connectivity()}; - parallel_for( - cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<Dimension>& x = xj[cell_id]; - cell_value[cell_id] = 2 * exp(x[0]) * sin(x[1]) + 3; - }); - CellValue<const double> interpolate_value = - InterpolateItemValue<double(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj); - - REQUIRE(same_cell_value(cell_value, interpolate_value)); - } - - SECTION("R3_affine_2d") - { - auto [i_symbol, found] = symbol_table->find("R3_affine_2d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); - - CellValue<TinyVector<3>> cell_value{mesh_2d->connectivity()}; - parallel_for( - cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<Dimension>& x = xj[cell_id]; - cell_value[cell_id] = TinyVector<3>{2 * x[0] + 3 * x[1] + 2, 3 * x[0] + x[1], 2 * x[1]}; - }); - CellValue<const TinyVector<3>> interpolate_value = - InterpolateItemValue<TinyVector<3>(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj); - - REQUIRE(same_cell_value(cell_value, interpolate_value)); - } - - SECTION("R3_non_linear_2d") - { - auto [i_symbol, found] = symbol_table->find("R3_non_linear_2d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); - - CellValue<TinyVector<3>> cell_value{mesh_2d->connectivity()}; - parallel_for( - cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<Dimension>& x = xj[cell_id]; - cell_value[cell_id] = TinyVector<3>{2 * exp(x[0]) * sin(x[1]) + 3, x[0] - 2 * x[1], 3}; - }); - CellValue<const TinyVector<3>> interpolate_value = - InterpolateItemValue<TinyVector<3>(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj); - - REQUIRE(same_cell_value(cell_value, interpolate_value)); - } - - SECTION("R2x2_affine_2d") - { - auto [i_symbol, found] = symbol_table->find("R2x2_affine_2d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); - - CellValue<TinyMatrix<2>> cell_value{mesh_2d->connectivity()}; - parallel_for( - cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<Dimension>& x = xj[cell_id]; - cell_value[cell_id] = TinyMatrix<2>{2 * x[0] + 3 * x[1] + 2, 3 * x[0] + x[1], 2 * x[0] + x[1], 2}; - }); - CellValue<const TinyMatrix<2>> interpolate_value = - InterpolateItemValue<TinyMatrix<2>(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj); - - REQUIRE(same_cell_value(cell_value, interpolate_value)); - } - - SECTION("R2x2_non_linear_2d") - { - auto [i_symbol, found] = symbol_table->find("R2x2_non_linear_2d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); - - CellValue<TinyMatrix<2>> cell_value{mesh_2d->connectivity()}; - parallel_for( - cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<Dimension>& x = xj[cell_id]; - cell_value[cell_id] = TinyMatrix<2>{2 * exp(x[0]) * sin(x[1]) + 3, sin(x[0] - 2 * x[1]), 3, x[0] * x[1]}; - }); - CellValue<const TinyMatrix<2>> interpolate_value = - InterpolateItemValue<TinyMatrix<2>(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj); - - REQUIRE(same_cell_value(cell_value, interpolate_value)); + TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"}; + + auto ast = ASTBuilder::build(input); + + ASTModulesImporter{*ast}; + ASTNodeTypeCleaner<language::import_instruction>{*ast}; + + ASTSymbolTableBuilder{*ast}; + ASTNodeDataTypeBuilder{*ast}; + + ASTNodeTypeCleaner<language::var_declaration>{*ast}; + ASTNodeTypeCleaner<language::fct_declaration>{*ast}; + ASTNodeExpressionBuilder{*ast}; + + std::shared_ptr<SymbolTable> symbol_table = ast->m_symbol_table; + + TAO_PEGTL_NAMESPACE::position position{TAO_PEGTL_NAMESPACE::internal::iterator{"fixture"}, "fixture"}; + position.byte = data.size(); // ensure that variables are declared at this point + + SECTION("scalar_affine_2d") + { + auto [i_symbol, found] = symbol_table->find("scalar_affine_2d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + CellValue<double> cell_value{mesh_2d->connectivity()}; + parallel_for( + cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<Dimension>& x = xj[cell_id]; + cell_value[cell_id] = 2 * x[0] + 3 * x[1] + 2; + }); + CellValue<const double> interpolate_value = + InterpolateItemValue<double(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj); + + REQUIRE(same_cell_value(cell_value, interpolate_value)); + } + + SECTION("scalar_non_linear_2d") + { + auto [i_symbol, found] = symbol_table->find("scalar_non_linear_2d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + CellValue<double> cell_value{mesh_2d->connectivity()}; + parallel_for( + cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<Dimension>& x = xj[cell_id]; + cell_value[cell_id] = 2 * exp(x[0]) * sin(x[1]) + 3; + }); + CellValue<const double> interpolate_value = + InterpolateItemValue<double(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj); + + REQUIRE(same_cell_value(cell_value, interpolate_value)); + } + + SECTION("R3_affine_2d") + { + auto [i_symbol, found] = symbol_table->find("R3_affine_2d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + CellValue<TinyVector<3>> cell_value{mesh_2d->connectivity()}; + parallel_for( + cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<Dimension>& x = xj[cell_id]; + cell_value[cell_id] = TinyVector<3>{2 * x[0] + 3 * x[1] + 2, 3 * x[0] + x[1], 2 * x[1]}; + }); + CellValue<const TinyVector<3>> interpolate_value = + InterpolateItemValue<TinyVector<3>(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj); + + REQUIRE(same_cell_value(cell_value, interpolate_value)); + } + + SECTION("R3_non_linear_2d") + { + auto [i_symbol, found] = symbol_table->find("R3_non_linear_2d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + CellValue<TinyVector<3>> cell_value{mesh_2d->connectivity()}; + parallel_for( + cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<Dimension>& x = xj[cell_id]; + cell_value[cell_id] = TinyVector<3>{2 * exp(x[0]) * sin(x[1]) + 3, x[0] - 2 * x[1], 3}; + }); + CellValue<const TinyVector<3>> interpolate_value = + InterpolateItemValue<TinyVector<3>(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj); + + REQUIRE(same_cell_value(cell_value, interpolate_value)); + } + + SECTION("R2x2_affine_2d") + { + auto [i_symbol, found] = symbol_table->find("R2x2_affine_2d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + CellValue<TinyMatrix<2>> cell_value{mesh_2d->connectivity()}; + parallel_for( + cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<Dimension>& x = xj[cell_id]; + cell_value[cell_id] = TinyMatrix<2>{2 * x[0] + 3 * x[1] + 2, 3 * x[0] + x[1], 2 * x[0] + x[1], 2}; + }); + CellValue<const TinyMatrix<2>> interpolate_value = + InterpolateItemValue<TinyMatrix<2>(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj); + + REQUIRE(same_cell_value(cell_value, interpolate_value)); + } + + SECTION("R2x2_non_linear_2d") + { + auto [i_symbol, found] = symbol_table->find("R2x2_non_linear_2d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + CellValue<TinyMatrix<2>> cell_value{mesh_2d->connectivity()}; + parallel_for( + cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<Dimension>& x = xj[cell_id]; + cell_value[cell_id] = + TinyMatrix<2>{2 * exp(x[0]) * sin(x[1]) + 3, sin(x[0] - 2 * x[1]), 3, x[0] * x[1]}; + }); + CellValue<const TinyMatrix<2>> interpolate_value = + InterpolateItemValue<TinyMatrix<2>(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj); + + REQUIRE(same_cell_value(cell_value, interpolate_value)); + } + } } } @@ -361,10 +379,16 @@ let R2x2_non_linear_2d: R^2 -> R^2x2, x -> (2*exp(x[0])*sin(x[1])+3, sin(x[0]-2* { constexpr size_t Dimension = 3; - const auto& mesh_3d = MeshDataBaseForTests::get().cartesianMesh3D(); - auto xj = MeshDataManager::instance().getMeshData(*mesh_3d).xj(); + std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); + + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_3d = named_mesh.mesh(); + + auto xj = MeshDataManager::instance().getMeshData(*mesh_3d).xj(); - std::string_view data = R"( + std::string_view data = R"( import math; let scalar_affine_3d: R^3 -> R, x -> 2 * x[0] + 3 * x[1] + 2 * x[2] - 1; let scalar_non_linear_3d: R^3 -> R, x -> 2 * exp(x[0]) * sin(x[1]) * x[2] + 3; @@ -373,145 +397,147 @@ let R3_non_linear_3d: R^3 -> R^3, x -> (2 * exp(x[0]) * sin(x[1]) + x[2] + 3, x[ let R2x2_affine_3d: R^3 -> R^2x2, x -> (2 * x[0] + 3 * x[1] + 2 * x[2] + 1, 3 * x[0] + x[1] + 2 * x[2], 2 * x[0] + x[1] + x[2], 2); let R2x2_non_linear_3d: R^3 -> R^2x2, x -> (2 * exp(x[0]) * sin(x[1]) + 3 * cos(x[2]), sin(x[0] - 2 * x[1] * x[2]), 3, x[0] * x[1] * x[2]); )"; - TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"}; - - auto ast = ASTBuilder::build(input); - - ASTModulesImporter{*ast}; - ASTNodeTypeCleaner<language::import_instruction>{*ast}; - - ASTSymbolTableBuilder{*ast}; - ASTNodeDataTypeBuilder{*ast}; - - ASTNodeTypeCleaner<language::var_declaration>{*ast}; - ASTNodeTypeCleaner<language::fct_declaration>{*ast}; - ASTNodeExpressionBuilder{*ast}; - - std::shared_ptr<SymbolTable> symbol_table = ast->m_symbol_table; - - TAO_PEGTL_NAMESPACE::position position{TAO_PEGTL_NAMESPACE::internal::iterator{"fixture"}, "fixture"}; - position.byte = data.size(); // ensure that variables are declared at this point - - SECTION("scalar_affine_3d") - { - auto [i_symbol, found] = symbol_table->find("scalar_affine_3d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); - - CellValue<double> cell_value{mesh_3d->connectivity()}; - parallel_for( - cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<Dimension>& x = xj[cell_id]; - cell_value[cell_id] = 2 * x[0] + 3 * x[1] + 2 * x[2] - 1; - }); - CellValue<const double> interpolate_value = - InterpolateItemValue<double(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj); - - REQUIRE(same_cell_value(cell_value, interpolate_value)); - } - - SECTION("scalar_non_linear_3d") - { - auto [i_symbol, found] = symbol_table->find("scalar_non_linear_3d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); - - CellValue<double> cell_value{mesh_3d->connectivity()}; - parallel_for( - cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<Dimension>& x = xj[cell_id]; - cell_value[cell_id] = 2 * exp(x[0]) * sin(x[1]) * x[2] + 3; - }); - CellValue<const double> interpolate_value = - InterpolateItemValue<double(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj); - - REQUIRE(same_cell_value(cell_value, interpolate_value)); - } - - SECTION("R3_affine_3d") - { - auto [i_symbol, found] = symbol_table->find("R3_affine_3d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); - - CellValue<TinyVector<3>> cell_value{mesh_3d->connectivity()}; - parallel_for( - cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<Dimension>& x = xj[cell_id]; - cell_value[cell_id] = TinyVector<3>{2 * x[0] + 3 * x[1] + 2, 3 * x[0] + x[1] + 2 * x[2], 2 * x[2]}; - }); - CellValue<const TinyVector<3>> interpolate_value = - InterpolateItemValue<TinyVector<3>(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj); - - REQUIRE(same_cell_value(cell_value, interpolate_value)); - } - - SECTION("R3_non_linear_3d") - { - auto [i_symbol, found] = symbol_table->find("R3_non_linear_3d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); - - CellValue<TinyVector<3>> cell_value{mesh_3d->connectivity()}; - parallel_for( - cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<Dimension>& x = xj[cell_id]; - cell_value[cell_id] = TinyVector<3>{2 * exp(x[0]) * sin(x[1]) + x[2] + 3, x[0] * x[2] - 2 * x[1], 3}; - }); - CellValue<const TinyVector<3>> interpolate_value = - InterpolateItemValue<TinyVector<3>(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj); - - REQUIRE(same_cell_value(cell_value, interpolate_value)); - } - - SECTION("R2x2_affine_3d") - { - auto [i_symbol, found] = symbol_table->find("R2x2_affine_3d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); - - CellValue<TinyMatrix<2>> cell_value{mesh_3d->connectivity()}; - parallel_for( - cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<Dimension>& x = xj[cell_id]; - cell_value[cell_id] = - TinyMatrix<2>{2 * x[0] + 3 * x[1] + 2 * x[2] + 1, 3 * x[0] + x[1] + 2 * x[2], 2 * x[0] + x[1] + x[2], 2}; - }); - CellValue<const TinyMatrix<2>> interpolate_value = - InterpolateItemValue<TinyMatrix<2>(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj); - - REQUIRE(same_cell_value(cell_value, interpolate_value)); - } - - SECTION("R2x2_non_linear_3d") - { - auto [i_symbol, found] = symbol_table->find("R2x2_non_linear_3d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); - - CellValue<TinyMatrix<2>> cell_value{mesh_3d->connectivity()}; - parallel_for( - cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<Dimension>& x = xj[cell_id]; - cell_value[cell_id] = TinyMatrix<2>{2 * exp(x[0]) * sin(x[1]) + 3 * cos(x[2]), sin(x[0] - 2 * x[1] * x[2]), - 3, x[0] * x[1] * x[2]}; - }); - CellValue<const TinyMatrix<2>> interpolate_value = - InterpolateItemValue<TinyMatrix<2>(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj); - - REQUIRE(same_cell_value(cell_value, interpolate_value)); + TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"}; + + auto ast = ASTBuilder::build(input); + + ASTModulesImporter{*ast}; + ASTNodeTypeCleaner<language::import_instruction>{*ast}; + + ASTSymbolTableBuilder{*ast}; + ASTNodeDataTypeBuilder{*ast}; + + ASTNodeTypeCleaner<language::var_declaration>{*ast}; + ASTNodeTypeCleaner<language::fct_declaration>{*ast}; + ASTNodeExpressionBuilder{*ast}; + + std::shared_ptr<SymbolTable> symbol_table = ast->m_symbol_table; + + TAO_PEGTL_NAMESPACE::position position{TAO_PEGTL_NAMESPACE::internal::iterator{"fixture"}, "fixture"}; + position.byte = data.size(); // ensure that variables are declared at this point + + SECTION("scalar_affine_3d") + { + auto [i_symbol, found] = symbol_table->find("scalar_affine_3d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + CellValue<double> cell_value{mesh_3d->connectivity()}; + parallel_for( + cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<Dimension>& x = xj[cell_id]; + cell_value[cell_id] = 2 * x[0] + 3 * x[1] + 2 * x[2] - 1; + }); + CellValue<const double> interpolate_value = + InterpolateItemValue<double(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj); + + REQUIRE(same_cell_value(cell_value, interpolate_value)); + } + + SECTION("scalar_non_linear_3d") + { + auto [i_symbol, found] = symbol_table->find("scalar_non_linear_3d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + CellValue<double> cell_value{mesh_3d->connectivity()}; + parallel_for( + cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<Dimension>& x = xj[cell_id]; + cell_value[cell_id] = 2 * exp(x[0]) * sin(x[1]) * x[2] + 3; + }); + CellValue<const double> interpolate_value = + InterpolateItemValue<double(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj); + + REQUIRE(same_cell_value(cell_value, interpolate_value)); + } + + SECTION("R3_affine_3d") + { + auto [i_symbol, found] = symbol_table->find("R3_affine_3d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + CellValue<TinyVector<3>> cell_value{mesh_3d->connectivity()}; + parallel_for( + cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<Dimension>& x = xj[cell_id]; + cell_value[cell_id] = TinyVector<3>{2 * x[0] + 3 * x[1] + 2, 3 * x[0] + x[1] + 2 * x[2], 2 * x[2]}; + }); + CellValue<const TinyVector<3>> interpolate_value = + InterpolateItemValue<TinyVector<3>(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj); + + REQUIRE(same_cell_value(cell_value, interpolate_value)); + } + + SECTION("R3_non_linear_3d") + { + auto [i_symbol, found] = symbol_table->find("R3_non_linear_3d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + CellValue<TinyVector<3>> cell_value{mesh_3d->connectivity()}; + parallel_for( + cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<Dimension>& x = xj[cell_id]; + cell_value[cell_id] = TinyVector<3>{2 * exp(x[0]) * sin(x[1]) + x[2] + 3, x[0] * x[2] - 2 * x[1], 3}; + }); + CellValue<const TinyVector<3>> interpolate_value = + InterpolateItemValue<TinyVector<3>(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj); + + REQUIRE(same_cell_value(cell_value, interpolate_value)); + } + + SECTION("R2x2_affine_3d") + { + auto [i_symbol, found] = symbol_table->find("R2x2_affine_3d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + CellValue<TinyMatrix<2>> cell_value{mesh_3d->connectivity()}; + parallel_for( + cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<Dimension>& x = xj[cell_id]; + cell_value[cell_id] = TinyMatrix<2>{2 * x[0] + 3 * x[1] + 2 * x[2] + 1, 3 * x[0] + x[1] + 2 * x[2], + 2 * x[0] + x[1] + x[2], 2}; + }); + CellValue<const TinyMatrix<2>> interpolate_value = + InterpolateItemValue<TinyMatrix<2>(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj); + + REQUIRE(same_cell_value(cell_value, interpolate_value)); + } + + SECTION("R2x2_non_linear_3d") + { + auto [i_symbol, found] = symbol_table->find("R2x2_non_linear_3d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + CellValue<TinyMatrix<2>> cell_value{mesh_3d->connectivity()}; + parallel_for( + cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<Dimension>& x = xj[cell_id]; + cell_value[cell_id] = TinyMatrix<2>{2 * exp(x[0]) * sin(x[1]) + 3 * cos(x[2]), + sin(x[0] - 2 * x[1] * x[2]), 3, x[0] * x[1] * x[2]}; + }); + CellValue<const TinyMatrix<2>> interpolate_value = + InterpolateItemValue<TinyMatrix<2>(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj); + + REQUIRE(same_cell_value(cell_value, interpolate_value)); + } + } } } } @@ -532,18 +558,24 @@ let R2x2_non_linear_3d: R^3 -> R^2x2, x -> (2 * exp(x[0]) * sin(x[1]) + 3 * cos( { constexpr size_t Dimension = 1; - const auto& mesh_1d = MeshDataBaseForTests::get().cartesianMesh1D(); - auto xj = MeshDataManager::instance().getMeshData(*mesh_1d).xj(); + std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - Array<const CellId> cell_id_list = [&] { - Array<CellId> cell_ids{mesh_1d->numberOfCells() / 2}; - for (size_t i_cell = 0; i_cell < cell_ids.size(); ++i_cell) { - cell_ids[i_cell] = static_cast<CellId>(2 * i_cell); - } - return cell_ids; - }(); + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_1d = named_mesh.mesh(); + + auto xj = MeshDataManager::instance().getMeshData(*mesh_1d).xj(); + + Array<const CellId> cell_id_list = [&] { + Array<CellId> cell_ids{mesh_1d->numberOfCells() / 2}; + for (size_t i_cell = 0; i_cell < cell_ids.size(); ++i_cell) { + cell_ids[i_cell] = static_cast<CellId>(2 * i_cell); + } + return cell_ids; + }(); - std::string_view data = R"( + std::string_view data = R"( import math; let scalar_affine_1d: R^1 -> R, x -> 2*x[0] + 2; let scalar_non_linear_1d: R^1 -> R, x -> 2 * exp(x[0]) + 3; @@ -552,149 +584,155 @@ let R3_non_linear_1d: R^1 -> R^3, x -> (2 * exp(x[0]) + 3, x[0] - 2, 3); let R2x2_affine_1d: R^1 -> R^2x2, x -> (2 * x[0] + 3 + 2, 3 * x[0], 2 * x[0], 2); let R2x2_non_linear_1d: R^1 -> R^2x2, x -> (2 * exp(x[0]) * sin(x[0]) + 3, sin(x[0] - 2 * x[0]), 3, x[0] * x[0]); )"; - TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"}; - - auto ast = ASTBuilder::build(input); - - ASTModulesImporter{*ast}; - ASTNodeTypeCleaner<language::import_instruction>{*ast}; - - ASTSymbolTableBuilder{*ast}; - ASTNodeDataTypeBuilder{*ast}; - - ASTNodeTypeCleaner<language::var_declaration>{*ast}; - ASTNodeTypeCleaner<language::fct_declaration>{*ast}; - ASTNodeExpressionBuilder{*ast}; - - std::shared_ptr<SymbolTable> symbol_table = ast->m_symbol_table; - - TAO_PEGTL_NAMESPACE::position position{TAO_PEGTL_NAMESPACE::internal::iterator{"fixture"}, "fixture"}; - position.byte = data.size(); // ensure that variables are declared at this point + TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"}; - SECTION("scalar_affine_1d") - { - auto [i_symbol, found] = symbol_table->find("scalar_affine_1d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + auto ast = ASTBuilder::build(input); - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + ASTModulesImporter{*ast}; + ASTNodeTypeCleaner<language::import_instruction>{*ast}; - Array<double> cell_value{cell_id_list.size()}; - parallel_for( - cell_value.size(), PUGS_LAMBDA(const size_t i) { - const TinyVector<Dimension>& x = xj[cell_id_list[i]]; - cell_value[i] = 2 * x[0] + 2; - }); + ASTSymbolTableBuilder{*ast}; + ASTNodeDataTypeBuilder{*ast}; - Array<const double> interpolate_value = - InterpolateItemValue<double(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj, cell_id_list); + ASTNodeTypeCleaner<language::var_declaration>{*ast}; + ASTNodeTypeCleaner<language::fct_declaration>{*ast}; + ASTNodeExpressionBuilder{*ast}; - REQUIRE(same_cell_value(cell_value, interpolate_value)); - } - - SECTION("scalar_non_linear_1d") - { - auto [i_symbol, found] = symbol_table->find("scalar_non_linear_1d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); - - Array<double> cell_value{cell_id_list.size()}; - parallel_for( - cell_value.size(), PUGS_LAMBDA(const size_t i) { - const TinyVector<Dimension>& x = xj[cell_id_list[i]]; - cell_value[i] = 2 * exp(x[0]) + 3; - }); - - Array<const double> interpolate_value = - InterpolateItemValue<double(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj, cell_id_list); - - REQUIRE(same_cell_value(cell_value, interpolate_value)); - } - - SECTION("R3_affine_1d") - { - auto [i_symbol, found] = symbol_table->find("R3_affine_1d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); - - Array<TinyVector<3>> cell_value{cell_id_list.size()}; - parallel_for( - cell_value.size(), PUGS_LAMBDA(const size_t i) { - const TinyVector<Dimension>& x = xj[cell_id_list[i]]; - cell_value[i] = TinyVector<3>{2 * x[0] + 2, 3 * x[0], 2}; - }); - - Array<const TinyVector<3>> interpolate_value = - InterpolateItemValue<TinyVector<3>(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj, cell_id_list); - - REQUIRE(same_cell_value(cell_value, interpolate_value)); - } - - SECTION("R3_non_linear_1d") - { - auto [i_symbol, found] = symbol_table->find("R3_non_linear_1d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); - - Array<TinyVector<3>> cell_value{cell_id_list.size()}; - parallel_for( - cell_value.size(), PUGS_LAMBDA(const size_t i) { - const TinyVector<Dimension>& x = xj[cell_id_list[i]]; - cell_value[i] = TinyVector<3>{2 * exp(x[0]) + 3, x[0] - 2, 3}; - }); - - Array<const TinyVector<3>> interpolate_value = - InterpolateItemValue<TinyVector<3>(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj, cell_id_list); - - REQUIRE(same_cell_value(cell_value, interpolate_value)); - } - - SECTION("R2x2_affine_1d") - { - auto [i_symbol, found] = symbol_table->find("R2x2_affine_1d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + std::shared_ptr<SymbolTable> symbol_table = ast->m_symbol_table; - Array<TinyMatrix<2>> cell_value{cell_id_list.size()}; - parallel_for( - cell_value.size(), PUGS_LAMBDA(const size_t i) { - const TinyVector<Dimension>& x = xj[cell_id_list[i]]; - cell_value[i] = TinyMatrix<2>{2 * x[0] + 3 + 2, 3 * x[0], 2 * x[0], 2}; - }); + TAO_PEGTL_NAMESPACE::position position{TAO_PEGTL_NAMESPACE::internal::iterator{"fixture"}, "fixture"}; + position.byte = data.size(); // ensure that variables are declared at this point - Array<const TinyMatrix<2>> interpolate_value = - InterpolateItemValue<TinyMatrix<2>(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj, cell_id_list); + SECTION("scalar_affine_1d") + { + auto [i_symbol, found] = symbol_table->find("scalar_affine_1d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - REQUIRE(same_cell_value(cell_value, interpolate_value)); - } + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); - SECTION("R2x2_non_linear_1d") - { - auto [i_symbol, found] = symbol_table->find("R2x2_non_linear_1d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + Array<double> cell_value{cell_id_list.size()}; + parallel_for( + cell_value.size(), PUGS_LAMBDA(const size_t i) { + const TinyVector<Dimension>& x = xj[cell_id_list[i]]; + cell_value[i] = 2 * x[0] + 2; + }); - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + Array<const double> interpolate_value = + InterpolateItemValue<double(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj, cell_id_list); - Array<TinyMatrix<2>> cell_value{cell_id_list.size()}; - parallel_for( - cell_value.size(), PUGS_LAMBDA(const size_t i) { - const TinyVector<Dimension>& x = xj[cell_id_list[i]]; - cell_value[i] = TinyMatrix<2>{2 * exp(x[0]) * sin(x[0]) + 3, sin(x[0] - 2 * x[0]), 3, x[0] * x[0]}; - }); + REQUIRE(same_cell_value(cell_value, interpolate_value)); + } + + SECTION("scalar_non_linear_1d") + { + auto [i_symbol, found] = symbol_table->find("scalar_non_linear_1d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - Array<const TinyMatrix<2>> interpolate_value = - InterpolateItemValue<TinyMatrix<2>(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj, cell_id_list); + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + Array<double> cell_value{cell_id_list.size()}; + parallel_for( + cell_value.size(), PUGS_LAMBDA(const size_t i) { + const TinyVector<Dimension>& x = xj[cell_id_list[i]]; + cell_value[i] = 2 * exp(x[0]) + 3; + }); + + Array<const double> interpolate_value = + InterpolateItemValue<double(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj, cell_id_list); + + REQUIRE(same_cell_value(cell_value, interpolate_value)); + } + + SECTION("R3_affine_1d") + { + auto [i_symbol, found] = symbol_table->find("R3_affine_1d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + Array<TinyVector<3>> cell_value{cell_id_list.size()}; + parallel_for( + cell_value.size(), PUGS_LAMBDA(const size_t i) { + const TinyVector<Dimension>& x = xj[cell_id_list[i]]; + cell_value[i] = TinyVector<3>{2 * x[0] + 2, 3 * x[0], 2}; + }); + + Array<const TinyVector<3>> interpolate_value = + InterpolateItemValue<TinyVector<3>(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj, + cell_id_list); + + REQUIRE(same_cell_value(cell_value, interpolate_value)); + } + + SECTION("R3_non_linear_1d") + { + auto [i_symbol, found] = symbol_table->find("R3_non_linear_1d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + Array<TinyVector<3>> cell_value{cell_id_list.size()}; + parallel_for( + cell_value.size(), PUGS_LAMBDA(const size_t i) { + const TinyVector<Dimension>& x = xj[cell_id_list[i]]; + cell_value[i] = TinyVector<3>{2 * exp(x[0]) + 3, x[0] - 2, 3}; + }); + + Array<const TinyVector<3>> interpolate_value = + InterpolateItemValue<TinyVector<3>(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj, + cell_id_list); - REQUIRE(same_cell_value(cell_value, interpolate_value)); + REQUIRE(same_cell_value(cell_value, interpolate_value)); + } + + SECTION("R2x2_affine_1d") + { + auto [i_symbol, found] = symbol_table->find("R2x2_affine_1d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + Array<TinyMatrix<2>> cell_value{cell_id_list.size()}; + parallel_for( + cell_value.size(), PUGS_LAMBDA(const size_t i) { + const TinyVector<Dimension>& x = xj[cell_id_list[i]]; + cell_value[i] = TinyMatrix<2>{2 * x[0] + 3 + 2, 3 * x[0], 2 * x[0], 2}; + }); + + Array<const TinyMatrix<2>> interpolate_value = + InterpolateItemValue<TinyMatrix<2>(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj, + cell_id_list); + + REQUIRE(same_cell_value(cell_value, interpolate_value)); + } + + SECTION("R2x2_non_linear_1d") + { + auto [i_symbol, found] = symbol_table->find("R2x2_non_linear_1d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + Array<TinyMatrix<2>> cell_value{cell_id_list.size()}; + parallel_for( + cell_value.size(), PUGS_LAMBDA(const size_t i) { + const TinyVector<Dimension>& x = xj[cell_id_list[i]]; + cell_value[i] = TinyMatrix<2>{2 * exp(x[0]) * sin(x[0]) + 3, sin(x[0] - 2 * x[0]), 3, x[0] * x[0]}; + }); + + Array<const TinyMatrix<2>> interpolate_value = + InterpolateItemValue<TinyMatrix<2>(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj, + cell_id_list); + + REQUIRE(same_cell_value(cell_value, interpolate_value)); + } + } } } @@ -702,15 +740,21 @@ let R2x2_non_linear_1d: R^1 -> R^2x2, x -> (2 * exp(x[0]) * sin(x[0]) + 3, sin(x { constexpr size_t Dimension = 2; - const auto& mesh_2d = MeshDataBaseForTests::get().cartesianMesh2D(); - auto xj = MeshDataManager::instance().getMeshData(*mesh_2d).xj(); + std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - Array<CellId> cell_id_list{mesh_2d->numberOfCells() / 2}; - for (size_t i_cell = 0; i_cell < cell_id_list.size(); ++i_cell) { - cell_id_list[i_cell] = static_cast<CellId>(2 * i_cell); - } + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_2d = named_mesh.mesh(); - std::string_view data = R"( + auto xj = MeshDataManager::instance().getMeshData(*mesh_2d).xj(); + + Array<CellId> cell_id_list{mesh_2d->numberOfCells() / 2}; + for (size_t i_cell = 0; i_cell < cell_id_list.size(); ++i_cell) { + cell_id_list[i_cell] = static_cast<CellId>(2 * i_cell); + } + + std::string_view data = R"( import math; let scalar_affine_2d: R^2 -> R, x -> 2*x[0] + 3*x[1] + 2; let scalar_non_linear_2d: R^2 -> R, x -> 2*exp(x[0])*sin(x[1])+3; @@ -719,144 +763,150 @@ let R3_non_linear_2d: R^2 -> R^3, x -> (2*exp(x[0])*sin(x[1])+3, x[0]-2*x[1], 3) let R2x2_affine_2d: R^2 -> R^2x2, x -> (2 * x[0] + 3 * x[1] + 2, 3 * x[0] + x[1], 2 * x[0] + x[1], 2); let R2x2_non_linear_2d: R^2 -> R^2x2, x -> (2*exp(x[0])*sin(x[1])+3, sin(x[0]-2*x[1]), 3, x[0]*x[1]); )"; - TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"}; - - auto ast = ASTBuilder::build(input); - - ASTModulesImporter{*ast}; - ASTNodeTypeCleaner<language::import_instruction>{*ast}; - - ASTSymbolTableBuilder{*ast}; - ASTNodeDataTypeBuilder{*ast}; - - ASTNodeTypeCleaner<language::var_declaration>{*ast}; - ASTNodeTypeCleaner<language::fct_declaration>{*ast}; - ASTNodeExpressionBuilder{*ast}; - - std::shared_ptr<SymbolTable> symbol_table = ast->m_symbol_table; - - TAO_PEGTL_NAMESPACE::position position{TAO_PEGTL_NAMESPACE::internal::iterator{"fixture"}, "fixture"}; - position.byte = data.size(); // ensure that variables are declared at this point - - SECTION("scalar_affine_2d") - { - auto [i_symbol, found] = symbol_table->find("scalar_affine_2d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); - - Array<double> cell_value{cell_id_list.size()}; - parallel_for( - cell_value.size(), PUGS_LAMBDA(const size_t i) { - const TinyVector<Dimension>& x = xj[cell_id_list[i]]; - cell_value[i] = 2 * x[0] + 3 * x[1] + 2; - }); - - Array<const double> interpolate_value = - InterpolateItemValue<double(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj, cell_id_list); - - REQUIRE(same_cell_value(cell_value, interpolate_value)); - } - - SECTION("scalar_non_linear_2d") - { - auto [i_symbol, found] = symbol_table->find("scalar_non_linear_2d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); - - Array<double> cell_value{cell_id_list.size()}; - parallel_for( - cell_value.size(), PUGS_LAMBDA(const size_t i) { - const TinyVector<Dimension>& x = xj[cell_id_list[i]]; - cell_value[i] = 2 * exp(x[0]) * sin(x[1]) + 3; - }); - Array<const double> interpolate_value = - InterpolateItemValue<double(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj, cell_id_list); - - REQUIRE(same_cell_value(cell_value, interpolate_value)); - } - - SECTION("R3_affine_2d") - { - auto [i_symbol, found] = symbol_table->find("R3_affine_2d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); - - Array<TinyVector<3>> cell_value{cell_id_list.size()}; - parallel_for( - cell_value.size(), PUGS_LAMBDA(const size_t i) { - const TinyVector<Dimension>& x = xj[cell_id_list[i]]; - cell_value[i] = TinyVector<3>{2 * x[0] + 3 * x[1] + 2, 3 * x[0] + x[1], 2 * x[1]}; - }); - Array<const TinyVector<3>> interpolate_value = - InterpolateItemValue<TinyVector<3>(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj, cell_id_list); - - REQUIRE(same_cell_value(cell_value, interpolate_value)); - } - - SECTION("R3_non_linear_2d") - { - auto [i_symbol, found] = symbol_table->find("R3_non_linear_2d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); - - Array<TinyVector<3>> cell_value{cell_id_list.size()}; - parallel_for( - cell_value.size(), PUGS_LAMBDA(const size_t i) { - const TinyVector<Dimension>& x = xj[cell_id_list[i]]; - cell_value[i] = TinyVector<3>{2 * exp(x[0]) * sin(x[1]) + 3, x[0] - 2 * x[1], 3}; - }); - Array<const TinyVector<3>> interpolate_value = - InterpolateItemValue<TinyVector<3>(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj, cell_id_list); - - REQUIRE(same_cell_value(cell_value, interpolate_value)); - } - - SECTION("R2x2_affine_2d") - { - auto [i_symbol, found] = symbol_table->find("R2x2_affine_2d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); - - Array<TinyMatrix<2>> cell_value{cell_id_list.size()}; - parallel_for( - cell_value.size(), PUGS_LAMBDA(const size_t i) { - const TinyVector<Dimension>& x = xj[cell_id_list[i]]; - cell_value[i] = TinyMatrix<2>{2 * x[0] + 3 * x[1] + 2, 3 * x[0] + x[1], 2 * x[0] + x[1], 2}; - }); - Array<const TinyMatrix<2>> interpolate_value = - InterpolateItemValue<TinyMatrix<2>(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj, cell_id_list); - - REQUIRE(same_cell_value(cell_value, interpolate_value)); - } - - SECTION("R2x2_non_linear_2d") - { - auto [i_symbol, found] = symbol_table->find("R2x2_non_linear_2d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); - - Array<TinyMatrix<2>> cell_value{cell_id_list.size()}; - parallel_for( - cell_value.size(), PUGS_LAMBDA(const size_t i) { - const TinyVector<Dimension>& x = xj[cell_id_list[i]]; - cell_value[i] = TinyMatrix<2>{2 * exp(x[0]) * sin(x[1]) + 3, sin(x[0] - 2 * x[1]), 3, x[0] * x[1]}; - }); - Array<const TinyMatrix<2>> interpolate_value = - InterpolateItemValue<TinyMatrix<2>(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj, cell_id_list); - - REQUIRE(same_cell_value(cell_value, interpolate_value)); + TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"}; + + auto ast = ASTBuilder::build(input); + + ASTModulesImporter{*ast}; + ASTNodeTypeCleaner<language::import_instruction>{*ast}; + + ASTSymbolTableBuilder{*ast}; + ASTNodeDataTypeBuilder{*ast}; + + ASTNodeTypeCleaner<language::var_declaration>{*ast}; + ASTNodeTypeCleaner<language::fct_declaration>{*ast}; + ASTNodeExpressionBuilder{*ast}; + + std::shared_ptr<SymbolTable> symbol_table = ast->m_symbol_table; + + TAO_PEGTL_NAMESPACE::position position{TAO_PEGTL_NAMESPACE::internal::iterator{"fixture"}, "fixture"}; + position.byte = data.size(); // ensure that variables are declared at this point + + SECTION("scalar_affine_2d") + { + auto [i_symbol, found] = symbol_table->find("scalar_affine_2d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + Array<double> cell_value{cell_id_list.size()}; + parallel_for( + cell_value.size(), PUGS_LAMBDA(const size_t i) { + const TinyVector<Dimension>& x = xj[cell_id_list[i]]; + cell_value[i] = 2 * x[0] + 3 * x[1] + 2; + }); + + Array<const double> interpolate_value = + InterpolateItemValue<double(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj, cell_id_list); + + REQUIRE(same_cell_value(cell_value, interpolate_value)); + } + + SECTION("scalar_non_linear_2d") + { + auto [i_symbol, found] = symbol_table->find("scalar_non_linear_2d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + Array<double> cell_value{cell_id_list.size()}; + parallel_for( + cell_value.size(), PUGS_LAMBDA(const size_t i) { + const TinyVector<Dimension>& x = xj[cell_id_list[i]]; + cell_value[i] = 2 * exp(x[0]) * sin(x[1]) + 3; + }); + Array<const double> interpolate_value = + InterpolateItemValue<double(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj, cell_id_list); + + REQUIRE(same_cell_value(cell_value, interpolate_value)); + } + + SECTION("R3_affine_2d") + { + auto [i_symbol, found] = symbol_table->find("R3_affine_2d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + Array<TinyVector<3>> cell_value{cell_id_list.size()}; + parallel_for( + cell_value.size(), PUGS_LAMBDA(const size_t i) { + const TinyVector<Dimension>& x = xj[cell_id_list[i]]; + cell_value[i] = TinyVector<3>{2 * x[0] + 3 * x[1] + 2, 3 * x[0] + x[1], 2 * x[1]}; + }); + Array<const TinyVector<3>> interpolate_value = + InterpolateItemValue<TinyVector<3>(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj, + cell_id_list); + + REQUIRE(same_cell_value(cell_value, interpolate_value)); + } + + SECTION("R3_non_linear_2d") + { + auto [i_symbol, found] = symbol_table->find("R3_non_linear_2d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + Array<TinyVector<3>> cell_value{cell_id_list.size()}; + parallel_for( + cell_value.size(), PUGS_LAMBDA(const size_t i) { + const TinyVector<Dimension>& x = xj[cell_id_list[i]]; + cell_value[i] = TinyVector<3>{2 * exp(x[0]) * sin(x[1]) + 3, x[0] - 2 * x[1], 3}; + }); + Array<const TinyVector<3>> interpolate_value = + InterpolateItemValue<TinyVector<3>(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj, + cell_id_list); + + REQUIRE(same_cell_value(cell_value, interpolate_value)); + } + + SECTION("R2x2_affine_2d") + { + auto [i_symbol, found] = symbol_table->find("R2x2_affine_2d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + Array<TinyMatrix<2>> cell_value{cell_id_list.size()}; + parallel_for( + cell_value.size(), PUGS_LAMBDA(const size_t i) { + const TinyVector<Dimension>& x = xj[cell_id_list[i]]; + cell_value[i] = TinyMatrix<2>{2 * x[0] + 3 * x[1] + 2, 3 * x[0] + x[1], 2 * x[0] + x[1], 2}; + }); + Array<const TinyMatrix<2>> interpolate_value = + InterpolateItemValue<TinyMatrix<2>(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj, + cell_id_list); + + REQUIRE(same_cell_value(cell_value, interpolate_value)); + } + + SECTION("R2x2_non_linear_2d") + { + auto [i_symbol, found] = symbol_table->find("R2x2_non_linear_2d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + Array<TinyMatrix<2>> cell_value{cell_id_list.size()}; + parallel_for( + cell_value.size(), PUGS_LAMBDA(const size_t i) { + const TinyVector<Dimension>& x = xj[cell_id_list[i]]; + cell_value[i] = TinyMatrix<2>{2 * exp(x[0]) * sin(x[1]) + 3, sin(x[0] - 2 * x[1]), 3, x[0] * x[1]}; + }); + Array<const TinyMatrix<2>> interpolate_value = + InterpolateItemValue<TinyMatrix<2>(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj, + cell_id_list); + + REQUIRE(same_cell_value(cell_value, interpolate_value)); + } + } } } @@ -864,15 +914,21 @@ let R2x2_non_linear_2d: R^2 -> R^2x2, x -> (2*exp(x[0])*sin(x[1])+3, sin(x[0]-2* { constexpr size_t Dimension = 3; - const auto& mesh_3d = MeshDataBaseForTests::get().cartesianMesh3D(); - auto xj = MeshDataManager::instance().getMeshData(*mesh_3d).xj(); + std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - Array<CellId> cell_id_list{mesh_3d->numberOfCells() / 2}; - for (size_t i_cell = 0; i_cell < cell_id_list.size(); ++i_cell) { - cell_id_list[i_cell] = static_cast<CellId>(2 * i_cell); - } + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_3d = named_mesh.mesh(); + + auto xj = MeshDataManager::instance().getMeshData(*mesh_3d).xj(); + + Array<CellId> cell_id_list{mesh_3d->numberOfCells() / 2}; + for (size_t i_cell = 0; i_cell < cell_id_list.size(); ++i_cell) { + cell_id_list[i_cell] = static_cast<CellId>(2 * i_cell); + } - std::string_view data = R"( + std::string_view data = R"( import math; let scalar_affine_3d: R^3 -> R, x -> 2 * x[0] + 3 * x[1] + 2 * x[2] - 1; let scalar_non_linear_3d: R^3 -> R, x -> 2 * exp(x[0]) * sin(x[1]) * x[2] + 3; @@ -881,145 +937,151 @@ let R3_non_linear_3d: R^3 -> R^3, x -> (2 * exp(x[0]) * sin(x[1]) + x[2] + 3, x[ let R2x2_affine_3d: R^3 -> R^2x2, x -> (2 * x[0] + 3 * x[1] + 2 * x[2] + 1, 3 * x[0] + x[1] + 2 * x[2], 2 * x[0] + x[1] + x[2], 2); let R2x2_non_linear_3d: R^3 -> R^2x2, x -> (2 * exp(x[0]) * sin(x[1]) + 3 * cos(x[2]), sin(x[0] - 2 * x[1] * x[2]), 3, x[0] * x[1] * x[2]); )"; - TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"}; - - auto ast = ASTBuilder::build(input); - - ASTModulesImporter{*ast}; - ASTNodeTypeCleaner<language::import_instruction>{*ast}; - - ASTSymbolTableBuilder{*ast}; - ASTNodeDataTypeBuilder{*ast}; - - ASTNodeTypeCleaner<language::var_declaration>{*ast}; - ASTNodeTypeCleaner<language::fct_declaration>{*ast}; - ASTNodeExpressionBuilder{*ast}; - - std::shared_ptr<SymbolTable> symbol_table = ast->m_symbol_table; - - TAO_PEGTL_NAMESPACE::position position{TAO_PEGTL_NAMESPACE::internal::iterator{"fixture"}, "fixture"}; - position.byte = data.size(); // ensure that variables are declared at this point - - SECTION("scalar_affine_3d") - { - auto [i_symbol, found] = symbol_table->find("scalar_affine_3d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); - - Array<double> cell_value{cell_id_list.size()}; - parallel_for( - cell_value.size(), PUGS_LAMBDA(const size_t i) { - const TinyVector<Dimension>& x = xj[cell_id_list[i]]; - cell_value[i] = 2 * x[0] + 3 * x[1] + 2 * x[2] - 1; - }); - Array<const double> interpolate_value = - InterpolateItemValue<double(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj, cell_id_list); - - REQUIRE(same_cell_value(cell_value, interpolate_value)); - } - - SECTION("scalar_non_linear_3d") - { - auto [i_symbol, found] = symbol_table->find("scalar_non_linear_3d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); - - Array<double> cell_value{cell_id_list.size()}; - parallel_for( - cell_value.size(), PUGS_LAMBDA(const size_t i) { - const TinyVector<Dimension>& x = xj[cell_id_list[i]]; - cell_value[i] = 2 * exp(x[0]) * sin(x[1]) * x[2] + 3; - }); - Array<const double> interpolate_value = - InterpolateItemValue<double(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj, cell_id_list); - - REQUIRE(same_cell_value(cell_value, interpolate_value)); - } - - SECTION("R3_affine_3d") - { - auto [i_symbol, found] = symbol_table->find("R3_affine_3d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); - - Array<TinyVector<3>> cell_value{cell_id_list.size()}; - parallel_for( - cell_value.size(), PUGS_LAMBDA(const size_t i) { - const TinyVector<Dimension>& x = xj[cell_id_list[i]]; - cell_value[i] = TinyVector<3>{2 * x[0] + 3 * x[1] + 2, 3 * x[0] + x[1] + 2 * x[2], 2 * x[2]}; - }); - Array<const TinyVector<3>> interpolate_value = - InterpolateItemValue<TinyVector<3>(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj, cell_id_list); - - REQUIRE(same_cell_value(cell_value, interpolate_value)); - } - - SECTION("R3_non_linear_3d") - { - auto [i_symbol, found] = symbol_table->find("R3_non_linear_3d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); - - Array<TinyVector<3>> cell_value{cell_id_list.size()}; - parallel_for( - cell_value.size(), PUGS_LAMBDA(const size_t i) { - const TinyVector<Dimension>& x = xj[cell_id_list[i]]; - cell_value[i] = TinyVector<3>{2 * exp(x[0]) * sin(x[1]) + x[2] + 3, x[0] * x[2] - 2 * x[1], 3}; - }); - Array<const TinyVector<3>> interpolate_value = - InterpolateItemValue<TinyVector<3>(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj, cell_id_list); - - REQUIRE(same_cell_value(cell_value, interpolate_value)); - } - - SECTION("R2x2_affine_3d") - { - auto [i_symbol, found] = symbol_table->find("R2x2_affine_3d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); - - Array<TinyMatrix<2>> cell_value{cell_id_list.size()}; - parallel_for( - cell_value.size(), PUGS_LAMBDA(const size_t i) { - const TinyVector<Dimension>& x = xj[cell_id_list[i]]; - cell_value[i] = - TinyMatrix<2>{2 * x[0] + 3 * x[1] + 2 * x[2] + 1, 3 * x[0] + x[1] + 2 * x[2], 2 * x[0] + x[1] + x[2], 2}; - }); - Array<const TinyMatrix<2>> interpolate_value = - InterpolateItemValue<TinyMatrix<2>(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj, cell_id_list); - - REQUIRE(same_cell_value(cell_value, interpolate_value)); - } - - SECTION("R2x2_non_linear_3d") - { - auto [i_symbol, found] = symbol_table->find("R2x2_non_linear_3d", position); - REQUIRE(found); - REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); - - FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); - - Array<TinyMatrix<2>> cell_value{cell_id_list.size()}; - parallel_for( - cell_value.size(), PUGS_LAMBDA(const size_t i) { - const TinyVector<Dimension>& x = xj[cell_id_list[i]]; - cell_value[i] = TinyMatrix<2>{2 * exp(x[0]) * sin(x[1]) + 3 * cos(x[2]), sin(x[0] - 2 * x[1] * x[2]), 3, - x[0] * x[1] * x[2]}; - }); - Array<const TinyMatrix<2>> interpolate_value = - InterpolateItemValue<TinyMatrix<2>(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj, cell_id_list); - - REQUIRE(same_cell_value(cell_value, interpolate_value)); + TAO_PEGTL_NAMESPACE::string_input input{data, "test.pgs"}; + + auto ast = ASTBuilder::build(input); + + ASTModulesImporter{*ast}; + ASTNodeTypeCleaner<language::import_instruction>{*ast}; + + ASTSymbolTableBuilder{*ast}; + ASTNodeDataTypeBuilder{*ast}; + + ASTNodeTypeCleaner<language::var_declaration>{*ast}; + ASTNodeTypeCleaner<language::fct_declaration>{*ast}; + ASTNodeExpressionBuilder{*ast}; + + std::shared_ptr<SymbolTable> symbol_table = ast->m_symbol_table; + + TAO_PEGTL_NAMESPACE::position position{TAO_PEGTL_NAMESPACE::internal::iterator{"fixture"}, "fixture"}; + position.byte = data.size(); // ensure that variables are declared at this point + + SECTION("scalar_affine_3d") + { + auto [i_symbol, found] = symbol_table->find("scalar_affine_3d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + Array<double> cell_value{cell_id_list.size()}; + parallel_for( + cell_value.size(), PUGS_LAMBDA(const size_t i) { + const TinyVector<Dimension>& x = xj[cell_id_list[i]]; + cell_value[i] = 2 * x[0] + 3 * x[1] + 2 * x[2] - 1; + }); + Array<const double> interpolate_value = + InterpolateItemValue<double(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj, cell_id_list); + + REQUIRE(same_cell_value(cell_value, interpolate_value)); + } + + SECTION("scalar_non_linear_3d") + { + auto [i_symbol, found] = symbol_table->find("scalar_non_linear_3d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + Array<double> cell_value{cell_id_list.size()}; + parallel_for( + cell_value.size(), PUGS_LAMBDA(const size_t i) { + const TinyVector<Dimension>& x = xj[cell_id_list[i]]; + cell_value[i] = 2 * exp(x[0]) * sin(x[1]) * x[2] + 3; + }); + Array<const double> interpolate_value = + InterpolateItemValue<double(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj, cell_id_list); + + REQUIRE(same_cell_value(cell_value, interpolate_value)); + } + + SECTION("R3_affine_3d") + { + auto [i_symbol, found] = symbol_table->find("R3_affine_3d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + Array<TinyVector<3>> cell_value{cell_id_list.size()}; + parallel_for( + cell_value.size(), PUGS_LAMBDA(const size_t i) { + const TinyVector<Dimension>& x = xj[cell_id_list[i]]; + cell_value[i] = TinyVector<3>{2 * x[0] + 3 * x[1] + 2, 3 * x[0] + x[1] + 2 * x[2], 2 * x[2]}; + }); + Array<const TinyVector<3>> interpolate_value = + InterpolateItemValue<TinyVector<3>(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj, + cell_id_list); + + REQUIRE(same_cell_value(cell_value, interpolate_value)); + } + + SECTION("R3_non_linear_3d") + { + auto [i_symbol, found] = symbol_table->find("R3_non_linear_3d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + Array<TinyVector<3>> cell_value{cell_id_list.size()}; + parallel_for( + cell_value.size(), PUGS_LAMBDA(const size_t i) { + const TinyVector<Dimension>& x = xj[cell_id_list[i]]; + cell_value[i] = TinyVector<3>{2 * exp(x[0]) * sin(x[1]) + x[2] + 3, x[0] * x[2] - 2 * x[1], 3}; + }); + Array<const TinyVector<3>> interpolate_value = + InterpolateItemValue<TinyVector<3>(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj, + cell_id_list); + + REQUIRE(same_cell_value(cell_value, interpolate_value)); + } + + SECTION("R2x2_affine_3d") + { + auto [i_symbol, found] = symbol_table->find("R2x2_affine_3d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + Array<TinyMatrix<2>> cell_value{cell_id_list.size()}; + parallel_for( + cell_value.size(), PUGS_LAMBDA(const size_t i) { + const TinyVector<Dimension>& x = xj[cell_id_list[i]]; + cell_value[i] = TinyMatrix<2>{2 * x[0] + 3 * x[1] + 2 * x[2] + 1, 3 * x[0] + x[1] + 2 * x[2], + 2 * x[0] + x[1] + x[2], 2}; + }); + Array<const TinyMatrix<2>> interpolate_value = + InterpolateItemValue<TinyMatrix<2>(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj, + cell_id_list); + + REQUIRE(same_cell_value(cell_value, interpolate_value)); + } + + SECTION("R2x2_non_linear_3d") + { + auto [i_symbol, found] = symbol_table->find("R2x2_non_linear_3d", position); + REQUIRE(found); + REQUIRE(i_symbol->attributes().dataType() == ASTNodeDataType::function_t); + + FunctionSymbolId function_symbol_id(std::get<uint64_t>(i_symbol->attributes().value()), symbol_table); + + Array<TinyMatrix<2>> cell_value{cell_id_list.size()}; + parallel_for( + cell_value.size(), PUGS_LAMBDA(const size_t i) { + const TinyVector<Dimension>& x = xj[cell_id_list[i]]; + cell_value[i] = TinyMatrix<2>{2 * exp(x[0]) * sin(x[1]) + 3 * cos(x[2]), sin(x[0] - 2 * x[1] * x[2]), 3, + x[0] * x[1] * x[2]}; + }); + Array<const TinyMatrix<2>> interpolate_value = + InterpolateItemValue<TinyMatrix<2>(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj, + cell_id_list); + + REQUIRE(same_cell_value(cell_value, interpolate_value)); + } + } } } } diff --git a/tests/test_ItemArray.cpp b/tests/test_ItemArray.cpp index 17337200786737dcc7b98c75eb18021cfd62a82d..3422d1da9c8e9627abf75fae743a826809ca5505 100644 --- a/tests/test_ItemArray.cpp +++ b/tests/test_ItemArray.cpp @@ -28,118 +28,150 @@ TEST_CASE("ItemArray", "[mesh]") SECTION("1D") { - const Mesh<Connectivity<1>>& mesh_1d = *MeshDataBaseForTests::get().cartesianMesh1D(); - const Connectivity<1>& connectivity = mesh_1d.connectivity(); - - REQUIRE_NOTHROW(NodeArray<int>{connectivity, 3}); - REQUIRE_NOTHROW(EdgeArray<int>{connectivity, 3}); - REQUIRE_NOTHROW(FaceArray<int>{connectivity, 3}); - REQUIRE_NOTHROW(CellArray<int>{connectivity, 3}); - - REQUIRE(NodeArray<int>{connectivity, 3}.isBuilt()); - REQUIRE(EdgeArray<int>{connectivity, 3}.isBuilt()); - REQUIRE(FaceArray<int>{connectivity, 3}.isBuilt()); - REQUIRE(CellArray<int>{connectivity, 3}.isBuilt()); - - NodeArray<int> node_value{connectivity, 3}; - EdgeArray<int> edge_value{connectivity, 3}; - FaceArray<int> face_value{connectivity, 3}; - CellArray<int> cell_value{connectivity, 3}; - - REQUIRE(edge_value.numberOfItems() == node_value.numberOfItems()); - REQUIRE(face_value.numberOfItems() == node_value.numberOfItems()); - REQUIRE(cell_value.numberOfItems() + 1 == node_value.numberOfItems()); - - REQUIRE(node_value.sizeOfArrays() == 3); - REQUIRE(edge_value.sizeOfArrays() == 3); - REQUIRE(face_value.sizeOfArrays() == 3); - REQUIRE(cell_value.sizeOfArrays() == 3); + std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); + + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_1d = named_mesh.mesh(); + + const Connectivity<1>& connectivity = mesh_1d->connectivity(); + + REQUIRE_NOTHROW(NodeArray<int>{connectivity, 3}); + REQUIRE_NOTHROW(EdgeArray<int>{connectivity, 3}); + REQUIRE_NOTHROW(FaceArray<int>{connectivity, 3}); + REQUIRE_NOTHROW(CellArray<int>{connectivity, 3}); + + REQUIRE(NodeArray<int>{connectivity, 3}.isBuilt()); + REQUIRE(EdgeArray<int>{connectivity, 3}.isBuilt()); + REQUIRE(FaceArray<int>{connectivity, 3}.isBuilt()); + REQUIRE(CellArray<int>{connectivity, 3}.isBuilt()); + + NodeArray<int> node_value{connectivity, 3}; + EdgeArray<int> edge_value{connectivity, 3}; + FaceArray<int> face_value{connectivity, 3}; + CellArray<int> cell_value{connectivity, 3}; + + REQUIRE(edge_value.numberOfItems() == node_value.numberOfItems()); + REQUIRE(face_value.numberOfItems() == node_value.numberOfItems()); + REQUIRE(cell_value.numberOfItems() + 1 == node_value.numberOfItems()); + + REQUIRE(node_value.sizeOfArrays() == 3); + REQUIRE(edge_value.sizeOfArrays() == 3); + REQUIRE(face_value.sizeOfArrays() == 3); + REQUIRE(cell_value.sizeOfArrays() == 3); + } + } } SECTION("2D") { - const Mesh<Connectivity<2>>& mesh_2d = *MeshDataBaseForTests::get().cartesianMesh2D(); - const Connectivity<2>& connectivity = mesh_2d.connectivity(); - - REQUIRE_NOTHROW(NodeArray<int>{connectivity, 2}); - REQUIRE_NOTHROW(EdgeArray<int>{connectivity, 2}); - REQUIRE_NOTHROW(FaceArray<int>{connectivity, 2}); - REQUIRE_NOTHROW(CellArray<int>{connectivity, 2}); - - REQUIRE(NodeArray<int>{connectivity, 2}.isBuilt()); - REQUIRE(EdgeArray<int>{connectivity, 2}.isBuilt()); - REQUIRE(FaceArray<int>{connectivity, 2}.isBuilt()); - REQUIRE(CellArray<int>{connectivity, 2}.isBuilt()); - - NodeArray<int> node_value{connectivity, 2}; - EdgeArray<int> edge_value{connectivity, 2}; - FaceArray<int> face_value{connectivity, 2}; - CellArray<int> cell_value{connectivity, 2}; - - REQUIRE(edge_value.numberOfItems() == face_value.numberOfItems()); - - REQUIRE(node_value.sizeOfArrays() == 2); - REQUIRE(edge_value.sizeOfArrays() == 2); - REQUIRE(face_value.sizeOfArrays() == 2); - REQUIRE(cell_value.sizeOfArrays() == 2); + std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); + + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_2d = named_mesh.mesh(); + + const Connectivity<2>& connectivity = mesh_2d->connectivity(); + + REQUIRE_NOTHROW(NodeArray<int>{connectivity, 2}); + REQUIRE_NOTHROW(EdgeArray<int>{connectivity, 2}); + REQUIRE_NOTHROW(FaceArray<int>{connectivity, 2}); + REQUIRE_NOTHROW(CellArray<int>{connectivity, 2}); + + REQUIRE(NodeArray<int>{connectivity, 2}.isBuilt()); + REQUIRE(EdgeArray<int>{connectivity, 2}.isBuilt()); + REQUIRE(FaceArray<int>{connectivity, 2}.isBuilt()); + REQUIRE(CellArray<int>{connectivity, 2}.isBuilt()); + + NodeArray<int> node_value{connectivity, 2}; + EdgeArray<int> edge_value{connectivity, 2}; + FaceArray<int> face_value{connectivity, 2}; + CellArray<int> cell_value{connectivity, 2}; + + REQUIRE(edge_value.numberOfItems() == face_value.numberOfItems()); + + REQUIRE(node_value.sizeOfArrays() == 2); + REQUIRE(edge_value.sizeOfArrays() == 2); + REQUIRE(face_value.sizeOfArrays() == 2); + REQUIRE(cell_value.sizeOfArrays() == 2); + } + } } SECTION("3D") { - const Mesh<Connectivity<3>>& mesh_3d = *MeshDataBaseForTests::get().cartesianMesh3D(); - const Connectivity<3>& connectivity = mesh_3d.connectivity(); - - REQUIRE_NOTHROW(NodeArray<int>{connectivity, 3}); - REQUIRE_NOTHROW(EdgeArray<int>{connectivity, 3}); - REQUIRE_NOTHROW(FaceArray<int>{connectivity, 3}); - REQUIRE_NOTHROW(CellArray<int>{connectivity, 3}); - - REQUIRE(NodeArray<int>{connectivity, 3}.isBuilt()); - REQUIRE(EdgeArray<int>{connectivity, 3}.isBuilt()); - REQUIRE(FaceArray<int>{connectivity, 3}.isBuilt()); - REQUIRE(CellArray<int>{connectivity, 3}.isBuilt()); - - NodeArray<int> node_value{connectivity, 3}; - EdgeArray<int> edge_value{connectivity, 3}; - FaceArray<int> face_value{connectivity, 3}; - CellArray<int> cell_value{connectivity, 3}; - - REQUIRE(node_value.sizeOfArrays() == 3); - REQUIRE(edge_value.sizeOfArrays() == 3); - REQUIRE(face_value.sizeOfArrays() == 3); - REQUIRE(cell_value.sizeOfArrays() == 3); + std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); + + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_3d = named_mesh.mesh(); + + const Connectivity<3>& connectivity = mesh_3d->connectivity(); + + REQUIRE_NOTHROW(NodeArray<int>{connectivity, 3}); + REQUIRE_NOTHROW(EdgeArray<int>{connectivity, 3}); + REQUIRE_NOTHROW(FaceArray<int>{connectivity, 3}); + REQUIRE_NOTHROW(CellArray<int>{connectivity, 3}); + + REQUIRE(NodeArray<int>{connectivity, 3}.isBuilt()); + REQUIRE(EdgeArray<int>{connectivity, 3}.isBuilt()); + REQUIRE(FaceArray<int>{connectivity, 3}.isBuilt()); + REQUIRE(CellArray<int>{connectivity, 3}.isBuilt()); + + NodeArray<int> node_value{connectivity, 3}; + EdgeArray<int> edge_value{connectivity, 3}; + FaceArray<int> face_value{connectivity, 3}; + CellArray<int> cell_value{connectivity, 3}; + + REQUIRE(node_value.sizeOfArrays() == 3); + REQUIRE(edge_value.sizeOfArrays() == 3); + REQUIRE(face_value.sizeOfArrays() == 3); + REQUIRE(cell_value.sizeOfArrays() == 3); + } + } } SECTION("set values from array") { - const Mesh<Connectivity<3>>& mesh_3d = *MeshDataBaseForTests::get().cartesianMesh3D(); - const Connectivity<3>& connectivity = mesh_3d.connectivity(); + std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - CellArray<size_t> cell_array{connectivity, 3}; + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_3d = named_mesh.mesh(); - Table<size_t> table{cell_array.numberOfItems(), cell_array.sizeOfArrays()}; - { - size_t k = 0; - for (size_t i = 0; i < table.numberOfRows(); ++i) { - for (size_t j = 0; j < table.numberOfColumns(); ++j) { - table(i, j) = k++; - } - } - } - cell_array = table; + const Connectivity<3>& connectivity = mesh_3d->connectivity(); - auto is_same = [](const CellArray<size_t>& cell_array, const Table<size_t>& table) { - bool is_same = true; - for (CellId cell_id = 0; cell_id < cell_array.numberOfItems(); ++cell_id) { - Array sub_array = cell_array[cell_id]; - for (size_t i = 0; i < sub_array.size(); ++i) { - is_same &= (sub_array[i] == table(cell_id, i)); + CellArray<size_t> cell_array{connectivity, 3}; + + Table<size_t> table{cell_array.numberOfItems(), cell_array.sizeOfArrays()}; + { + size_t k = 0; + for (size_t i = 0; i < table.numberOfRows(); ++i) { + for (size_t j = 0; j < table.numberOfColumns(); ++j) { + table(i, j) = k++; + } + } } + cell_array = table; + + auto is_same = [](const CellArray<size_t>& cell_array, const Table<size_t>& table) { + bool is_same = true; + for (CellId cell_id = 0; cell_id < cell_array.numberOfItems(); ++cell_id) { + Array sub_array = cell_array[cell_id]; + for (size_t i = 0; i < sub_array.size(); ++i) { + is_same &= (sub_array[i] == table(cell_id, i)); + } + } + return is_same; + }; + + REQUIRE(is_same(cell_array, table)); } - return is_same; - }; - - REQUIRE(is_same(cell_array, table)); + } } SECTION("copy") @@ -155,43 +187,59 @@ TEST_CASE("ItemArray", "[mesh]") return is_same; }; - const Mesh<Connectivity<3>>& mesh_3d = *MeshDataBaseForTests::get().cartesianMesh3D(); - const Connectivity<3>& connectivity = mesh_3d.connectivity(); + std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); + + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_3d = named_mesh.mesh(); - CellArray<int> cell_array{connectivity, 4}; - cell_array.fill(parallel::rank()); + const Connectivity<3>& connectivity = mesh_3d->connectivity(); - CellArray<const int> cell_array_const_view{cell_array}; - REQUIRE(cell_array.numberOfItems() == cell_array_const_view.numberOfItems()); - REQUIRE(cell_array.sizeOfArrays() == cell_array_const_view.sizeOfArrays()); - REQUIRE(is_same(cell_array_const_view, static_cast<std::int64_t>(parallel::rank()))); + CellArray<int> cell_array{connectivity, 4}; + cell_array.fill(parallel::rank()); - CellArray<const int> const_cell_array; - const_cell_array = copy(cell_array); + CellArray<const int> cell_array_const_view{cell_array}; + REQUIRE(cell_array.numberOfItems() == cell_array_const_view.numberOfItems()); + REQUIRE(cell_array.sizeOfArrays() == cell_array_const_view.sizeOfArrays()); + REQUIRE(is_same(cell_array_const_view, static_cast<std::int64_t>(parallel::rank()))); - CellArray<int> duplicated_cell_array{connectivity, cell_array.sizeOfArrays()}; - copy_to(const_cell_array, duplicated_cell_array); + CellArray<const int> const_cell_array; + const_cell_array = copy(cell_array); - cell_array.fill(0); + CellArray<int> duplicated_cell_array{connectivity, cell_array.sizeOfArrays()}; + copy_to(const_cell_array, duplicated_cell_array); - REQUIRE(is_same(cell_array, 0)); - REQUIRE(is_same(cell_array_const_view, 0)); - REQUIRE(is_same(const_cell_array, static_cast<std::int64_t>(parallel::rank()))); - REQUIRE(is_same(duplicated_cell_array, static_cast<std::int64_t>(parallel::rank()))); + cell_array.fill(0); + + REQUIRE(is_same(cell_array, 0)); + REQUIRE(is_same(cell_array_const_view, 0)); + REQUIRE(is_same(const_cell_array, static_cast<std::int64_t>(parallel::rank()))); + REQUIRE(is_same(duplicated_cell_array, static_cast<std::int64_t>(parallel::rank()))); + } + } } SECTION("WeakItemArray") { - const Mesh<Connectivity<2>>& mesh_2d = *MeshDataBaseForTests::get().cartesianMesh2D(); - const Connectivity<2>& connectivity = mesh_2d.connectivity(); + std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); + + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_2d = named_mesh.mesh(); + + const Connectivity<2>& connectivity = mesh_2d->connectivity(); - WeakFaceArray<int> weak_face_array{connectivity, 5}; + WeakFaceArray<int> weak_face_array{connectivity, 5}; - weak_face_array.fill(parallel::rank()); + weak_face_array.fill(parallel::rank()); - FaceArray<const int> face_array{weak_face_array}; + FaceArray<const int> face_array{weak_face_array}; - REQUIRE(face_array.connectivity_ptr() == weak_face_array.connectivity_ptr()); + REQUIRE(face_array.connectivity_ptr() == weak_face_array.connectivity_ptr()); + } + } } #ifndef NDEBUG @@ -214,35 +262,51 @@ TEST_CASE("ItemArray", "[mesh]") SECTION("checking for bounds violation") { - const Mesh<Connectivity<3>>& mesh_3d = *MeshDataBaseForTests::get().cartesianMesh3D(); - const Connectivity<3>& connectivity = mesh_3d.connectivity(); + std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); + + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_3d = named_mesh.mesh(); - CellArray<int> cell_array{connectivity, 1}; - CellId invalid_cell_id = connectivity.numberOfCells(); - REQUIRE_THROWS_AS(cell_array[invalid_cell_id], AssertError); + const Connectivity<3>& connectivity = mesh_3d->connectivity(); - FaceArray<int> face_array{connectivity, 2}; - FaceId invalid_face_id = connectivity.numberOfFaces(); - REQUIRE_THROWS_AS(face_array[invalid_face_id], AssertError); + CellArray<int> cell_array{connectivity, 1}; + CellId invalid_cell_id = connectivity.numberOfCells(); + REQUIRE_THROWS_AS(cell_array[invalid_cell_id], AssertError); - EdgeArray<int> edge_array{connectivity, 1}; - EdgeId invalid_edge_id = connectivity.numberOfEdges(); - REQUIRE_THROWS_AS(edge_array[invalid_edge_id], AssertError); + FaceArray<int> face_array{connectivity, 2}; + FaceId invalid_face_id = connectivity.numberOfFaces(); + REQUIRE_THROWS_AS(face_array[invalid_face_id], AssertError); - NodeArray<int> node_array{connectivity, 0}; - NodeId invalid_node_id = connectivity.numberOfNodes(); - REQUIRE_THROWS_AS(node_array[invalid_node_id], AssertError); + EdgeArray<int> edge_array{connectivity, 1}; + EdgeId invalid_edge_id = connectivity.numberOfEdges(); + REQUIRE_THROWS_AS(edge_array[invalid_edge_id], AssertError); + + NodeArray<int> node_array{connectivity, 0}; + NodeId invalid_node_id = connectivity.numberOfNodes(); + REQUIRE_THROWS_AS(node_array[invalid_node_id], AssertError); + } + } } SECTION("set values from invalid array size") { - const Mesh<Connectivity<3>>& mesh_3d = *MeshDataBaseForTests::get().cartesianMesh3D(); - const Connectivity<3>& connectivity = mesh_3d.connectivity(); + std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); + + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_3d = named_mesh.mesh(); + + const Connectivity<3>& connectivity = mesh_3d->connectivity(); - CellArray<size_t> cell_array{connectivity, 2}; + CellArray<size_t> cell_array{connectivity, 2}; - Table<size_t> values{3, connectivity.numberOfCells() + 3}; - REQUIRE_THROWS_AS(cell_array = values, AssertError); + Table<size_t> values{3, connectivity.numberOfCells() + 3}; + REQUIRE_THROWS_AS(cell_array = values, AssertError); + } + } } } #endif // NDEBUG diff --git a/tests/test_ItemArrayUtils.cpp b/tests/test_ItemArrayUtils.cpp index 6eb6894d41aa3700fdc86e6c0d7c9d83acda328e..af91ecb70897073a4069f20457190b6e20318e72 100644 --- a/tests/test_ItemArrayUtils.cpp +++ b/tests/test_ItemArrayUtils.cpp @@ -19,750 +19,774 @@ TEST_CASE("ItemArrayUtils", "[mesh]") { SECTION("1D") { - const Mesh<Connectivity<1>>& mesh_1d = *MeshDataBaseForTests::get().cartesianMesh1D(); - const Connectivity<1>& connectivity = mesh_1d.connectivity(); - - SECTION("node") - { - WeakNodeArray<size_t> weak_node_array{connectivity, 4}; - auto node_number = connectivity.nodeNumber(); - - for (NodeId i_node = 0; i_node < mesh_1d.numberOfNodes(); ++i_node) { - Array array = weak_node_array[i_node]; - const size_t number = node_number[i_node]; - for (size_t i = 0; i < array.size(); ++i) { - array[i] = number + (parallel::rank() + 1) * i; - } - } + std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - NodeArray<const size_t> node_array{weak_node_array}; + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_1d = named_mesh.mesh(); - REQUIRE(node_array.connectivity_ptr() == weak_node_array.connectivity_ptr()); + const Connectivity<1>& connectivity = mesh_1d->connectivity(); - { // before synchronization - auto node_owner = connectivity.nodeOwner(); - auto node_is_owned = connectivity.nodeIsOwned(); + SECTION("node") + { + WeakNodeArray<size_t> weak_node_array{connectivity, 4}; + auto node_number = connectivity.nodeNumber(); - bool is_synchronized = (parallel::size() > 1); - bool is_valid = true; - for (NodeId i_node = 0; i_node < mesh_1d.numberOfNodes(); ++i_node) { - Array array = node_array[i_node]; - const size_t number = node_number[i_node]; - const size_t owner = node_owner[i_node]; - if (node_is_owned[i_node]) { - for (size_t i = 0; i < array.size(); ++i) { - is_valid &= (array[i] == number + (owner + 1) * i); - } - } else { + for (NodeId i_node = 0; i_node < mesh_1d->numberOfNodes(); ++i_node) { + Array array = weak_node_array[i_node]; + const size_t number = node_number[i_node]; for (size_t i = 0; i < array.size(); ++i) { - is_synchronized &= (array[i] == number + (owner + 1) * i); + array[i] = number + (parallel::rank() + 1) * i; } } - } - REQUIRE(is_valid); - REQUIRE(not is_synchronized); - } - - synchronize(weak_node_array); - - { // after synchronization - auto node_owner = connectivity.nodeOwner(); + NodeArray<const size_t> node_array{weak_node_array}; + + REQUIRE(node_array.connectivity_ptr() == weak_node_array.connectivity_ptr()); + + { // before synchronization + auto node_owner = connectivity.nodeOwner(); + auto node_is_owned = connectivity.nodeIsOwned(); + + bool is_synchronized = (parallel::size() > 1); + bool is_valid = true; + for (NodeId i_node = 0; i_node < mesh_1d->numberOfNodes(); ++i_node) { + Array array = node_array[i_node]; + const size_t number = node_number[i_node]; + const size_t owner = node_owner[i_node]; + if (node_is_owned[i_node]) { + for (size_t i = 0; i < array.size(); ++i) { + is_valid &= (array[i] == number + (owner + 1) * i); + } + } else { + for (size_t i = 0; i < array.size(); ++i) { + is_synchronized &= (array[i] == number + (owner + 1) * i); + } + } + } - bool is_synchronized = true; - for (NodeId i_node = 0; i_node < mesh_1d.numberOfNodes(); ++i_node) { - Array array = node_array[i_node]; - const size_t number = node_number[i_node]; - const size_t owner = node_owner[i_node]; - for (size_t i = 0; i < array.size(); ++i) { - is_synchronized &= (array[i] == number + (owner + 1) * i); + REQUIRE(is_valid); + REQUIRE(not is_synchronized); } - } - - REQUIRE(is_synchronized); - } - } - SECTION("edge") - { - WeakEdgeArray<size_t> weak_edge_array{connectivity, 4}; - auto edge_number = connectivity.edgeNumber(); + synchronize(weak_node_array); - for (EdgeId i_edge = 0; i_edge < mesh_1d.numberOfEdges(); ++i_edge) { - Array array = weak_edge_array[i_edge]; - const size_t number = edge_number[i_edge]; - for (size_t i = 0; i < array.size(); ++i) { - array[i] = number + (parallel::rank() + 1) * i; - } - } + { // after synchronization + auto node_owner = connectivity.nodeOwner(); - EdgeArray<const size_t> edge_array{weak_edge_array}; + bool is_synchronized = true; + for (NodeId i_node = 0; i_node < mesh_1d->numberOfNodes(); ++i_node) { + Array array = node_array[i_node]; + const size_t number = node_number[i_node]; + const size_t owner = node_owner[i_node]; + for (size_t i = 0; i < array.size(); ++i) { + is_synchronized &= (array[i] == number + (owner + 1) * i); + } + } - REQUIRE(edge_array.connectivity_ptr() == weak_edge_array.connectivity_ptr()); + REQUIRE(is_synchronized); + } + } - { // before synchronization - auto edge_owner = connectivity.edgeOwner(); - auto edge_is_owned = connectivity.edgeIsOwned(); + SECTION("edge") + { + WeakEdgeArray<size_t> weak_edge_array{connectivity, 4}; + auto edge_number = connectivity.edgeNumber(); - bool is_synchronized = (parallel::size() > 1); - bool is_valid = true; - for (EdgeId i_edge = 0; i_edge < mesh_1d.numberOfEdges(); ++i_edge) { - Array array = edge_array[i_edge]; - const size_t number = edge_number[i_edge]; - const size_t owner = edge_owner[i_edge]; - if (edge_is_owned[i_edge]) { - for (size_t i = 0; i < array.size(); ++i) { - is_valid &= (array[i] == number + (owner + 1) * i); - } - } else { + for (EdgeId i_edge = 0; i_edge < mesh_1d->numberOfEdges(); ++i_edge) { + Array array = weak_edge_array[i_edge]; + const size_t number = edge_number[i_edge]; for (size_t i = 0; i < array.size(); ++i) { - is_synchronized &= (array[i] == number + (owner + 1) * i); + array[i] = number + (parallel::rank() + 1) * i; } } - } - - REQUIRE(is_valid); - REQUIRE(not is_synchronized); - } - - synchronize(weak_edge_array); - { // after synchronization - auto edge_owner = connectivity.edgeOwner(); + EdgeArray<const size_t> edge_array{weak_edge_array}; + + REQUIRE(edge_array.connectivity_ptr() == weak_edge_array.connectivity_ptr()); + + { // before synchronization + auto edge_owner = connectivity.edgeOwner(); + auto edge_is_owned = connectivity.edgeIsOwned(); + + bool is_synchronized = (parallel::size() > 1); + bool is_valid = true; + for (EdgeId i_edge = 0; i_edge < mesh_1d->numberOfEdges(); ++i_edge) { + Array array = edge_array[i_edge]; + const size_t number = edge_number[i_edge]; + const size_t owner = edge_owner[i_edge]; + if (edge_is_owned[i_edge]) { + for (size_t i = 0; i < array.size(); ++i) { + is_valid &= (array[i] == number + (owner + 1) * i); + } + } else { + for (size_t i = 0; i < array.size(); ++i) { + is_synchronized &= (array[i] == number + (owner + 1) * i); + } + } + } - bool is_synchronized = true; - for (EdgeId i_edge = 0; i_edge < mesh_1d.numberOfEdges(); ++i_edge) { - Array array = edge_array[i_edge]; - const size_t number = edge_number[i_edge]; - const size_t owner = edge_owner[i_edge]; - for (size_t i = 0; i < array.size(); ++i) { - is_synchronized &= (array[i] == number + (owner + 1) * i); + REQUIRE(is_valid); + REQUIRE(not is_synchronized); } - } - REQUIRE(is_synchronized); - } - } + synchronize(weak_edge_array); - SECTION("face") - { - WeakFaceArray<size_t> weak_face_array{connectivity, 4}; - auto face_number = connectivity.faceNumber(); + { // after synchronization + auto edge_owner = connectivity.edgeOwner(); - for (FaceId i_face = 0; i_face < mesh_1d.numberOfFaces(); ++i_face) { - Array array = weak_face_array[i_face]; - const size_t number = face_number[i_face]; - for (size_t i = 0; i < array.size(); ++i) { - array[i] = number + (parallel::rank() + 1) * i; - } - } - - FaceArray<const size_t> face_array{weak_face_array}; + bool is_synchronized = true; + for (EdgeId i_edge = 0; i_edge < mesh_1d->numberOfEdges(); ++i_edge) { + Array array = edge_array[i_edge]; + const size_t number = edge_number[i_edge]; + const size_t owner = edge_owner[i_edge]; + for (size_t i = 0; i < array.size(); ++i) { + is_synchronized &= (array[i] == number + (owner + 1) * i); + } + } - REQUIRE(face_array.connectivity_ptr() == weak_face_array.connectivity_ptr()); + REQUIRE(is_synchronized); + } + } - { // before synchronization - auto face_owner = connectivity.faceOwner(); - auto face_is_owned = connectivity.faceIsOwned(); + SECTION("face") + { + WeakFaceArray<size_t> weak_face_array{connectivity, 4}; + auto face_number = connectivity.faceNumber(); - bool is_synchronized = (parallel::size() > 1); - bool is_valid = true; - for (FaceId i_face = 0; i_face < mesh_1d.numberOfFaces(); ++i_face) { - Array array = face_array[i_face]; - const size_t number = face_number[i_face]; - const size_t owner = face_owner[i_face]; - if (face_is_owned[i_face]) { - for (size_t i = 0; i < array.size(); ++i) { - is_valid &= (array[i] == number + (owner + 1) * i); - } - } else { + for (FaceId i_face = 0; i_face < mesh_1d->numberOfFaces(); ++i_face) { + Array array = weak_face_array[i_face]; + const size_t number = face_number[i_face]; for (size_t i = 0; i < array.size(); ++i) { - is_synchronized &= (array[i] == number + (owner + 1) * i); + array[i] = number + (parallel::rank() + 1) * i; } } - } - - REQUIRE(is_valid); - REQUIRE(not is_synchronized); - } - synchronize(weak_face_array); - - { // after synchronization - auto face_owner = connectivity.faceOwner(); + FaceArray<const size_t> face_array{weak_face_array}; + + REQUIRE(face_array.connectivity_ptr() == weak_face_array.connectivity_ptr()); + + { // before synchronization + auto face_owner = connectivity.faceOwner(); + auto face_is_owned = connectivity.faceIsOwned(); + + bool is_synchronized = (parallel::size() > 1); + bool is_valid = true; + for (FaceId i_face = 0; i_face < mesh_1d->numberOfFaces(); ++i_face) { + Array array = face_array[i_face]; + const size_t number = face_number[i_face]; + const size_t owner = face_owner[i_face]; + if (face_is_owned[i_face]) { + for (size_t i = 0; i < array.size(); ++i) { + is_valid &= (array[i] == number + (owner + 1) * i); + } + } else { + for (size_t i = 0; i < array.size(); ++i) { + is_synchronized &= (array[i] == number + (owner + 1) * i); + } + } + } - bool is_synchronized = true; - for (FaceId i_face = 0; i_face < mesh_1d.numberOfFaces(); ++i_face) { - Array array = face_array[i_face]; - const size_t number = face_number[i_face]; - const size_t owner = face_owner[i_face]; - for (size_t i = 0; i < array.size(); ++i) { - is_synchronized &= (array[i] == number + (owner + 1) * i); + REQUIRE(is_valid); + REQUIRE(not is_synchronized); } - } - REQUIRE(is_synchronized); - } - } + synchronize(weak_face_array); - SECTION("cell") - { - WeakCellArray<size_t> weak_cell_array{connectivity, 4}; - auto cell_number = connectivity.cellNumber(); + { // after synchronization + auto face_owner = connectivity.faceOwner(); - for (CellId i_cell = 0; i_cell < mesh_1d.numberOfCells(); ++i_cell) { - Array array = weak_cell_array[i_cell]; - const size_t number = cell_number[i_cell]; - for (size_t i = 0; i < array.size(); ++i) { - array[i] = number + (parallel::rank() + 1) * i; - } - } - - CellArray<const size_t> cell_array{weak_cell_array}; + bool is_synchronized = true; + for (FaceId i_face = 0; i_face < mesh_1d->numberOfFaces(); ++i_face) { + Array array = face_array[i_face]; + const size_t number = face_number[i_face]; + const size_t owner = face_owner[i_face]; + for (size_t i = 0; i < array.size(); ++i) { + is_synchronized &= (array[i] == number + (owner + 1) * i); + } + } - REQUIRE(cell_array.connectivity_ptr() == weak_cell_array.connectivity_ptr()); + REQUIRE(is_synchronized); + } + } - { // before synchronization - auto cell_owner = connectivity.cellOwner(); - auto cell_is_owned = connectivity.cellIsOwned(); + SECTION("cell") + { + WeakCellArray<size_t> weak_cell_array{connectivity, 4}; + auto cell_number = connectivity.cellNumber(); - bool is_synchronized = (parallel::size() > 1); - bool is_valid = true; - for (CellId i_cell = 0; i_cell < mesh_1d.numberOfCells(); ++i_cell) { - Array array = cell_array[i_cell]; - const size_t number = cell_number[i_cell]; - const size_t owner = cell_owner[i_cell]; - if (cell_is_owned[i_cell]) { + for (CellId i_cell = 0; i_cell < mesh_1d->numberOfCells(); ++i_cell) { + Array array = weak_cell_array[i_cell]; + const size_t number = cell_number[i_cell]; for (size_t i = 0; i < array.size(); ++i) { - is_valid &= (array[i] == number + (owner + 1) * i); + array[i] = number + (parallel::rank() + 1) * i; } - } else { - for (size_t i = 0; i < array.size(); ++i) { - is_synchronized &= (array[i] == number + (owner + 1) * i); + } + + CellArray<const size_t> cell_array{weak_cell_array}; + + REQUIRE(cell_array.connectivity_ptr() == weak_cell_array.connectivity_ptr()); + + { // before synchronization + auto cell_owner = connectivity.cellOwner(); + auto cell_is_owned = connectivity.cellIsOwned(); + + bool is_synchronized = (parallel::size() > 1); + bool is_valid = true; + for (CellId i_cell = 0; i_cell < mesh_1d->numberOfCells(); ++i_cell) { + Array array = cell_array[i_cell]; + const size_t number = cell_number[i_cell]; + const size_t owner = cell_owner[i_cell]; + if (cell_is_owned[i_cell]) { + for (size_t i = 0; i < array.size(); ++i) { + is_valid &= (array[i] == number + (owner + 1) * i); + } + } else { + for (size_t i = 0; i < array.size(); ++i) { + is_synchronized &= (array[i] == number + (owner + 1) * i); + } + } } + + REQUIRE(is_valid); + REQUIRE(not is_synchronized); } - } - REQUIRE(is_valid); - REQUIRE(not is_synchronized); - } + synchronize(weak_cell_array); - synchronize(weak_cell_array); + { // after synchronization + auto cell_owner = connectivity.cellOwner(); - { // after synchronization - auto cell_owner = connectivity.cellOwner(); + bool is_synchronized = true; + for (CellId i_cell = 0; i_cell < mesh_1d->numberOfCells(); ++i_cell) { + Array array = cell_array[i_cell]; + const size_t number = cell_number[i_cell]; + const size_t owner = cell_owner[i_cell]; + for (size_t i = 0; i < array.size(); ++i) { + is_synchronized &= (array[i] == number + (owner + 1) * i); + } + } - bool is_synchronized = true; - for (CellId i_cell = 0; i_cell < mesh_1d.numberOfCells(); ++i_cell) { - Array array = cell_array[i_cell]; - const size_t number = cell_number[i_cell]; - const size_t owner = cell_owner[i_cell]; - for (size_t i = 0; i < array.size(); ++i) { - is_synchronized &= (array[i] == number + (owner + 1) * i); + REQUIRE(is_synchronized); } } - - REQUIRE(is_synchronized); } } } SECTION("2D") { - const Mesh<Connectivity<2>>& mesh_2d = *MeshDataBaseForTests::get().cartesianMesh2D(); - const Connectivity<2>& connectivity = mesh_2d.connectivity(); - - SECTION("node") - { - WeakNodeArray<size_t> weak_node_array{connectivity, 3}; - auto node_number = connectivity.nodeNumber(); - - for (NodeId i_node = 0; i_node < mesh_2d.numberOfNodes(); ++i_node) { - Array array = weak_node_array[i_node]; - const size_t number = node_number[i_node]; - for (size_t i = 0; i < array.size(); ++i) { - array[i] = number + (parallel::rank() + 1) * i; - } - } + std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - NodeArray<const size_t> node_array{weak_node_array}; + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_2d = named_mesh.mesh(); - REQUIRE(node_array.connectivity_ptr() == weak_node_array.connectivity_ptr()); + const Connectivity<2>& connectivity = mesh_2d->connectivity(); - { // before synchronization - auto node_owner = connectivity.nodeOwner(); - auto node_is_owned = connectivity.nodeIsOwned(); + SECTION("node") + { + WeakNodeArray<size_t> weak_node_array{connectivity, 3}; + auto node_number = connectivity.nodeNumber(); - bool is_synchronized = (parallel::size() > 1); - bool is_valid = true; - for (NodeId i_node = 0; i_node < mesh_2d.numberOfNodes(); ++i_node) { - Array array = node_array[i_node]; - const size_t number = node_number[i_node]; - const size_t owner = node_owner[i_node]; - if (node_is_owned[i_node]) { + for (NodeId i_node = 0; i_node < mesh_2d->numberOfNodes(); ++i_node) { + Array array = weak_node_array[i_node]; + const size_t number = node_number[i_node]; for (size_t i = 0; i < array.size(); ++i) { - is_valid &= (array[i] == number + (owner + 1) * i); - } - } else { - for (size_t i = 0; i < array.size(); ++i) { - is_synchronized &= (array[i] == number + (owner + 1) * i); + array[i] = number + (parallel::rank() + 1) * i; } } - } - - REQUIRE(is_valid); - REQUIRE(not is_synchronized); - } - - synchronize(weak_node_array); - { // after synchronization - auto node_owner = connectivity.nodeOwner(); + NodeArray<const size_t> node_array{weak_node_array}; + + REQUIRE(node_array.connectivity_ptr() == weak_node_array.connectivity_ptr()); + + { // before synchronization + auto node_owner = connectivity.nodeOwner(); + auto node_is_owned = connectivity.nodeIsOwned(); + + bool is_synchronized = (parallel::size() > 1); + bool is_valid = true; + for (NodeId i_node = 0; i_node < mesh_2d->numberOfNodes(); ++i_node) { + Array array = node_array[i_node]; + const size_t number = node_number[i_node]; + const size_t owner = node_owner[i_node]; + if (node_is_owned[i_node]) { + for (size_t i = 0; i < array.size(); ++i) { + is_valid &= (array[i] == number + (owner + 1) * i); + } + } else { + for (size_t i = 0; i < array.size(); ++i) { + is_synchronized &= (array[i] == number + (owner + 1) * i); + } + } + } - bool is_synchronized = true; - for (NodeId i_node = 0; i_node < mesh_2d.numberOfNodes(); ++i_node) { - Array array = node_array[i_node]; - const size_t number = node_number[i_node]; - const size_t owner = node_owner[i_node]; - for (size_t i = 0; i < array.size(); ++i) { - is_synchronized &= (array[i] == number + (owner + 1) * i); + REQUIRE(is_valid); + REQUIRE(not is_synchronized); } - } - REQUIRE(is_synchronized); - } - } + synchronize(weak_node_array); - SECTION("edge") - { - WeakEdgeArray<size_t> weak_edge_array{connectivity, 3}; - auto edge_number = connectivity.edgeNumber(); + { // after synchronization + auto node_owner = connectivity.nodeOwner(); - for (EdgeId i_edge = 0; i_edge < mesh_2d.numberOfEdges(); ++i_edge) { - Array array = weak_edge_array[i_edge]; - const size_t number = edge_number[i_edge]; - for (size_t i = 0; i < array.size(); ++i) { - array[i] = number + (parallel::rank() + 1) * i; - } - } - - EdgeArray<const size_t> edge_array{weak_edge_array}; + bool is_synchronized = true; + for (NodeId i_node = 0; i_node < mesh_2d->numberOfNodes(); ++i_node) { + Array array = node_array[i_node]; + const size_t number = node_number[i_node]; + const size_t owner = node_owner[i_node]; + for (size_t i = 0; i < array.size(); ++i) { + is_synchronized &= (array[i] == number + (owner + 1) * i); + } + } - REQUIRE(edge_array.connectivity_ptr() == weak_edge_array.connectivity_ptr()); + REQUIRE(is_synchronized); + } + } - { // before synchronization - auto edge_owner = connectivity.edgeOwner(); - auto edge_is_owned = connectivity.edgeIsOwned(); + SECTION("edge") + { + WeakEdgeArray<size_t> weak_edge_array{connectivity, 3}; + auto edge_number = connectivity.edgeNumber(); - bool is_synchronized = (parallel::size() > 1); - bool is_valid = true; - for (EdgeId i_edge = 0; i_edge < mesh_2d.numberOfEdges(); ++i_edge) { - Array array = edge_array[i_edge]; - const size_t number = edge_number[i_edge]; - const size_t owner = edge_owner[i_edge]; - if (edge_is_owned[i_edge]) { + for (EdgeId i_edge = 0; i_edge < mesh_2d->numberOfEdges(); ++i_edge) { + Array array = weak_edge_array[i_edge]; + const size_t number = edge_number[i_edge]; for (size_t i = 0; i < array.size(); ++i) { - is_valid &= (array[i] == number + (owner + 1) * i); - } - } else { - for (size_t i = 0; i < array.size(); ++i) { - is_synchronized &= (array[i] == number + (owner + 1) * i); + array[i] = number + (parallel::rank() + 1) * i; } } - } - - REQUIRE(is_valid); - REQUIRE(not is_synchronized); - } - - synchronize(weak_edge_array); - { // after synchronization - auto edge_owner = connectivity.edgeOwner(); + EdgeArray<const size_t> edge_array{weak_edge_array}; + + REQUIRE(edge_array.connectivity_ptr() == weak_edge_array.connectivity_ptr()); + + { // before synchronization + auto edge_owner = connectivity.edgeOwner(); + auto edge_is_owned = connectivity.edgeIsOwned(); + + bool is_synchronized = (parallel::size() > 1); + bool is_valid = true; + for (EdgeId i_edge = 0; i_edge < mesh_2d->numberOfEdges(); ++i_edge) { + Array array = edge_array[i_edge]; + const size_t number = edge_number[i_edge]; + const size_t owner = edge_owner[i_edge]; + if (edge_is_owned[i_edge]) { + for (size_t i = 0; i < array.size(); ++i) { + is_valid &= (array[i] == number + (owner + 1) * i); + } + } else { + for (size_t i = 0; i < array.size(); ++i) { + is_synchronized &= (array[i] == number + (owner + 1) * i); + } + } + } - bool is_synchronized = true; - for (EdgeId i_edge = 0; i_edge < mesh_2d.numberOfEdges(); ++i_edge) { - Array array = edge_array[i_edge]; - const size_t number = edge_number[i_edge]; - const size_t owner = edge_owner[i_edge]; - for (size_t i = 0; i < array.size(); ++i) { - is_synchronized &= (array[i] == number + (owner + 1) * i); + REQUIRE(is_valid); + REQUIRE(not is_synchronized); } - } - - REQUIRE(is_synchronized); - } - } - SECTION("face") - { - WeakFaceArray<size_t> weak_face_array{connectivity, 3}; - auto face_number = connectivity.faceNumber(); + synchronize(weak_edge_array); - for (FaceId i_face = 0; i_face < mesh_2d.numberOfFaces(); ++i_face) { - Array array = weak_face_array[i_face]; - const size_t number = face_number[i_face]; - for (size_t i = 0; i < array.size(); ++i) { - array[i] = number + (parallel::rank() + 1) * i; - } - } + { // after synchronization + auto edge_owner = connectivity.edgeOwner(); - FaceArray<const size_t> face_array{weak_face_array}; + bool is_synchronized = true; + for (EdgeId i_edge = 0; i_edge < mesh_2d->numberOfEdges(); ++i_edge) { + Array array = edge_array[i_edge]; + const size_t number = edge_number[i_edge]; + const size_t owner = edge_owner[i_edge]; + for (size_t i = 0; i < array.size(); ++i) { + is_synchronized &= (array[i] == number + (owner + 1) * i); + } + } - REQUIRE(face_array.connectivity_ptr() == weak_face_array.connectivity_ptr()); + REQUIRE(is_synchronized); + } + } - { // before synchronization - auto face_owner = connectivity.faceOwner(); - auto face_is_owned = connectivity.faceIsOwned(); + SECTION("face") + { + WeakFaceArray<size_t> weak_face_array{connectivity, 3}; + auto face_number = connectivity.faceNumber(); - bool is_synchronized = (parallel::size() > 1); - bool is_valid = true; - for (FaceId i_face = 0; i_face < mesh_2d.numberOfFaces(); ++i_face) { - Array array = face_array[i_face]; - const size_t number = face_number[i_face]; - const size_t owner = face_owner[i_face]; - if (face_is_owned[i_face]) { + for (FaceId i_face = 0; i_face < mesh_2d->numberOfFaces(); ++i_face) { + Array array = weak_face_array[i_face]; + const size_t number = face_number[i_face]; for (size_t i = 0; i < array.size(); ++i) { - is_valid &= (array[i] == number + (owner + 1) * i); - } - } else { - for (size_t i = 0; i < array.size(); ++i) { - is_synchronized &= (array[i] == number + (owner + 1) * i); + array[i] = number + (parallel::rank() + 1) * i; } } - } - - REQUIRE(is_valid); - REQUIRE(not is_synchronized); - } - - synchronize(weak_face_array); - { // after synchronization - auto face_owner = connectivity.faceOwner(); + FaceArray<const size_t> face_array{weak_face_array}; + + REQUIRE(face_array.connectivity_ptr() == weak_face_array.connectivity_ptr()); + + { // before synchronization + auto face_owner = connectivity.faceOwner(); + auto face_is_owned = connectivity.faceIsOwned(); + + bool is_synchronized = (parallel::size() > 1); + bool is_valid = true; + for (FaceId i_face = 0; i_face < mesh_2d->numberOfFaces(); ++i_face) { + Array array = face_array[i_face]; + const size_t number = face_number[i_face]; + const size_t owner = face_owner[i_face]; + if (face_is_owned[i_face]) { + for (size_t i = 0; i < array.size(); ++i) { + is_valid &= (array[i] == number + (owner + 1) * i); + } + } else { + for (size_t i = 0; i < array.size(); ++i) { + is_synchronized &= (array[i] == number + (owner + 1) * i); + } + } + } - bool is_synchronized = true; - for (FaceId i_face = 0; i_face < mesh_2d.numberOfFaces(); ++i_face) { - Array array = face_array[i_face]; - const size_t number = face_number[i_face]; - const size_t owner = face_owner[i_face]; - for (size_t i = 0; i < array.size(); ++i) { - is_synchronized &= (array[i] == number + (owner + 1) * i); + REQUIRE(is_valid); + REQUIRE(not is_synchronized); } - } - REQUIRE(is_synchronized); - } - } + synchronize(weak_face_array); - SECTION("cell") - { - WeakCellArray<size_t> weak_cell_array{connectivity, 3}; - auto cell_number = connectivity.cellNumber(); + { // after synchronization + auto face_owner = connectivity.faceOwner(); - for (CellId i_cell = 0; i_cell < mesh_2d.numberOfCells(); ++i_cell) { - Array array = weak_cell_array[i_cell]; - const size_t number = cell_number[i_cell]; - for (size_t i = 0; i < array.size(); ++i) { - array[i] = number + (parallel::rank() + 1) * i; - } - } - - CellArray<const size_t> cell_array{weak_cell_array}; + bool is_synchronized = true; + for (FaceId i_face = 0; i_face < mesh_2d->numberOfFaces(); ++i_face) { + Array array = face_array[i_face]; + const size_t number = face_number[i_face]; + const size_t owner = face_owner[i_face]; + for (size_t i = 0; i < array.size(); ++i) { + is_synchronized &= (array[i] == number + (owner + 1) * i); + } + } - REQUIRE(cell_array.connectivity_ptr() == weak_cell_array.connectivity_ptr()); + REQUIRE(is_synchronized); + } + } - { // before synchronization - auto cell_owner = connectivity.cellOwner(); - auto cell_is_owned = connectivity.cellIsOwned(); + SECTION("cell") + { + WeakCellArray<size_t> weak_cell_array{connectivity, 3}; + auto cell_number = connectivity.cellNumber(); - bool is_synchronized = (parallel::size() > 1); - bool is_valid = true; - for (CellId i_cell = 0; i_cell < mesh_2d.numberOfCells(); ++i_cell) { - Array array = cell_array[i_cell]; - const size_t number = cell_number[i_cell]; - const size_t owner = cell_owner[i_cell]; - if (cell_is_owned[i_cell]) { + for (CellId i_cell = 0; i_cell < mesh_2d->numberOfCells(); ++i_cell) { + Array array = weak_cell_array[i_cell]; + const size_t number = cell_number[i_cell]; for (size_t i = 0; i < array.size(); ++i) { - is_valid &= (array[i] == number + (owner + 1) * i); + array[i] = number + (parallel::rank() + 1) * i; } - } else { - for (size_t i = 0; i < array.size(); ++i) { - is_synchronized &= (array[i] == number + (owner + 1) * i); + } + + CellArray<const size_t> cell_array{weak_cell_array}; + + REQUIRE(cell_array.connectivity_ptr() == weak_cell_array.connectivity_ptr()); + + { // before synchronization + auto cell_owner = connectivity.cellOwner(); + auto cell_is_owned = connectivity.cellIsOwned(); + + bool is_synchronized = (parallel::size() > 1); + bool is_valid = true; + for (CellId i_cell = 0; i_cell < mesh_2d->numberOfCells(); ++i_cell) { + Array array = cell_array[i_cell]; + const size_t number = cell_number[i_cell]; + const size_t owner = cell_owner[i_cell]; + if (cell_is_owned[i_cell]) { + for (size_t i = 0; i < array.size(); ++i) { + is_valid &= (array[i] == number + (owner + 1) * i); + } + } else { + for (size_t i = 0; i < array.size(); ++i) { + is_synchronized &= (array[i] == number + (owner + 1) * i); + } + } } + + REQUIRE(is_valid); + REQUIRE(not is_synchronized); } - } - REQUIRE(is_valid); - REQUIRE(not is_synchronized); - } + synchronize(weak_cell_array); - synchronize(weak_cell_array); + { // after synchronization + auto cell_owner = connectivity.cellOwner(); - { // after synchronization - auto cell_owner = connectivity.cellOwner(); + bool is_synchronized = true; + for (CellId i_cell = 0; i_cell < mesh_2d->numberOfCells(); ++i_cell) { + Array array = cell_array[i_cell]; + const size_t number = cell_number[i_cell]; + const size_t owner = cell_owner[i_cell]; + for (size_t i = 0; i < array.size(); ++i) { + is_synchronized &= (array[i] == number + (owner + 1) * i); + } + } - bool is_synchronized = true; - for (CellId i_cell = 0; i_cell < mesh_2d.numberOfCells(); ++i_cell) { - Array array = cell_array[i_cell]; - const size_t number = cell_number[i_cell]; - const size_t owner = cell_owner[i_cell]; - for (size_t i = 0; i < array.size(); ++i) { - is_synchronized &= (array[i] == number + (owner + 1) * i); + REQUIRE(is_synchronized); } } - - REQUIRE(is_synchronized); } } } SECTION("3D") { - const Mesh<Connectivity<3>>& mesh_3d = *MeshDataBaseForTests::get().cartesianMesh3D(); - const Connectivity<3>& connectivity = mesh_3d.connectivity(); - - SECTION("node") - { - WeakNodeArray<size_t> weak_node_array{connectivity, 4}; - auto node_number = connectivity.nodeNumber(); - - for (NodeId i_node = 0; i_node < mesh_3d.numberOfNodes(); ++i_node) { - Array array = weak_node_array[i_node]; - const size_t number = node_number[i_node]; - for (size_t i = 0; i < array.size(); ++i) { - array[i] = number + (parallel::rank() + 1) * i; - } - } + std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - NodeArray<const size_t> node_array{weak_node_array}; + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_3d = named_mesh.mesh(); - REQUIRE(node_array.connectivity_ptr() == weak_node_array.connectivity_ptr()); + const Connectivity<3>& connectivity = mesh_3d->connectivity(); - { // before synchronization - auto node_owner = connectivity.nodeOwner(); - auto node_is_owned = connectivity.nodeIsOwned(); + SECTION("node") + { + WeakNodeArray<size_t> weak_node_array{connectivity, 4}; + auto node_number = connectivity.nodeNumber(); - bool is_synchronized = (parallel::size() > 1); - bool is_valid = true; - for (NodeId i_node = 0; i_node < mesh_3d.numberOfNodes(); ++i_node) { - Array array = node_array[i_node]; - const size_t number = node_number[i_node]; - const size_t owner = node_owner[i_node]; - if (node_is_owned[i_node]) { - for (size_t i = 0; i < array.size(); ++i) { - is_valid &= (array[i] == number + (owner + 1) * i); - } - } else { + for (NodeId i_node = 0; i_node < mesh_3d->numberOfNodes(); ++i_node) { + Array array = weak_node_array[i_node]; + const size_t number = node_number[i_node]; for (size_t i = 0; i < array.size(); ++i) { - is_synchronized &= (array[i] == number + (owner + 1) * i); + array[i] = number + (parallel::rank() + 1) * i; } } - } - - REQUIRE(is_valid); - REQUIRE(not is_synchronized); - } - synchronize(weak_node_array); - - { // after synchronization - auto node_owner = connectivity.nodeOwner(); + NodeArray<const size_t> node_array{weak_node_array}; + + REQUIRE(node_array.connectivity_ptr() == weak_node_array.connectivity_ptr()); + + { // before synchronization + auto node_owner = connectivity.nodeOwner(); + auto node_is_owned = connectivity.nodeIsOwned(); + + bool is_synchronized = (parallel::size() > 1); + bool is_valid = true; + for (NodeId i_node = 0; i_node < mesh_3d->numberOfNodes(); ++i_node) { + Array array = node_array[i_node]; + const size_t number = node_number[i_node]; + const size_t owner = node_owner[i_node]; + if (node_is_owned[i_node]) { + for (size_t i = 0; i < array.size(); ++i) { + is_valid &= (array[i] == number + (owner + 1) * i); + } + } else { + for (size_t i = 0; i < array.size(); ++i) { + is_synchronized &= (array[i] == number + (owner + 1) * i); + } + } + } - bool is_synchronized = true; - for (NodeId i_node = 0; i_node < mesh_3d.numberOfNodes(); ++i_node) { - Array array = node_array[i_node]; - const size_t number = node_number[i_node]; - const size_t owner = node_owner[i_node]; - for (size_t i = 0; i < array.size(); ++i) { - is_synchronized &= (array[i] == number + (owner + 1) * i); + REQUIRE(is_valid); + REQUIRE(not is_synchronized); } - } - REQUIRE(is_synchronized); - } - } - - SECTION("edge") - { - WeakEdgeArray<size_t> weak_edge_array{connectivity, 4}; - auto edge_number = connectivity.edgeNumber(); + synchronize(weak_node_array); - for (EdgeId i_edge = 0; i_edge < mesh_3d.numberOfEdges(); ++i_edge) { - Array array = weak_edge_array[i_edge]; - const size_t number = edge_number[i_edge]; - for (size_t i = 0; i < array.size(); ++i) { - array[i] = number + (parallel::rank() + 1) * i; - } - } + { // after synchronization + auto node_owner = connectivity.nodeOwner(); - EdgeArray<const size_t> edge_array{weak_edge_array}; + bool is_synchronized = true; + for (NodeId i_node = 0; i_node < mesh_3d->numberOfNodes(); ++i_node) { + Array array = node_array[i_node]; + const size_t number = node_number[i_node]; + const size_t owner = node_owner[i_node]; + for (size_t i = 0; i < array.size(); ++i) { + is_synchronized &= (array[i] == number + (owner + 1) * i); + } + } - REQUIRE(edge_array.connectivity_ptr() == weak_edge_array.connectivity_ptr()); + REQUIRE(is_synchronized); + } + } - { // before synchronization - auto edge_owner = connectivity.edgeOwner(); - auto edge_is_owned = connectivity.edgeIsOwned(); + SECTION("edge") + { + WeakEdgeArray<size_t> weak_edge_array{connectivity, 4}; + auto edge_number = connectivity.edgeNumber(); - bool is_synchronized = (parallel::size() > 1); - bool is_valid = true; - for (EdgeId i_edge = 0; i_edge < mesh_3d.numberOfEdges(); ++i_edge) { - Array array = edge_array[i_edge]; - const size_t number = edge_number[i_edge]; - const size_t owner = edge_owner[i_edge]; - if (edge_is_owned[i_edge]) { + for (EdgeId i_edge = 0; i_edge < mesh_3d->numberOfEdges(); ++i_edge) { + Array array = weak_edge_array[i_edge]; + const size_t number = edge_number[i_edge]; for (size_t i = 0; i < array.size(); ++i) { - is_valid &= (array[i] == number + (owner + 1) * i); - } - } else { - for (size_t i = 0; i < array.size(); ++i) { - is_synchronized &= (array[i] == number + (owner + 1) * i); + array[i] = number + (parallel::rank() + 1) * i; } } - } - REQUIRE(is_valid); - REQUIRE(not is_synchronized); - } - - synchronize(weak_edge_array); - - { // after synchronization - auto edge_owner = connectivity.edgeOwner(); + EdgeArray<const size_t> edge_array{weak_edge_array}; + + REQUIRE(edge_array.connectivity_ptr() == weak_edge_array.connectivity_ptr()); + + { // before synchronization + auto edge_owner = connectivity.edgeOwner(); + auto edge_is_owned = connectivity.edgeIsOwned(); + + bool is_synchronized = (parallel::size() > 1); + bool is_valid = true; + for (EdgeId i_edge = 0; i_edge < mesh_3d->numberOfEdges(); ++i_edge) { + Array array = edge_array[i_edge]; + const size_t number = edge_number[i_edge]; + const size_t owner = edge_owner[i_edge]; + if (edge_is_owned[i_edge]) { + for (size_t i = 0; i < array.size(); ++i) { + is_valid &= (array[i] == number + (owner + 1) * i); + } + } else { + for (size_t i = 0; i < array.size(); ++i) { + is_synchronized &= (array[i] == number + (owner + 1) * i); + } + } + } - bool is_synchronized = true; - for (EdgeId i_edge = 0; i_edge < mesh_3d.numberOfEdges(); ++i_edge) { - Array array = edge_array[i_edge]; - const size_t number = edge_number[i_edge]; - const size_t owner = edge_owner[i_edge]; - for (size_t i = 0; i < array.size(); ++i) { - is_synchronized &= (array[i] == number + (owner + 1) * i); + REQUIRE(is_valid); + REQUIRE(not is_synchronized); } - } - REQUIRE(is_synchronized); - } - } - - SECTION("face") - { - WeakFaceArray<size_t> weak_face_array{connectivity, 4}; - auto face_number = connectivity.faceNumber(); + synchronize(weak_edge_array); - for (FaceId i_face = 0; i_face < mesh_3d.numberOfFaces(); ++i_face) { - Array array = weak_face_array[i_face]; - const size_t number = face_number[i_face]; - for (size_t i = 0; i < array.size(); ++i) { - array[i] = number + (parallel::rank() + 1) * i; - } - } + { // after synchronization + auto edge_owner = connectivity.edgeOwner(); - FaceArray<const size_t> face_array{weak_face_array}; + bool is_synchronized = true; + for (EdgeId i_edge = 0; i_edge < mesh_3d->numberOfEdges(); ++i_edge) { + Array array = edge_array[i_edge]; + const size_t number = edge_number[i_edge]; + const size_t owner = edge_owner[i_edge]; + for (size_t i = 0; i < array.size(); ++i) { + is_synchronized &= (array[i] == number + (owner + 1) * i); + } + } - REQUIRE(face_array.connectivity_ptr() == weak_face_array.connectivity_ptr()); + REQUIRE(is_synchronized); + } + } - { // before synchronization - auto face_owner = connectivity.faceOwner(); - auto face_is_owned = connectivity.faceIsOwned(); + SECTION("face") + { + WeakFaceArray<size_t> weak_face_array{connectivity, 4}; + auto face_number = connectivity.faceNumber(); - bool is_synchronized = (parallel::size() > 1); - bool is_valid = true; - for (FaceId i_face = 0; i_face < mesh_3d.numberOfFaces(); ++i_face) { - Array array = face_array[i_face]; - const size_t number = face_number[i_face]; - const size_t owner = face_owner[i_face]; - if (face_is_owned[i_face]) { + for (FaceId i_face = 0; i_face < mesh_3d->numberOfFaces(); ++i_face) { + Array array = weak_face_array[i_face]; + const size_t number = face_number[i_face]; for (size_t i = 0; i < array.size(); ++i) { - is_valid &= (array[i] == number + (owner + 1) * i); - } - } else { - for (size_t i = 0; i < array.size(); ++i) { - is_synchronized &= (array[i] == number + (owner + 1) * i); + array[i] = number + (parallel::rank() + 1) * i; } } - } - REQUIRE(is_valid); - REQUIRE(not is_synchronized); - } - - synchronize(weak_face_array); - - { // after synchronization - auto face_owner = connectivity.faceOwner(); + FaceArray<const size_t> face_array{weak_face_array}; + + REQUIRE(face_array.connectivity_ptr() == weak_face_array.connectivity_ptr()); + + { // before synchronization + auto face_owner = connectivity.faceOwner(); + auto face_is_owned = connectivity.faceIsOwned(); + + bool is_synchronized = (parallel::size() > 1); + bool is_valid = true; + for (FaceId i_face = 0; i_face < mesh_3d->numberOfFaces(); ++i_face) { + Array array = face_array[i_face]; + const size_t number = face_number[i_face]; + const size_t owner = face_owner[i_face]; + if (face_is_owned[i_face]) { + for (size_t i = 0; i < array.size(); ++i) { + is_valid &= (array[i] == number + (owner + 1) * i); + } + } else { + for (size_t i = 0; i < array.size(); ++i) { + is_synchronized &= (array[i] == number + (owner + 1) * i); + } + } + } - bool is_synchronized = true; - for (FaceId i_face = 0; i_face < mesh_3d.numberOfFaces(); ++i_face) { - Array array = face_array[i_face]; - const size_t number = face_number[i_face]; - const size_t owner = face_owner[i_face]; - for (size_t i = 0; i < array.size(); ++i) { - is_synchronized &= (array[i] == number + (owner + 1) * i); + REQUIRE(is_valid); + REQUIRE(not is_synchronized); } - } - REQUIRE(is_synchronized); - } - } + synchronize(weak_face_array); - SECTION("cell") - { - WeakCellArray<size_t> weak_cell_array{connectivity, 4}; - auto cell_number = connectivity.cellNumber(); + { // after synchronization + auto face_owner = connectivity.faceOwner(); - for (CellId i_cell = 0; i_cell < mesh_3d.numberOfCells(); ++i_cell) { - Array array = weak_cell_array[i_cell]; - const size_t number = cell_number[i_cell]; - for (size_t i = 0; i < array.size(); ++i) { - array[i] = number + (parallel::rank() + 1) * i; - } - } - - CellArray<const size_t> cell_array{weak_cell_array}; + bool is_synchronized = true; + for (FaceId i_face = 0; i_face < mesh_3d->numberOfFaces(); ++i_face) { + Array array = face_array[i_face]; + const size_t number = face_number[i_face]; + const size_t owner = face_owner[i_face]; + for (size_t i = 0; i < array.size(); ++i) { + is_synchronized &= (array[i] == number + (owner + 1) * i); + } + } - REQUIRE(cell_array.connectivity_ptr() == weak_cell_array.connectivity_ptr()); + REQUIRE(is_synchronized); + } + } - { // before synchronization - auto cell_owner = connectivity.cellOwner(); - auto cell_is_owned = connectivity.cellIsOwned(); + SECTION("cell") + { + WeakCellArray<size_t> weak_cell_array{connectivity, 4}; + auto cell_number = connectivity.cellNumber(); - bool is_synchronized = (parallel::size() > 1); - bool is_valid = true; - for (CellId i_cell = 0; i_cell < mesh_3d.numberOfCells(); ++i_cell) { - Array array = cell_array[i_cell]; - const size_t number = cell_number[i_cell]; - const size_t owner = cell_owner[i_cell]; - if (cell_is_owned[i_cell]) { + for (CellId i_cell = 0; i_cell < mesh_3d->numberOfCells(); ++i_cell) { + Array array = weak_cell_array[i_cell]; + const size_t number = cell_number[i_cell]; for (size_t i = 0; i < array.size(); ++i) { - is_valid &= (array[i] == number + (owner + 1) * i); + array[i] = number + (parallel::rank() + 1) * i; } - } else { - for (size_t i = 0; i < array.size(); ++i) { - is_synchronized &= (array[i] == number + (owner + 1) * i); + } + + CellArray<const size_t> cell_array{weak_cell_array}; + + REQUIRE(cell_array.connectivity_ptr() == weak_cell_array.connectivity_ptr()); + + { // before synchronization + auto cell_owner = connectivity.cellOwner(); + auto cell_is_owned = connectivity.cellIsOwned(); + + bool is_synchronized = (parallel::size() > 1); + bool is_valid = true; + for (CellId i_cell = 0; i_cell < mesh_3d->numberOfCells(); ++i_cell) { + Array array = cell_array[i_cell]; + const size_t number = cell_number[i_cell]; + const size_t owner = cell_owner[i_cell]; + if (cell_is_owned[i_cell]) { + for (size_t i = 0; i < array.size(); ++i) { + is_valid &= (array[i] == number + (owner + 1) * i); + } + } else { + for (size_t i = 0; i < array.size(); ++i) { + is_synchronized &= (array[i] == number + (owner + 1) * i); + } + } } + + REQUIRE(is_valid); + REQUIRE(not is_synchronized); } - } - REQUIRE(is_valid); - REQUIRE(not is_synchronized); - } + synchronize(weak_cell_array); - synchronize(weak_cell_array); + { // after synchronization + auto cell_owner = connectivity.cellOwner(); - { // after synchronization - auto cell_owner = connectivity.cellOwner(); + bool is_synchronized = true; + for (CellId i_cell = 0; i_cell < mesh_3d->numberOfCells(); ++i_cell) { + Array array = cell_array[i_cell]; + const size_t number = cell_number[i_cell]; + const size_t owner = cell_owner[i_cell]; + for (size_t i = 0; i < array.size(); ++i) { + is_synchronized &= (array[i] == number + (owner + 1) * i); + } + } - bool is_synchronized = true; - for (CellId i_cell = 0; i_cell < mesh_3d.numberOfCells(); ++i_cell) { - Array array = cell_array[i_cell]; - const size_t number = cell_number[i_cell]; - const size_t owner = cell_owner[i_cell]; - for (size_t i = 0; i < array.size(); ++i) { - is_synchronized &= (array[i] == number + (owner + 1) * i); + REQUIRE(is_synchronized); } } - - REQUIRE(is_synchronized); } } } diff --git a/tests/test_ItemValue.cpp b/tests/test_ItemValue.cpp index 1c4ab49faf757cc0b2e871f9bf4e0ba33061ece7..84778227aa28e7a23267f9ec355822d257718c89 100644 --- a/tests/test_ItemValue.cpp +++ b/tests/test_ItemValue.cpp @@ -26,119 +26,167 @@ TEST_CASE("ItemValue", "[mesh]") SECTION("1D") { - const Mesh<Connectivity<1>>& mesh_1d = *MeshDataBaseForTests::get().cartesianMesh1D(); - const Connectivity<1>& connectivity = mesh_1d.connectivity(); - - REQUIRE_NOTHROW(NodeValue<int>{connectivity}); - REQUIRE_NOTHROW(EdgeValue<int>{connectivity}); - REQUIRE_NOTHROW(FaceValue<int>{connectivity}); - REQUIRE_NOTHROW(CellValue<int>{connectivity}); - - REQUIRE(NodeValue<int>{connectivity}.isBuilt()); - REQUIRE(EdgeValue<int>{connectivity}.isBuilt()); - REQUIRE(FaceValue<int>{connectivity}.isBuilt()); - REQUIRE(CellValue<int>{connectivity}.isBuilt()); - - NodeValue<int> node_value{connectivity}; - EdgeValue<int> edge_value{connectivity}; - FaceValue<int> face_value{connectivity}; - CellValue<int> cell_value{connectivity}; - - REQUIRE(edge_value.numberOfItems() == node_value.numberOfItems()); - REQUIRE(face_value.numberOfItems() == node_value.numberOfItems()); - REQUIRE(cell_value.numberOfItems() + 1 == node_value.numberOfItems()); + std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); + + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_1d = named_mesh.mesh(); + + const Connectivity<1>& connectivity = mesh_1d->connectivity(); + + REQUIRE_NOTHROW(NodeValue<int>{connectivity}); + REQUIRE_NOTHROW(EdgeValue<int>{connectivity}); + REQUIRE_NOTHROW(FaceValue<int>{connectivity}); + REQUIRE_NOTHROW(CellValue<int>{connectivity}); + + REQUIRE(NodeValue<int>{connectivity}.isBuilt()); + REQUIRE(EdgeValue<int>{connectivity}.isBuilt()); + REQUIRE(FaceValue<int>{connectivity}.isBuilt()); + REQUIRE(CellValue<int>{connectivity}.isBuilt()); + + NodeValue<int> node_value{connectivity}; + EdgeValue<int> edge_value{connectivity}; + FaceValue<int> face_value{connectivity}; + CellValue<int> cell_value{connectivity}; + + REQUIRE(edge_value.numberOfItems() == node_value.numberOfItems()); + REQUIRE(face_value.numberOfItems() == node_value.numberOfItems()); + REQUIRE(cell_value.numberOfItems() + 1 == node_value.numberOfItems()); + } + } } SECTION("2D") { - const Mesh<Connectivity<2>>& mesh_2d = *MeshDataBaseForTests::get().cartesianMesh2D(); - const Connectivity<2>& connectivity = mesh_2d.connectivity(); + std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); + + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_2d = named_mesh.mesh(); - REQUIRE_NOTHROW(NodeValue<int>{connectivity}); - REQUIRE_NOTHROW(EdgeValue<int>{connectivity}); - REQUIRE_NOTHROW(FaceValue<int>{connectivity}); - REQUIRE_NOTHROW(CellValue<int>{connectivity}); + const Connectivity<2>& connectivity = mesh_2d->connectivity(); - REQUIRE(NodeValue<int>{connectivity}.isBuilt()); - REQUIRE(EdgeValue<int>{connectivity}.isBuilt()); - REQUIRE(FaceValue<int>{connectivity}.isBuilt()); - REQUIRE(CellValue<int>{connectivity}.isBuilt()); + REQUIRE_NOTHROW(NodeValue<int>{connectivity}); + REQUIRE_NOTHROW(EdgeValue<int>{connectivity}); + REQUIRE_NOTHROW(FaceValue<int>{connectivity}); + REQUIRE_NOTHROW(CellValue<int>{connectivity}); - EdgeValue<int> edge_value{connectivity}; - FaceValue<int> face_value{connectivity}; + REQUIRE(NodeValue<int>{connectivity}.isBuilt()); + REQUIRE(EdgeValue<int>{connectivity}.isBuilt()); + REQUIRE(FaceValue<int>{connectivity}.isBuilt()); + REQUIRE(CellValue<int>{connectivity}.isBuilt()); - REQUIRE(edge_value.numberOfItems() == face_value.numberOfItems()); + EdgeValue<int> edge_value{connectivity}; + FaceValue<int> face_value{connectivity}; + + REQUIRE(edge_value.numberOfItems() == face_value.numberOfItems()); + } + } } SECTION("3D") { - const Mesh<Connectivity<3>>& mesh_3d = *MeshDataBaseForTests::get().cartesianMesh3D(); - const Connectivity<3>& connectivity = mesh_3d.connectivity(); - - REQUIRE_NOTHROW(NodeValue<int>{connectivity}); - REQUIRE_NOTHROW(EdgeValue<int>{connectivity}); - REQUIRE_NOTHROW(FaceValue<int>{connectivity}); - REQUIRE_NOTHROW(CellValue<int>{connectivity}); - - REQUIRE(NodeValue<int>{connectivity}.isBuilt()); - REQUIRE(EdgeValue<int>{connectivity}.isBuilt()); - REQUIRE(FaceValue<int>{connectivity}.isBuilt()); - REQUIRE(CellValue<int>{connectivity}.isBuilt()); + std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); + + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_3d = named_mesh.mesh(); + + const Connectivity<3>& connectivity = mesh_3d->connectivity(); + + REQUIRE_NOTHROW(NodeValue<int>{connectivity}); + REQUIRE_NOTHROW(EdgeValue<int>{connectivity}); + REQUIRE_NOTHROW(FaceValue<int>{connectivity}); + REQUIRE_NOTHROW(CellValue<int>{connectivity}); + + REQUIRE(NodeValue<int>{connectivity}.isBuilt()); + REQUIRE(EdgeValue<int>{connectivity}.isBuilt()); + REQUIRE(FaceValue<int>{connectivity}.isBuilt()); + REQUIRE(CellValue<int>{connectivity}.isBuilt()); + } + } } SECTION("set values from array") { - const Mesh<Connectivity<3>>& mesh_3d = *MeshDataBaseForTests::get().cartesianMesh3D(); - const Connectivity<3>& connectivity = mesh_3d.connectivity(); + std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - CellValue<size_t> cell_value{connectivity}; + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_3d = named_mesh.mesh(); - Array<size_t> values{cell_value.numberOfItems()}; - for (size_t i = 0; i < values.size(); ++i) { - values[i] = i; - } + const Connectivity<3>& connectivity = mesh_3d->connectivity(); - cell_value = values; + CellValue<size_t> cell_value{connectivity}; - for (CellId i_cell = 0; i_cell < mesh_3d.numberOfCells(); ++i_cell) { - REQUIRE(cell_value[i_cell] == i_cell); + Array<size_t> values{cell_value.numberOfItems()}; + for (size_t i = 0; i < values.size(); ++i) { + values[i] = i; + } + + cell_value = values; + + for (CellId i_cell = 0; i_cell < mesh_3d->numberOfCells(); ++i_cell) { + REQUIRE(cell_value[i_cell] == i_cell); + } + } } } SECTION("copy") { - const Mesh<Connectivity<3>>& mesh_3d = *MeshDataBaseForTests::get().cartesianMesh3D(); - const Connectivity<3>& connectivity = mesh_3d.connectivity(); + std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - CellValue<int> cell_value{connectivity}; - cell_value.fill(parallel::rank()); + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_3d = named_mesh.mesh(); - CellValue<const int> const_cell_value; - const_cell_value = copy(cell_value); + const Connectivity<3>& connectivity = mesh_3d->connectivity(); - cell_value.fill(0); + CellValue<int> cell_value{connectivity}; + cell_value.fill(parallel::rank()); - for (CellId i_cell = 0; i_cell < mesh_3d.numberOfCells(); ++i_cell) { - REQUIRE(cell_value[i_cell] == 0); - } + CellValue<const int> const_cell_value; + const_cell_value = copy(cell_value); - for (CellId i_cell = 0; i_cell < mesh_3d.numberOfCells(); ++i_cell) { - REQUIRE(const_cell_value[i_cell] == static_cast<std::int64_t>(parallel::rank())); + cell_value.fill(0); + + for (CellId i_cell = 0; i_cell < mesh_3d->numberOfCells(); ++i_cell) { + REQUIRE(cell_value[i_cell] == 0); + } + + for (CellId i_cell = 0; i_cell < mesh_3d->numberOfCells(); ++i_cell) { + REQUIRE(const_cell_value[i_cell] == static_cast<std::int64_t>(parallel::rank())); + } + } } } SECTION("WeakItemValue") { - const Mesh<Connectivity<2>>& mesh_2d = *MeshDataBaseForTests::get().cartesianMesh2D(); - const Connectivity<2>& connectivity = mesh_2d.connectivity(); + std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); + + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_2d = named_mesh.mesh(); + + const Connectivity<2>& connectivity = mesh_2d->connectivity(); - WeakFaceValue<int> weak_face_value{connectivity}; + WeakFaceValue<int> weak_face_value{connectivity}; - weak_face_value.fill(parallel::rank()); + weak_face_value.fill(parallel::rank()); - FaceValue<const int> face_value{weak_face_value}; + FaceValue<const int> face_value{weak_face_value}; - REQUIRE(face_value.connectivity_ptr() == weak_face_value.connectivity_ptr()); + REQUIRE(face_value.connectivity_ptr() == weak_face_value.connectivity_ptr()); + } + } } #ifndef NDEBUG @@ -161,48 +209,80 @@ TEST_CASE("ItemValue", "[mesh]") SECTION("checking for bounds violation") { - const Mesh<Connectivity<3>>& mesh_3d = *MeshDataBaseForTests::get().cartesianMesh3D(); - const Connectivity<3>& connectivity = mesh_3d.connectivity(); + std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); + + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_3d = named_mesh.mesh(); + + const Connectivity<3>& connectivity = mesh_3d->connectivity(); - CellValue<int> cell_value{connectivity}; - CellId invalid_cell_id = connectivity.numberOfCells(); - REQUIRE_THROWS_AS(cell_value[invalid_cell_id], AssertError); + CellValue<int> cell_value{connectivity}; + CellId invalid_cell_id = connectivity.numberOfCells(); + REQUIRE_THROWS_AS(cell_value[invalid_cell_id], AssertError); - FaceValue<int> face_value{connectivity}; - FaceId invalid_face_id = connectivity.numberOfFaces(); - REQUIRE_THROWS_AS(face_value[invalid_face_id], AssertError); + FaceValue<int> face_value{connectivity}; + FaceId invalid_face_id = connectivity.numberOfFaces(); + REQUIRE_THROWS_AS(face_value[invalid_face_id], AssertError); - EdgeValue<int> edge_value{connectivity}; - EdgeId invalid_edge_id = connectivity.numberOfEdges(); - REQUIRE_THROWS_AS(edge_value[invalid_edge_id], AssertError); + EdgeValue<int> edge_value{connectivity}; + EdgeId invalid_edge_id = connectivity.numberOfEdges(); + REQUIRE_THROWS_AS(edge_value[invalid_edge_id], AssertError); - NodeValue<int> node_value{connectivity}; - NodeId invalid_node_id = connectivity.numberOfNodes(); - REQUIRE_THROWS_AS(node_value[invalid_node_id], AssertError); + NodeValue<int> node_value{connectivity}; + NodeId invalid_node_id = connectivity.numberOfNodes(); + REQUIRE_THROWS_AS(node_value[invalid_node_id], AssertError); + } + } } SECTION("set values from invalid array size") { - const Mesh<Connectivity<3>>& mesh_3d = *MeshDataBaseForTests::get().cartesianMesh3D(); - const Connectivity<3>& connectivity = mesh_3d.connectivity(); + std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - CellValue<size_t> cell_value{connectivity}; + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_3d = named_mesh.mesh(); - Array<size_t> values{3 + cell_value.numberOfItems()}; - REQUIRE_THROWS_AS(cell_value = values, AssertError); + const Connectivity<3>& connectivity = mesh_3d->connectivity(); + + CellValue<size_t> cell_value{connectivity}; + + Array<size_t> values{3 + cell_value.numberOfItems()}; + REQUIRE_THROWS_AS(cell_value = values, AssertError); + } + } } SECTION("invalid copy_to") { - const Mesh<Connectivity<2>>& mesh_2d = *MeshDataBaseForTests::get().cartesianMesh2D(); - const Connectivity<2>& connectivity_2d = mesh_2d.connectivity(); + std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); + + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_2d = named_mesh.mesh(); + + const Connectivity<2>& connectivity_2d = mesh_2d->connectivity(); + + std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); + + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_3d = named_mesh.mesh(); - const Mesh<Connectivity<3>>& mesh_3d = *MeshDataBaseForTests::get().cartesianMesh3D(); - const Connectivity<3>& connectivity_3d = mesh_3d.connectivity(); + const Connectivity<3>& connectivity_3d = mesh_3d->connectivity(); - CellValue<int> cell_2d_value{connectivity_2d}; - CellValue<int> cell_3d_value{connectivity_3d}; - REQUIRE_THROWS_AS(copy_to(cell_2d_value, cell_3d_value), AssertError); + CellValue<int> cell_2d_value{connectivity_2d}; + CellValue<int> cell_3d_value{connectivity_3d}; + REQUIRE_THROWS_AS(copy_to(cell_2d_value, cell_3d_value), AssertError); + } + } + } + } } } #endif // NDEBUG diff --git a/tests/test_ItemValueUtils.cpp b/tests/test_ItemValueUtils.cpp index b77dfecd58fe2aa2ee2addcc483f631f3e3ec62f..bee143e751de72affa1134998d8561a997bc7f12 100644 --- a/tests/test_ItemValueUtils.cpp +++ b/tests/test_ItemValueUtils.cpp @@ -17,38 +17,46 @@ TEST_CASE("ItemValueUtils", "[mesh]") { SECTION("Synchronize") { - const Mesh<Connectivity<2>>& mesh_2d = *MeshDataBaseForTests::get().cartesianMesh2D(); - const Connectivity<2>& connectivity = mesh_2d.connectivity(); + std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - WeakFaceValue<int> weak_face_value{connectivity}; + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_2d = named_mesh.mesh(); - weak_face_value.fill(parallel::rank()); + const Connectivity<2>& connectivity = mesh_2d->connectivity(); - FaceValue<const int> face_value{weak_face_value}; + WeakFaceValue<int> weak_face_value{connectivity}; - REQUIRE(face_value.connectivity_ptr() == weak_face_value.connectivity_ptr()); + weak_face_value.fill(parallel::rank()); - { // before synchronization - auto face_owner = connectivity.faceOwner(); - auto face_is_owned = connectivity.faceIsOwned(); + FaceValue<const int> face_value{weak_face_value}; - for (FaceId i_face = 0; i_face < mesh_2d.numberOfFaces(); ++i_face) { - if (face_is_owned[i_face]) { - REQUIRE(face_owner[i_face] == face_value[i_face]); - } else { - REQUIRE(face_owner[i_face] != face_value[i_face]); + REQUIRE(face_value.connectivity_ptr() == weak_face_value.connectivity_ptr()); + + { // before synchronization + auto face_owner = connectivity.faceOwner(); + auto face_is_owned = connectivity.faceIsOwned(); + + for (FaceId i_face = 0; i_face < mesh_2d->numberOfFaces(); ++i_face) { + if (face_is_owned[i_face]) { + REQUIRE(face_owner[i_face] == face_value[i_face]); + } else { + REQUIRE(face_owner[i_face] != face_value[i_face]); + } + } } - } - } - synchronize(weak_face_value); + synchronize(weak_face_value); - { // after synchronization - auto face_owner = connectivity.faceOwner(); - auto face_is_owned = connectivity.faceIsOwned(); + { // after synchronization + auto face_owner = connectivity.faceOwner(); + auto face_is_owned = connectivity.faceIsOwned(); - for (FaceId i_face = 0; i_face < mesh_2d.numberOfFaces(); ++i_face) { - REQUIRE(face_owner[i_face] == face_value[i_face]); + for (FaceId i_face = 0; i_face < mesh_2d->numberOfFaces(); ++i_face) { + REQUIRE(face_owner[i_face] == face_value[i_face]); + } + } } } } @@ -57,59 +65,83 @@ TEST_CASE("ItemValueUtils", "[mesh]") { SECTION("1D") { - const Mesh<Connectivity<1>>& mesh_1d = *MeshDataBaseForTests::get().cartesianMesh1D(); - const Connectivity<1>& connectivity = mesh_1d.connectivity(); + std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - CellValue<int> cell_value{connectivity}; - cell_value.fill(-1); + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_1d = named_mesh.mesh(); - auto cell_is_owned = connectivity.cellIsOwned(); - parallel_for( - mesh_1d.numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - if (cell_is_owned[cell_id]) { - cell_value[cell_id] = 10 + parallel::rank(); - } - }); + const Connectivity<1>& connectivity = mesh_1d->connectivity(); + + CellValue<int> cell_value{connectivity}; + cell_value.fill(-1); + + auto cell_is_owned = connectivity.cellIsOwned(); + parallel_for( + mesh_1d->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + if (cell_is_owned[cell_id]) { + cell_value[cell_id] = 10 + parallel::rank(); + } + }); - REQUIRE(min(cell_value) == 10); + REQUIRE(min(cell_value) == 10); + } + } } SECTION("2D") { - const Mesh<Connectivity<2>>& mesh_2d = *MeshDataBaseForTests::get().cartesianMesh2D(); - const Connectivity<2>& connectivity = mesh_2d.connectivity(); + std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - CellValue<int> cell_value{connectivity}; - cell_value.fill(-1); + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_2d = named_mesh.mesh(); - auto cell_is_owned = connectivity.cellIsOwned(); - parallel_for( - mesh_2d.numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - if (cell_is_owned[cell_id]) { - cell_value[cell_id] = 10 + parallel::rank(); - } - }); + const Connectivity<2>& connectivity = mesh_2d->connectivity(); - REQUIRE(min(cell_value) == 10); + CellValue<int> cell_value{connectivity}; + cell_value.fill(-1); + + auto cell_is_owned = connectivity.cellIsOwned(); + parallel_for( + mesh_2d->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + if (cell_is_owned[cell_id]) { + cell_value[cell_id] = 10 + parallel::rank(); + } + }); + + REQUIRE(min(cell_value) == 10); + } + } } SECTION("3D") { - const Mesh<Connectivity<3>>& mesh_3d = *MeshDataBaseForTests::get().cartesianMesh3D(); - const Connectivity<3>& connectivity = mesh_3d.connectivity(); + std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - CellValue<int> cell_value{connectivity}; - cell_value.fill(-1); + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_3d = named_mesh.mesh(); - auto cell_is_owned = connectivity.cellIsOwned(); - parallel_for( - mesh_3d.numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - if (cell_is_owned[cell_id]) { - cell_value[cell_id] = 10 + parallel::rank(); - } - }); + const Connectivity<3>& connectivity = mesh_3d->connectivity(); + + CellValue<int> cell_value{connectivity}; + cell_value.fill(-1); + + auto cell_is_owned = connectivity.cellIsOwned(); + parallel_for( + mesh_3d->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + if (cell_is_owned[cell_id]) { + cell_value[cell_id] = 10 + parallel::rank(); + } + }); - REQUIRE(min(cell_value) == 10); + REQUIRE(min(cell_value) == 10); + } + } } } @@ -117,59 +149,83 @@ TEST_CASE("ItemValueUtils", "[mesh]") { SECTION("1D") { - const Mesh<Connectivity<1>>& mesh_1d = *MeshDataBaseForTests::get().cartesianMesh1D(); - const Connectivity<1>& connectivity = mesh_1d.connectivity(); + std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - CellValue<size_t> cell_value{connectivity}; - cell_value.fill(std::numeric_limits<size_t>::max()); + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_1d = named_mesh.mesh(); - auto cell_is_owned = connectivity.cellIsOwned(); - parallel_for( - mesh_1d.numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - if (cell_is_owned[cell_id]) { - cell_value[cell_id] = parallel::rank() + 1; - } - }); + const Connectivity<1>& connectivity = mesh_1d->connectivity(); - REQUIRE(max(cell_value) == parallel::size()); + CellValue<size_t> cell_value{connectivity}; + cell_value.fill(std::numeric_limits<size_t>::max()); + + auto cell_is_owned = connectivity.cellIsOwned(); + parallel_for( + mesh_1d->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + if (cell_is_owned[cell_id]) { + cell_value[cell_id] = parallel::rank() + 1; + } + }); + + REQUIRE(max(cell_value) == parallel::size()); + } + } } SECTION("2D") { - const Mesh<Connectivity<2>>& mesh_2d = *MeshDataBaseForTests::get().cartesianMesh2D(); - const Connectivity<2>& connectivity = mesh_2d.connectivity(); + std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - CellValue<size_t> cell_value{connectivity}; - cell_value.fill(std::numeric_limits<size_t>::max()); + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_2d = named_mesh.mesh(); - auto cell_is_owned = connectivity.cellIsOwned(); - parallel_for( - mesh_2d.numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - if (cell_is_owned[cell_id]) { - cell_value[cell_id] = parallel::rank() + 1; - } - }); + const Connectivity<2>& connectivity = mesh_2d->connectivity(); + + CellValue<size_t> cell_value{connectivity}; + cell_value.fill(std::numeric_limits<size_t>::max()); + + auto cell_is_owned = connectivity.cellIsOwned(); + parallel_for( + mesh_2d->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + if (cell_is_owned[cell_id]) { + cell_value[cell_id] = parallel::rank() + 1; + } + }); - REQUIRE(max(cell_value) == parallel::size()); + REQUIRE(max(cell_value) == parallel::size()); + } + } } SECTION("3D") { - const Mesh<Connectivity<3>>& mesh_3d = *MeshDataBaseForTests::get().cartesianMesh3D(); - const Connectivity<3>& connectivity = mesh_3d.connectivity(); + std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - CellValue<size_t> cell_value{connectivity}; - cell_value.fill(std::numeric_limits<size_t>::max()); + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_3d = named_mesh.mesh(); - auto cell_is_owned = connectivity.cellIsOwned(); - parallel_for( - mesh_3d.numberOfCells(), PUGS_LAMBDA(CellId cell_id) { - if (cell_is_owned[cell_id]) { - cell_value[cell_id] = parallel::rank() + 1; - } - }); + const Connectivity<3>& connectivity = mesh_3d->connectivity(); - REQUIRE(max(cell_value) == parallel::size()); + CellValue<size_t> cell_value{connectivity}; + cell_value.fill(std::numeric_limits<size_t>::max()); + + auto cell_is_owned = connectivity.cellIsOwned(); + parallel_for( + mesh_3d->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + if (cell_is_owned[cell_id]) { + cell_value[cell_id] = parallel::rank() + 1; + } + }); + + REQUIRE(max(cell_value) == parallel::size()); + } + } } } @@ -177,65 +233,89 @@ TEST_CASE("ItemValueUtils", "[mesh]") { SECTION("1D") { - const Mesh<Connectivity<1>>& mesh_1d = *MeshDataBaseForTests::get().cartesianMesh1D(); - const Connectivity<1>& connectivity = mesh_1d.connectivity(); + std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - CellValue<size_t> cell_value{connectivity}; - cell_value.fill(5); + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_1d = named_mesh.mesh(); - auto cell_is_owned = connectivity.cellIsOwned(); + const Connectivity<1>& connectivity = mesh_1d->connectivity(); - const size_t global_number_of_cells = [&] { - size_t number_of_cells = 0; - for (CellId cell_id = 0; cell_id < cell_is_owned.numberOfItems(); ++cell_id) { - number_of_cells += cell_is_owned[cell_id]; - } - return parallel::allReduceSum(number_of_cells); - }(); + CellValue<size_t> cell_value{connectivity}; + cell_value.fill(5); + + auto cell_is_owned = connectivity.cellIsOwned(); - REQUIRE(sum(cell_value) == 5 * global_number_of_cells); + const size_t global_number_of_cells = [&] { + size_t number_of_cells = 0; + for (CellId cell_id = 0; cell_id < cell_is_owned.numberOfItems(); ++cell_id) { + number_of_cells += cell_is_owned[cell_id]; + } + return parallel::allReduceSum(number_of_cells); + }(); + + REQUIRE(sum(cell_value) == 5 * global_number_of_cells); + } + } } SECTION("2D") { - const Mesh<Connectivity<2>>& mesh_2d = *MeshDataBaseForTests::get().cartesianMesh2D(); - const Connectivity<2>& connectivity = mesh_2d.connectivity(); + std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - FaceValue<size_t> face_value{connectivity}; - face_value.fill(2); + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_2d = named_mesh.mesh(); - auto face_is_owned = connectivity.faceIsOwned(); + const Connectivity<2>& connectivity = mesh_2d->connectivity(); - const size_t global_number_of_faces = [&] { - size_t number_of_faces = 0; - for (FaceId face_id = 0; face_id < face_is_owned.numberOfItems(); ++face_id) { - number_of_faces += face_is_owned[face_id]; - } - return parallel::allReduceSum(number_of_faces); - }(); + FaceValue<size_t> face_value{connectivity}; + face_value.fill(2); - REQUIRE(sum(face_value) == 2 * global_number_of_faces); + auto face_is_owned = connectivity.faceIsOwned(); + + const size_t global_number_of_faces = [&] { + size_t number_of_faces = 0; + for (FaceId face_id = 0; face_id < face_is_owned.numberOfItems(); ++face_id) { + number_of_faces += face_is_owned[face_id]; + } + return parallel::allReduceSum(number_of_faces); + }(); + + REQUIRE(sum(face_value) == 2 * global_number_of_faces); + } + } } SECTION("3D") { - const Mesh<Connectivity<3>>& mesh_3d = *MeshDataBaseForTests::get().cartesianMesh3D(); - const Connectivity<3>& connectivity = mesh_3d.connectivity(); + std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - NodeValue<size_t> node_value{connectivity}; - node_value.fill(3); + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_3d = named_mesh.mesh(); - auto node_is_owned = connectivity.nodeIsOwned(); + const Connectivity<3>& connectivity = mesh_3d->connectivity(); - const size_t global_number_of_nodes = [&] { - size_t number_of_nodes = 0; - for (NodeId node_id = 0; node_id < node_is_owned.numberOfItems(); ++node_id) { - number_of_nodes += node_is_owned[node_id]; - } - return parallel::allReduceSum(number_of_nodes); - }(); + NodeValue<size_t> node_value{connectivity}; + node_value.fill(3); + + auto node_is_owned = connectivity.nodeIsOwned(); - REQUIRE(sum(node_value) == 3 * global_number_of_nodes); + const size_t global_number_of_nodes = [&] { + size_t number_of_nodes = 0; + for (NodeId node_id = 0; node_id < node_is_owned.numberOfItems(); ++node_id) { + number_of_nodes += node_is_owned[node_id]; + } + return parallel::allReduceSum(number_of_nodes); + }(); + + REQUIRE(sum(node_value) == 3 * global_number_of_nodes); + } + } } } } diff --git a/tests/test_LineTransformation.cpp b/tests/test_LineTransformation.cpp new file mode 100644 index 0000000000000000000000000000000000000000..908d2d693973d13d48288cda7f7d021ee187c7a7 --- /dev/null +++ b/tests/test_LineTransformation.cpp @@ -0,0 +1,118 @@ +#include <catch2/catch_approx.hpp> +#include <catch2/catch_test_macros.hpp> + +#include <analysis/GaussQuadratureDescriptor.hpp> +#include <analysis/QuadratureManager.hpp> +#include <geometry/LineTransformation.hpp> + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("LineTransformation", "[geometry]") +{ + SECTION("1D") + { + using R1 = TinyVector<1>; + + const R1 a = 0.3; + const R1 b = 2.7; + + const LineTransformation<1> t(a, b); + + REQUIRE(t(-1)[0] == Catch::Approx(0.3)); + REQUIRE(t(0)[0] == Catch::Approx(1.5)); + REQUIRE(t(1)[0] == Catch::Approx(2.7)); + + REQUIRE(t.jacobianDeterminant() == Catch::Approx(1.2)); + + auto p = [](const R1& X) { + const double x = X[0]; + return 2 * x * x + 3 * x + 2; + }; + + QuadratureFormula<1> qf = QuadratureManager::instance().getLineFormula(GaussQuadratureDescriptor(2)); + + double sum = 0; + for (size_t i = 0; i < qf.numberOfPoints(); ++i) { + sum += qf.weight(i) * t.jacobianDeterminant() * p(t(qf.point(i))); + } + + auto P = [](const R1& X) { + const double x = X[0]; + return 2. / 3 * x * x * x + 3. / 2 * x * x + 2 * x; + }; + + REQUIRE(sum == Catch::Approx(P(b) - P(a))); + } + + SECTION("2D") + { + using R2 = TinyVector<2>; + + const R2 a = {0.3, 1.2}; + const R2 b = {2.7, 0.7}; + + const LineTransformation<2> t(a, b); + + REQUIRE(t(-1)[0] == Catch::Approx(0.3)); + REQUIRE(t(-1)[1] == Catch::Approx(1.2)); + REQUIRE(t(0)[0] == Catch::Approx(1.5)); + REQUIRE(t(0)[1] == Catch::Approx(0.95)); + REQUIRE(t(1)[0] == Catch::Approx(2.7)); + REQUIRE(t(1)[1] == Catch::Approx(0.7)); + + REQUIRE(t.velocityNorm() == Catch::Approx(l2Norm(0.5 * (b - a)))); + + auto p = [](const R2& X) { + const double x = X[0]; + const double y = X[1]; + return 2 * x * x + 3 * x - 3 * y * y + y + 2; + }; + + QuadratureFormula<1> qf = QuadratureManager::instance().getLineFormula(GaussQuadratureDescriptor(2)); + + double sum = 0; + for (size_t i = 0; i < qf.numberOfPoints(); ++i) { + sum += qf.weight(i) * t.velocityNorm() * p(t(qf.point(i))); + } + + REQUIRE(sum == Catch::Approx(24.8585155630822)); + } + + SECTION("3D") + { + using R3 = TinyVector<3>; + + const R3 a = {0.3, 1.2, -1}; + const R3 b = {2.7, 0.7, 0.3}; + + const LineTransformation<3> t(a, b); + + REQUIRE(t(-1)[0] == Catch::Approx(0.3)); + REQUIRE(t(-1)[1] == Catch::Approx(1.2)); + REQUIRE(t(-1)[2] == Catch::Approx(-1.)); + REQUIRE(t(0)[0] == Catch::Approx(1.5)); + REQUIRE(t(0)[1] == Catch::Approx(0.95)); + REQUIRE(t(0)[2] == Catch::Approx(-0.35)); + REQUIRE(t(1)[0] == Catch::Approx(2.7)); + REQUIRE(t(1)[1] == Catch::Approx(0.7)); + REQUIRE(t(1)[2] == Catch::Approx(0.3)); + + REQUIRE(t.velocityNorm() == Catch::Approx(l2Norm(0.5 * (b - a)))); + + auto p = [](const R3& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return 2 * x * x + 3 * x - 3 * y * y + y + 2 * z * z - 0.5 * z + 2; + }; + + QuadratureFormula<1> qf = QuadratureManager::instance().getLineFormula(GaussQuadratureDescriptor(2)); + + double sum = 0; + for (size_t i = 0; i < qf.numberOfPoints(); ++i) { + sum += qf.weight(i) * t.velocityNorm() * p(t(qf.point(i))); + } + + REQUIRE(sum == Catch::Approx(30.08440406681767)); + } +} diff --git a/tests/test_OFStream.cpp b/tests/test_OFStream.cpp index 5ca9c38fd4b8f01f6ed28a263d9199905481edf5..edcee297572862e12d62a8a5032757ea84b364e2 100644 --- a/tests/test_OFStream.cpp +++ b/tests/test_OFStream.cpp @@ -12,7 +12,7 @@ TEST_CASE("OFStream", "[language]") { SECTION("ofstream") { - const std::string basename = std::filesystem::temp_directory_path().append("ofstream_"); + const std::string basename = std::filesystem::path{PUGS_BINARY_DIR}.append("tests").append("ofstream_"); const std::string filename = basename + std::to_string(parallel::rank()); // Ensures that the file is closed after this line diff --git a/tests/test_PrismGaussQuadrature.cpp b/tests/test_PrismGaussQuadrature.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ceff287e5ac5c823c9f427ba6801babfeaa47481 --- /dev/null +++ b/tests/test_PrismGaussQuadrature.cpp @@ -0,0 +1,686 @@ +#include <catch2/catch_approx.hpp> +#include <catch2/catch_test_macros.hpp> +#include <catch2/matchers/catch_matchers_all.hpp> + +#include <analysis/GaussQuadratureDescriptor.hpp> +#include <analysis/PrismGaussQuadrature.hpp> +#include <analysis/QuadratureManager.hpp> +#include <geometry/TetrahedronTransformation.hpp> +#include <utils/Exceptions.hpp> + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("PrismGaussQuadrature", "[analysis]") +{ + auto integrate = [](auto f, auto quadrature_formula) { + auto point_list = quadrature_formula.pointList(); + auto weight_list = quadrature_formula.weightList(); + + auto value = weight_list[0] * f(point_list[0]); + for (size_t i = 1; i < weight_list.size(); ++i) { + value += weight_list[i] * f(point_list[i]); + } + + return value; + }; + + auto integrate_on_prism = [](auto f, auto quadrature_formula, const std::array<TinyVector<3>, 4>& tetrahedron) { + const auto& A = tetrahedron[0]; + const auto& B = tetrahedron[1]; + const auto& C = tetrahedron[2]; + const auto& D = tetrahedron[3]; + + TinyMatrix<3> J; + for (size_t i = 0; i < 3; ++i) { + J(i, 0) = B[i] - A[i]; + J(i, 1) = C[i] - A[i]; + J(i, 2) = 0.5 * (D[i] - A[i]); + } + TinyVector s = 0.5 * (A + D); + + auto point_list = quadrature_formula.pointList(); + auto weight_list = quadrature_formula.weightList(); + auto value = weight_list[0] * f(J * (point_list[0]) + s); + for (size_t i = 1; i < weight_list.size(); ++i) { + value += weight_list[i] * f(J * (point_list[i]) + s); + } + + return det(J) * value; + }; + + auto get_order = [&integrate, &integrate_on_prism](auto f, auto quadrature_formula, const double exact_value) { + using R3 = TinyVector<3>; + + const R3 A{+0, +0, -1}; + const R3 B{+1, +0, -1}; + const R3 C{+0, +1, -1}; + const R3 D{+0, +0, +1}; + const R3 E{+1, +0, +1}; + const R3 F{+0, +1, +1}; + + const R3 M_AB = 0.5 * (A + B); + const R3 M_AC = 0.5 * (A + C); + const R3 M_BC = 0.5 * (B + C); + const R3 M_DE = 0.5 * (D + E); + const R3 M_AD = 0.5 * (A + D); + const R3 M_BE = 0.5 * (B + E); + const R3 M_CF = 0.5 * (C + F); + const R3 M_ABED = 0.25 * (A + B + E + D); + const R3 M_BCFE = 0.25 * (B + C + E + F); + const R3 M_ADFC = 0.25 * (A + D + F + C); + + const double int_T_hat = integrate(f, quadrature_formula); + const double int_refined // + = integrate_on_prism(f, quadrature_formula, {A, M_AB, M_AC, M_AD}) + + integrate_on_prism(f, quadrature_formula, {B, M_BC, M_AB, M_BE}) + + integrate_on_prism(f, quadrature_formula, {C, M_AC, M_BC, M_CF}) + + integrate_on_prism(f, quadrature_formula, {M_AB, M_BC, M_AC, M_ABED}) + + integrate_on_prism(f, quadrature_formula, {M_AD, M_ABED, M_ADFC, D}) + + integrate_on_prism(f, quadrature_formula, {M_BE, M_BCFE, M_ABED, E}) + + integrate_on_prism(f, quadrature_formula, {M_CF, M_ADFC, M_BCFE, F}) + + integrate_on_prism(f, quadrature_formula, {M_ABED, M_BCFE, M_ADFC, M_DE}); + + return -std::log(std::abs(int_refined - exact_value) / std::abs(int_T_hat - exact_value)) / std::log(2); + }; + + auto p0 = [](const TinyVector<3>&) { return 4; }; + auto p1 = [](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return 2 * x + 3 * y + z - 1; + }; + auto p2 = [&p1](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p1(X) * (2.5 * x - 3 * y + z + 3); + }; + auto p3 = [&p2](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p2(X) * (3 * x + 2 * y - 3 * z - 1); + }; + auto p4 = [&p3](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p3(X) * (2 * x - 0.5 * y - 1.3 * z + 1); + }; + auto p5 = [&p4](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p4(X) * (-0.1 * x + 1.3 * y - 3 * z + 1); + }; + auto p6 = [&p5](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p5(X) * 7875. / 143443 * (2 * x - y + 4 * z + 1); + }; + auto p7 = [&p6](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p6(X) * (0.7 * x - 2.7 * y + 1.3 * z - 2); + }; + auto p8 = [&p7](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p7(X) * (0.3 * x + 1.2 * y - 0.7 * z + 0.2); + }; + auto p9 = [&p8](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p8(X) * (-0.2 * x + 1.1 * y - 0.5 * z + 0.6); + }; + auto p10 = [&p9](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p9(X) * (0.7 * x - 0.6 * y - 0.7 * z - 0.2); + }; + auto p11 = [&p10](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p10(X) * (-1.3 * x + 0.6 * y - 1.3 * z + 0.7); + }; + auto p12 = [&p11](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p11(X) * (0.3 * x - 0.7 * y + 0.3 * z + 0.7); + }; + auto p13 = [&p12](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p12(X) * (0.9 * x + 0.2 * y - 0.4 * z + 0.5); + }; + auto p14 = [&p13](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p13(X) * (0.6 * x - 1.2 * y + 0.7 * z - 0.4); + }; + auto p15 = [&p14](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p14(X) * (-0.2 * x - 0.7 * y + 0.9 * z + 0.8); + }; + auto p16 = [&p15](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p15(X) * (0.7 * x + 0.2 * y - 0.6 * z + 0.4); + }; + auto p17 = [&p16](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p16(X) * (-0.1 * x + 0.8 * y + 0.3 * z - 0.2); + }; + auto p18 = [&p17](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p17(X) * (0.7 * x - 0.2 * y - 0.3 * z + 0.8); + }; + auto p19 = [&p18](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p18(X) * (-0.7 * x + 1.2 * y + 1.3 * z + 0.8); + }; + auto p20 = [&p19](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p19(X) * (0.7 * x - 1.2 * y + 0.3 * z - 0.6); + }; + auto p21 = [&p20](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p20(X) * (0.7 * x - 1.2 * y + 0.3 * z - 0.6); + }; + + SECTION("degree 1") + { + const QuadratureFormula<3>& l1 = QuadratureManager::instance().getPrismFormula(GaussQuadratureDescriptor(1)); + + REQUIRE(l1.numberOfPoints() == 1); + + REQUIRE(integrate(p0, l1) == Catch::Approx(4)); + REQUIRE(integrate(p1, l1) == Catch::Approx(2. / 3)); + REQUIRE(integrate(p2, l1) != Catch::Approx(47. / 24)); + + REQUIRE(get_order(p2, l1, 47. / 24) == Catch::Approx(2)); + } + + SECTION("degree 2") + { + const QuadratureFormula<3>& l2 = QuadratureManager::instance().getPrismFormula(GaussQuadratureDescriptor(2)); + + REQUIRE(l2.numberOfPoints() == 5); + + REQUIRE(integrate(p0, l2) == Catch::Approx(4)); + REQUIRE(integrate(p1, l2) == Catch::Approx(2. / 3)); + REQUIRE(integrate(p2, l2) == Catch::Approx(47. / 24)); + REQUIRE(integrate(p3, l2) != Catch::Approx(-427. / 360)); + + // In a weird way, one gets 4th order on this test + REQUIRE(get_order(p3, l2, -427. / 360) == Catch::Approx(4)); + } + + SECTION("degree 3") + { + const QuadratureFormula<3>& l3 = QuadratureManager::instance().getPrismFormula(GaussQuadratureDescriptor(3)); + + REQUIRE(l3.numberOfPoints() == 8); + + REQUIRE(integrate(p0, l3) == Catch::Approx(4)); + REQUIRE(integrate(p1, l3) == Catch::Approx(2. / 3)); + REQUIRE(integrate(p2, l3) == Catch::Approx(47. / 24)); + REQUIRE(integrate(p3, l3) == Catch::Approx(-427. / 360)); + REQUIRE(integrate(p4, l3) != Catch::Approx(1003. / 3600)); + + REQUIRE(get_order(p4, l3, 1003. / 3600) == Catch::Approx(4)); + } + + SECTION("degree 4") + { + const QuadratureFormula<3>& l4 = QuadratureManager::instance().getPrismFormula(GaussQuadratureDescriptor(4)); + + REQUIRE(l4.numberOfPoints() == 11); + + REQUIRE(integrate(p0, l4) == Catch::Approx(4)); + REQUIRE(integrate(p1, l4) == Catch::Approx(2. / 3)); + REQUIRE(integrate(p2, l4) == Catch::Approx(47. / 24)); + REQUIRE(integrate(p3, l4) == Catch::Approx(-427. / 360)); + REQUIRE(integrate(p4, l4) == Catch::Approx(1003. / 3600)); + REQUIRE(integrate(p5, l4) != Catch::Approx(34031. / 18000)); + + REQUIRE(get_order(p5, l4, 34031. / 18000) >= Catch::Approx(5)); + } + + SECTION("degree 5") + { + const QuadratureFormula<3>& l5 = QuadratureManager::instance().getPrismFormula(GaussQuadratureDescriptor(5)); + + REQUIRE(l5.numberOfPoints() == 16); + + REQUIRE(integrate(p0, l5) == Catch::Approx(4)); + REQUIRE(integrate(p1, l5) == Catch::Approx(2. / 3)); + REQUIRE(integrate(p2, l5) == Catch::Approx(47. / 24)); + REQUIRE(integrate(p3, l5) == Catch::Approx(-427. / 360)); + REQUIRE(integrate(p4, l5) == Catch::Approx(1003. / 3600)); + REQUIRE(integrate(p5, l5) == Catch::Approx(34031. / 18000)); + REQUIRE(integrate(p6, l5) != Catch::Approx(36346369. / 55082112)); + + REQUIRE(get_order(p6, l5, 36346369. / 55082112) == Catch::Approx(6)); + } + + SECTION("degree 6") + { + const QuadratureFormula<3>& l6 = QuadratureManager::instance().getPrismFormula(GaussQuadratureDescriptor(6)); + + REQUIRE(l6.numberOfPoints() == 28); + + REQUIRE(integrate(p0, l6) == Catch::Approx(4)); + REQUIRE(integrate(p1, l6) == Catch::Approx(2. / 3)); + REQUIRE(integrate(p2, l6) == Catch::Approx(47. / 24)); + REQUIRE(integrate(p3, l6) == Catch::Approx(-427. / 360)); + REQUIRE(integrate(p4, l6) == Catch::Approx(1003. / 3600)); + REQUIRE(integrate(p5, l6) == Catch::Approx(34031. / 18000)); + REQUIRE(integrate(p6, l6) == Catch::Approx(36346369. / 55082112)); + REQUIRE(integrate(p7, l6) != Catch::Approx(-1128861017. / 918035200)); + + // In a weird way, one gets 8th order on this test + REQUIRE(get_order(p7, l6, -1128861017. / 918035200) == Catch::Approx(8)); + } + + SECTION("degree 7") + { + const QuadratureFormula<3>& l7 = QuadratureManager::instance().getPrismFormula(GaussQuadratureDescriptor(7)); + + REQUIRE(l7.numberOfPoints() == 35); + + REQUIRE(integrate(p0, l7) == Catch::Approx(4)); + REQUIRE(integrate(p1, l7) == Catch::Approx(2. / 3)); + REQUIRE(integrate(p2, l7) == Catch::Approx(47. / 24)); + REQUIRE(integrate(p3, l7) == Catch::Approx(-427. / 360)); + REQUIRE(integrate(p4, l7) == Catch::Approx(1003. / 3600)); + REQUIRE(integrate(p5, l7) == Catch::Approx(34031. / 18000)); + REQUIRE(integrate(p6, l7) == Catch::Approx(36346369. / 55082112)); + REQUIRE(integrate(p7, l7) == Catch::Approx(-1128861017. / 918035200)); + REQUIRE(integrate(p8, l7) != Catch::Approx(-21178319419. / 27541056000)); + + REQUIRE(get_order(p8, l7, -21178319419. / 27541056000) == Catch::Approx(8)); + } + + SECTION("degree 8") + { + const QuadratureFormula<3>& l8 = QuadratureManager::instance().getPrismFormula(GaussQuadratureDescriptor(8)); + + REQUIRE(l8.numberOfPoints() == 46); + + REQUIRE(integrate(p0, l8) == Catch::Approx(4)); + REQUIRE(integrate(p1, l8) == Catch::Approx(2. / 3)); + REQUIRE(integrate(p2, l8) == Catch::Approx(47. / 24)); + REQUIRE(integrate(p3, l8) == Catch::Approx(-427. / 360)); + REQUIRE(integrate(p4, l8) == Catch::Approx(1003. / 3600)); + REQUIRE(integrate(p5, l8) == Catch::Approx(34031. / 18000)); + REQUIRE(integrate(p6, l8) == Catch::Approx(36346369. / 55082112)); + REQUIRE(integrate(p7, l8) == Catch::Approx(-1128861017. / 918035200)); + REQUIRE(integrate(p8, l8) == Catch::Approx(-21178319419. / 27541056000)); + REQUIRE(integrate(p9, l8) != Catch::Approx(-5483758803191. / 9088548480000)); + + // In a weird way, one gets 10th order on this test + REQUIRE(get_order(p9, l8, -5483758803191. / 9088548480000) == Catch::Approx(10)); + } + + SECTION("degree 9") + { + const QuadratureFormula<3>& l9 = QuadratureManager::instance().getPrismFormula(GaussQuadratureDescriptor(9)); + + REQUIRE(l9.numberOfPoints() == 59); + + REQUIRE(integrate(p0, l9) == Catch::Approx(4)); + REQUIRE(integrate(p1, l9) == Catch::Approx(2. / 3)); + REQUIRE(integrate(p2, l9) == Catch::Approx(47. / 24)); + REQUIRE(integrate(p3, l9) == Catch::Approx(-427. / 360)); + REQUIRE(integrate(p4, l9) == Catch::Approx(1003. / 3600)); + REQUIRE(integrate(p5, l9) == Catch::Approx(34031. / 18000)); + REQUIRE(integrate(p6, l9) == Catch::Approx(36346369. / 55082112)); + REQUIRE(integrate(p7, l9) == Catch::Approx(-1128861017. / 918035200)); + REQUIRE(integrate(p8, l9) == Catch::Approx(-21178319419. / 27541056000)); + REQUIRE(integrate(p9, l9) == Catch::Approx(-5483758803191. / 9088548480000)); + REQUIRE(integrate(p10, l9) != Catch::Approx(-9456848221657. / 22721371200000)); + + REQUIRE(get_order(p10, l9, -9456848221657. / 22721371200000) == Catch::Approx(10)); + } + + SECTION("degree 10") + { + const QuadratureFormula<3>& l10 = QuadratureManager::instance().getPrismFormula(GaussQuadratureDescriptor(10)); + + REQUIRE(l10.numberOfPoints() == 84); + + REQUIRE(integrate(p0, l10) == Catch::Approx(4)); + REQUIRE(integrate(p1, l10) == Catch::Approx(2. / 3)); + REQUIRE(integrate(p2, l10) == Catch::Approx(47. / 24)); + REQUIRE(integrate(p3, l10) == Catch::Approx(-427. / 360)); + REQUIRE(integrate(p4, l10) == Catch::Approx(1003. / 3600)); + REQUIRE(integrate(p5, l10) == Catch::Approx(34031. / 18000)); + REQUIRE(integrate(p6, l10) == Catch::Approx(36346369. / 55082112)); + REQUIRE(integrate(p7, l10) == Catch::Approx(-1128861017. / 918035200)); + REQUIRE(integrate(p8, l10) == Catch::Approx(-21178319419. / 27541056000)); + REQUIRE(integrate(p9, l10) == Catch::Approx(-5483758803191. / 9088548480000)); + REQUIRE(integrate(p10, l10) == Catch::Approx(-9456848221657. / 22721371200000)); + REQUIRE(integrate(p11, l10) != Catch::Approx(-4571362439539697. / 7518708288000000)); + + // In a weird way, one gets 12th order on this test + REQUIRE(get_order(p11, l10, -4571362439539697. / 7518708288000000) == Catch::Approx(12)); + } + + SECTION("degree 11") + { + const QuadratureFormula<3>& l11 = QuadratureManager::instance().getPrismFormula(GaussQuadratureDescriptor(11)); + + REQUIRE(l11.numberOfPoints() == 99); + + REQUIRE(integrate(p0, l11) == Catch::Approx(4)); + REQUIRE(integrate(p1, l11) == Catch::Approx(2. / 3)); + REQUIRE(integrate(p2, l11) == Catch::Approx(47. / 24)); + REQUIRE(integrate(p3, l11) == Catch::Approx(-427. / 360)); + REQUIRE(integrate(p4, l11) == Catch::Approx(1003. / 3600)); + REQUIRE(integrate(p5, l11) == Catch::Approx(34031. / 18000)); + REQUIRE(integrate(p6, l11) == Catch::Approx(36346369. / 55082112)); + REQUIRE(integrate(p7, l11) == Catch::Approx(-1128861017. / 918035200)); + REQUIRE(integrate(p8, l11) == Catch::Approx(-21178319419. / 27541056000)); + REQUIRE(integrate(p9, l11) == Catch::Approx(-5483758803191. / 9088548480000)); + REQUIRE(integrate(p10, l11) == Catch::Approx(-9456848221657. / 22721371200000)); + REQUIRE(integrate(p11, l11) == Catch::Approx(-4571362439539697. / 7518708288000000)); + REQUIRE(integrate(p12, l11) != Catch::Approx(-491755535075074133. / 1378429852800000000)); + + REQUIRE(get_order(p12, l11, -491755535075074133. / 1378429852800000000) == Catch::Approx(12)); + } + + SECTION("degree 12") + { + const QuadratureFormula<3>& l12 = QuadratureManager::instance().getPrismFormula(GaussQuadratureDescriptor(12)); + + REQUIRE(l12.numberOfPoints() == 136); + + REQUIRE(integrate(p0, l12) == Catch::Approx(4)); + REQUIRE(integrate(p1, l12) == Catch::Approx(2. / 3)); + REQUIRE(integrate(p2, l12) == Catch::Approx(47. / 24)); + REQUIRE(integrate(p3, l12) == Catch::Approx(-427. / 360)); + REQUIRE(integrate(p4, l12) == Catch::Approx(1003. / 3600)); + REQUIRE(integrate(p5, l12) == Catch::Approx(34031. / 18000)); + REQUIRE(integrate(p6, l12) == Catch::Approx(36346369. / 55082112)); + REQUIRE(integrate(p7, l12) == Catch::Approx(-1128861017. / 918035200)); + REQUIRE(integrate(p8, l12) == Catch::Approx(-21178319419. / 27541056000)); + REQUIRE(integrate(p9, l12) == Catch::Approx(-5483758803191. / 9088548480000)); + REQUIRE(integrate(p10, l12) == Catch::Approx(-9456848221657. / 22721371200000)); + REQUIRE(integrate(p11, l12) == Catch::Approx(-4571362439539697. / 7518708288000000)); + REQUIRE(integrate(p12, l12) == Catch::Approx(-491755535075074133. / 1378429852800000000)); + REQUIRE(integrate(p13, l12) != Catch::Approx(-1620413117251976393. / 4135289558400000000)); + + // In a weird way, one gets almost 14th order on this test + REQUIRE(get_order(p13, l12, -1620413117251976393. / 4135289558400000000) == Catch::Approx(14).margin(0.01)); + } + + SECTION("degree 13") + { + const QuadratureFormula<3>& l13 = QuadratureManager::instance().getPrismFormula(GaussQuadratureDescriptor(13)); + + REQUIRE(l13.numberOfPoints() == 162); + + REQUIRE(integrate(p0, l13) == Catch::Approx(4)); + REQUIRE(integrate(p1, l13) == Catch::Approx(2. / 3)); + REQUIRE(integrate(p2, l13) == Catch::Approx(47. / 24)); + REQUIRE(integrate(p3, l13) == Catch::Approx(-427. / 360)); + REQUIRE(integrate(p4, l13) == Catch::Approx(1003. / 3600)); + REQUIRE(integrate(p5, l13) == Catch::Approx(34031. / 18000)); + REQUIRE(integrate(p6, l13) == Catch::Approx(36346369. / 55082112)); + REQUIRE(integrate(p7, l13) == Catch::Approx(-1128861017. / 918035200)); + REQUIRE(integrate(p8, l13) == Catch::Approx(-21178319419. / 27541056000)); + REQUIRE(integrate(p9, l13) == Catch::Approx(-5483758803191. / 9088548480000)); + REQUIRE(integrate(p10, l13) == Catch::Approx(-9456848221657. / 22721371200000)); + REQUIRE(integrate(p11, l13) == Catch::Approx(-4571362439539697. / 7518708288000000)); + REQUIRE(integrate(p12, l13) == Catch::Approx(-491755535075074133. / 1378429852800000000)); + REQUIRE(integrate(p13, l13) == Catch::Approx(-1620413117251976393. / 4135289558400000000)); + REQUIRE(integrate(p14, l13) != Catch::Approx(296918520496968826367. / 827057911680000000000.)); + + REQUIRE(get_order(p14, l13, 296918520496968826367. / 827057911680000000000.) == Catch::Approx(14)); + } + + SECTION("degree 14") + { + const QuadratureFormula<3>& l14 = QuadratureManager::instance().getPrismFormula(GaussQuadratureDescriptor(14)); + + REQUIRE(l14.numberOfPoints() == 194); + + REQUIRE(integrate(p0, l14) == Catch::Approx(4)); + REQUIRE(integrate(p1, l14) == Catch::Approx(2. / 3)); + REQUIRE(integrate(p2, l14) == Catch::Approx(47. / 24)); + REQUIRE(integrate(p3, l14) == Catch::Approx(-427. / 360)); + REQUIRE(integrate(p4, l14) == Catch::Approx(1003. / 3600)); + REQUIRE(integrate(p5, l14) == Catch::Approx(34031. / 18000)); + REQUIRE(integrate(p6, l14) == Catch::Approx(36346369. / 55082112)); + REQUIRE(integrate(p7, l14) == Catch::Approx(-1128861017. / 918035200)); + REQUIRE(integrate(p8, l14) == Catch::Approx(-21178319419. / 27541056000)); + REQUIRE(integrate(p9, l14) == Catch::Approx(-5483758803191. / 9088548480000)); + REQUIRE(integrate(p10, l14) == Catch::Approx(-9456848221657. / 22721371200000)); + REQUIRE(integrate(p11, l14) == Catch::Approx(-4571362439539697. / 7518708288000000)); + REQUIRE(integrate(p12, l14) == Catch::Approx(-491755535075074133. / 1378429852800000000)); + REQUIRE(integrate(p13, l14) == Catch::Approx(-1620413117251976393. / 4135289558400000000)); + REQUIRE(integrate(p14, l14) == Catch::Approx(296918520496968826367. / 827057911680000000000.)); + REQUIRE(integrate(p15, l14) != Catch::Approx(-7727953154629829488841. / 210899767478400000000000.)); + + // In a weird way, one gets almost 16th order on this test + REQUIRE(get_order(p15, l14, -7727953154629829488841. / 210899767478400000000000.) == + Catch::Approx(16).margin(0.01)); + } + + SECTION("degree 15") + { + const QuadratureFormula<3>& l15 = QuadratureManager::instance().getPrismFormula(GaussQuadratureDescriptor(15)); + + REQUIRE(l15.numberOfPoints() == 238); + + REQUIRE(integrate(p0, l15) == Catch::Approx(4)); + REQUIRE(integrate(p1, l15) == Catch::Approx(2. / 3)); + REQUIRE(integrate(p2, l15) == Catch::Approx(47. / 24)); + REQUIRE(integrate(p3, l15) == Catch::Approx(-427. / 360)); + REQUIRE(integrate(p4, l15) == Catch::Approx(1003. / 3600)); + REQUIRE(integrate(p5, l15) == Catch::Approx(34031. / 18000)); + REQUIRE(integrate(p6, l15) == Catch::Approx(36346369. / 55082112)); + REQUIRE(integrate(p7, l15) == Catch::Approx(-1128861017. / 918035200)); + REQUIRE(integrate(p8, l15) == Catch::Approx(-21178319419. / 27541056000)); + REQUIRE(integrate(p9, l15) == Catch::Approx(-5483758803191. / 9088548480000)); + REQUIRE(integrate(p10, l15) == Catch::Approx(-9456848221657. / 22721371200000)); + REQUIRE(integrate(p11, l15) == Catch::Approx(-4571362439539697. / 7518708288000000)); + REQUIRE(integrate(p12, l15) == Catch::Approx(-491755535075074133. / 1378429852800000000)); + REQUIRE(integrate(p13, l15) == Catch::Approx(-1620413117251976393. / 4135289558400000000)); + REQUIRE(integrate(p14, l15) == Catch::Approx(296918520496968826367. / 827057911680000000000.)); + REQUIRE(integrate(p15, l15) == Catch::Approx(-7727953154629829488841. / 210899767478400000000000.)); + REQUIRE(integrate(p16, l15) != Catch::Approx(-18153283669186101815689. / 527249418696000000000000.)); + + REQUIRE(get_order(p16, l15, -18153283669186101815689. / 527249418696000000000000.) == Catch::Approx(16)); + } + + SECTION("degree 16") + { + const QuadratureFormula<3>& l16 = QuadratureManager::instance().getPrismFormula(GaussQuadratureDescriptor(16)); + + REQUIRE(l16.numberOfPoints() == 287); + + REQUIRE(integrate(p0, l16) == Catch::Approx(4)); + REQUIRE(integrate(p1, l16) == Catch::Approx(2. / 3)); + REQUIRE(integrate(p2, l16) == Catch::Approx(47. / 24)); + REQUIRE(integrate(p3, l16) == Catch::Approx(-427. / 360)); + REQUIRE(integrate(p4, l16) == Catch::Approx(1003. / 3600)); + REQUIRE(integrate(p5, l16) == Catch::Approx(34031. / 18000)); + REQUIRE(integrate(p6, l16) == Catch::Approx(36346369. / 55082112)); + REQUIRE(integrate(p7, l16) == Catch::Approx(-1128861017. / 918035200)); + REQUIRE(integrate(p8, l16) == Catch::Approx(-21178319419. / 27541056000)); + REQUIRE(integrate(p9, l16) == Catch::Approx(-5483758803191. / 9088548480000)); + REQUIRE(integrate(p10, l16) == Catch::Approx(-9456848221657. / 22721371200000)); + REQUIRE(integrate(p11, l16) == Catch::Approx(-4571362439539697. / 7518708288000000)); + REQUIRE(integrate(p12, l16) == Catch::Approx(-491755535075074133. / 1378429852800000000)); + REQUIRE(integrate(p13, l16) == Catch::Approx(-1620413117251976393. / 4135289558400000000)); + REQUIRE(integrate(p14, l16) == Catch::Approx(296918520496968826367. / 827057911680000000000.)); + REQUIRE(integrate(p15, l16) == Catch::Approx(-7727953154629829488841. / 210899767478400000000000.)); + REQUIRE(integrate(p16, l16) == Catch::Approx(-18153283669186101815689. / 527249418696000000000000.)); + REQUIRE(integrate(p17, l16) != Catch::Approx(5157361121064510230030071. / 200354779104480000000000000.)); + + // In a weird way, one gets almost 18th order on this test + REQUIRE(get_order(p17, l16, 5157361121064510230030071. / 200354779104480000000000000.) == + Catch::Approx(18).margin(0.1)); + } + + SECTION("degree 17") + { + const QuadratureFormula<3>& l17 = QuadratureManager::instance().getPrismFormula(GaussQuadratureDescriptor(17)); + + REQUIRE(l17.numberOfPoints() == 338); + + REQUIRE(integrate(p0, l17) == Catch::Approx(4)); + REQUIRE(integrate(p1, l17) == Catch::Approx(2. / 3)); + REQUIRE(integrate(p2, l17) == Catch::Approx(47. / 24)); + REQUIRE(integrate(p3, l17) == Catch::Approx(-427. / 360)); + REQUIRE(integrate(p4, l17) == Catch::Approx(1003. / 3600)); + REQUIRE(integrate(p5, l17) == Catch::Approx(34031. / 18000)); + REQUIRE(integrate(p6, l17) == Catch::Approx(36346369. / 55082112)); + REQUIRE(integrate(p7, l17) == Catch::Approx(-1128861017. / 918035200)); + REQUIRE(integrate(p8, l17) == Catch::Approx(-21178319419. / 27541056000)); + REQUIRE(integrate(p9, l17) == Catch::Approx(-5483758803191. / 9088548480000)); + REQUIRE(integrate(p10, l17) == Catch::Approx(-9456848221657. / 22721371200000)); + REQUIRE(integrate(p11, l17) == Catch::Approx(-4571362439539697. / 7518708288000000)); + REQUIRE(integrate(p12, l17) == Catch::Approx(-491755535075074133. / 1378429852800000000)); + REQUIRE(integrate(p13, l17) == Catch::Approx(-1620413117251976393. / 4135289558400000000)); + REQUIRE(integrate(p14, l17) == Catch::Approx(296918520496968826367. / 827057911680000000000.)); + REQUIRE(integrate(p15, l17) == Catch::Approx(-7727953154629829488841. / 210899767478400000000000.)); + REQUIRE(integrate(p16, l17) == Catch::Approx(-18153283669186101815689. / 527249418696000000000000.)); + REQUIRE(integrate(p17, l17) == Catch::Approx(5157361121064510230030071. / 200354779104480000000000000.)); + REQUIRE(integrate(p18, l17) != + Catch::Approx(195337148397715128549413507. / 5609933814925440000000000000.).epsilon(1E-10)); + + REQUIRE(get_order(p18, l17, 195337148397715128549413507. / 5609933814925440000000000000.) == Catch::Approx(18)); + } + + SECTION("degree 18") + { + const QuadratureFormula<3>& l18 = QuadratureManager::instance().getPrismFormula(GaussQuadratureDescriptor(18)); + + REQUIRE(l18.numberOfPoints() == 396); + + REQUIRE(integrate(p0, l18) == Catch::Approx(4)); + REQUIRE(integrate(p1, l18) == Catch::Approx(2. / 3)); + REQUIRE(integrate(p2, l18) == Catch::Approx(47. / 24)); + REQUIRE(integrate(p3, l18) == Catch::Approx(-427. / 360)); + REQUIRE(integrate(p4, l18) == Catch::Approx(1003. / 3600)); + REQUIRE(integrate(p5, l18) == Catch::Approx(34031. / 18000)); + REQUIRE(integrate(p6, l18) == Catch::Approx(36346369. / 55082112)); + REQUIRE(integrate(p7, l18) == Catch::Approx(-1128861017. / 918035200)); + REQUIRE(integrate(p8, l18) == Catch::Approx(-21178319419. / 27541056000)); + REQUIRE(integrate(p9, l18) == Catch::Approx(-5483758803191. / 9088548480000)); + REQUIRE(integrate(p10, l18) == Catch::Approx(-9456848221657. / 22721371200000)); + REQUIRE(integrate(p11, l18) == Catch::Approx(-4571362439539697. / 7518708288000000)); + REQUIRE(integrate(p12, l18) == Catch::Approx(-491755535075074133. / 1378429852800000000)); + REQUIRE(integrate(p13, l18) == Catch::Approx(-1620413117251976393. / 4135289558400000000)); + REQUIRE(integrate(p14, l18) == Catch::Approx(296918520496968826367. / 827057911680000000000.)); + REQUIRE(integrate(p15, l18) == Catch::Approx(-7727953154629829488841. / 210899767478400000000000.)); + REQUIRE(integrate(p16, l18) == Catch::Approx(-18153283669186101815689. / 527249418696000000000000.)); + REQUIRE(integrate(p17, l18) == Catch::Approx(5157361121064510230030071. / 200354779104480000000000000.)); + REQUIRE(integrate(p18, l18) == Catch::Approx(195337148397715128549413507. / 5609933814925440000000000000.)); + REQUIRE(integrate(p19, l18) != + Catch::Approx(-417563570921497136922189149. / 14024834537313600000000000000.).epsilon(1E-10)); + + // In a weird way, one gets almost 20th order on this test + REQUIRE(get_order(p19, l18, -417563570921497136922189149. / 14024834537313600000000000000.) == + Catch::Approx(20).margin(0.01)); + } + + SECTION("degree 19") + { + const QuadratureFormula<3>& l19 = QuadratureManager::instance().getPrismFormula(GaussQuadratureDescriptor(19)); + + REQUIRE(l19.numberOfPoints() == 420); + + REQUIRE(integrate(p0, l19) == Catch::Approx(4)); + REQUIRE(integrate(p1, l19) == Catch::Approx(2. / 3)); + REQUIRE(integrate(p2, l19) == Catch::Approx(47. / 24)); + REQUIRE(integrate(p3, l19) == Catch::Approx(-427. / 360)); + REQUIRE(integrate(p4, l19) == Catch::Approx(1003. / 3600)); + REQUIRE(integrate(p5, l19) == Catch::Approx(34031. / 18000)); + REQUIRE(integrate(p6, l19) == Catch::Approx(36346369. / 55082112)); + REQUIRE(integrate(p7, l19) == Catch::Approx(-1128861017. / 918035200)); + REQUIRE(integrate(p8, l19) == Catch::Approx(-21178319419. / 27541056000)); + REQUIRE(integrate(p9, l19) == Catch::Approx(-5483758803191. / 9088548480000)); + REQUIRE(integrate(p10, l19) == Catch::Approx(-9456848221657. / 22721371200000)); + REQUIRE(integrate(p11, l19) == Catch::Approx(-4571362439539697. / 7518708288000000)); + REQUIRE(integrate(p12, l19) == Catch::Approx(-491755535075074133. / 1378429852800000000)); + REQUIRE(integrate(p13, l19) == Catch::Approx(-1620413117251976393. / 4135289558400000000)); + REQUIRE(integrate(p14, l19) == Catch::Approx(296918520496968826367. / 827057911680000000000.)); + REQUIRE(integrate(p15, l19) == Catch::Approx(-7727953154629829488841. / 210899767478400000000000.)); + REQUIRE(integrate(p16, l19) == Catch::Approx(-18153283669186101815689. / 527249418696000000000000.)); + REQUIRE(integrate(p17, l19) == Catch::Approx(5157361121064510230030071. / 200354779104480000000000000.)); + REQUIRE(integrate(p18, l19) == Catch::Approx(195337148397715128549413507. / 5609933814925440000000000000.)); + REQUIRE(integrate(p19, l19) == Catch::Approx(-417563570921497136922189149. / 14024834537313600000000000000.)); + REQUIRE(integrate(p20, l19) != + Catch::Approx(4740816174053415637444760963. / 205697573213932800000000000000.).epsilon(1E-10)); + + REQUIRE(get_order(p20, l19, 4740816174053415637444760963. / 205697573213932800000000000000.) == + Catch::Approx(20).margin(0.01)); + } + + SECTION("degree 20") + { + const QuadratureFormula<3>& l20 = QuadratureManager::instance().getPrismFormula(GaussQuadratureDescriptor(20)); + + REQUIRE(l20.numberOfPoints() == 518); + + REQUIRE(integrate(p0, l20) == Catch::Approx(4)); + REQUIRE(integrate(p1, l20) == Catch::Approx(2. / 3)); + REQUIRE(integrate(p2, l20) == Catch::Approx(47. / 24)); + REQUIRE(integrate(p3, l20) == Catch::Approx(-427. / 360)); + REQUIRE(integrate(p4, l20) == Catch::Approx(1003. / 3600)); + REQUIRE(integrate(p5, l20) == Catch::Approx(34031. / 18000)); + REQUIRE(integrate(p6, l20) == Catch::Approx(36346369. / 55082112)); + REQUIRE(integrate(p7, l20) == Catch::Approx(-1128861017. / 918035200)); + REQUIRE(integrate(p8, l20) == Catch::Approx(-21178319419. / 27541056000)); + REQUIRE(integrate(p9, l20) == Catch::Approx(-5483758803191. / 9088548480000)); + REQUIRE(integrate(p10, l20) == Catch::Approx(-9456848221657. / 22721371200000)); + REQUIRE(integrate(p11, l20) == Catch::Approx(-4571362439539697. / 7518708288000000)); + REQUIRE(integrate(p12, l20) == Catch::Approx(-491755535075074133. / 1378429852800000000)); + REQUIRE(integrate(p13, l20) == Catch::Approx(-1620413117251976393. / 4135289558400000000)); + REQUIRE(integrate(p14, l20) == Catch::Approx(296918520496968826367. / 827057911680000000000.)); + REQUIRE(integrate(p15, l20) == Catch::Approx(-7727953154629829488841. / 210899767478400000000000.)); + REQUIRE(integrate(p16, l20) == Catch::Approx(-18153283669186101815689. / 527249418696000000000000.)); + REQUIRE(integrate(p17, l20) == Catch::Approx(5157361121064510230030071. / 200354779104480000000000000.)); + REQUIRE(integrate(p18, l20) == Catch::Approx(195337148397715128549413507. / 5609933814925440000000000000.)); + REQUIRE(integrate(p19, l20) == Catch::Approx(-417563570921497136922189149. / 14024834537313600000000000000.)); + REQUIRE(integrate(p20, l20) == Catch::Approx(4740816174053415637444760963. / 205697573213932800000000000000.)); + REQUIRE(integrate(p21, l20) != + Catch::Approx(-164372186128198750911065614811351. / 7096566275880681600000000000000000.).epsilon(1E-10)); + + // In a weird way, one gets almost 22th order on this test + REQUIRE(get_order(p21, l20, -164372186128198750911065614811351. / 7096566275880681600000000000000000.) == + Catch::Approx(22).margin(0.01)); + } + + SECTION("max implemented degree") + { + REQUIRE(QuadratureManager::instance().maxPrismDegree(QuadratureType::Gauss) == PrismGaussQuadrature::max_degree); + } +} diff --git a/tests/test_PrismTransformation.cpp b/tests/test_PrismTransformation.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f933fe308fbc64915faf04449aeca364f0904053 --- /dev/null +++ b/tests/test_PrismTransformation.cpp @@ -0,0 +1,106 @@ +#include <catch2/catch_approx.hpp> +#include <catch2/catch_test_macros.hpp> + +#include <analysis/GaussQuadratureDescriptor.hpp> +#include <analysis/QuadratureManager.hpp> +#include <geometry/PrismTransformation.hpp> + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("PrismTransformation", "[geometry]") +{ + using R3 = TinyVector<3>; + + const R3 a_hat = {0, 0, -1}; + const R3 b_hat = {1, 0, -1}; + const R3 c_hat = {0, 1, -1}; + const R3 d_hat = {0, 0, +1}; + const R3 e_hat = {1, 0, +1}; + const R3 f_hat = {0, 1, +1}; + + const R3 m_hat = {1. / 3, 1. / 3, 0}; + + const R3 a = {1, 2, 0}; + const R3 b = {3, 1, 3}; + const R3 c = {2, 5, 2}; + const R3 d = {0, 3, 1}; + const R3 e = {1, 2, 5}; + const R3 f = {3, 1, 7}; + + const PrismTransformation t(a, b, c, d, e, f); + + SECTION("points") + { + REQUIRE(l2Norm(t(a_hat) - a) == Catch::Approx(0)); + REQUIRE(l2Norm(t(b_hat) - b) == Catch::Approx(0)); + REQUIRE(l2Norm(t(c_hat) - c) == Catch::Approx(0)); + REQUIRE(l2Norm(t(d_hat) - d) == Catch::Approx(0)); + REQUIRE(l2Norm(t(e_hat) - e) == Catch::Approx(0)); + REQUIRE(l2Norm(t(f_hat) - f) == Catch::Approx(0)); + + R3 m = (1. / 6) * (a + b + c + d + e + f); + + REQUIRE(l2Norm(t(m_hat) - m) == Catch::Approx(0).margin(1E-14)); + } + + SECTION("Jacobian determinant") + { + SECTION("at points") + { + auto detJ = [](const R3 X) { + const double& x = X[0]; + const double& y = X[1]; + const double& z = X[2]; + + return ((2 * y + 0.5 * x + 0.5) * (z + 2) - (y - 0.5 * x - 0.5) * (2 * z + 4)) + + (1.5 - 0.5 * z) * ((2 * y + 0.5 * x + 0.5) * (0.5 - 2.5 * z) - (0.5 - 2.5 * y) * (2 * z + 4)) + + (0.5 * z + 3.5) * ((0.5 - 2.5 * y) * (z + 2) - (y - 0.5 * x - 0.5) * (0.5 - 2.5 * z)); + }; + + REQUIRE(t.jacobianDeterminant(a_hat) == Catch::Approx(detJ(a_hat))); + REQUIRE(t.jacobianDeterminant(b_hat) == Catch::Approx(detJ(b_hat))); + REQUIRE(t.jacobianDeterminant(c_hat) == Catch::Approx(detJ(c_hat))); + REQUIRE(t.jacobianDeterminant(d_hat) == Catch::Approx(detJ(d_hat))); + REQUIRE(t.jacobianDeterminant(e_hat) == Catch::Approx(detJ(e_hat))); + REQUIRE(t.jacobianDeterminant(f_hat) == Catch::Approx(detJ(f_hat))); + + REQUIRE(t.jacobianDeterminant(m_hat) == Catch::Approx(detJ(m_hat))); + } + + SECTION("volume calculation") + { + // due to the z component of the jacobian determinant, degree 3 + // polynomials must be exactly integrated + const QuadratureFormula<3>& gauss = QuadratureManager::instance().getPrismFormula(GaussQuadratureDescriptor(3)); + + double volume = 0; + for (size_t i = 0; i < gauss.numberOfPoints(); ++i) { + volume += gauss.weight(i) * t.jacobianDeterminant(gauss.point(i)); + } + + // 11/2 is actually the volume of the prism + REQUIRE(volume == Catch::Approx(11. / 2)); + } + + SECTION("exact polynomial integration") + { + auto p = [](const R3& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + + return 3 * x * x + 2 * y * y + 3 * z * z + 4 * x + 3 * y + 2 * z + 1; + }; + + // 5 is the minimum quadrature rule to integrate the polynomial on the prism + const QuadratureFormula<3>& gauss = QuadratureManager::instance().getPrismFormula(GaussQuadratureDescriptor(5)); + + double integral = 0; + for (size_t i = 0; i < gauss.numberOfPoints(); ++i) { + integral += gauss.weight(i) * t.jacobianDeterminant(gauss.point(i)) * p(t(gauss.point(i))); + } + + REQUIRE(integral == Catch::Approx(30377. / 90)); + } + } +} diff --git a/tests/test_PugsFunctionAdapter.cpp b/tests/test_PugsFunctionAdapter.cpp index 76f3a06aa3f96c208e6c02c16f8006e22160a8f6..cb0dbc7c5e1b76dfeeb6390ddca70524e22d7dc1 100644 --- a/tests/test_PugsFunctionAdapter.cpp +++ b/tests/test_PugsFunctionAdapter.cpp @@ -33,7 +33,7 @@ class TestBinary<OutputType(InputType...)> : public PugsFunctionAdapter<OutputTy auto& expression = Adapter::getFunctionExpression(function_symbol_id); auto convert_result = Adapter::getResultConverter(expression.m_data_type); - Array<ExecutionPolicy> context_list = Adapter::getContextList(expression); + auto context_list = Adapter::getContextList(expression); auto& execution_policy = context_list[0]; @@ -50,7 +50,7 @@ class TestBinary<OutputType(InputType...)> : public PugsFunctionAdapter<OutputTy auto& expression = Adapter::getFunctionExpression(function_symbol_id); auto convert_result = Adapter::getResultConverter(expression.m_data_type); - Array<ExecutionPolicy> context_list = Adapter::getContextList(expression); + auto context_list = Adapter::getContextList(expression); auto& execution_policy = context_list[0]; diff --git a/tests/test_PyramidGaussQuadrature.cpp b/tests/test_PyramidGaussQuadrature.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e648c96fb13df144945e7c73cdf381545ff1169b --- /dev/null +++ b/tests/test_PyramidGaussQuadrature.cpp @@ -0,0 +1,570 @@ +#include <catch2/catch_approx.hpp> +#include <catch2/catch_test_macros.hpp> +#include <catch2/matchers/catch_matchers_all.hpp> + +#include <analysis/GaussQuadratureDescriptor.hpp> +#include <analysis/PyramidGaussQuadrature.hpp> +#include <analysis/QuadratureManager.hpp> +#include <geometry/TetrahedronTransformation.hpp> +#include <utils/Exceptions.hpp> + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("PyramidGaussQuadrature", "[analysis]") +{ + auto integrate = [](auto f, auto quadrature_formula) { + auto point_list = quadrature_formula.pointList(); + auto weight_list = quadrature_formula.weightList(); + + auto value = weight_list[0] * f(point_list[0]); + for (size_t i = 1; i < weight_list.size(); ++i) { + value += weight_list[i] * f(point_list[i]); + } + + return value; + }; + + auto p0 = [](const TinyVector<3>&) { return 4; }; + auto p1 = [](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return 2 * x + 3 * y + z - 1; + }; + auto p2 = [&p1](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p1(X) * (2.5 * x - 3 * y + z + 3); + }; + auto p3 = [&p2](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p2(X) * (3 * x + 2 * y - 3 * z - 1); + }; + auto p4 = [&p3](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p3(X) * (2 * x - 0.5 * y - 1.3 * z + 1); + }; + auto p5 = [&p4](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p4(X) * (-0.1 * x + 1.3 * y - 3 * z + 1); + }; + auto p6 = [&p5](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p5(X) * 7875. / 143443 * (2 * x - y + 4 * z + 1); + }; + auto p7 = [&p6](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p6(X) * (0.7 * x - 2.7 * y + 1.3 * z - 2); + }; + auto p8 = [&p7](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p7(X) * (0.3 * x + 1.2 * y - 0.7 * z + 0.2); + }; + auto p9 = [&p8](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p8(X) * (-0.2 * x + 1.1 * y - 0.5 * z + 0.6); + }; + auto p10 = [&p9](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p9(X) * (0.7 * x - 0.6 * y - 0.7 * z - 0.2); + }; + auto p11 = [&p10](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p10(X) * (-1.3 * x + 0.6 * y - 1.3 * z + 0.7); + }; + auto p12 = [&p11](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p11(X) * (0.3 * x - 0.7 * y + 0.3 * z + 0.7); + }; + auto p13 = [&p12](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p12(X) * (0.9 * x + 0.2 * y - 0.4 * z + 0.5); + }; + auto p14 = [&p13](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p13(X) * (0.6 * x - 1.2 * y + 0.7 * z - 0.4); + }; + auto p15 = [&p14](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p14(X) * (-0.2 * x - 0.7 * y + 0.9 * z + 0.8); + }; + auto p16 = [&p15](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p15(X) * (0.7 * x + 0.2 * y - 0.6 * z + 0.4); + }; + auto p17 = [&p16](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p16(X) * (-0.1 * x + 0.8 * y + 0.3 * z - 0.2); + }; + auto p18 = [&p17](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p17(X) * (0.7 * x - 0.2 * y - 0.3 * z + 0.8); + }; + auto p19 = [&p18](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p18(X) * (-0.7 * x + 1.2 * y + 1.3 * z + 0.8); + }; + auto p20 = [&p19](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p19(X) * (0.7 * x - 1.2 * y + 0.3 * z - 0.6); + }; + auto p21 = [&p20](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p20(X) * (0.7 * x - 1.2 * y + 0.3 * z - 0.6); + }; + + SECTION("degree 1") + { + const QuadratureFormula<3>& l1 = QuadratureManager::instance().getPyramidFormula(GaussQuadratureDescriptor(1)); + + REQUIRE(l1.numberOfPoints() == 1); + + REQUIRE(integrate(p0, l1) == Catch::Approx(16. / 3)); + REQUIRE(integrate(p1, l1) == Catch::Approx(-1)); + REQUIRE(integrate(p2, l1) != Catch::Approx(-64. / 15)); + } + + SECTION("degree 2") + { + const QuadratureFormula<3>& l2 = QuadratureManager::instance().getPyramidFormula(GaussQuadratureDescriptor(2)); + + REQUIRE(l2.numberOfPoints() == 5); + + REQUIRE(integrate(p0, l2) == Catch::Approx(16. / 3)); + REQUIRE(integrate(p1, l2) == Catch::Approx(-1)); + REQUIRE(integrate(p2, l2) == Catch::Approx(-64. / 15)); + REQUIRE(integrate(p3, l2) != Catch::Approx(83. / 5)); + } + + SECTION("degree 3") + { + const QuadratureFormula<3>& l3 = QuadratureManager::instance().getPyramidFormula(GaussQuadratureDescriptor(3)); + + REQUIRE(l3.numberOfPoints() == 6); + + REQUIRE(integrate(p0, l3) == Catch::Approx(16. / 3)); + REQUIRE(integrate(p1, l3) == Catch::Approx(-1)); + REQUIRE(integrate(p2, l3) == Catch::Approx(-64. / 15)); + REQUIRE(integrate(p3, l3) == Catch::Approx(83. / 5)); + REQUIRE(integrate(p4, l3) != Catch::Approx(26809. / 3150)); + } + + SECTION("degree 4") + { + const QuadratureFormula<3>& l4 = QuadratureManager::instance().getPyramidFormula(GaussQuadratureDescriptor(4)); + + REQUIRE(l4.numberOfPoints() == 10); + + REQUIRE(integrate(p0, l4) == Catch::Approx(16. / 3)); + REQUIRE(integrate(p1, l4) == Catch::Approx(-1)); + REQUIRE(integrate(p2, l4) == Catch::Approx(-64. / 15)); + REQUIRE(integrate(p3, l4) == Catch::Approx(83. / 5)); + REQUIRE(integrate(p4, l4) == Catch::Approx(26809. / 3150)); + REQUIRE(integrate(p5, l4) != Catch::Approx(42881. / 63000)); + } + + SECTION("degree 5") + { + const QuadratureFormula<3>& l5 = QuadratureManager::instance().getPyramidFormula(GaussQuadratureDescriptor(5)); + + REQUIRE(l5.numberOfPoints() == 15); + + REQUIRE(integrate(p0, l5) == Catch::Approx(16. / 3)); + REQUIRE(integrate(p1, l5) == Catch::Approx(-1)); + REQUIRE(integrate(p2, l5) == Catch::Approx(-64. / 15)); + REQUIRE(integrate(p3, l5) == Catch::Approx(83. / 5)); + REQUIRE(integrate(p4, l5) == Catch::Approx(26809. / 3150)); + REQUIRE(integrate(p5, l5) == Catch::Approx(42881. / 63000)); + REQUIRE(integrate(p6, l5) != Catch::Approx(-59509. / 1290987)); + } + + SECTION("degree 6") + { + const QuadratureFormula<3>& l6 = QuadratureManager::instance().getPyramidFormula(GaussQuadratureDescriptor(6)); + + REQUIRE(l6.numberOfPoints() == 23); + + REQUIRE(integrate(p0, l6) == Catch::Approx(16. / 3)); + REQUIRE(integrate(p1, l6) == Catch::Approx(-1)); + REQUIRE(integrate(p2, l6) == Catch::Approx(-64. / 15)); + REQUIRE(integrate(p3, l6) == Catch::Approx(83. / 5)); + REQUIRE(integrate(p4, l6) == Catch::Approx(26809. / 3150)); + REQUIRE(integrate(p5, l6) == Catch::Approx(42881. / 63000)); + REQUIRE(integrate(p6, l6) == Catch::Approx(-59509. / 1290987)); + REQUIRE(integrate(p7, l6) != Catch::Approx(-79258447. / 64549350)); + } + + SECTION("degree 7") + { + const QuadratureFormula<3>& l7 = QuadratureManager::instance().getPyramidFormula(GaussQuadratureDescriptor(7)); + + REQUIRE(l7.numberOfPoints() == 31); + + REQUIRE(integrate(p0, l7) == Catch::Approx(16. / 3)); + REQUIRE(integrate(p1, l7) == Catch::Approx(-1)); + REQUIRE(integrate(p2, l7) == Catch::Approx(-64. / 15)); + REQUIRE(integrate(p3, l7) == Catch::Approx(83. / 5)); + REQUIRE(integrate(p4, l7) == Catch::Approx(26809. / 3150)); + REQUIRE(integrate(p5, l7) == Catch::Approx(42881. / 63000)); + REQUIRE(integrate(p6, l7) == Catch::Approx(-59509. / 1290987)); + REQUIRE(integrate(p7, l7) == Catch::Approx(-79258447. / 64549350)); + REQUIRE(integrate(p8, l7) != Catch::Approx(-64936890181. / 56803428000)); + } + + SECTION("degree 8") + { + const QuadratureFormula<3>& l8 = QuadratureManager::instance().getPyramidFormula(GaussQuadratureDescriptor(8)); + + REQUIRE(l8.numberOfPoints() == 47); + + REQUIRE(integrate(p0, l8) == Catch::Approx(16. / 3)); + REQUIRE(integrate(p1, l8) == Catch::Approx(-1)); + REQUIRE(integrate(p2, l8) == Catch::Approx(-64. / 15)); + REQUIRE(integrate(p3, l8) == Catch::Approx(83. / 5)); + REQUIRE(integrate(p4, l8) == Catch::Approx(26809. / 3150)); + REQUIRE(integrate(p5, l8) == Catch::Approx(42881. / 63000)); + REQUIRE(integrate(p6, l8) == Catch::Approx(-59509. / 1290987)); + REQUIRE(integrate(p7, l8) == Catch::Approx(-79258447. / 64549350)); + REQUIRE(integrate(p8, l8) == Catch::Approx(-64936890181. / 56803428000)); + REQUIRE(integrate(p9, l8) != Catch::Approx(-46104457917. / 31557460000)); + } + + SECTION("degree 9") + { + const QuadratureFormula<3>& l9 = QuadratureManager::instance().getPyramidFormula(GaussQuadratureDescriptor(9)); + + REQUIRE(l9.numberOfPoints() == 62); + + REQUIRE(integrate(p0, l9) == Catch::Approx(16. / 3)); + REQUIRE(integrate(p1, l9) == Catch::Approx(-1)); + REQUIRE(integrate(p2, l9) == Catch::Approx(-64. / 15)); + REQUIRE(integrate(p3, l9) == Catch::Approx(83. / 5)); + REQUIRE(integrate(p4, l9) == Catch::Approx(26809. / 3150)); + REQUIRE(integrate(p5, l9) == Catch::Approx(42881. / 63000)); + REQUIRE(integrate(p6, l9) == Catch::Approx(-59509. / 1290987)); + REQUIRE(integrate(p7, l9) == Catch::Approx(-79258447. / 64549350)); + REQUIRE(integrate(p8, l9) == Catch::Approx(-64936890181. / 56803428000)); + REQUIRE(integrate(p9, l9) == Catch::Approx(-46104457917. / 31557460000)); + REQUIRE(integrate(p10, l9) != Catch::Approx(14564160020837. / 73844456400000)); + } + + SECTION("degree 10") + { + const QuadratureFormula<3>& l10 = QuadratureManager::instance().getPyramidFormula(GaussQuadratureDescriptor(10)); + + REQUIRE(l10.numberOfPoints() == 80); + + REQUIRE(integrate(p0, l10) == Catch::Approx(16. / 3)); + REQUIRE(integrate(p1, l10) == Catch::Approx(-1)); + REQUIRE(integrate(p2, l10) == Catch::Approx(-64. / 15)); + REQUIRE(integrate(p3, l10) == Catch::Approx(83. / 5)); + REQUIRE(integrate(p4, l10) == Catch::Approx(26809. / 3150)); + REQUIRE(integrate(p5, l10) == Catch::Approx(42881. / 63000)); + REQUIRE(integrate(p6, l10) == Catch::Approx(-59509. / 1290987)); + REQUIRE(integrate(p7, l10) == Catch::Approx(-79258447. / 64549350)); + REQUIRE(integrate(p8, l10) == Catch::Approx(-64936890181. / 56803428000)); + REQUIRE(integrate(p9, l10) == Catch::Approx(-46104457917. / 31557460000)); + REQUIRE(integrate(p10, l10) == Catch::Approx(14564160020837. / 73844456400000)); + REQUIRE(integrate(p11, l10) != Catch::Approx(70717900459291. / 1723037316000000)); + } + + SECTION("degree 11") + { + const QuadratureFormula<3>& l11 = QuadratureManager::instance().getPyramidFormula(GaussQuadratureDescriptor(11)); + + REQUIRE(l11.numberOfPoints() == 103); + + REQUIRE(integrate(p0, l11) == Catch::Approx(16. / 3)); + REQUIRE(integrate(p1, l11) == Catch::Approx(-1)); + REQUIRE(integrate(p2, l11) == Catch::Approx(-64. / 15)); + REQUIRE(integrate(p3, l11) == Catch::Approx(83. / 5)); + REQUIRE(integrate(p4, l11) == Catch::Approx(26809. / 3150)); + REQUIRE(integrate(p5, l11) == Catch::Approx(42881. / 63000)); + REQUIRE(integrate(p6, l11) == Catch::Approx(-59509. / 1290987)); + REQUIRE(integrate(p7, l11) == Catch::Approx(-79258447. / 64549350)); + REQUIRE(integrate(p8, l11) == Catch::Approx(-64936890181. / 56803428000)); + REQUIRE(integrate(p9, l11) == Catch::Approx(-46104457917. / 31557460000)); + REQUIRE(integrate(p10, l11) == Catch::Approx(14564160020837. / 73844456400000)); + REQUIRE(integrate(p11, l11) == Catch::Approx(70717900459291. / 1723037316000000)); + REQUIRE(integrate(p12, l11) != Catch::Approx(4088535221940569. / 129227798700000000)); + } + + SECTION("degree 12") + { + const QuadratureFormula<3>& l12 = QuadratureManager::instance().getPyramidFormula(GaussQuadratureDescriptor(12)); + + REQUIRE(l12.numberOfPoints() == 127); + + REQUIRE(integrate(p0, l12) == Catch::Approx(16. / 3)); + REQUIRE(integrate(p1, l12) == Catch::Approx(-1)); + REQUIRE(integrate(p2, l12) == Catch::Approx(-64. / 15)); + REQUIRE(integrate(p3, l12) == Catch::Approx(83. / 5)); + REQUIRE(integrate(p4, l12) == Catch::Approx(26809. / 3150)); + REQUIRE(integrate(p5, l12) == Catch::Approx(42881. / 63000)); + REQUIRE(integrate(p6, l12) == Catch::Approx(-59509. / 1290987)); + REQUIRE(integrate(p7, l12) == Catch::Approx(-79258447. / 64549350)); + REQUIRE(integrate(p8, l12) == Catch::Approx(-64936890181. / 56803428000)); + REQUIRE(integrate(p9, l12) == Catch::Approx(-46104457917. / 31557460000)); + REQUIRE(integrate(p10, l12) == Catch::Approx(14564160020837. / 73844456400000)); + REQUIRE(integrate(p11, l12) == Catch::Approx(70717900459291. / 1723037316000000)); + REQUIRE(integrate(p12, l12) == Catch::Approx(4088535221940569. / 129227798700000000)); + REQUIRE(integrate(p13, l12) != Catch::Approx(4202215015498883. / 129227798700000000)); + } + + SECTION("degree 13") + { + const QuadratureFormula<3>& l13 = QuadratureManager::instance().getPyramidFormula(GaussQuadratureDescriptor(13)); + + REQUIRE(l13.numberOfPoints() == 152); + + REQUIRE(integrate(p0, l13) == Catch::Approx(16. / 3)); + REQUIRE(integrate(p1, l13) == Catch::Approx(-1)); + REQUIRE(integrate(p2, l13) == Catch::Approx(-64. / 15)); + REQUIRE(integrate(p3, l13) == Catch::Approx(83. / 5)); + REQUIRE(integrate(p4, l13) == Catch::Approx(26809. / 3150)); + REQUIRE(integrate(p5, l13) == Catch::Approx(42881. / 63000)); + REQUIRE(integrate(p6, l13) == Catch::Approx(-59509. / 1290987)); + REQUIRE(integrate(p7, l13) == Catch::Approx(-79258447. / 64549350)); + REQUIRE(integrate(p8, l13) == Catch::Approx(-64936890181. / 56803428000)); + REQUIRE(integrate(p9, l13) == Catch::Approx(-46104457917. / 31557460000)); + REQUIRE(integrate(p10, l13) == Catch::Approx(14564160020837. / 73844456400000)); + REQUIRE(integrate(p11, l13) == Catch::Approx(70717900459291. / 1723037316000000)); + REQUIRE(integrate(p12, l13) == Catch::Approx(4088535221940569. / 129227798700000000)); + REQUIRE(integrate(p13, l13) == Catch::Approx(4202215015498883. / 129227798700000000)); + REQUIRE(integrate(p14, l13) != Catch::Approx(-13139133580740403. / 4992892222500000000.)); + } + + SECTION("degree 14") + { + const QuadratureFormula<3>& l14 = QuadratureManager::instance().getPyramidFormula(GaussQuadratureDescriptor(14)); + + REQUIRE(l14.numberOfPoints() == 184); + + REQUIRE(integrate(p0, l14) == Catch::Approx(16. / 3)); + REQUIRE(integrate(p1, l14) == Catch::Approx(-1)); + REQUIRE(integrate(p2, l14) == Catch::Approx(-64. / 15)); + REQUIRE(integrate(p3, l14) == Catch::Approx(83. / 5)); + REQUIRE(integrate(p4, l14) == Catch::Approx(26809. / 3150)); + REQUIRE(integrate(p5, l14) == Catch::Approx(42881. / 63000)); + REQUIRE(integrate(p6, l14) == Catch::Approx(-59509. / 1290987)); + REQUIRE(integrate(p7, l14) == Catch::Approx(-79258447. / 64549350)); + REQUIRE(integrate(p8, l14) == Catch::Approx(-64936890181. / 56803428000)); + REQUIRE(integrate(p9, l14) == Catch::Approx(-46104457917. / 31557460000)); + REQUIRE(integrate(p10, l14) == Catch::Approx(14564160020837. / 73844456400000)); + REQUIRE(integrate(p11, l14) == Catch::Approx(70717900459291. / 1723037316000000)); + REQUIRE(integrate(p12, l14) == Catch::Approx(4088535221940569. / 129227798700000000)); + REQUIRE(integrate(p13, l14) == Catch::Approx(4202215015498883. / 129227798700000000)); + REQUIRE(integrate(p14, l14) == Catch::Approx(-13139133580740403. / 4992892222500000000.)); + REQUIRE(integrate(p15, l14) != Catch::Approx(50695835504084747233. / 3295308866850000000000.)); + } + + SECTION("degree 15") + { + const QuadratureFormula<3>& l15 = QuadratureManager::instance().getPyramidFormula(GaussQuadratureDescriptor(15)); + + REQUIRE(l15.numberOfPoints() == 234); + + REQUIRE(integrate(p0, l15) == Catch::Approx(16. / 3)); + REQUIRE(integrate(p1, l15) == Catch::Approx(-1)); + REQUIRE(integrate(p2, l15) == Catch::Approx(-64. / 15)); + REQUIRE(integrate(p3, l15) == Catch::Approx(83. / 5)); + REQUIRE(integrate(p4, l15) == Catch::Approx(26809. / 3150)); + REQUIRE(integrate(p5, l15) == Catch::Approx(42881. / 63000)); + REQUIRE(integrate(p6, l15) == Catch::Approx(-59509. / 1290987)); + REQUIRE(integrate(p7, l15) == Catch::Approx(-79258447. / 64549350)); + REQUIRE(integrate(p8, l15) == Catch::Approx(-64936890181. / 56803428000)); + REQUIRE(integrate(p9, l15) == Catch::Approx(-46104457917. / 31557460000)); + REQUIRE(integrate(p10, l15) == Catch::Approx(14564160020837. / 73844456400000)); + REQUIRE(integrate(p11, l15) == Catch::Approx(70717900459291. / 1723037316000000)); + REQUIRE(integrate(p12, l15) == Catch::Approx(4088535221940569. / 129227798700000000)); + REQUIRE(integrate(p13, l15) == Catch::Approx(4202215015498883. / 129227798700000000)); + REQUIRE(integrate(p14, l15) == Catch::Approx(-13139133580740403. / 4992892222500000000.)); + REQUIRE(integrate(p15, l15) == Catch::Approx(50695835504084747233. / 3295308866850000000000.)); + REQUIRE(integrate(p16, l15) != Catch::Approx(7438848232461834482681. / 834811579602000000000000.)); + } + + SECTION("degree 16") + { + const QuadratureFormula<3>& l16 = QuadratureManager::instance().getPyramidFormula(GaussQuadratureDescriptor(16)); + + REQUIRE(l16.numberOfPoints() == 285); + + REQUIRE(integrate(p0, l16) == Catch::Approx(16. / 3)); + REQUIRE(integrate(p1, l16) == Catch::Approx(-1)); + REQUIRE(integrate(p2, l16) == Catch::Approx(-64. / 15)); + REQUIRE(integrate(p3, l16) == Catch::Approx(83. / 5)); + REQUIRE(integrate(p4, l16) == Catch::Approx(26809. / 3150)); + REQUIRE(integrate(p5, l16) == Catch::Approx(42881. / 63000)); + REQUIRE(integrate(p6, l16) == Catch::Approx(-59509. / 1290987)); + REQUIRE(integrate(p7, l16) == Catch::Approx(-79258447. / 64549350)); + REQUIRE(integrate(p8, l16) == Catch::Approx(-64936890181. / 56803428000)); + REQUIRE(integrate(p9, l16) == Catch::Approx(-46104457917. / 31557460000)); + REQUIRE(integrate(p10, l16) == Catch::Approx(14564160020837. / 73844456400000)); + REQUIRE(integrate(p11, l16) == Catch::Approx(70717900459291. / 1723037316000000)); + REQUIRE(integrate(p12, l16) == Catch::Approx(4088535221940569. / 129227798700000000)); + REQUIRE(integrate(p13, l16) == Catch::Approx(4202215015498883. / 129227798700000000)); + REQUIRE(integrate(p14, l16) == Catch::Approx(-13139133580740403. / 4992892222500000000.)); + REQUIRE(integrate(p15, l16) == Catch::Approx(50695835504084747233. / 3295308866850000000000.)); + REQUIRE(integrate(p16, l16) == Catch::Approx(7438848232461834482681. / 834811579602000000000000.)); + REQUIRE(integrate(p17, l16) != Catch::Approx(-49370451351776632471. / 4384514598750000000000.)); + } + + SECTION("degree 17") + { + const QuadratureFormula<3>& l17 = QuadratureManager::instance().getPyramidFormula(GaussQuadratureDescriptor(17)); + + REQUIRE(l17.numberOfPoints() == 319); + + REQUIRE(integrate(p0, l17) == Catch::Approx(16. / 3)); + REQUIRE(integrate(p1, l17) == Catch::Approx(-1)); + REQUIRE(integrate(p2, l17) == Catch::Approx(-64. / 15)); + REQUIRE(integrate(p3, l17) == Catch::Approx(83. / 5)); + REQUIRE(integrate(p4, l17) == Catch::Approx(26809. / 3150)); + REQUIRE(integrate(p5, l17) == Catch::Approx(42881. / 63000)); + REQUIRE(integrate(p6, l17) == Catch::Approx(-59509. / 1290987)); + REQUIRE(integrate(p7, l17) == Catch::Approx(-79258447. / 64549350)); + REQUIRE(integrate(p8, l17) == Catch::Approx(-64936890181. / 56803428000)); + REQUIRE(integrate(p9, l17) == Catch::Approx(-46104457917. / 31557460000)); + REQUIRE(integrate(p10, l17) == Catch::Approx(14564160020837. / 73844456400000)); + REQUIRE(integrate(p11, l17) == Catch::Approx(70717900459291. / 1723037316000000)); + REQUIRE(integrate(p12, l17) == Catch::Approx(4088535221940569. / 129227798700000000)); + REQUIRE(integrate(p13, l17) == Catch::Approx(4202215015498883. / 129227798700000000)); + REQUIRE(integrate(p14, l17) == Catch::Approx(-13139133580740403. / 4992892222500000000.)); + REQUIRE(integrate(p15, l17) == Catch::Approx(50695835504084747233. / 3295308866850000000000.)); + REQUIRE(integrate(p16, l17) == Catch::Approx(7438848232461834482681. / 834811579602000000000000.)); + REQUIRE(integrate(p17, l17) == Catch::Approx(-49370451351776632471. / 4384514598750000000000.)); + REQUIRE(integrate(p18, l17) != Catch::Approx(-3041981344499113218848083. / 194789368573800000000000000.)); + } + + SECTION("degree 18") + { + const QuadratureFormula<3>& l18 = QuadratureManager::instance().getPyramidFormula(GaussQuadratureDescriptor(18)); + + REQUIRE(l18.numberOfPoints() == 357); + + REQUIRE(integrate(p0, l18) == Catch::Approx(16. / 3)); + REQUIRE(integrate(p1, l18) == Catch::Approx(-1)); + REQUIRE(integrate(p2, l18) == Catch::Approx(-64. / 15)); + REQUIRE(integrate(p3, l18) == Catch::Approx(83. / 5)); + REQUIRE(integrate(p4, l18) == Catch::Approx(26809. / 3150)); + REQUIRE(integrate(p5, l18) == Catch::Approx(42881. / 63000)); + REQUIRE(integrate(p6, l18) == Catch::Approx(-59509. / 1290987)); + REQUIRE(integrate(p7, l18) == Catch::Approx(-79258447. / 64549350)); + REQUIRE(integrate(p8, l18) == Catch::Approx(-64936890181. / 56803428000)); + REQUIRE(integrate(p9, l18) == Catch::Approx(-46104457917. / 31557460000)); + REQUIRE(integrate(p10, l18) == Catch::Approx(14564160020837. / 73844456400000)); + REQUIRE(integrate(p11, l18) == Catch::Approx(70717900459291. / 1723037316000000)); + REQUIRE(integrate(p12, l18) == Catch::Approx(4088535221940569. / 129227798700000000)); + REQUIRE(integrate(p13, l18) == Catch::Approx(4202215015498883. / 129227798700000000)); + REQUIRE(integrate(p14, l18) == Catch::Approx(-13139133580740403. / 4992892222500000000.)); + REQUIRE(integrate(p15, l18) == Catch::Approx(50695835504084747233. / 3295308866850000000000.)); + REQUIRE(integrate(p16, l18) == Catch::Approx(7438848232461834482681. / 834811579602000000000000.)); + REQUIRE(integrate(p17, l18) == Catch::Approx(-49370451351776632471. / 4384514598750000000000.)); + REQUIRE(integrate(p18, l18) == Catch::Approx(-3041981344499113218848083. / 194789368573800000000000000.)); + REQUIRE(integrate(p19, l18) != Catch::Approx(6741839335620301740899793. / 892784605963250000000000000.)); + } + + SECTION("degree 19") + { + const QuadratureFormula<3>& l19 = QuadratureManager::instance().getPyramidFormula(GaussQuadratureDescriptor(19)); + + REQUIRE(l19.numberOfPoints() == 418); + + REQUIRE(integrate(p0, l19) == Catch::Approx(16. / 3)); + REQUIRE(integrate(p1, l19) == Catch::Approx(-1)); + REQUIRE(integrate(p2, l19) == Catch::Approx(-64. / 15)); + REQUIRE(integrate(p3, l19) == Catch::Approx(83. / 5)); + REQUIRE(integrate(p4, l19) == Catch::Approx(26809. / 3150)); + REQUIRE(integrate(p5, l19) == Catch::Approx(42881. / 63000)); + REQUIRE(integrate(p6, l19) == Catch::Approx(-59509. / 1290987)); + REQUIRE(integrate(p7, l19) == Catch::Approx(-79258447. / 64549350)); + REQUIRE(integrate(p8, l19) == Catch::Approx(-64936890181. / 56803428000)); + REQUIRE(integrate(p9, l19) == Catch::Approx(-46104457917. / 31557460000)); + REQUIRE(integrate(p10, l19) == Catch::Approx(14564160020837. / 73844456400000)); + REQUIRE(integrate(p11, l19) == Catch::Approx(70717900459291. / 1723037316000000)); + REQUIRE(integrate(p12, l19) == Catch::Approx(4088535221940569. / 129227798700000000)); + REQUIRE(integrate(p13, l19) == Catch::Approx(4202215015498883. / 129227798700000000)); + REQUIRE(integrate(p14, l19) == Catch::Approx(-13139133580740403. / 4992892222500000000.)); + REQUIRE(integrate(p15, l19) == Catch::Approx(50695835504084747233. / 3295308866850000000000.)); + REQUIRE(integrate(p16, l19) == Catch::Approx(7438848232461834482681. / 834811579602000000000000.)); + REQUIRE(integrate(p17, l19) == Catch::Approx(-49370451351776632471. / 4384514598750000000000.)); + REQUIRE(integrate(p18, l19) == Catch::Approx(-3041981344499113218848083. / 194789368573800000000000000.)); + REQUIRE(integrate(p19, l19) == Catch::Approx(6741839335620301740899793. / 892784605963250000000000000.)); + REQUIRE(integrate(p20, l19) != Catch::Approx(50574805739660969727328017511. / 4928171024917140000000000000000.)); + } + + SECTION("degree 20") + { + const QuadratureFormula<3>& l20 = QuadratureManager::instance().getPyramidFormula(GaussQuadratureDescriptor(20)); + + REQUIRE(l20.numberOfPoints() == 489); + + REQUIRE(integrate(p0, l20) == Catch::Approx(16. / 3)); + REQUIRE(integrate(p1, l20) == Catch::Approx(-1)); + REQUIRE(integrate(p2, l20) == Catch::Approx(-64. / 15)); + REQUIRE(integrate(p3, l20) == Catch::Approx(83. / 5)); + REQUIRE(integrate(p4, l20) == Catch::Approx(26809. / 3150)); + REQUIRE(integrate(p5, l20) == Catch::Approx(42881. / 63000)); + REQUIRE(integrate(p6, l20) == Catch::Approx(-59509. / 1290987)); + REQUIRE(integrate(p7, l20) == Catch::Approx(-79258447. / 64549350)); + REQUIRE(integrate(p8, l20) == Catch::Approx(-64936890181. / 56803428000)); + REQUIRE(integrate(p9, l20) == Catch::Approx(-46104457917. / 31557460000)); + REQUIRE(integrate(p10, l20) == Catch::Approx(14564160020837. / 73844456400000)); + REQUIRE(integrate(p11, l20) == Catch::Approx(70717900459291. / 1723037316000000)); + REQUIRE(integrate(p12, l20) == Catch::Approx(4088535221940569. / 129227798700000000)); + REQUIRE(integrate(p13, l20) == Catch::Approx(4202215015498883. / 129227798700000000)); + REQUIRE(integrate(p14, l20) == Catch::Approx(-13139133580740403. / 4992892222500000000.)); + REQUIRE(integrate(p15, l20) == Catch::Approx(50695835504084747233. / 3295308866850000000000.)); + REQUIRE(integrate(p16, l20) == Catch::Approx(7438848232461834482681. / 834811579602000000000000.)); + REQUIRE(integrate(p17, l20) == Catch::Approx(-49370451351776632471. / 4384514598750000000000.)); + REQUIRE(integrate(p18, l20) == Catch::Approx(-3041981344499113218848083. / 194789368573800000000000000.)); + REQUIRE(integrate(p19, l20) == Catch::Approx(6741839335620301740899793. / 892784605963250000000000000.)); + REQUIRE(integrate(p20, l20) == Catch::Approx(50574805739660969727328017511. / 4928171024917140000000000000000.)); + REQUIRE(integrate(p21, l20) != Catch::Approx(796248143552124247176376796357. / 110883848060635650000000000000000.)); + } + + SECTION("max implemented degree") + { + REQUIRE(QuadratureManager::instance().maxPyramidDegree(QuadratureType::Gauss) == + PyramidGaussQuadrature::max_degree); + } +} diff --git a/tests/test_PyramidTransformation.cpp b/tests/test_PyramidTransformation.cpp new file mode 100644 index 0000000000000000000000000000000000000000..23b7369e625b20307ddab31d222b1b2ae3d607b4 --- /dev/null +++ b/tests/test_PyramidTransformation.cpp @@ -0,0 +1,98 @@ +#include <catch2/catch_approx.hpp> +#include <catch2/catch_test_macros.hpp> + +#include <analysis/GaussLegendreQuadratureDescriptor.hpp> +#include <analysis/GaussQuadratureDescriptor.hpp> +#include <analysis/QuadratureManager.hpp> +#include <geometry/CubeTransformation.hpp> +#include <geometry/PyramidTransformation.hpp> + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("PyramidTransformation", "[geometry]") +{ + using R3 = TinyVector<3>; + + const R3 a_hat = {-1, -1, +0}; + const R3 b_hat = {+1, -1, +0}; + const R3 c_hat = {+1, +1, +0}; + const R3 d_hat = {-1, +1, +0}; + const R3 e_hat = {+0, +0, +1}; + + const R3 m_hat = {0, 0, 1. / 5}; + + const R3 a = {1, 2, 0}; + const R3 b = {3, 1, 3}; + const R3 c = {2, 5, 2}; + const R3 d = {0, 3, 1}; + const R3 e = {1, 2, 5}; + + const PyramidTransformation t(a, b, c, d, e); + + SECTION("points") + { + REQUIRE(l2Norm(t(a_hat) - a) == Catch::Approx(0)); + REQUIRE(l2Norm(t(b_hat) - b) == Catch::Approx(0)); + REQUIRE(l2Norm(t(c_hat) - c) == Catch::Approx(0)); + REQUIRE(l2Norm(t(d_hat) - d) == Catch::Approx(0)); + REQUIRE(l2Norm(t(e_hat) - e) == Catch::Approx(0)); + + R3 m = (1. / 5) * (a + b + c + d + e); + REQUIRE(l2Norm(t(m_hat) - m) == Catch::Approx(0).margin(1E-14)); + } + + SECTION("Jacobian determinant") + { + SECTION("at points") + { + auto detJ = [](const R3 X) { + const double& x = X[0]; + const double& y = X[1]; + + return (43 * x + 13 * y + 93) / 16; + }; + + REQUIRE(t.jacobianDeterminant(a_hat) == Catch::Approx(detJ(a_hat))); + REQUIRE(t.jacobianDeterminant(b_hat) == Catch::Approx(detJ(b_hat))); + REQUIRE(t.jacobianDeterminant(c_hat) == Catch::Approx(detJ(c_hat))); + REQUIRE(t.jacobianDeterminant(d_hat) == Catch::Approx(detJ(d_hat))); + REQUIRE(t.jacobianDeterminant(e_hat) == Catch::Approx(detJ(e_hat))); + + REQUIRE(t.jacobianDeterminant(m_hat) == Catch::Approx(detJ(m_hat))); + } + + SECTION("volume calculation") + { + // The jacobian determinant is a degree 1 polynomial + const QuadratureFormula<3>& gauss = QuadratureManager::instance().getPyramidFormula(GaussQuadratureDescriptor(1)); + + double volume = 0; + for (size_t i = 0; i < gauss.numberOfPoints(); ++i) { + volume += gauss.weight(i) * t.jacobianDeterminant(gauss.point(i)); + } + + // 31 / 4 is actually the volume of the pyramid + REQUIRE(volume == Catch::Approx(31. / 4)); + } + + SECTION("exact polynomial integration") + { + auto p = [](const R3& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + + return 3 * x * x + 2 * y * y + 3 * z * z + 4 * x + 3 * y + 2 * z + 1; + }; + + // 4 is the minimum quadrature rule to integrate the polynomial on the pyramid + const QuadratureFormula<3>& gauss = QuadratureManager::instance().getPyramidFormula(GaussQuadratureDescriptor(4)); + double integral = 0; + for (size_t i = 0; i < gauss.numberOfPoints(); ++i) { + integral += gauss.weight(i) * t.jacobianDeterminant(gauss.point(i)) * p(t(gauss.point(i))); + } + + REQUIRE(integral == Catch::Approx(213095. / 448)); + } + } +} diff --git a/tests/test_SmallArray.cpp b/tests/test_SmallArray.cpp index 9b5d482791f9df0a19c41c64cb55070c5bf8be24..251134047754e6c2b8f5012c4d1713d973fa7823 100644 --- a/tests/test_SmallArray.cpp +++ b/tests/test_SmallArray.cpp @@ -1,6 +1,8 @@ #include <catch2/catch_test_macros.hpp> #include <catch2/matchers/catch_matchers_all.hpp> +#include <algebra/TinyMatrix.hpp> +#include <algebra/TinyVector.hpp> #include <utils/PugsAssert.hpp> #include <utils/SmallArray.hpp> #include <utils/Types.hpp> @@ -281,5 +283,71 @@ TEST_CASE("SmallArray", "[utils]") REQUIRE(array[i] == std::numeric_limits<int>::max() / 2); } } + + SECTION("checking for SmallArray reductions") + { + SmallArray<int> a(10); + a[0] = 13; + a[1] = 1; + a[2] = 8; + a[3] = -3; + a[4] = 23; + a[5] = -1; + a[6] = 13; + a[7] = 0; + a[8] = 12; + a[9] = 9; + + SECTION("Min") + { + REQUIRE(min(a) == -3); + } + + SECTION("Max") + { + REQUIRE(max(a) == 23); + } + + SECTION("Sum") + { + REQUIRE((sum(a) == 75)); + } + + SECTION("TinyVector Sum") + { + using N2 = TinyVector<2, int>; + SmallArray<N2> b(10); + b[0] = {13, 2}; + b[1] = {1, 3}; + b[2] = {8, -2}; + b[3] = {-3, 2}; + b[4] = {23, 4}; + b[5] = {-1, -3}; + b[6] = {13, 17}; + b[7] = {0, 9}; + b[8] = {12, 13}; + b[9] = {9, -17}; + + REQUIRE((sum(b) == N2{75, 28})); + } + + SECTION("TinyMatrix Sum") + { + using N22 = TinyMatrix<2, 2, int>; + SmallArray<N22> b(10); + b[0] = {13, 2, 0, 1}; + b[1] = {1, 3, 6, 3}; + b[2] = {8, -2, -1, 21}; + b[3] = {-3, 2, 5, 12}; + b[4] = {23, 4, 7, 1}; + b[5] = {-1, -3, 33, 11}; + b[6] = {13, 17, 12, 13}; + b[7] = {0, 9, 1, 14}; + b[8] = {12, 13, -3, -71}; + b[9] = {9, -17, 0, 16}; + + REQUIRE((sum(b) == N22{75, 28, 60, 21})); + } + } #endif // NDEBUG } diff --git a/tests/test_SquareGaussQuadrature.cpp b/tests/test_SquareGaussQuadrature.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5e6b9d6e5ee066cd8db48c6a2297bfc3d12cfcd8 --- /dev/null +++ b/tests/test_SquareGaussQuadrature.cpp @@ -0,0 +1,480 @@ +#include <catch2/catch_approx.hpp> +#include <catch2/catch_test_macros.hpp> +#include <catch2/matchers/catch_matchers_all.hpp> + +#include <algebra/TinyMatrix.hpp> + +#include <analysis/GaussQuadratureDescriptor.hpp> +#include <analysis/QuadratureManager.hpp> +#include <analysis/SquareGaussQuadrature.hpp> +#include <utils/Exceptions.hpp> + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("SquareGaussQuadrature", "[analysis]") +{ + auto integrate = [](auto f, auto quadrature_formula) { + auto point_list = quadrature_formula.pointList(); + auto weight_list = quadrature_formula.weightList(); + + auto value = weight_list[0] * f(point_list[0]); + for (size_t i = 1; i < weight_list.size(); ++i) { + value += weight_list[i] * f(point_list[i]); + } + + return value; + }; + + auto integrate_on_rectangle = [](auto f, auto quadrature_formula, const std::array<TinyVector<2>, 3>& triangle) { + const auto& A = triangle[0]; + const auto& B = triangle[1]; + const auto& C = triangle[2]; + + TinyMatrix<2> J; + for (size_t i = 0; i < 2; ++i) { + J(i, 0) = 0.5 * (B[i] - A[i]); + J(i, 1) = 0.5 * (C[i] - A[i]); + } + TinyVector s = 0.5 * (B + C); + + auto point_list = quadrature_formula.pointList(); + auto weight_list = quadrature_formula.weightList(); + + auto value = weight_list[0] * f(J * (point_list[0]) + s); + for (size_t i = 1; i < weight_list.size(); ++i) { + value += weight_list[i] * f(J * (point_list[i]) + s); + } + + return det(J) * value; + }; + + auto get_order = [&integrate, &integrate_on_rectangle](auto f, auto quadrature_formula, const double exact_value) { + using R2 = TinyVector<2>; + const double int_K_hat = integrate(f, quadrature_formula); + const double int_refined // + = integrate_on_rectangle(f, quadrature_formula, {R2{-1, -1}, R2{0, -1}, R2{-1, 0}}) + + integrate_on_rectangle(f, quadrature_formula, {R2{0, -1}, R2{1, -1}, R2{0, 0}}) + + integrate_on_rectangle(f, quadrature_formula, {R2{-1, 0}, R2{0, 0}, R2{-1, 1}}) + + integrate_on_rectangle(f, quadrature_formula, {R2{0, 0}, R2{1, 0}, R2{0, 1}}); + + return -std::log((int_refined - exact_value) / (int_K_hat - exact_value)) / std::log(2); + }; + + auto p0 = [](const TinyVector<2>&) { return 2; }; + auto p1 = [](const TinyVector<2>& X) { + const double x = X[0]; + const double y = X[1]; + return 2 * x + 3 * y + 1; + }; + auto p2 = [&p1](const TinyVector<2>& X) { + const double x = X[0]; + const double y = X[1]; + return p1(X) * (2.5 * x - 3 * y + 3); + }; + auto p3 = [&p2](const TinyVector<2>& X) { + const double x = X[0]; + const double y = X[1]; + return p2(X) * (-1.5 * x + 3 * y - 3); + }; + auto p4 = [&p3](const TinyVector<2>& X) { + const double x = X[0]; + const double y = X[1]; + return p3(X) * (x + y + 1); + }; + auto p5 = [&p4](const TinyVector<2>& X) { + const double x = X[0]; + const double y = X[1]; + return p4(X) * (-0.2 * x - 1.3 * y - 0.7); + }; + auto p6 = [&p5](const TinyVector<2>& X) { + const double x = X[0]; + const double y = X[1]; + return p5(X) * (3 * x - 2 * y + 3); + }; + auto p7 = [&p6](const TinyVector<2>& X) { + const double x = X[0]; + const double y = X[1]; + return p6(X) * (-2 * x + 4 * y - 7); + }; + auto p8 = [&p7](const TinyVector<2>& X) { + const double x = X[0]; + 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") + { + const QuadratureFormula<2>& l1 = QuadratureManager::instance().getSquareFormula(GaussQuadratureDescriptor(1)); + + REQUIRE(l1.numberOfPoints() == 1); + + REQUIRE(integrate(p0, l1) == Catch::Approx(8)); + REQUIRE(integrate(p1, l1) == Catch::Approx(4)); + REQUIRE(integrate(p2, l1) != Catch::Approx(20. / 3)); + + REQUIRE(get_order(p2, l1, 20. / 3) == Catch::Approx(2)); + } + + SECTION("degree 2 and 3") + { + const QuadratureFormula<2>& l2 = QuadratureManager::instance().getSquareFormula(GaussQuadratureDescriptor(2)); + const QuadratureFormula<2>& l3 = QuadratureManager::instance().getSquareFormula(GaussQuadratureDescriptor(3)); + + REQUIRE(&l2 == &l3); + + REQUIRE(l3.numberOfPoints() == 4); + + REQUIRE(integrate(p0, l3) == Catch::Approx(8)); + REQUIRE(integrate(p1, l3) == Catch::Approx(4)); + REQUIRE(integrate(p2, l3) == Catch::Approx(20. / 3)); + REQUIRE(integrate(p3, l3) == Catch::Approx(-13)); + REQUIRE(integrate(p4, l3) != Catch::Approx(-1184. / 15)); + + REQUIRE(get_order(p4, l3, -1184. / 15) == Catch::Approx(4)); + } + + SECTION("degree 4 and 5") + { + const QuadratureFormula<2>& l4 = QuadratureManager::instance().getSquareFormula(GaussQuadratureDescriptor(4)); + const QuadratureFormula<2>& l5 = QuadratureManager::instance().getSquareFormula(GaussQuadratureDescriptor(5)); + + REQUIRE(&l4 == &l5); + + REQUIRE(l5.numberOfPoints() == 8); + + REQUIRE(integrate(p0, l5) == Catch::Approx(8)); + REQUIRE(integrate(p1, l5) == Catch::Approx(4)); + REQUIRE(integrate(p2, l5) == Catch::Approx(20. / 3)); + REQUIRE(integrate(p3, l5) == Catch::Approx(-13)); + REQUIRE(integrate(p4, l5) == Catch::Approx(-1184. / 15)); + REQUIRE(integrate(p5, l5) == Catch::Approx(1971. / 25)); + REQUIRE(integrate(p6, l5) != Catch::Approx(60441. / 175)); + + REQUIRE(get_order(p6, l5, 60441. / 175) == Catch::Approx(6)); + } + + SECTION("degree 6 and 7") + { + const QuadratureFormula<2>& l6 = QuadratureManager::instance().getSquareFormula(GaussQuadratureDescriptor(6)); + const QuadratureFormula<2>& l7 = QuadratureManager::instance().getSquareFormula(GaussQuadratureDescriptor(7)); + + REQUIRE(&l6 == &l7); + + REQUIRE(l7.numberOfPoints() == 12); + + REQUIRE(integrate(p0, l7) == Catch::Approx(8)); + REQUIRE(integrate(p1, l7) == Catch::Approx(4)); + REQUIRE(integrate(p2, l7) == Catch::Approx(20. / 3)); + REQUIRE(integrate(p3, l7) == Catch::Approx(-13)); + REQUIRE(integrate(p4, l7) == Catch::Approx(-1184. / 15)); + REQUIRE(integrate(p5, l7) == Catch::Approx(1971. / 25)); + REQUIRE(integrate(p6, l7) == Catch::Approx(60441. / 175)); + REQUIRE(integrate(p7, l7) == Catch::Approx(-1307119. / 525)); + REQUIRE(integrate(p8, l7) != Catch::Approx(957697. / 175)); + + REQUIRE(get_order(p8, l7, 957697. / 175) == Catch::Approx(8)); + } + + SECTION("degree 8 and 9") + { + const QuadratureFormula<2>& l8 = QuadratureManager::instance().getSquareFormula(GaussQuadratureDescriptor(8)); + const QuadratureFormula<2>& l9 = QuadratureManager::instance().getSquareFormula(GaussQuadratureDescriptor(9)); + + REQUIRE(&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") + { + const QuadratureFormula<2>& l10 = QuadratureManager::instance().getSquareFormula(GaussQuadratureDescriptor(10)); + const QuadratureFormula<2>& l11 = QuadratureManager::instance().getSquareFormula(GaussQuadratureDescriptor(11)); + + REQUIRE(&l10 == &l11); + + REQUIRE(l11.numberOfPoints() == 28); + + 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") + { + const QuadratureFormula<2>& l12 = QuadratureManager::instance().getSquareFormula(GaussQuadratureDescriptor(12)); + const QuadratureFormula<2>& l13 = QuadratureManager::instance().getSquareFormula(GaussQuadratureDescriptor(13)); + + REQUIRE(&l12 == &l13); + + REQUIRE(l13.numberOfPoints() == 37); + + 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") + { + const QuadratureFormula<2>& l14 = QuadratureManager::instance().getSquareFormula(GaussQuadratureDescriptor(14)); + const QuadratureFormula<2>& l15 = QuadratureManager::instance().getSquareFormula(GaussQuadratureDescriptor(15)); + + REQUIRE(&l14 == &l15); + + REQUIRE(l15.numberOfPoints() == 48); + + 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") + { + const QuadratureFormula<2>& l16 = QuadratureManager::instance().getSquareFormula(GaussQuadratureDescriptor(16)); + const QuadratureFormula<2>& l17 = QuadratureManager::instance().getSquareFormula(GaussQuadratureDescriptor(17)); + + REQUIRE(&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") + { + const QuadratureFormula<2>& l18 = QuadratureManager::instance().getSquareFormula(GaussQuadratureDescriptor(18)); + const QuadratureFormula<2>& l19 = QuadratureManager::instance().getSquareFormula(GaussQuadratureDescriptor(19)); + + REQUIRE(&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.).epsilon(1E-8)); + + REQUIRE(get_order(p20, l19, -891851528496270127477. / 884086328125000000.) == Catch::Approx(20).margin(0.001)); + } + + SECTION("degree 20 and 21") + { + const QuadratureFormula<2>& l20 = QuadratureManager::instance().getSquareFormula(GaussQuadratureDescriptor(20)); + const QuadratureFormula<2>& l21 = QuadratureManager::instance().getSquareFormula(GaussQuadratureDescriptor(21)); + + REQUIRE(&l20 == &l21); + + REQUIRE(l21.numberOfPoints() == 85); + + 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("max implemented degree") + { + REQUIRE(QuadratureManager::instance().maxSquareDegree(QuadratureType::Gauss) == SquareGaussQuadrature::max_degree); + } + + SECTION("Access functions") + { + const QuadratureFormula<2>& quadrature_formula = + QuadratureManager::instance().getSquareFormula(GaussQuadratureDescriptor(7)); + + auto point_list = quadrature_formula.pointList(); + auto weight_list = quadrature_formula.weightList(); + + REQUIRE(point_list.size() == quadrature_formula.numberOfPoints()); + REQUIRE(weight_list.size() == quadrature_formula.numberOfPoints()); + + for (size_t i = 0; i < quadrature_formula.numberOfPoints(); ++i) { + REQUIRE(&point_list[i] == &quadrature_formula.point(i)); + REQUIRE(&weight_list[i] == &quadrature_formula.weight(i)); + } + } +} diff --git a/tests/test_SquareTransformation.cpp b/tests/test_SquareTransformation.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a1ead02fc75d25f5ff0194b4157e22497d6005dc --- /dev/null +++ b/tests/test_SquareTransformation.cpp @@ -0,0 +1,273 @@ +#include <catch2/catch_approx.hpp> +#include <catch2/catch_test_macros.hpp> + +#include <analysis/GaussLegendreQuadratureDescriptor.hpp> +#include <analysis/GaussLobattoQuadratureDescriptor.hpp> +#include <analysis/GaussQuadratureDescriptor.hpp> +#include <analysis/QuadratureManager.hpp> +#include <geometry/SquareTransformation.hpp> + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("SquareTransformation", "[geometry]") +{ + SECTION("2D") + { + using R2 = TinyVector<2>; + + const R2 a_hat = {-1, -1}; + const R2 b_hat = {+1, -1}; + const R2 c_hat = {+1, +1}; + const R2 d_hat = {-1, +1}; + + const R2 m_hat = zero; + + const R2 a = {0, 0}; + const R2 b = {8, -2}; + const R2 c = {12, 7}; + const R2 d = {3, 7}; + + const R2 m = 0.25 * (a + b + c + d); + + const SquareTransformation<2> t(a, b, c, d); + + SECTION("values") + { + REQUIRE(t(a_hat)[0] == Catch::Approx(a[0])); + REQUIRE(t(a_hat)[1] == Catch::Approx(a[1])); + + REQUIRE(t(b_hat)[0] == Catch::Approx(b[0])); + REQUIRE(t(b_hat)[1] == Catch::Approx(b[1])); + + REQUIRE(t(c_hat)[0] == Catch::Approx(c[0])); + REQUIRE(t(c_hat)[1] == Catch::Approx(c[1])); + + REQUIRE(t(d_hat)[0] == Catch::Approx(d[0])); + REQUIRE(t(d_hat)[1] == Catch::Approx(d[1])); + + REQUIRE(t(m_hat)[0] == Catch::Approx(m[0])); + REQUIRE(t(m_hat)[1] == Catch::Approx(m[1])); + } + + SECTION("Jacobian determinant") + { + SECTION("at points") + { + auto detJ = [](const R2& X) { + const double x = X[0]; + const double y = X[1]; + + return 0.25 * ((0.5 * x + 4) * (y + 17) - 0.5 * (x + 7) * (y - 1)); + }; + + REQUIRE(t.jacobianDeterminant(a_hat) == Catch::Approx(detJ(a_hat))); + REQUIRE(t.jacobianDeterminant(b_hat) == Catch::Approx(detJ(b_hat))); + REQUIRE(t.jacobianDeterminant(c_hat) == Catch::Approx(detJ(c_hat))); + REQUIRE(t.jacobianDeterminant(d_hat) == Catch::Approx(detJ(d_hat))); + + REQUIRE(t.jacobianDeterminant(m_hat) == Catch::Approx(detJ(m_hat))); + } + + SECTION("Gauss order 1") + { + // One point is enough in 2d + const QuadratureFormula<2>& gauss = + QuadratureManager::instance().getSquareFormula(GaussLegendreQuadratureDescriptor(1)); + + double surface = 0; + for (size_t i = 0; i < gauss.numberOfPoints(); ++i) { + surface += gauss.weight(i) * t.jacobianDeterminant(gauss.point(i)); + } + + // 71.5 is actually the surface of the quadrangle + REQUIRE(surface == Catch::Approx(71.5)); + } + + SECTION("Gauss order 3") + { + auto p = [](const R2& X) { + const double& x = X[0]; + const double& y = X[1]; + + return (2 * x + 3 * y + 2) * (x - 2 * y - 1); + }; + + // Jacbian determinant is a degree 1 polynomial, so the + // following formula is required to reach exactness + const QuadratureFormula<2>& gauss = + QuadratureManager::instance().getSquareFormula(GaussLegendreQuadratureDescriptor(3)); + + double integral = 0; + for (size_t i = 0; i < gauss.numberOfPoints(); ++i) { + integral += gauss.weight(i) * t.jacobianDeterminant(gauss.point(i)) * p(t(gauss.point(i))); + } + + REQUIRE(integral == Catch::Approx(-76277. / 24)); + } + } + } + + SECTION("degenerate 2D ") + { + SECTION("2D") + { + using R2 = TinyVector<2>; + + const R2 a = {1, 2}; + const R2 b = {3, 1}; + const R2 c = {2, 5}; + + const SquareTransformation<2> t(a, b, c, c); + + auto p = [](const R2& X) { + const double x = X[0]; + const double y = X[1]; + return 2 * x * x + 3 * x * y + y * y + 3 * y + 1; + }; + + SECTION("Gauss") + { + QuadratureFormula<2> qf = QuadratureManager::instance().getSquareFormula(GaussQuadratureDescriptor(2)); + + double sum = 0; + for (size_t i = 0; i < qf.numberOfPoints(); ++i) { + R2 xi = qf.point(i); + sum += qf.weight(i) * t.jacobianDeterminant(xi) * p(t(xi)); + } + + REQUIRE(sum == Catch::Approx(3437. / 24)); + } + + SECTION("Gauss Legendre") + { + QuadratureFormula<2> qf = QuadratureManager::instance().getSquareFormula(GaussLegendreQuadratureDescriptor(2)); + + double sum = 0; + for (size_t i = 0; i < qf.numberOfPoints(); ++i) { + R2 xi = qf.point(i); + sum += qf.weight(i) * t.jacobianDeterminant(xi) * p(t(xi)); + } + + REQUIRE(sum == Catch::Approx(3437. / 24)); + } + + SECTION("Gauss Lobatto") + { + QuadratureFormula<2> qf = QuadratureManager::instance().getSquareFormula(GaussLobattoQuadratureDescriptor(2)); + + double sum = 0; + for (size_t i = 0; i < qf.numberOfPoints(); ++i) { + R2 xi = qf.point(i); + sum += qf.weight(i) * t.jacobianDeterminant(xi) * p(t(xi)); + } + + REQUIRE(sum == Catch::Approx(3437. / 24)); + } + } + } + + SECTION("3D") + { + using R2 = TinyVector<2>; + + const R2 a_hat = {-1, -1}; + const R2 b_hat = {+1, -1}; + const R2 c_hat = {+1, +1}; + const R2 d_hat = {-1, +1}; + + const R2 m_hat = zero; + + using R3 = TinyVector<3>; + + const R3 a = {0, 0, -1}; + const R3 b = {8, -2, 3}; + const R3 c = {12, 7, 2}; + const R3 d = {3, 7, 1}; + + const R3 m = 0.25 * (a + b + c + d); + + const SquareTransformation<3> t(a, b, c, d); + + SECTION("values") + { + REQUIRE(t(a_hat)[0] == Catch::Approx(a[0])); + REQUIRE(t(a_hat)[1] == Catch::Approx(a[1])); + REQUIRE(t(a_hat)[2] == Catch::Approx(a[2])); + + REQUIRE(t(b_hat)[0] == Catch::Approx(b[0])); + REQUIRE(t(b_hat)[1] == Catch::Approx(b[1])); + REQUIRE(t(b_hat)[2] == Catch::Approx(b[2])); + + REQUIRE(t(c_hat)[0] == Catch::Approx(c[0])); + REQUIRE(t(c_hat)[1] == Catch::Approx(c[1])); + REQUIRE(t(c_hat)[2] == Catch::Approx(c[2])); + + REQUIRE(t(d_hat)[0] == Catch::Approx(d[0])); + REQUIRE(t(d_hat)[1] == Catch::Approx(d[1])); + REQUIRE(t(d_hat)[2] == Catch::Approx(d[2])); + + REQUIRE(t(m_hat)[0] == Catch::Approx(m[0])); + REQUIRE(t(m_hat)[1] == Catch::Approx(m[1])); + REQUIRE(t(m_hat)[2] == Catch::Approx(m[2])); + } + + SECTION("Area variation norm") + { + auto area_variation_norm = [&](const R2& X) { + const double x = X[0]; + const double y = X[1]; + + const R3 J1 = 0.25 * (-a + b + c - d); + const R3 J2 = 0.25 * (-a - b + c + d); + const R3 J3 = 0.25 * (a - b + c - d); + + return l2Norm(crossProduct(J1 + y * J3, J2 + x * J3)); + }; + + SECTION("at points") + { + REQUIRE(t.areaVariationNorm(a_hat) == Catch::Approx(area_variation_norm(a_hat))); + REQUIRE(t.areaVariationNorm(b_hat) == Catch::Approx(area_variation_norm(b_hat))); + REQUIRE(t.areaVariationNorm(c_hat) == Catch::Approx(area_variation_norm(c_hat))); + REQUIRE(t.areaVariationNorm(d_hat) == Catch::Approx(area_variation_norm(d_hat))); + + REQUIRE(t.areaVariationNorm(m_hat) == Catch::Approx(area_variation_norm(m_hat))); + } + + auto p = [](const R3& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return 2 * x * x + 3 * x - 3 * y * y + y + 2 * z * z - 0.5 * z + 2; + }; + + SECTION("Gauss order 3") + { + // Due to the area variation term (square root of a + // polynomial), Gauss-like quadrature cannot be exact for + // general 3d quadrangle. + // + // Moreover, even the surface of general 3d quadrangle cannot + // be computed exactly. + // + // So for this test we integrate the following function: + // f(x,y,z) := p(x,y,z) * |dA(t^-1(x,y,z))| + // + // dA denotes the area change on the reference element. This + // function can be exactly integrated since computing the + // integral on the reference quadrangle, one gets a dA^2, + // which is a polynomial. + const QuadratureFormula<2>& gauss = + QuadratureManager::instance().getSquareFormula(GaussLegendreQuadratureDescriptor(4)); + + double integral = 0; + for (size_t i = 0; i < gauss.numberOfPoints(); ++i) { + const double fX = (t.areaVariationNorm(gauss.point(i)) * p(t(gauss.point(i)))); + integral += gauss.weight(i) * t.areaVariationNorm(gauss.point(i)) * fX; + } + + REQUIRE(integral == Catch::Approx(60519715. / 576)); + } + } + } +} diff --git a/tests/test_SubItemArrayPerItem.cpp b/tests/test_SubItemArrayPerItem.cpp index d1cb315046b5450e975b7ced5e795103bb6453ad..c72f98b76de01f6562aac21c5cc008716606a0a5 100644 --- a/tests/test_SubItemArrayPerItem.cpp +++ b/tests/test_SubItemArrayPerItem.cpp @@ -64,457 +64,483 @@ TEST_CASE("SubItemArrayPerItem", "[mesh]") SECTION("1D") { - const Mesh<Connectivity<1>>& mesh_1d = *MeshDataBaseForTests::get().cartesianMesh1D(); - const Connectivity<1>& connectivity = mesh_1d.connectivity(); + std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - SECTION("per cell") - { - NodeArrayPerCell<int> node_array_per_cell{connectivity, 3}; - REQUIRE(node_array_per_cell.numberOfItems() == connectivity.numberOfCells()); - REQUIRE(node_array_per_cell.numberOfArrays() == number_of_arrays(node_array_per_cell)); - REQUIRE(node_array_per_cell.sizeOfArrays() == 3); - - auto cell_to_node_matrix = connectivity.cellToNodeMatrix(); - { - bool is_correct = true; - for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { - is_correct &= - (cell_to_node_matrix[cell_id].size() == node_array_per_cell.numberOfSubArrays(cell_id)) and - (node_array_per_cell.itemTable(cell_id).numberOfRows() == node_array_per_cell.numberOfSubArrays(cell_id)); - } - REQUIRE(is_correct); - } - - const NodeArrayPerCell<const int> const_node_array_per_cell = node_array_per_cell; + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) { - bool is_correct = true; - for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { - is_correct &= (const_node_array_per_cell.itemTable(cell_id).numberOfRows() == - node_array_per_cell.numberOfSubArrays(cell_id)); - } - REQUIRE(is_correct); - } - - EdgeArrayPerCell<int> edge_array_per_cell{connectivity, 4}; - REQUIRE(edge_array_per_cell.numberOfItems() == connectivity.numberOfCells()); - REQUIRE(edge_array_per_cell.numberOfArrays() == number_of_arrays(edge_array_per_cell)); - REQUIRE(edge_array_per_cell.sizeOfArrays() == 4); + auto mesh_1d = named_mesh.mesh(); + + const Connectivity<1>& connectivity = mesh_1d->connectivity(); + + SECTION("per cell") + { + NodeArrayPerCell<int> node_array_per_cell{connectivity, 3}; + REQUIRE(node_array_per_cell.numberOfItems() == connectivity.numberOfCells()); + REQUIRE(node_array_per_cell.numberOfArrays() == number_of_arrays(node_array_per_cell)); + REQUIRE(node_array_per_cell.sizeOfArrays() == 3); + + auto cell_to_node_matrix = connectivity.cellToNodeMatrix(); + { + bool is_correct = true; + for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { + is_correct &= + (cell_to_node_matrix[cell_id].size() == node_array_per_cell.numberOfSubArrays(cell_id)) and + (node_array_per_cell.itemTable(cell_id).numberOfRows() == + node_array_per_cell.numberOfSubArrays(cell_id)); + } + REQUIRE(is_correct); + } - auto cell_to_edge_matrix = connectivity.cellToEdgeMatrix(); - { - bool is_correct = true; - for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { - is_correct &= (cell_to_edge_matrix[cell_id].size() == edge_array_per_cell.numberOfSubArrays(cell_id)); - } - REQUIRE(is_correct); - } + const NodeArrayPerCell<const int> const_node_array_per_cell = node_array_per_cell; + { + bool is_correct = true; + for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { + is_correct &= (const_node_array_per_cell.itemTable(cell_id).numberOfRows() == + node_array_per_cell.numberOfSubArrays(cell_id)); + } + REQUIRE(is_correct); + } - FaceArrayPerCell<int> face_array_per_cell{connectivity, 2}; - REQUIRE(face_array_per_cell.numberOfItems() == connectivity.numberOfCells()); - REQUIRE(face_array_per_cell.numberOfArrays() == number_of_arrays(face_array_per_cell)); - REQUIRE(face_array_per_cell.sizeOfArrays() == 2); + EdgeArrayPerCell<int> edge_array_per_cell{connectivity, 4}; + REQUIRE(edge_array_per_cell.numberOfItems() == connectivity.numberOfCells()); + REQUIRE(edge_array_per_cell.numberOfArrays() == number_of_arrays(edge_array_per_cell)); + REQUIRE(edge_array_per_cell.sizeOfArrays() == 4); + + auto cell_to_edge_matrix = connectivity.cellToEdgeMatrix(); + { + bool is_correct = true; + for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { + is_correct &= (cell_to_edge_matrix[cell_id].size() == edge_array_per_cell.numberOfSubArrays(cell_id)); + } + REQUIRE(is_correct); + } - auto cell_to_face_matrix = connectivity.cellToFaceMatrix(); - { - bool is_correct = true; - for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { - is_correct &= (cell_to_face_matrix[cell_id].size() == face_array_per_cell.numberOfSubArrays(cell_id)); + FaceArrayPerCell<int> face_array_per_cell{connectivity, 2}; + REQUIRE(face_array_per_cell.numberOfItems() == connectivity.numberOfCells()); + REQUIRE(face_array_per_cell.numberOfArrays() == number_of_arrays(face_array_per_cell)); + REQUIRE(face_array_per_cell.sizeOfArrays() == 2); + + auto cell_to_face_matrix = connectivity.cellToFaceMatrix(); + { + bool is_correct = true; + for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { + is_correct &= (cell_to_face_matrix[cell_id].size() == face_array_per_cell.numberOfSubArrays(cell_id)); + } + REQUIRE(is_correct); + } } - REQUIRE(is_correct); - } - } - SECTION("per face") - { - CellArrayPerFace<int> cell_array_per_face{connectivity, 2}; - REQUIRE(cell_array_per_face.numberOfItems() == connectivity.numberOfFaces()); - REQUIRE(cell_array_per_face.numberOfArrays() == number_of_arrays(cell_array_per_face)); - REQUIRE(cell_array_per_face.sizeOfArrays() == 2); - - auto face_to_cell_matrix = connectivity.faceToCellMatrix(); - { - bool is_correct = true; - for (FaceId face_id = 0; face_id < connectivity.numberOfFaces(); ++face_id) { - is_correct &= (face_to_cell_matrix[face_id].size() == cell_array_per_face.numberOfSubArrays(face_id)); + SECTION("per face") + { + CellArrayPerFace<int> cell_array_per_face{connectivity, 2}; + REQUIRE(cell_array_per_face.numberOfItems() == connectivity.numberOfFaces()); + REQUIRE(cell_array_per_face.numberOfArrays() == number_of_arrays(cell_array_per_face)); + REQUIRE(cell_array_per_face.sizeOfArrays() == 2); + + auto face_to_cell_matrix = connectivity.faceToCellMatrix(); + { + bool is_correct = true; + for (FaceId face_id = 0; face_id < connectivity.numberOfFaces(); ++face_id) { + is_correct &= (face_to_cell_matrix[face_id].size() == cell_array_per_face.numberOfSubArrays(face_id)); + } + REQUIRE(is_correct); + } } - REQUIRE(is_correct); - } - } - - SECTION("per edge") - { - CellArrayPerEdge<int> cell_array_per_edge{connectivity, 3}; - REQUIRE(cell_array_per_edge.numberOfItems() == connectivity.numberOfEdges()); - REQUIRE(cell_array_per_edge.numberOfArrays() == number_of_arrays(cell_array_per_edge)); - REQUIRE(cell_array_per_edge.sizeOfArrays() == 3); - auto edge_to_cell_matrix = connectivity.edgeToCellMatrix(); - { - bool is_correct = true; - for (EdgeId edge_id = 0; edge_id < connectivity.numberOfEdges(); ++edge_id) { - is_correct &= (edge_to_cell_matrix[edge_id].size() == cell_array_per_edge.numberOfSubArrays(edge_id)); + SECTION("per edge") + { + CellArrayPerEdge<int> cell_array_per_edge{connectivity, 3}; + REQUIRE(cell_array_per_edge.numberOfItems() == connectivity.numberOfEdges()); + REQUIRE(cell_array_per_edge.numberOfArrays() == number_of_arrays(cell_array_per_edge)); + REQUIRE(cell_array_per_edge.sizeOfArrays() == 3); + + auto edge_to_cell_matrix = connectivity.edgeToCellMatrix(); + { + bool is_correct = true; + for (EdgeId edge_id = 0; edge_id < connectivity.numberOfEdges(); ++edge_id) { + is_correct &= (edge_to_cell_matrix[edge_id].size() == cell_array_per_edge.numberOfSubArrays(edge_id)); + } + REQUIRE(is_correct); + } } - REQUIRE(is_correct); - } - } - - SECTION("per node") - { - CellArrayPerNode<int> cell_array_per_node{connectivity, 4}; - REQUIRE(cell_array_per_node.numberOfItems() == connectivity.numberOfNodes()); - REQUIRE(cell_array_per_node.numberOfArrays() == number_of_arrays(cell_array_per_node)); - REQUIRE(cell_array_per_node.sizeOfArrays() == 4); - auto node_to_cell_matrix = connectivity.nodeToCellMatrix(); - { - bool is_correct = true; - for (NodeId node_id = 0; node_id < connectivity.numberOfNodes(); ++node_id) { - is_correct &= (node_to_cell_matrix[node_id].size() == cell_array_per_node.numberOfSubArrays(node_id)); + SECTION("per node") + { + CellArrayPerNode<int> cell_array_per_node{connectivity, 4}; + REQUIRE(cell_array_per_node.numberOfItems() == connectivity.numberOfNodes()); + REQUIRE(cell_array_per_node.numberOfArrays() == number_of_arrays(cell_array_per_node)); + REQUIRE(cell_array_per_node.sizeOfArrays() == 4); + + auto node_to_cell_matrix = connectivity.nodeToCellMatrix(); + { + bool is_correct = true; + for (NodeId node_id = 0; node_id < connectivity.numberOfNodes(); ++node_id) { + is_correct &= (node_to_cell_matrix[node_id].size() == cell_array_per_node.numberOfSubArrays(node_id)); + } + REQUIRE(is_correct); + } } - REQUIRE(is_correct); } } } SECTION("2D") { - const Mesh<Connectivity<2>>& mesh_2d = *MeshDataBaseForTests::get().cartesianMesh2D(); - const Connectivity<2>& connectivity = mesh_2d.connectivity(); - - SECTION("per cell") - { - NodeArrayPerCell<int> node_array_per_cell{connectivity, 5}; - REQUIRE(node_array_per_cell.numberOfItems() == connectivity.numberOfCells()); - REQUIRE(node_array_per_cell.numberOfArrays() == number_of_arrays(node_array_per_cell)); - REQUIRE(node_array_per_cell.sizeOfArrays() == 5); + std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - auto cell_to_node_matrix = connectivity.cellToNodeMatrix(); + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) { - bool is_correct = true; - for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { - is_correct &= (cell_to_node_matrix[cell_id].size() == node_array_per_cell.numberOfSubArrays(cell_id)); - } - REQUIRE(is_correct); - } - - EdgeArrayPerCell<int> edge_array_per_cell{connectivity, 4}; - REQUIRE(edge_array_per_cell.numberOfItems() == connectivity.numberOfCells()); - REQUIRE(edge_array_per_cell.numberOfArrays() == number_of_arrays(edge_array_per_cell)); - REQUIRE(edge_array_per_cell.sizeOfArrays() == 4); - - auto cell_to_edge_matrix = connectivity.cellToEdgeMatrix(); - { - bool is_correct = true; - for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { - is_correct &= (cell_to_edge_matrix[cell_id].size() == edge_array_per_cell.numberOfSubArrays(cell_id)); - } - REQUIRE(is_correct); - } - - FaceArrayPerCell<int> face_array_per_cell{connectivity, 3}; - REQUIRE(face_array_per_cell.numberOfItems() == connectivity.numberOfCells()); - REQUIRE(face_array_per_cell.numberOfArrays() == number_of_arrays(face_array_per_cell)); - REQUIRE(face_array_per_cell.sizeOfArrays() == 3); - - auto cell_to_face_matrix = connectivity.cellToFaceMatrix(); - { - bool is_correct = true; - for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { - is_correct &= (cell_to_face_matrix[cell_id].size() == face_array_per_cell.numberOfSubArrays(cell_id)); - } - REQUIRE(is_correct); - } - } - - SECTION("per face") - { - CellArrayPerFace<int> cell_array_per_face{connectivity, 3}; - REQUIRE(cell_array_per_face.numberOfItems() == connectivity.numberOfFaces()); - REQUIRE(cell_array_per_face.numberOfArrays() == number_of_arrays(cell_array_per_face)); - REQUIRE(cell_array_per_face.sizeOfArrays() == 3); - - auto face_to_cell_matrix = connectivity.faceToCellMatrix(); - { - bool is_correct = true; - for (FaceId face_id = 0; face_id < connectivity.numberOfFaces(); ++face_id) { - is_correct &= (face_to_cell_matrix[face_id].size() == cell_array_per_face.numberOfSubArrays(face_id)); - } - REQUIRE(is_correct); - } - - NodeArrayPerFace<int> node_array_per_face{connectivity, 2}; - REQUIRE(node_array_per_face.numberOfItems() == connectivity.numberOfFaces()); - REQUIRE(node_array_per_face.numberOfArrays() == number_of_arrays(node_array_per_face)); - REQUIRE(node_array_per_face.sizeOfArrays() == 2); - - auto face_to_node_matrix = connectivity.faceToNodeMatrix(); - { - bool is_correct = true; - for (FaceId face_id = 0; face_id < connectivity.numberOfFaces(); ++face_id) { - is_correct &= (face_to_node_matrix[face_id].size() == node_array_per_face.numberOfSubArrays(face_id)); - } - REQUIRE(is_correct); - } - } + auto mesh_2d = named_mesh.mesh(); + + const Connectivity<2>& connectivity = mesh_2d->connectivity(); + + SECTION("per cell") + { + NodeArrayPerCell<int> node_array_per_cell{connectivity, 5}; + REQUIRE(node_array_per_cell.numberOfItems() == connectivity.numberOfCells()); + REQUIRE(node_array_per_cell.numberOfArrays() == number_of_arrays(node_array_per_cell)); + REQUIRE(node_array_per_cell.sizeOfArrays() == 5); + + auto cell_to_node_matrix = connectivity.cellToNodeMatrix(); + { + bool is_correct = true; + for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { + is_correct &= (cell_to_node_matrix[cell_id].size() == node_array_per_cell.numberOfSubArrays(cell_id)); + } + REQUIRE(is_correct); + } - SECTION("per edge") - { - CellArrayPerEdge<int> cell_array_per_edge{connectivity, 3}; - REQUIRE(cell_array_per_edge.numberOfItems() == connectivity.numberOfEdges()); - REQUIRE(cell_array_per_edge.numberOfArrays() == number_of_arrays(cell_array_per_edge)); - REQUIRE(cell_array_per_edge.sizeOfArrays() == 3); + EdgeArrayPerCell<int> edge_array_per_cell{connectivity, 4}; + REQUIRE(edge_array_per_cell.numberOfItems() == connectivity.numberOfCells()); + REQUIRE(edge_array_per_cell.numberOfArrays() == number_of_arrays(edge_array_per_cell)); + REQUIRE(edge_array_per_cell.sizeOfArrays() == 4); + + auto cell_to_edge_matrix = connectivity.cellToEdgeMatrix(); + { + bool is_correct = true; + for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { + is_correct &= (cell_to_edge_matrix[cell_id].size() == edge_array_per_cell.numberOfSubArrays(cell_id)); + } + REQUIRE(is_correct); + } - auto edge_to_cell_matrix = connectivity.edgeToCellMatrix(); - { - bool is_correct = true; - for (EdgeId edge_id = 0; edge_id < connectivity.numberOfEdges(); ++edge_id) { - is_correct &= (edge_to_cell_matrix[edge_id].size() == cell_array_per_edge.numberOfSubArrays(edge_id)); + FaceArrayPerCell<int> face_array_per_cell{connectivity, 3}; + REQUIRE(face_array_per_cell.numberOfItems() == connectivity.numberOfCells()); + REQUIRE(face_array_per_cell.numberOfArrays() == number_of_arrays(face_array_per_cell)); + REQUIRE(face_array_per_cell.sizeOfArrays() == 3); + + auto cell_to_face_matrix = connectivity.cellToFaceMatrix(); + { + bool is_correct = true; + for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { + is_correct &= (cell_to_face_matrix[cell_id].size() == face_array_per_cell.numberOfSubArrays(cell_id)); + } + REQUIRE(is_correct); + } } - REQUIRE(is_correct); - } - NodeArrayPerEdge<int> node_array_per_edge{connectivity, 5}; - REQUIRE(node_array_per_edge.numberOfItems() == connectivity.numberOfEdges()); - REQUIRE(node_array_per_edge.numberOfArrays() == number_of_arrays(node_array_per_edge)); - REQUIRE(node_array_per_edge.sizeOfArrays() == 5); + SECTION("per face") + { + CellArrayPerFace<int> cell_array_per_face{connectivity, 3}; + REQUIRE(cell_array_per_face.numberOfItems() == connectivity.numberOfFaces()); + REQUIRE(cell_array_per_face.numberOfArrays() == number_of_arrays(cell_array_per_face)); + REQUIRE(cell_array_per_face.sizeOfArrays() == 3); + + auto face_to_cell_matrix = connectivity.faceToCellMatrix(); + { + bool is_correct = true; + for (FaceId face_id = 0; face_id < connectivity.numberOfFaces(); ++face_id) { + is_correct &= (face_to_cell_matrix[face_id].size() == cell_array_per_face.numberOfSubArrays(face_id)); + } + REQUIRE(is_correct); + } - auto edge_to_node_matrix = connectivity.edgeToNodeMatrix(); - { - bool is_correct = true; - for (EdgeId edge_id = 0; edge_id < connectivity.numberOfEdges(); ++edge_id) { - is_correct &= (edge_to_node_matrix[edge_id].size() == node_array_per_edge.numberOfSubArrays(edge_id)); + NodeArrayPerFace<int> node_array_per_face{connectivity, 2}; + REQUIRE(node_array_per_face.numberOfItems() == connectivity.numberOfFaces()); + REQUIRE(node_array_per_face.numberOfArrays() == number_of_arrays(node_array_per_face)); + REQUIRE(node_array_per_face.sizeOfArrays() == 2); + + auto face_to_node_matrix = connectivity.faceToNodeMatrix(); + { + bool is_correct = true; + for (FaceId face_id = 0; face_id < connectivity.numberOfFaces(); ++face_id) { + is_correct &= (face_to_node_matrix[face_id].size() == node_array_per_face.numberOfSubArrays(face_id)); + } + REQUIRE(is_correct); + } } - REQUIRE(is_correct); - } - } - SECTION("per node") - { - EdgeArrayPerNode<int> edge_array_per_node{connectivity, 4}; - REQUIRE(edge_array_per_node.numberOfItems() == connectivity.numberOfNodes()); - REQUIRE(edge_array_per_node.numberOfArrays() == number_of_arrays(edge_array_per_node)); - REQUIRE(edge_array_per_node.sizeOfArrays() == 4); + SECTION("per edge") + { + CellArrayPerEdge<int> cell_array_per_edge{connectivity, 3}; + REQUIRE(cell_array_per_edge.numberOfItems() == connectivity.numberOfEdges()); + REQUIRE(cell_array_per_edge.numberOfArrays() == number_of_arrays(cell_array_per_edge)); + REQUIRE(cell_array_per_edge.sizeOfArrays() == 3); + + auto edge_to_cell_matrix = connectivity.edgeToCellMatrix(); + { + bool is_correct = true; + for (EdgeId edge_id = 0; edge_id < connectivity.numberOfEdges(); ++edge_id) { + is_correct &= (edge_to_cell_matrix[edge_id].size() == cell_array_per_edge.numberOfSubArrays(edge_id)); + } + REQUIRE(is_correct); + } - auto node_to_edge_matrix = connectivity.nodeToEdgeMatrix(); - { - bool is_correct = true; - for (NodeId node_id = 0; node_id < connectivity.numberOfNodes(); ++node_id) { - is_correct &= (node_to_edge_matrix[node_id].size() == edge_array_per_node.numberOfSubArrays(node_id)); + NodeArrayPerEdge<int> node_array_per_edge{connectivity, 5}; + REQUIRE(node_array_per_edge.numberOfItems() == connectivity.numberOfEdges()); + REQUIRE(node_array_per_edge.numberOfArrays() == number_of_arrays(node_array_per_edge)); + REQUIRE(node_array_per_edge.sizeOfArrays() == 5); + + auto edge_to_node_matrix = connectivity.edgeToNodeMatrix(); + { + bool is_correct = true; + for (EdgeId edge_id = 0; edge_id < connectivity.numberOfEdges(); ++edge_id) { + is_correct &= (edge_to_node_matrix[edge_id].size() == node_array_per_edge.numberOfSubArrays(edge_id)); + } + REQUIRE(is_correct); + } } - REQUIRE(is_correct); - } - - FaceArrayPerNode<int> face_array_per_node{connectivity, 3}; - REQUIRE(face_array_per_node.numberOfItems() == connectivity.numberOfNodes()); - REQUIRE(face_array_per_node.numberOfArrays() == number_of_arrays(face_array_per_node)); - REQUIRE(face_array_per_node.sizeOfArrays() == 3); - auto node_to_face_matrix = connectivity.nodeToFaceMatrix(); - { - bool is_correct = true; - for (NodeId node_id = 0; node_id < connectivity.numberOfNodes(); ++node_id) { - is_correct &= (node_to_face_matrix[node_id].size() == face_array_per_node.numberOfSubArrays(node_id)); - } - REQUIRE(is_correct); - } + SECTION("per node") + { + EdgeArrayPerNode<int> edge_array_per_node{connectivity, 4}; + REQUIRE(edge_array_per_node.numberOfItems() == connectivity.numberOfNodes()); + REQUIRE(edge_array_per_node.numberOfArrays() == number_of_arrays(edge_array_per_node)); + REQUIRE(edge_array_per_node.sizeOfArrays() == 4); + + auto node_to_edge_matrix = connectivity.nodeToEdgeMatrix(); + { + bool is_correct = true; + for (NodeId node_id = 0; node_id < connectivity.numberOfNodes(); ++node_id) { + is_correct &= (node_to_edge_matrix[node_id].size() == edge_array_per_node.numberOfSubArrays(node_id)); + } + REQUIRE(is_correct); + } - CellArrayPerNode<int> cell_array_per_node{connectivity, 2}; - REQUIRE(cell_array_per_node.numberOfItems() == connectivity.numberOfNodes()); - REQUIRE(cell_array_per_node.numberOfArrays() == number_of_arrays(cell_array_per_node)); - REQUIRE(cell_array_per_node.sizeOfArrays() == 2); + FaceArrayPerNode<int> face_array_per_node{connectivity, 3}; + REQUIRE(face_array_per_node.numberOfItems() == connectivity.numberOfNodes()); + REQUIRE(face_array_per_node.numberOfArrays() == number_of_arrays(face_array_per_node)); + REQUIRE(face_array_per_node.sizeOfArrays() == 3); + + auto node_to_face_matrix = connectivity.nodeToFaceMatrix(); + { + bool is_correct = true; + for (NodeId node_id = 0; node_id < connectivity.numberOfNodes(); ++node_id) { + is_correct &= (node_to_face_matrix[node_id].size() == face_array_per_node.numberOfSubArrays(node_id)); + } + REQUIRE(is_correct); + } - auto node_to_cell_matrix = connectivity.nodeToCellMatrix(); - { - bool is_correct = true; - for (NodeId node_id = 0; node_id < connectivity.numberOfNodes(); ++node_id) { - is_correct &= (node_to_cell_matrix[node_id].size() == cell_array_per_node.numberOfSubArrays(node_id)); + CellArrayPerNode<int> cell_array_per_node{connectivity, 2}; + REQUIRE(cell_array_per_node.numberOfItems() == connectivity.numberOfNodes()); + REQUIRE(cell_array_per_node.numberOfArrays() == number_of_arrays(cell_array_per_node)); + REQUIRE(cell_array_per_node.sizeOfArrays() == 2); + + auto node_to_cell_matrix = connectivity.nodeToCellMatrix(); + { + bool is_correct = true; + for (NodeId node_id = 0; node_id < connectivity.numberOfNodes(); ++node_id) { + is_correct &= (node_to_cell_matrix[node_id].size() == cell_array_per_node.numberOfSubArrays(node_id)); + } + REQUIRE(is_correct); + } } - REQUIRE(is_correct); } } } + SECTION("3D") { - const Mesh<Connectivity<3>>& mesh_3d = *MeshDataBaseForTests::get().cartesianMesh3D(); - const Connectivity<3>& connectivity = mesh_3d.connectivity(); - - SECTION("per cell") - { - NodeArrayPerCell<int> node_array_per_cell{connectivity, 3}; - REQUIRE(node_array_per_cell.numberOfItems() == connectivity.numberOfCells()); - REQUIRE(node_array_per_cell.numberOfArrays() == number_of_arrays(node_array_per_cell)); - REQUIRE(node_array_per_cell.sizeOfArrays() == 3); - - auto cell_to_node_matrix = connectivity.cellToNodeMatrix(); - { - bool is_correct = true; - for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { - is_correct &= (cell_to_node_matrix[cell_id].size() == node_array_per_cell.numberOfSubArrays(cell_id)); - } - REQUIRE(is_correct); - } - - EdgeArrayPerCell<int> edge_array_per_cell{connectivity, 4}; - REQUIRE(edge_array_per_cell.numberOfItems() == connectivity.numberOfCells()); - REQUIRE(edge_array_per_cell.numberOfArrays() == number_of_arrays(edge_array_per_cell)); - REQUIRE(edge_array_per_cell.sizeOfArrays() == 4); - - auto cell_to_edge_matrix = connectivity.cellToEdgeMatrix(); - { - bool is_correct = true; - for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { - is_correct &= (cell_to_edge_matrix[cell_id].size() == edge_array_per_cell.numberOfSubArrays(cell_id)); - } - REQUIRE(is_correct); - } - - FaceArrayPerCell<int> face_array_per_cell{connectivity, 3}; - REQUIRE(face_array_per_cell.numberOfItems() == connectivity.numberOfCells()); - REQUIRE(face_array_per_cell.numberOfArrays() == number_of_arrays(face_array_per_cell)); - REQUIRE(face_array_per_cell.sizeOfArrays() == 3); - - auto cell_to_face_matrix = connectivity.cellToFaceMatrix(); - { - bool is_correct = true; - for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { - is_correct &= (cell_to_face_matrix[cell_id].size() == face_array_per_cell.numberOfSubArrays(cell_id)); - } - REQUIRE(is_correct); - } - } - - SECTION("per face") - { - CellArrayPerFace<int> cell_array_per_face{connectivity, 5}; - REQUIRE(cell_array_per_face.numberOfItems() == connectivity.numberOfFaces()); - REQUIRE(cell_array_per_face.numberOfArrays() == number_of_arrays(cell_array_per_face)); - REQUIRE(cell_array_per_face.sizeOfArrays() == 5); - - auto face_to_cell_matrix = connectivity.faceToCellMatrix(); - { - bool is_correct = true; - for (FaceId face_id = 0; face_id < connectivity.numberOfFaces(); ++face_id) { - is_correct &= (face_to_cell_matrix[face_id].size() == cell_array_per_face.numberOfSubArrays(face_id)); - } - REQUIRE(is_correct); - } - - EdgeArrayPerFace<int> edge_array_per_face{connectivity, 3}; - REQUIRE(edge_array_per_face.numberOfItems() == connectivity.numberOfFaces()); - REQUIRE(edge_array_per_face.numberOfArrays() == number_of_arrays(edge_array_per_face)); - REQUIRE(edge_array_per_face.sizeOfArrays() == 3); + std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - auto face_to_edge_matrix = connectivity.faceToEdgeMatrix(); + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) { - bool is_correct = true; - for (FaceId face_id = 0; face_id < connectivity.numberOfFaces(); ++face_id) { - is_correct &= (face_to_edge_matrix[face_id].size() == edge_array_per_face.numberOfSubArrays(face_id)); - } - REQUIRE(is_correct); - } + auto mesh_3d = named_mesh.mesh(); + + const Connectivity<3>& connectivity = mesh_3d->connectivity(); + + SECTION("per cell") + { + NodeArrayPerCell<int> node_array_per_cell{connectivity, 3}; + REQUIRE(node_array_per_cell.numberOfItems() == connectivity.numberOfCells()); + REQUIRE(node_array_per_cell.numberOfArrays() == number_of_arrays(node_array_per_cell)); + REQUIRE(node_array_per_cell.sizeOfArrays() == 3); + + auto cell_to_node_matrix = connectivity.cellToNodeMatrix(); + { + bool is_correct = true; + for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { + is_correct &= (cell_to_node_matrix[cell_id].size() == node_array_per_cell.numberOfSubArrays(cell_id)); + } + REQUIRE(is_correct); + } - NodeArrayPerFace<int> node_array_per_face{connectivity, 2}; - REQUIRE(node_array_per_face.numberOfItems() == connectivity.numberOfFaces()); - REQUIRE(node_array_per_face.numberOfArrays() == number_of_arrays(node_array_per_face)); - REQUIRE(node_array_per_face.sizeOfArrays() == 2); + EdgeArrayPerCell<int> edge_array_per_cell{connectivity, 4}; + REQUIRE(edge_array_per_cell.numberOfItems() == connectivity.numberOfCells()); + REQUIRE(edge_array_per_cell.numberOfArrays() == number_of_arrays(edge_array_per_cell)); + REQUIRE(edge_array_per_cell.sizeOfArrays() == 4); + + auto cell_to_edge_matrix = connectivity.cellToEdgeMatrix(); + { + bool is_correct = true; + for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { + is_correct &= (cell_to_edge_matrix[cell_id].size() == edge_array_per_cell.numberOfSubArrays(cell_id)); + } + REQUIRE(is_correct); + } - auto face_to_node_matrix = connectivity.faceToNodeMatrix(); - { - bool is_correct = true; - for (FaceId face_id = 0; face_id < connectivity.numberOfFaces(); ++face_id) { - is_correct &= (face_to_node_matrix[face_id].size() == node_array_per_face.numberOfSubArrays(face_id)); + FaceArrayPerCell<int> face_array_per_cell{connectivity, 3}; + REQUIRE(face_array_per_cell.numberOfItems() == connectivity.numberOfCells()); + REQUIRE(face_array_per_cell.numberOfArrays() == number_of_arrays(face_array_per_cell)); + REQUIRE(face_array_per_cell.sizeOfArrays() == 3); + + auto cell_to_face_matrix = connectivity.cellToFaceMatrix(); + { + bool is_correct = true; + for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { + is_correct &= (cell_to_face_matrix[cell_id].size() == face_array_per_cell.numberOfSubArrays(cell_id)); + } + REQUIRE(is_correct); + } } - REQUIRE(is_correct); - } - } - - SECTION("per edge") - { - CellArrayPerEdge<int> cell_array_per_edge{connectivity, 3}; - REQUIRE(cell_array_per_edge.numberOfItems() == connectivity.numberOfEdges()); - REQUIRE(cell_array_per_edge.numberOfArrays() == number_of_arrays(cell_array_per_edge)); - REQUIRE(cell_array_per_edge.sizeOfArrays() == 3); - auto edge_to_cell_matrix = connectivity.edgeToCellMatrix(); - { - bool is_correct = true; - for (EdgeId edge_id = 0; edge_id < connectivity.numberOfEdges(); ++edge_id) { - is_correct &= (edge_to_cell_matrix[edge_id].size() == cell_array_per_edge.numberOfSubArrays(edge_id)); - } - REQUIRE(is_correct); - } + SECTION("per face") + { + CellArrayPerFace<int> cell_array_per_face{connectivity, 5}; + REQUIRE(cell_array_per_face.numberOfItems() == connectivity.numberOfFaces()); + REQUIRE(cell_array_per_face.numberOfArrays() == number_of_arrays(cell_array_per_face)); + REQUIRE(cell_array_per_face.sizeOfArrays() == 5); + + auto face_to_cell_matrix = connectivity.faceToCellMatrix(); + { + bool is_correct = true; + for (FaceId face_id = 0; face_id < connectivity.numberOfFaces(); ++face_id) { + is_correct &= (face_to_cell_matrix[face_id].size() == cell_array_per_face.numberOfSubArrays(face_id)); + } + REQUIRE(is_correct); + } - FaceArrayPerEdge<int> face_array_per_edge{connectivity, 5}; - REQUIRE(face_array_per_edge.numberOfItems() == connectivity.numberOfEdges()); - REQUIRE(face_array_per_edge.numberOfArrays() == number_of_arrays(face_array_per_edge)); - REQUIRE(face_array_per_edge.sizeOfArrays() == 5); + EdgeArrayPerFace<int> edge_array_per_face{connectivity, 3}; + REQUIRE(edge_array_per_face.numberOfItems() == connectivity.numberOfFaces()); + REQUIRE(edge_array_per_face.numberOfArrays() == number_of_arrays(edge_array_per_face)); + REQUIRE(edge_array_per_face.sizeOfArrays() == 3); + + auto face_to_edge_matrix = connectivity.faceToEdgeMatrix(); + { + bool is_correct = true; + for (FaceId face_id = 0; face_id < connectivity.numberOfFaces(); ++face_id) { + is_correct &= (face_to_edge_matrix[face_id].size() == edge_array_per_face.numberOfSubArrays(face_id)); + } + REQUIRE(is_correct); + } - auto edge_to_face_matrix = connectivity.edgeToFaceMatrix(); - { - bool is_correct = true; - for (EdgeId edge_id = 0; edge_id < connectivity.numberOfEdges(); ++edge_id) { - is_correct &= (edge_to_face_matrix[edge_id].size() == face_array_per_edge.numberOfSubArrays(edge_id)); + NodeArrayPerFace<int> node_array_per_face{connectivity, 2}; + REQUIRE(node_array_per_face.numberOfItems() == connectivity.numberOfFaces()); + REQUIRE(node_array_per_face.numberOfArrays() == number_of_arrays(node_array_per_face)); + REQUIRE(node_array_per_face.sizeOfArrays() == 2); + + auto face_to_node_matrix = connectivity.faceToNodeMatrix(); + { + bool is_correct = true; + for (FaceId face_id = 0; face_id < connectivity.numberOfFaces(); ++face_id) { + is_correct &= (face_to_node_matrix[face_id].size() == node_array_per_face.numberOfSubArrays(face_id)); + } + REQUIRE(is_correct); + } } - REQUIRE(is_correct); - } - - NodeArrayPerEdge<int> node_array_per_edge{connectivity, 3}; - REQUIRE(node_array_per_edge.numberOfItems() == connectivity.numberOfEdges()); - REQUIRE(node_array_per_edge.numberOfArrays() == number_of_arrays(node_array_per_edge)); - REQUIRE(node_array_per_edge.sizeOfArrays() == 3); - auto edge_to_node_matrix = connectivity.edgeToNodeMatrix(); - { - bool is_correct = true; - for (EdgeId edge_id = 0; edge_id < connectivity.numberOfEdges(); ++edge_id) { - is_correct &= (edge_to_node_matrix[edge_id].size() == node_array_per_edge.numberOfSubArrays(edge_id)); - } - REQUIRE(is_correct); - } - } + SECTION("per edge") + { + CellArrayPerEdge<int> cell_array_per_edge{connectivity, 3}; + REQUIRE(cell_array_per_edge.numberOfItems() == connectivity.numberOfEdges()); + REQUIRE(cell_array_per_edge.numberOfArrays() == number_of_arrays(cell_array_per_edge)); + REQUIRE(cell_array_per_edge.sizeOfArrays() == 3); + + auto edge_to_cell_matrix = connectivity.edgeToCellMatrix(); + { + bool is_correct = true; + for (EdgeId edge_id = 0; edge_id < connectivity.numberOfEdges(); ++edge_id) { + is_correct &= (edge_to_cell_matrix[edge_id].size() == cell_array_per_edge.numberOfSubArrays(edge_id)); + } + REQUIRE(is_correct); + } - SECTION("per node") - { - EdgeArrayPerNode<int> edge_array_per_node{connectivity, 3}; - REQUIRE(edge_array_per_node.numberOfItems() == connectivity.numberOfNodes()); - REQUIRE(edge_array_per_node.numberOfArrays() == number_of_arrays(edge_array_per_node)); - REQUIRE(edge_array_per_node.sizeOfArrays() == 3); + FaceArrayPerEdge<int> face_array_per_edge{connectivity, 5}; + REQUIRE(face_array_per_edge.numberOfItems() == connectivity.numberOfEdges()); + REQUIRE(face_array_per_edge.numberOfArrays() == number_of_arrays(face_array_per_edge)); + REQUIRE(face_array_per_edge.sizeOfArrays() == 5); + + auto edge_to_face_matrix = connectivity.edgeToFaceMatrix(); + { + bool is_correct = true; + for (EdgeId edge_id = 0; edge_id < connectivity.numberOfEdges(); ++edge_id) { + is_correct &= (edge_to_face_matrix[edge_id].size() == face_array_per_edge.numberOfSubArrays(edge_id)); + } + REQUIRE(is_correct); + } - auto node_to_edge_matrix = connectivity.nodeToEdgeMatrix(); - { - bool is_correct = true; - for (NodeId node_id = 0; node_id < connectivity.numberOfNodes(); ++node_id) { - is_correct &= (node_to_edge_matrix[node_id].size() == edge_array_per_node.numberOfSubArrays(node_id)); + NodeArrayPerEdge<int> node_array_per_edge{connectivity, 3}; + REQUIRE(node_array_per_edge.numberOfItems() == connectivity.numberOfEdges()); + REQUIRE(node_array_per_edge.numberOfArrays() == number_of_arrays(node_array_per_edge)); + REQUIRE(node_array_per_edge.sizeOfArrays() == 3); + + auto edge_to_node_matrix = connectivity.edgeToNodeMatrix(); + { + bool is_correct = true; + for (EdgeId edge_id = 0; edge_id < connectivity.numberOfEdges(); ++edge_id) { + is_correct &= (edge_to_node_matrix[edge_id].size() == node_array_per_edge.numberOfSubArrays(edge_id)); + } + REQUIRE(is_correct); + } } - REQUIRE(is_correct); - } - - FaceArrayPerNode<int> face_array_per_node{connectivity, 4}; - REQUIRE(face_array_per_node.numberOfItems() == connectivity.numberOfNodes()); - REQUIRE(face_array_per_node.numberOfArrays() == number_of_arrays(face_array_per_node)); - REQUIRE(face_array_per_node.sizeOfArrays() == 4); - auto node_to_face_matrix = connectivity.nodeToFaceMatrix(); - { - bool is_correct = true; - for (NodeId node_id = 0; node_id < connectivity.numberOfNodes(); ++node_id) { - is_correct &= (node_to_face_matrix[node_id].size() == face_array_per_node.numberOfSubArrays(node_id)); - } - REQUIRE(is_correct); - } + SECTION("per node") + { + EdgeArrayPerNode<int> edge_array_per_node{connectivity, 3}; + REQUIRE(edge_array_per_node.numberOfItems() == connectivity.numberOfNodes()); + REQUIRE(edge_array_per_node.numberOfArrays() == number_of_arrays(edge_array_per_node)); + REQUIRE(edge_array_per_node.sizeOfArrays() == 3); + + auto node_to_edge_matrix = connectivity.nodeToEdgeMatrix(); + { + bool is_correct = true; + for (NodeId node_id = 0; node_id < connectivity.numberOfNodes(); ++node_id) { + is_correct &= (node_to_edge_matrix[node_id].size() == edge_array_per_node.numberOfSubArrays(node_id)); + } + REQUIRE(is_correct); + } - CellArrayPerNode<int> cell_array_per_node{connectivity, 5}; - REQUIRE(cell_array_per_node.numberOfItems() == connectivity.numberOfNodes()); - REQUIRE(cell_array_per_node.numberOfArrays() == number_of_arrays(cell_array_per_node)); - REQUIRE(cell_array_per_node.sizeOfArrays() == 5); + FaceArrayPerNode<int> face_array_per_node{connectivity, 4}; + REQUIRE(face_array_per_node.numberOfItems() == connectivity.numberOfNodes()); + REQUIRE(face_array_per_node.numberOfArrays() == number_of_arrays(face_array_per_node)); + REQUIRE(face_array_per_node.sizeOfArrays() == 4); + + auto node_to_face_matrix = connectivity.nodeToFaceMatrix(); + { + bool is_correct = true; + for (NodeId node_id = 0; node_id < connectivity.numberOfNodes(); ++node_id) { + is_correct &= (node_to_face_matrix[node_id].size() == face_array_per_node.numberOfSubArrays(node_id)); + } + REQUIRE(is_correct); + } - auto node_to_cell_matrix = connectivity.nodeToCellMatrix(); - { - bool is_correct = true; - for (NodeId node_id = 0; node_id < connectivity.numberOfNodes(); ++node_id) { - is_correct &= (node_to_cell_matrix[node_id].size() == cell_array_per_node.numberOfSubArrays(node_id)); + CellArrayPerNode<int> cell_array_per_node{connectivity, 5}; + REQUIRE(cell_array_per_node.numberOfItems() == connectivity.numberOfNodes()); + REQUIRE(cell_array_per_node.numberOfArrays() == number_of_arrays(cell_array_per_node)); + REQUIRE(cell_array_per_node.sizeOfArrays() == 5); + + auto node_to_cell_matrix = connectivity.nodeToCellMatrix(); + { + bool is_correct = true; + for (NodeId node_id = 0; node_id < connectivity.numberOfNodes(); ++node_id) { + is_correct &= (node_to_cell_matrix[node_id].size() == cell_array_per_node.numberOfSubArrays(node_id)); + } + REQUIRE(is_correct); + } } - REQUIRE(is_correct); } } } @@ -524,325 +550,365 @@ TEST_CASE("SubItemArrayPerItem", "[mesh]") { SECTION("1D") { - const Mesh<Connectivity<1>>& mesh_1d = *MeshDataBaseForTests::get().cartesianMesh1D(); - const Connectivity<1>& connectivity = mesh_1d.connectivity(); + std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - EdgeArrayPerCell<size_t> edge_arrays_per_cell{connectivity, 3}; - { - size_t array = 0; - for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { - for (size_t i_edge = 0; i_edge < edge_arrays_per_cell.numberOfSubArrays(cell_id); ++i_edge) { - for (size_t i = 0; i < edge_arrays_per_cell(cell_id, i_edge).size(); ++i) { - edge_arrays_per_cell(cell_id, i_edge)[i] = array++; + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_1d = named_mesh.mesh(); + + const Connectivity<1>& connectivity = mesh_1d->connectivity(); + + EdgeArrayPerCell<size_t> edge_arrays_per_cell{connectivity, 3}; + { + size_t array = 0; + for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { + for (size_t i_edge = 0; i_edge < edge_arrays_per_cell.numberOfSubArrays(cell_id); ++i_edge) { + for (size_t i = 0; i < edge_arrays_per_cell(cell_id, i_edge).size(); ++i) { + edge_arrays_per_cell(cell_id, i_edge)[i] = array++; + } + } } } - } - } - { - bool is_same = true; - size_t k = 0; - for (size_t i = 0; i < edge_arrays_per_cell.numberOfArrays(); ++i) { - for (size_t j = 0; j < edge_arrays_per_cell.sizeOfArrays(); ++j, ++k) { - is_same &= (edge_arrays_per_cell[i][j] == k); + { + bool is_same = true; + size_t k = 0; + for (size_t i = 0; i < edge_arrays_per_cell.numberOfArrays(); ++i) { + for (size_t j = 0; j < edge_arrays_per_cell.sizeOfArrays(); ++j, ++k) { + is_same &= (edge_arrays_per_cell[i][j] == k); + } + } + REQUIRE(is_same); } - } - REQUIRE(is_same); - } - { - size_t k = 0; - for (size_t i = 0; i < edge_arrays_per_cell.numberOfArrays(); ++i) { - for (size_t j = 0; j < edge_arrays_per_cell.sizeOfArrays(); ++j, ++k) { - edge_arrays_per_cell[i][j] = k * k + 1; + { + size_t k = 0; + for (size_t i = 0; i < edge_arrays_per_cell.numberOfArrays(); ++i) { + for (size_t j = 0; j < edge_arrays_per_cell.sizeOfArrays(); ++j, ++k) { + edge_arrays_per_cell[i][j] = k * k + 1; + } + } } - } - } - { - bool is_same = true; - size_t i = 0; - for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { - for (size_t i_edge = 0; i_edge < edge_arrays_per_cell.numberOfSubArrays(cell_id); ++i_edge) { - for (size_t l = 0; l < edge_arrays_per_cell(cell_id, i_edge).size(); ++l, ++i) { - is_same &= (edge_arrays_per_cell(cell_id, i_edge)[l] == i * i + 1); + { + bool is_same = true; + size_t i = 0; + for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { + for (size_t i_edge = 0; i_edge < edge_arrays_per_cell.numberOfSubArrays(cell_id); ++i_edge) { + for (size_t l = 0; l < edge_arrays_per_cell(cell_id, i_edge).size(); ++l, ++i) { + is_same &= (edge_arrays_per_cell(cell_id, i_edge)[l] == i * i + 1); + } + } } + REQUIRE(is_same); } - } - REQUIRE(is_same); - } - const EdgeArrayPerCell<const size_t> const_edge_arrays_per_cell = edge_arrays_per_cell; - { - bool is_same = true; - size_t i = 0; - for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { - const auto& cell_table = const_edge_arrays_per_cell.itemTable(cell_id); - for (size_t i_edge = 0; i_edge < cell_table.numberOfRows(); ++i_edge) { - const auto& array = cell_table[i_edge]; - for (size_t l = 0; l < array.size(); ++l, ++i) { - is_same &= (array[l] == i * i + 1); + const EdgeArrayPerCell<const size_t> const_edge_arrays_per_cell = edge_arrays_per_cell; + { + bool is_same = true; + size_t i = 0; + for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { + const auto& cell_table = const_edge_arrays_per_cell.itemTable(cell_id); + for (size_t i_edge = 0; i_edge < cell_table.numberOfRows(); ++i_edge) { + const auto& array = cell_table[i_edge]; + for (size_t l = 0; l < array.size(); ++l, ++i) { + is_same &= (array[l] == i * i + 1); + } + } } + REQUIRE(is_same); } } - REQUIRE(is_same); } } SECTION("2D") { - const Mesh<Connectivity<2>>& mesh_2d = *MeshDataBaseForTests::get().cartesianMesh2D(); - const Connectivity<2>& connectivity = mesh_2d.connectivity(); + std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - CellArrayPerFace<size_t> cell_arrays_per_face{connectivity, 3}; - { - size_t array = 0; - for (FaceId face_id = 0; face_id < connectivity.numberOfFaces(); ++face_id) { - for (size_t i_cell = 0; i_cell < cell_arrays_per_face.numberOfSubArrays(face_id); ++i_cell) { - for (size_t i = 0; i < cell_arrays_per_face(face_id, i_cell).size(); ++i) { - cell_arrays_per_face(face_id, i_cell)[i] = array++; + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_2d = named_mesh.mesh(); + + const Connectivity<2>& connectivity = mesh_2d->connectivity(); + + CellArrayPerFace<size_t> cell_arrays_per_face{connectivity, 3}; + { + size_t array = 0; + for (FaceId face_id = 0; face_id < connectivity.numberOfFaces(); ++face_id) { + for (size_t i_cell = 0; i_cell < cell_arrays_per_face.numberOfSubArrays(face_id); ++i_cell) { + for (size_t i = 0; i < cell_arrays_per_face(face_id, i_cell).size(); ++i) { + cell_arrays_per_face(face_id, i_cell)[i] = array++; + } + } } } - } - } - { - bool is_same = true; - size_t k = 0; - for (size_t i = 0; i < cell_arrays_per_face.numberOfArrays(); ++i) { - for (size_t j = 0; j < cell_arrays_per_face.sizeOfArrays(); ++j, ++k) { - is_same &= (cell_arrays_per_face[i][j] == k); + { + bool is_same = true; + size_t k = 0; + for (size_t i = 0; i < cell_arrays_per_face.numberOfArrays(); ++i) { + for (size_t j = 0; j < cell_arrays_per_face.sizeOfArrays(); ++j, ++k) { + is_same &= (cell_arrays_per_face[i][j] == k); + } + } + REQUIRE(is_same); } - } - REQUIRE(is_same); - } - { - size_t k = 0; - for (size_t i = 0; i < cell_arrays_per_face.numberOfArrays(); ++i) { - for (size_t j = 0; j < cell_arrays_per_face.sizeOfArrays(); ++j, ++k) { - cell_arrays_per_face[i][j] = 3 * k + 1; + { + size_t k = 0; + for (size_t i = 0; i < cell_arrays_per_face.numberOfArrays(); ++i) { + for (size_t j = 0; j < cell_arrays_per_face.sizeOfArrays(); ++j, ++k) { + cell_arrays_per_face[i][j] = 3 * k + 1; + } + } } - } - } - { - bool is_same = true; - size_t i = 0; - for (FaceId face_id = 0; face_id < connectivity.numberOfFaces(); ++face_id) { - for (size_t i_cell = 0; i_cell < cell_arrays_per_face.numberOfSubArrays(face_id); ++i_cell) { - for (size_t l = 0; l < cell_arrays_per_face(face_id, i_cell).size(); ++l, ++i) { - is_same &= (cell_arrays_per_face(face_id, i_cell)[l] == 3 * i + 1); + { + bool is_same = true; + size_t i = 0; + for (FaceId face_id = 0; face_id < connectivity.numberOfFaces(); ++face_id) { + for (size_t i_cell = 0; i_cell < cell_arrays_per_face.numberOfSubArrays(face_id); ++i_cell) { + for (size_t l = 0; l < cell_arrays_per_face(face_id, i_cell).size(); ++l, ++i) { + is_same &= (cell_arrays_per_face(face_id, i_cell)[l] == 3 * i + 1); + } + } } + REQUIRE(is_same); } - } - REQUIRE(is_same); - } - const CellArrayPerFace<const size_t> const_cell_arrays_per_face = cell_arrays_per_face; - { - bool is_same = true; - size_t i = 0; - for (FaceId face_id = 0; face_id < connectivity.numberOfFaces(); ++face_id) { - const auto& face_table = const_cell_arrays_per_face.itemTable(face_id); - for (size_t i_cell = 0; i_cell < face_table.numberOfRows(); ++i_cell) { - const auto& array = face_table[i_cell]; - for (size_t l = 0; l < array.size(); ++l, ++i) { - is_same &= (array[l] == 3 * i + 1); + const CellArrayPerFace<const size_t> const_cell_arrays_per_face = cell_arrays_per_face; + { + bool is_same = true; + size_t i = 0; + for (FaceId face_id = 0; face_id < connectivity.numberOfFaces(); ++face_id) { + const auto& face_table = const_cell_arrays_per_face.itemTable(face_id); + for (size_t i_cell = 0; i_cell < face_table.numberOfRows(); ++i_cell) { + const auto& array = face_table[i_cell]; + for (size_t l = 0; l < array.size(); ++l, ++i) { + is_same &= (array[l] == 3 * i + 1); + } + } } + REQUIRE(is_same); } } - REQUIRE(is_same); } } SECTION("3D") { - const Mesh<Connectivity<3>>& mesh_3d = *MeshDataBaseForTests::get().cartesianMesh3D(); - const Connectivity<3>& connectivity = mesh_3d.connectivity(); + std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - FaceArrayPerNode<size_t> face_arrays_per_node{connectivity, 3}; - { - size_t array = 0; - for (NodeId node_id = 0; node_id < connectivity.numberOfNodes(); ++node_id) { - for (size_t i_face = 0; i_face < face_arrays_per_node.numberOfSubArrays(node_id); ++i_face) { - for (size_t i = 0; i < face_arrays_per_node(node_id, i_face).size(); ++i) - face_arrays_per_node(node_id, i_face)[i] = array++; + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_3d = named_mesh.mesh(); + + const Connectivity<3>& connectivity = mesh_3d->connectivity(); + + FaceArrayPerNode<size_t> face_arrays_per_node{connectivity, 3}; + { + size_t array = 0; + for (NodeId node_id = 0; node_id < connectivity.numberOfNodes(); ++node_id) { + for (size_t i_face = 0; i_face < face_arrays_per_node.numberOfSubArrays(node_id); ++i_face) { + for (size_t i = 0; i < face_arrays_per_node(node_id, i_face).size(); ++i) + face_arrays_per_node(node_id, i_face)[i] = array++; + } + } } - } - } - { - bool is_same = true; - size_t k = 0; - for (size_t i = 0; i < face_arrays_per_node.numberOfArrays(); ++i) { - for (size_t j = 0; j < face_arrays_per_node.sizeOfArrays(); ++j, ++k) { - is_same &= (face_arrays_per_node[i][j] == k); + { + bool is_same = true; + size_t k = 0; + for (size_t i = 0; i < face_arrays_per_node.numberOfArrays(); ++i) { + for (size_t j = 0; j < face_arrays_per_node.sizeOfArrays(); ++j, ++k) { + is_same &= (face_arrays_per_node[i][j] == k); + } + REQUIRE(is_same); + } } - REQUIRE(is_same); - } - } - { - size_t k = 0; - for (size_t i = 0; i < face_arrays_per_node.numberOfArrays(); ++i) { - for (size_t j = 0; j < face_arrays_per_node.sizeOfArrays(); ++j, ++k) { - face_arrays_per_node[i][j] = 3 + k * k; + { + size_t k = 0; + for (size_t i = 0; i < face_arrays_per_node.numberOfArrays(); ++i) { + for (size_t j = 0; j < face_arrays_per_node.sizeOfArrays(); ++j, ++k) { + face_arrays_per_node[i][j] = 3 + k * k; + } + } } - } - } - { - bool is_same = true; - size_t i = 0; - for (NodeId node_id = 0; node_id < connectivity.numberOfNodes(); ++node_id) { - for (size_t i_face = 0; i_face < face_arrays_per_node.numberOfSubArrays(node_id); ++i_face) { - for (size_t l = 0; l < face_arrays_per_node(node_id, i_face).size(); ++l, ++i) { - is_same &= (face_arrays_per_node(node_id, i_face)[l] == 3 + i * i); + { + bool is_same = true; + size_t i = 0; + for (NodeId node_id = 0; node_id < connectivity.numberOfNodes(); ++node_id) { + for (size_t i_face = 0; i_face < face_arrays_per_node.numberOfSubArrays(node_id); ++i_face) { + for (size_t l = 0; l < face_arrays_per_node(node_id, i_face).size(); ++l, ++i) { + is_same &= (face_arrays_per_node(node_id, i_face)[l] == 3 + i * i); + } + } } + REQUIRE(is_same); } - } - REQUIRE(is_same); - } - const FaceArrayPerNode<const size_t> const_face_arrays_per_node = face_arrays_per_node; - { - bool is_same = true; - size_t i = 0; - for (NodeId node_id = 0; node_id < connectivity.numberOfNodes(); ++node_id) { - const auto& node_table = const_face_arrays_per_node.itemTable(node_id); - for (size_t i_face = 0; i_face < node_table.numberOfRows(); ++i_face) { - const auto& array = node_table[i_face]; - for (size_t l = 0; l < array.size(); ++l, ++i) { - is_same &= (array[l] == 3 + i * i); + const FaceArrayPerNode<const size_t> const_face_arrays_per_node = face_arrays_per_node; + { + bool is_same = true; + size_t i = 0; + for (NodeId node_id = 0; node_id < connectivity.numberOfNodes(); ++node_id) { + const auto& node_table = const_face_arrays_per_node.itemTable(node_id); + for (size_t i_face = 0; i_face < node_table.numberOfRows(); ++i_face) { + const auto& array = node_table[i_face]; + for (size_t l = 0; l < array.size(); ++l, ++i) { + is_same &= (array[l] == 3 + i * i); + } + } } + REQUIRE(is_same); } } - REQUIRE(is_same); } } } SECTION("copy") { - const Mesh<Connectivity<3>>& mesh_3d = *MeshDataBaseForTests::get().cartesianMesh3D(); - const Connectivity<3>& connectivity = mesh_3d.connectivity(); + std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - SECTION("classic") - { - NodeArrayPerCell<size_t> node_array_per_cell{connectivity, 3}; + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) { - size_t k = 0; - for (size_t i = 0; i < node_array_per_cell.numberOfArrays(); ++i) { - for (size_t j = 0; j < node_array_per_cell.sizeOfArrays(); ++j, ++k) { - node_array_per_cell[i][j] = k; - } - } - } - NodeArrayPerCell<size_t> copy_node_array_per_cell = copy(node_array_per_cell); - { - bool is_same = true; - for (size_t i = 0; i < copy_node_array_per_cell.numberOfArrays(); ++i) { - for (size_t j = 0; j < node_array_per_cell.sizeOfArrays(); ++j) { - is_same &= (copy_node_array_per_cell[i][j] == node_array_per_cell[i][j]); - } - } + auto mesh_3d = named_mesh.mesh(); - REQUIRE(is_same); - } + const Connectivity<3>& connectivity = mesh_3d->connectivity(); - { - for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { - auto cell_table = node_array_per_cell.itemTable(cell_id); - for (size_t i_node = 0; i_node < node_array_per_cell.numberOfSubArrays(cell_id); ++i_node) { - auto node_array = cell_table[i_node]; - for (size_t i = 0; i < node_array.size(); ++i) { - node_array[i] = cell_id + i_node + i; + SECTION("classic") + { + NodeArrayPerCell<size_t> node_array_per_cell{connectivity, 3}; + { + size_t k = 0; + for (size_t i = 0; i < node_array_per_cell.numberOfArrays(); ++i) { + for (size_t j = 0; j < node_array_per_cell.sizeOfArrays(); ++j, ++k) { + node_array_per_cell[i][j] = k; + } } } - } - } + NodeArrayPerCell<size_t> copy_node_array_per_cell = copy(node_array_per_cell); + { + bool is_same = true; + for (size_t i = 0; i < copy_node_array_per_cell.numberOfArrays(); ++i) { + for (size_t j = 0; j < node_array_per_cell.sizeOfArrays(); ++j) { + is_same &= (copy_node_array_per_cell[i][j] == node_array_per_cell[i][j]); + } + } - { - bool is_same = true; - for (size_t i = 0; i < copy_node_array_per_cell.numberOfArrays(); ++i) { - for (size_t j = 0; j < copy_node_array_per_cell.sizeOfArrays(); ++j) { - is_same &= (copy_node_array_per_cell[i][j] == node_array_per_cell[i][j]); + REQUIRE(is_same); } - } - REQUIRE(not is_same); - } - } + { + for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { + auto cell_table = node_array_per_cell.itemTable(cell_id); + for (size_t i_node = 0; i_node < node_array_per_cell.numberOfSubArrays(cell_id); ++i_node) { + auto node_array = cell_table[i_node]; + for (size_t i = 0; i < node_array.size(); ++i) { + node_array[i] = cell_id + i_node + i; + } + } + } + } - SECTION("from weak") - { - WeakNodeArrayPerCell<size_t> node_array_per_cell{connectivity, 3}; - { - size_t k = 0; - for (size_t i = 0; i < node_array_per_cell.numberOfArrays(); ++i) { - for (size_t j = 0; j < node_array_per_cell.sizeOfArrays(); ++j, ++k) { - node_array_per_cell[i][j] = k; + { + bool is_same = true; + for (size_t i = 0; i < copy_node_array_per_cell.numberOfArrays(); ++i) { + for (size_t j = 0; j < copy_node_array_per_cell.sizeOfArrays(); ++j) { + is_same &= (copy_node_array_per_cell[i][j] == node_array_per_cell[i][j]); + } + } + + REQUIRE(not is_same); } } - } - NodeArrayPerCell<size_t> copy_node_array_per_cell = copy(node_array_per_cell); - { - bool is_same = true; - for (size_t i = 0; i < copy_node_array_per_cell.numberOfArrays(); ++i) { - for (size_t j = 0; j < node_array_per_cell.sizeOfArrays(); ++j) { - is_same &= (copy_node_array_per_cell[i][j] == node_array_per_cell[i][j]); + SECTION("from weak") + { + WeakNodeArrayPerCell<size_t> node_array_per_cell{connectivity, 3}; + { + size_t k = 0; + for (size_t i = 0; i < node_array_per_cell.numberOfArrays(); ++i) { + for (size_t j = 0; j < node_array_per_cell.sizeOfArrays(); ++j, ++k) { + node_array_per_cell[i][j] = k; + } + } } - } - REQUIRE(is_same); - } + NodeArrayPerCell<size_t> copy_node_array_per_cell = copy(node_array_per_cell); + { + bool is_same = true; + for (size_t i = 0; i < copy_node_array_per_cell.numberOfArrays(); ++i) { + for (size_t j = 0; j < node_array_per_cell.sizeOfArrays(); ++j) { + is_same &= (copy_node_array_per_cell[i][j] == node_array_per_cell[i][j]); + } + } - { - for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { - auto cell_table = node_array_per_cell.itemTable(cell_id); - for (size_t i_node = 0; i_node < node_array_per_cell.numberOfSubArrays(cell_id); ++i_node) { - auto node_array = cell_table[i_node]; - for (size_t i = 0; i < node_array.size(); ++i) { - node_array[i] = cell_id + i_node + i; + REQUIRE(is_same); + } + + { + for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { + auto cell_table = node_array_per_cell.itemTable(cell_id); + for (size_t i_node = 0; i_node < node_array_per_cell.numberOfSubArrays(cell_id); ++i_node) { + auto node_array = cell_table[i_node]; + for (size_t i = 0; i < node_array.size(); ++i) { + node_array[i] = cell_id + i_node + i; + } + } } } - } - } - { - bool is_same = true; - for (size_t i = 0; i < copy_node_array_per_cell.numberOfArrays(); ++i) { - for (size_t j = 0; j < node_array_per_cell.sizeOfArrays(); ++j) { - is_same &= (copy_node_array_per_cell[i][j] == node_array_per_cell[i][j]); + { + bool is_same = true; + for (size_t i = 0; i < copy_node_array_per_cell.numberOfArrays(); ++i) { + for (size_t j = 0; j < node_array_per_cell.sizeOfArrays(); ++j) { + is_same &= (copy_node_array_per_cell[i][j] == node_array_per_cell[i][j]); + } + } + + REQUIRE(not is_same); } } - - REQUIRE(not is_same); } } } SECTION("WeakSubItemArrayPerItem") { - const Mesh<Connectivity<2>>& mesh_2d = *MeshDataBaseForTests::get().cartesianMesh2D(); - const Connectivity<2>& connectivity = mesh_2d.connectivity(); + std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - WeakFaceArrayPerCell<int> weak_face_array_per_cell{connectivity, 3}; - { - size_t k = 0; - for (size_t i = 0; i < weak_face_array_per_cell.numberOfArrays(); ++i) { - for (size_t j = 0; j < weak_face_array_per_cell.sizeOfArrays(); ++j, ++k) { - weak_face_array_per_cell[i][j] = k; + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_2d = named_mesh.mesh(); + + const Connectivity<2>& connectivity = mesh_2d->connectivity(); + + WeakFaceArrayPerCell<int> weak_face_array_per_cell{connectivity, 3}; + { + size_t k = 0; + for (size_t i = 0; i < weak_face_array_per_cell.numberOfArrays(); ++i) { + for (size_t j = 0; j < weak_face_array_per_cell.sizeOfArrays(); ++j, ++k) { + weak_face_array_per_cell[i][j] = k; + } + } } - } - } - FaceArrayPerCell<const int> face_array_per_cell{weak_face_array_per_cell}; + FaceArrayPerCell<const int> face_array_per_cell{weak_face_array_per_cell}; - REQUIRE(face_array_per_cell.connectivity_ptr() == weak_face_array_per_cell.connectivity_ptr()); - REQUIRE(face_array_per_cell.sizeOfArrays() == weak_face_array_per_cell.sizeOfArrays()); + REQUIRE(face_array_per_cell.connectivity_ptr() == weak_face_array_per_cell.connectivity_ptr()); + REQUIRE(face_array_per_cell.sizeOfArrays() == weak_face_array_per_cell.sizeOfArrays()); - bool is_same = true; - for (size_t i = 0; i < weak_face_array_per_cell.numberOfArrays(); ++i) { - for (size_t j = 0; j < weak_face_array_per_cell.sizeOfArrays(); ++j) { - is_same &= (face_array_per_cell[i][j] == weak_face_array_per_cell[i][j]); + bool is_same = true; + for (size_t i = 0; i < weak_face_array_per_cell.numberOfArrays(); ++i) { + for (size_t j = 0; j < weak_face_array_per_cell.sizeOfArrays(); ++j) { + is_same &= (face_array_per_cell[i][j] == weak_face_array_per_cell[i][j]); + } + } + REQUIRE(is_same); } } - REQUIRE(is_same); } #ifndef NDEBUG @@ -889,71 +955,83 @@ TEST_CASE("SubItemArrayPerItem", "[mesh]") SECTION("checking for bounds violation") { - const Mesh<Connectivity<3>>& mesh_3d = *MeshDataBaseForTests::get().cartesianMesh3D(); - const Connectivity<3>& connectivity = mesh_3d.connectivity(); + std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - CellArrayPerFace<int> cell_array_per_face{connectivity, 3}; - { - FaceId invalid_face_id = connectivity.numberOfFaces(); - REQUIRE_THROWS_AS(cell_array_per_face(invalid_face_id, 0), AssertError); - } - if (connectivity.numberOfFaces() > 0) { - FaceId face_id = 0; - const auto& face_table = cell_array_per_face.itemTable(face_id); - REQUIRE_THROWS_AS(cell_array_per_face(face_id, face_table.numberOfRows()), AssertError); - REQUIRE_THROWS_AS(face_table[face_table.numberOfRows()], AssertError); - REQUIRE_THROWS_AS(cell_array_per_face.itemTable(face_id)[face_table.numberOfRows()], AssertError); - REQUIRE_THROWS_AS(cell_array_per_face.itemTable(face_id)[0][cell_array_per_face.sizeOfArrays()], AssertError); - REQUIRE_THROWS_AS(cell_array_per_face.itemTable(face_id)[0][cell_array_per_face.sizeOfArrays()] = 2, - AssertError); - } + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_3d = named_mesh.mesh(); - FaceArrayPerNode<int> face_array_per_node{connectivity, 5}; - { - NodeId invalid_node_id = connectivity.numberOfNodes(); - REQUIRE_THROWS_AS(face_array_per_node(invalid_node_id, 0), AssertError); - } - if (connectivity.numberOfNodes() > 0) { - NodeId node_id = 0; - const auto& node_table = face_array_per_node.itemTable(node_id); - REQUIRE_THROWS_AS(face_array_per_node(node_id, node_table.numberOfRows()), AssertError); - REQUIRE_THROWS_AS(node_table[node_table.numberOfRows()], AssertError); - REQUIRE_THROWS_AS(face_array_per_node.itemTable(node_id)[node_table.numberOfRows()], AssertError); - REQUIRE_THROWS_AS(face_array_per_node.itemTable(node_id)[0][face_array_per_node.sizeOfArrays()], AssertError); - REQUIRE_THROWS_AS(face_array_per_node.itemTable(node_id)[0][face_array_per_node.sizeOfArrays()] = 2, - AssertError); - } + const Connectivity<3>& connectivity = mesh_3d->connectivity(); - EdgeArrayPerCell<int> edge_array_per_cell{connectivity, 3}; - { - CellId invalid_cell_id = connectivity.numberOfCells(); - REQUIRE_THROWS_AS(edge_array_per_cell(invalid_cell_id, 0), AssertError); - } - if (connectivity.numberOfCells() > 0) { - CellId cell_id = 0; - const auto& cell_table = edge_array_per_cell.itemTable(cell_id); - REQUIRE_THROWS_AS(edge_array_per_cell(cell_id, cell_table.numberOfRows()), AssertError); - REQUIRE_THROWS_AS(cell_table[cell_table.numberOfRows()], AssertError); - REQUIRE_THROWS_AS(edge_array_per_cell.itemTable(cell_id)[cell_table.numberOfRows()], AssertError); - REQUIRE_THROWS_AS(edge_array_per_cell.itemTable(cell_id)[0][edge_array_per_cell.sizeOfArrays()], AssertError); - REQUIRE_THROWS_AS(edge_array_per_cell.itemTable(cell_id)[0][edge_array_per_cell.sizeOfArrays()] == 2, - AssertError); - } + CellArrayPerFace<int> cell_array_per_face{connectivity, 3}; + { + FaceId invalid_face_id = connectivity.numberOfFaces(); + REQUIRE_THROWS_AS(cell_array_per_face(invalid_face_id, 0), AssertError); + } + if (connectivity.numberOfFaces() > 0) { + FaceId face_id = 0; + const auto& face_table = cell_array_per_face.itemTable(face_id); + REQUIRE_THROWS_AS(cell_array_per_face(face_id, face_table.numberOfRows()), AssertError); + REQUIRE_THROWS_AS(face_table[face_table.numberOfRows()], AssertError); + REQUIRE_THROWS_AS(cell_array_per_face.itemTable(face_id)[face_table.numberOfRows()], AssertError); + REQUIRE_THROWS_AS(cell_array_per_face.itemTable(face_id)[0][cell_array_per_face.sizeOfArrays()], + AssertError); + REQUIRE_THROWS_AS(cell_array_per_face.itemTable(face_id)[0][cell_array_per_face.sizeOfArrays()] = 2, + AssertError); + } - NodeArrayPerEdge<int> node_array_per_edge{connectivity, 3}; - { - EdgeId invalid_edge_id = connectivity.numberOfEdges(); - REQUIRE_THROWS_AS(node_array_per_edge(invalid_edge_id, 0), AssertError); - } - if (connectivity.numberOfEdges() > 0) { - EdgeId edge_id = 0; - const auto& edge_table = node_array_per_edge.itemTable(edge_id); - REQUIRE_THROWS_AS(node_array_per_edge(edge_id, edge_table.numberOfRows()), AssertError); - REQUIRE_THROWS_AS(edge_table[edge_table.numberOfRows()], AssertError); - REQUIRE_THROWS_AS(node_array_per_edge.itemTable(edge_id)[edge_table.numberOfRows()], AssertError); - REQUIRE_THROWS_AS(node_array_per_edge.itemTable(edge_id)[0][node_array_per_edge.sizeOfArrays()], AssertError); - REQUIRE_THROWS_AS(node_array_per_edge.itemTable(edge_id)[0][node_array_per_edge.sizeOfArrays()] = 2, - AssertError); + FaceArrayPerNode<int> face_array_per_node{connectivity, 5}; + { + NodeId invalid_node_id = connectivity.numberOfNodes(); + REQUIRE_THROWS_AS(face_array_per_node(invalid_node_id, 0), AssertError); + } + if (connectivity.numberOfNodes() > 0) { + NodeId node_id = 0; + const auto& node_table = face_array_per_node.itemTable(node_id); + REQUIRE_THROWS_AS(face_array_per_node(node_id, node_table.numberOfRows()), AssertError); + REQUIRE_THROWS_AS(node_table[node_table.numberOfRows()], AssertError); + REQUIRE_THROWS_AS(face_array_per_node.itemTable(node_id)[node_table.numberOfRows()], AssertError); + REQUIRE_THROWS_AS(face_array_per_node.itemTable(node_id)[0][face_array_per_node.sizeOfArrays()], + AssertError); + REQUIRE_THROWS_AS(face_array_per_node.itemTable(node_id)[0][face_array_per_node.sizeOfArrays()] = 2, + AssertError); + } + + EdgeArrayPerCell<int> edge_array_per_cell{connectivity, 3}; + { + CellId invalid_cell_id = connectivity.numberOfCells(); + REQUIRE_THROWS_AS(edge_array_per_cell(invalid_cell_id, 0), AssertError); + } + if (connectivity.numberOfCells() > 0) { + CellId cell_id = 0; + const auto& cell_table = edge_array_per_cell.itemTable(cell_id); + REQUIRE_THROWS_AS(edge_array_per_cell(cell_id, cell_table.numberOfRows()), AssertError); + REQUIRE_THROWS_AS(cell_table[cell_table.numberOfRows()], AssertError); + REQUIRE_THROWS_AS(edge_array_per_cell.itemTable(cell_id)[cell_table.numberOfRows()], AssertError); + REQUIRE_THROWS_AS(edge_array_per_cell.itemTable(cell_id)[0][edge_array_per_cell.sizeOfArrays()], + AssertError); + REQUIRE_THROWS_AS(edge_array_per_cell.itemTable(cell_id)[0][edge_array_per_cell.sizeOfArrays()] == 2, + AssertError); + } + + NodeArrayPerEdge<int> node_array_per_edge{connectivity, 3}; + { + EdgeId invalid_edge_id = connectivity.numberOfEdges(); + REQUIRE_THROWS_AS(node_array_per_edge(invalid_edge_id, 0), AssertError); + } + if (connectivity.numberOfEdges() > 0) { + EdgeId edge_id = 0; + const auto& edge_table = node_array_per_edge.itemTable(edge_id); + REQUIRE_THROWS_AS(node_array_per_edge(edge_id, edge_table.numberOfRows()), AssertError); + REQUIRE_THROWS_AS(edge_table[edge_table.numberOfRows()], AssertError); + REQUIRE_THROWS_AS(node_array_per_edge.itemTable(edge_id)[edge_table.numberOfRows()], AssertError); + REQUIRE_THROWS_AS(node_array_per_edge.itemTable(edge_id)[0][node_array_per_edge.sizeOfArrays()], + AssertError); + REQUIRE_THROWS_AS(node_array_per_edge.itemTable(edge_id)[0][node_array_per_edge.sizeOfArrays()] = 2, + AssertError); + } + } } } } diff --git a/tests/test_SubItemValuePerItem.cpp b/tests/test_SubItemValuePerItem.cpp index f9b71010b411c3a53b968703202882f1d4fd0df1..5eaadd94d88d07d2c802e9da867ab5ae2442aa5a 100644 --- a/tests/test_SubItemValuePerItem.cpp +++ b/tests/test_SubItemValuePerItem.cpp @@ -64,660 +64,724 @@ TEST_CASE("SubItemValuePerItem", "[mesh]") SECTION("1D") { - const Mesh<Connectivity<1>>& mesh_1d = *MeshDataBaseForTests::get().cartesianMesh1D(); - const Connectivity<1>& connectivity = mesh_1d.connectivity(); + std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - SECTION("per cell") - { - NodeValuePerCell<int> node_value_per_cell{connectivity}; - REQUIRE(node_value_per_cell.numberOfItems() == connectivity.numberOfCells()); - REQUIRE(node_value_per_cell.numberOfValues() == number_of_values(node_value_per_cell)); - - auto cell_to_node_matrix = connectivity.cellToNodeMatrix(); - { - bool is_correct = true; - for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { - is_correct &= - (cell_to_node_matrix[cell_id].size() == node_value_per_cell.numberOfSubValues(cell_id)) and - (node_value_per_cell.itemValues(cell_id).size() == node_value_per_cell.numberOfSubValues(cell_id)); - } - REQUIRE(is_correct); - } - - const NodeValuePerCell<const int> const_node_value_per_cell = node_value_per_cell; - { - bool is_correct = true; - for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { - is_correct &= - (const_node_value_per_cell.itemValues(cell_id).size() == node_value_per_cell.numberOfSubValues(cell_id)); - } - REQUIRE(is_correct); - } - - EdgeValuePerCell<int> edge_value_per_cell{connectivity}; - REQUIRE(edge_value_per_cell.numberOfItems() == connectivity.numberOfCells()); - REQUIRE(edge_value_per_cell.numberOfValues() == number_of_values(edge_value_per_cell)); - - auto cell_to_edge_matrix = connectivity.cellToEdgeMatrix(); - { - bool is_correct = true; - for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { - is_correct &= (cell_to_edge_matrix[cell_id].size() == edge_value_per_cell.numberOfSubValues(cell_id)); - } - REQUIRE(is_correct); - } - - FaceValuePerCell<int> face_value_per_cell{connectivity}; - REQUIRE(face_value_per_cell.numberOfItems() == connectivity.numberOfCells()); - REQUIRE(face_value_per_cell.numberOfValues() == number_of_values(face_value_per_cell)); - - auto cell_to_face_matrix = connectivity.cellToFaceMatrix(); + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) { - bool is_correct = true; - for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { - is_correct &= (cell_to_face_matrix[cell_id].size() == face_value_per_cell.numberOfSubValues(cell_id)); + auto mesh_1d = named_mesh.mesh(); + + const Connectivity<1>& connectivity = mesh_1d->connectivity(); + + SECTION("per cell") + { + NodeValuePerCell<int> node_value_per_cell{connectivity}; + REQUIRE(node_value_per_cell.numberOfItems() == connectivity.numberOfCells()); + REQUIRE(node_value_per_cell.numberOfValues() == number_of_values(node_value_per_cell)); + + auto cell_to_node_matrix = connectivity.cellToNodeMatrix(); + { + bool is_correct = true; + for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { + is_correct &= + (cell_to_node_matrix[cell_id].size() == node_value_per_cell.numberOfSubValues(cell_id)) and + (node_value_per_cell.itemValues(cell_id).size() == node_value_per_cell.numberOfSubValues(cell_id)); + } + REQUIRE(is_correct); + } + + const NodeValuePerCell<const int> const_node_value_per_cell = node_value_per_cell; + { + bool is_correct = true; + for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { + is_correct &= (const_node_value_per_cell.itemValues(cell_id).size() == + node_value_per_cell.numberOfSubValues(cell_id)); + } + REQUIRE(is_correct); + } + + EdgeValuePerCell<int> edge_value_per_cell{connectivity}; + REQUIRE(edge_value_per_cell.numberOfItems() == connectivity.numberOfCells()); + REQUIRE(edge_value_per_cell.numberOfValues() == number_of_values(edge_value_per_cell)); + + auto cell_to_edge_matrix = connectivity.cellToEdgeMatrix(); + { + bool is_correct = true; + for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { + is_correct &= (cell_to_edge_matrix[cell_id].size() == edge_value_per_cell.numberOfSubValues(cell_id)); + } + REQUIRE(is_correct); + } + + FaceValuePerCell<int> face_value_per_cell{connectivity}; + REQUIRE(face_value_per_cell.numberOfItems() == connectivity.numberOfCells()); + REQUIRE(face_value_per_cell.numberOfValues() == number_of_values(face_value_per_cell)); + + auto cell_to_face_matrix = connectivity.cellToFaceMatrix(); + { + bool is_correct = true; + for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { + is_correct &= (cell_to_face_matrix[cell_id].size() == face_value_per_cell.numberOfSubValues(cell_id)); + } + REQUIRE(is_correct); + } + } + + SECTION("per face") + { + CellValuePerFace<int> cell_value_per_face{connectivity}; + REQUIRE(cell_value_per_face.numberOfItems() == connectivity.numberOfFaces()); + REQUIRE(cell_value_per_face.numberOfValues() == number_of_values(cell_value_per_face)); + + auto face_to_cell_matrix = connectivity.faceToCellMatrix(); + { + bool is_correct = true; + for (FaceId face_id = 0; face_id < connectivity.numberOfFaces(); ++face_id) { + is_correct &= (face_to_cell_matrix[face_id].size() == cell_value_per_face.numberOfSubValues(face_id)); + } + REQUIRE(is_correct); + } + } + + SECTION("per edge") + { + CellValuePerEdge<int> cell_value_per_edge{connectivity}; + REQUIRE(cell_value_per_edge.numberOfItems() == connectivity.numberOfEdges()); + REQUIRE(cell_value_per_edge.numberOfValues() == number_of_values(cell_value_per_edge)); + + auto edge_to_cell_matrix = connectivity.edgeToCellMatrix(); + { + bool is_correct = true; + for (EdgeId edge_id = 0; edge_id < connectivity.numberOfEdges(); ++edge_id) { + is_correct &= (edge_to_cell_matrix[edge_id].size() == cell_value_per_edge.numberOfSubValues(edge_id)); + } + REQUIRE(is_correct); + } + } + + SECTION("per node") + { + CellValuePerNode<int> cell_value_per_node{connectivity}; + REQUIRE(cell_value_per_node.numberOfItems() == connectivity.numberOfNodes()); + REQUIRE(cell_value_per_node.numberOfValues() == number_of_values(cell_value_per_node)); + + auto node_to_cell_matrix = connectivity.nodeToCellMatrix(); + { + bool is_correct = true; + for (NodeId node_id = 0; node_id < connectivity.numberOfNodes(); ++node_id) { + is_correct &= (node_to_cell_matrix[node_id].size() == cell_value_per_node.numberOfSubValues(node_id)); + } + REQUIRE(is_correct); + } } - REQUIRE(is_correct); - } - } - - SECTION("per face") - { - CellValuePerFace<int> cell_value_per_face{connectivity}; - REQUIRE(cell_value_per_face.numberOfItems() == connectivity.numberOfFaces()); - REQUIRE(cell_value_per_face.numberOfValues() == number_of_values(cell_value_per_face)); - - auto face_to_cell_matrix = connectivity.faceToCellMatrix(); - { - bool is_correct = true; - for (FaceId face_id = 0; face_id < connectivity.numberOfFaces(); ++face_id) { - is_correct &= (face_to_cell_matrix[face_id].size() == cell_value_per_face.numberOfSubValues(face_id)); - } - REQUIRE(is_correct); } } + } - SECTION("per edge") - { - CellValuePerEdge<int> cell_value_per_edge{connectivity}; - REQUIRE(cell_value_per_edge.numberOfItems() == connectivity.numberOfEdges()); - REQUIRE(cell_value_per_edge.numberOfValues() == number_of_values(cell_value_per_edge)); + SECTION("2D") + { + std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - auto edge_to_cell_matrix = connectivity.edgeToCellMatrix(); + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) { - bool is_correct = true; - for (EdgeId edge_id = 0; edge_id < connectivity.numberOfEdges(); ++edge_id) { - is_correct &= (edge_to_cell_matrix[edge_id].size() == cell_value_per_edge.numberOfSubValues(edge_id)); + auto mesh_2d = named_mesh.mesh(); + + const Connectivity<2>& connectivity = mesh_2d->connectivity(); + + SECTION("per cell") + { + NodeValuePerCell<int> node_value_per_cell{connectivity}; + REQUIRE(node_value_per_cell.numberOfItems() == connectivity.numberOfCells()); + REQUIRE(node_value_per_cell.numberOfValues() == number_of_values(node_value_per_cell)); + + auto cell_to_node_matrix = connectivity.cellToNodeMatrix(); + { + bool is_correct = true; + for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { + is_correct &= (cell_to_node_matrix[cell_id].size() == node_value_per_cell.numberOfSubValues(cell_id)); + } + REQUIRE(is_correct); + } + + EdgeValuePerCell<int> edge_value_per_cell{connectivity}; + REQUIRE(edge_value_per_cell.numberOfItems() == connectivity.numberOfCells()); + REQUIRE(edge_value_per_cell.numberOfValues() == number_of_values(edge_value_per_cell)); + + auto cell_to_edge_matrix = connectivity.cellToEdgeMatrix(); + { + bool is_correct = true; + for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { + is_correct &= (cell_to_edge_matrix[cell_id].size() == edge_value_per_cell.numberOfSubValues(cell_id)); + } + REQUIRE(is_correct); + } + + FaceValuePerCell<int> face_value_per_cell{connectivity}; + REQUIRE(face_value_per_cell.numberOfItems() == connectivity.numberOfCells()); + REQUIRE(face_value_per_cell.numberOfValues() == number_of_values(face_value_per_cell)); + + auto cell_to_face_matrix = connectivity.cellToFaceMatrix(); + { + bool is_correct = true; + for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { + is_correct &= (cell_to_face_matrix[cell_id].size() == face_value_per_cell.numberOfSubValues(cell_id)); + } + REQUIRE(is_correct); + } + } + + SECTION("per face") + { + CellValuePerFace<int> cell_value_per_face{connectivity}; + REQUIRE(cell_value_per_face.numberOfItems() == connectivity.numberOfFaces()); + REQUIRE(cell_value_per_face.numberOfValues() == number_of_values(cell_value_per_face)); + + auto face_to_cell_matrix = connectivity.faceToCellMatrix(); + { + bool is_correct = true; + for (FaceId face_id = 0; face_id < connectivity.numberOfFaces(); ++face_id) { + is_correct &= (face_to_cell_matrix[face_id].size() == cell_value_per_face.numberOfSubValues(face_id)); + } + REQUIRE(is_correct); + } + + NodeValuePerFace<int> node_value_per_face{connectivity}; + REQUIRE(node_value_per_face.numberOfItems() == connectivity.numberOfFaces()); + REQUIRE(node_value_per_face.numberOfValues() == number_of_values(node_value_per_face)); + + auto face_to_node_matrix = connectivity.faceToNodeMatrix(); + { + bool is_correct = true; + for (FaceId face_id = 0; face_id < connectivity.numberOfFaces(); ++face_id) { + is_correct &= (face_to_node_matrix[face_id].size() == node_value_per_face.numberOfSubValues(face_id)); + } + REQUIRE(is_correct); + } + } + + SECTION("per edge") + { + CellValuePerEdge<int> cell_value_per_edge{connectivity}; + REQUIRE(cell_value_per_edge.numberOfItems() == connectivity.numberOfEdges()); + REQUIRE(cell_value_per_edge.numberOfValues() == number_of_values(cell_value_per_edge)); + + auto edge_to_cell_matrix = connectivity.edgeToCellMatrix(); + { + bool is_correct = true; + for (EdgeId edge_id = 0; edge_id < connectivity.numberOfEdges(); ++edge_id) { + is_correct &= (edge_to_cell_matrix[edge_id].size() == cell_value_per_edge.numberOfSubValues(edge_id)); + } + REQUIRE(is_correct); + } + + NodeValuePerEdge<int> node_value_per_edge{connectivity}; + REQUIRE(node_value_per_edge.numberOfItems() == connectivity.numberOfEdges()); + REQUIRE(node_value_per_edge.numberOfValues() == number_of_values(node_value_per_edge)); + + auto edge_to_node_matrix = connectivity.edgeToNodeMatrix(); + { + bool is_correct = true; + for (EdgeId edge_id = 0; edge_id < connectivity.numberOfEdges(); ++edge_id) { + is_correct &= (edge_to_node_matrix[edge_id].size() == node_value_per_edge.numberOfSubValues(edge_id)); + } + REQUIRE(is_correct); + } + } + + SECTION("per node") + { + EdgeValuePerNode<int> edge_value_per_node{connectivity}; + REQUIRE(edge_value_per_node.numberOfItems() == connectivity.numberOfNodes()); + REQUIRE(edge_value_per_node.numberOfValues() == number_of_values(edge_value_per_node)); + + auto node_to_edge_matrix = connectivity.nodeToEdgeMatrix(); + { + bool is_correct = true; + for (NodeId node_id = 0; node_id < connectivity.numberOfNodes(); ++node_id) { + is_correct &= (node_to_edge_matrix[node_id].size() == edge_value_per_node.numberOfSubValues(node_id)); + } + REQUIRE(is_correct); + } + + FaceValuePerNode<int> face_value_per_node{connectivity}; + REQUIRE(face_value_per_node.numberOfItems() == connectivity.numberOfNodes()); + REQUIRE(face_value_per_node.numberOfValues() == number_of_values(face_value_per_node)); + + auto node_to_face_matrix = connectivity.nodeToFaceMatrix(); + { + bool is_correct = true; + for (NodeId node_id = 0; node_id < connectivity.numberOfNodes(); ++node_id) { + is_correct &= (node_to_face_matrix[node_id].size() == face_value_per_node.numberOfSubValues(node_id)); + } + REQUIRE(is_correct); + } + + CellValuePerNode<int> cell_value_per_node{connectivity}; + REQUIRE(cell_value_per_node.numberOfItems() == connectivity.numberOfNodes()); + REQUIRE(cell_value_per_node.numberOfValues() == number_of_values(cell_value_per_node)); + + auto node_to_cell_matrix = connectivity.nodeToCellMatrix(); + { + bool is_correct = true; + for (NodeId node_id = 0; node_id < connectivity.numberOfNodes(); ++node_id) { + is_correct &= (node_to_cell_matrix[node_id].size() == cell_value_per_node.numberOfSubValues(node_id)); + } + REQUIRE(is_correct); + } } - REQUIRE(is_correct); } } + } - SECTION("per node") - { - CellValuePerNode<int> cell_value_per_node{connectivity}; - REQUIRE(cell_value_per_node.numberOfItems() == connectivity.numberOfNodes()); - REQUIRE(cell_value_per_node.numberOfValues() == number_of_values(cell_value_per_node)); + SECTION("3D") + { + std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - auto node_to_cell_matrix = connectivity.nodeToCellMatrix(); + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) { - bool is_correct = true; - for (NodeId node_id = 0; node_id < connectivity.numberOfNodes(); ++node_id) { - is_correct &= (node_to_cell_matrix[node_id].size() == cell_value_per_node.numberOfSubValues(node_id)); + auto mesh_3d = named_mesh.mesh(); + + const Connectivity<3>& connectivity = mesh_3d->connectivity(); + + SECTION("per cell") + { + NodeValuePerCell<int> node_value_per_cell{connectivity}; + REQUIRE(node_value_per_cell.numberOfItems() == connectivity.numberOfCells()); + REQUIRE(node_value_per_cell.numberOfValues() == number_of_values(node_value_per_cell)); + + auto cell_to_node_matrix = connectivity.cellToNodeMatrix(); + { + bool is_correct = true; + for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { + is_correct &= (cell_to_node_matrix[cell_id].size() == node_value_per_cell.numberOfSubValues(cell_id)); + } + REQUIRE(is_correct); + } + + EdgeValuePerCell<int> edge_value_per_cell{connectivity}; + REQUIRE(edge_value_per_cell.numberOfItems() == connectivity.numberOfCells()); + REQUIRE(edge_value_per_cell.numberOfValues() == number_of_values(edge_value_per_cell)); + + auto cell_to_edge_matrix = connectivity.cellToEdgeMatrix(); + { + bool is_correct = true; + for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { + is_correct &= (cell_to_edge_matrix[cell_id].size() == edge_value_per_cell.numberOfSubValues(cell_id)); + } + REQUIRE(is_correct); + } + + FaceValuePerCell<int> face_value_per_cell{connectivity}; + REQUIRE(face_value_per_cell.numberOfItems() == connectivity.numberOfCells()); + REQUIRE(face_value_per_cell.numberOfValues() == number_of_values(face_value_per_cell)); + + auto cell_to_face_matrix = connectivity.cellToFaceMatrix(); + { + bool is_correct = true; + for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { + is_correct &= (cell_to_face_matrix[cell_id].size() == face_value_per_cell.numberOfSubValues(cell_id)); + } + REQUIRE(is_correct); + } + } + + SECTION("per face") + { + CellValuePerFace<int> cell_value_per_face{connectivity}; + REQUIRE(cell_value_per_face.numberOfItems() == connectivity.numberOfFaces()); + REQUIRE(cell_value_per_face.numberOfValues() == number_of_values(cell_value_per_face)); + + auto face_to_cell_matrix = connectivity.faceToCellMatrix(); + { + bool is_correct = true; + for (FaceId face_id = 0; face_id < connectivity.numberOfFaces(); ++face_id) { + is_correct &= (face_to_cell_matrix[face_id].size() == cell_value_per_face.numberOfSubValues(face_id)); + } + REQUIRE(is_correct); + } + + EdgeValuePerFace<int> edge_value_per_face{connectivity}; + REQUIRE(edge_value_per_face.numberOfItems() == connectivity.numberOfFaces()); + REQUIRE(edge_value_per_face.numberOfValues() == number_of_values(edge_value_per_face)); + + auto face_to_edge_matrix = connectivity.faceToEdgeMatrix(); + { + bool is_correct = true; + for (FaceId face_id = 0; face_id < connectivity.numberOfFaces(); ++face_id) { + is_correct &= (face_to_edge_matrix[face_id].size() == edge_value_per_face.numberOfSubValues(face_id)); + } + REQUIRE(is_correct); + } + + NodeValuePerFace<int> node_value_per_face{connectivity}; + REQUIRE(node_value_per_face.numberOfItems() == connectivity.numberOfFaces()); + REQUIRE(node_value_per_face.numberOfValues() == number_of_values(node_value_per_face)); + + auto face_to_node_matrix = connectivity.faceToNodeMatrix(); + { + bool is_correct = true; + for (FaceId face_id = 0; face_id < connectivity.numberOfFaces(); ++face_id) { + is_correct &= (face_to_node_matrix[face_id].size() == node_value_per_face.numberOfSubValues(face_id)); + } + REQUIRE(is_correct); + } + } + + SECTION("per edge") + { + CellValuePerEdge<int> cell_value_per_edge{connectivity}; + REQUIRE(cell_value_per_edge.numberOfItems() == connectivity.numberOfEdges()); + REQUIRE(cell_value_per_edge.numberOfValues() == number_of_values(cell_value_per_edge)); + + auto edge_to_cell_matrix = connectivity.edgeToCellMatrix(); + { + bool is_correct = true; + for (EdgeId edge_id = 0; edge_id < connectivity.numberOfEdges(); ++edge_id) { + is_correct &= (edge_to_cell_matrix[edge_id].size() == cell_value_per_edge.numberOfSubValues(edge_id)); + } + REQUIRE(is_correct); + } + + FaceValuePerEdge<int> face_value_per_edge{connectivity}; + REQUIRE(face_value_per_edge.numberOfItems() == connectivity.numberOfEdges()); + REQUIRE(face_value_per_edge.numberOfValues() == number_of_values(face_value_per_edge)); + + auto edge_to_face_matrix = connectivity.edgeToFaceMatrix(); + { + bool is_correct = true; + for (EdgeId edge_id = 0; edge_id < connectivity.numberOfEdges(); ++edge_id) { + is_correct &= (edge_to_face_matrix[edge_id].size() == face_value_per_edge.numberOfSubValues(edge_id)); + } + REQUIRE(is_correct); + } + + NodeValuePerEdge<int> node_value_per_edge{connectivity}; + REQUIRE(node_value_per_edge.numberOfItems() == connectivity.numberOfEdges()); + REQUIRE(node_value_per_edge.numberOfValues() == number_of_values(node_value_per_edge)); + + auto edge_to_node_matrix = connectivity.edgeToNodeMatrix(); + { + bool is_correct = true; + for (EdgeId edge_id = 0; edge_id < connectivity.numberOfEdges(); ++edge_id) { + is_correct &= (edge_to_node_matrix[edge_id].size() == node_value_per_edge.numberOfSubValues(edge_id)); + } + REQUIRE(is_correct); + } + } + + SECTION("per node") + { + EdgeValuePerNode<int> edge_value_per_node{connectivity}; + REQUIRE(edge_value_per_node.numberOfItems() == connectivity.numberOfNodes()); + REQUIRE(edge_value_per_node.numberOfValues() == number_of_values(edge_value_per_node)); + + auto node_to_edge_matrix = connectivity.nodeToEdgeMatrix(); + { + bool is_correct = true; + for (NodeId node_id = 0; node_id < connectivity.numberOfNodes(); ++node_id) { + is_correct &= (node_to_edge_matrix[node_id].size() == edge_value_per_node.numberOfSubValues(node_id)); + } + REQUIRE(is_correct); + } + + FaceValuePerNode<int> face_value_per_node{connectivity}; + REQUIRE(face_value_per_node.numberOfItems() == connectivity.numberOfNodes()); + REQUIRE(face_value_per_node.numberOfValues() == number_of_values(face_value_per_node)); + + auto node_to_face_matrix = connectivity.nodeToFaceMatrix(); + { + bool is_correct = true; + for (NodeId node_id = 0; node_id < connectivity.numberOfNodes(); ++node_id) { + is_correct &= (node_to_face_matrix[node_id].size() == face_value_per_node.numberOfSubValues(node_id)); + } + REQUIRE(is_correct); + } + + CellValuePerNode<int> cell_value_per_node{connectivity}; + REQUIRE(cell_value_per_node.numberOfItems() == connectivity.numberOfNodes()); + REQUIRE(cell_value_per_node.numberOfValues() == number_of_values(cell_value_per_node)); + + auto node_to_cell_matrix = connectivity.nodeToCellMatrix(); + { + bool is_correct = true; + for (NodeId node_id = 0; node_id < connectivity.numberOfNodes(); ++node_id) { + is_correct &= (node_to_cell_matrix[node_id].size() == cell_value_per_node.numberOfSubValues(node_id)); + } + REQUIRE(is_correct); + } } - REQUIRE(is_correct); } } } + } - SECTION("2D") + SECTION("array view") + { + SECTION("1D") { - const Mesh<Connectivity<2>>& mesh_2d = *MeshDataBaseForTests::get().cartesianMesh2D(); - const Connectivity<2>& connectivity = mesh_2d.connectivity(); + std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - SECTION("per cell") - { - NodeValuePerCell<int> node_value_per_cell{connectivity}; - REQUIRE(node_value_per_cell.numberOfItems() == connectivity.numberOfCells()); - REQUIRE(node_value_per_cell.numberOfValues() == number_of_values(node_value_per_cell)); - - auto cell_to_node_matrix = connectivity.cellToNodeMatrix(); + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) { - bool is_correct = true; - for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { - is_correct &= (cell_to_node_matrix[cell_id].size() == node_value_per_cell.numberOfSubValues(cell_id)); - } - REQUIRE(is_correct); - } + auto mesh_1d = named_mesh.mesh(); - EdgeValuePerCell<int> edge_value_per_cell{connectivity}; - REQUIRE(edge_value_per_cell.numberOfItems() == connectivity.numberOfCells()); - REQUIRE(edge_value_per_cell.numberOfValues() == number_of_values(edge_value_per_cell)); + const Connectivity<1>& connectivity = mesh_1d->connectivity(); - auto cell_to_edge_matrix = connectivity.cellToEdgeMatrix(); - { - bool is_correct = true; - for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { - is_correct &= (cell_to_edge_matrix[cell_id].size() == edge_value_per_cell.numberOfSubValues(cell_id)); + EdgeValuePerCell<size_t> edge_values_per_cell{connectivity}; + { + size_t value = 0; + for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { + for (size_t i_edge = 0; i_edge < edge_values_per_cell.numberOfSubValues(cell_id); ++i_edge) { + edge_values_per_cell(cell_id, i_edge) = value++; + } + } } - REQUIRE(is_correct); - } - - FaceValuePerCell<int> face_value_per_cell{connectivity}; - REQUIRE(face_value_per_cell.numberOfItems() == connectivity.numberOfCells()); - REQUIRE(face_value_per_cell.numberOfValues() == number_of_values(face_value_per_cell)); - - auto cell_to_face_matrix = connectivity.cellToFaceMatrix(); - { - bool is_correct = true; - for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { - is_correct &= (cell_to_face_matrix[cell_id].size() == face_value_per_cell.numberOfSubValues(cell_id)); + { + bool is_same = true; + for (size_t i = 0; i < edge_values_per_cell.numberOfValues(); ++i) { + is_same &= (edge_values_per_cell[i] == i); + } + REQUIRE(is_same); } - REQUIRE(is_correct); - } - } - - SECTION("per face") - { - CellValuePerFace<int> cell_value_per_face{connectivity}; - REQUIRE(cell_value_per_face.numberOfItems() == connectivity.numberOfFaces()); - REQUIRE(cell_value_per_face.numberOfValues() == number_of_values(cell_value_per_face)); - auto face_to_cell_matrix = connectivity.faceToCellMatrix(); - { - bool is_correct = true; - for (FaceId face_id = 0; face_id < connectivity.numberOfFaces(); ++face_id) { - is_correct &= (face_to_cell_matrix[face_id].size() == cell_value_per_face.numberOfSubValues(face_id)); + for (size_t i = 0; i < edge_values_per_cell.numberOfValues(); ++i) { + edge_values_per_cell[i] = i * i + 1; } - REQUIRE(is_correct); - } - - NodeValuePerFace<int> node_value_per_face{connectivity}; - REQUIRE(node_value_per_face.numberOfItems() == connectivity.numberOfFaces()); - REQUIRE(node_value_per_face.numberOfValues() == number_of_values(node_value_per_face)); - - auto face_to_node_matrix = connectivity.faceToNodeMatrix(); - { - bool is_correct = true; - for (FaceId face_id = 0; face_id < connectivity.numberOfFaces(); ++face_id) { - is_correct &= (face_to_node_matrix[face_id].size() == node_value_per_face.numberOfSubValues(face_id)); + { + bool is_same = true; + size_t i = 0; + for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { + for (size_t i_edge = 0; i_edge < edge_values_per_cell.numberOfSubValues(cell_id); ++i_edge, ++i) { + is_same &= (edge_values_per_cell(cell_id, i_edge) == i * i + 1); + } + } + REQUIRE(is_same); } - REQUIRE(is_correct); } } + } - SECTION("per edge") - { - CellValuePerEdge<int> cell_value_per_edge{connectivity}; - REQUIRE(cell_value_per_edge.numberOfItems() == connectivity.numberOfEdges()); - REQUIRE(cell_value_per_edge.numberOfValues() == number_of_values(cell_value_per_edge)); + SECTION("2D") + { + std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - auto edge_to_cell_matrix = connectivity.edgeToCellMatrix(); + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) { - bool is_correct = true; - for (EdgeId edge_id = 0; edge_id < connectivity.numberOfEdges(); ++edge_id) { - is_correct &= (edge_to_cell_matrix[edge_id].size() == cell_value_per_edge.numberOfSubValues(edge_id)); - } - REQUIRE(is_correct); - } + auto mesh_2d = named_mesh.mesh(); - NodeValuePerEdge<int> node_value_per_edge{connectivity}; - REQUIRE(node_value_per_edge.numberOfItems() == connectivity.numberOfEdges()); - REQUIRE(node_value_per_edge.numberOfValues() == number_of_values(node_value_per_edge)); + const Connectivity<2>& connectivity = mesh_2d->connectivity(); - auto edge_to_node_matrix = connectivity.edgeToNodeMatrix(); - { - bool is_correct = true; - for (EdgeId edge_id = 0; edge_id < connectivity.numberOfEdges(); ++edge_id) { - is_correct &= (edge_to_node_matrix[edge_id].size() == node_value_per_edge.numberOfSubValues(edge_id)); + CellValuePerFace<size_t> cell_values_per_face{connectivity}; + { + size_t value = 0; + for (FaceId face_id = 0; face_id < connectivity.numberOfFaces(); ++face_id) { + for (size_t i_cell = 0; i_cell < cell_values_per_face.numberOfSubValues(face_id); ++i_cell) { + cell_values_per_face(face_id, i_cell) = value++; + } + } } - REQUIRE(is_correct); - } - } - - SECTION("per node") - { - EdgeValuePerNode<int> edge_value_per_node{connectivity}; - REQUIRE(edge_value_per_node.numberOfItems() == connectivity.numberOfNodes()); - REQUIRE(edge_value_per_node.numberOfValues() == number_of_values(edge_value_per_node)); - - auto node_to_edge_matrix = connectivity.nodeToEdgeMatrix(); - { - bool is_correct = true; - for (NodeId node_id = 0; node_id < connectivity.numberOfNodes(); ++node_id) { - is_correct &= (node_to_edge_matrix[node_id].size() == edge_value_per_node.numberOfSubValues(node_id)); + { + bool is_same = true; + for (size_t i = 0; i < cell_values_per_face.numberOfValues(); ++i) { + is_same &= (cell_values_per_face[i] == i); + } + REQUIRE(is_same); } - REQUIRE(is_correct); - } - - FaceValuePerNode<int> face_value_per_node{connectivity}; - REQUIRE(face_value_per_node.numberOfItems() == connectivity.numberOfNodes()); - REQUIRE(face_value_per_node.numberOfValues() == number_of_values(face_value_per_node)); - - auto node_to_face_matrix = connectivity.nodeToFaceMatrix(); - { - bool is_correct = true; - for (NodeId node_id = 0; node_id < connectivity.numberOfNodes(); ++node_id) { - is_correct &= (node_to_face_matrix[node_id].size() == face_value_per_node.numberOfSubValues(node_id)); + for (size_t i = 0; i < cell_values_per_face.numberOfValues(); ++i) { + cell_values_per_face[i] = 3 * i + 1; } - REQUIRE(is_correct); - } - - CellValuePerNode<int> cell_value_per_node{connectivity}; - REQUIRE(cell_value_per_node.numberOfItems() == connectivity.numberOfNodes()); - REQUIRE(cell_value_per_node.numberOfValues() == number_of_values(cell_value_per_node)); - - auto node_to_cell_matrix = connectivity.nodeToCellMatrix(); - { - bool is_correct = true; - for (NodeId node_id = 0; node_id < connectivity.numberOfNodes(); ++node_id) { - is_correct &= (node_to_cell_matrix[node_id].size() == cell_value_per_node.numberOfSubValues(node_id)); + { + bool is_same = true; + size_t i = 0; + for (FaceId face_id = 0; face_id < connectivity.numberOfFaces(); ++face_id) { + for (size_t i_cell = 0; i_cell < cell_values_per_face.numberOfSubValues(face_id); ++i_cell, ++i) { + is_same &= (cell_values_per_face(face_id, i_cell) == 3 * i + 1); + } + } + REQUIRE(is_same); } - REQUIRE(is_correct); } } } SECTION("3D") { - const Mesh<Connectivity<3>>& mesh_3d = *MeshDataBaseForTests::get().cartesianMesh3D(); - const Connectivity<3>& connectivity = mesh_3d.connectivity(); - - SECTION("per cell") - { - NodeValuePerCell<int> node_value_per_cell{connectivity}; - REQUIRE(node_value_per_cell.numberOfItems() == connectivity.numberOfCells()); - REQUIRE(node_value_per_cell.numberOfValues() == number_of_values(node_value_per_cell)); + std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - auto cell_to_node_matrix = connectivity.cellToNodeMatrix(); + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) { - bool is_correct = true; - for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { - is_correct &= (cell_to_node_matrix[cell_id].size() == node_value_per_cell.numberOfSubValues(cell_id)); - } - REQUIRE(is_correct); - } + auto mesh_3d = named_mesh.mesh(); - EdgeValuePerCell<int> edge_value_per_cell{connectivity}; - REQUIRE(edge_value_per_cell.numberOfItems() == connectivity.numberOfCells()); - REQUIRE(edge_value_per_cell.numberOfValues() == number_of_values(edge_value_per_cell)); + const Connectivity<3>& connectivity = mesh_3d->connectivity(); - auto cell_to_edge_matrix = connectivity.cellToEdgeMatrix(); - { - bool is_correct = true; - for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { - is_correct &= (cell_to_edge_matrix[cell_id].size() == edge_value_per_cell.numberOfSubValues(cell_id)); + FaceValuePerNode<size_t> face_values_per_node{connectivity}; + { + size_t value = 0; + for (NodeId node_id = 0; node_id < connectivity.numberOfNodes(); ++node_id) { + for (size_t i_face = 0; i_face < face_values_per_node.numberOfSubValues(node_id); ++i_face) { + face_values_per_node.itemValues(node_id)[i_face] = value++; + } + } + } + { + bool is_same = true; + for (size_t i = 0; i < face_values_per_node.numberOfValues(); ++i) { + is_same &= (face_values_per_node[i] == i); + } + REQUIRE(is_same); } - REQUIRE(is_correct); - } - - FaceValuePerCell<int> face_value_per_cell{connectivity}; - REQUIRE(face_value_per_cell.numberOfItems() == connectivity.numberOfCells()); - REQUIRE(face_value_per_cell.numberOfValues() == number_of_values(face_value_per_cell)); - auto cell_to_face_matrix = connectivity.cellToFaceMatrix(); - { - bool is_correct = true; - for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { - is_correct &= (cell_to_face_matrix[cell_id].size() == face_value_per_cell.numberOfSubValues(cell_id)); + for (size_t i = 0; i < face_values_per_node.numberOfValues(); ++i) { + face_values_per_node[i] = 3 + i * i; + } + { + bool is_same = true; + size_t i = 0; + for (NodeId node_id = 0; node_id < connectivity.numberOfNodes(); ++node_id) { + for (size_t i_face = 0; i_face < face_values_per_node.numberOfSubValues(node_id); ++i_face, ++i) { + is_same &= (face_values_per_node.itemValues(node_id)[i_face] == 3 + i * i); + } + } + REQUIRE(is_same); } - REQUIRE(is_correct); } } + } + } - SECTION("per face") - { - CellValuePerFace<int> cell_value_per_face{connectivity}; - REQUIRE(cell_value_per_face.numberOfItems() == connectivity.numberOfFaces()); - REQUIRE(cell_value_per_face.numberOfValues() == number_of_values(cell_value_per_face)); + SECTION("copy") + { + std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - auto face_to_cell_matrix = connectivity.faceToCellMatrix(); - { - bool is_correct = true; - for (FaceId face_id = 0; face_id < connectivity.numberOfFaces(); ++face_id) { - is_correct &= (face_to_cell_matrix[face_id].size() == cell_value_per_face.numberOfSubValues(face_id)); - } - REQUIRE(is_correct); - } + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_3d = named_mesh.mesh(); - EdgeValuePerFace<int> edge_value_per_face{connectivity}; - REQUIRE(edge_value_per_face.numberOfItems() == connectivity.numberOfFaces()); - REQUIRE(edge_value_per_face.numberOfValues() == number_of_values(edge_value_per_face)); + const Connectivity<3>& connectivity = mesh_3d->connectivity(); - auto face_to_edge_matrix = connectivity.faceToEdgeMatrix(); + SECTION("classic") { - bool is_correct = true; - for (FaceId face_id = 0; face_id < connectivity.numberOfFaces(); ++face_id) { - is_correct &= (face_to_edge_matrix[face_id].size() == edge_value_per_face.numberOfSubValues(face_id)); - } - REQUIRE(is_correct); - } + NodeValuePerCell<size_t> node_value_per_cell{connectivity}; - NodeValuePerFace<int> node_value_per_face{connectivity}; - REQUIRE(node_value_per_face.numberOfItems() == connectivity.numberOfFaces()); - REQUIRE(node_value_per_face.numberOfValues() == number_of_values(node_value_per_face)); - - auto face_to_node_matrix = connectivity.faceToNodeMatrix(); - { - bool is_correct = true; - for (FaceId face_id = 0; face_id < connectivity.numberOfFaces(); ++face_id) { - is_correct &= (face_to_node_matrix[face_id].size() == node_value_per_face.numberOfSubValues(face_id)); + { + size_t value = 0; + for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { + for (size_t i_node = 0; i_node < node_value_per_cell.numberOfSubValues(cell_id); ++i_node) { + node_value_per_cell.itemValues(cell_id)[i_node] = value++; + } + } } - REQUIRE(is_correct); - } - } - SECTION("per edge") - { - CellValuePerEdge<int> cell_value_per_edge{connectivity}; - REQUIRE(cell_value_per_edge.numberOfItems() == connectivity.numberOfEdges()); - REQUIRE(cell_value_per_edge.numberOfValues() == number_of_values(cell_value_per_edge)); - - auto edge_to_cell_matrix = connectivity.edgeToCellMatrix(); - { - bool is_correct = true; - for (EdgeId edge_id = 0; edge_id < connectivity.numberOfEdges(); ++edge_id) { - is_correct &= (edge_to_cell_matrix[edge_id].size() == cell_value_per_edge.numberOfSubValues(edge_id)); - } - REQUIRE(is_correct); - } + NodeValuePerCell<size_t> copy_node_value_per_cell = copy(node_value_per_cell); - FaceValuePerEdge<int> face_value_per_edge{connectivity}; - REQUIRE(face_value_per_edge.numberOfItems() == connectivity.numberOfEdges()); - REQUIRE(face_value_per_edge.numberOfValues() == number_of_values(face_value_per_edge)); + { + bool is_same = true; + for (size_t i = 0; i < copy_node_value_per_cell.numberOfValues(); ++i) { + is_same &= (copy_node_value_per_cell[i] == node_value_per_cell[i]); + } - auto edge_to_face_matrix = connectivity.edgeToFaceMatrix(); - { - bool is_correct = true; - for (EdgeId edge_id = 0; edge_id < connectivity.numberOfEdges(); ++edge_id) { - is_correct &= (edge_to_face_matrix[edge_id].size() == face_value_per_edge.numberOfSubValues(edge_id)); + REQUIRE(is_same); } - REQUIRE(is_correct); - } - - NodeValuePerEdge<int> node_value_per_edge{connectivity}; - REQUIRE(node_value_per_edge.numberOfItems() == connectivity.numberOfEdges()); - REQUIRE(node_value_per_edge.numberOfValues() == number_of_values(node_value_per_edge)); - auto edge_to_node_matrix = connectivity.edgeToNodeMatrix(); - { - bool is_correct = true; - for (EdgeId edge_id = 0; edge_id < connectivity.numberOfEdges(); ++edge_id) { - is_correct &= (edge_to_node_matrix[edge_id].size() == node_value_per_edge.numberOfSubValues(edge_id)); + { + for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { + for (size_t i_node = 0; i_node < node_value_per_cell.numberOfSubValues(cell_id); ++i_node) { + node_value_per_cell.itemValues(cell_id)[i_node] = i_node; + } + } } - REQUIRE(is_correct); - } - } - SECTION("per node") - { - EdgeValuePerNode<int> edge_value_per_node{connectivity}; - REQUIRE(edge_value_per_node.numberOfItems() == connectivity.numberOfNodes()); - REQUIRE(edge_value_per_node.numberOfValues() == number_of_values(edge_value_per_node)); + { + bool is_same = true; + for (size_t i = 0; i < copy_node_value_per_cell.numberOfValues(); ++i) { + is_same &= (copy_node_value_per_cell[i] == node_value_per_cell[i]); + } - auto node_to_edge_matrix = connectivity.nodeToEdgeMatrix(); - { - bool is_correct = true; - for (NodeId node_id = 0; node_id < connectivity.numberOfNodes(); ++node_id) { - is_correct &= (node_to_edge_matrix[node_id].size() == edge_value_per_node.numberOfSubValues(node_id)); + REQUIRE(not is_same); } - REQUIRE(is_correct); } - FaceValuePerNode<int> face_value_per_node{connectivity}; - REQUIRE(face_value_per_node.numberOfItems() == connectivity.numberOfNodes()); - REQUIRE(face_value_per_node.numberOfValues() == number_of_values(face_value_per_node)); - - auto node_to_face_matrix = connectivity.nodeToFaceMatrix(); + SECTION("from weak") { - bool is_correct = true; - for (NodeId node_id = 0; node_id < connectivity.numberOfNodes(); ++node_id) { - is_correct &= (node_to_face_matrix[node_id].size() == face_value_per_node.numberOfSubValues(node_id)); - } - REQUIRE(is_correct); - } + WeakNodeValuePerCell<size_t> node_value_per_cell{connectivity}; - CellValuePerNode<int> cell_value_per_node{connectivity}; - REQUIRE(cell_value_per_node.numberOfItems() == connectivity.numberOfNodes()); - REQUIRE(cell_value_per_node.numberOfValues() == number_of_values(cell_value_per_node)); - - auto node_to_cell_matrix = connectivity.nodeToCellMatrix(); - { - bool is_correct = true; - for (NodeId node_id = 0; node_id < connectivity.numberOfNodes(); ++node_id) { - is_correct &= (node_to_cell_matrix[node_id].size() == cell_value_per_node.numberOfSubValues(node_id)); + { + size_t value = 0; + for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { + for (size_t i_node = 0; i_node < node_value_per_cell.numberOfSubValues(cell_id); ++i_node) { + node_value_per_cell.itemValues(cell_id)[i_node] = value++; + } + } } - REQUIRE(is_correct); - } - } - } - } - SECTION("array view") - { - SECTION("1D") - { - const Mesh<Connectivity<1>>& mesh_1d = *MeshDataBaseForTests::get().cartesianMesh1D(); - const Connectivity<1>& connectivity = mesh_1d.connectivity(); + NodeValuePerCell<size_t> copy_node_value_per_cell = copy(node_value_per_cell); - EdgeValuePerCell<size_t> edge_values_per_cell{connectivity}; - { - size_t value = 0; - for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { - for (size_t i_edge = 0; i_edge < edge_values_per_cell.numberOfSubValues(cell_id); ++i_edge) { - edge_values_per_cell(cell_id, i_edge) = value++; - } - } - } - { - bool is_same = true; - for (size_t i = 0; i < edge_values_per_cell.numberOfValues(); ++i) { - is_same &= (edge_values_per_cell[i] == i); - } - REQUIRE(is_same); - } + { + bool is_same = true; + for (size_t i = 0; i < copy_node_value_per_cell.numberOfValues(); ++i) { + is_same &= (copy_node_value_per_cell[i] == node_value_per_cell[i]); + } - for (size_t i = 0; i < edge_values_per_cell.numberOfValues(); ++i) { - edge_values_per_cell[i] = i * i + 1; - } - { - bool is_same = true; - size_t i = 0; - for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { - for (size_t i_edge = 0; i_edge < edge_values_per_cell.numberOfSubValues(cell_id); ++i_edge, ++i) { - is_same &= (edge_values_per_cell(cell_id, i_edge) == i * i + 1); + REQUIRE(is_same); } - } - REQUIRE(is_same); - } - } - - SECTION("2D") - { - const Mesh<Connectivity<2>>& mesh_2d = *MeshDataBaseForTests::get().cartesianMesh2D(); - const Connectivity<2>& connectivity = mesh_2d.connectivity(); - CellValuePerFace<size_t> cell_values_per_face{connectivity}; - { - size_t value = 0; - for (FaceId face_id = 0; face_id < connectivity.numberOfFaces(); ++face_id) { - for (size_t i_cell = 0; i_cell < cell_values_per_face.numberOfSubValues(face_id); ++i_cell) { - cell_values_per_face(face_id, i_cell) = value++; - } - } - } - { - bool is_same = true; - for (size_t i = 0; i < cell_values_per_face.numberOfValues(); ++i) { - is_same &= (cell_values_per_face[i] == i); - } - REQUIRE(is_same); - } - for (size_t i = 0; i < cell_values_per_face.numberOfValues(); ++i) { - cell_values_per_face[i] = 3 * i + 1; - } - { - bool is_same = true; - size_t i = 0; - for (FaceId face_id = 0; face_id < connectivity.numberOfFaces(); ++face_id) { - for (size_t i_cell = 0; i_cell < cell_values_per_face.numberOfSubValues(face_id); ++i_cell, ++i) { - is_same &= (cell_values_per_face(face_id, i_cell) == 3 * i + 1); + { + for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { + for (size_t i_node = 0; i_node < node_value_per_cell.numberOfSubValues(cell_id); ++i_node) { + node_value_per_cell.itemValues(cell_id)[i_node] = i_node; + } + } } - } - REQUIRE(is_same); - } - } - SECTION("3D") - { - const Mesh<Connectivity<3>>& mesh_3d = *MeshDataBaseForTests::get().cartesianMesh3D(); - const Connectivity<3>& connectivity = mesh_3d.connectivity(); + { + bool is_same = true; + for (size_t i = 0; i < copy_node_value_per_cell.numberOfValues(); ++i) { + is_same &= (copy_node_value_per_cell[i] == node_value_per_cell[i]); + } - FaceValuePerNode<size_t> face_values_per_node{connectivity}; - { - size_t value = 0; - for (NodeId node_id = 0; node_id < connectivity.numberOfNodes(); ++node_id) { - for (size_t i_face = 0; i_face < face_values_per_node.numberOfSubValues(node_id); ++i_face) { - face_values_per_node.itemValues(node_id)[i_face] = value++; + REQUIRE(not is_same); } } } - { - bool is_same = true; - for (size_t i = 0; i < face_values_per_node.numberOfValues(); ++i) { - is_same &= (face_values_per_node[i] == i); - } - REQUIRE(is_same); - } - - for (size_t i = 0; i < face_values_per_node.numberOfValues(); ++i) { - face_values_per_node[i] = 3 + i * i; - } - { - bool is_same = true; - size_t i = 0; - for (NodeId node_id = 0; node_id < connectivity.numberOfNodes(); ++node_id) { - for (size_t i_face = 0; i_face < face_values_per_node.numberOfSubValues(node_id); ++i_face, ++i) { - is_same &= (face_values_per_node.itemValues(node_id)[i_face] == 3 + i * i); - } - } - REQUIRE(is_same); - } } } - SECTION("copy") + SECTION("WeakSubItemValuePerItem") { - const Mesh<Connectivity<3>>& mesh_3d = *MeshDataBaseForTests::get().cartesianMesh3D(); - const Connectivity<3>& connectivity = mesh_3d.connectivity(); - - SECTION("classic") - { - NodeValuePerCell<size_t> node_value_per_cell{connectivity}; + std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) { - size_t value = 0; - for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { - for (size_t i_node = 0; i_node < node_value_per_cell.numberOfSubValues(cell_id); ++i_node) { - node_value_per_cell.itemValues(cell_id)[i_node] = value++; - } - } - } - - NodeValuePerCell<size_t> copy_node_value_per_cell = copy(node_value_per_cell); + auto mesh_2d = named_mesh.mesh(); - { - bool is_same = true; - for (size_t i = 0; i < copy_node_value_per_cell.numberOfValues(); ++i) { - is_same &= (copy_node_value_per_cell[i] == node_value_per_cell[i]); - } - - REQUIRE(is_same); - } + const Connectivity<2>& connectivity = mesh_2d->connectivity(); - { - for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { - for (size_t i_node = 0; i_node < node_value_per_cell.numberOfSubValues(cell_id); ++i_node) { - node_value_per_cell.itemValues(cell_id)[i_node] = i_node; - } - } - } + WeakFaceValuePerCell<int> weak_face_value_per_cell{connectivity}; - { - bool is_same = true; - for (size_t i = 0; i < copy_node_value_per_cell.numberOfValues(); ++i) { - is_same &= (copy_node_value_per_cell[i] == node_value_per_cell[i]); + for (size_t i = 0; i < weak_face_value_per_cell.numberOfValues(); ++i) { + weak_face_value_per_cell[i] = i; } - REQUIRE(not is_same); - } - } - - SECTION("from weak") - { - WeakNodeValuePerCell<size_t> node_value_per_cell{connectivity}; - - { - size_t value = 0; - for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { - for (size_t i_node = 0; i_node < node_value_per_cell.numberOfSubValues(cell_id); ++i_node) { - node_value_per_cell.itemValues(cell_id)[i_node] = value++; - } - } - } + FaceValuePerCell<const int> face_value_per_cell{weak_face_value_per_cell}; - NodeValuePerCell<size_t> copy_node_value_per_cell = copy(node_value_per_cell); + REQUIRE(face_value_per_cell.connectivity_ptr() == weak_face_value_per_cell.connectivity_ptr()); - { bool is_same = true; - for (size_t i = 0; i < copy_node_value_per_cell.numberOfValues(); ++i) { - is_same &= (copy_node_value_per_cell[i] == node_value_per_cell[i]); + for (size_t i = 0; i < weak_face_value_per_cell.numberOfValues(); ++i) { + is_same &= (face_value_per_cell[i] == weak_face_value_per_cell[i]); } - REQUIRE(is_same); } - - { - for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { - for (size_t i_node = 0; i_node < node_value_per_cell.numberOfSubValues(cell_id); ++i_node) { - node_value_per_cell.itemValues(cell_id)[i_node] = i_node; - } - } - } - - { - bool is_same = true; - for (size_t i = 0; i < copy_node_value_per_cell.numberOfValues(); ++i) { - is_same &= (copy_node_value_per_cell[i] == node_value_per_cell[i]); - } - - REQUIRE(not is_same); - } } } - SECTION("WeakSubItemValuePerItem") - { - const Mesh<Connectivity<2>>& mesh_2d = *MeshDataBaseForTests::get().cartesianMesh2D(); - const Connectivity<2>& connectivity = mesh_2d.connectivity(); - - WeakFaceValuePerCell<int> weak_face_value_per_cell{connectivity}; - - for (size_t i = 0; i < weak_face_value_per_cell.numberOfValues(); ++i) { - weak_face_value_per_cell[i] = i; - } - - FaceValuePerCell<const int> face_value_per_cell{weak_face_value_per_cell}; - - REQUIRE(face_value_per_cell.connectivity_ptr() == weak_face_value_per_cell.connectivity_ptr()); - - bool is_same = true; - for (size_t i = 0; i < weak_face_value_per_cell.numberOfValues(); ++i) { - is_same &= (face_value_per_cell[i] == weak_face_value_per_cell[i]); - } - REQUIRE(is_same); - } - #ifndef NDEBUG SECTION("error") { @@ -758,59 +822,67 @@ TEST_CASE("SubItemValuePerItem", "[mesh]") SECTION("checking for bounds violation") { - const Mesh<Connectivity<3>>& mesh_3d = *MeshDataBaseForTests::get().cartesianMesh3D(); - const Connectivity<3>& connectivity = mesh_3d.connectivity(); + std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - CellValuePerFace<int> cell_value_per_face{connectivity}; - { - FaceId invalid_face_id = connectivity.numberOfFaces(); - REQUIRE_THROWS_AS(cell_value_per_face(invalid_face_id, 0), AssertError); - } - if (connectivity.numberOfFaces() > 0) { - FaceId face_id = 0; - const auto& cell_values = cell_value_per_face.itemValues(face_id); - REQUIRE_THROWS_AS(cell_value_per_face(face_id, cell_values.size()), AssertError); - REQUIRE_THROWS_AS(cell_values[cell_values.size()], AssertError); - REQUIRE_THROWS_AS(cell_value_per_face.itemValues(face_id)[cell_values.size()] = 2, AssertError); - } + for (auto named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_3d = named_mesh.mesh(); - FaceValuePerNode<int> face_value_per_node{connectivity}; - { - NodeId invalid_node_id = connectivity.numberOfNodes(); - REQUIRE_THROWS_AS(face_value_per_node(invalid_node_id, 0), AssertError); - } - if (connectivity.numberOfNodes() > 0) { - NodeId node_id = 0; - const auto& face_values = face_value_per_node.itemValues(node_id); - REQUIRE_THROWS_AS(face_value_per_node(node_id, face_values.size()), AssertError); - REQUIRE_THROWS_AS(face_values[face_values.size()], AssertError); - REQUIRE_THROWS_AS(face_value_per_node.itemValues(node_id)[face_values.size()] = 2, AssertError); - } + const Connectivity<3>& connectivity = mesh_3d->connectivity(); - EdgeValuePerCell<int> edge_value_per_cell{connectivity}; - { - CellId invalid_cell_id = connectivity.numberOfCells(); - REQUIRE_THROWS_AS(edge_value_per_cell(invalid_cell_id, 0), AssertError); - } - if (connectivity.numberOfCells() > 0) { - CellId cell_id = 0; - const auto& edge_values = edge_value_per_cell.itemValues(cell_id); - REQUIRE_THROWS_AS(edge_value_per_cell(cell_id, edge_values.size()), AssertError); - REQUIRE_THROWS_AS(edge_values[edge_values.size()], AssertError); - REQUIRE_THROWS_AS(edge_value_per_cell.itemValues(cell_id)[edge_values.size()] = 2, AssertError); - } + CellValuePerFace<int> cell_value_per_face{connectivity}; + { + FaceId invalid_face_id = connectivity.numberOfFaces(); + REQUIRE_THROWS_AS(cell_value_per_face(invalid_face_id, 0), AssertError); + } + if (connectivity.numberOfFaces() > 0) { + FaceId face_id = 0; + const auto& cell_values = cell_value_per_face.itemValues(face_id); + REQUIRE_THROWS_AS(cell_value_per_face(face_id, cell_values.size()), AssertError); + REQUIRE_THROWS_AS(cell_values[cell_values.size()], AssertError); + REQUIRE_THROWS_AS(cell_value_per_face.itemValues(face_id)[cell_values.size()] = 2, AssertError); + } - NodeValuePerEdge<int> node_value_per_edge{connectivity}; - { - EdgeId invalid_edge_id = connectivity.numberOfEdges(); - REQUIRE_THROWS_AS(node_value_per_edge(invalid_edge_id, 0), AssertError); - } - if (connectivity.numberOfEdges() > 0) { - EdgeId edge_id = 0; - const auto& node_values = node_value_per_edge.itemValues(edge_id); - REQUIRE_THROWS_AS(node_value_per_edge(edge_id, node_values.size()), AssertError); - REQUIRE_THROWS_AS(node_values[node_values.size()], AssertError); - REQUIRE_THROWS_AS(node_value_per_edge.itemValues(edge_id)[node_values.size()] = 2, AssertError); + FaceValuePerNode<int> face_value_per_node{connectivity}; + { + NodeId invalid_node_id = connectivity.numberOfNodes(); + REQUIRE_THROWS_AS(face_value_per_node(invalid_node_id, 0), AssertError); + } + if (connectivity.numberOfNodes() > 0) { + NodeId node_id = 0; + const auto& face_values = face_value_per_node.itemValues(node_id); + REQUIRE_THROWS_AS(face_value_per_node(node_id, face_values.size()), AssertError); + REQUIRE_THROWS_AS(face_values[face_values.size()], AssertError); + REQUIRE_THROWS_AS(face_value_per_node.itemValues(node_id)[face_values.size()] = 2, AssertError); + } + + EdgeValuePerCell<int> edge_value_per_cell{connectivity}; + { + CellId invalid_cell_id = connectivity.numberOfCells(); + REQUIRE_THROWS_AS(edge_value_per_cell(invalid_cell_id, 0), AssertError); + } + if (connectivity.numberOfCells() > 0) { + CellId cell_id = 0; + const auto& edge_values = edge_value_per_cell.itemValues(cell_id); + REQUIRE_THROWS_AS(edge_value_per_cell(cell_id, edge_values.size()), AssertError); + REQUIRE_THROWS_AS(edge_values[edge_values.size()], AssertError); + REQUIRE_THROWS_AS(edge_value_per_cell.itemValues(cell_id)[edge_values.size()] = 2, AssertError); + } + + NodeValuePerEdge<int> node_value_per_edge{connectivity}; + { + EdgeId invalid_edge_id = connectivity.numberOfEdges(); + REQUIRE_THROWS_AS(node_value_per_edge(invalid_edge_id, 0), AssertError); + } + if (connectivity.numberOfEdges() > 0) { + EdgeId edge_id = 0; + const auto& node_values = node_value_per_edge.itemValues(edge_id); + REQUIRE_THROWS_AS(node_value_per_edge(edge_id, node_values.size()), AssertError); + REQUIRE_THROWS_AS(node_values[node_values.size()], AssertError); + REQUIRE_THROWS_AS(node_value_per_edge.itemValues(edge_id)[node_values.size()] = 2, AssertError); + } + } } } } diff --git a/tests/test_TensorialGaussLegendreQuadrature.cpp b/tests/test_TensorialGaussLegendreQuadrature.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b2ac6c80c57009ea16ac8911e0609e59f60cb178 --- /dev/null +++ b/tests/test_TensorialGaussLegendreQuadrature.cpp @@ -0,0 +1,628 @@ +#include <catch2/catch_approx.hpp> +#include <catch2/catch_test_macros.hpp> +#include <catch2/matchers/catch_matchers_all.hpp> + +#include <analysis/GaussLegendreQuadratureDescriptor.hpp> +#include <analysis/QuadratureManager.hpp> +#include <analysis/TensorialGaussLegendreQuadrature.hpp> +#include <utils/Exceptions.hpp> + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("TensorialGaussLegendreQuadrature", "[analysis]") +{ + 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("degree 1") + { + const QuadratureFormula<1>& l1 = + QuadratureManager::instance().getLineFormula(GaussLegendreQuadratureDescriptor(1)); + + 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("degree 2 and 3") + { + const QuadratureFormula<1>& l2 = + QuadratureManager::instance().getLineFormula(GaussLegendreQuadratureDescriptor(2)); + const QuadratureFormula<1>& l3 = + QuadratureManager::instance().getLineFormula(GaussLegendreQuadratureDescriptor(3)); + + REQUIRE(&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("degree 4 and 5") + { + const QuadratureFormula<1>& l4 = + QuadratureManager::instance().getLineFormula(GaussLegendreQuadratureDescriptor(4)); + const QuadratureFormula<1>& l5 = + QuadratureManager::instance().getLineFormula(GaussLegendreQuadratureDescriptor(5)); + + REQUIRE(&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("degree 6 and 7") + { + const QuadratureFormula<1>& l6 = + QuadratureManager::instance().getLineFormula(GaussLegendreQuadratureDescriptor(6)); + const QuadratureFormula<1>& l7 = + QuadratureManager::instance().getLineFormula(GaussLegendreQuadratureDescriptor(7)); + + REQUIRE(&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("degree 8 and 9") + { + const QuadratureFormula<1>& l8 = + QuadratureManager::instance().getLineFormula(GaussLegendreQuadratureDescriptor(8)); + const QuadratureFormula<1>& l9 = + QuadratureManager::instance().getLineFormula(GaussLegendreQuadratureDescriptor(9)); + + REQUIRE(&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("degree 10 and 11") + { + const QuadratureFormula<1>& l10 = + QuadratureManager::instance().getLineFormula(GaussLegendreQuadratureDescriptor(10)); + const QuadratureFormula<1>& l11 = + QuadratureManager::instance().getLineFormula(GaussLegendreQuadratureDescriptor(11)); + + REQUIRE(&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("degree 12 and 13") + { + const QuadratureFormula<1>& l12 = + QuadratureManager::instance().getLineFormula(GaussLegendreQuadratureDescriptor(12)); + const QuadratureFormula<1>& l13 = + QuadratureManager::instance().getLineFormula(GaussLegendreQuadratureDescriptor(13)); + + REQUIRE(&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("degree 14 and 15") + { + const QuadratureFormula<1>& l14 = + QuadratureManager::instance().getLineFormula(GaussLegendreQuadratureDescriptor(14)); + const QuadratureFormula<1>& l15 = + QuadratureManager::instance().getLineFormula(GaussLegendreQuadratureDescriptor(15)); + + REQUIRE(&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("degree 16 and 17") + { + const QuadratureFormula<1>& l16 = + QuadratureManager::instance().getLineFormula(GaussLegendreQuadratureDescriptor(16)); + const QuadratureFormula<1>& l17 = + QuadratureManager::instance().getLineFormula(GaussLegendreQuadratureDescriptor(17)); + + REQUIRE(&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("degree 18 and 19") + { + const QuadratureFormula<1>& l18 = + QuadratureManager::instance().getLineFormula(GaussLegendreQuadratureDescriptor(18)); + const QuadratureFormula<1>& l19 = + QuadratureManager::instance().getLineFormula(GaussLegendreQuadratureDescriptor(19)); + + REQUIRE(&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("degree 20 and 21") + { + const QuadratureFormula<1>& l20 = + QuadratureManager::instance().getLineFormula(GaussLegendreQuadratureDescriptor(20)); + const QuadratureFormula<1>& l21 = + QuadratureManager::instance().getLineFormula(GaussLegendreQuadratureDescriptor(21)); + + REQUIRE(&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("degree 22 and 23") + { + const QuadratureFormula<1>& l22 = + QuadratureManager::instance().getLineFormula(GaussLegendreQuadratureDescriptor(22)); + const QuadratureFormula<1>& l23 = + QuadratureManager::instance().getLineFormula(GaussLegendreQuadratureDescriptor(23)); + + REQUIRE(&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("max implemented degree") + { + REQUIRE(QuadratureManager::instance().maxLineDegree(QuadratureType::GaussLegendre) == + TensorialGaussLegendreQuadrature<1>::max_degree); + } + } + + SECTION("2D") + { + auto integrate = [](auto f, auto quadrature_formula, const double xa, const double xb, const double ya, + const double yb) { + auto point_list = quadrature_formula.pointList(); + auto weight_list = quadrature_formula.weightList(); + + const double alphax = 0.5 * (xb - xa); + const double betax = 0.5 * (xa + xb); + + const double alphay = 0.5 * (yb - ya); + const double betay = 0.5 * (ya + yb); + + auto x = [&alphax, &betax, &alphay, &betay](auto x_hat) { + return TinyVector<2>{alphax * x_hat[0] + betax, alphay * x_hat[1] + betay}; + }; + + 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 alphax * alphay * value; + }; + + auto p6 = [](const double x) { return 7 * std::pow(x, 6); }; + auto p7 = [](const double x) { return 8 * std::pow(x, 7); }; + + auto px7y6 = [&p6, &p7](const TinyVector<2>& X) { + const double x = X[0]; + const double y = X[1]; + return p7(x) * p6(y); + }; + + SECTION("degree 6 and 7") + { + const QuadratureFormula<2>& l6 = + QuadratureManager::instance().getSquareFormula(GaussLegendreQuadratureDescriptor(6)); + const QuadratureFormula<2>& l7 = + QuadratureManager::instance().getSquareFormula(GaussLegendreQuadratureDescriptor(7)); + + REQUIRE(&l6 == &l7); + + REQUIRE(l7.numberOfPoints() == 4 * 4); + + REQUIRE(integrate(px7y6, l7, 0, 1, 0.2, 0.8) == Catch::Approx(std::pow(0.8, 7) - std::pow(0.2, 7))); + } + } + + SECTION("3D") + { + auto integrate = [](auto f, auto quadrature_formula, const double xa, const double xb, const double ya, + const double yb, const double za, const double zb) { + auto point_list = quadrature_formula.pointList(); + auto weight_list = quadrature_formula.weightList(); + + const double alphax = 0.5 * (xb - xa); + const double betax = 0.5 * (xa + xb); + + const double alphay = 0.5 * (yb - ya); + const double betay = 0.5 * (ya + yb); + + const double alphaz = 0.5 * (zb - za); + const double betaz = 0.5 * (za + zb); + + auto x = [&alphax, &betax, &alphay, &betay, &alphaz, &betaz](auto x_hat) { + return TinyVector<3>{alphax * x_hat[0] + betax, alphay * x_hat[1] + betay, alphaz * x_hat[2] + betaz}; + }; + + 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 alphax * alphay * alphaz * value; + }; + + auto p6 = [](const double x) { return 7 * std::pow(x, 6); }; + auto p7 = [](const double x) { return 8 * std::pow(x, 7); }; + + auto px7y6 = [&p6, &p7](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p7(x) * p6(y) + p7(z); + }; + + SECTION("degree 6 and 7") + { + const QuadratureFormula<3>& l6 = + QuadratureManager::instance().getCubeFormula(GaussLegendreQuadratureDescriptor(6)); + const QuadratureFormula<3>& l7 = + QuadratureManager::instance().getCubeFormula(GaussLegendreQuadratureDescriptor(7)); + + REQUIRE(&l6 == &l7); + + REQUIRE(l7.numberOfPoints() == 4 * 4 * 4); + + REQUIRE(integrate(px7y6, l7, 0, 1, 0.2, 0.8, -0.1, 0.7) == + Catch::Approx((std::pow(0.8, 7) - std::pow(0.2, 7)) * (0.7 - -0.1) + + (0.8 - 0.2) * (std::pow(0.7, 8) - std::pow(-0.1, 8)))); + } + } +} diff --git a/tests/test_TensorialGaussLobattoQuadrature.cpp b/tests/test_TensorialGaussLobattoQuadrature.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1c08404ecaaf98fedb4dfa841a5ed8d845cfca09 --- /dev/null +++ b/tests/test_TensorialGaussLobattoQuadrature.cpp @@ -0,0 +1,420 @@ +#include <catch2/catch_approx.hpp> +#include <catch2/catch_test_macros.hpp> +#include <catch2/matchers/catch_matchers_all.hpp> + +#include <analysis/GaussLobattoQuadratureDescriptor.hpp> +#include <analysis/QuadratureManager.hpp> +#include <analysis/TensorialGaussLobattoQuadrature.hpp> +#include <utils/Exceptions.hpp> + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("TensorialGaussLobattoQuadrature", "[analysis]") +{ + 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); + }; + + SECTION("degree 1") + { + const QuadratureFormula<1>& l1 = + QuadratureManager::instance().getLineFormula(GaussLobattoQuadratureDescriptor(1)); + + REQUIRE(is_symmetric_formula(l1)); + + REQUIRE(l1.numberOfPoints() == 2); + + 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("degree 2 and 3") + { + const QuadratureFormula<1>& l2 = + QuadratureManager::instance().getLineFormula(GaussLobattoQuadratureDescriptor(2)); + const QuadratureFormula<1>& l3 = + QuadratureManager::instance().getLineFormula(GaussLobattoQuadratureDescriptor(3)); + + REQUIRE(&l2 == &l3); + REQUIRE(is_symmetric_formula(l3)); + + REQUIRE(l3.numberOfPoints() == 3); + + 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("degree 4 and 5") + { + const QuadratureFormula<1>& l4 = + QuadratureManager::instance().getLineFormula(GaussLobattoQuadratureDescriptor(4)); + const QuadratureFormula<1>& l5 = + QuadratureManager::instance().getLineFormula(GaussLobattoQuadratureDescriptor(5)); + + REQUIRE(&l4 == &l5); + REQUIRE(is_symmetric_formula(l5)); + + REQUIRE(l5.numberOfPoints() == 4); + + 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("degree 6 and 7") + { + const QuadratureFormula<1>& l6 = + QuadratureManager::instance().getLineFormula(GaussLobattoQuadratureDescriptor(6)); + const QuadratureFormula<1>& l7 = + QuadratureManager::instance().getLineFormula(GaussLobattoQuadratureDescriptor(7)); + + REQUIRE(&l6 == &l7); + REQUIRE(is_symmetric_formula(l7)); + + REQUIRE(l7.numberOfPoints() == 5); + + 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("degree 8 and 9") + { + const QuadratureFormula<1>& l8 = + QuadratureManager::instance().getLineFormula(GaussLobattoQuadratureDescriptor(8)); + const QuadratureFormula<1>& l9 = + QuadratureManager::instance().getLineFormula(GaussLobattoQuadratureDescriptor(9)); + + REQUIRE(&l8 == &l9); + REQUIRE(is_symmetric_formula(l9)); + + REQUIRE(l9.numberOfPoints() == 6); + + 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("degree 10 and 11") + { + const QuadratureFormula<1>& l10 = + QuadratureManager::instance().getLineFormula(GaussLobattoQuadratureDescriptor(10)); + const QuadratureFormula<1>& l11 = + QuadratureManager::instance().getLineFormula(GaussLobattoQuadratureDescriptor(11)); + + REQUIRE(&l10 == &l11); + REQUIRE(is_symmetric_formula(l11)); + + REQUIRE(l11.numberOfPoints() == 7); + + 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("degree 12 and 13") + { + const QuadratureFormula<1>& l12 = + QuadratureManager::instance().getLineFormula(GaussLobattoQuadratureDescriptor(12)); + const QuadratureFormula<1>& l13 = + QuadratureManager::instance().getLineFormula(GaussLobattoQuadratureDescriptor(13)); + + REQUIRE(&l12 == &l13); + REQUIRE(is_symmetric_formula(l13)); + + REQUIRE(l13.numberOfPoints() == 8); + + 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("max implemented degree") + { + REQUIRE(QuadratureManager::instance().maxLineDegree(QuadratureType::GaussLobatto) == + TensorialGaussLobattoQuadrature<1>::max_degree); + } + } + + SECTION("2D") + { + auto integrate = [](auto f, auto quadrature_formula, const double xa, const double xb, const double ya, + const double yb) { + auto point_list = quadrature_formula.pointList(); + auto weight_list = quadrature_formula.weightList(); + + const double alphax = 0.5 * (xb - xa); + const double betax = 0.5 * (xa + xb); + + const double alphay = 0.5 * (yb - ya); + const double betay = 0.5 * (ya + yb); + + auto x = [&alphax, &betax, &alphay, &betay](auto x_hat) { + return TinyVector<2>{alphax * x_hat[0] + betax, alphay * x_hat[1] + betay}; + }; + + 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 alphax * alphay * value; + }; + + auto p6 = [](const double x) { return 7 * std::pow(x, 6); }; + auto p7 = [](const double x) { return 8 * std::pow(x, 7); }; + + auto px7y6 = [&p6, &p7](const TinyVector<2>& X) { + const double x = X[0]; + const double y = X[1]; + return p7(x) * p6(y); + }; + + SECTION("degree 6 and 7") + { + const QuadratureFormula<2>& l6 = + QuadratureManager::instance().getSquareFormula(GaussLobattoQuadratureDescriptor(6)); + const QuadratureFormula<2>& l7 = + QuadratureManager::instance().getSquareFormula(GaussLobattoQuadratureDescriptor(7)); + + REQUIRE(&l6 == &l7); + + REQUIRE(l7.numberOfPoints() == 5 * 5); + + REQUIRE(integrate(px7y6, l7, 0, 1, 0.2, 0.8) == Catch::Approx(std::pow(0.8, 7) - std::pow(0.2, 7))); + } + } + + SECTION("3D") + { + auto integrate = [](auto f, auto quadrature_formula, const double xa, const double xb, const double ya, + const double yb, const double za, const double zb) { + auto point_list = quadrature_formula.pointList(); + auto weight_list = quadrature_formula.weightList(); + + const double alphax = 0.5 * (xb - xa); + const double betax = 0.5 * (xa + xb); + + const double alphay = 0.5 * (yb - ya); + const double betay = 0.5 * (ya + yb); + + const double alphaz = 0.5 * (zb - za); + const double betaz = 0.5 * (za + zb); + + auto x = [&alphax, &betax, &alphay, &betay, &alphaz, &betaz](auto x_hat) { + return TinyVector<3>{alphax * x_hat[0] + betax, alphay * x_hat[1] + betay, alphaz * x_hat[2] + betaz}; + }; + + 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 alphax * alphay * alphaz * value; + }; + + auto p6 = [](const double x) { return 7 * std::pow(x, 6); }; + auto p7 = [](const double x) { return 8 * std::pow(x, 7); }; + + auto px7y6 = [&p6, &p7](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p7(x) * p6(y) + p7(z); + }; + + SECTION("degree 6 and 7") + { + const QuadratureFormula<3>& l6 = + QuadratureManager::instance().getCubeFormula(GaussLobattoQuadratureDescriptor(6)); + const QuadratureFormula<3>& l7 = + QuadratureManager::instance().getCubeFormula(GaussLobattoQuadratureDescriptor(7)); + + REQUIRE(&l6 == &l7); + + REQUIRE(l7.numberOfPoints() == 5 * 5 * 5); + + REQUIRE(integrate(px7y6, l7, 0, 1, 0.2, 0.8, -0.1, 0.7) == + Catch::Approx((std::pow(0.8, 7) - std::pow(0.2, 7)) * (0.7 - -0.1) + + (0.8 - 0.2) * (std::pow(0.7, 8) - std::pow(-0.1, 8)))); + } + } + + SECTION("Access functions") + { + const QuadratureFormula<3>& quadrature_formula = + QuadratureManager::instance().getCubeFormula(GaussLobattoQuadratureDescriptor(7)); + + auto point_list = quadrature_formula.pointList(); + auto weight_list = quadrature_formula.weightList(); + + REQUIRE(point_list.size() == quadrature_formula.numberOfPoints()); + REQUIRE(weight_list.size() == quadrature_formula.numberOfPoints()); + + for (size_t i = 0; i < quadrature_formula.numberOfPoints(); ++i) { + REQUIRE(&point_list[i] == &quadrature_formula.point(i)); + REQUIRE(&weight_list[i] == &quadrature_formula.weight(i)); + } + } +} diff --git a/tests/test_TetrahedronGaussQuadrature.cpp b/tests/test_TetrahedronGaussQuadrature.cpp new file mode 100644 index 0000000000000000000000000000000000000000..605d1dc1fa7476719fe16ac595ff55491f5bd8e8 --- /dev/null +++ b/tests/test_TetrahedronGaussQuadrature.cpp @@ -0,0 +1,683 @@ +#include <catch2/catch_approx.hpp> +#include <catch2/catch_test_macros.hpp> +#include <catch2/matchers/catch_matchers_all.hpp> + +#include <analysis/GaussQuadratureDescriptor.hpp> +#include <analysis/QuadratureManager.hpp> +#include <analysis/TetrahedronGaussQuadrature.hpp> +#include <geometry/TetrahedronTransformation.hpp> +#include <utils/Exceptions.hpp> + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("TetrahedronGaussQuadrature", "[analysis]") +{ + auto integrate = [](auto f, auto quadrature_formula) { + using R3 = TinyVector<3>; + + const R3 A{-1, -1, -1}; + const R3 B{+1, -1, -1}; + const R3 C{-1, +1, -1}; + const R3 D{-1, -1, +1}; + + TetrahedronTransformation t{A, B, C, D}; + + auto point_list = quadrature_formula.pointList(); + auto weight_list = quadrature_formula.weightList(); + + auto value = weight_list[0] * f(t(point_list[0])); + for (size_t i = 1; i < weight_list.size(); ++i) { + value += weight_list[i] * f(t(point_list[i])); + } + + return t.jacobianDeterminant() * value; + }; + + auto integrate_on_tetra = [](auto f, auto quadrature_formula, const TinyVector<3>& a, const TinyVector<3>& b, + const TinyVector<3>& c, const TinyVector<3>& d) { + TetrahedronTransformation t{a, b, c, d}; + + auto point_list = quadrature_formula.pointList(); + auto weight_list = quadrature_formula.weightList(); + + auto value = weight_list[0] * f(t(point_list[0])); + for (size_t i = 1; i < weight_list.size(); ++i) { + value += weight_list[i] * f(t(point_list[i])); + } + + return t.jacobianDeterminant() * value; + }; + + auto get_order = [&integrate, &integrate_on_tetra](auto f, auto quadrature_formula, const double exact_value) { + using R3 = TinyVector<3>; + + const R3 A{-1, -1, -1}; + const R3 B{+1, -1, -1}; + const R3 C{-1, +1, -1}; + const R3 D{-1, -1, +1}; + + const R3 M_AB = 0.5 * (A + B); + const R3 M_AC = 0.5 * (A + C); + const R3 M_AD = 0.5 * (A + D); + const R3 M_BC = 0.5 * (B + C); + const R3 M_BD = 0.5 * (B + D); + const R3 M_CD = 0.5 * (C + D); + + const double int_T_hat = integrate(f, quadrature_formula); + const double int_refined // + = integrate_on_tetra(f, quadrature_formula, A, M_AB, M_AC, M_AD) + + integrate_on_tetra(f, quadrature_formula, B, M_AB, M_BD, M_BC) + + integrate_on_tetra(f, quadrature_formula, C, M_AC, M_BC, M_CD) + + integrate_on_tetra(f, quadrature_formula, D, M_AD, M_CD, M_BD) + + integrate_on_tetra(f, quadrature_formula, M_BD, M_AC, M_AD, M_CD) + + integrate_on_tetra(f, quadrature_formula, M_AB, M_AC, M_AD, M_BD) + + integrate_on_tetra(f, quadrature_formula, M_BC, M_AB, M_BD, M_AC) + + integrate_on_tetra(f, quadrature_formula, M_BC, M_AC, M_BD, M_CD); + + return -std::log(std::abs(int_refined - exact_value) / std::abs(int_T_hat - exact_value)) / std::log(2); + }; + + auto p0 = [](const TinyVector<3>&) { return 4; }; + auto p1 = [](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return 2 * x + 3 * y + z - 1; + }; + auto p2 = [&p1](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p1(X) * (2.5 * x - 3 * y + z + 3); + }; + auto p3 = [&p2](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p2(X) * (3 * x + 2 * y - 3 * z - 1); + }; + auto p4 = [&p3](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p3(X) * (2 * x - 0.5 * y - 1.3 * z + 1); + }; + auto p5 = [&p4](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p4(X) * (-0.1 * x + 1.3 * y - 3 * z + 1); + }; + auto p6 = [&p5](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p5(X) * 7875. / 143443 * (2 * x - y + 4 * z + 1); + }; + auto p7 = [&p6](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p6(X) * (0.7 * x - 2.7 * y + 1.3 * z - 2); + }; + auto p8 = [&p7](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p7(X) * (0.3 * x + 1.2 * y - 0.7 * z + 0.2); + }; + auto p9 = [&p8](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p8(X) * (-0.2 * x + 1.1 * y - 0.5 * z + 0.6); + }; + auto p10 = [&p9](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p9(X) * (0.7 * x - 0.6 * y - 0.7 * z - 0.2); + }; + auto p11 = [&p10](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p10(X) * (-1.3 * x + 0.6 * y - 1.3 * z + 0.7); + }; + auto p12 = [&p11](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p11(X) * (0.3 * x - 0.7 * y + 0.3 * z + 0.7); + }; + auto p13 = [&p12](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p12(X) * (0.9 * x + 0.2 * y - 0.4 * z + 0.5); + }; + auto p14 = [&p13](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p13(X) * (0.6 * x - 1.2 * y + 0.7 * z - 0.4); + }; + auto p15 = [&p14](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p14(X) * (-0.2 * x - 0.7 * y + 0.9 * z + 0.8); + }; + auto p16 = [&p15](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p15(X) * (0.7 * x + 0.2 * y - 0.6 * z + 0.4); + }; + auto p17 = [&p16](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p16(X) * (-0.1 * x + 0.8 * y + 0.3 * z - 0.2); + }; + auto p18 = [&p17](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p17(X) * (0.7 * x - 0.2 * y - 0.3 * z + 0.8); + }; + auto p19 = [&p18](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p18(X) * (-0.7 * x + 1.2 * y + 1.3 * z + 0.8); + }; + auto p20 = [&p19](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p19(X) * (0.7 * x - 1.2 * y + 0.3 * z - 0.6); + }; + auto p21 = [&p20](const TinyVector<3>& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return p20(X) * (0.7 * x - 1.2 * y + 0.3 * z - 0.6); + }; + + SECTION("degree 1") + { + const QuadratureFormula<3>& l1 = QuadratureManager::instance().getTetrahedronFormula(GaussQuadratureDescriptor(1)); + + REQUIRE(l1.numberOfPoints() == 1); + + REQUIRE(integrate(p0, l1) == Catch::Approx(16. / 3)); + REQUIRE(integrate(p1, l1) == Catch::Approx(-16. / 3)); + REQUIRE(integrate(p2, l1) != Catch::Approx(-47. / 3)); + + REQUIRE(get_order(p2, l1, -47. / 3) >= Catch::Approx(2)); + } + + SECTION("degree 2") + { + const QuadratureFormula<3>& l2 = QuadratureManager::instance().getTetrahedronFormula(GaussQuadratureDescriptor(2)); + + REQUIRE(l2.numberOfPoints() == 4); + + REQUIRE(integrate(p0, l2) == Catch::Approx(16. / 3)); + REQUIRE(integrate(p1, l2) == Catch::Approx(-16. / 3)); + REQUIRE(integrate(p2, l2) == Catch::Approx(-47. / 3)); + REQUIRE(integrate(p3, l2) != Catch::Approx(557. / 15)); + + REQUIRE(get_order(p3, l2, 557. / 15) >= Catch::Approx(3)); + } + + SECTION("degree 3") + { + const QuadratureFormula<3>& l3 = QuadratureManager::instance().getTetrahedronFormula(GaussQuadratureDescriptor(3)); + + REQUIRE(l3.numberOfPoints() == 8); + + REQUIRE(integrate(p0, l3) == Catch::Approx(16. / 3)); + REQUIRE(integrate(p1, l3) == Catch::Approx(-16. / 3)); + REQUIRE(integrate(p2, l3) == Catch::Approx(-47. / 3)); + REQUIRE(integrate(p3, l3) == Catch::Approx(557. / 15)); + REQUIRE(integrate(p4, l3) != Catch::Approx(4499. / 1575)); + } + + SECTION("degree 4") + { + const QuadratureFormula<3>& l4 = QuadratureManager::instance().getTetrahedronFormula(GaussQuadratureDescriptor(4)); + + REQUIRE(l4.numberOfPoints() == 14); + + REQUIRE(integrate(p0, l4) == Catch::Approx(16. / 3)); + REQUIRE(integrate(p1, l4) == Catch::Approx(-16. / 3)); + REQUIRE(integrate(p2, l4) == Catch::Approx(-47. / 3)); + REQUIRE(integrate(p3, l4) == Catch::Approx(557. / 15)); + REQUIRE(integrate(p4, l4) == Catch::Approx(4499. / 1575)); + REQUIRE(integrate(p5, l4) != Catch::Approx(143443. / 7875)); + + REQUIRE(get_order(p5, l4, 143443. / 7875) >= Catch::Approx(5)); + } + + SECTION("degree 5") + { + const QuadratureFormula<3>& l5 = QuadratureManager::instance().getTetrahedronFormula(GaussQuadratureDescriptor(5)); + + REQUIRE(l5.numberOfPoints() == 14); + + REQUIRE(integrate(p0, l5) == Catch::Approx(16. / 3)); + REQUIRE(integrate(p1, l5) == Catch::Approx(-16. / 3)); + REQUIRE(integrate(p2, l5) == Catch::Approx(-47. / 3)); + REQUIRE(integrate(p3, l5) == Catch::Approx(557. / 15)); + REQUIRE(integrate(p4, l5) == Catch::Approx(4499. / 1575)); + REQUIRE(integrate(p5, l5) == Catch::Approx(143443. / 7875)); + REQUIRE(integrate(p6, l5) != Catch::Approx(-75773. / 2581974)); + } + + SECTION("degree 6") + { + const QuadratureFormula<3>& l6 = QuadratureManager::instance().getTetrahedronFormula(GaussQuadratureDescriptor(6)); + + REQUIRE(l6.numberOfPoints() == 24); + + REQUIRE(integrate(p0, l6) == Catch::Approx(16. / 3)); + REQUIRE(integrate(p1, l6) == Catch::Approx(-16. / 3)); + REQUIRE(integrate(p2, l6) == Catch::Approx(-47. / 3)); + REQUIRE(integrate(p3, l6) == Catch::Approx(557. / 15)); + REQUIRE(integrate(p4, l6) == Catch::Approx(4499. / 1575)); + REQUIRE(integrate(p5, l6) == Catch::Approx(143443. / 7875)); + REQUIRE(integrate(p6, l6) == Catch::Approx(-75773. / 2581974)); + REQUIRE(integrate(p7, l6) != Catch::Approx(86951548. / 32274675)); + + REQUIRE(get_order(p7, l6, 86951548. / 32274675) >= Catch::Approx(7)); + } + + SECTION("degree 7") + { + const QuadratureFormula<3>& l7 = QuadratureManager::instance().getTetrahedronFormula(GaussQuadratureDescriptor(7)); + + REQUIRE(l7.numberOfPoints() == 35); + + REQUIRE(integrate(p0, l7) == Catch::Approx(16. / 3)); + REQUIRE(integrate(p1, l7) == Catch::Approx(-16. / 3)); + REQUIRE(integrate(p2, l7) == Catch::Approx(-47. / 3)); + REQUIRE(integrate(p3, l7) == Catch::Approx(557. / 15)); + REQUIRE(integrate(p4, l7) == Catch::Approx(4499. / 1575)); + REQUIRE(integrate(p5, l7) == Catch::Approx(143443. / 7875)); + REQUIRE(integrate(p6, l7) == Catch::Approx(-75773. / 2581974)); + REQUIRE(integrate(p7, l7) == Catch::Approx(86951548. / 32274675)); + REQUIRE(integrate(p8, l7) != Catch::Approx(-863556317. / 322746750)); + + REQUIRE(get_order(p8, l7, -863556317. / 322746750) == Catch::Approx(8).margin(0.5)); + } + + SECTION("degree 8") + { + const QuadratureFormula<3>& l8 = QuadratureManager::instance().getTetrahedronFormula(GaussQuadratureDescriptor(8)); + + REQUIRE(l8.numberOfPoints() == 46); + + REQUIRE(integrate(p0, l8) == Catch::Approx(16. / 3)); + REQUIRE(integrate(p1, l8) == Catch::Approx(-16. / 3)); + REQUIRE(integrate(p2, l8) == Catch::Approx(-47. / 3)); + REQUIRE(integrate(p3, l8) == Catch::Approx(557. / 15)); + REQUIRE(integrate(p4, l8) == Catch::Approx(4499. / 1575)); + REQUIRE(integrate(p5, l8) == Catch::Approx(143443. / 7875)); + REQUIRE(integrate(p6, l8) == Catch::Approx(-75773. / 2581974)); + REQUIRE(integrate(p7, l8) == Catch::Approx(86951548. / 32274675)); + REQUIRE(integrate(p8, l8) == Catch::Approx(-863556317. / 322746750)); + REQUIRE(integrate(p9, l8) != Catch::Approx(1168568393. / 3227467500)); + + // In a weird way, one gets almost 10th order on this test + REQUIRE(get_order(p9, l8, 1168568393. / 3227467500) == Catch::Approx(10)); + } + + SECTION("degree 9") + { + const QuadratureFormula<3>& l9 = QuadratureManager::instance().getTetrahedronFormula(GaussQuadratureDescriptor(9)); + + REQUIRE(l9.numberOfPoints() == 59); + + REQUIRE(integrate(p0, l9) == Catch::Approx(16. / 3)); + REQUIRE(integrate(p1, l9) == Catch::Approx(-16. / 3)); + REQUIRE(integrate(p2, l9) == Catch::Approx(-47. / 3)); + REQUIRE(integrate(p3, l9) == Catch::Approx(557. / 15)); + REQUIRE(integrate(p4, l9) == Catch::Approx(4499. / 1575)); + REQUIRE(integrate(p5, l9) == Catch::Approx(143443. / 7875)); + REQUIRE(integrate(p6, l9) == Catch::Approx(-75773. / 2581974)); + REQUIRE(integrate(p7, l9) == Catch::Approx(86951548. / 32274675)); + REQUIRE(integrate(p8, l9) == Catch::Approx(-863556317. / 322746750)); + REQUIRE(integrate(p9, l9) == Catch::Approx(1168568393. / 3227467500)); + REQUIRE(integrate(p10, l9) != Catch::Approx(-473611706567. / 461527852500)); + + // No order test. Too bad ~4.5 when one expects 10 asymptotically + } + + SECTION("degree 10") + { + const QuadratureFormula<3>& l10 = + QuadratureManager::instance().getTetrahedronFormula(GaussQuadratureDescriptor(10)); + + REQUIRE(l10.numberOfPoints() == 81); + + REQUIRE(integrate(p0, l10) == Catch::Approx(16. / 3)); + REQUIRE(integrate(p1, l10) == Catch::Approx(-16. / 3)); + REQUIRE(integrate(p2, l10) == Catch::Approx(-47. / 3)); + REQUIRE(integrate(p3, l10) == Catch::Approx(557. / 15)); + REQUIRE(integrate(p4, l10) == Catch::Approx(4499. / 1575)); + REQUIRE(integrate(p5, l10) == Catch::Approx(143443. / 7875)); + REQUIRE(integrate(p6, l10) == Catch::Approx(-75773. / 2581974)); + REQUIRE(integrate(p7, l10) == Catch::Approx(86951548. / 32274675)); + REQUIRE(integrate(p8, l10) == Catch::Approx(-863556317. / 322746750)); + REQUIRE(integrate(p9, l10) == Catch::Approx(1168568393. / 3227467500)); + REQUIRE(integrate(p10, l10) == Catch::Approx(-473611706567. / 461527852500)); + REQUIRE(integrate(p11, l10) != Catch::Approx(-340332578501887. / 323069496750000)); + + // In a weird way, one gets almost 12th order on this test + REQUIRE(get_order(p11, l10, -340332578501887. / 323069496750000) == Catch::Approx(12)); + } + + SECTION("degree 11") + { + const QuadratureFormula<3>& l11 = + QuadratureManager::instance().getTetrahedronFormula(GaussQuadratureDescriptor(11)); + + REQUIRE(l11.numberOfPoints() == 110); + + REQUIRE(integrate(p0, l11) == Catch::Approx(16. / 3)); + REQUIRE(integrate(p1, l11) == Catch::Approx(-16. / 3)); + REQUIRE(integrate(p2, l11) == Catch::Approx(-47. / 3)); + REQUIRE(integrate(p3, l11) == Catch::Approx(557. / 15)); + REQUIRE(integrate(p4, l11) == Catch::Approx(4499. / 1575)); + REQUIRE(integrate(p5, l11) == Catch::Approx(143443. / 7875)); + REQUIRE(integrate(p6, l11) == Catch::Approx(-75773. / 2581974)); + REQUIRE(integrate(p7, l11) == Catch::Approx(86951548. / 32274675)); + REQUIRE(integrate(p8, l11) == Catch::Approx(-863556317. / 322746750)); + REQUIRE(integrate(p9, l11) == Catch::Approx(1168568393. / 3227467500)); + REQUIRE(integrate(p10, l11) == Catch::Approx(-473611706567. / 461527852500)); + REQUIRE(integrate(p11, l11) == Catch::Approx(-340332578501887. / 323069496750000)); + REQUIRE(integrate(p12, l11) != Catch::Approx(-9990191769716047. / 16153474837500000)); + + // No order test. Too bad ~11 when one expects 12 asymptotically + } + + SECTION("degree 12") + { + const QuadratureFormula<3>& l12 = + QuadratureManager::instance().getTetrahedronFormula(GaussQuadratureDescriptor(12)); + + REQUIRE(l12.numberOfPoints() == 168); + + REQUIRE(integrate(p0, l12) == Catch::Approx(16. / 3)); + REQUIRE(integrate(p1, l12) == Catch::Approx(-16. / 3)); + REQUIRE(integrate(p2, l12) == Catch::Approx(-47. / 3)); + REQUIRE(integrate(p3, l12) == Catch::Approx(557. / 15)); + REQUIRE(integrate(p4, l12) == Catch::Approx(4499. / 1575)); + REQUIRE(integrate(p5, l12) == Catch::Approx(143443. / 7875)); + REQUIRE(integrate(p6, l12) == Catch::Approx(-75773. / 2581974)); + REQUIRE(integrate(p7, l12) == Catch::Approx(86951548. / 32274675)); + REQUIRE(integrate(p8, l12) == Catch::Approx(-863556317. / 322746750)); + REQUIRE(integrate(p9, l12) == Catch::Approx(1168568393. / 3227467500)); + REQUIRE(integrate(p10, l12) == Catch::Approx(-473611706567. / 461527852500)); + REQUIRE(integrate(p11, l12) == Catch::Approx(-340332578501887. / 323069496750000)); + REQUIRE(integrate(p12, l12) == Catch::Approx(-9990191769716047. / 16153474837500000)); + REQUIRE(integrate(p13, l12) != Catch::Approx(-31229729533861. / 5384491612500000)); + + // In a weird way, one gets almost 14th order on this test + REQUIRE(get_order(p13, l12, -31229729533861. / 5384491612500000) == Catch::Approx(14).margin(0.01)); + } + + SECTION("degree 13") + { + const QuadratureFormula<3>& l13 = + QuadratureManager::instance().getTetrahedronFormula(GaussQuadratureDescriptor(13)); + + REQUIRE(l13.numberOfPoints() == 172); + + REQUIRE(integrate(p0, l13) == Catch::Approx(16. / 3)); + REQUIRE(integrate(p1, l13) == Catch::Approx(-16. / 3)); + REQUIRE(integrate(p2, l13) == Catch::Approx(-47. / 3)); + REQUIRE(integrate(p3, l13) == Catch::Approx(557. / 15)); + REQUIRE(integrate(p4, l13) == Catch::Approx(4499. / 1575)); + REQUIRE(integrate(p5, l13) == Catch::Approx(143443. / 7875)); + REQUIRE(integrate(p6, l13) == Catch::Approx(-75773. / 2581974)); + REQUIRE(integrate(p7, l13) == Catch::Approx(86951548. / 32274675)); + REQUIRE(integrate(p8, l13) == Catch::Approx(-863556317. / 322746750)); + REQUIRE(integrate(p9, l13) == Catch::Approx(1168568393. / 3227467500)); + REQUIRE(integrate(p10, l13) == Catch::Approx(-473611706567. / 461527852500)); + REQUIRE(integrate(p11, l13) == Catch::Approx(-340332578501887. / 323069496750000)); + REQUIRE(integrate(p12, l13) == Catch::Approx(-9990191769716047. / 16153474837500000)); + REQUIRE(integrate(p13, l13) == Catch::Approx(-31229729533861. / 5384491612500000)); + REQUIRE(integrate(p14, l13) != Catch::Approx(3758162710897404343. / 13730453611875000000.)); + + REQUIRE(get_order(p14, l13, 3758162710897404343. / 13730453611875000000.) == Catch::Approx(14).margin(0.5)); + } + + SECTION("degree 14") + { + const QuadratureFormula<3>& l14 = + QuadratureManager::instance().getTetrahedronFormula(GaussQuadratureDescriptor(14)); + + REQUIRE(l14.numberOfPoints() == 204); + + REQUIRE(integrate(p0, l14) == Catch::Approx(16. / 3)); + REQUIRE(integrate(p1, l14) == Catch::Approx(-16. / 3)); + REQUIRE(integrate(p2, l14) == Catch::Approx(-47. / 3)); + REQUIRE(integrate(p3, l14) == Catch::Approx(557. / 15)); + REQUIRE(integrate(p4, l14) == Catch::Approx(4499. / 1575)); + REQUIRE(integrate(p5, l14) == Catch::Approx(143443. / 7875)); + REQUIRE(integrate(p6, l14) == Catch::Approx(-75773. / 2581974)); + REQUIRE(integrate(p7, l14) == Catch::Approx(86951548. / 32274675)); + REQUIRE(integrate(p8, l14) == Catch::Approx(-863556317. / 322746750)); + REQUIRE(integrate(p9, l14) == Catch::Approx(1168568393. / 3227467500)); + REQUIRE(integrate(p10, l14) == Catch::Approx(-473611706567. / 461527852500)); + REQUIRE(integrate(p11, l14) == Catch::Approx(-340332578501887. / 323069496750000)); + REQUIRE(integrate(p12, l14) == Catch::Approx(-9990191769716047. / 16153474837500000)); + REQUIRE(integrate(p13, l14) == Catch::Approx(-31229729533861. / 5384491612500000)); + REQUIRE(integrate(p14, l14) == Catch::Approx(3758162710897404343. / 13730453611875000000.)); + REQUIRE(integrate(p15, l14) != Catch::Approx(49733943385709654587. / 137304536118750000000.)); + + // In a weird way, one gets almost 16th order on this test + REQUIRE(get_order(p15, l14, 49733943385709654587. / 137304536118750000000.) == Catch::Approx(16).margin(0.01)); + } + + SECTION("degree 15") + { + const QuadratureFormula<3>& l15 = + QuadratureManager::instance().getTetrahedronFormula(GaussQuadratureDescriptor(15)); + + REQUIRE(l15.numberOfPoints() == 264); + + REQUIRE(integrate(p0, l15) == Catch::Approx(16. / 3)); + REQUIRE(integrate(p1, l15) == Catch::Approx(-16. / 3)); + REQUIRE(integrate(p2, l15) == Catch::Approx(-47. / 3)); + REQUIRE(integrate(p3, l15) == Catch::Approx(557. / 15)); + REQUIRE(integrate(p4, l15) == Catch::Approx(4499. / 1575)); + REQUIRE(integrate(p5, l15) == Catch::Approx(143443. / 7875)); + REQUIRE(integrate(p6, l15) == Catch::Approx(-75773. / 2581974)); + REQUIRE(integrate(p7, l15) == Catch::Approx(86951548. / 32274675)); + REQUIRE(integrate(p8, l15) == Catch::Approx(-863556317. / 322746750)); + REQUIRE(integrate(p9, l15) == Catch::Approx(1168568393. / 3227467500)); + REQUIRE(integrate(p10, l15) == Catch::Approx(-473611706567. / 461527852500)); + REQUIRE(integrate(p11, l15) == Catch::Approx(-340332578501887. / 323069496750000)); + REQUIRE(integrate(p12, l15) == Catch::Approx(-9990191769716047. / 16153474837500000)); + REQUIRE(integrate(p13, l15) == Catch::Approx(-31229729533861. / 5384491612500000)); + REQUIRE(integrate(p14, l15) == Catch::Approx(3758162710897404343. / 13730453611875000000.)); + REQUIRE(integrate(p15, l15) == Catch::Approx(49733943385709654587. / 137304536118750000000.)); + REQUIRE(integrate(p16, l15) != Catch::Approx(-7270030713465096260897. / 26087861862562500000000.)); + + REQUIRE(get_order(p16, l15, -7270030713465096260897. / 26087861862562500000000.) == + Catch::Approx(16.5).margin(0.2)); + } + + SECTION("degree 16") + { + const QuadratureFormula<3>& l16 = + QuadratureManager::instance().getTetrahedronFormula(GaussQuadratureDescriptor(16)); + + REQUIRE(l16.numberOfPoints() == 304); + + REQUIRE(integrate(p0, l16) == Catch::Approx(16. / 3)); + REQUIRE(integrate(p1, l16) == Catch::Approx(-16. / 3)); + REQUIRE(integrate(p2, l16) == Catch::Approx(-47. / 3)); + REQUIRE(integrate(p3, l16) == Catch::Approx(557. / 15)); + REQUIRE(integrate(p4, l16) == Catch::Approx(4499. / 1575)); + REQUIRE(integrate(p5, l16) == Catch::Approx(143443. / 7875)); + REQUIRE(integrate(p6, l16) == Catch::Approx(-75773. / 2581974)); + REQUIRE(integrate(p7, l16) == Catch::Approx(86951548. / 32274675)); + REQUIRE(integrate(p8, l16) == Catch::Approx(-863556317. / 322746750)); + REQUIRE(integrate(p9, l16) == Catch::Approx(1168568393. / 3227467500)); + REQUIRE(integrate(p10, l16) == Catch::Approx(-473611706567. / 461527852500)); + REQUIRE(integrate(p11, l16) == Catch::Approx(-340332578501887. / 323069496750000)); + REQUIRE(integrate(p12, l16) == Catch::Approx(-9990191769716047. / 16153474837500000)); + REQUIRE(integrate(p13, l16) == Catch::Approx(-31229729533861. / 5384491612500000)); + REQUIRE(integrate(p14, l16) == Catch::Approx(3758162710897404343. / 13730453611875000000.)); + REQUIRE(integrate(p15, l16) == Catch::Approx(49733943385709654587. / 137304536118750000000.)); + REQUIRE(integrate(p16, l16) == Catch::Approx(-7270030713465096260897. / 26087861862562500000000.)); + REQUIRE(integrate(p17, l16) != Catch::Approx(34859214238288098805889. / 195658963969218750000000.)); + + // In a weird way, one gets almost 18th order on this test + REQUIRE(get_order(p17, l16, 34859214238288098805889. / 195658963969218750000000.) == Catch::Approx(18).margin(0.1)); + } + + SECTION("degree 17") + { + const QuadratureFormula<3>& l17 = + QuadratureManager::instance().getTetrahedronFormula(GaussQuadratureDescriptor(17)); + + REQUIRE(l17.numberOfPoints() == 364); + + REQUIRE(integrate(p0, l17) == Catch::Approx(16. / 3)); + REQUIRE(integrate(p1, l17) == Catch::Approx(-16. / 3)); + REQUIRE(integrate(p2, l17) == Catch::Approx(-47. / 3)); + REQUIRE(integrate(p3, l17) == Catch::Approx(557. / 15)); + REQUIRE(integrate(p4, l17) == Catch::Approx(4499. / 1575)); + REQUIRE(integrate(p5, l17) == Catch::Approx(143443. / 7875)); + REQUIRE(integrate(p6, l17) == Catch::Approx(-75773. / 2581974)); + REQUIRE(integrate(p7, l17) == Catch::Approx(86951548. / 32274675)); + REQUIRE(integrate(p8, l17) == Catch::Approx(-863556317. / 322746750)); + REQUIRE(integrate(p9, l17) == Catch::Approx(1168568393. / 3227467500)); + REQUIRE(integrate(p10, l17) == Catch::Approx(-473611706567. / 461527852500)); + REQUIRE(integrate(p11, l17) == Catch::Approx(-340332578501887. / 323069496750000)); + REQUIRE(integrate(p12, l17) == Catch::Approx(-9990191769716047. / 16153474837500000)); + REQUIRE(integrate(p13, l17) == Catch::Approx(-31229729533861. / 5384491612500000)); + REQUIRE(integrate(p14, l17) == Catch::Approx(3758162710897404343. / 13730453611875000000.)); + REQUIRE(integrate(p15, l17) == Catch::Approx(49733943385709654587. / 137304536118750000000.)); + REQUIRE(integrate(p16, l17) == Catch::Approx(-7270030713465096260897. / 26087861862562500000000.)); + REQUIRE(integrate(p17, l17) == Catch::Approx(34859214238288098805889. / 195658963969218750000000.)); + REQUIRE(integrate(p18, l17) != Catch::Approx(115510477527288033058991. / 13696127477845312500000000.)); + + REQUIRE(get_order(p18, l17, 115510477527288033058991. / 13696127477845312500000000.) == + Catch::Approx(18).margin(0.2)); + } + + SECTION("degree 18") + { + const QuadratureFormula<3>& l18 = + QuadratureManager::instance().getTetrahedronFormula(GaussQuadratureDescriptor(18)); + + REQUIRE(l18.numberOfPoints() == 436); + + REQUIRE(integrate(p0, l18) == Catch::Approx(16. / 3)); + REQUIRE(integrate(p1, l18) == Catch::Approx(-16. / 3)); + REQUIRE(integrate(p2, l18) == Catch::Approx(-47. / 3)); + REQUIRE(integrate(p3, l18) == Catch::Approx(557. / 15)); + REQUIRE(integrate(p4, l18) == Catch::Approx(4499. / 1575)); + REQUIRE(integrate(p5, l18) == Catch::Approx(143443. / 7875)); + REQUIRE(integrate(p6, l18) == Catch::Approx(-75773. / 2581974)); + REQUIRE(integrate(p7, l18) == Catch::Approx(86951548. / 32274675)); + REQUIRE(integrate(p8, l18) == Catch::Approx(-863556317. / 322746750)); + REQUIRE(integrate(p9, l18) == Catch::Approx(1168568393. / 3227467500)); + REQUIRE(integrate(p10, l18) == Catch::Approx(-473611706567. / 461527852500)); + REQUIRE(integrate(p11, l18) == Catch::Approx(-340332578501887. / 323069496750000)); + REQUIRE(integrate(p12, l18) == Catch::Approx(-9990191769716047. / 16153474837500000)); + REQUIRE(integrate(p13, l18) == Catch::Approx(-31229729533861. / 5384491612500000)); + REQUIRE(integrate(p14, l18) == Catch::Approx(3758162710897404343. / 13730453611875000000.)); + REQUIRE(integrate(p15, l18) == Catch::Approx(49733943385709654587. / 137304536118750000000.)); + REQUIRE(integrate(p16, l18) == Catch::Approx(-7270030713465096260897. / 26087861862562500000000.)); + REQUIRE(integrate(p17, l18) == Catch::Approx(34859214238288098805889. / 195658963969218750000000.)); + REQUIRE(integrate(p18, l18) == Catch::Approx(115510477527288033058991. / 13696127477845312500000000.)); + REQUIRE(integrate(p19, l18) != + Catch::Approx(2328326230028547427138903. / 57945154713960937500000000.).epsilon(1E-10)); + + // In a weird way, one gets almost 20th order on this test + REQUIRE(get_order(p19, l18, 2328326230028547427138903. / 57945154713960937500000000.) == + Catch::Approx(20).margin(0.01)); + } + + SECTION("degree 19") + { + const QuadratureFormula<3>& l19 = + QuadratureManager::instance().getTetrahedronFormula(GaussQuadratureDescriptor(19)); + + REQUIRE(l19.numberOfPoints() == 487); + + REQUIRE(integrate(p0, l19) == Catch::Approx(16. / 3)); + REQUIRE(integrate(p1, l19) == Catch::Approx(-16. / 3)); + REQUIRE(integrate(p2, l19) == Catch::Approx(-47. / 3)); + REQUIRE(integrate(p3, l19) == Catch::Approx(557. / 15)); + REQUIRE(integrate(p4, l19) == Catch::Approx(4499. / 1575)); + REQUIRE(integrate(p5, l19) == Catch::Approx(143443. / 7875)); + REQUIRE(integrate(p6, l19) == Catch::Approx(-75773. / 2581974)); + REQUIRE(integrate(p7, l19) == Catch::Approx(86951548. / 32274675)); + REQUIRE(integrate(p8, l19) == Catch::Approx(-863556317. / 322746750)); + REQUIRE(integrate(p9, l19) == Catch::Approx(1168568393. / 3227467500)); + REQUIRE(integrate(p10, l19) == Catch::Approx(-473611706567. / 461527852500)); + REQUIRE(integrate(p11, l19) == Catch::Approx(-340332578501887. / 323069496750000)); + REQUIRE(integrate(p12, l19) == Catch::Approx(-9990191769716047. / 16153474837500000)); + REQUIRE(integrate(p13, l19) == Catch::Approx(-31229729533861. / 5384491612500000)); + REQUIRE(integrate(p14, l19) == Catch::Approx(3758162710897404343. / 13730453611875000000.)); + REQUIRE(integrate(p15, l19) == Catch::Approx(49733943385709654587. / 137304536118750000000.)); + REQUIRE(integrate(p16, l19) == Catch::Approx(-7270030713465096260897. / 26087861862562500000000.)); + REQUIRE(integrate(p17, l19) == Catch::Approx(34859214238288098805889. / 195658963969218750000000.)); + REQUIRE(integrate(p18, l19) == Catch::Approx(115510477527288033058991. / 13696127477845312500000000.)); + REQUIRE(integrate(p19, l19) == Catch::Approx(2328326230028547427138903. / 57945154713960937500000000.)); + REQUIRE(integrate(p20, l19) != + Catch::Approx(-20113634155270986416106151. / 19250668066082578125000000000.).epsilon(1E-10)); + + // No order test. Too bad ~16 when one expects 20 asymptotically + } + + SECTION("degree 20") + { + const QuadratureFormula<3>& l20 = + QuadratureManager::instance().getTetrahedronFormula(GaussQuadratureDescriptor(20)); + + REQUIRE(l20.numberOfPoints() == 552); + + REQUIRE(integrate(p0, l20) == Catch::Approx(16. / 3)); + REQUIRE(integrate(p1, l20) == Catch::Approx(-16. / 3)); + REQUIRE(integrate(p2, l20) == Catch::Approx(-47. / 3)); + REQUIRE(integrate(p3, l20) == Catch::Approx(557. / 15)); + REQUIRE(integrate(p4, l20) == Catch::Approx(4499. / 1575)); + REQUIRE(integrate(p5, l20) == Catch::Approx(143443. / 7875)); + REQUIRE(integrate(p6, l20) == Catch::Approx(-75773. / 2581974)); + REQUIRE(integrate(p7, l20) == Catch::Approx(86951548. / 32274675)); + REQUIRE(integrate(p8, l20) == Catch::Approx(-863556317. / 322746750)); + REQUIRE(integrate(p9, l20) == Catch::Approx(1168568393. / 3227467500)); + REQUIRE(integrate(p10, l20) == Catch::Approx(-473611706567. / 461527852500)); + REQUIRE(integrate(p11, l20) == Catch::Approx(-340332578501887. / 323069496750000)); + REQUIRE(integrate(p12, l20) == Catch::Approx(-9990191769716047. / 16153474837500000)); + REQUIRE(integrate(p13, l20) == Catch::Approx(-31229729533861. / 5384491612500000)); + REQUIRE(integrate(p14, l20) == Catch::Approx(3758162710897404343. / 13730453611875000000.)); + REQUIRE(integrate(p15, l20) == Catch::Approx(49733943385709654587. / 137304536118750000000.)); + REQUIRE(integrate(p16, l20) == Catch::Approx(-7270030713465096260897. / 26087861862562500000000.)); + REQUIRE(integrate(p17, l20) == Catch::Approx(34859214238288098805889. / 195658963969218750000000.)); + REQUIRE(integrate(p18, l20) == Catch::Approx(115510477527288033058991. / 13696127477845312500000000.)); + REQUIRE(integrate(p19, l20) == Catch::Approx(2328326230028547427138903. / 57945154713960937500000000.)); + REQUIRE(integrate(p20, l20) == Catch::Approx(-20113634155270986416106151. / 19250668066082578125000000000.)); + REQUIRE(integrate(p21, l20) != Catch::Approx(16760093568330570728566871. / 7598947920822070312500000000.)); + + // In a weird way, one gets almost 22th order on this test + REQUIRE(get_order(p21, l20, 16760093568330570728566871. / 7598947920822070312500000000.) == + Catch::Approx(22).margin(0.01)); + } + + SECTION("max implemented degree") + { + REQUIRE(QuadratureManager::instance().maxTetrahedronDegree(QuadratureType::Gauss) == + TetrahedronGaussQuadrature::max_degree); + } +} diff --git a/tests/test_TetrahedronTransformation.cpp b/tests/test_TetrahedronTransformation.cpp new file mode 100644 index 0000000000000000000000000000000000000000..91739b99e7030e1b8490869fb770f1978cce9334 --- /dev/null +++ b/tests/test_TetrahedronTransformation.cpp @@ -0,0 +1,61 @@ +#include <catch2/catch_approx.hpp> +#include <catch2/catch_test_macros.hpp> + +#include <analysis/GaussQuadratureDescriptor.hpp> +#include <analysis/QuadratureManager.hpp> +#include <geometry/TetrahedronTransformation.hpp> + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("TetrahedronTransformation", "[geometry]") +{ + using R3 = TinyVector<3>; + + const R3 a = {1, 2, 1}; + const R3 b = {3, 1, 3}; + const R3 c = {2, 5, 2}; + const R3 d = {2, 3, 4}; + + const TetrahedronTransformation t(a, b, c, d); + + REQUIRE(t({0, 0, 0})[0] == Catch::Approx(1)); + REQUIRE(t({0, 0, 0})[1] == Catch::Approx(2)); + REQUIRE(t({0, 0, 0})[2] == Catch::Approx(1)); + + REQUIRE(t({1, 0, 0})[0] == Catch::Approx(3)); + REQUIRE(t({1, 0, 0})[1] == Catch::Approx(1)); + REQUIRE(t({1, 0, 0})[2] == Catch::Approx(3)); + + REQUIRE(t({0, 1, 0})[0] == Catch::Approx(2)); + REQUIRE(t({0, 1, 0})[1] == Catch::Approx(5)); + REQUIRE(t({0, 1, 0})[2] == Catch::Approx(2)); + + REQUIRE(t({0, 0, 1})[0] == Catch::Approx(2)); + REQUIRE(t({0, 0, 1})[1] == Catch::Approx(3)); + REQUIRE(t({0, 0, 1})[2] == Catch::Approx(4)); + + REQUIRE(t({0.25, 0.25, 0.25})[0] == Catch::Approx(2)); + REQUIRE(t({0.25, 0.25, 0.25})[1] == Catch::Approx(11. / 4)); + REQUIRE(t({0.25, 0.25, 0.25})[2] == Catch::Approx(2.5)); + + REQUIRE(t.jacobianDeterminant() == Catch::Approx(14)); + + SECTION("Polynomial integral") + { + auto p = [](const R3& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return 2 * x * x + 3 * x * y + y * y + 3 * y - z * z + 2 * x * z + 2 * z; + }; + + QuadratureFormula<3> qf = QuadratureManager::instance().getTetrahedronFormula(GaussQuadratureDescriptor(2)); + + double sum = 0; + for (size_t i = 0; i < qf.numberOfPoints(); ++i) { + sum += qf.weight(i) * t.jacobianDeterminant() * p(t(qf.point(i))); + } + + REQUIRE(sum == Catch::Approx(231. / 2)); + } +} diff --git a/tests/test_TriangleGaussQuadrature.cpp b/tests/test_TriangleGaussQuadrature.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3d7b5dffaf2f0290d5b15dcb6796188512f62cf8 --- /dev/null +++ b/tests/test_TriangleGaussQuadrature.cpp @@ -0,0 +1,628 @@ +#include <catch2/catch_approx.hpp> +#include <catch2/catch_test_macros.hpp> +#include <catch2/matchers/catch_matchers_all.hpp> + +#include <analysis/GaussQuadratureDescriptor.hpp> +#include <analysis/QuadratureManager.hpp> +#include <analysis/TriangleGaussQuadrature.hpp> +#include <geometry/TriangleTransformation.hpp> +#include <utils/Exceptions.hpp> + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("TriangleGaussQuadrature", "[analysis]") +{ + auto integrate = [](auto f, auto quadrature_formula) { + using R2 = TinyVector<2>; + + const R2 A{-1, -1}; + const R2 B{+1, -1}; + const R2 C{-1, +1}; + + TriangleTransformation<2> t{A, B, C}; + + auto point_list = quadrature_formula.pointList(); + auto weight_list = quadrature_formula.weightList(); + + auto value = weight_list[0] * f(t(point_list[0])); + for (size_t i = 1; i < weight_list.size(); ++i) { + value += weight_list[i] * f(t(point_list[i])); + } + + return t.jacobianDeterminant() * value; + }; + + auto integrate_on_triangle = [](auto f, auto quadrature_formula, const TinyVector<2>& a, const TinyVector<2>& b, + const TinyVector<2>& c) { + TriangleTransformation<2> t(a, b, c); + + auto point_list = quadrature_formula.pointList(); + auto weight_list = quadrature_formula.weightList(); + + auto value = weight_list[0] * f(t(point_list[0])); + for (size_t i = 1; i < weight_list.size(); ++i) { + value += weight_list[i] * f(t(point_list[i])); + } + + return t.jacobianDeterminant() * value; + }; + + auto get_order = [&integrate, &integrate_on_triangle](auto f, auto quadrature_formula, const double exact_value) { + using R2 = TinyVector<2>; + const double int_T_hat = integrate(f, quadrature_formula); + const double int_refined // + = integrate_on_triangle(f, quadrature_formula, R2{-1, -1}, R2{0, -1}, R2{-1, 0}) + + integrate_on_triangle(f, quadrature_formula, R2{0, -1}, R2{0, 0}, R2{-1, 0}) + + integrate_on_triangle(f, quadrature_formula, R2{0, -1}, R2{1, -1}, R2{0, 0}) + + integrate_on_triangle(f, quadrature_formula, R2{-1, 0}, R2{0, 0}, R2{-1, 1}); + + return -std::log(std::abs(int_refined - exact_value) / std::abs(int_T_hat - exact_value)) / std::log(2); + }; + + auto p0 = [](const TinyVector<2>&) { return 2; }; + auto p1 = [](const TinyVector<2>& X) { + const double x = X[0]; + const double y = X[1]; + return 2 * x + 3 * y + 1; + }; + auto p2 = [&p1](const TinyVector<2>& X) { + const double x = X[0]; + const double y = X[1]; + return p1(X) * (2.5 * x - 3 * y + 3); + }; + auto p3 = [&p2](const TinyVector<2>& X) { + const double x = X[0]; + const double y = X[1]; + return p2(X) * (-1.5 * x + 3 * y - 3); + }; + auto p4 = [&p3](const TinyVector<2>& X) { + const double x = X[0]; + const double y = X[1]; + return p3(X) * (x + y + 1); + }; + auto p5 = [&p4](const TinyVector<2>& X) { + const double x = X[0]; + const double y = X[1]; + return p4(X) * (-0.2 * x - 1.3 * y - 0.7); + }; + auto p6 = [&p5](const TinyVector<2>& X) { + const double x = X[0]; + const double y = X[1]; + return p5(X) * (3 * x - 2 * y + 3); + }; + auto p7 = [&p6](const TinyVector<2>& X) { + const double x = X[0]; + const double y = X[1]; + return p6(X) * (-2 * x + 4 * y - 7); + }; + auto p8 = [&p7](const TinyVector<2>& X) { + const double x = X[0]; + const double y = X[1]; + return p7(X) * (0.2 * x - 0.3 * y - 0.3); + }; + auto p9 = [&p8](const TinyVector<2>& X) { + const double x = X[0]; + const double y = X[1]; + return p8(X) * (0.9 * x + 0.6 * y - 0.4); + }; + auto p10 = [&p9](const TinyVector<2>& X) { + const double x = X[0]; + const double y = X[1]; + return p9(X) * (-0.1 * x + 0.3 * y + 0.6); + }; + auto p11 = [&p10](const TinyVector<2>& X) { + const double x = X[0]; + const double y = X[1]; + return p10(X) * (0.7 * x - 0.6 * y + 0.2); + }; + auto p12 = [&p11](const TinyVector<2>& X) { + const double x = X[0]; + const double y = X[1]; + return p11(X) * (0.2 * x + 0.3 * y - 0.4); + }; + auto p13 = [&p12](const TinyVector<2>& X) { + const double x = X[0]; + const double y = X[1]; + return p12(X) * (-0.9 * x + 0.4 * y + 0.3); + }; + auto p14 = [&p13](const TinyVector<2>& X) { + const double x = X[0]; + const double y = X[1]; + return p13(X) * (0.7 * x - 0.8 * y - 0.9); + }; + auto p15 = [&p14](const TinyVector<2>& X) { + const double x = X[0]; + const double y = X[1]; + return p14(X) * (-0.9 * x + 0.4 * y + 0.2); + }; + auto p16 = [&p15](const TinyVector<2>& X) { + const double x = X[0]; + const double y = X[1]; + return p15(X) * (-1.3 * x - 1.2 * y - 0.9); + }; + auto p17 = [&p16](const TinyVector<2>& X) { + const double x = X[0]; + const double y = X[1]; + return p16(X) * (0.7 * x + 0.6 * y - 0.2); + }; + auto p18 = [&p17](const TinyVector<2>& X) { + const double x = X[0]; + const double y = X[1]; + return p17(X) * (-0.2 * x + 0.5 * y + 0.7); + }; + auto p19 = [&p18](const TinyVector<2>& X) { + const double x = X[0]; + const double y = X[1]; + return p18(X) * (0.4 * x - 0.7 * y - 0.3); + }; + auto p20 = [&p19](const TinyVector<2>& X) { + const double x = X[0]; + const double y = X[1]; + return p19(X) * (-0.1 * x + 0.8 * y - 0.7); + }; + auto p21 = [&p20](const TinyVector<2>& X) { + const double x = X[0]; + const double y = X[1]; + return p20(X) * (0.5 * x - 0.2 * y + 0.3); + }; + + SECTION("degree 1") + { + const QuadratureFormula<2>& l1 = QuadratureManager::instance().getTriangleFormula(GaussQuadratureDescriptor(1)); + + REQUIRE(l1.numberOfPoints() == 1); + + REQUIRE(integrate(p0, l1) == Catch::Approx(4)); + REQUIRE(integrate(p1, l1) == Catch::Approx(-4. / 3)); + REQUIRE(integrate(p2, l1) != Catch::Approx(-19. / 3)); + + REQUIRE(get_order(p2, l1, -19. / 3) == Catch::Approx(2)); + } + + SECTION("degree 2") + { + const QuadratureFormula<2>& l2 = QuadratureManager::instance().getTriangleFormula(GaussQuadratureDescriptor(2)); + + REQUIRE(l2.numberOfPoints() == 3); + + REQUIRE(integrate(p0, l2) == Catch::Approx(4)); + REQUIRE(integrate(p1, l2) == Catch::Approx(-4. / 3)); + REQUIRE(integrate(p2, l2) == Catch::Approx(-19. / 3)); + REQUIRE(integrate(p3, l2) != Catch::Approx(146. / 5)); + + // In a weird way, the formula achieves 4th order on this test + REQUIRE(get_order(p3, l2, 146. / 5) == Catch::Approx(4)); + } + + SECTION("degree 3 and 4") + { + const QuadratureFormula<2>& l3 = QuadratureManager::instance().getTriangleFormula(GaussQuadratureDescriptor(3)); + const QuadratureFormula<2>& l4 = QuadratureManager::instance().getTriangleFormula(GaussQuadratureDescriptor(4)); + + bool is_same = true; + is_same &= (l3.numberOfPoints() == l4.numberOfPoints()); + for (size_t i = 0; i < l3.pointList().size(); ++i) { + is_same &= (l3.point(i) == l3.point(i)); + is_same &= (l3.weight(i) == l3.weight(i)); + } + + REQUIRE(is_same); + + REQUIRE(l4.numberOfPoints() == 6); + + REQUIRE(integrate(p0, l4) == Catch::Approx(4)); + REQUIRE(integrate(p1, l4) == Catch::Approx(-4. / 3)); + REQUIRE(integrate(p2, l4) == Catch::Approx(-19. / 3)); + REQUIRE(integrate(p3, l4) == Catch::Approx(146. / 5)); + REQUIRE(integrate(p4, l4) == Catch::Approx(-25. / 6)); + REQUIRE(integrate(p5, l4) != Catch::Approx(-17. / 10)); + + // In a weird way, the formula achieves 6th order on this test + REQUIRE(get_order(p5, l4, -17. / 10) == Catch::Approx(6)); + } + + SECTION("degree 5") + { + const QuadratureFormula<2>& l5 = QuadratureManager::instance().getTriangleFormula(GaussQuadratureDescriptor(5)); + + REQUIRE(l5.numberOfPoints() == 7); + + REQUIRE(integrate(p0, l5) == Catch::Approx(4)); + REQUIRE(integrate(p1, l5) == Catch::Approx(-4. / 3)); + REQUIRE(integrate(p2, l5) == Catch::Approx(-19. / 3)); + REQUIRE(integrate(p3, l5) == Catch::Approx(146. / 5)); + REQUIRE(integrate(p4, l5) == Catch::Approx(-25. / 6)); + REQUIRE(integrate(p5, l5) == Catch::Approx(-17. / 10)); + REQUIRE(integrate(p6, l5) != Catch::Approx(-197. / 175)); + + REQUIRE(get_order(p6, l5, -197. / 175) == Catch::Approx(6)); + } + + SECTION("degree 6") + { + const QuadratureFormula<2>& l6 = QuadratureManager::instance().getTriangleFormula(GaussQuadratureDescriptor(6)); + + REQUIRE(l6.numberOfPoints() == 12); + + REQUIRE(integrate(p0, l6) == Catch::Approx(4)); + REQUIRE(integrate(p1, l6) == Catch::Approx(-4. / 3)); + REQUIRE(integrate(p2, l6) == Catch::Approx(-19. / 3)); + REQUIRE(integrate(p3, l6) == Catch::Approx(146. / 5)); + REQUIRE(integrate(p4, l6) == Catch::Approx(-25. / 6)); + REQUIRE(integrate(p5, l6) == Catch::Approx(-17. / 10)); + REQUIRE(integrate(p6, l6) == Catch::Approx(-197. / 175)); + REQUIRE(integrate(p7, l6) != Catch::Approx(-4507. / 1575)); + + REQUIRE(get_order(p7, l6, -4507. / 1575) == Catch::Approx(8)); + } + + SECTION("degree 7") + { + const QuadratureFormula<2>& l7 = QuadratureManager::instance().getTriangleFormula(GaussQuadratureDescriptor(7)); + + REQUIRE(l7.numberOfPoints() == 15); + + REQUIRE(integrate(p0, l7) == Catch::Approx(4)); + REQUIRE(integrate(p1, l7) == Catch::Approx(-4. / 3)); + REQUIRE(integrate(p2, l7) == Catch::Approx(-19. / 3)); + REQUIRE(integrate(p3, l7) == Catch::Approx(146. / 5)); + REQUIRE(integrate(p4, l7) == Catch::Approx(-25. / 6)); + REQUIRE(integrate(p5, l7) == Catch::Approx(-17. / 10)); + REQUIRE(integrate(p6, l7) == Catch::Approx(-197. / 175)); + REQUIRE(integrate(p7, l7) == Catch::Approx(-4507. / 1575)); + REQUIRE(integrate(p8, l7) != Catch::Approx(-23867. / 1575)); + + REQUIRE(get_order(p8, l7, -23867. / 1575) == Catch::Approx(8)); + } + + SECTION("degree 8") + { + const QuadratureFormula<2>& l8 = QuadratureManager::instance().getTriangleFormula(GaussQuadratureDescriptor(8)); + + REQUIRE(l8.numberOfPoints() == 16); + + REQUIRE(integrate(p0, l8) == Catch::Approx(4)); + REQUIRE(integrate(p1, l8) == Catch::Approx(-4. / 3)); + REQUIRE(integrate(p2, l8) == Catch::Approx(-19. / 3)); + REQUIRE(integrate(p3, l8) == Catch::Approx(146. / 5)); + REQUIRE(integrate(p4, l8) == Catch::Approx(-25. / 6)); + REQUIRE(integrate(p5, l8) == Catch::Approx(-17. / 10)); + REQUIRE(integrate(p6, l8) == Catch::Approx(-197. / 175)); + REQUIRE(integrate(p7, l8) == Catch::Approx(-4507. / 1575)); + REQUIRE(integrate(p8, l8) == Catch::Approx(-23867. / 1575)); + REQUIRE(integrate(p9, l8) != Catch::Approx(7782251. / 346500)); + + // In a weird way, the formula achieves 10th order on this test + REQUIRE(get_order(p9, l8, 7782251. / 346500) == Catch::Approx(10)); + } + + SECTION("degree 9") + { + const QuadratureFormula<2>& l9 = QuadratureManager::instance().getTriangleFormula(GaussQuadratureDescriptor(9)); + + REQUIRE(l9.numberOfPoints() == 19); + + REQUIRE(integrate(p0, l9) == Catch::Approx(4)); + REQUIRE(integrate(p1, l9) == Catch::Approx(-4. / 3)); + REQUIRE(integrate(p2, l9) == Catch::Approx(-19. / 3)); + REQUIRE(integrate(p3, l9) == Catch::Approx(146. / 5)); + REQUIRE(integrate(p4, l9) == Catch::Approx(-25. / 6)); + REQUIRE(integrate(p5, l9) == Catch::Approx(-17. / 10)); + REQUIRE(integrate(p6, l9) == Catch::Approx(-197. / 175)); + REQUIRE(integrate(p7, l9) == Catch::Approx(-4507. / 1575)); + REQUIRE(integrate(p8, l9) == Catch::Approx(-23867. / 1575)); + REQUIRE(integrate(p9, l9) == Catch::Approx(7782251. / 346500)); + REQUIRE(integrate(p10, l9) != Catch::Approx(126885809. / 14437500)); + + REQUIRE(get_order(p10, l9, 126885809. / 14437500) == Catch::Approx(10)); + } + + SECTION("degree 10") + { + const QuadratureFormula<2>& l10 = QuadratureManager::instance().getTriangleFormula(GaussQuadratureDescriptor(10)); + + REQUIRE(l10.numberOfPoints() == 25); + + REQUIRE(integrate(p0, l10) == Catch::Approx(4)); + REQUIRE(integrate(p1, l10) == Catch::Approx(-4. / 3)); + REQUIRE(integrate(p2, l10) == Catch::Approx(-19. / 3)); + REQUIRE(integrate(p3, l10) == Catch::Approx(146. / 5)); + REQUIRE(integrate(p4, l10) == Catch::Approx(-25. / 6)); + REQUIRE(integrate(p5, l10) == Catch::Approx(-17. / 10)); + REQUIRE(integrate(p6, l10) == Catch::Approx(-197. / 175)); + REQUIRE(integrate(p7, l10) == Catch::Approx(-4507. / 1575)); + REQUIRE(integrate(p8, l10) == Catch::Approx(-23867. / 1575)); + REQUIRE(integrate(p9, l10) == Catch::Approx(7782251. / 346500)); + REQUIRE(integrate(p10, l10) == Catch::Approx(126885809. / 14437500)); + REQUIRE(integrate(p11, l10) != Catch::Approx(22133453663. / 11261250000)); + + // In a weird way, the formula achieves 12th order on this test + REQUIRE(get_order(p11, l10, 22133453663. / 11261250000) == Catch::Approx(12)); + } + + SECTION("degree 11") + { + const QuadratureFormula<2>& l11 = QuadratureManager::instance().getTriangleFormula(GaussQuadratureDescriptor(11)); + + REQUIRE(l11.numberOfPoints() == 28); + + REQUIRE(integrate(p0, l11) == Catch::Approx(4)); + REQUIRE(integrate(p1, l11) == Catch::Approx(-4. / 3)); + REQUIRE(integrate(p2, l11) == Catch::Approx(-19. / 3)); + REQUIRE(integrate(p3, l11) == Catch::Approx(146. / 5)); + REQUIRE(integrate(p4, l11) == Catch::Approx(-25. / 6)); + REQUIRE(integrate(p5, l11) == Catch::Approx(-17. / 10)); + REQUIRE(integrate(p6, l11) == Catch::Approx(-197. / 175)); + REQUIRE(integrate(p7, l11) == Catch::Approx(-4507. / 1575)); + REQUIRE(integrate(p8, l11) == Catch::Approx(-23867. / 1575)); + REQUIRE(integrate(p9, l11) == Catch::Approx(7782251. / 346500)); + REQUIRE(integrate(p10, l11) == Catch::Approx(126885809. / 14437500)); + REQUIRE(integrate(p11, l11) == Catch::Approx(22133453663. / 11261250000)); + REQUIRE(integrate(p12, l11) != Catch::Approx(-419453736959. / 262762500000)); + + REQUIRE(get_order(p12, l11, -419453736959. / 262762500000) == Catch::Approx(12)); + } + + SECTION("degree 12") + { + const QuadratureFormula<2>& l12 = QuadratureManager::instance().getTriangleFormula(GaussQuadratureDescriptor(12)); + + REQUIRE(l12.numberOfPoints() == 33); + + REQUIRE(integrate(p0, l12) == Catch::Approx(4)); + REQUIRE(integrate(p1, l12) == Catch::Approx(-4. / 3)); + REQUIRE(integrate(p2, l12) == Catch::Approx(-19. / 3)); + REQUIRE(integrate(p3, l12) == Catch::Approx(146. / 5)); + REQUIRE(integrate(p4, l12) == Catch::Approx(-25. / 6)); + REQUIRE(integrate(p5, l12) == Catch::Approx(-17. / 10)); + REQUIRE(integrate(p6, l12) == Catch::Approx(-197. / 175)); + REQUIRE(integrate(p7, l12) == Catch::Approx(-4507. / 1575)); + REQUIRE(integrate(p8, l12) == Catch::Approx(-23867. / 1575)); + REQUIRE(integrate(p9, l12) == Catch::Approx(7782251. / 346500)); + REQUIRE(integrate(p10, l12) == Catch::Approx(126885809. / 14437500)); + REQUIRE(integrate(p11, l12) == Catch::Approx(22133453663. / 11261250000)); + REQUIRE(integrate(p12, l12) == Catch::Approx(-419453736959. / 262762500000)); + REQUIRE(integrate(p13, l12) != Catch::Approx(-3625092349117. / 7882875000000)); + + // In a weird way, the formula achieves 14th order on this test + REQUIRE(get_order(p13, l12, -3625092349117. / 7882875000000) == Catch::Approx(14)); + } + + SECTION("degree 13") + { + const QuadratureFormula<2>& l13 = QuadratureManager::instance().getTriangleFormula(GaussQuadratureDescriptor(13)); + + REQUIRE(l13.numberOfPoints() == 37); + + REQUIRE(integrate(p0, l13) == Catch::Approx(4)); + REQUIRE(integrate(p1, l13) == Catch::Approx(-4. / 3)); + REQUIRE(integrate(p2, l13) == Catch::Approx(-19. / 3)); + REQUIRE(integrate(p3, l13) == Catch::Approx(146. / 5)); + REQUIRE(integrate(p4, l13) == Catch::Approx(-25. / 6)); + REQUIRE(integrate(p5, l13) == Catch::Approx(-17. / 10)); + REQUIRE(integrate(p6, l13) == Catch::Approx(-197. / 175)); + REQUIRE(integrate(p7, l13) == Catch::Approx(-4507. / 1575)); + REQUIRE(integrate(p8, l13) == Catch::Approx(-23867. / 1575)); + REQUIRE(integrate(p9, l13) == Catch::Approx(7782251. / 346500)); + REQUIRE(integrate(p10, l13) == Catch::Approx(126885809. / 14437500)); + REQUIRE(integrate(p11, l13) == Catch::Approx(22133453663. / 11261250000)); + REQUIRE(integrate(p12, l13) == Catch::Approx(-419453736959. / 262762500000)); + REQUIRE(integrate(p13, l13) == Catch::Approx(-3625092349117. / 7882875000000)); + REQUIRE(integrate(p14, l13) != Catch::Approx(541632196607. / 1642265625000)); + + REQUIRE(get_order(p14, l13, 541632196607. / 1642265625000) == Catch::Approx(14)); + } + + SECTION("degree 14") + { + const QuadratureFormula<2>& l14 = QuadratureManager::instance().getTriangleFormula(GaussQuadratureDescriptor(14)); + + REQUIRE(l14.numberOfPoints() == 42); + + REQUIRE(integrate(p0, l14) == Catch::Approx(4)); + REQUIRE(integrate(p1, l14) == Catch::Approx(-4. / 3)); + REQUIRE(integrate(p2, l14) == Catch::Approx(-19. / 3)); + REQUIRE(integrate(p3, l14) == Catch::Approx(146. / 5)); + REQUIRE(integrate(p4, l14) == Catch::Approx(-25. / 6)); + REQUIRE(integrate(p5, l14) == Catch::Approx(-17. / 10)); + REQUIRE(integrate(p6, l14) == Catch::Approx(-197. / 175)); + REQUIRE(integrate(p7, l14) == Catch::Approx(-4507. / 1575)); + REQUIRE(integrate(p8, l14) == Catch::Approx(-23867. / 1575)); + REQUIRE(integrate(p9, l14) == Catch::Approx(7782251. / 346500)); + REQUIRE(integrate(p10, l14) == Catch::Approx(126885809. / 14437500)); + REQUIRE(integrate(p11, l14) == Catch::Approx(22133453663. / 11261250000)); + REQUIRE(integrate(p12, l14) == Catch::Approx(-419453736959. / 262762500000)); + REQUIRE(integrate(p13, l14) == Catch::Approx(-3625092349117. / 7882875000000)); + REQUIRE(integrate(p14, l14) == Catch::Approx(541632196607. / 1642265625000)); + REQUIRE(integrate(p15, l14) != Catch::Approx(-287809833862769. / 3350221875000000)); + + // In a weird way, the formula achieves 16th order on this test + REQUIRE(get_order(p15, l14, -287809833862769. / 3350221875000000) == Catch::Approx(16)); + } + + SECTION("degree 15") + { + const QuadratureFormula<2>& l15 = QuadratureManager::instance().getTriangleFormula(GaussQuadratureDescriptor(15)); + + REQUIRE(l15.numberOfPoints() == 49); + + REQUIRE(integrate(p0, l15) == Catch::Approx(4)); + REQUIRE(integrate(p1, l15) == Catch::Approx(-4. / 3)); + REQUIRE(integrate(p2, l15) == Catch::Approx(-19. / 3)); + REQUIRE(integrate(p3, l15) == Catch::Approx(146. / 5)); + REQUIRE(integrate(p4, l15) == Catch::Approx(-25. / 6)); + REQUIRE(integrate(p5, l15) == Catch::Approx(-17. / 10)); + REQUIRE(integrate(p6, l15) == Catch::Approx(-197. / 175)); + REQUIRE(integrate(p7, l15) == Catch::Approx(-4507. / 1575)); + REQUIRE(integrate(p8, l15) == Catch::Approx(-23867. / 1575)); + REQUIRE(integrate(p9, l15) == Catch::Approx(7782251. / 346500)); + REQUIRE(integrate(p10, l15) == Catch::Approx(126885809. / 14437500)); + REQUIRE(integrate(p11, l15) == Catch::Approx(22133453663. / 11261250000)); + REQUIRE(integrate(p12, l15) == Catch::Approx(-419453736959. / 262762500000)); + REQUIRE(integrate(p13, l15) == Catch::Approx(-3625092349117. / 7882875000000)); + REQUIRE(integrate(p14, l15) == Catch::Approx(541632196607. / 1642265625000)); + REQUIRE(integrate(p15, l15) == Catch::Approx(-287809833862769. / 3350221875000000)); + REQUIRE(integrate(p16, l15) != Catch::Approx(3340311405172793. / 6700443750000000).epsilon(1E-10)); + + REQUIRE(get_order(p16, l15, 3340311405172793. / 6700443750000000) == Catch::Approx(16)); + } + + SECTION("degree 16") + { + const QuadratureFormula<2>& l16 = QuadratureManager::instance().getTriangleFormula(GaussQuadratureDescriptor(16)); + + REQUIRE(l16.numberOfPoints() == 55); + + REQUIRE(integrate(p0, l16) == Catch::Approx(4)); + REQUIRE(integrate(p1, l16) == Catch::Approx(-4. / 3)); + REQUIRE(integrate(p2, l16) == Catch::Approx(-19. / 3)); + REQUIRE(integrate(p3, l16) == Catch::Approx(146. / 5)); + REQUIRE(integrate(p4, l16) == Catch::Approx(-25. / 6)); + REQUIRE(integrate(p5, l16) == Catch::Approx(-17. / 10)); + REQUIRE(integrate(p6, l16) == Catch::Approx(-197. / 175)); + REQUIRE(integrate(p7, l16) == Catch::Approx(-4507. / 1575)); + REQUIRE(integrate(p8, l16) == Catch::Approx(-23867. / 1575)); + REQUIRE(integrate(p9, l16) == Catch::Approx(7782251. / 346500)); + REQUIRE(integrate(p10, l16) == Catch::Approx(126885809. / 14437500)); + REQUIRE(integrate(p11, l16) == Catch::Approx(22133453663. / 11261250000)); + REQUIRE(integrate(p12, l16) == Catch::Approx(-419453736959. / 262762500000)); + REQUIRE(integrate(p13, l16) == Catch::Approx(-3625092349117. / 7882875000000)); + REQUIRE(integrate(p14, l16) == Catch::Approx(541632196607. / 1642265625000)); + REQUIRE(integrate(p15, l16) == Catch::Approx(-287809833862769. / 3350221875000000)); + REQUIRE(integrate(p16, l16) == Catch::Approx(3340311405172793. / 6700443750000000)); + REQUIRE(integrate(p17, l16) != Catch::Approx(-8386984372282772827. / 19096264687500000000.).epsilon(1E-10)); + + // In a weird way, the formula achieves ~18th order on this test + REQUIRE(get_order(p17, l16, -8386984372282772827. / 19096264687500000000.) == Catch::Approx(18).margin(1E-2)); + } + + SECTION("degree 17") + { + const QuadratureFormula<2>& l17 = QuadratureManager::instance().getTriangleFormula(GaussQuadratureDescriptor(17)); + + REQUIRE(l17.numberOfPoints() == 60); + + REQUIRE(integrate(p0, l17) == Catch::Approx(4)); + REQUIRE(integrate(p1, l17) == Catch::Approx(-4. / 3)); + REQUIRE(integrate(p2, l17) == Catch::Approx(-19. / 3)); + REQUIRE(integrate(p3, l17) == Catch::Approx(146. / 5)); + REQUIRE(integrate(p4, l17) == Catch::Approx(-25. / 6)); + REQUIRE(integrate(p5, l17) == Catch::Approx(-17. / 10)); + REQUIRE(integrate(p6, l17) == Catch::Approx(-197. / 175)); + REQUIRE(integrate(p7, l17) == Catch::Approx(-4507. / 1575)); + REQUIRE(integrate(p8, l17) == Catch::Approx(-23867. / 1575)); + REQUIRE(integrate(p9, l17) == Catch::Approx(7782251. / 346500)); + REQUIRE(integrate(p10, l17) == Catch::Approx(126885809. / 14437500)); + REQUIRE(integrate(p11, l17) == Catch::Approx(22133453663. / 11261250000)); + REQUIRE(integrate(p12, l17) == Catch::Approx(-419453736959. / 262762500000)); + REQUIRE(integrate(p13, l17) == Catch::Approx(-3625092349117. / 7882875000000)); + REQUIRE(integrate(p14, l17) == Catch::Approx(541632196607. / 1642265625000)); + REQUIRE(integrate(p15, l17) == Catch::Approx(-287809833862769. / 3350221875000000)); + REQUIRE(integrate(p16, l17) == Catch::Approx(3340311405172793. / 6700443750000000)); + REQUIRE(integrate(p17, l17) == Catch::Approx(-8386984372282772827. / 19096264687500000000.)); + REQUIRE(integrate(p18, l17) != Catch::Approx(-1599289493784003137. / 6820094531250000000.).epsilon(1E-10)); + + REQUIRE(get_order(p18, l17, -1599289493784003137. / 6820094531250000000.) == Catch::Approx(18).margin(1E-2)); + } + + SECTION("degree 18") + { + const QuadratureFormula<2>& l18 = QuadratureManager::instance().getTriangleFormula(GaussQuadratureDescriptor(18)); + + REQUIRE(l18.numberOfPoints() == 67); + + REQUIRE(integrate(p0, l18) == Catch::Approx(4)); + REQUIRE(integrate(p1, l18) == Catch::Approx(-4. / 3)); + REQUIRE(integrate(p2, l18) == Catch::Approx(-19. / 3)); + REQUIRE(integrate(p3, l18) == Catch::Approx(146. / 5)); + REQUIRE(integrate(p4, l18) == Catch::Approx(-25. / 6)); + REQUIRE(integrate(p5, l18) == Catch::Approx(-17. / 10)); + REQUIRE(integrate(p6, l18) == Catch::Approx(-197. / 175)); + REQUIRE(integrate(p7, l18) == Catch::Approx(-4507. / 1575)); + REQUIRE(integrate(p8, l18) == Catch::Approx(-23867. / 1575)); + REQUIRE(integrate(p9, l18) == Catch::Approx(7782251. / 346500)); + REQUIRE(integrate(p10, l18) == Catch::Approx(126885809. / 14437500)); + REQUIRE(integrate(p11, l18) == Catch::Approx(22133453663. / 11261250000)); + REQUIRE(integrate(p12, l18) == Catch::Approx(-419453736959. / 262762500000)); + REQUIRE(integrate(p13, l18) == Catch::Approx(-3625092349117. / 7882875000000)); + REQUIRE(integrate(p14, l18) == Catch::Approx(541632196607. / 1642265625000)); + REQUIRE(integrate(p15, l18) == Catch::Approx(-287809833862769. / 3350221875000000)); + REQUIRE(integrate(p16, l18) == Catch::Approx(3340311405172793. / 6700443750000000)); + REQUIRE(integrate(p17, l18) == Catch::Approx(-8386984372282772827. / 19096264687500000000.)); + REQUIRE(integrate(p18, l18) == Catch::Approx(-1599289493784003137. / 6820094531250000000.)); + REQUIRE(integrate(p19, l18) != Catch::Approx(5280879341958226453. / 47740661718750000000.).epsilon(1E-10)); + + // In a weird way, the formula achieves ~20th order on this test + REQUIRE(get_order(p19, l18, 5280879341958226453. / 47740661718750000000.) == Catch::Approx(20).margin(0.1)); + } + + SECTION("degree 19") + { + const QuadratureFormula<2>& l19 = QuadratureManager::instance().getTriangleFormula(GaussQuadratureDescriptor(19)); + + REQUIRE(l19.numberOfPoints() == 73); + + REQUIRE(integrate(p0, l19) == Catch::Approx(4)); + REQUIRE(integrate(p1, l19) == Catch::Approx(-4. / 3)); + REQUIRE(integrate(p2, l19) == Catch::Approx(-19. / 3)); + REQUIRE(integrate(p3, l19) == Catch::Approx(146. / 5)); + REQUIRE(integrate(p4, l19) == Catch::Approx(-25. / 6)); + REQUIRE(integrate(p5, l19) == Catch::Approx(-17. / 10)); + REQUIRE(integrate(p6, l19) == Catch::Approx(-197. / 175)); + REQUIRE(integrate(p7, l19) == Catch::Approx(-4507. / 1575)); + REQUIRE(integrate(p8, l19) == Catch::Approx(-23867. / 1575)); + REQUIRE(integrate(p9, l19) == Catch::Approx(7782251. / 346500)); + REQUIRE(integrate(p10, l19) == Catch::Approx(126885809. / 14437500)); + REQUIRE(integrate(p11, l19) == Catch::Approx(22133453663. / 11261250000)); + REQUIRE(integrate(p12, l19) == Catch::Approx(-419453736959. / 262762500000)); + REQUIRE(integrate(p13, l19) == Catch::Approx(-3625092349117. / 7882875000000)); + REQUIRE(integrate(p14, l19) == Catch::Approx(541632196607. / 1642265625000)); + REQUIRE(integrate(p15, l19) == Catch::Approx(-287809833862769. / 3350221875000000)); + REQUIRE(integrate(p16, l19) == Catch::Approx(3340311405172793. / 6700443750000000)); + REQUIRE(integrate(p17, l19) == Catch::Approx(-8386984372282772827. / 19096264687500000000.)); + REQUIRE(integrate(p18, l19) == Catch::Approx(-1599289493784003137. / 6820094531250000000.)); + REQUIRE(integrate(p19, l19) == Catch::Approx(5280879341958226453. / 47740661718750000000.)); + REQUIRE(integrate(p20, l19) != Catch::Approx(1390615013183923183. / 85251181640625000000.).epsilon(1E-10)); + + REQUIRE(get_order(p20, l19, 1390615013183923183. / 85251181640625000000.) == Catch::Approx(20).margin(0.1)); + } + + SECTION("degree 20") + { + const QuadratureFormula<2>& l20 = QuadratureManager::instance().getTriangleFormula(GaussQuadratureDescriptor(20)); + + REQUIRE(l20.numberOfPoints() == 79); + + REQUIRE(integrate(p0, l20) == Catch::Approx(4)); + REQUIRE(integrate(p1, l20) == Catch::Approx(-4. / 3)); + REQUIRE(integrate(p2, l20) == Catch::Approx(-19. / 3)); + REQUIRE(integrate(p3, l20) == Catch::Approx(146. / 5)); + REQUIRE(integrate(p4, l20) == Catch::Approx(-25. / 6)); + REQUIRE(integrate(p5, l20) == Catch::Approx(-17. / 10)); + REQUIRE(integrate(p6, l20) == Catch::Approx(-197. / 175)); + REQUIRE(integrate(p7, l20) == Catch::Approx(-4507. / 1575)); + REQUIRE(integrate(p8, l20) == Catch::Approx(-23867. / 1575)); + REQUIRE(integrate(p9, l20) == Catch::Approx(7782251. / 346500)); + REQUIRE(integrate(p10, l20) == Catch::Approx(126885809. / 14437500)); + REQUIRE(integrate(p11, l20) == Catch::Approx(22133453663. / 11261250000)); + REQUIRE(integrate(p12, l20) == Catch::Approx(-419453736959. / 262762500000)); + REQUIRE(integrate(p13, l20) == Catch::Approx(-3625092349117. / 7882875000000)); + REQUIRE(integrate(p14, l20) == Catch::Approx(541632196607. / 1642265625000)); + REQUIRE(integrate(p15, l20) == Catch::Approx(-287809833862769. / 3350221875000000)); + REQUIRE(integrate(p16, l20) == Catch::Approx(3340311405172793. / 6700443750000000)); + REQUIRE(integrate(p17, l20) == Catch::Approx(-8386984372282772827. / 19096264687500000000.)); + REQUIRE(integrate(p18, l20) == Catch::Approx(-1599289493784003137. / 6820094531250000000.)); + REQUIRE(integrate(p19, l20) == Catch::Approx(5280879341958226453. / 47740661718750000000.)); + REQUIRE(integrate(p20, l20) == Catch::Approx(1390615013183923183. / 85251181640625000000.)); + REQUIRE(integrate(p21, l20) != Catch::Approx(-520205676970121316953. / 215685489550781250000000.).epsilon(1E-10)); + + // In a weird way, the formula achieves ~22th order on this test + REQUIRE(get_order(p21, l20, -520205676970121316953. / 215685489550781250000000.) == Catch::Approx(22).margin(0.5)); + } + + SECTION("max implemented degree") + { + REQUIRE(QuadratureManager::instance().maxTriangleDegree(QuadratureType::Gauss) == + TriangleGaussQuadrature::max_degree); + } +} diff --git a/tests/test_TriangleTransformation.cpp b/tests/test_TriangleTransformation.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e9561e859d727ea6c4019eaa78de125fbab8ba00 --- /dev/null +++ b/tests/test_TriangleTransformation.cpp @@ -0,0 +1,141 @@ +#include <catch2/catch_approx.hpp> +#include <catch2/catch_test_macros.hpp> + +#include <analysis/GaussQuadratureDescriptor.hpp> +#include <analysis/QuadratureManager.hpp> +#include <geometry/TriangleTransformation.hpp> + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("TriangleTransformation", "[geometry]") +{ + SECTION("2D") + { + using R2 = TinyVector<2>; + + const R2 a = {1, 2}; + const R2 b = {3, 1}; + const R2 c = {2, 5}; + + const TriangleTransformation<2> t(a, b, c); + + REQUIRE(t({0, 0})[0] == Catch::Approx(1)); + REQUIRE(t({0, 0})[1] == Catch::Approx(2)); + + REQUIRE(t({1, 0})[0] == Catch::Approx(3)); + REQUIRE(t({1, 0})[1] == Catch::Approx(1)); + + REQUIRE(t({0, 1})[0] == Catch::Approx(2)); + REQUIRE(t({0, 1})[1] == Catch::Approx(5)); + + REQUIRE(t({1. / 3, 1. / 3})[0] == Catch::Approx(2)); + REQUIRE(t({1. / 3, 1. / 3})[1] == Catch::Approx(8. / 3)); + + REQUIRE(t.jacobianDeterminant() == Catch::Approx(7)); + + SECTION("Polynomial integral") + { + auto p = [](const R2& X) { + const double x = X[0]; + const double y = X[1]; + return 2 * x * x + 3 * x * y + y * y + 3 * y + 1; + }; + + QuadratureFormula<2> qf = QuadratureManager::instance().getTriangleFormula(GaussQuadratureDescriptor(2)); + + double sum = 0; + for (size_t i = 0; i < qf.numberOfPoints(); ++i) { + sum += qf.weight(i) * t.jacobianDeterminant() * p(t(qf.point(i))); + } + + REQUIRE(sum == Catch::Approx(3437. / 24)); + } + } + + SECTION("3D") + { + SECTION("Data") + { + using R3 = TinyVector<3>; + + const R3 a = {1, 2, 2}; + const R3 b = {4, 1, 3}; + const R3 c = {2, 5, 1}; + + const TriangleTransformation<3> t(a, b, c); + + REQUIRE(t({0, 0})[0] == Catch::Approx(1)); + REQUIRE(t({0, 0})[1] == Catch::Approx(2)); + REQUIRE(t({0, 0})[2] == Catch::Approx(2)); + + REQUIRE(t({1, 0})[0] == Catch::Approx(4)); + REQUIRE(t({1, 0})[1] == Catch::Approx(1)); + REQUIRE(t({1, 0})[2] == Catch::Approx(3)); + + REQUIRE(t({0, 1})[0] == Catch::Approx(2)); + REQUIRE(t({0, 1})[1] == Catch::Approx(5)); + REQUIRE(t({0, 1})[2] == Catch::Approx(1)); + + REQUIRE(t({1. / 3, 1. / 3})[0] == Catch::Approx(7. / 3)); + REQUIRE(t({1. / 3, 1. / 3})[1] == Catch::Approx(8. / 3)); + REQUIRE(t({1. / 3, 1. / 3})[2] == Catch::Approx(2)); + + REQUIRE(t.areaVariationNorm() == Catch::Approx(2 * std::sqrt(30))); + } + + SECTION("Area modulus") + { + using R3 = TinyVector<3>; + + const R3 a_hat = {0, 0, 0}; + const R3 b_hat = {1, 0, 0}; + const R3 c_hat = {0, 1, 0}; + + const double theta = 2.3; + TinyMatrix<3> r_theta(1, 0, 0, // + 0, std::cos(theta), std::sin(theta), // + 0, -std::sin(theta), std::cos(theta)); + + const double phi = 0.7; + TinyMatrix<3> r_phi(std::cos(phi), std::sin(phi), 0, // + -std::sin(phi), std::cos(phi), 0, // + 0, 0, 1); + + const R3 a = r_phi * r_theta * a_hat; + const R3 b = r_phi * r_theta * b_hat; + const R3 c = r_phi * r_theta * c_hat; + + const TriangleTransformation<3> t(a, b, c); + + // The triangle (a,b,c) is just a rotation of the initial one + REQUIRE(t.areaVariationNorm() == Catch::Approx(1)); + } + + SECTION("Polynomial integral") + { + using R3 = TinyVector<3>; + + const R3 a = {1, 2, 2}; + const R3 b = {4, 1, 3}; + const R3 c = {2, 5, 1}; + + const TriangleTransformation<3> t(a, b, c); + + auto p = [](const R3& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + return 2 * x * x + 3 * x - 3 * y * y + y + 2 * z * z - 0.5 * z + 2; + }; + + QuadratureFormula<2> qf = QuadratureManager::instance().getTriangleFormula(GaussQuadratureDescriptor(2)); + + double sum = 0; + for (size_t i = 0; i < qf.numberOfPoints(); ++i) { + sum += qf.weight(i) * t.areaVariationNorm() * p(t(qf.point(i))); + } + + REQUIRE(sum == Catch::Approx(39.2534499545369)); + } + } +} diff --git a/tests/test_main.cpp b/tests/test_main.cpp index 9c03ba9213ece8947688036ca7d5554c8e38a279..fa207c91b9b743ffa1986c20a3cdc6e1622c0a1a 100644 --- a/tests/test_main.cpp +++ b/tests/test_main.cpp @@ -2,6 +2,7 @@ #include <Kokkos_Core.hpp> +#include <analysis/QuadratureManager.hpp> #include <language/utils/OperatorRepository.hpp> #include <mesh/DiamondDualConnectivityManager.hpp> #include <mesh/DiamondDualMeshManager.hpp> @@ -36,6 +37,7 @@ main(int argc, char* argv[]) SynchronizerManager::create(); RandomEngine::create(); + QuadratureManager::create(); MeshDataManager::create(); DiamondDualConnectivityManager::create(); DiamondDualMeshManager::create(); @@ -53,6 +55,7 @@ main(int argc, char* argv[]) DiamondDualMeshManager::destroy(); DiamondDualConnectivityManager::destroy(); MeshDataManager::destroy(); + QuadratureManager::destroy(); RandomEngine::destroy(); SynchronizerManager::destroy(); }