diff --git a/kratos/mpi/tests/cpp_tests/utilities/test_parallel_fill_communicator.cpp b/kratos/mpi/tests/cpp_tests/utilities/test_parallel_fill_communicator.cpp index 6c175fdf58ae..a2bb0eeac331 100644 --- a/kratos/mpi/tests/cpp_tests/utilities/test_parallel_fill_communicator.cpp +++ b/kratos/mpi/tests/cpp_tests/utilities/test_parallel_fill_communicator.cpp @@ -131,4 +131,100 @@ KRATOS_TEST_CASE_IN_SUITE(ParallelFillCommunicatorExecuteTriangleMesh, KratosMPI } } +KRATOS_TEST_CASE_IN_SUITE(ParallelFillCommunicatorExecuteTriforceMesh, KratosMPICoreFastSuite) +{ + // The model part + Model current_model; + ModelPart& r_model_part = current_model.CreateModelPart("Main"); + + // The data communicator + const DataCommunicator& r_data_communicator = Testing::GetDefaultDataCommunicator(); + + // MPI data + const int rank = r_data_communicator.Rank(); + const int world_size = r_data_communicator.Size(); + + // Fill the model part + MPICppTestUtilities::GenerateDistributedTriforceMesh(r_model_part, r_data_communicator); + + // Check that the communicator is correctly filled + const auto& r_neighbours_indices = r_model_part.GetCommunicator().NeighbourIndices(); + if (world_size == 1) { + KRATOS_EXPECT_EQ(r_neighbours_indices.size(), 0); + KRATOS_EXPECT_EQ(r_model_part.GetCommunicator().LocalMesh().NumberOfNodes(), 6); + KRATOS_EXPECT_EQ(r_model_part.GetCommunicator().GhostMesh().NumberOfNodes(), 0); + KRATOS_EXPECT_EQ(r_model_part.GetCommunicator().InterfaceMesh().NumberOfNodes(), 0); + } else if (world_size == 2) { + KRATOS_EXPECT_EQ(r_neighbours_indices.size(), 1); + if (rank == 0) { + KRATOS_EXPECT_EQ(r_neighbours_indices[0], 1); + KRATOS_EXPECT_EQ(r_model_part.GetCommunicator().LocalMesh().NumberOfNodes(), 5); + KRATOS_EXPECT_EQ(r_model_part.GetCommunicator().GhostMesh().NumberOfNodes(), 1); + KRATOS_EXPECT_EQ(r_model_part.GetCommunicator().InterfaceMesh().NumberOfNodes(), 3); + } else if (rank == 1) { + KRATOS_EXPECT_EQ(r_neighbours_indices[0], 0); + KRATOS_EXPECT_EQ(r_model_part.GetCommunicator().LocalMesh().NumberOfNodes(), 1); + KRATOS_EXPECT_EQ(r_model_part.GetCommunicator().GhostMesh().NumberOfNodes(), 2); + KRATOS_EXPECT_EQ(r_model_part.GetCommunicator().InterfaceMesh().NumberOfNodes(), 3); + } + } else { + if (rank == 0) { + KRATOS_EXPECT_EQ(r_neighbours_indices[0], 1); + KRATOS_EXPECT_EQ(r_model_part.GetCommunicator().LocalMesh().NumberOfNodes(), 5); + KRATOS_EXPECT_EQ(r_model_part.GetCommunicator().GhostMesh().NumberOfNodes(), 1); + KRATOS_EXPECT_EQ(r_model_part.GetCommunicator().InterfaceMesh().NumberOfNodes(), 3); + } else if (rank == 1) { + KRATOS_EXPECT_EQ(r_neighbours_indices[0], 0); + KRATOS_EXPECT_EQ(r_model_part.GetCommunicator().LocalMesh().NumberOfNodes(), 1); + KRATOS_EXPECT_EQ(r_model_part.GetCommunicator().GhostMesh().NumberOfNodes(), 2); + KRATOS_EXPECT_EQ(r_model_part.GetCommunicator().InterfaceMesh().NumberOfNodes(), 3); + } else { // The rest of the ranks + KRATOS_EXPECT_EQ(r_model_part.GetCommunicator().LocalMesh().NumberOfNodes(), 0); + KRATOS_EXPECT_EQ(r_model_part.GetCommunicator().GhostMesh().NumberOfNodes(), 0); + KRATOS_EXPECT_EQ(r_model_part.GetCommunicator().InterfaceMesh().NumberOfNodes(), 0); + } + } + + // Check the submodelpart + ModelPart& r_sub_model_part = r_model_part.GetSubModelPart("SkinModelPart"); + + // Check that the communicator is correctly filled + const auto& r_sub_neighbours_indices = r_sub_model_part.GetCommunicator().NeighbourIndices(); + if (world_size == 1) { + KRATOS_EXPECT_EQ(r_sub_neighbours_indices.size(), 0); + KRATOS_EXPECT_EQ(r_sub_model_part.GetCommunicator().LocalMesh().NumberOfNodes(), 6); + KRATOS_EXPECT_EQ(r_sub_model_part.GetCommunicator().GhostMesh().NumberOfNodes(), 0); + KRATOS_EXPECT_EQ(r_sub_model_part.GetCommunicator().InterfaceMesh().NumberOfNodes(), 0); + } else if (world_size == 2) { + KRATOS_EXPECT_EQ(r_sub_neighbours_indices.size(), 1); + if (rank == 0) { + KRATOS_EXPECT_EQ(r_sub_neighbours_indices[0], 1); + KRATOS_EXPECT_EQ(r_sub_model_part.GetCommunicator().LocalMesh().NumberOfNodes(), 5); + KRATOS_EXPECT_EQ(r_sub_model_part.GetCommunicator().GhostMesh().NumberOfNodes(), 1); + KRATOS_EXPECT_EQ(r_sub_model_part.GetCommunicator().InterfaceMesh().NumberOfNodes(), 3); + } else if (rank == 1) { + KRATOS_EXPECT_EQ(r_sub_neighbours_indices[0], 0); + KRATOS_EXPECT_EQ(r_sub_model_part.GetCommunicator().LocalMesh().NumberOfNodes(), 1); + KRATOS_EXPECT_EQ(r_sub_model_part.GetCommunicator().GhostMesh().NumberOfNodes(), 2); + KRATOS_EXPECT_EQ(r_sub_model_part.GetCommunicator().InterfaceMesh().NumberOfNodes(), 3); + } + } else { + if (rank == 0) { + KRATOS_EXPECT_EQ(r_sub_neighbours_indices[0], 1); + KRATOS_EXPECT_EQ(r_sub_model_part.GetCommunicator().LocalMesh().NumberOfNodes(), 5); + KRATOS_EXPECT_EQ(r_sub_model_part.GetCommunicator().GhostMesh().NumberOfNodes(), 1); + KRATOS_EXPECT_EQ(r_sub_model_part.GetCommunicator().InterfaceMesh().NumberOfNodes(), 3); + } else if (rank == 1) { + KRATOS_EXPECT_EQ(r_sub_neighbours_indices[0], 0); + KRATOS_EXPECT_EQ(r_sub_model_part.GetCommunicator().LocalMesh().NumberOfNodes(), 1); + KRATOS_EXPECT_EQ(r_sub_model_part.GetCommunicator().GhostMesh().NumberOfNodes(), 2); + KRATOS_EXPECT_EQ(r_sub_model_part.GetCommunicator().InterfaceMesh().NumberOfNodes(), 3); + } else { // The rest of the ranks + KRATOS_EXPECT_EQ(r_sub_model_part.GetCommunicator().LocalMesh().NumberOfNodes(), 0); + KRATOS_EXPECT_EQ(r_sub_model_part.GetCommunicator().GhostMesh().NumberOfNodes(), 0); + KRATOS_EXPECT_EQ(r_sub_model_part.GetCommunicator().InterfaceMesh().NumberOfNodes(), 0); + } + } +} + } // namespace Kratos::Testing \ No newline at end of file diff --git a/kratos/mpi/tests/test_utilities/mpi_cpp_test_utilities.cpp b/kratos/mpi/tests/test_utilities/mpi_cpp_test_utilities.cpp index f5369eac6e0c..95ba19414559 100644 --- a/kratos/mpi/tests/test_utilities/mpi_cpp_test_utilities.cpp +++ b/kratos/mpi/tests/test_utilities/mpi_cpp_test_utilities.cpp @@ -211,13 +211,13 @@ void MPICppTestUtilities::GenerateDistributedTriangleMesh( } auto pgeom1 = Kratos::make_shared>(PointerVector{std::vector({pnode1, pnode2, pnode5})}); - rModelPart.AddElement(Kratos::make_intrusive( 1, pgeom1, p_prop)); + rModelPart.AddElement(Kratos::make_intrusive( 1, pgeom1, p_prop)); auto pgeom2 = Kratos::make_shared>(PointerVector{std::vector({pnode2, pnode3, pnode5})}); - rModelPart.AddElement(Kratos::make_intrusive( 2, pgeom2, p_prop)); + rModelPart.AddElement(Kratos::make_intrusive( 2, pgeom2, p_prop)); auto pgeom3 = Kratos::make_shared>(PointerVector{std::vector({pnode3, pnode4, pnode5})}); - rModelPart.AddElement(Kratos::make_intrusive( 3, pgeom3, p_prop)); + rModelPart.AddElement(Kratos::make_intrusive( 3, pgeom3, p_prop)); auto pgeom4 = Kratos::make_shared>(PointerVector{std::vector({pnode4, pnode1, pnode5})}); - rModelPart.AddElement(Kratos::make_intrusive( 4, pgeom4, p_prop)); + rModelPart.AddElement(Kratos::make_intrusive( 4, pgeom4, p_prop)); } else { // if (world_size == 1) { // TODO: Do more than one partition if (rank == 0) { auto pnode1 = rModelPart.CreateNewNode(1, 0.0, 0.0, 0.0); @@ -233,11 +233,11 @@ void MPICppTestUtilities::GenerateDistributedTriangleMesh( pnode5->FastGetSolutionStepValue(PARTITION_INDEX) = 1; auto pgeom1 = Kratos::make_shared>(PointerVector{std::vector({pnode1, pnode2, pnode5})}); - rModelPart.AddElement(Kratos::make_intrusive( 1, pgeom1, p_prop)); + rModelPart.AddElement(Kratos::make_intrusive( 1, pgeom1, p_prop)); auto pgeom2 = Kratos::make_shared>(PointerVector{std::vector({pnode2, pnode3, pnode5})}); - rModelPart.AddElement(Kratos::make_intrusive( 2, pgeom2, p_prop)); - auto pgeom4 = Kratos::make_shared>(PointerVector{std::vector({pnode4, pnode1, pnode5})}); - rModelPart.AddElement(Kratos::make_intrusive( 4, pgeom4, p_prop)); + rModelPart.AddElement(Kratos::make_intrusive( 2, pgeom2, p_prop)); + auto pgeom4 = Kratos::make_shared>(PointerVector{std::vector({pnode4, pnode1, pnode5})}); + rModelPart.AddElement(Kratos::make_intrusive( 4, pgeom4, p_prop)); } else if (rank == 1) { auto pnode3 = rModelPart.CreateNewNode(3, 1.0, 1.0, 0.0); auto pnode4 = rModelPart.CreateNewNode(4, 0.0, 1.0, 0.0); @@ -250,7 +250,100 @@ void MPICppTestUtilities::GenerateDistributedTriangleMesh( pnode5->FastGetSolutionStepValue(PARTITION_INDEX) = 1; auto pgeom3 = Kratos::make_shared>(PointerVector{std::vector({pnode3, pnode4, pnode5})}); - rModelPart.AddElement(Kratos::make_intrusive( 3, pgeom3, p_prop)); + rModelPart.AddElement(Kratos::make_intrusive( 3, pgeom3, p_prop)); + } + } + + // Detect skin + Parameters skin_process_parameters = Parameters(R"( + { + "name_auxiliar_model_part" : "SkinModelPart", + "name_auxiliar_condition" : "Condition", + "list_model_parts_to_assign_conditions" : [], + "echo_level" : 0 + })"); + auto skin_process = SkinDetectionProcess<2>(rModelPart, skin_process_parameters); + skin_process.Execute(); + + // Compute communication plan and fill communicator meshes correctly + auto filler = ParallelFillCommunicator(rModelPart, rDataCommunicator); + filler.Execute(); +} + +/***********************************************************************************/ +/***********************************************************************************/ + +void MPICppTestUtilities::GenerateDistributedTriforceMesh( + ModelPart& rModelPart, + const DataCommunicator& rDataCommunicator + ) +{ + // Add variables + rModelPart.AddNodalSolutionStepVariable(PARTITION_INDEX); + + // Create properties + auto p_prop = rModelPart.CreateNewProperties(1, 0); + + // MPI data + const int rank = rDataCommunicator.Rank(); + const int world_size = rDataCommunicator.Size(); + + // Initially everything in one partition + if (world_size == 1) { + auto pnode1 = rModelPart.CreateNewNode(1, 0.0, 0.0, 0.0); + auto pnode2 = rModelPart.CreateNewNode(2, 0.5, 0.0, 0.0); + auto pnode3 = rModelPart.CreateNewNode(3, 1.0, 0.0, 0.0); + auto pnode4 = rModelPart.CreateNewNode(4, 0.25, 0.43301270189221932338, 0.0); + auto pnode5 = rModelPart.CreateNewNode(5, 0.75, 0.43301270189221932338, 0.0); + auto pnode6 = rModelPart.CreateNewNode(6, 0.50, 0.86602540378443864676, 0.0); + + /// Add PARTITION_INDEX + for (auto& r_node : rModelPart.Nodes()) { + r_node.FastGetSolutionStepValue(PARTITION_INDEX) = rank; + } + + auto pgeom1 = Kratos::make_shared>(PointerVector{std::vector({pnode1, pnode2, pnode4})}); + rModelPart.AddElement(Kratos::make_intrusive( 1, pgeom1, p_prop)); + auto pgeom2 = Kratos::make_shared>(PointerVector{std::vector({pnode2, pnode3, pnode5})}); + rModelPart.AddElement(Kratos::make_intrusive( 2, pgeom2, p_prop)); + auto pgeom3 = Kratos::make_shared>(PointerVector{std::vector({pnode2, pnode5, pnode4})}); + rModelPart.AddElement(Kratos::make_intrusive( 3, pgeom3, p_prop)); + auto pgeom4 = Kratos::make_shared>(PointerVector{std::vector({pnode4, pnode5, pnode6})}); + rModelPart.AddElement(Kratos::make_intrusive( 4, pgeom4, p_prop)); + } else { // if (world_size == 1) { // TODO: Do more than one partition + if (rank == 0) { + auto pnode1 = rModelPart.CreateNewNode(1, 0.0, 0.0, 0.0); + auto pnode2 = rModelPart.CreateNewNode(2, 0.5, 0.0, 0.0); + auto pnode3 = rModelPart.CreateNewNode(3, 1.0, 0.0, 0.0); + auto pnode4 = rModelPart.CreateNewNode(4, 0.25, 0.43301270189221932338, 0.0); + auto pnode5 = rModelPart.CreateNewNode(5, 0.75, 0.43301270189221932338, 0.0); + auto pnode6 = rModelPart.CreateNewNode(6, 0.50, 0.86602540378443864676, 0.0); + + /// Add PARTITION_INDEX + for (auto& r_node : rModelPart.Nodes()) { + r_node.FastGetSolutionStepValue(PARTITION_INDEX) = 0; + } + pnode2->FastGetSolutionStepValue(PARTITION_INDEX) = 1; + + auto pgeom1 = Kratos::make_shared>(PointerVector{std::vector({pnode1, pnode2, pnode4})}); + rModelPart.AddElement(Kratos::make_intrusive( 1, pgeom1, p_prop)); + auto pgeom2 = Kratos::make_shared>(PointerVector{std::vector({pnode2, pnode3, pnode5})}); + rModelPart.AddElement(Kratos::make_intrusive( 2, pgeom2, p_prop)); + auto pgeom4 = Kratos::make_shared>(PointerVector{std::vector({pnode4, pnode5, pnode6})}); + rModelPart.AddElement(Kratos::make_intrusive( 4, pgeom4, p_prop)); + } else if (rank == 1) { + auto pnode2 = rModelPart.CreateNewNode(2, 0.5, 0.0, 0.0); + auto pnode4 = rModelPart.CreateNewNode(4, 0.25, 0.43301270189221932338, 0.0); + auto pnode5 = rModelPart.CreateNewNode(5, 0.75, 0.43301270189221932338, 0.0); + + /// Add PARTITION_INDEX + for (auto& r_node : rModelPart.Nodes()) { + r_node.FastGetSolutionStepValue(PARTITION_INDEX) = 0; + } + pnode2->FastGetSolutionStepValue(PARTITION_INDEX) = 1; + + auto pgeom3 = Kratos::make_shared>(PointerVector{std::vector({pnode2, pnode5, pnode4})}); + rModelPart.AddElement(Kratos::make_intrusive( 3, pgeom3, p_prop)); } } diff --git a/kratos/mpi/tests/test_utilities/mpi_cpp_test_utilities.h b/kratos/mpi/tests/test_utilities/mpi_cpp_test_utilities.h index ecb217eded2d..fba628628ba4 100644 --- a/kratos/mpi/tests/test_utilities/mpi_cpp_test_utilities.h +++ b/kratos/mpi/tests/test_utilities/mpi_cpp_test_utilities.h @@ -47,6 +47,18 @@ static void GenerateDistributedTriangleMesh( const DataCommunicator& rDataCommunicator ); +/** +* @brief It generates a Triforce mesh +* @details ▲ +* ▲ ▲ +* @param rModelPart The model part to be filled +* @param rDataCommunicator The data communicator +*/ +static void GenerateDistributedTriforceMesh( + ModelPart& rModelPart, + const DataCommunicator& rDataCommunicator + ); + /** * @brief Synchronizes local pointers to global pointers of the given ModelPart using the provided * @details DataCommunicator and returns a shared pointer to a GlobalPointerCommunicator.