diff --git a/src/scheme/test_reconstruction.cpp b/src/scheme/test_reconstruction.cpp index bf1c51121d943b37e854e295b5c472140239fc78..3753143d38ff1ea8c2c6b32472039e30cb985109 100644 --- a/src/scheme/test_reconstruction.cpp +++ b/src/scheme/test_reconstruction.cpp @@ -7,10 +7,36 @@ void test_reconstruction(const std::vector<std::shared_ptr<const DiscreteFunctionVariant>>& discrete_function_variant_list, uint64_t degree) { - PolynomialReconstructionDescriptor descriptor{PolynomialReconstructionDescriptor::IntegrationMethod::element, degree}; - { - const size_t nb_loops = 1; - std::cout << "** variable list at once (" << nb_loops << " times)\n"; + std::vector descriptor_list = + {PolynomialReconstructionDescriptor{PolynomialReconstructionDescriptor::IntegrationMethod::cell_center, degree}, + PolynomialReconstructionDescriptor{PolynomialReconstructionDescriptor::IntegrationMethod::element, degree}, + PolynomialReconstructionDescriptor{PolynomialReconstructionDescriptor::IntegrationMethod::boundary, degree}}; + + [[maybe_unused]] auto x = + PolynomialReconstruction{ + PolynomialReconstructionDescriptor{PolynomialReconstructionDescriptor::IntegrationMethod::cell_center, degree}} + .build(discrete_function_variant_list); + + for (auto&& descriptor : descriptor_list) { + std::string method_name; + switch (descriptor.integrationMethod()) { + case PolynomialReconstructionDescriptor::IntegrationMethod::element: { + method_name = "element"; + break; + } + case PolynomialReconstructionDescriptor::IntegrationMethod::boundary: { + method_name = "boundary"; + break; + } + case PolynomialReconstructionDescriptor::IntegrationMethod::cell_center: { + method_name = "cell_center"; + break; + } + } + + const size_t nb_loops = 50; + std::cout << "** variable list at once (" << nb_loops << " times) using " << rang::fgB::yellow << method_name + << rang::fg::reset << "\n"; PolynomialReconstruction reconstruction{descriptor}; Timer t; diff --git a/tests/test_QuadraticPolynomialReconstruction.cpp b/tests/test_QuadraticPolynomialReconstruction.cpp index 69c685f544f774205effbcf304dca43ff7d84658..6b992e960c3a47d0ddf050b30ac893492edd509b 100644 --- a/tests/test_QuadraticPolynomialReconstruction.cpp +++ b/tests/test_QuadraticPolynomialReconstruction.cpp @@ -584,16 +584,326 @@ TEST_CASE("QuadraticPolynomialReconstruction", "[scheme]") return L1_error; }; + std::map<std::string, PolynomialReconstructionDescriptor> name_method_map = + {{"element", + PolynomialReconstructionDescriptor{PolynomialReconstructionDescriptor::IntegrationMethod::element, 2}}, + {"boundary", + PolynomialReconstructionDescriptor{PolynomialReconstructionDescriptor::IntegrationMethod::boundary, 2}}}; + + for (auto [method_name, method_descriptor] : name_method_map) { + SECTION(method_name) + { + SECTION("R data") + { + for (auto named_mesh : MeshDataBaseForTests::get().all2DMeshes()) { + SECTION(named_mesh.name()) + { + auto p_mesh = named_mesh.mesh()->get<Mesh<2>>(); + auto& mesh = *p_mesh; + + auto f_exact = [](const R2& x) { + return 2.3 + 1.7 * x[0] + 0.2 * x[1] - 3.2 * x[0] * x[0] + 1.3 * x[0] * x[1] - 1.4 * x[1] * x[1]; + }; + + auto xr = mesh.xr(); + auto Vj = MeshDataManager::instance().getMeshData(mesh).Vj(); + + auto cell_type = mesh.connectivity().cellType(); + auto cell_to_node_matrix = mesh.connectivity().cellToNodeMatrix(); + + DiscreteFunctionP0<double> fh{p_mesh}; + + parallel_for( + mesh.numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { + auto cell_node_list = cell_to_node_matrix[cell_id]; + double value = 0; + integrate_in_cell(cell_type[cell_id], cell_node_list, xr, f_exact, value); + fh[cell_id] = value / Vj[cell_id]; + }); + + auto reconstructions = PolynomialReconstruction{method_descriptor}.build(fh); + + auto dpk_fh = reconstructions[0]->get<DiscreteFunctionDPk<2, const double>>(); + + double L1_error = compute_L1_error(cell_type, mesh, f_exact, dpk_fh); + REQUIRE(parallel::allReduceMax(L1_error) == Catch::Approx(0).margin(1E-13)); + } + } + } + + SECTION("R^3 data") + { + using R3 = TinyVector<3>; + + for (auto named_mesh : MeshDataBaseForTests::get().all2DMeshes()) { + SECTION(named_mesh.name()) + { + auto p_mesh = named_mesh.mesh()->get<Mesh<2>>(); + auto& mesh = *p_mesh; + + auto u_exact = [](const R2& X) -> R3 { + const double x = X[0]; + const double y = X[1]; + const double x2 = x * x; + const double xy = x * y; + const double y2 = y * y; + + return R3{+2.3 + 1.7 * x + 1.3 * y - 3.2 * x2 + 1.6 * xy + 0.9 * y2, // + +7.0 + 5.0 * x - 2.4 * y + 3.0 * x2 - 0.8 * xy + 1.1 * y2, // + -4.0 + 3.5 * x - 0.7 * y + 2.7 * x2 - 2.1 * xy - 1.8 * y2}; + }; + + auto xr = mesh.xr(); + auto Vj = MeshDataManager::instance().getMeshData(mesh).Vj(); + + auto cell_type = mesh.connectivity().cellType(); + auto cell_to_node_matrix = mesh.connectivity().cellToNodeMatrix(); + + DiscreteFunctionP0<R3> uh{p_mesh}; + + parallel_for( + mesh.numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { + auto cell_node_list = cell_to_node_matrix[cell_id]; + R3 value = zero; + integrate_in_cell(cell_type[cell_id], cell_node_list, xr, u_exact, value); + uh[cell_id] = 1. / Vj[cell_id] * value; + }); + + auto reconstructions = PolynomialReconstruction{method_descriptor}.build(uh); + + auto dpk_uh = reconstructions[0]->get<DiscreteFunctionDPk<2, const R3>>(); + + double L1_error = compute_L1_error(cell_type, mesh, u_exact, dpk_uh); + REQUIRE(parallel::allReduceMax(L1_error) == Catch::Approx(0).margin(1E-13)); + } + } + } + + SECTION("R^2x2 data") + { + using R2x2 = TinyMatrix<2, 2>; + + for (auto named_mesh : MeshDataBaseForTests::get().all2DMeshes()) { + SECTION(named_mesh.name()) + { + auto p_mesh = named_mesh.mesh()->get<Mesh<2>>(); + auto& mesh = *p_mesh; + + auto A_exact = [](const R2& X) -> R2x2 { + const double x = X[0]; + const double y = X[1]; + const double x2 = x * x; + const double xy = x * y; + const double y2 = y * y; + + return R2x2{+2.3 + 1.7 * x + 1.2 * y + 1.1 * x2 + 0.7 * xy - 0.8 * y2, // + -1.7 + 2.1 * x - 2.2 * y - 1.9 * x2 + 0.2 * xy + 1.2 * y2, // + +1.4 - 0.6 * x - 2.1 * y + 0.3 * x2 - 3.1 * xy + 1.3 * y2, // + +2.4 - 2.3 * x + 1.3 * y - 0.8 * x2 + 1.2 * xy - 2.0 * y2}; + }; + + auto xr = mesh.xr(); + auto Vj = MeshDataManager::instance().getMeshData(mesh).Vj(); + + auto cell_type = mesh.connectivity().cellType(); + auto cell_to_node_matrix = mesh.connectivity().cellToNodeMatrix(); + + DiscreteFunctionP0<R2x2> Ah{p_mesh}; + + parallel_for( + mesh.numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { + auto cell_node_list = cell_to_node_matrix[cell_id]; + R2x2 value = zero; + integrate_in_cell(cell_type[cell_id], cell_node_list, xr, A_exact, value); + Ah[cell_id] = 1. / Vj[cell_id] * value; + }); + + auto reconstructions = PolynomialReconstruction{method_descriptor}.build(Ah); + + auto dpk_Ah = reconstructions[0]->get<DiscreteFunctionDPk<2, const R2x2>>(); + + double L1_error = compute_L1_error(cell_type, mesh, A_exact, dpk_Ah); + REQUIRE(parallel::allReduceMax(L1_error) == Catch::Approx(0).margin(1E-13)); + } + } + } + } + } + } + + SECTION("3D") + { + using R3 = TinyVector<3>; + + auto integrate_in_cell = [](const CellType& cell_type, const auto& cell_node_list, const auto& xr, + const auto& exact, auto& value) { + switch (cell_type) { + 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]]}; + QuadratureFormula<3> qf = QuadratureManager::instance().getTetrahedronFormula(GaussQuadratureDescriptor{2}); + for (size_t i_q = 0; i_q < qf.numberOfPoints(); ++i_q) { + const R3 x_hat = qf.point(i_q); + const R3 x = T(x_hat); + value += qf.weight(i_q) * T.jacobianDeterminant() * exact(x); + } + 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]]}; + QuadratureFormula<3> qf = QuadratureManager::instance().getPyramidFormula(GaussQuadratureDescriptor{3}); + for (size_t i_q = 0; i_q < qf.numberOfPoints(); ++i_q) { + const R3 x_hat = qf.point(i_q); + const R3 x = T(x_hat); + value += qf.weight(i_q) * T.jacobianDeterminant(x_hat) * exact(x); + } + 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]]}; + QuadratureFormula<3> qf = QuadratureManager::instance().getPrismFormula(GaussQuadratureDescriptor{3}); + for (size_t i_q = 0; i_q < qf.numberOfPoints(); ++i_q) { + const R3 x_hat = qf.point(i_q); + const R3 x = T(x_hat); + value += qf.weight(i_q) * T.jacobianDeterminant(x_hat) * exact(x); + } + 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]]}; + QuadratureFormula<3> qf = QuadratureManager::instance().getCubeFormula(GaussLegendreQuadratureDescriptor{3}); + for (size_t i_q = 0; i_q < qf.numberOfPoints(); ++i_q) { + const R3 x_hat = qf.point(i_q); + const R3 x = T(x_hat); + value += qf.weight(i_q) * T.jacobianDeterminant(x_hat) * exact(x); + } + break; + } + default: { + throw UnexpectedError("invalid cell type"); + } + } + }; + + auto compute_L1_error = [](const auto& cell_type, const auto& mesh, const auto& exact, const auto& dpk) { + auto cell_to_node_matrix = mesh.connectivity().cellToNodeMatrix(); + const auto& xr = mesh.xr(); + + using DataType = typename std::decay_t<decltype(dpk)>::data_type; + + auto sum_abs = [](const DataType& diff) -> double { + if constexpr (std::is_arithmetic_v<DataType>) { + return std::abs(diff); + } else if constexpr (is_tiny_vector_v<DataType>) { + double sum = 0; + for (size_t i = 0; i < diff.dimension(); ++i) { + sum += std::abs(diff[i]); + } + return sum; + } else if constexpr (is_tiny_matrix_v<DataType>) { + double sum = 0; + for (size_t i = 0; i < diff.numberOfRows(); ++i) { + for (size_t j = 0; j < diff.numberOfRows(); ++j) { + sum += std::abs(diff(i, j)); + } + } + return sum; + } else { + throw UnexpectedError("unexpected value type"); + } + }; + + double L1_error = 0; + for (CellId cell_id = 0; cell_id < mesh.numberOfCells(); ++cell_id) { + const auto cell_node_list = cell_to_node_matrix[cell_id]; + const auto dpkj = dpk[cell_id]; + + double error = 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]]}; + QuadratureFormula<3> qf = QuadratureManager::instance().getTetrahedronFormula(GaussQuadratureDescriptor{2}); + for (size_t i_q = 0; i_q < qf.numberOfPoints(); ++i_q) { + const R3 x_hat = qf.point(i_q); + const R3 x = T(x_hat); + DataType diff = qf.weight(i_q) * T.jacobianDeterminant() * (exact(x) - dpkj(x)); + error += sum_abs(diff); + } + 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]]}; + QuadratureFormula<3> qf = QuadratureManager::instance().getPyramidFormula(GaussQuadratureDescriptor{3}); + for (size_t i_q = 0; i_q < qf.numberOfPoints(); ++i_q) { + const R3 x_hat = qf.point(i_q); + const R3 x = T(x_hat); + DataType diff = qf.weight(i_q) * T.jacobianDeterminant(x_hat) * (exact(x) - dpkj(x)); + error += sum_abs(diff); + } + 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]]}; + QuadratureFormula<3> qf = QuadratureManager::instance().getPrismFormula(GaussQuadratureDescriptor{3}); + for (size_t i_q = 0; i_q < qf.numberOfPoints(); ++i_q) { + const R3 x_hat = qf.point(i_q); + const R3 x = T(x_hat); + DataType diff = qf.weight(i_q) * T.jacobianDeterminant(x_hat) * (exact(x) - dpkj(x)); + error += sum_abs(diff); + } + 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]]}; + QuadratureFormula<3> qf = + QuadratureManager::instance().getCubeFormula(GaussLegendreQuadratureDescriptor{3}); + for (size_t i_q = 0; i_q < qf.numberOfPoints(); ++i_q) { + const R3 x_hat = qf.point(i_q); + const R3 x = T(x_hat); + DataType diff = qf.weight(i_q) * T.jacobianDeterminant(x_hat) * (exact(x) - dpkj(x)); + error += sum_abs(diff); + } + break; + } + default: { + throw UnexpectedError("invalid cell type"); + } + } + + L1_error += error; + } + return L1_error; + }; + SECTION("R data") { - for (auto named_mesh : MeshDataBaseForTests::get().all2DMeshes()) { + for (auto named_mesh : MeshDataBaseForTests::get().all3DMeshes()) { SECTION(named_mesh.name()) { - auto p_mesh = named_mesh.mesh()->get<Mesh<2>>(); - auto& mesh = *p_mesh; + auto p_mesh = named_mesh.mesh()->get<Mesh<3>>(); + auto& mesh = *p_mesh; + auto f_exact = [](const R3& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + const double x2 = x * x; + const double xy = x * y; + const double xz = x * z; + const double y2 = y * y; + const double yz = y * z; + const double z2 = z * z; - auto f_exact = [](const R2& x) { - return 2.3 + 1.7 * x[0] + 0.2 * x[1] - 3.2 * x[0] * x[0] + 1.3 * x[0] * x[1] - 1.4 * x[1] * x[1]; + return 2.3 + 1.7 * x + 0.2 * y + 1.4 * z - 3.2 * x2 + 1.3 * xy - 1.6 * xz - 1.4 * y2 + 2 * yz - 1.8 * z2; }; auto xr = mesh.xr(); @@ -614,7 +924,7 @@ TEST_CASE("QuadraticPolynomialReconstruction", "[scheme]") auto reconstructions = PolynomialReconstruction{descriptor}.build(fh); - auto dpk_fh = reconstructions[0]->get<DiscreteFunctionDPk<2, const double>>(); + auto dpk_fh = reconstructions[0]->get<DiscreteFunctionDPk<3, const double>>(); double L1_error = compute_L1_error(cell_type, mesh, f_exact, dpk_fh); REQUIRE(parallel::allReduceMax(L1_error) == Catch::Approx(0).margin(1E-13)); @@ -624,24 +934,29 @@ TEST_CASE("QuadraticPolynomialReconstruction", "[scheme]") SECTION("R^3 data") { - using R3 = TinyVector<3>; - - for (auto named_mesh : MeshDataBaseForTests::get().all2DMeshes()) { + for (auto named_mesh : MeshDataBaseForTests::get().all3DMeshes()) { SECTION(named_mesh.name()) { - auto p_mesh = named_mesh.mesh()->get<Mesh<2>>(); + auto p_mesh = named_mesh.mesh()->get<Mesh<3>>(); auto& mesh = *p_mesh; - auto u_exact = [](const R2& X) -> R3 { + auto u_exact = [](const R3& X) -> R3 { const double x = X[0]; const double y = X[1]; + const double z = X[2]; const double x2 = x * x; const double xy = x * y; + const double xz = x * z; const double y2 = y * y; - - return R3{+2.3 + 1.7 * x + 1.3 * y - 3.2 * x2 + 1.6 * xy + 0.9 * y2, // - +7.0 + 5.0 * x - 2.4 * y + 3.0 * x2 - 0.8 * xy + 1.1 * y2, // - -4.0 + 3.5 * x - 0.7 * y + 2.7 * x2 - 2.1 * xy - 1.8 * y2}; + const double yz = y * z; + const double z2 = z * z; + + return R3{+2.3 + 1.7 * x - 2.2 * y + 1.8 * z // + + 0.3 * x2 - 1.3 * xy + 2.7 * xz + 0.7 * y2 + 2.0 * yz - 1.2 * z2, // + +1.4 - 0.6 * x + 1.3 * y - 3.7 * z // + + 3.1 * x2 - 2.4 * xy - 1.5 * xz - 1.9 * y2 + 0.2 * yz + 0.9 * z2, // + -0.2 + 3.1 * x - 1.1 * y + 1.9 * z // + - 1.3 * x2 + 2.8 * xy - 2.1 * xz + 3.2 * y2 - 2.1 * yz + 1.6 * z2}; }; auto xr = mesh.xr(); @@ -662,8 +977,7 @@ TEST_CASE("QuadraticPolynomialReconstruction", "[scheme]") auto reconstructions = PolynomialReconstruction{descriptor}.build(uh); - auto dpk_uh = reconstructions[0]->get<DiscreteFunctionDPk<2, const R3>>(); - + auto dpk_uh = reconstructions[0]->get<DiscreteFunctionDPk<3, const R3>>(); double L1_error = compute_L1_error(cell_type, mesh, u_exact, dpk_uh); REQUIRE(parallel::allReduceMax(L1_error) == Catch::Approx(0).margin(1E-13)); } @@ -674,23 +988,32 @@ TEST_CASE("QuadraticPolynomialReconstruction", "[scheme]") { using R2x2 = TinyMatrix<2, 2>; - for (auto named_mesh : MeshDataBaseForTests::get().all2DMeshes()) { + for (auto named_mesh : MeshDataBaseForTests::get().all3DMeshes()) { SECTION(named_mesh.name()) { - auto p_mesh = named_mesh.mesh()->get<Mesh<2>>(); + auto p_mesh = named_mesh.mesh()->get<Mesh<3>>(); auto& mesh = *p_mesh; - auto A_exact = [](const R2& X) -> R2x2 { + auto A_exact = [](const R3& X) -> R2x2 { const double x = X[0]; const double y = X[1]; + const double z = X[2]; const double x2 = x * x; const double xy = x * y; + const double xz = x * z; const double y2 = y * y; - - return R2x2{+2.3 + 1.7 * x + 1.2 * y + 1.1 * x2 + 0.7 * xy - 0.8 * y2, // - -1.7 + 2.1 * x - 2.2 * y - 1.9 * x2 + 0.2 * xy + 1.2 * y2, // - +1.4 - 0.6 * x - 2.1 * y + 0.3 * x2 - 3.1 * xy + 1.3 * y2, // - +2.4 - 2.3 * x + 1.3 * y - 0.8 * x2 + 1.2 * xy - 2.0 * y2}; + const double yz = y * z; + const double z2 = z * z; + + return R2x2{+2.3 + 1.7 * x - 2.2 * y + 1.8 * z // + + 0.3 * x2 - 1.3 * xy + 2.7 * xz + 0.7 * y2 + 2.0 * yz - 1.2 * z2, // + +1.4 - 0.6 * x + 1.3 * y - 3.7 * z // + + 3.1 * x2 - 2.4 * xy - 1.5 * xz - 1.9 * y2 + 0.2 * yz + 0.9 * z2, // + // + -0.2 + 3.1 * x - 1.1 * y + 1.9 * z // + - 1.3 * x2 + 2.8 * xy - 2.1 * xz + 3.2 * y2 - 2.1 * yz + 1.6 * z2, // + +0.9 - 1.3 * x + 2.1 * y + 3.1 * z // + + 1.1 * x2 + 1.8 * xy + 1.2 * xz - 2.3 * y2 + 3.3 * yz - 1.2 * z2}; }; auto xr = mesh.xr(); @@ -709,490 +1032,13 @@ TEST_CASE("QuadraticPolynomialReconstruction", "[scheme]") Ah[cell_id] = 1. / Vj[cell_id] * value; }); + descriptor.setRowWeighting(false); auto reconstructions = PolynomialReconstruction{descriptor}.build(Ah); - auto dpk_Ah = reconstructions[0]->get<DiscreteFunctionDPk<2, const R2x2>>(); - - double L1_error = compute_L1_error(cell_type, mesh, A_exact, dpk_Ah); - REQUIRE(parallel::allReduceMax(L1_error) == Catch::Approx(0).margin(1E-13)); - } - } - } - - // SECTION("vector data") - // { - // using R4 = TinyVector<4>; - - // for (auto named_mesh : MeshDataBaseForTests::get().all2DMeshes()) { - // SECTION(named_mesh.name()) - // { - // auto p_mesh = named_mesh.mesh()->get<Mesh<2>>(); - // auto& mesh = *p_mesh; - - // auto vector_affine = [](const R2& x) -> R4 { - // return R4{+2.3 + 1.7 * x[0] + 1.2 * x[1], -1.7 + 2.1 * x[0] - 2.2 * x[1], // - // +1.4 - 0.6 * x[0] - 2.1 * x[1], +2.4 - 2.3 * x[0] + 1.3 * x[1]}; - // }; - // auto xj = MeshDataManager::instance().getMeshData(mesh).xj(); - - // DiscreteFunctionP0Vector<double> Vh{p_mesh, 4}; - - // parallel_for( - // mesh.numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { - // auto vector = vector_affine(xj[cell_id]); - // for (size_t i = 0; i < vector.dimension(); ++i) { - // Vh[cell_id][i] = vector[i]; - // } - // }); - - // auto reconstructions = PolynomialReconstruction{descriptor}.build(Vh); - - // auto dpk_Vh = reconstructions[0]->get<DiscreteFunctionDPkVector<2, const double>>(); - - // { - // double max_mean_error = 0; - // for (CellId cell_id = 0; cell_id < mesh.numberOfCells(); ++cell_id) { - // auto vector = vector_affine(xj[cell_id]); - // for (size_t i = 0; i < vector.dimension(); ++i) { - // max_mean_error = std::max(max_mean_error, std::abs(dpk_Vh(cell_id, i)(xj[cell_id]) - vector[i])); - // } - // } - // REQUIRE(parallel::allReduceMax(max_mean_error) == Catch::Approx(0).margin(1E-14)); - // } - - // { - // double max_x_slope_error = 0; - // const R4 slope{+1.7, +2.1, -0.6, -2.3}; - // for (CellId cell_id = 0; cell_id < mesh.numberOfCells(); ++cell_id) { - // for (size_t i = 0; i < slope.dimension(); ++i) { - // const double reconstructed_slope = (1 / 0.2) * (dpk_Vh(cell_id, i)(R2{0.1, 0} + xj[cell_id]) - - // dpk_Vh(cell_id, i)(xj[cell_id] - R2{0.1, 0})); - - // max_x_slope_error = std::max(max_x_slope_error, std::abs(reconstructed_slope - slope[i])); - // } - // } - // REQUIRE(parallel::allReduceMax(max_x_slope_error) == Catch::Approx(0).margin(1E-13)); - // } - - // { - // double max_y_slope_error = 0; - // const R4 slope{+1.2, -2.2, -2.1, +1.3}; - // for (CellId cell_id = 0; cell_id < mesh.numberOfCells(); ++cell_id) { - // for (size_t i = 0; i < slope.dimension(); ++i) { - // const double reconstructed_slope = (1 / 0.2) * (dpk_Vh(cell_id, i)(R2{0, 0.1} + xj[cell_id]) - - // dpk_Vh(cell_id, i)(xj[cell_id] - R2{0, 0.1})); - - // 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)); - // } - // } - // } - // } - } - - SECTION("3D") - { - using R3 = TinyVector<3>; - - SECTION("R data") - { - for (auto named_mesh : MeshDataBaseForTests::get().all3DMeshes()) { - SECTION(named_mesh.name()) - { - auto p_mesh = named_mesh.mesh()->get<Mesh<3>>(); - auto& mesh = *p_mesh; - auto f_exact = [](const R3& X) { - const double& x = X[0]; - const double& y = X[1]; - const double& z = X[2]; - - return 2.3 + 1.7 * x + 0.2 * y + 1.4 * z - 3.2 * x * x + 1.3 * x * y - 1.6 * x * z - 1.4 * y * y + - 2 * y * z - 1.8 * z * z; - }; - - auto xr = mesh.xr(); - auto xj = MeshDataManager::instance().getMeshData(mesh).xj(); - auto Vj = MeshDataManager::instance().getMeshData(mesh).Vj(); - - auto cell_type = mesh.connectivity().cellType(); - auto cell_to_node_matrix = mesh.connectivity().cellToNodeMatrix(); - - DiscreteFunctionP0<double> fh{p_mesh}; - - parallel_for( - mesh.numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { - auto cell_node_list = cell_to_node_matrix[cell_id]; - double value = 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]]}; - QuadratureFormula<3> qf = - QuadratureManager::instance().getTetrahedronFormula(GaussQuadratureDescriptor{2}); - for (size_t i_q = 0; i_q < qf.numberOfPoints(); ++i_q) { - const R3 x_hat = qf.point(i_q); - const R3 x = T(x_hat); - value += qf.weight(i_q) * f_exact(x) * T.jacobianDeterminant(); - } - 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]]}; - QuadratureFormula<3> qf = - QuadratureManager::instance().getPyramidFormula(GaussQuadratureDescriptor{3}); - for (size_t i_q = 0; i_q < qf.numberOfPoints(); ++i_q) { - const R3 x_hat = qf.point(i_q); - const R3 x = T(x_hat); - value += qf.weight(i_q) * f_exact(x) * T.jacobianDeterminant(x_hat); - } - 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]]}; - QuadratureFormula<3> qf = QuadratureManager::instance().getPrismFormula(GaussQuadratureDescriptor{3}); - for (size_t i_q = 0; i_q < qf.numberOfPoints(); ++i_q) { - const R3 x_hat = qf.point(i_q); - const R3 x = T(x_hat); - value += qf.weight(i_q) * f_exact(x) * T.jacobianDeterminant(x_hat); - } - 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]]}; - QuadratureFormula<3> qf = - QuadratureManager::instance().getCubeFormula(GaussLegendreQuadratureDescriptor{3}); - for (size_t i_q = 0; i_q < qf.numberOfPoints(); ++i_q) { - const R3 x_hat = qf.point(i_q); - const R3 x = T(x_hat); - value += qf.weight(i_q) * f_exact(x) * T.jacobianDeterminant(x_hat); - } - break; - } - default: { - throw UnexpectedError("invalid cell type"); - } - } - - fh[cell_id] = value / Vj[cell_id]; - }); - - auto reconstructions = PolynomialReconstruction{descriptor}.build(fh); - - auto dpk_fh = reconstructions[0]->get<DiscreteFunctionDPk<3, const double>>(); - - { - double L1_error = 0; - for (CellId cell_id = 0; cell_id < mesh.numberOfCells(); ++cell_id) { - const auto cell_node_list = cell_to_node_matrix[cell_id]; - const auto dpkj = dpk_fh[cell_id]; - - double error = 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]]}; - QuadratureFormula<3> qf = - QuadratureManager::instance().getTetrahedronFormula(GaussQuadratureDescriptor{2}); - for (size_t i_q = 0; i_q < qf.numberOfPoints(); ++i_q) { - const R3 x_hat = qf.point(i_q); - const R3 x = T(x_hat); - error += std::abs(qf.weight(i_q) * (f_exact(x) - dpkj(x)) * T.jacobianDeterminant()); - } - 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]]}; - QuadratureFormula<3> qf = - QuadratureManager::instance().getPyramidFormula(GaussQuadratureDescriptor{3}); - for (size_t i_q = 0; i_q < qf.numberOfPoints(); ++i_q) { - const R3 x_hat = qf.point(i_q); - const R3 x = T(x_hat); - error += std::abs(qf.weight(i_q) * (f_exact(x) - dpkj(x)) * T.jacobianDeterminant(x_hat)); - } - 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]]}; - QuadratureFormula<3> qf = QuadratureManager::instance().getPrismFormula(GaussQuadratureDescriptor{3}); - for (size_t i_q = 0; i_q < qf.numberOfPoints(); ++i_q) { - const R3 x_hat = qf.point(i_q); - const R3 x = T(x_hat); - error += std::abs(qf.weight(i_q) * (f_exact(x) - dpkj(x)) * T.jacobianDeterminant(x_hat)); - } - 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]]}; - QuadratureFormula<3> qf = - QuadratureManager::instance().getCubeFormula(GaussLegendreQuadratureDescriptor{3}); - for (size_t i_q = 0; i_q < qf.numberOfPoints(); ++i_q) { - const R3 x_hat = qf.point(i_q); - const R3 x = T(x_hat); - error += std::abs(qf.weight(i_q) * (f_exact(x) - dpkj(x)) * T.jacobianDeterminant(x_hat)); - } - break; - } - default: { - throw UnexpectedError("invalid cell type"); - } - } - - L1_error += error; - } - REQUIRE(parallel::allReduceMax(L1_error) == Catch::Approx(0).margin(1E-13)); - } + auto dpk_Ah = reconstructions[0]->get<DiscreteFunctionDPk<3, const R2x2>>(); } } } - - // SECTION("R^3 data") - // { - // for (auto named_mesh : MeshDataBaseForTests::get().all3DMeshes()) { - // SECTION(named_mesh.name()) - // { - // auto p_mesh = named_mesh.mesh()->get<Mesh<3>>(); - // auto& mesh = *p_mesh; - - // auto R3_affine = [](const R3& x) -> R3 { - // return R3{+2.3 + 1.7 * x[0] - 2.2 * x[1] + 1.8 * x[2], // - // +1.4 - 0.6 * x[0] + 1.3 * x[1] - 3.7 * x[2], // - // -0.2 + 3.1 * x[0] - 1.1 * x[1] + 1.9 * x[2]}; - // }; - // auto xj = MeshDataManager::instance().getMeshData(mesh).xj(); - - // DiscreteFunctionP0<R3> uh{p_mesh}; - - // parallel_for( - // mesh.numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { uh[cell_id] = R3_affine(xj[cell_id]); }); - - // auto reconstructions = PolynomialReconstruction{descriptor}.build(uh); - - // auto dpk_uh = reconstructions[0]->get<DiscreteFunctionDPk<3, const R3>>(); - - // { - // double max_mean_error = 0; - // for (CellId cell_id = 0; cell_id < mesh.numberOfCells(); ++cell_id) { - // max_mean_error = - // std::max(max_mean_error, l2Norm(dpk_uh[cell_id](xj[cell_id]) - R3_affine(xj[cell_id]))); - // } - // REQUIRE(parallel::allReduceMax(max_mean_error) == Catch::Approx(0).margin(1E-14)); - // } - - // { - // double max_x_slope_error = 0; - // for (CellId cell_id = 0; cell_id < mesh.numberOfCells(); ++cell_id) { - // const R3 reconstructed_slope = (1 / 0.2) * (dpk_uh[cell_id](R3{0.1, 0, 0} + xj[cell_id]) - - // dpk_uh[cell_id](xj[cell_id] - R3{0.1, 0, 0})); - - // 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-12)); - // } - - // { - // double max_y_slope_error = 0; - // for (CellId cell_id = 0; cell_id < mesh.numberOfCells(); ++cell_id) { - // const R3 reconstructed_slope = (1 / 0.2) * (dpk_uh[cell_id](R3{0, 0.1, 0} + xj[cell_id]) - - // dpk_uh[cell_id](xj[cell_id] - R3{0, 0.1, 0})); - - // 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-12)); - // } - - // { - // double max_z_slope_error = 0; - // for (CellId cell_id = 0; cell_id < mesh.numberOfCells(); ++cell_id) { - // const R3 reconstructed_slope = (1 / 0.2) * (dpk_uh[cell_id](R3{0, 0, 0.1} + xj[cell_id]) - - // dpk_uh[cell_id](xj[cell_id] - R3{0, 0, 0.1})); - - // 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-12)); - // } - // } - // } - // } - - // SECTION("R^2x2 data") - // { - // using R2x2 = TinyMatrix<2, 2>; - - // for (auto named_mesh : MeshDataBaseForTests::get().all3DMeshes()) { - // SECTION(named_mesh.name()) - // { - // auto p_mesh = named_mesh.mesh()->get<Mesh<3>>(); - // auto& mesh = *p_mesh; - - // auto R2x2_affine = [](const R3& x) -> R2x2 { - // return R2x2{+2.3 + 1.7 * x[0] + 1.2 * x[1] - 1.3 * x[2], -1.7 + 2.1 * x[0] - 2.2 * x[1] - 2.4 * x[2], - // // - // +2.4 - 2.3 * x[0] + 1.3 * x[1] + 1.4 * x[2], -0.2 + 3.1 * x[0] + 0.8 * x[1] - 1.8 * - // x[2]}; - // }; - // auto xj = MeshDataManager::instance().getMeshData(mesh).xj(); - - // DiscreteFunctionP0<R2x2> Ah{p_mesh}; - - // parallel_for( - // mesh.numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { Ah[cell_id] = R2x2_affine(xj[cell_id]); }); - - // descriptor.setRowWeighting(false); - // auto reconstructions = PolynomialReconstruction{descriptor}.build(Ah); - - // auto dpk_Ah = reconstructions[0]->get<DiscreteFunctionDPk<3, const R2x2>>(); - - // { - // double max_mean_error = 0; - // for (CellId cell_id = 0; cell_id < mesh.numberOfCells(); ++cell_id) { - // max_mean_error = - // std::max(max_mean_error, frobeniusNorm(dpk_Ah[cell_id](xj[cell_id]) - R2x2_affine(xj[cell_id]))); - // } - // REQUIRE(parallel::allReduceMax(max_mean_error) == Catch::Approx(0).margin(1E-14)); - // } - - // { - // double max_x_slope_error = 0; - // for (CellId cell_id = 0; cell_id < mesh.numberOfCells(); ++cell_id) { - // const R2x2 reconstructed_slope = (1 / 0.2) * (dpk_Ah[cell_id](R3{0.1, 0, 0} + xj[cell_id]) - - // dpk_Ah[cell_id](xj[cell_id] - R3{0.1, 0, 0})); - - // max_x_slope_error = std::max(max_x_slope_error, frobeniusNorm(reconstructed_slope - R2x2{+1.7, 2.1, - // // - // -2.3, - // +3.1})); - // } - // REQUIRE(parallel::allReduceMax(max_x_slope_error) == Catch::Approx(0).margin(1E-13)); - // } - - // { - // double max_y_slope_error = 0; - // for (CellId cell_id = 0; cell_id < mesh.numberOfCells(); ++cell_id) { - // const R2x2 reconstructed_slope = (1 / 0.2) * (dpk_Ah[cell_id](R3{0, 0.1, 0} + xj[cell_id]) - - // dpk_Ah[cell_id](xj[cell_id] - R3{0, 0.1, 0})); - - // max_y_slope_error = - // 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-12)); - // } - - // { - // double max_z_slope_error = 0; - // for (CellId cell_id = 0; cell_id < mesh.numberOfCells(); ++cell_id) { - // const R2x2 reconstructed_slope = (1 / 0.2) * (dpk_Ah[cell_id](R3{0, 0, 0.1} + xj[cell_id]) - - // dpk_Ah[cell_id](xj[cell_id] - R3{0, 0, 0.1})); - - // max_z_slope_error = - // 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-12)); - // } - // } - // } - // } - - // SECTION("vector data") - // { - // using R4 = TinyVector<4>; - - // for (auto named_mesh : MeshDataBaseForTests::get().all3DMeshes()) { - // SECTION(named_mesh.name()) - // { - // auto p_mesh = named_mesh.mesh()->get<Mesh<3>>(); - // auto& mesh = *p_mesh; - - // auto vector_affine = [](const R3& x) -> R4 { - // return R4{+2.3 + 1.7 * x[0] + 1.2 * x[1] - 1.3 * x[2], -1.7 + 2.1 * x[0] - 2.2 * x[1] - 2.4 * x[2], - // // - // +2.4 - 2.3 * x[0] + 1.3 * x[1] + 1.4 * x[2], -0.2 + 3.1 * x[0] + 0.8 * x[1] - 1.8 * x[2]}; - // }; - // auto xj = MeshDataManager::instance().getMeshData(mesh).xj(); - - // DiscreteFunctionP0Vector<double> Vh{p_mesh, 4}; - - // parallel_for( - // mesh.numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { - // auto vector = vector_affine(xj[cell_id]); - // for (size_t i = 0; i < vector.dimension(); ++i) { - // Vh[cell_id][i] = vector[i]; - // } - // }); - - // descriptor.setPreconditioning(false); - // auto reconstructions = PolynomialReconstruction{descriptor}.build(Vh); - - // auto dpk_Vh = reconstructions[0]->get<DiscreteFunctionDPkVector<3, const double>>(); - - // { - // double max_mean_error = 0; - // for (CellId cell_id = 0; cell_id < mesh.numberOfCells(); ++cell_id) { - // auto vector = vector_affine(xj[cell_id]); - // for (size_t i = 0; i < vector.dimension(); ++i) { - // max_mean_error = std::max(max_mean_error, std::abs(dpk_Vh(cell_id, i)(xj[cell_id]) - vector[i])); - // } - // } - // REQUIRE(parallel::allReduceMax(max_mean_error) == Catch::Approx(0).margin(1E-14)); - // } - - // { - // double max_x_slope_error = 0; - // const R4 slope{+1.7, 2.1, -2.3, +3.1}; - // for (CellId cell_id = 0; cell_id < mesh.numberOfCells(); ++cell_id) { - // for (size_t i = 0; i < slope.dimension(); ++i) { - // const double reconstructed_slope = (1 / 0.2) * (dpk_Vh(cell_id, i)(R3{0.1, 0, 0} + xj[cell_id]) - - // dpk_Vh(cell_id, i)(xj[cell_id] - R3{0.1, 0, 0})); - - // max_x_slope_error = std::max(max_x_slope_error, std::abs(reconstructed_slope - slope[i])); - // } - // } - // REQUIRE(parallel::allReduceMax(max_x_slope_error) == Catch::Approx(0).margin(1E-13)); - // } - - // { - // double max_y_slope_error = 0; - // const R4 slope{+1.2, -2.2, 1.3, +0.8}; - // for (CellId cell_id = 0; cell_id < mesh.numberOfCells(); ++cell_id) { - // for (size_t i = 0; i < slope.dimension(); ++i) { - // const double reconstructed_slope = (1 / 0.2) * (dpk_Vh(cell_id, i)(R3{0, 0.1, 0} + xj[cell_id]) - - // dpk_Vh(cell_id, i)(xj[cell_id] - R3{0, 0.1, 0})); - - // 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-12)); - // } - - // { - // double max_z_slope_error = 0; - // const R4 slope{-1.3, -2.4, +1.4, -1.8}; - // for (CellId cell_id = 0; cell_id < mesh.numberOfCells(); ++cell_id) { - // for (size_t i = 0; i < slope.dimension(); ++i) { - // const double reconstructed_slope = (1 / 0.2) * (dpk_Vh(cell_id, i)(R3{0, 0, 0.1} + xj[cell_id]) - - // dpk_Vh(cell_id, i)(xj[cell_id] - R3{0, 0, 0.1})); - - // max_z_slope_error = std::max(max_z_slope_error, std::abs(reconstructed_slope - slope[i])); - // } - // } - // REQUIRE(parallel::allReduceMax(max_z_slope_error) == Catch::Approx(0).margin(1E-13)); - // } - // } - // } - // } } } }