#include <catch2/catch_test_macros.hpp> #include <catch2/matchers/catch_matchers_all.hpp> #include <MeshDataBaseForTests.hpp> #include <algebra/TinyMatrix.hpp> #include <mesh/Connectivity.hpp> #include <mesh/Mesh.hpp> #include <mesh/MeshLineEdgeBoundary.hpp> #include <mesh/NamedBoundaryDescriptor.hpp> #include <mesh/NumberedBoundaryDescriptor.hpp> // clazy:excludeall=non-pod-global-static TEST_CASE("MeshLineEdgeBoundary", "[mesh]") { auto is_same = [](const auto& a, const auto& b) -> bool { if (a.size() > 0 and b.size() > 0) { return (a[0] == b[0]); } else { return (a.size() == b.size()); } }; auto get_edge_list_from_tag = [](const size_t tag, const auto& connectivity) -> Array<const EdgeId> { for (size_t i = 0; i < connectivity.template numberOfRefItemList<ItemType::edge>(); ++i) { const auto& ref_edge_list = connectivity.template refItemList<ItemType::edge>(i); const RefId ref_id = ref_edge_list.refId(); if (ref_id.tagNumber() == tag) { return ref_edge_list.list(); } } return {}; }; auto get_edge_list_from_name = [](const std::string& name, const auto& connectivity) -> Array<const EdgeId> { for (size_t i = 0; i < connectivity.template numberOfRefItemList<ItemType::edge>(); ++i) { const auto& ref_edge_list = connectivity.template refItemList<ItemType::edge>(i); const RefId ref_id = ref_edge_list.refId(); if (ref_id.tagName() == name) { return ref_edge_list.list(); } } return {}; }; SECTION("aligned axis") { SECTION("2D") { static constexpr size_t Dimension = 2; using ConnectivityType = Connectivity<Dimension>; using MeshType = Mesh<ConnectivityType>; using R2 = TinyVector<2>; SECTION("cartesian 2d") { std::shared_ptr p_mesh = MeshDataBaseForTests::get().cartesian2DMesh(); const MeshType& mesh = *p_mesh; const ConnectivityType& connectivity = mesh.connectivity(); { const std::set<size_t> tag_set = {0, 1, 2, 3}; for (auto tag : tag_set) { NumberedBoundaryDescriptor numbered_boundary_descriptor(tag); const auto& edge_boundary = getMeshLineEdgeBoundary(mesh, numbered_boundary_descriptor); auto edge_list = get_edge_list_from_tag(tag, connectivity); REQUIRE(is_same(edge_boundary.edgeList(), edge_list)); R2 direction = zero; switch (tag) { case 0: { direction = R2{0, 1}; break; } case 1: { direction = R2{0, 1}; break; } case 2: { direction = R2{1, 0}; break; } case 3: { direction = R2{1, 0}; break; } default: { FAIL("unexpected tag number"); } } REQUIRE(l2Norm(edge_boundary.direction() - direction) == Catch::Approx(0).margin(1E-13)); } { REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NumberedBoundaryDescriptor(10)), "error: cannot find edge list with name \"10\""); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NumberedBoundaryDescriptor(11)), "error: cannot find edge list with name \"11\""); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NumberedBoundaryDescriptor(12)), "error: cannot find edge list with name \"12\""); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NumberedBoundaryDescriptor(13)), "error: cannot find edge list with name \"13\""); } } { const std::set<std::string> name_set = {"XMIN", "XMAX", "YMIN", "YMAX"}; for (auto name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& edge_boundary = getMeshLineEdgeBoundary(mesh, named_boundary_descriptor); auto edge_list = get_edge_list_from_name(name, connectivity); REQUIRE(is_same(edge_boundary.edgeList(), edge_list)); R2 direction = zero; if (name == "XMIN") { direction = R2{0, 1}; } else if (name == "XMAX") { direction = R2{0, 1}; } else if (name == "YMIN") { direction = R2{1, 0}; } else if (name == "YMAX") { direction = R2{1, 0}; } else { FAIL("unexpected name: " + name); } REQUIRE(l2Norm(edge_boundary.direction() - direction) == Catch::Approx(0).margin(1E-13)); } { REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NamedBoundaryDescriptor("XMINYMIN")), "error: cannot find edge list with name \"XMINYMIN\""); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NamedBoundaryDescriptor("XMINYMAX")), "error: cannot find edge list with name \"XMINYMAX\""); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NamedBoundaryDescriptor("XMAXYMIN")), "error: cannot find edge list with name \"XMAXYMIN\""); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NamedBoundaryDescriptor("XMAXYMAX")), "error: cannot find edge list with name \"XMAXYMAX\""); } } } SECTION("hybrid 2d") { std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid2DMesh(); const MeshType& mesh = *p_mesh; const ConnectivityType& connectivity = mesh.connectivity(); { const std::set<size_t> tag_set = {1, 2, 3, 4}; for (auto tag : tag_set) { NumberedBoundaryDescriptor numbered_boundary_descriptor(tag); const auto& edge_boundary = getMeshLineEdgeBoundary(mesh, numbered_boundary_descriptor); auto edge_list = get_edge_list_from_tag(tag, connectivity); REQUIRE(is_same(edge_boundary.edgeList(), edge_list)); R2 direction = zero; switch (tag) { case 1: { direction = R2{0, 1}; break; } case 2: { direction = R2{0, 1}; break; } case 3: { direction = R2{1, 0}; break; } case 4: { direction = R2{1, 0}; break; } default: { FAIL("unexpected tag number"); } } REQUIRE(l2Norm(edge_boundary.direction() - direction) == Catch::Approx(0).margin(1E-13)); } { REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NumberedBoundaryDescriptor(8)), "error: cannot find edge list with name \"8\""); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NumberedBoundaryDescriptor(9)), "error: cannot find edge list with name \"9\""); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NumberedBoundaryDescriptor(10)), "error: cannot find edge list with name \"10\""); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NumberedBoundaryDescriptor(11)), "error: cannot find edge list with name \"11\""); } } { const std::set<std::string> name_set = {"XMIN", "XMAX", "YMIN", "YMAX"}; for (auto name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& edge_boundary = getMeshLineEdgeBoundary(mesh, named_boundary_descriptor); auto edge_list = get_edge_list_from_name(name, connectivity); R2 direction = zero; REQUIRE(is_same(edge_boundary.edgeList(), edge_list)); if (name == "XMIN") { direction = R2{0, 1}; } else if (name == "XMAX") { direction = R2{0, 1}; } else if (name == "YMIN") { direction = R2{1, 0}; } else if (name == "YMAX") { direction = R2{1, 0}; } else { FAIL("unexpected name: " + name); } REQUIRE(l2Norm(edge_boundary.direction() - direction) == Catch::Approx(0).margin(1E-13)); } { REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NamedBoundaryDescriptor("XMINYMIN")), "error: cannot find edge list with name \"XMINYMIN\""); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NamedBoundaryDescriptor("XMINYMAX")), "error: cannot find edge list with name \"XMINYMAX\""); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NamedBoundaryDescriptor("XMAXYMIN")), "error: cannot find edge list with name \"XMAXYMIN\""); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NamedBoundaryDescriptor("XMAXYMAX")), "error: cannot find edge list with name \"XMAXYMAX\""); } } } } SECTION("3D") { static constexpr size_t Dimension = 3; using ConnectivityType = Connectivity<Dimension>; using MeshType = Mesh<ConnectivityType>; using R3 = TinyVector<3>; SECTION("cartesian 3d") { std::shared_ptr p_mesh = MeshDataBaseForTests::get().cartesian3DMesh(); const MeshType& mesh = *p_mesh; const ConnectivityType& connectivity = mesh.connectivity(); { const std::set<size_t> tag_set = {20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}; for (auto tag : tag_set) { NumberedBoundaryDescriptor numbered_boundary_descriptor(tag); const auto& edge_boundary = getMeshLineEdgeBoundary(mesh, numbered_boundary_descriptor); auto edge_list = get_edge_list_from_tag(tag, connectivity); REQUIRE(is_same(edge_boundary.edgeList(), edge_list)); R3 direction = zero; switch (tag) { case 20: case 21: case 22: case 23: { direction = R3{0, 0, -1}; break; } case 24: case 25: case 26: case 27: { direction = R3{0, -1, 0}; break; } case 28: case 29: case 30: case 31: { direction = R3{1, 0, 0}; break; } default: { FAIL("unexpected tag number"); } } REQUIRE(l2Norm(edge_boundary.direction() - direction) == Catch::Approx(0).margin(1E-13)); } REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NumberedBoundaryDescriptor(0)), "error: invalid boundary \"XMIN(0)\": boundary is not a line!"); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NumberedBoundaryDescriptor(1)), "error: invalid boundary \"XMAX(1)\": boundary is not a line!"); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NumberedBoundaryDescriptor(2)), "error: invalid boundary \"YMIN(2)\": boundary is not a line!"); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NumberedBoundaryDescriptor(3)), "error: invalid boundary \"YMAX(3)\": boundary is not a line!"); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NumberedBoundaryDescriptor(4)), "error: invalid boundary \"ZMIN(4)\": boundary is not a line!"); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NumberedBoundaryDescriptor(5)), "error: invalid boundary \"ZMAX(5)\": boundary is not a line!"); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NumberedBoundaryDescriptor(10)), "error: cannot find edge list with name \"10\""); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NumberedBoundaryDescriptor(11)), "error: cannot find edge list with name \"11\""); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NumberedBoundaryDescriptor(12)), "error: cannot find edge list with name \"12\""); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NumberedBoundaryDescriptor(13)), "error: cannot find edge list with name \"13\""); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NumberedBoundaryDescriptor(14)), "error: cannot find edge list with name \"14\""); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NumberedBoundaryDescriptor(15)), "error: cannot find edge list with name \"15\""); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NumberedBoundaryDescriptor(16)), "error: cannot find edge list with name \"16\""); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NumberedBoundaryDescriptor(17)), "error: cannot find edge list with name \"17\""); } { const std::set<std::string> name_set = {"XMINYMIN", "XMINYMAX", "XMAXYMIN", "XMAXYMAX", "XMINZMIN", "XMINZMAX", "XMAXZMAX", "XMINZMAX", "YMINZMIN", "YMINZMAX", "YMAXZMAX", "YMAXZMIN"}; for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& edge_boundary = getMeshLineEdgeBoundary(mesh, named_boundary_descriptor); auto edge_list = get_edge_list_from_name(name, connectivity); REQUIRE(is_same(edge_boundary.edgeList(), edge_list)); R3 direction = zero; if ((name == "XMINYMIN") or (name == "XMINYMAX") or (name == "XMAXYMIN") or (name == "XMAXYMAX")) { direction = R3{0, 0, -1}; } else if ((name == "XMINZMIN") or (name == "XMINZMAX") or (name == "XMAXZMIN") or (name == "XMAXZMAX")) { direction = R3{0, -1, 0}; } else if ((name == "YMINZMIN") or (name == "YMINZMAX") or (name == "YMAXZMIN") or (name == "YMAXZMAX")) { direction = R3{1, 0, 0}; } else { FAIL("unexpected name: " + name); } REQUIRE(l2Norm(edge_boundary.direction() - direction) == Catch::Approx(0).margin(1E-13)); } { REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NamedBoundaryDescriptor("XMIN")), "error: invalid boundary \"XMIN(0)\": boundary is not a line!"); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NamedBoundaryDescriptor("XMAX")), "error: invalid boundary \"XMAX(1)\": boundary is not a line!"); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NamedBoundaryDescriptor("YMIN")), "error: invalid boundary \"YMIN(2)\": boundary is not a line!"); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NamedBoundaryDescriptor("YMAX")), "error: invalid boundary \"YMAX(3)\": boundary is not a line!"); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NamedBoundaryDescriptor("ZMIN")), "error: invalid boundary \"ZMIN(4)\": boundary is not a line!"); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NamedBoundaryDescriptor("ZMAX")), "error: invalid boundary \"ZMAX(5)\": boundary is not a line!"); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NamedBoundaryDescriptor("XMINYMINZMIN")), "error: cannot find edge list with name \"XMINYMINZMIN\""); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NamedBoundaryDescriptor("XMAXYMINZMIN")), "error: cannot find edge list with name \"XMAXYMINZMIN\""); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NamedBoundaryDescriptor("XMAXYMAXZMIN")), "error: cannot find edge list with name \"XMAXYMAXZMIN\""); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NamedBoundaryDescriptor("XMINYMAXZMIN")), "error: cannot find edge list with name \"XMINYMAXZMIN\""); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NamedBoundaryDescriptor("XMINYMINZMAX")), "error: cannot find edge list with name \"XMINYMINZMAX\""); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NamedBoundaryDescriptor("XMAXYMINZMAX")), "error: cannot find edge list with name \"XMAXYMINZMAX\""); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NamedBoundaryDescriptor("XMAXYMAXZMAX")), "error: cannot find edge list with name \"XMAXYMAXZMAX\""); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NamedBoundaryDescriptor("XMINYMAXZMAX")), "error: cannot find edge list with name \"XMINYMAXZMAX\""); } } } SECTION("hybrid 3d") { std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid3DMesh(); const MeshType& mesh = *p_mesh; const ConnectivityType& connectivity = mesh.connectivity(); { const std::set<size_t> tag_set = {28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39}; for (auto tag : tag_set) { NumberedBoundaryDescriptor numbered_boundary_descriptor(tag); const auto& edge_boundary = getMeshLineEdgeBoundary(mesh, numbered_boundary_descriptor); auto edge_list = get_edge_list_from_tag(tag, connectivity); REQUIRE(is_same(edge_boundary.edgeList(), edge_list)); R3 direction = zero; switch (tag) { case 30: case 31: case 34: case 35: { direction = R3{0, 0, -1}; break; } case 28: case 29: case 32: case 33: { direction = R3{0, -1, 0}; break; } case 36: case 37: case 38: case 39: { direction = R3{1, 0, 0}; break; } default: { FAIL("unexpected tag number"); } } REQUIRE(l2Norm(edge_boundary.direction() - direction) == Catch::Approx(0).margin(1E-13)); } { REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NumberedBoundaryDescriptor(22)), "error: invalid boundary \"XMIN(22)\": boundary is not a line!"); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NumberedBoundaryDescriptor(23)), "error: invalid boundary \"XMAX(23)\": boundary is not a line!"); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NumberedBoundaryDescriptor(24)), "error: invalid boundary \"ZMAX(24)\": boundary is not a line!"); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NumberedBoundaryDescriptor(25)), "error: invalid boundary \"ZMIN(25)\": boundary is not a line!"); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NumberedBoundaryDescriptor(26)), "error: invalid boundary \"YMAX(26)\": boundary is not a line!"); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NumberedBoundaryDescriptor(27)), "error: invalid boundary \"YMIN(27)\": boundary is not a line!"); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NumberedBoundaryDescriptor(40)), "error: cannot find edge list with name \"40\""); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NumberedBoundaryDescriptor(41)), "error: cannot find edge list with name \"41\""); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NumberedBoundaryDescriptor(42)), "error: cannot find edge list with name \"42\""); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NumberedBoundaryDescriptor(43)), "error: cannot find edge list with name \"43\""); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NumberedBoundaryDescriptor(44)), "error: cannot find edge list with name \"44\""); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NumberedBoundaryDescriptor(45)), "error: cannot find edge list with name \"45\""); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NumberedBoundaryDescriptor(47)), "error: cannot find edge list with name \"47\""); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NumberedBoundaryDescriptor(51)), "error: cannot find edge list with name \"51\""); } } { const std::set<std::string> name_set = {"XMINYMIN", "XMINYMAX", "XMAXYMIN", "XMAXYMAX", "XMINZMIN", "XMINZMAX", "XMAXZMAX", "XMINZMAX", "YMINZMIN", "YMINZMAX", "YMAXZMAX", "YMAXZMIN"}; for (auto name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& edge_boundary = getMeshLineEdgeBoundary(mesh, named_boundary_descriptor); auto edge_list = get_edge_list_from_name(name, connectivity); REQUIRE(is_same(edge_boundary.edgeList(), edge_list)); R3 direction = zero; if ((name == "XMINYMIN") or (name == "XMINYMAX") or (name == "XMAXYMIN") or (name == "XMAXYMAX")) { direction = R3{0, 0, -1}; } else if ((name == "XMINZMIN") or (name == "XMINZMAX") or (name == "XMAXZMIN") or (name == "XMAXZMAX")) { direction = R3{0, -1, 0}; } else if ((name == "YMINZMIN") or (name == "YMINZMAX") or (name == "YMAXZMIN") or (name == "YMAXZMAX")) { direction = R3{1, 0, 0}; } else { FAIL("unexpected name: " + name); } REQUIRE(l2Norm(edge_boundary.direction() - direction) == Catch::Approx(0).margin(1E-13)); } { REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NamedBoundaryDescriptor("XMIN")), "error: invalid boundary \"XMIN(22)\": boundary is not a line!"); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NamedBoundaryDescriptor("XMAX")), "error: invalid boundary \"XMAX(23)\": boundary is not a line!"); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NamedBoundaryDescriptor("YMIN")), "error: invalid boundary \"YMIN(27)\": boundary is not a line!"); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NamedBoundaryDescriptor("YMAX")), "error: invalid boundary \"YMAX(26)\": boundary is not a line!"); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NamedBoundaryDescriptor("ZMIN")), "error: invalid boundary \"ZMIN(25)\": boundary is not a line!"); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NamedBoundaryDescriptor("ZMAX")), "error: invalid boundary \"ZMAX(24)\": boundary is not a line!"); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NamedBoundaryDescriptor("XMINYMINZMIN")), "error: cannot find edge list with name \"XMINYMINZMIN\""); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NamedBoundaryDescriptor("XMAXYMINZMIN")), "error: cannot find edge list with name \"XMAXYMINZMIN\""); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NamedBoundaryDescriptor("XMAXYMAXZMIN")), "error: cannot find edge list with name \"XMAXYMAXZMIN\""); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NamedBoundaryDescriptor("XMINYMAXZMIN")), "error: cannot find edge list with name \"XMINYMAXZMIN\""); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NamedBoundaryDescriptor("XMINYMINZMAX")), "error: cannot find edge list with name \"XMINYMINZMAX\""); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NamedBoundaryDescriptor("XMAXYMINZMAX")), "error: cannot find edge list with name \"XMAXYMINZMAX\""); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NamedBoundaryDescriptor("XMAXYMAXZMAX")), "error: cannot find edge list with name \"XMAXYMAXZMAX\""); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NamedBoundaryDescriptor("XMINYMAXZMAX")), "error: cannot find edge list with name \"XMINYMAXZMAX\""); } } } } } SECTION("rotated axis") { SECTION("2D") { static constexpr size_t Dimension = 2; using ConnectivityType = Connectivity<Dimension>; using MeshType = Mesh<ConnectivityType>; using R2 = TinyVector<2>; const double theta = 0.3; const TinyMatrix<2> R{std::cos(theta), -std::sin(theta), // std::sin(theta), std::cos(theta)}; SECTION("cartesian 2d") { std::shared_ptr p_mesh = MeshDataBaseForTests::get().cartesian2DMesh(); const ConnectivityType& connectivity = p_mesh->connectivity(); auto xr = p_mesh->xr(); NodeValue<R2> rotated_xr{connectivity}; parallel_for( connectivity.numberOfNodes(), PUGS_LAMBDA(const NodeId node_id) { rotated_xr[node_id] = R * xr[node_id]; }); MeshType mesh{p_mesh->shared_connectivity(), rotated_xr}; { const std::set<size_t> tag_set = {0, 1, 2, 3}; for (auto tag : tag_set) { NumberedBoundaryDescriptor numbered_boundary_descriptor(tag); const auto& edge_boundary = getMeshLineEdgeBoundary(mesh, numbered_boundary_descriptor); auto edge_list = get_edge_list_from_tag(tag, connectivity); REQUIRE(is_same(edge_boundary.edgeList(), edge_list)); R2 direction = zero; switch (tag) { case 0: { direction = R * R2{0, -1}; break; } case 1: { direction = R * R2{0, -1}; break; } case 2: { direction = R * R2{1, 0}; break; } case 3: { direction = R * R2{1, 0}; break; } default: { FAIL("unexpected tag number"); } } REQUIRE(l2Norm(edge_boundary.direction() - direction) == Catch::Approx(0).margin(1E-13)); } } { const std::set<std::string> name_set = {"XMIN", "XMAX", "YMIN", "YMAX"}; for (auto name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& edge_boundary = getMeshLineEdgeBoundary(mesh, named_boundary_descriptor); auto edge_list = get_edge_list_from_name(name, connectivity); REQUIRE(is_same(edge_boundary.edgeList(), edge_list)); R2 direction = zero; if (name == "XMIN") { direction = R * R2{0, -1}; } else if (name == "XMAX") { direction = R * R2{0, -1}; } else if (name == "YMIN") { direction = R * R2{1, 0}; } else if (name == "YMAX") { direction = R * R2{1, 0}; } else { FAIL("unexpected name: " + name); } REQUIRE(l2Norm(edge_boundary.direction() - direction) == Catch::Approx(0).margin(1E-13)); } } } SECTION("hybrid 2d") { std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid2DMesh(); const ConnectivityType& connectivity = p_mesh->connectivity(); auto xr = p_mesh->xr(); NodeValue<R2> rotated_xr{connectivity}; parallel_for( connectivity.numberOfNodes(), PUGS_LAMBDA(const NodeId node_id) { rotated_xr[node_id] = R * xr[node_id]; }); MeshType mesh{p_mesh->shared_connectivity(), rotated_xr}; { const std::set<size_t> tag_set = {1, 2, 3, 4}; for (auto tag : tag_set) { NumberedBoundaryDescriptor numbered_boundary_descriptor(tag); const auto& edge_boundary = getMeshLineEdgeBoundary(mesh, numbered_boundary_descriptor); auto edge_list = get_edge_list_from_tag(tag, connectivity); REQUIRE(is_same(edge_boundary.edgeList(), edge_list)); R2 direction = zero; switch (tag) { case 1: { direction = R * R2{0, -1}; break; } case 2: { direction = R * R2{0, -1}; break; } case 3: { direction = R * R2{1, 0}; break; } case 4: { direction = R * R2{1, 0}; break; } default: { FAIL("unexpected tag number"); } } REQUIRE(l2Norm(edge_boundary.direction() - direction) == Catch::Approx(0).margin(1E-13)); } } { const std::set<std::string> name_set = {"XMIN", "XMAX", "YMIN", "YMAX"}; for (auto name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& edge_boundary = getMeshLineEdgeBoundary(mesh, named_boundary_descriptor); auto edge_list = get_edge_list_from_name(name, connectivity); R2 direction = zero; REQUIRE(is_same(edge_boundary.edgeList(), edge_list)); if (name == "XMIN") { direction = R * R2{0, -1}; } else if (name == "XMAX") { direction = R * R2{0, -1}; } else if (name == "YMIN") { direction = R * R2{1, 0}; } else if (name == "YMAX") { direction = R * R2{1, 0}; } else { FAIL("unexpected name: " + name); } REQUIRE(l2Norm(edge_boundary.direction() - direction) == Catch::Approx(0).margin(1E-13)); } } } } SECTION("3D") { static constexpr size_t Dimension = 3; using ConnectivityType = Connectivity<Dimension>; using MeshType = Mesh<ConnectivityType>; using R3 = TinyVector<3>; const double theta = 0.3; const double phi = 0.4; const TinyMatrix<3> R = TinyMatrix<3>{std::cos(theta), -std::sin(theta), 0, std::sin(theta), std::cos(theta), 0, 0, 0, 1} * TinyMatrix<3>{0, std::cos(phi), -std::sin(phi), 0, std::sin(phi), std::cos(phi), 1, 0, 0}; SECTION("cartesian 3d") { std::shared_ptr p_mesh = MeshDataBaseForTests::get().cartesian3DMesh(); const ConnectivityType& connectivity = p_mesh->connectivity(); auto xr = p_mesh->xr(); NodeValue<R3> rotated_xr{connectivity}; parallel_for( connectivity.numberOfNodes(), PUGS_LAMBDA(const NodeId node_id) { rotated_xr[node_id] = R * xr[node_id]; }); MeshType mesh{p_mesh->shared_connectivity(), rotated_xr}; { const std::set<size_t> tag_set = {20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}; for (auto tag : tag_set) { NumberedBoundaryDescriptor numbered_boundary_descriptor(tag); const auto& edge_boundary = getMeshLineEdgeBoundary(mesh, numbered_boundary_descriptor); auto edge_list = get_edge_list_from_tag(tag, connectivity); REQUIRE(is_same(edge_boundary.edgeList(), edge_list)); R3 direction = zero; switch (tag) { case 20: case 21: case 22: case 23: { direction = R * R3{0, 0, -1}; break; } case 24: case 25: case 26: case 27: { direction = R * R3{0, 1, 0}; break; } case 28: case 29: case 30: case 31: { direction = R * R3{-1, 0, 0}; break; } default: { FAIL("unexpected tag number"); } } REQUIRE(l2Norm(edge_boundary.direction() - direction) == Catch::Approx(0).margin(1E-13)); } } { const std::set<std::string> name_set = {"XMINYMIN", "XMINYMAX", "XMAXYMIN", "XMAXYMAX", "XMINZMIN", "XMINZMAX", "XMAXZMAX", "XMINZMAX", "YMINZMIN", "YMINZMAX", "YMAXZMAX", "YMAXZMIN"}; for (auto name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& edge_boundary = getMeshLineEdgeBoundary(mesh, named_boundary_descriptor); auto edge_list = get_edge_list_from_name(name, connectivity); REQUIRE(is_same(edge_boundary.edgeList(), edge_list)); R3 direction = zero; if ((name == "XMINYMIN") or (name == "XMINYMAX") or (name == "XMAXYMIN") or (name == "XMAXYMAX")) { direction = R * R3{0, 0, -1}; } else if ((name == "XMINZMIN") or (name == "XMINZMAX") or (name == "XMAXZMIN") or (name == "XMAXZMAX")) { direction = R * R3{0, 1, 0}; } else if ((name == "YMINZMIN") or (name == "YMINZMAX") or (name == "YMAXZMIN") or (name == "YMAXZMAX")) { direction = R * R3{-1, 0, 0}; } else { FAIL("unexpected name: " + name); } REQUIRE(l2Norm(edge_boundary.direction() - direction) == Catch::Approx(0).margin(1E-13)); } } } SECTION("hybrid 3d") { std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid3DMesh(); const ConnectivityType& connectivity = p_mesh->connectivity(); auto xr = p_mesh->xr(); NodeValue<R3> rotated_xr{connectivity}; parallel_for( connectivity.numberOfNodes(), PUGS_LAMBDA(const NodeId node_id) { rotated_xr[node_id] = R * xr[node_id]; }); MeshType mesh{p_mesh->shared_connectivity(), rotated_xr}; { const std::set<size_t> tag_set = {28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39}; for (auto tag : tag_set) { NumberedBoundaryDescriptor numbered_boundary_descriptor(tag); const auto& edge_boundary = getMeshLineEdgeBoundary(mesh, numbered_boundary_descriptor); auto edge_list = get_edge_list_from_tag(tag, connectivity); REQUIRE(is_same(edge_boundary.edgeList(), edge_list)); R3 direction = zero; switch (tag) { case 30: case 31: case 34: case 35: { direction = R * R3{0, 0, -1}; break; } case 28: case 29: case 32: case 33: { direction = R * R3{0, 1, 0}; break; } case 36: case 37: case 38: case 39: { direction = R * R3{-1, 0, 0}; break; } default: { FAIL("unexpected tag number"); } } REQUIRE(l2Norm(edge_boundary.direction() - direction) == Catch::Approx(0).margin(1E-13)); } } { const std::set<std::string> name_set = {"XMINYMIN", "XMINYMAX", "XMAXYMIN", "XMAXYMAX", "XMINZMIN", "XMINZMAX", "XMAXZMAX", "XMINZMAX", "YMINZMIN", "YMINZMAX", "YMAXZMAX", "YMAXZMIN"}; for (auto name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& edge_boundary = getMeshLineEdgeBoundary(mesh, named_boundary_descriptor); auto edge_list = get_edge_list_from_name(name, connectivity); REQUIRE(is_same(edge_boundary.edgeList(), edge_list)); R3 direction = zero; if ((name == "XMINYMIN") or (name == "XMINYMAX") or (name == "XMAXYMIN") or (name == "XMAXYMAX")) { direction = R * R3{0, 0, -1}; } else if ((name == "XMINZMIN") or (name == "XMINZMAX") or (name == "XMAXZMIN") or (name == "XMAXZMAX")) { direction = R * R3{0, 1, 0}; } else if ((name == "YMINZMIN") or (name == "YMINZMAX") or (name == "YMAXZMIN") or (name == "YMAXZMAX")) { direction = R * R3{-1, 0, 0}; } else { FAIL("unexpected name: " + name); } REQUIRE(l2Norm(edge_boundary.direction() - direction) == Catch::Approx(0).margin(1E-13)); } } } } } SECTION("curved mesh") { SECTION("2D") { static constexpr size_t Dimension = 2; using ConnectivityType = Connectivity<Dimension>; using MeshType = Mesh<ConnectivityType>; using R2 = TinyVector<2>; auto curve = [](const R2& X) -> R2 { return R2{X[0], (1 + X[0] * X[0]) * X[1]}; }; SECTION("hybrid 2d") { std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid2DMesh(); const ConnectivityType& connectivity = p_mesh->connectivity(); auto xr = p_mesh->xr(); NodeValue<TinyVector<2>> curved_xr{connectivity}; parallel_for( connectivity.numberOfNodes(), PUGS_LAMBDA(const NodeId node_id) { curved_xr[node_id] = curve(xr[node_id]); }); MeshType mesh{p_mesh->shared_connectivity(), curved_xr}; { const std::set<size_t> tag_set = {1, 2, 4}; for (auto tag : tag_set) { NumberedBoundaryDescriptor numbered_boundary_descriptor(tag); const auto& edge_boundary = getMeshLineEdgeBoundary(mesh, numbered_boundary_descriptor); auto edge_list = get_edge_list_from_tag(tag, connectivity); REQUIRE(is_same(edge_boundary.edgeList(), edge_list)); R2 direction = zero; switch (tag) { case 1: { direction = R2{0, 1}; break; } case 2: { direction = R2{0, 1}; break; } case 4: { direction = R2{1, 0}; break; } default: { FAIL("unexpected tag number"); } } REQUIRE(l2Norm(edge_boundary.direction() - direction) == Catch::Approx(0).margin(1E-13)); } { NumberedBoundaryDescriptor numbered_boundary_descriptor(3); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, numbered_boundary_descriptor), "error: invalid boundary \"YMAX(3)\": boundary is not a line!"); } } { const std::set<std::string> name_set = {"XMIN", "XMAX", "YMIN"}; for (auto name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& edge_boundary = getMeshLineEdgeBoundary(mesh, named_boundary_descriptor); auto edge_list = get_edge_list_from_name(name, connectivity); R2 direction = zero; REQUIRE(is_same(edge_boundary.edgeList(), edge_list)); if (name == "XMIN") { direction = R2{0, 1}; } else if (name == "XMAX") { direction = R2{0, 1}; } else if (name == "YMIN") { direction = R2{1, 0}; } else { FAIL("unexpected name: " + name); } REQUIRE(l2Norm(edge_boundary.direction() - direction) == Catch::Approx(0).margin(1E-13)); } { NamedBoundaryDescriptor named_boundary_descriptor("YMAX"); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, named_boundary_descriptor), "error: invalid boundary \"YMAX(3)\": boundary is not a line!"); } } } } SECTION("3D") { static constexpr size_t Dimension = 3; using ConnectivityType = Connectivity<Dimension>; using MeshType = Mesh<ConnectivityType>; using R3 = TinyVector<3>; SECTION("cartesian 3d") { std::shared_ptr p_mesh = MeshDataBaseForTests::get().cartesian3DMesh(); const ConnectivityType& connectivity = p_mesh->connectivity(); auto xr = p_mesh->xr(); auto curve = [](const R3& X) -> R3 { return R3{X[0], (1 + X[0] * X[0]) * (X[1] + 1), (1 - 0.2 * X[0] * X[0]) * X[2]}; }; NodeValue<R3> curved_xr{connectivity}; parallel_for( connectivity.numberOfNodes(), PUGS_LAMBDA(const NodeId node_id) { curved_xr[node_id] = curve(xr[node_id]); }); MeshType mesh{p_mesh->shared_connectivity(), curved_xr}; { const std::set<size_t> tag_set = {20, 21, 22, 23, 24, 25, 26, 27, 28}; for (auto tag : tag_set) { auto edge_list = get_edge_list_from_tag(tag, connectivity); NumberedBoundaryDescriptor numbered_boundary_descriptor(tag); const auto& edge_boundary = getMeshLineEdgeBoundary(mesh, numbered_boundary_descriptor); REQUIRE(is_same(edge_boundary.edgeList(), edge_list)); R3 direction = zero; switch (tag) { case 20: case 21: case 22: case 23: { direction = R3{0, 0, -1}; break; } case 24: case 25: case 26: case 27: { direction = R3{0, -1, 0}; break; } case 28: { direction = R3{1, 0, 0}; break; } default: { FAIL("unexpected tag number"); } } REQUIRE(l2Norm(edge_boundary.direction() - direction) == Catch::Approx(0).margin(1E-13)); } { REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NumberedBoundaryDescriptor(29)), "error: invalid boundary \"YMINZMAX(29)\": boundary is not a line!"); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NumberedBoundaryDescriptor(30)), "error: invalid boundary \"YMAXZMAX(30)\": boundary is not a line!"); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NumberedBoundaryDescriptor(31)), "error: invalid boundary \"YMAXZMIN(31)\": boundary is not a line!"); } } { const std::set<std::string> name_set = {"XMINYMIN", "XMINYMAX", "XMAXYMIN", "XMAXYMAX", "XMINZMIN", "XMINZMAX", "XMAXZMAX", "XMINZMAX", "YMINZMIN"}; for (auto name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& edge_boundary = getMeshLineEdgeBoundary(mesh, named_boundary_descriptor); auto edge_list = get_edge_list_from_name(name, connectivity); REQUIRE(is_same(edge_boundary.edgeList(), edge_list)); R3 direction = zero; if ((name == "XMINYMIN") or (name == "XMINYMAX") or (name == "XMAXYMIN") or (name == "XMAXYMAX")) { direction = R3{0, 0, -1}; } else if ((name == "XMINZMIN") or (name == "XMINZMAX") or (name == "XMAXZMIN") or (name == "XMAXZMAX")) { direction = R3{0, -1, 0}; } else if ((name == "YMINZMIN")) { direction = R3{1, 0, 0}; } else { FAIL("unexpected name: " + name); } REQUIRE(l2Norm(edge_boundary.direction() - direction) == Catch::Approx(0).margin(1E-13)); } { REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NamedBoundaryDescriptor("YMAXZMAX")), "error: invalid boundary \"YMAXZMAX(30)\": boundary is not a line!"); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NamedBoundaryDescriptor("YMINZMAX")), "error: invalid boundary \"YMINZMAX(29)\": boundary is not a line!"); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NamedBoundaryDescriptor("YMAXZMIN")), "error: invalid boundary \"YMAXZMIN(31)\": boundary is not a line!"); } } } SECTION("hybrid 3d") { std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid3DMesh(); const ConnectivityType& connectivity = p_mesh->connectivity(); auto xr = p_mesh->xr(); auto curve = [](const R3& X) -> R3 { return R3{X[0], (1 + X[0] * X[0]) * X[1], (1 - 0.2 * X[0] * X[0]) * X[2]}; }; NodeValue<R3> curved_xr{connectivity}; parallel_for( connectivity.numberOfNodes(), PUGS_LAMBDA(const NodeId node_id) { curved_xr[node_id] = curve(xr[node_id]); }); MeshType mesh{p_mesh->shared_connectivity(), curved_xr}; { const std::set<size_t> tag_set = {28, 29, 30, 31, 32, 33, 34, 35, 36}; for (auto tag : tag_set) { NumberedBoundaryDescriptor numbered_boundary_descriptor(tag); const auto& edge_boundary = getMeshLineEdgeBoundary(mesh, numbered_boundary_descriptor); auto edge_list = get_edge_list_from_tag(tag, connectivity); REQUIRE(is_same(edge_boundary.edgeList(), edge_list)); R3 direction = zero; switch (tag) { case 30: case 31: case 34: case 35: { direction = R3{0, 0, -1}; break; } case 28: case 29: case 32: case 33: { direction = R3{0, -1, 0}; break; } case 36: // case 37: // case 38: case 39: { direction = R3{1, 0, 0}; break; } default: { FAIL("unexpected tag number"); } } REQUIRE(l2Norm(edge_boundary.direction() - direction) == Catch::Approx(0).margin(1E-13)); } { REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NumberedBoundaryDescriptor(37)), "error: invalid boundary \"YMINZMAX(37)\": boundary is not a line!"); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NumberedBoundaryDescriptor(38)), "error: invalid boundary \"YMAXZMIN(38)\": boundary is not a line!"); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NumberedBoundaryDescriptor(39)), "error: invalid boundary \"YMAXZMAX(39)\": boundary is not a line!"); } } { const std::set<std::string> name_set = {"XMINYMIN", "XMINYMAX", "XMAXYMIN", "XMAXYMAX", "XMINZMIN", "XMINZMAX", "XMAXZMAX", "XMINZMAX", "YMINZMIN"}; for (auto name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& edge_boundary = getMeshLineEdgeBoundary(mesh, named_boundary_descriptor); auto edge_list = get_edge_list_from_name(name, connectivity); REQUIRE(is_same(edge_boundary.edgeList(), edge_list)); R3 direction = zero; if ((name == "XMINYMIN") or (name == "XMINYMAX") or (name == "XMAXYMIN") or (name == "XMAXYMAX")) { direction = R3{0, 0, -1}; } else if ((name == "XMINZMIN") or (name == "XMINZMAX") or (name == "XMAXZMIN") or (name == "XMAXZMAX")) { direction = R3{0, -1, 0}; } else if ((name == "YMINZMIN")) { direction = R3{1, 0, 0}; } else { FAIL("unexpected name: " + name); } REQUIRE(l2Norm(edge_boundary.direction() - direction) == Catch::Approx(0).margin(1E-13)); } { REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NamedBoundaryDescriptor("YMAXZMAX")), "error: invalid boundary \"YMAXZMAX(39)\": boundary is not a line!"); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NamedBoundaryDescriptor("YMINZMAX")), "error: invalid boundary \"YMINZMAX(37)\": boundary is not a line!"); REQUIRE_THROWS_WITH(getMeshLineEdgeBoundary(mesh, NamedBoundaryDescriptor("YMAXZMIN")), "error: invalid boundary \"YMAXZMIN(38)\": boundary is not a line!"); } } } } } }