From 07a692ac61324398c3c0b859307e855db8205a4b Mon Sep 17 00:00:00 2001 From: Lena Ploetzke Date: Wed, 21 Jan 2026 16:06:30 +0100 Subject: [PATCH 1/8] add partition and balance functionality --- mesh_handle/mesh.hxx | 51 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 46 insertions(+), 5 deletions(-) diff --git a/mesh_handle/mesh.hxx b/mesh_handle/mesh.hxx index 4f4cc879fc..ff1a1d65b5 100644 --- a/mesh_handle/mesh.hxx +++ b/mesh_handle/mesh.hxx @@ -277,12 +277,53 @@ 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. + * \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. + * \note The balanced mesh is not repartitioned per default to maintain a balanced load. + * Call \ref set_partition if you want to repartition the balanced mesh. + */ + void + set_balance () + { + 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 (tm_uncommitted_forest.value (), m_forest, true); + } + /** 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, - * currently only T8_GHOST_FACES is supported. This value - * is ignored if \a do_ghost = false. - */ + * \param [in] do_ghost If true a ghost layer will be created. + * \param [in] ghost_type Controls which neighbors count as ghost elements, + * currently only T8_GHOST_FACES is supported. This value + * is ignored if \a do_ghost = false. + */ void set_ghost (bool do_ghost = true, t8_ghost_type_t ghost_type = T8_GHOST_FACES) { From cb6a8e0323a0d274736ed11001a9c10f97bb063b Mon Sep 17 00:00:00 2001 From: Lena Ploetzke Date: Wed, 21 Jan 2026 16:55:48 +0100 Subject: [PATCH 2/8] begin test --- mesh_handle/mesh.hxx | 15 ++++++++++++++- test/mesh_handle/t8_gtest_adapt.cxx | 10 ++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/mesh_handle/mesh.hxx b/mesh_handle/mesh.hxx index ff1a1d65b5..f94087f5d9 100644 --- a/mesh_handle/mesh.hxx +++ b/mesh_handle/mesh.hxx @@ -30,6 +30,8 @@ #include "element.hxx" #include "competence_pack.hxx" #include "adapt.hxx" +#include "t8_forest/t8_forest_balance.h" +#include "t8_forest/t8_forest_types.h" #include #include #include @@ -162,6 +164,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. @@ -315,7 +328,7 @@ class mesh { m_uncommitted_forest = new_forest; } // Disable repartitioning and let the user call set_partition if desired. - t8_forest_set_balance (tm_uncommitted_forest.value (), m_forest, true); + t8_forest_set_balance (m_uncommitted_forest.value (), m_forest, true); } /** Enable or disable the creation of a layer of ghost elements. diff --git a/test/mesh_handle/t8_gtest_adapt.cxx b/test/mesh_handle/t8_gtest_adapt.cxx index 5739c790a1..3b909782e1 100644 --- a/test/mesh_handle/t8_gtest_adapt.cxx +++ b/test/mesh_handle/t8_gtest_adapt.cxx @@ -129,6 +129,16 @@ TEST (t8_gtest_handle_adapt, compare_adapt_with_forest) // Compare results. EXPECT_TRUE (t8_forest_is_equal (mesh_handle.get_forest (), forest)); + // Adapt the mesh handle again and check that it is unbalanced afterwards. + mesh_handle.set_adapt ( + mesh_class::mesh_adapt_callback_wrapper (adapt_callback_test, user_data), false); + mesh_handle.commit (); + EXPECT_FALSE (mesh_handle.is_balanced ()); + mesh_handle.set_balance (); + mesh_handle.set_partition (); + mesh_handle.commit (); + // TODO have a look at t8_gtest_forest_commit for a better structure + EXPECT_TRUE (mesh_handle.is_balanced ()); // Clean up. t8_forest_unref (&forest); } From d0990b29d20d27c84d3734928f4b280fdea7e2ec Mon Sep 17 00:00:00 2001 From: Lena Ploetzke Date: Thu, 22 Jan 2026 16:04:39 +0100 Subject: [PATCH 3/8] adapt test to check also partition and balance --- test/mesh_handle/t8_gtest_adapt.cxx | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/test/mesh_handle/t8_gtest_adapt.cxx b/test/mesh_handle/t8_gtest_adapt.cxx index 3b909782e1..218ff40589 100644 --- a/test/mesh_handle/t8_gtest_adapt.cxx +++ b/test/mesh_handle/t8_gtest_adapt.cxx @@ -21,7 +21,7 @@ along with t8code; if not, write to the Free Software Foundation, Inc., */ /** - * \file t8_gtest_adapt.cxx + * \file t8_gtest_adapt_balance_partition.cxx * Tests for the adapt routines of mesh handles. * This tests uses 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 @@ -100,6 +100,8 @@ forest_adapt_callback_example (t8_forest_t forest, t8_forest_t forest_from, t8_l /** Test the adapt routine of a mesh handle. * We compare the result to a classically adapted forest with similar callback. + * Therefore we ensure that the functionality for the mesh handle works based on the assumption that the forest functionality is correct. + * Forest functionality is tested elsewhere. */ TEST (t8_gtest_handle_adapt, compare_adapt_with_forest) { @@ -137,8 +139,18 @@ TEST (t8_gtest_handle_adapt, compare_adapt_with_forest) mesh_handle.set_balance (); mesh_handle.set_partition (); mesh_handle.commit (); - // TODO have a look at t8_gtest_forest_commit for a better structure 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, 0); + t8_forest_set_balance (forest_compare, NULL, 0); + t8_forest_commit (forest_compare); + // Compare results. + EXPECT_TRUE (t8_forest_is_equal (mesh_handle.get_forest (), forest_compare)); // Clean up. - t8_forest_unref (&forest); + t8_forest_unref (&forest_compare); } From 72287c871e4c02b65f416421e42049f1aecf5e46 Mon Sep 17 00:00:00 2001 From: Lena Ploetzke Date: Thu, 22 Jan 2026 16:05:39 +0100 Subject: [PATCH 4/8] rename adapt test --- .../{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 e782a56bc97052d0e366724d129c2b3595460f96 Mon Sep 17 00:00:00 2001 From: Lena Ploetzke Date: Mon, 26 Jan 2026 10:33:16 +0100 Subject: [PATCH 5/8] WIP: add balance,partition --- test/CMakeLists.txt | 14 +++++++------- .../t8_gtest_adapt_partition_balance.cxx | 17 +++++++++-------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 77b3c56d99..44bf59d4bd 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -211,13 +211,13 @@ 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 ) + 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() copy_test_file( test_cube_unstructured_1.inp ) diff --git a/test/mesh_handle/t8_gtest_adapt_partition_balance.cxx b/test/mesh_handle/t8_gtest_adapt_partition_balance.cxx index 218ff40589..abf50cee51 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_balance_partition.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 @@ -98,10 +100,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. - * Therefore we ensure that the functionality for the mesh handle works based on the assumption that the forest functionality is correct. - * Forest functionality is tested elsewhere. +/** 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) { @@ -136,6 +137,7 @@ TEST (t8_gtest_handle_adapt, compare_adapt_with_forest) mesh_class::mesh_adapt_callback_wrapper (adapt_callback_test, user_data), false); mesh_handle.commit (); EXPECT_FALSE (mesh_handle.is_balanced ()); + // Now apply partition and balance. mesh_handle.set_balance (); mesh_handle.set_partition (); mesh_handle.commit (); @@ -149,7 +151,6 @@ TEST (t8_gtest_handle_adapt, compare_adapt_with_forest) t8_forest_set_partition (forest_compare, NULL, 0); t8_forest_set_balance (forest_compare, NULL, 0); t8_forest_commit (forest_compare); - // Compare results. EXPECT_TRUE (t8_forest_is_equal (mesh_handle.get_forest (), forest_compare)); // Clean up. t8_forest_unref (&forest_compare); From a869748e75623b38202285b10d9cb973c2ed1f1b Mon Sep 17 00:00:00 2001 From: Lena Ploetzke Date: Tue, 27 Jan 2026 11:24:17 +0100 Subject: [PATCH 6/8] add flag and correct test --- mesh_handle/adapt.hxx | 10 +++++----- mesh_handle/mesh.hxx | 18 +++++++++++------- .../t8_gtest_adapt_partition_balance.cxx | 12 +++++------- 3 files changed, 21 insertions(+), 19 deletions(-) diff --git a/mesh_handle/adapt.hxx b/mesh_handle/adapt.hxx index 9bf787c917..cf962b0b62 100644 --- a/mesh_handle/adapt.hxx +++ b/mesh_handle/adapt.hxx @@ -120,8 +120,8 @@ class AdaptRegistry { public: /** Static function to register \a context using \a forest as identifier. * This makes the context publicly available using the Registry. - * \param [in] forest The forest identifier. In our case, this is the forest to be adapted - * and not the forest from which we adapt. + * \param [in] forest The forest identifier. In our case, this is the forest from which we adapt the mesh because + * we do not change this forest during adaptation such that it is valid unique identifier. * \param [in] context The context to register. Use unique pointer to ensure proper memory management and ownership. */ static void @@ -135,7 +135,7 @@ class AdaptRegistry { } /** Static function to unregister a context using \a forest as identifier. - * \param [in] forest The forest identifier. In our case, this is the forest to be adapted. + * \param [in] forest The forest identifier. In our case, this is the forest from which we adapt. */ static void unregister_context (t8_forest_t forest) @@ -146,7 +146,7 @@ class AdaptRegistry { } /** Getter for a context using \a forest as identifier. - * \param [in] forest The forest identifier. In our case, this is the forest to be adapted. + * \param [in] forest The forest identifier. In our case, this is the forest from which we adapt. * \return Pointer to the context registered with the id \a forest if found, nullptr otherwise. */ static MeshAdaptContextBase* @@ -193,7 +193,7 @@ mesh_adapt_callback_wrapper ([[maybe_unused]] t8_forest_t forest, t8_forest_t fo { // Get static adapt context from the registry. // Via this, we can access the mesh handle and the user defined adapt callback that uses mesh handle functionality. - auto* context = AdaptRegistry::get (forest); + auto* context = AdaptRegistry::get (forest_from); if (!context) { t8_global_infof ( "Something went wrong while registering the adaptation callbacks. Please check your implementation."); diff --git a/mesh_handle/mesh.hxx b/mesh_handle/mesh.hxx index 6a52c477e2..c9a459367d 100644 --- a/mesh_handle/mesh.hxx +++ b/mesh_handle/mesh.hxx @@ -283,8 +283,7 @@ class mesh { } // Create and register adaptation context holding the mesh handle and the user defined callback. detail::AdaptRegistry::register_context ( - m_uncommitted_forest.value (), - std::make_unique> (*this, std::move (adapt_callback))); + m_forest, std::make_unique> (*this, std::move (adapt_callback))); // Set up the forest for adaptation using the wrapper callback. t8_forest_set_adapt (m_uncommitted_forest.value (), m_forest, detail::mesh_adapt_callback_wrapper, recursive); @@ -314,13 +313,16 @@ class mesh { * 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. - * \note The balanced mesh is not repartitioned per default to maintain a balanced load. - * Call \ref set_partition if you want to repartition the balanced mesh. */ void - set_balance () + set_balance (bool no_repartition = false) { if (!m_uncommitted_forest.has_value ()) { t8_forest_t new_forest; @@ -328,7 +330,7 @@ class mesh { 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, true); + t8_forest_set_balance (m_uncommitted_forest.value (), m_forest, no_repartition); } /** Enable or disable the creation of a layer of ghost elements. @@ -367,16 +369,18 @@ class mesh { if (m_uncommitted_forest.value ()->set_from == NULL) { t8_forest_set_copy (m_uncommitted_forest.value (), m_forest); } + 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::AdaptRegistry::get (m_uncommitted_forest.value ()) != nullptr) { - detail::AdaptRegistry::unregister_context (m_uncommitted_forest.value ()); + detail::AdaptRegistry::unregister_context (m_forest); if (!std::is_void::value) { t8_global_infof ( "Please note that the element data is not interpolated automatically during adaptation. Use the " "function set_element_data() to provide new adapted element data.\n"); } } + t8_forest_unref (&m_forest); // Update underlying forest of the mesh. m_forest = m_uncommitted_forest.value (); m_uncommitted_forest = std::nullopt; diff --git a/test/mesh_handle/t8_gtest_adapt_partition_balance.cxx b/test/mesh_handle/t8_gtest_adapt_partition_balance.cxx index abf50cee51..1afa512dbb 100644 --- a/test/mesh_handle/t8_gtest_adapt_partition_balance.cxx +++ b/test/mesh_handle/t8_gtest_adapt_partition_balance.cxx @@ -127,17 +127,14 @@ 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 check that it is unbalanced afterwards. + // Adapt the mesh handle again and apply partition and balance. mesh_handle.set_adapt ( mesh_class::mesh_adapt_callback_wrapper (adapt_callback_test, user_data), false); - mesh_handle.commit (); - EXPECT_FALSE (mesh_handle.is_balanced ()); - // Now apply partition and balance. mesh_handle.set_balance (); mesh_handle.set_partition (); mesh_handle.commit (); @@ -148,10 +145,11 @@ TEST (t8_gtest_handle_adapt, compare_adapt_with_forest) 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, 0); - t8_forest_set_balance (forest_compare, NULL, 0); + 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_compare); } From 75657fac69afe3ea9232438e8ef9457d39339a0f Mon Sep 17 00:00:00 2001 From: Lena Ploetzke Date: Tue, 27 Jan 2026 13:55:50 +0100 Subject: [PATCH 7/8] change order for codecov --- test/mesh_handle/t8_gtest_adapt_partition_balance.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/mesh_handle/t8_gtest_adapt_partition_balance.cxx b/test/mesh_handle/t8_gtest_adapt_partition_balance.cxx index 1afa512dbb..3dde1d26cf 100644 --- a/test/mesh_handle/t8_gtest_adapt_partition_balance.cxx +++ b/test/mesh_handle/t8_gtest_adapt_partition_balance.cxx @@ -133,10 +133,10 @@ TEST (t8_gtest_handle_adapt, compare_adapt_with_forest) EXPECT_TRUE (t8_forest_is_equal (mesh_handle.get_forest (), forest)); // Adapt the mesh handle again and apply partition and balance. - mesh_handle.set_adapt ( - mesh_class::mesh_adapt_callback_wrapper (adapt_callback_test, user_data), false); 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 ()); From b2433ee4e5f33f93d6b6e4321fbfcca73657d5e3 Mon Sep 17 00:00:00 2001 From: Lena Ploetzke Date: Tue, 24 Mar 2026 14:49:11 +0100 Subject: [PATCH 8/8] merge --- mesh_handle/README.md | 4 +- mesh_handle/{ => internal}/adapt.hxx | 73 +++++++++---------- mesh_handle/mesh.hxx | 17 +++-- .../t8_gtest_adapt_partition_balance.cxx | 5 +- 4 files changed, 47 insertions(+), 52 deletions(-) rename mesh_handle/{ => internal}/adapt.hxx (74%) diff --git a/mesh_handle/README.md b/mesh_handle/README.md index 2242a6204f..20f220981d 100644 --- a/mesh_handle/README.md +++ b/mesh_handle/README.md @@ -11,4 +11,6 @@ The folder's most important files are: - The [constructor_wrappers.hxx](constructor_wrappers.hxx) allows to define a mesh handle using a cmesh instead of a forest and provides a very small number of examples where the user needs no cmesh. - The [element.hxx](element.hxx) defines the elements (mesh or ghost elements) of the mesh handle. - The [competences.hxx](competences.hxx) defines additional competences/functionality of an element to access additional data. -- The [competence_pack.hxx](competence_pack.hxx) is needed to pack element or mesh competences to pass it as template parameter to the mesh. \ No newline at end of file +- The [competence_pack.hxx](competence_pack.hxx) is needed to pack element or mesh competences to pass it as template parameter to the mesh. + +Headers in the [internal/](internal/) folder are only intended to implement details of the mesh handle, so they should not need to be included for any other purpose. \ No newline at end of file diff --git a/mesh_handle/adapt.hxx b/mesh_handle/internal/adapt.hxx similarity index 74% rename from mesh_handle/adapt.hxx rename to mesh_handle/internal/adapt.hxx index cf962b0b62..61b390e41f 100644 --- a/mesh_handle/adapt.hxx +++ b/mesh_handle/internal/adapt.hxx @@ -29,9 +29,9 @@ #include #include -#include "mesh.hxx" -#include +#include #include +#include namespace t8_mesh_handle { @@ -41,70 +41,63 @@ namespace detail { /** Virtual base class for mesh adaptation contexts. - * We need this base class and not only \ref MeshAdaptContext for the \ref AdaptRegistry. - * AdaptRegistry should not be templated because we need to access registered contexts in \ref mesh_adapt_callback_wrapper, + * We need this base class and not only \ref mesh_adapt_context for the \ref adapt_registry. + * adapt_registry should not be templated because we need to access registered contexts in \ref mesh_adapt_callback_wrapper, * where we do not know the type of the mesh. Therefore, we work with a map of forests to instances of this base class to remain template free. */ -struct MeshAdaptContextBase +struct mesh_adapt_context_base { /** Virtual destructor for safe polymorphic deletion. */ - virtual ~MeshAdaptContextBase () = default; + virtual ~mesh_adapt_context_base () = default; /** Pure virtual callback for mesh adaptation. - * \param [in] lelement_handle_id Local flat element ID in the mesh handle of the first element. - * \param [in] is_family If 1, the entries with indices \a lelement_handle_id,..., \a lelement_handle_id+ \a num_elements-1 - * form a family. If 0, they do not. - * \param [in] num_elements The number of elements that form a family or 1 if \a is_family is 0. + * \param [in] lelement_handle_id Local flat element ID in the mesh handle of the first element selected for adaptation. + * \param [in] is_family true if the entries with indices \a lelement_handle_id,..., + * \a lelement_handle_id+ \a num_elements-1 form a family, false otherwise. + * \param [in] num_elements The number of elements that form a family or 1 if \a is_family is false. * \return 1 if the element with index \a lelement_handle_id should be refined, * -1 if the family shall be coarsened, * 0 else. */ virtual int - adapt_mesh (const t8_locidx_t lelement_handle_id, const int is_family, const int num_elements) + adapt_mesh (const t8_locidx_t lelement_handle_id, const bool is_family, const int num_elements) = 0; }; /** Templated mesh adaptation context holding the mesh handle and the user defined callback. - * Class inherits from \ref MeshAdaptContextBase and implements the virtual adapt callback using the mesh and the callback. + * Struct inherits from \ref mesh_adapt_context_base and implements the virtual adapt callback using the mesh and the callback. * \tparam TMesh The mesh handle class. */ template -struct MeshAdaptContext final: MeshAdaptContextBase +struct mesh_adapt_context final: mesh_adapt_context_base { /** Constructor of the context with the mesh handle and the user defined callback. * \param [in] mesh_handle The mesh handle to adapt. * \param [in] adapt_callback The adapt callback. */ - MeshAdaptContext (TMesh& mesh_handle, typename TMesh::adapt_callback_type adapt_callback) + mesh_adapt_context (TMesh& mesh_handle, typename TMesh::adapt_callback_type adapt_callback) : m_mesh_handle (mesh_handle), m_adapt_callback (std::move (adapt_callback)) { } /** Callback for mesh adaptation using the user defined adapt callback. * \param [in] lelement_handle_id Local flat element ID in the mesh handle of the first element. - * \param [in] is_family If 1, the entries with indices \a lelement_handle_id,..., \a lelement_handle_id+ \a num_elements-1 - * form a family. If 0, they do not. - * \param [in] num_elements The number of elements that form a family or 1 if \a is_family is 0. + * \param [in] is_family true if the entries with indices \a lelement_handle_id,..., + * \a lelement_handle_id+ \a num_elements-1 form a family, false otherwise. + * \param [in] num_elements The number of elements that form a family or 1 if \a is_family is false. * \return 1 if the element with index \a lelement_handle_id should be refined, * -1 if the family shall be coarsened, * 0 else. */ int - adapt_mesh (const t8_locidx_t lelement_handle_id, const int is_family, const int num_elements) override + adapt_mesh (const t8_locidx_t lelement_handle_id, const bool is_family, const int num_elements) override { // Check if adapt callback is set and call it using the correct mesh handle function arguments. T8_ASSERTF (m_adapt_callback, "No adapt callback set."); - std::vector element_vec; - if (is_family) { - for (int i = 0; i < num_elements; i++) { - element_vec.push_back (m_mesh_handle[lelement_handle_id + i]); - } - } - else { - element_vec.push_back (m_mesh_handle[lelement_handle_id]); - } - return m_adapt_callback (m_mesh_handle, element_vec); + const int count = is_family ? num_elements : 1; + std::span element_view (&m_mesh_handle[lelement_handle_id], count); + return m_adapt_callback (m_mesh_handle, element_view); } private: @@ -116,21 +109,21 @@ struct MeshAdaptContext final: MeshAdaptContextBase * This globally accessible static class is required to get the handle and the callback in the forest callback, * as the predefined header permits to give these as function arguments. */ -class AdaptRegistry { +class adapt_registry { public: /** Static function to register \a context using \a forest as identifier. - * This makes the context publicly available using the Registry. + * This makes the context publicly available using the registry. * \param [in] forest The forest identifier. In our case, this is the forest from which we adapt the mesh because - * we do not change this forest during adaptation such that it is valid unique identifier. + * we do not change this forest during adaptation such that it is valid unique identifier. * \param [in] context The context to register. Use unique pointer to ensure proper memory management and ownership. */ static void - register_context (t8_forest_t forest, std::unique_ptr context) + register_context (t8_forest_t forest, std::unique_ptr context) { auto& map = get_map (); auto [it, inserted] = map.emplace (forest, std::move (context)); if (!inserted) { - throw std::logic_error ("Context already registered"); + t8_global_productionf ("Context already registered!"); } } @@ -149,7 +142,7 @@ class AdaptRegistry { * \param [in] forest The forest identifier. In our case, this is the forest from which we adapt. * \return Pointer to the context registered with the id \a forest if found, nullptr otherwise. */ - static MeshAdaptContextBase* + static mesh_adapt_context_base* get (t8_forest_t forest) { auto& map = get_map (); @@ -158,14 +151,14 @@ class AdaptRegistry { } private: - /** Get the static map associating t8_forest_t with MeshAdaptContextBase references. + /** Get the static map associating t8_forest_t with mesh_adapt_context_base references. * We use a getter instead of private member variable to ensure single initialization. - * \return Reference to the static unordered map of t8_forest_t to MeshAdaptContextBase references. + * \return Reference to the static unordered map of t8_forest_t to mesh_adapt_context_base references. */ - static std::unordered_map>& + static std::unordered_map>& get_map () { - static std::unordered_map> map; + static std::unordered_map> map; return map; } }; @@ -193,9 +186,9 @@ mesh_adapt_callback_wrapper ([[maybe_unused]] t8_forest_t forest, t8_forest_t fo { // Get static adapt context from the registry. // Via this, we can access the mesh handle and the user defined adapt callback that uses mesh handle functionality. - auto* context = AdaptRegistry::get (forest_from); + auto* context = adapt_registry::get (forest_from); if (!context) { - t8_global_infof ( + t8_global_productionf ( "Something went wrong while registering the adaptation callbacks. Please check your implementation."); return 0; // No adaptation as default. } diff --git a/mesh_handle/mesh.hxx b/mesh_handle/mesh.hxx index 06d5477a6a..6fc25b834d 100644 --- a/mesh_handle/mesh.hxx +++ b/mesh_handle/mesh.hxx @@ -29,7 +29,7 @@ #include #include "element.hxx" #include "competence_pack.hxx" -#include "adapt.hxx" +#include "internal/adapt.hxx" #include "t8_forest/t8_forest_balance.h" #include "t8_forest/t8_forest_types.h" #include @@ -38,6 +38,7 @@ #include #include #include +#include namespace t8_mesh_handle { @@ -84,7 +85,7 @@ class mesh { * -1 if the family \a elements shall be coarsened, * 0 else. */ - using adapt_callback_type = std::function& elements)>; + using adapt_callback_type = std::function elements)>; /** Templated callback function prototype to decide for refining and coarsening of a family of elements * or one element in a mesh handle including user data. @@ -101,7 +102,7 @@ class mesh { */ template using adapt_callback_type_with_userdata - = std::function& elements, TUserDataType user_data)>; + = std::function elements, TUserDataType user_data)>; /** * Constructor for a mesh of the handle. @@ -262,7 +263,7 @@ class mesh { mesh_adapt_callback_wrapper (adapt_callback_type_with_userdata adapt_callback_with_userdata, const TUserDataType& user_data) { - return [=] (const SelfType& mesh, const std::vector& elements) { + return [=] (const SelfType& mesh, std::span elements) { return adapt_callback_with_userdata (mesh, elements, user_data); }; } @@ -283,8 +284,8 @@ class mesh { m_uncommitted_forest = new_forest; } // Create and register adaptation context holding the mesh handle and the user defined callback. - detail::AdaptRegistry::register_context ( - m_forest, std::make_unique> (*this, std::move (adapt_callback))); + detail::adapt_registry::register_context ( + m_forest, std::make_unique> (*this, std::move (adapt_callback))); // Set up the forest for adaptation using the wrapper callback. t8_forest_set_adapt (m_uncommitted_forest.value (), m_forest, detail::mesh_adapt_callback_wrapper, recursive); @@ -373,8 +374,8 @@ 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::AdaptRegistry::get (m_uncommitted_forest.value ()) != nullptr) { - detail::AdaptRegistry::unregister_context (m_forest); + if (detail::adapt_registry::get (m_uncommitted_forest.value ()) != nullptr) { + detail::adapt_registry::unregister_context (m_forest); if (!std::is_void::value) { t8_global_infof ( "Please note that the element data is not interpolated automatically during adaptation. Use the " diff --git a/test/mesh_handle/t8_gtest_adapt_partition_balance.cxx b/test/mesh_handle/t8_gtest_adapt_partition_balance.cxx index fa09ba5367..4a04b9f12e 100644 --- a/test/mesh_handle/t8_gtest_adapt_partition_balance.cxx +++ b/test/mesh_handle/t8_gtest_adapt_partition_balance.cxx @@ -34,13 +34,12 @@ along with t8code; if not, write to the Free Software Foundation, Inc., #include #include -#include #include #include #include #include #include -#include +#include /** Dummy user data taken from tutorial for test purposes. */ struct dummy_user_data @@ -63,7 +62,7 @@ struct dummy_user_data template int adapt_callback_test ([[maybe_unused]] const TMeshClass &mesh, - const std::vector &elements, const dummy_user_data &user_data) + std::span elements, const dummy_user_data &user_data) { auto element_centroid = elements[0].get_centroid (); double dist = t8_dist (element_centroid, user_data.midpoint);