diff --git a/src/scheme/PolynomialReconstruction.cpp b/src/scheme/PolynomialReconstruction.cpp index 4fa7cc1d3e3f669eff35969405869a8173ae9721..69d24b9e588587e83aab48ef194e8ed20883fca8 100644 --- a/src/scheme/PolynomialReconstruction.cpp +++ b/src/scheme/PolynomialReconstruction.cpp @@ -7,7 +7,11 @@ #include <analysis/GaussQuadratureDescriptor.hpp> #include <analysis/QuadratureFormula.hpp> #include <analysis/QuadratureManager.hpp> +#include <geometry/CubeTransformation.hpp> +#include <geometry/PrismTransformation.hpp> +#include <geometry/PyramidTransformation.hpp> #include <geometry/SquareTransformation.hpp> +#include <geometry/TetrahedronTransformation.hpp> #include <geometry/TriangleTransformation.hpp> class PolynomialReconstruction::MutableDiscreteFunctionDPkVariant @@ -220,6 +224,16 @@ PolynomialReconstruction::_build( mean_i_of_ejk_pool[i] = SmallArray<double>(basis_dimension - 1); } +#warning remove after rework + const bool FORCE_INTEGRATE = []() { + auto value = std::getenv("INTEGRATE"); + if (value == nullptr) { + return false; + } else { + return true; + } + }(); + parallel_for( mesh.numberOfCells(), PUGS_LAMBDA(const CellId cell_j_id) { if (cell_is_owned[cell_j_id]) { @@ -286,17 +300,7 @@ PolynomialReconstruction::_build( ShrinkMatrixView A(A_pool[t], stencil_cell_list.size()); -#warning remove after rework - std::string ENV_SWITCH = []() { - auto value = std::getenv("INTEGRATE"); - if (value == nullptr) { - return std::string{""}; - } else { - return std::string{value}; - } - }(); - - if ((m_descriptor.degree() == 1) and ((MeshType::Dimension == 3) or (ENV_SWITCH == ""))) { + if ((m_descriptor.degree() == 1) and (not FORCE_INTEGRATE)) { const Rd& Xj = xj[cell_j_id]; for (size_t i = 0; i < stencil_cell_list.size(); ++i) { const CellId cell_i_id = stencil_cell_list[i]; @@ -352,7 +356,7 @@ PolynomialReconstruction::_build( compute_mean_ejk(quadrature, T, Xj, Vj[cell_j_id], m_descriptor.degree(), basis_dimension, mean_j_of_ejk); } else { - throw NotImplementedError("unexpected cell type"); + throw NotImplementedError("unexpected cell type: " + std::string{name(cell_type[cell_j_id])}); } for (size_t i = 0; i < stencil_cell_list.size(); ++i) { @@ -370,7 +374,7 @@ PolynomialReconstruction::_build( mean_i_of_ejk); } else { - throw NotImplementedError("unexpected cell type"); + throw NotImplementedError("unexpected cell type: " + std::string{name(cell_type[cell_i_id])}); } for (size_t l = 0; l < basis_dimension - 1; ++l) { @@ -443,7 +447,7 @@ PolynomialReconstruction::_build( compute_mean_ejk(quadrature, T, Xj, Vj[cell_j_id], m_descriptor.degree(), basis_dimension, mean_j_of_ejk); } else { - throw NotImplementedError("unexpected cell type"); + throw NotImplementedError("unexpected cell type: " + std::string{name(cell_type[cell_j_id])}); } for (size_t i = 0; i < stencil_cell_list.size(); ++i) { @@ -470,13 +474,171 @@ PolynomialReconstruction::_build( mean_i_of_ejk); } else { - throw NotImplementedError("unexpected cell type"); + throw NotImplementedError("unexpected cell type: " + std::string{name(cell_type[cell_i_id])}); + } + + for (size_t l = 0; l < basis_dimension - 1; ++l) { + A(i, l) = mean_i_of_ejk[l] - mean_j_of_ejk[l]; + } + } + + } else if constexpr (MeshType::Dimension == 3) { + auto compute_mean_ejk = [&inv_Vj_wq_detJ_ek](const auto& quadrature, const auto& T, const Rd& Xj, + const double Vi, const size_t degree, const size_t dimension, + SmallArray<double>& mean_of_ejk) { + mean_of_ejk.fill(0); + + for (size_t i_q = 0; i_q < quadrature.numberOfPoints(); ++i_q) { + const double wq = quadrature.weight(i_q); + const Rd& xi_q = quadrature.point(i_q); + const double detT = [&] { + if constexpr (std::is_same_v<TetrahedronTransformation, std::decay_t<decltype(T)>>) { + return T.jacobianDeterminant(); + } else { + return T.jacobianDeterminant(xi_q); + } + }(); + + const Rd X_Xj = T(xi_q) - Xj; + + const double x_xj = X_Xj[0]; + const double y_yj = X_Xj[1]; + const double z_zj = X_Xj[2]; + + { + size_t k = 0; + inv_Vj_wq_detJ_ek[k++] = wq * detT / Vi; + for (; k <= degree; ++k) { + inv_Vj_wq_detJ_ek[k] = x_xj * inv_Vj_wq_detJ_ek[k - 1]; + } + + for (size_t i_y = 1; i_y <= degree; ++i_y) { + const size_t begin_i_y_1 = ((i_y - 1) * (2 * degree - i_y + 4)) / 2; + for (size_t l = 0; l <= degree - i_y; ++l) { + inv_Vj_wq_detJ_ek[k++] = y_yj * inv_Vj_wq_detJ_ek[begin_i_y_1 + l]; + } + } + + for (size_t i_z = 1; i_z <= degree; ++i_z) { + const size_t begin_i_z_1 = i_z * (i_z + 1) * (i_z + 2) / 6 - 1; + for (size_t i_y = 0; i_y <= degree - i_z; ++i_y) { + const size_t begin_i_y_1 = (i_y * (2 * degree - i_y + 3)) / 2 + begin_i_z_1; + for (size_t l = 0; l <= degree - i_y - i_z; ++l) { + inv_Vj_wq_detJ_ek[k++] = z_zj * inv_Vj_wq_detJ_ek[begin_i_y_1 + l]; + } + } + } + } + + for (size_t k = 1; k < dimension; ++k) { + mean_of_ejk[k - 1] += inv_Vj_wq_detJ_ek[k]; + } + } + }; + + const Rd& Xj = xj[cell_j_id]; + + if (cell_type[cell_j_id] == CellType::Tetrahedron) { + auto cell_node = cell_to_node_matrix[cell_j_id]; + + const TetrahedronTransformation T{xr[cell_node[0]], xr[cell_node[1]], xr[cell_node[2]], xr[cell_node[3]]}; + + const auto& quadrature = + QuadratureManager::instance().getTetrahedronFormula(GaussQuadratureDescriptor{m_descriptor.degree()}); + + compute_mean_ejk(quadrature, T, Xj, Vj[cell_j_id], m_descriptor.degree(), basis_dimension, mean_j_of_ejk); + + } else if (cell_type[cell_j_id] == CellType::Prism) { + auto cell_node = cell_to_node_matrix[cell_j_id]; + + const PrismTransformation T{xr[cell_node[0]], xr[cell_node[1]], xr[cell_node[2]], // + xr[cell_node[3]], xr[cell_node[4]], xr[cell_node[5]]}; + + const auto& quadrature = + QuadratureManager::instance().getPrismFormula(GaussQuadratureDescriptor{m_descriptor.degree() + 1}); + + compute_mean_ejk(quadrature, T, Xj, Vj[cell_j_id], m_descriptor.degree(), basis_dimension, mean_j_of_ejk); + + } else if (cell_type[cell_j_id] == CellType::Pyramid) { + auto cell_node = cell_to_node_matrix[cell_j_id]; + + const PyramidTransformation T{xr[cell_node[0]], xr[cell_node[1]], xr[cell_node[2]], xr[cell_node[3]], + xr[cell_node[4]]}; + + const auto& quadrature = + QuadratureManager::instance().getPyramidFormula(GaussQuadratureDescriptor{m_descriptor.degree() + 1}); + + compute_mean_ejk(quadrature, T, Xj, Vj[cell_j_id], m_descriptor.degree(), basis_dimension, mean_j_of_ejk); + + } else if (cell_type[cell_j_id] == CellType::Hexahedron) { + auto cell_node = cell_to_node_matrix[cell_j_id]; + + const CubeTransformation T{xr[cell_node[0]], xr[cell_node[1]], xr[cell_node[2]], xr[cell_node[3]], + xr[cell_node[4]], xr[cell_node[5]], xr[cell_node[6]], xr[cell_node[7]]}; + + const auto& quadrature = QuadratureManager::instance().getCubeFormula( + GaussLegendreQuadratureDescriptor{m_descriptor.degree() + 1}); + + compute_mean_ejk(quadrature, T, Xj, Vj[cell_j_id], m_descriptor.degree(), basis_dimension, mean_j_of_ejk); + + } else { + throw NotImplementedError("unexpected cell type: " + std::string{name(cell_type[cell_j_id])}); + } + + for (size_t i = 0; i < stencil_cell_list.size(); ++i) { + const CellId cell_i_id = stencil_cell_list[i]; + + auto cell_node = cell_to_node_matrix[cell_i_id]; + + if (cell_type[cell_i_id] == CellType::Tetrahedron) { + const TetrahedronTransformation T{xr[cell_node[0]], xr[cell_node[1]], xr[cell_node[2]], + xr[cell_node[3]]}; + + const auto& quadrature = + QuadratureManager::instance().getTetrahedronFormula(GaussQuadratureDescriptor{m_descriptor.degree()}); + + compute_mean_ejk(quadrature, T, Xj, Vj[cell_i_id], m_descriptor.degree(), basis_dimension, + mean_i_of_ejk); + + } else if (cell_type[cell_i_id] == CellType::Prism) { + const PrismTransformation T{xr[cell_node[0]], xr[cell_node[1]], xr[cell_node[2]], // + xr[cell_node[3]], xr[cell_node[4]], xr[cell_node[5]]}; + + const auto& quadrature = + QuadratureManager::instance().getPrismFormula(GaussQuadratureDescriptor{m_descriptor.degree() + 1}); + + compute_mean_ejk(quadrature, T, Xj, Vj[cell_i_id], m_descriptor.degree(), basis_dimension, + mean_i_of_ejk); + + } else if (cell_type[cell_i_id] == CellType::Pyramid) { + const PyramidTransformation T{xr[cell_node[0]], xr[cell_node[1]], xr[cell_node[2]], xr[cell_node[3]], + xr[cell_node[4]]}; + + const auto& quadrature = + QuadratureManager::instance().getPyramidFormula(GaussQuadratureDescriptor{m_descriptor.degree() + 1}); + + compute_mean_ejk(quadrature, T, Xj, Vj[cell_i_id], m_descriptor.degree(), basis_dimension, + mean_i_of_ejk); + + } else if (cell_type[cell_i_id] == CellType::Hexahedron) { + const CubeTransformation T{xr[cell_node[0]], xr[cell_node[1]], xr[cell_node[2]], xr[cell_node[3]], + xr[cell_node[4]], xr[cell_node[5]], xr[cell_node[6]], xr[cell_node[7]]}; + + const auto& quadrature = QuadratureManager::instance().getCubeFormula( + GaussLegendreQuadratureDescriptor{m_descriptor.degree() + 1}); + + compute_mean_ejk(quadrature, T, Xj, Vj[cell_i_id], m_descriptor.degree(), basis_dimension, + mean_i_of_ejk); + + } else { + throw NotImplementedError("unexpected cell type: " + std::string{name(cell_type[cell_i_id])}); } for (size_t l = 0; l < basis_dimension - 1; ++l) { A(i, l) = mean_i_of_ejk[l] - mean_j_of_ejk[l]; } } + } else { throw NotImplementedError("unexpected dimension"); } diff --git a/tests/test_PolynomialReconstruction.cpp b/tests/test_PolynomialReconstruction.cpp index 0e9398fab9398ef286ccb7e3932cd6ca4fa31bf8..47a538f0d1f4e32d8367616739b878ddbe728cb7 100644 --- a/tests/test_PolynomialReconstruction.cpp +++ b/tests/test_PolynomialReconstruction.cpp @@ -692,7 +692,7 @@ TEST_CASE("PolynomialReconstruction", "[scheme]") max_x_slope_error = std::max(max_x_slope_error, std::abs(reconstructed_slope - 1.7)); } - REQUIRE(parallel::allReduceMax(max_x_slope_error) == Catch::Approx(0).margin(1E-14)); + REQUIRE(parallel::allReduceMax(max_x_slope_error) == Catch::Approx(0).margin(1E-13)); } { @@ -703,7 +703,7 @@ TEST_CASE("PolynomialReconstruction", "[scheme]") max_y_slope_error = std::max(max_y_slope_error, std::abs(reconstructed_slope - (-1.3))); } - REQUIRE(parallel::allReduceMax(max_y_slope_error) == Catch::Approx(0).margin(1E-14)); + REQUIRE(parallel::allReduceMax(max_y_slope_error) == Catch::Approx(0).margin(1E-13)); } { @@ -714,7 +714,7 @@ TEST_CASE("PolynomialReconstruction", "[scheme]") max_z_slope_error = std::max(max_z_slope_error, std::abs(reconstructed_slope - 2.1)); } - REQUIRE(parallel::allReduceMax(max_z_slope_error) == Catch::Approx(0).margin(1E-14)); + REQUIRE(parallel::allReduceMax(max_z_slope_error) == Catch::Approx(0).margin(1E-12)); } } } @@ -761,7 +761,7 @@ TEST_CASE("PolynomialReconstruction", "[scheme]") max_x_slope_error = std::max(max_x_slope_error, l2Norm(reconstructed_slope - R3{1.7, -0.6, 3.1})); } - REQUIRE(parallel::allReduceMax(max_x_slope_error) == Catch::Approx(0).margin(1E-13)); + REQUIRE(parallel::allReduceMax(max_x_slope_error) == Catch::Approx(0).margin(1E-12)); } { @@ -772,7 +772,7 @@ TEST_CASE("PolynomialReconstruction", "[scheme]") max_y_slope_error = std::max(max_y_slope_error, l2Norm(reconstructed_slope - R3{-2.2, 1.3, -1.1})); } - REQUIRE(parallel::allReduceMax(max_y_slope_error) == Catch::Approx(0).margin(1E-13)); + REQUIRE(parallel::allReduceMax(max_y_slope_error) == Catch::Approx(0).margin(1E-12)); } { @@ -783,7 +783,7 @@ TEST_CASE("PolynomialReconstruction", "[scheme]") max_z_slope_error = std::max(max_z_slope_error, l2Norm(reconstructed_slope - R3{1.8, -3.7, 1.9})); } - REQUIRE(parallel::allReduceMax(max_z_slope_error) == Catch::Approx(0).margin(1E-13)); + REQUIRE(parallel::allReduceMax(max_z_slope_error) == Catch::Approx(0).margin(1E-12)); } } } @@ -847,7 +847,7 @@ TEST_CASE("PolynomialReconstruction", "[scheme]") std::max(max_y_slope_error, frobeniusNorm(reconstructed_slope - R2x2{+1.2, -2.2, // 1.3, +0.8})); } - REQUIRE(parallel::allReduceMax(max_y_slope_error) == Catch::Approx(0).margin(1E-13)); + REQUIRE(parallel::allReduceMax(max_y_slope_error) == Catch::Approx(0).margin(1E-12)); } { @@ -860,7 +860,7 @@ TEST_CASE("PolynomialReconstruction", "[scheme]") std::max(max_z_slope_error, frobeniusNorm(reconstructed_slope - R2x2{-1.3, -2.4, // +1.4, -1.8})); } - REQUIRE(parallel::allReduceMax(max_z_slope_error) == Catch::Approx(0).margin(1E-13)); + REQUIRE(parallel::allReduceMax(max_z_slope_error) == Catch::Approx(0).margin(1E-12)); } } } @@ -934,7 +934,7 @@ TEST_CASE("PolynomialReconstruction", "[scheme]") max_y_slope_error = std::max(max_y_slope_error, std::abs(reconstructed_slope - slope[i])); } } - REQUIRE(parallel::allReduceMax(max_y_slope_error) == Catch::Approx(0).margin(1E-13)); + REQUIRE(parallel::allReduceMax(max_y_slope_error) == Catch::Approx(0).margin(1E-12)); } {