diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 3b0e5e84185f8bc0c248b8ebca9c6f1713fd1126..a907e37e43b49f318d45cdb5e02183341ea56015 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -177,6 +177,7 @@ add_executable (mpi_unit_tests test_ItemValueUtils.cpp test_MeshFaceBoundary.cpp test_MeshFlatFaceBoundary.cpp + test_MeshNodeBoundary.cpp test_Messenger.cpp test_OFStream.cpp test_Partitioner.cpp diff --git a/tests/test_MeshNodeBoundary.cpp b/tests/test_MeshNodeBoundary.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ba36ad53f6860523e42f65c33143eb66bd8047bf --- /dev/null +++ b/tests/test_MeshNodeBoundary.cpp @@ -0,0 +1,353 @@ +#include <catch2/catch_test_macros.hpp> +#include <catch2/matchers/catch_matchers_all.hpp> + +#include <MeshDataBaseForTests.hpp> + +#include <mesh/Connectivity.hpp> +#include <mesh/Mesh.hpp> +#include <mesh/MeshNodeBoundary.hpp> +#include <mesh/NamedBoundaryDescriptor.hpp> +#include <mesh/NumberedBoundaryDescriptor.hpp> + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("MeshNodeBoundary", "[mesh]") +{ + auto is_same = [](const auto& a, const auto& b) -> bool { + if (a.size() > 0 and b.size() > 0) { + return (a.size() == b.size()) and (&(a[0]) == &(b[0])); + } else { + return (a.size() == b.size()); + } + }; + + auto get_node_list_from_tag = [](const size_t tag, const auto& connectivity) -> Array<const NodeId> { + for (size_t i = 0; i < connectivity.template numberOfRefItemList<ItemType::node>(); ++i) { + const auto& ref_node_list = connectivity.template refItemList<ItemType::node>(i); + const RefId ref_id = ref_node_list.refId(); + if (ref_id.tagNumber() == tag) { + return ref_node_list.list(); + } + } + return {}; + }; + + auto get_node_list_from_name = [](const std::string& name, const auto& connectivity) -> Array<const NodeId> { + for (size_t i = 0; i < connectivity.template numberOfRefItemList<ItemType::node>(); ++i) { + const auto& ref_node_list = connectivity.template refItemList<ItemType::node>(i); + const RefId ref_id = ref_node_list.refId(); + if (ref_id.tagName() == name) { + return ref_node_list.list(); + } + } + return {}; + }; + + SECTION("1D") + { + static constexpr size_t Dimension = 1; + + using ConnectivityType = Connectivity<Dimension>; + using MeshType = Mesh<ConnectivityType>; + + SECTION("cartesian 1d") + { + std::shared_ptr p_mesh = MeshDataBaseForTests::get().cartesian1DMesh(); + const MeshType& mesh = *p_mesh; + + const ConnectivityType& connectivity = mesh.connectivity(); + + { + const std::set<size_t> tag_set = {0, 1}; + + for (auto tag : tag_set) { + NumberedBoundaryDescriptor numbered_boundary_descriptor(tag); + const auto& node_boundary = getMeshNodeBoundary(mesh, numbered_boundary_descriptor); + + auto node_list = get_node_list_from_tag(tag, connectivity); + REQUIRE(is_same(node_boundary.nodeList(), node_list)); + } + } + + { + const std::set<std::string> name_set = {"XMIN", "XMAX"}; + + for (auto name : name_set) { + NamedBoundaryDescriptor named_boundary_descriptor(name); + const auto& node_boundary = getMeshNodeBoundary(mesh, named_boundary_descriptor); + + auto node_list = get_node_list_from_name(name, connectivity); + + REQUIRE(is_same(node_boundary.nodeList(), node_list)); + } + } + } + + SECTION("unordered 1d") + { + std::shared_ptr p_mesh = MeshDataBaseForTests::get().unordered1DMesh(); + const MeshType& mesh = *p_mesh; + + const ConnectivityType& connectivity = mesh.connectivity(); + + { + const std::set<size_t> tag_set = {1, 2}; + + for (auto tag : tag_set) { + NumberedBoundaryDescriptor numbered_boundary_descriptor(tag); + const auto& node_boundary = getMeshNodeBoundary(mesh, numbered_boundary_descriptor); + + auto node_list = get_node_list_from_tag(tag, connectivity); + REQUIRE(is_same(node_boundary.nodeList(), node_list)); + } + } + + { + const std::set<std::string> name_set = {"XMIN", "XMAX"}; + + for (auto name : name_set) { + NamedBoundaryDescriptor named_boundary_descriptor(name); + const auto& node_boundary = getMeshNodeBoundary(mesh, named_boundary_descriptor); + + auto node_list = get_node_list_from_name(name, connectivity); + REQUIRE(is_same(node_boundary.nodeList(), node_list)); + } + } + } + } + + SECTION("2D") + { + static constexpr size_t Dimension = 2; + + using ConnectivityType = Connectivity<Dimension>; + using MeshType = Mesh<ConnectivityType>; + + 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, 10, 11, 12, 13}; + + for (auto tag : tag_set) { + NumberedBoundaryDescriptor numbered_boundary_descriptor(tag); + const auto& node_boundary = getMeshNodeBoundary(mesh, numbered_boundary_descriptor); + + auto node_list = get_node_list_from_tag(tag, connectivity); + REQUIRE(is_same(node_boundary.nodeList(), node_list)); + } + } + + { + const std::set<std::string> name_set = {"XMIN", "XMAX", "YMIN", "YMAX", + "XMINYMIN", "XMINYMAX", "XMAXYMIN", "XMAXYMAX"}; + + for (auto name : name_set) { + NamedBoundaryDescriptor numbered_boundary_descriptor(name); + const auto& node_boundary = getMeshNodeBoundary(mesh, numbered_boundary_descriptor); + + auto node_list = get_node_list_from_name(name, connectivity); + REQUIRE(is_same(node_boundary.nodeList(), node_list)); + } + } + } + + 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, 8, 9, 10, 11}; + + for (auto tag : tag_set) { + NumberedBoundaryDescriptor numbered_boundary_descriptor(tag); + const auto& node_boundary = getMeshNodeBoundary(mesh, numbered_boundary_descriptor); + + auto node_list = get_node_list_from_tag(tag, connectivity); + REQUIRE(is_same(node_boundary.nodeList(), node_list)); + } + } + + { + const std::set<std::string> name_set = {"XMIN", "YMIN", "XMAX", "YMIN", + "XMINYMIN", "XMINYMAX", "XMAXYMIN", "XMAXYMAX"}; + + for (auto name : name_set) { + NamedBoundaryDescriptor numbered_boundary_descriptor(name); + const auto& node_boundary = getMeshNodeBoundary(mesh, numbered_boundary_descriptor); + + auto node_list = get_node_list_from_name(name, connectivity); + REQUIRE(is_same(node_boundary.nodeList(), node_list)); + } + } + } + } + + SECTION("3D") + { + static constexpr size_t Dimension = 3; + + using ConnectivityType = Connectivity<Dimension>; + using MeshType = Mesh<ConnectivityType>; + + 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 = {0, 1, 2, 3, 4, 5, 10, 11, 12, 13, 14, 15, 16, + 17, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}; + + for (auto tag : tag_set) { + NumberedBoundaryDescriptor numbered_boundary_descriptor(tag); + const auto& node_boundary = getMeshNodeBoundary(mesh, numbered_boundary_descriptor); + + auto node_list = get_node_list_from_tag(tag, connectivity); + REQUIRE(is_same(node_boundary.nodeList(), node_list)); + } + } + + { + const std::set<std::string> name_set = {// faces + "XMIN", "XMAX", "YMIN", "YMAX", "ZMIN", "ZMAX", + // ridges + "XMINYMIN", "XMINYMAX", "XMINZMIN", "XMINZMAX", "XMAXYMIN", "XMAXYMAX", + "XMAXZMIN", "XMAXZMAX", "YMINZMIN", "YMINZMAX", "YMAXZMIN", "YMAXZMAX", + // corners + "XMINYMINZMIN", "XMINYMINZMAX", "XMINYMAXZMIN", "XMINYMAXZMAX", + "XMAXYMINZMIN", "XMAXYMINZMAX", "XMAXYMAXZMIN", "XMAXYMAXZMAX"}; + + for (auto name : name_set) { + NamedBoundaryDescriptor numbered_boundary_descriptor(name); + const auto& node_boundary = getMeshNodeBoundary(mesh, numbered_boundary_descriptor); + + auto node_list = get_node_list_from_name(name, connectivity); + REQUIRE(is_same(node_boundary.nodeList(), node_list)); + } + } + } + + 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 = {22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 47, 51}; + + for (auto tag : tag_set) { + NumberedBoundaryDescriptor numbered_boundary_descriptor(tag); + const auto& node_boundary = getMeshNodeBoundary(mesh, numbered_boundary_descriptor); + + auto node_list = get_node_list_from_tag(tag, connectivity); + REQUIRE(is_same(node_boundary.nodeList(), node_list)); + } + } + + { + const std::set<std::string> name_set = {// faces + "XMIN", "XMAX", "YMIN", "YMAX", "ZMIN", "ZMAX", + // ridges + "XMINYMIN", "XMINYMAX", "XMINZMIN", "XMINZMAX", "XMAXYMIN", "XMAXYMAX", + "XMAXZMIN", "XMAXZMAX", "YMINZMIN", "YMINZMAX", "YMAXZMIN", "YMAXZMAX", + // corners + "XMINYMINZMIN", "XMINYMINZMAX", "XMINYMAXZMIN", "XMINYMAXZMAX", + "XMAXYMINZMIN", "XMAXYMINZMAX", "XMAXYMAXZMIN", "XMAXYMAXZMAX"}; + + for (auto name : name_set) { + NamedBoundaryDescriptor numbered_boundary_descriptor(name); + const auto& node_boundary = getMeshNodeBoundary(mesh, numbered_boundary_descriptor); + + auto node_list = get_node_list_from_name(name, connectivity); + REQUIRE(is_same(node_boundary.nodeList(), node_list)); + } + } + } + } + + SECTION("errors") + { + SECTION("cannot find boundary") + { + static constexpr size_t Dimension = 3; + + using ConnectivityType = Connectivity<Dimension>; + using MeshType = Mesh<ConnectivityType>; + + std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid3DMesh(); + const MeshType& mesh = *p_mesh; + + NamedBoundaryDescriptor named_boundary_descriptor("invalid_boundary"); + + REQUIRE_THROWS_WITH(getMeshNodeBoundary(mesh, named_boundary_descriptor), + "error: cannot find node list with name \"invalid_boundary\""); + } + + SECTION("surface is inside") + { + SECTION("1D") + { + static constexpr size_t Dimension = 1; + + using ConnectivityType = Connectivity<Dimension>; + using MeshType = Mesh<ConnectivityType>; + + std::shared_ptr p_mesh = MeshDataBaseForTests::get().unordered1DMesh(); + const MeshType& mesh = *p_mesh; + + NamedBoundaryDescriptor named_boundary_descriptor("INTERFACE"); + + REQUIRE_THROWS_WITH(getMeshNodeBoundary(mesh, named_boundary_descriptor), + "error: invalid boundary \"INTERFACE\": inner nodes cannot be used to define mesh " + "boundaries"); + } + + SECTION("2D") + { + static constexpr size_t Dimension = 2; + + using ConnectivityType = Connectivity<Dimension>; + using MeshType = Mesh<ConnectivityType>; + + std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid2DMesh(); + const MeshType& mesh = *p_mesh; + + NamedBoundaryDescriptor named_boundary_descriptor("INTERFACE"); + + REQUIRE_THROWS_WITH(getMeshNodeBoundary(mesh, named_boundary_descriptor), + "error: invalid boundary \"INTERFACE\": inner edges cannot be used to define mesh " + "boundaries"); + } + + SECTION("3D") + { + static constexpr size_t Dimension = 3; + + using ConnectivityType = Connectivity<Dimension>; + using MeshType = Mesh<ConnectivityType>; + + std::shared_ptr p_mesh = MeshDataBaseForTests::get().hybrid3DMesh(); + const MeshType& mesh = *p_mesh; + + NamedBoundaryDescriptor named_boundary_descriptor("INTERFACE1"); + + REQUIRE_THROWS_WITH(getMeshNodeBoundary(mesh, named_boundary_descriptor), + "error: invalid boundary \"INTERFACE1\": inner faces cannot be used to define mesh " + "boundaries"); + } + } + } +}