From fcdd7194cf0621e7e900ec8f801a7b483a1e1f03 Mon Sep 17 00:00:00 2001 From: Lena Ploetzke Date: Tue, 24 Mar 2026 15:22:13 +0100 Subject: [PATCH 1/5] rename --- .../{t8_gtest_adapt.cxx => t8_gtest_adapt_partition_balance.cxx} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename test/mesh_handle/{t8_gtest_adapt.cxx => t8_gtest_adapt_partition_balance.cxx} (100%) diff --git a/test/mesh_handle/t8_gtest_adapt.cxx b/test/mesh_handle/t8_gtest_adapt_partition_balance.cxx similarity index 100% rename from test/mesh_handle/t8_gtest_adapt.cxx rename to test/mesh_handle/t8_gtest_adapt_partition_balance.cxx From 83af2cb1ba1fcf2fa1705b1de4645ae31cf8989a Mon Sep 17 00:00:00 2001 From: Lena Ploetzke Date: Tue, 24 Mar 2026 15:30:49 +0100 Subject: [PATCH 2/5] add partition and balance --- mesh_handle/mesh.hxx | 57 +++++++++++++++++++ test/CMakeLists.txt | 16 +++--- .../t8_gtest_adapt_partition_balance.cxx | 35 +++++++++--- 3 files changed, 93 insertions(+), 15 deletions(-) diff --git a/mesh_handle/mesh.hxx b/mesh_handle/mesh.hxx index cfca082b8b..6fc25b834d 100644 --- a/mesh_handle/mesh.hxx +++ b/mesh_handle/mesh.hxx @@ -30,6 +30,8 @@ #include "element.hxx" #include "competence_pack.hxx" #include "internal/adapt.hxx" +#include "t8_forest/t8_forest_balance.h" +#include "t8_forest/t8_forest_types.h" #include #include #include @@ -164,6 +166,17 @@ class mesh { return m_forest; } + /** Check if the local elements of the mesh are balanced. + * The mesh is said to be balanced if each element has face neighbors of level + * at most +1 or -1 of the element's level. + * \return true if the local elements are balanced, false otherwise. + */ + bool + is_balanced () + { + return t8_forest_is_balanced (m_forest); + } + // --- Methods to access elements. --- /** * Returns a constant iterator to the first (local) mesh element. @@ -278,6 +291,50 @@ class mesh { t8_forest_set_adapt (m_uncommitted_forest.value (), m_forest, detail::mesh_adapt_callback_wrapper, recursive); } + /** If this function is called, the mesh will be partitioned on committing. + * The partitioning is done according to the SFC and each rank is assigned + * the same (maybe +1) number of elements. + * \note The partition is carried out only when \ref commit is called. + * \note This setting can be combined with \ref set_adapt and \ref set_balance. The order in which + * these operations are executed is always 1) Adapt 2) Partition 3) Balance. + * \param [in] set_for_coarsening If true, the partitions are choose such that coarsening + * an element once is a process local operation. Default is false. + */ + void + set_partition (bool set_for_coarsening = false) + { + if (!m_uncommitted_forest.has_value ()) { + t8_forest_t new_forest; + t8_forest_init (&new_forest); + m_uncommitted_forest = new_forest; + } + t8_forest_set_partition (m_uncommitted_forest.value (), m_forest, set_for_coarsening); + } + + /** If this function is called, the mesh will be balanced on committing. + * The mesh is said to be balanced if each element has face neighbors of level + * at most +1 or -1 of the element's level. + * \note The balance is carried out only when \ref commit is called. + * \param [in] no_repartition Balance constructs several intermediate steps that + * are refined from each other. In order to maintain a balanced load, a repartitioning is performed in each + * round and the resulting mesh is load-balanced per default. + * Set \a no_repartition to true if this behaviour is not desired. + * If \a no_repartition is false (default), an additional call of \ref set_partition is not necessary. + * \note This setting can be combined with \ref set_adapt and \ref set_partition. The order in which + * these operations are executed is always 1) Adapt 2) Partition 3) Balance. + */ + void + set_balance (bool no_repartition = false) + { + if (!m_uncommitted_forest.has_value ()) { + t8_forest_t new_forest; + t8_forest_init (&new_forest); + m_uncommitted_forest = new_forest; + } + // Disable repartitioning and let the user call set_partition if desired. + t8_forest_set_balance (m_uncommitted_forest.value (), m_forest, no_repartition); + } + /** Enable or disable the creation of a layer of ghost elements. * \param [in] do_ghost If true a ghost layer will be created. * \param [in] ghost_type Controls which neighbors count as ghost elements, diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 55753ff638..6aecf7f639 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -220,11 +220,11 @@ endif() add_t8_cpp_test( NAME t8_gtest_vector_split_serial SOURCES t8_helper_functions/t8_gtest_vector_split.cxx ) if( T8CODE_BUILD_MESH_HANDLE ) - add_t8_cpp_test( NAME t8_gtest_mesh_handle_parallel SOURCES mesh_handle/t8_gtest_mesh_handle.cxx ) - add_t8_cpp_test( NAME t8_gtest_compare_handle_to_forest_serial SOURCES mesh_handle/t8_gtest_compare_handle_to_forest.cxx ) - add_t8_cpp_test( NAME t8_gtest_handle_ghost_parallel SOURCES mesh_handle/t8_gtest_ghost.cxx ) - add_t8_cpp_test( NAME t8_gtest_custom_competence_serial SOURCES mesh_handle/t8_gtest_custom_competence.cxx ) - add_t8_cpp_test( NAME t8_gtest_cache_competence_serial SOURCES mesh_handle/t8_gtest_cache_competence.cxx ) - add_t8_cpp_test( NAME t8_gtest_handle_data_parallel SOURCES mesh_handle/t8_gtest_handle_data.cxx ) - add_t8_cpp_test( NAME t8_gtest_handle_adapt_serial SOURCES mesh_handle/t8_gtest_adapt.cxx ) -endif() + add_t8_cpp_test( NAME t8_gtest_mesh_handle_parallel SOURCES mesh_handle/t8_gtest_mesh_handle.cxx ) + add_t8_cpp_test( NAME t8_gtest_compare_handle_to_forest_serial SOURCES mesh_handle/t8_gtest_compare_handle_to_forest.cxx ) + add_t8_cpp_test( NAME t8_gtest_handle_ghost_parallel SOURCES mesh_handle/t8_gtest_ghost.cxx ) + add_t8_cpp_test( NAME t8_gtest_custom_competence_serial SOURCES mesh_handle/t8_gtest_custom_competence.cxx ) + add_t8_cpp_test( NAME t8_gtest_cache_competence_serial SOURCES mesh_handle/t8_gtest_cache_competence.cxx ) + add_t8_cpp_test( NAME t8_gtest_handle_data_parallel SOURCES mesh_handle/t8_gtest_handle_data.cxx ) + add_t8_cpp_test( NAME t8_gtest_adapt_partition_balance_parallel SOURCES mesh_handle/t8_gtest_adapt_partition_balance.cxx ) +endif() \ No newline at end of file diff --git a/test/mesh_handle/t8_gtest_adapt_partition_balance.cxx b/test/mesh_handle/t8_gtest_adapt_partition_balance.cxx index e7e16f80d8..4a04b9f12e 100644 --- a/test/mesh_handle/t8_gtest_adapt_partition_balance.cxx +++ b/test/mesh_handle/t8_gtest_adapt_partition_balance.cxx @@ -21,11 +21,13 @@ along with t8code; if not, write to the Free Software Foundation, Inc., */ /** - * \file t8_gtest_adapt.cxx - * Tests for the adapt routines of mesh handles. - * This tests uses the callback and user data of tutorial step 3 as example. + * \file t8_gtest_adapt_partition_balance.cxx + * Tests for the adapt, partition and balance routines of mesh handles. + * For the adapt routine, we use the callback and user data of tutorial step 3 as example. * The adaptation criterion is to look at the midpoint coordinates of the current element and if * they are inside a sphere around a given midpoint we refine, if they are outside, we coarsen. + * The test compares the results of the mesh handle to a forest adapted with the same criterion and balanced and partitioned similarly. + * Therefore, the check is based on the assumption that the forest functionality works as intended and is tested elsewhere. */ #include #include @@ -97,8 +99,9 @@ forest_adapt_callback_example (t8_forest_t forest, t8_forest_t forest_from, t8_l return 0; } -/** Test the adapt routine of a mesh handle. - * We compare the result to a classically adapted forest with similar callback. +/** Test the adapt partition and balance routine of a mesh handle. + * The test compares the results of the mesh handle to a forest adapted with the same criterion and balanced and partitioned similarly. + * Therefore, the check is based on the assumption that the forest functionality works as intended and is tested elsewhere. */ TEST (t8_gtest_handle_adapt, compare_adapt_with_forest) { @@ -123,11 +126,29 @@ TEST (t8_gtest_handle_adapt, compare_adapt_with_forest) mesh_class::mesh_adapt_callback_wrapper (adapt_callback_test, user_data), false); mesh_handle.commit (); // Adapt forest classically. - forest = t8_forest_new_adapt (forest, forest_adapt_callback_example, 0, 1, &user_data); + forest = t8_forest_new_adapt (forest, forest_adapt_callback_example, 0, 0, &user_data); // Compare results. EXPECT_TRUE (t8_forest_is_equal (mesh_handle.get_forest (), forest)); + // Adapt the mesh handle again and apply partition and balance. + mesh_handle.set_balance (); + mesh_handle.set_partition (); + mesh_handle.set_adapt ( + mesh_class::mesh_adapt_callback_wrapper (adapt_callback_test, user_data), false); + mesh_handle.commit (); + EXPECT_TRUE (mesh_handle.is_balanced ()); + + // Compare the results again to an appropriate forest. + t8_forest_t forest_compare; + t8_forest_init (&forest_compare); + t8_forest_set_user_data (forest_compare, &user_data); + t8_forest_set_adapt (forest_compare, forest, forest_adapt_callback_example, false); + t8_forest_set_partition (forest_compare, NULL, false); + t8_forest_set_balance (forest_compare, NULL, false); + t8_forest_commit (forest_compare); + EXPECT_TRUE (t8_forest_is_equal (mesh_handle.get_forest (), forest_compare)); + // Clean up. - t8_forest_unref (&forest); + t8_forest_unref (&forest_compare); } From 40243db6ba89904fc06cecab692c77dcbcbfd642 Mon Sep 17 00:00:00 2001 From: lenaploetzke <70579874+lenaploetzke@users.noreply.github.com> Date: Thu, 26 Mar 2026 11:31:33 +0100 Subject: [PATCH 3/5] Apply suggestions from code review Co-authored-by: spenke91 --- mesh_handle/mesh.hxx | 5 ++--- test/mesh_handle/t8_gtest_adapt_partition_balance.cxx | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/mesh_handle/mesh.hxx b/mesh_handle/mesh.hxx index 6fc25b834d..ab06da357d 100644 --- a/mesh_handle/mesh.hxx +++ b/mesh_handle/mesh.hxx @@ -167,7 +167,7 @@ class mesh { } /** Check if the local elements of the mesh are balanced. - * The mesh is said to be balanced if each element has face neighbors of level + * The mesh is said to be balanced if the level difference between face neighbors is at most 1. * at most +1 or -1 of the element's level. * \return true if the local elements are balanced, false otherwise. */ @@ -312,8 +312,7 @@ class mesh { } /** If this function is called, the mesh will be balanced on committing. - * The mesh is said to be balanced if each element has face neighbors of level - * at most +1 or -1 of the element's level. + * The mesh is said to be balanced if the element level between face neighbors differs by at most 1. * \note The balance is carried out only when \ref commit is called. * \param [in] no_repartition Balance constructs several intermediate steps that * are refined from each other. In order to maintain a balanced load, a repartitioning is performed in each diff --git a/test/mesh_handle/t8_gtest_adapt_partition_balance.cxx b/test/mesh_handle/t8_gtest_adapt_partition_balance.cxx index 4a04b9f12e..4ddeed776e 100644 --- a/test/mesh_handle/t8_gtest_adapt_partition_balance.cxx +++ b/test/mesh_handle/t8_gtest_adapt_partition_balance.cxx @@ -99,7 +99,7 @@ forest_adapt_callback_example (t8_forest_t forest, t8_forest_t forest_from, t8_l return 0; } -/** Test the adapt partition and balance routine of a mesh handle. +/** Test the adapt, partition and balance routines of a mesh handle. * The test compares the results of the mesh handle to a forest adapted with the same criterion and balanced and partitioned similarly. * Therefore, the check is based on the assumption that the forest functionality works as intended and is tested elsewhere. */ From a1eca4c35293fd698609f50bc663238b24519b3e Mon Sep 17 00:00:00 2001 From: Lena Ploetzke Date: Thu, 26 Mar 2026 11:43:59 +0100 Subject: [PATCH 4/5] review and README --- mesh_handle/mesh.hxx | 1 - test/mesh_handle/README.md | 1 + test/mesh_handle/t8_gtest_adapt_partition_balance.cxx | 9 +++------ 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/mesh_handle/mesh.hxx b/mesh_handle/mesh.hxx index 6fc25b834d..5e3d23c017 100644 --- a/mesh_handle/mesh.hxx +++ b/mesh_handle/mesh.hxx @@ -331,7 +331,6 @@ class mesh { t8_forest_init (&new_forest); m_uncommitted_forest = new_forest; } - // Disable repartitioning and let the user call set_partition if desired. t8_forest_set_balance (m_uncommitted_forest.value (), m_forest, no_repartition); } diff --git a/test/mesh_handle/README.md b/test/mesh_handle/README.md index fa33158829..e76d668e68 100644 --- a/test/mesh_handle/README.md +++ b/test/mesh_handle/README.md @@ -11,3 +11,4 @@ Therefore, the tests are structured as follows: - [t8_gtest_cache_competence.cxx](t8_gtest_cache_competence.cxx) tests that *all predefined caching competences* work as intended. - [t8_gtest_ghost.cxx](t8_gtest_ghost.cxx) checks ghosts and the neighbor algorithm. Furthermore tests if *all functions work also for ghost cells* if applicable. - [t8_gtest_handle_data.cxx](t8_gtest_handle_data.cxx) tests that user and element data functionality works as intended. +- [t8_gtest_adapt_partition_balance.cxx](t8_gtest_adapt_partition_balance.cxx) implements tests for the adapt, partition and balance routines of mesh handle. diff --git a/test/mesh_handle/t8_gtest_adapt_partition_balance.cxx b/test/mesh_handle/t8_gtest_adapt_partition_balance.cxx index 4a04b9f12e..c9f4aa2785 100644 --- a/test/mesh_handle/t8_gtest_adapt_partition_balance.cxx +++ b/test/mesh_handle/t8_gtest_adapt_partition_balance.cxx @@ -22,12 +22,7 @@ along with t8code; if not, write to the Free Software Foundation, Inc., /** * \file t8_gtest_adapt_partition_balance.cxx - * Tests for the adapt, partition and balance routines of mesh handles. - * For the adapt routine, we use the callback and user data of tutorial step 3 as example. - * The adaptation criterion is to look at the midpoint coordinates of the current element and if - * they are inside a sphere around a given midpoint we refine, if they are outside, we coarsen. - * The test compares the results of the mesh handle to a forest adapted with the same criterion and balanced and partitioned similarly. - * Therefore, the check is based on the assumption that the forest functionality works as intended and is tested elsewhere. + * Tests for the adapt, partition and balance routines of mesh handle. */ #include #include @@ -50,6 +45,8 @@ struct dummy_user_data }; /** Callback function for the mesh handle to decide for refining or coarsening of (a family of) elements. + * The adaptation criterion is to look at the midpoint coordinates of the current element and if + * they are inside a sphere around a given midpoint we refine, if they are outside, we coarsen. * The function header fits the definition of \ref TMesh::adapt_callback_type_with_userdata. * \tparam TMeshClass The mesh handle class. * \param [in] mesh The mesh that should be adapted. From a602e258cf432d9995b84452a2aac1c60de2a29f Mon Sep 17 00:00:00 2001 From: Lena Ploetzke Date: Wed, 1 Apr 2026 11:52:18 +0200 Subject: [PATCH 5/5] resolve error --- mesh_handle/mesh.hxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mesh_handle/mesh.hxx b/mesh_handle/mesh.hxx index 5a5c62a0e1..c052e2acc6 100644 --- a/mesh_handle/mesh.hxx +++ b/mesh_handle/mesh.hxx @@ -372,7 +372,7 @@ class mesh { t8_forest_ref (m_forest); t8_forest_commit (m_uncommitted_forest.value ()); // Check if we adapted and unregister the adapt context if so. - if (detail::adapt_registry::get (m_uncommitted_forest.value ()) != nullptr) { + if (detail::adapt_registry::get (m_forest) != nullptr) { detail::adapt_registry::unregister_context (m_forest); if (!std::is_void::value) { t8_global_infof (