From 6226b685a38002b1e0ab932fd0bb12ba7460d3b3 Mon Sep 17 00:00:00 2001 From: Johannes Holke Date: Thu, 14 Nov 2024 15:21:27 +0100 Subject: [PATCH 1/7] add ghost check functionality to t8_forest_element_is_leaf --- src/t8_forest/t8_forest.cxx | 13 ++++++++++++- src/t8_forest/t8_forest_general.h | 19 +++++++++++++++++++ src/t8_forest/t8_forest_ghost.cxx | 18 +++++++++++++++++- src/t8_forest/t8_forest_ghost.h | 14 ++++++++++++++ 4 files changed, 62 insertions(+), 2 deletions(-) diff --git a/src/t8_forest/t8_forest.cxx b/src/t8_forest/t8_forest.cxx index 51b60d5814..ca2add47df 100644 --- a/src/t8_forest/t8_forest.cxx +++ b/src/t8_forest/t8_forest.cxx @@ -2034,6 +2034,15 @@ t8_forest_tree_is_local (const t8_forest_t forest, const t8_locidx_t local_tree) int t8_forest_element_is_leaf (const t8_forest_t forest, const t8_element_t *element, const t8_locidx_t local_tree) +{ + bool check_ghost = false; + T8_ASSERT (t8_forest_tree_is_local (forest, local_tree)); + return t8_forest_element_is_leaf_or_ghost (forest, element, local_tree, check_ghost); +} + +int +t8_forest_element_is_leaf_or_ghost (const t8_forest_t forest, const t8_element_t *element, const t8_locidx_t local_tree, + const int check_ghost) { T8_ASSERT (t8_forest_is_committed (forest)); T8_ASSERT (t8_forest_tree_is_local (forest, local_tree)); @@ -2041,7 +2050,9 @@ t8_forest_element_is_leaf (const t8_forest_t forest, const t8_element_t *element /* We get the array of the tree's elements and then search in the array of elements for our * element candidate. */ /* Get the array */ - const t8_element_array_t *elements = t8_forest_get_tree_element_array (forest, local_tree); + const t8_element_array_t *elements = !check_ghost ? t8_forest_tree_get_leaves (forest, local_tree) + : t8_forest_ghost_get_tree_elements (forest, local_tree); + T8_ASSERT (elements != NULL); /* In order to find the element, we need to compute its linear id. diff --git a/src/t8_forest/t8_forest_general.h b/src/t8_forest/t8_forest_general.h index cf4d4db3f3..51e1490cb0 100644 --- a/src/t8_forest/t8_forest_general.h +++ b/src/t8_forest/t8_forest_general.h @@ -517,6 +517,25 @@ t8_forest_get_coarse_tree (t8_forest_t forest, t8_locidx_t ltreeid); int t8_forest_element_is_leaf (const t8_forest_t forest, const t8_element_t *element, const t8_locidx_t local_tree); +/** + * Query whether a given element or a ghost is a leaf of a local or ghost tree in a forest. + * + * \param [in] forest The forest. + * \param [in] element An element of a local tree in \a forest. + * \param [in] local_tree A local tree id of \a forest or a ghost tree id + * \param [in] check_ghost If true \a element is interpreted as a ghost element and + * \a local_tree as the id of a ghost tree (0 <= \a local_tree < num_ghost_trees). + * If false \a element is interpreted as an element and \a local_tree as + * the id of a local tree (0 <= \a local_tree < num_local_trees). + * \return True (non-zero) if and only if \a element is a leaf (or ghost) in \a local_tree of \a forest. + * \note \a forest must be committed before calling this function. + * \ref t8_forest_element_is_leaf + * \ref t8_forest_element_is_ghost + */ +int +t8_forest_element_is_leaf_or_ghost (const t8_forest_t forest, const t8_element_t *element, const t8_locidx_t local_tree, + const int check_ghost); + /** Compute the leaf face orientation at given face in a forest. * \param [in] forest The forest. Must have a valid ghost layer. * \param [in] ltreeid A local tree id. diff --git a/src/t8_forest/t8_forest_ghost.cxx b/src/t8_forest/t8_forest_ghost.cxx index c2c9691caf..d26cf7beb8 100644 --- a/src/t8_forest/t8_forest_ghost.cxx +++ b/src/t8_forest/t8_forest_ghost.cxx @@ -263,6 +263,14 @@ t8_forest_ghost_num_trees (const t8_forest_t forest) return forest->ghosts->ghost_trees->elem_count; } +static bool +t8_forest_tree_is_ghost (const t8_forest_t forest, const t8_locidx_t lghost_tree) +{ + T8_ASSERT (t8_forest_is_committed (forest)); + + return 0 <= lghost_tree && lghost_tree < t8_forest_get_num_ghost_trees (forest); +} + /* Given an index into the ghost_trees array return the ghost tree */ static t8_ghost_tree_t * t8_forest_ghost_get_tree (const t8_forest_t forest, const t8_locidx_t lghost_tree) @@ -274,7 +282,7 @@ t8_forest_ghost_get_tree (const t8_forest_t forest, const t8_locidx_t lghost_tre ghost = forest->ghosts; T8_ASSERT (ghost != NULL); T8_ASSERT (ghost->ghost_trees != NULL); - T8_ASSERT (0 <= lghost_tree && lghost_tree < t8_forest_ghost_num_trees (forest)); + T8_ASSERT (t8_forest_tree_is_ghost (forest, lghost_tree)); ghost_tree = (t8_ghost_tree_t *) t8_sc_array_index_locidx (ghost->ghost_trees, lghost_tree); return ghost_tree; @@ -365,6 +373,14 @@ t8_forest_ghost_get_element (t8_forest_t forest, t8_locidx_t lghost_tree, t8_loc return t8_element_array_index_locidx_mutable (&ghost_tree->elements, lelement); } +int +t8_forest_element_is_ghost (const t8_forest_t forest, const t8_element_t *element, const t8_locidx_t lghost_tree) +{ + bool check_ghost = true; + T8_ASSERT (t8_forest_tree_is_ghost (forest, lghost_tree)); + return t8_forest_element_is_leaf_or_ghost (forest, element, lghost_tree, check_ghost); +} + /* Initialize a t8_ghost_remote_tree_t */ static void t8_ghost_init_remote_tree (t8_forest_t forest, t8_gloidx_t gtreeid, int remote_rank, t8_eclass_t eclass, diff --git a/src/t8_forest/t8_forest_ghost.h b/src/t8_forest/t8_forest_ghost.h index 427a73109e..f9b3e02785 100644 --- a/src/t8_forest/t8_forest_ghost.h +++ b/src/t8_forest/t8_forest_ghost.h @@ -108,6 +108,20 @@ t8_forest_ghost_get_global_treeid (const t8_forest_t forest, const t8_locidx_t l t8_element_t * t8_forest_ghost_get_element (t8_forest_t forest, t8_locidx_t lghost_tree, t8_locidx_t lelement); + +/** + * Query whether a given element is a ghost of a certrain tree in a forest. + * + * \param [in] forest The forest. + * \param [in] element An element of a ghost tree in \a forest. + * \param [in] lghost_tree A local ghost tree id of \a forest. (0 <= \a lghost_tree < num_ghost_trees) + * \return True (non-zero) if and only if \a element is a ghost in \a lghost_tree of \a forest. + * \note \a forest must be committed before calling this function. + */ +int +t8_forest_element_is_ghost (const t8_forest_t forest, const t8_element_t *element, const t8_locidx_t lghost_tree); + + /** Return the array of remote ranks. * \param [in] forest A forest with constructed ghost layer. * \param [in,out] num_remotes On output the number of remote ranks is stored here. From 0fa3f7b28a91d31600781f74b70a916e485ca383 Mon Sep 17 00:00:00 2001 From: Johannes Holke Date: Thu, 14 Nov 2024 15:22:11 +0100 Subject: [PATCH 2/7] comment and remove empty lines --- src/t8_forest/t8_forest_ghost.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/t8_forest/t8_forest_ghost.h b/src/t8_forest/t8_forest_ghost.h index f9b3e02785..3b8042df10 100644 --- a/src/t8_forest/t8_forest_ghost.h +++ b/src/t8_forest/t8_forest_ghost.h @@ -96,7 +96,7 @@ t8_forest_ghost_get_tree_class (const t8_forest_t forest, const t8_locidx_t lgho /** Given a local ghost tree compute the global tree id of it. * \param [in] forest The forest. Ghost layer must exist. - * \param [in] lghost_tree The ghost tree id of a ghost tree. + * \param [in] lghost_tree The ghost tree id of a ghost tree. (0 <= \a lghost_tree < num_ghost_trees) * \return The global id of the local ghost tree \a lghost_tree. * \a forest must be committed before calling this function. * \see https://github.com/DLR-AMR/t8code/wiki/Tree-indexing for more details about tree indexing. @@ -108,7 +108,6 @@ t8_forest_ghost_get_global_treeid (const t8_forest_t forest, const t8_locidx_t l t8_element_t * t8_forest_ghost_get_element (t8_forest_t forest, t8_locidx_t lghost_tree, t8_locidx_t lelement); - /** * Query whether a given element is a ghost of a certrain tree in a forest. * @@ -121,7 +120,6 @@ t8_forest_ghost_get_element (t8_forest_t forest, t8_locidx_t lghost_tree, t8_loc int t8_forest_element_is_ghost (const t8_forest_t forest, const t8_element_t *element, const t8_locidx_t lghost_tree); - /** Return the array of remote ranks. * \param [in] forest A forest with constructed ghost layer. * \param [in,out] num_remotes On output the number of remote ranks is stored here. From 108664c890d72377457420354f38fad056e31f95 Mon Sep 17 00:00:00 2001 From: Johannes Holke Date: Thu, 14 Nov 2024 15:35:23 +0100 Subject: [PATCH 3/7] extend is leaf test to ghosts --- test/t8_forest/t8_gtest_element_is_leaf.cxx | 65 ++++++++++++++++++--- 1 file changed, 58 insertions(+), 7 deletions(-) diff --git a/test/t8_forest/t8_gtest_element_is_leaf.cxx b/test/t8_forest/t8_gtest_element_is_leaf.cxx index 51d32755ae..bcb193122a 100644 --- a/test/t8_forest/t8_gtest_element_is_leaf.cxx +++ b/test/t8_forest/t8_gtest_element_is_leaf.cxx @@ -24,6 +24,7 @@ #include #include #include +#include #include #include "test/t8_cmesh_generator/t8_cmesh_example_sets.hxx" #include @@ -62,7 +63,7 @@ t8_test_adapt_first_child (t8_forest_t forest, t8_forest_t forest_from, t8_locid return 0; } -class element_is_leaf: public testing::TestWithParam> { +class element_is_leaf_or_ghost: public testing::TestWithParam> { protected: void SetUp () override @@ -77,7 +78,7 @@ class element_is_leaf: public testing::TestWithParamt8_element_new (1, ¬_leaf); /* Iterate over all the tree's leaf elements, check whether the leaf - * is correctly identified by t8_forest_element_is_leaf, + * is correctly identified by t8_forest_element_is_leaf and t8_forest_element_is_leaf_or_ghost, * build its parent and its first child (if they exist), and verify - * that t8_forest_element_is_leaf returns false. */ + * that t8_forest_element_is_leaf and t8_forest_element_is_leaf_or_ghost returns false. */ for (t8_locidx_t ielement = 0; ielement < num_elements_in_tree; ++ielement) { const t8_element_t *leaf_element = t8_forest_get_element_in_tree (forest, itree, ielement); EXPECT_TRUE (t8_forest_element_is_leaf (forest, leaf_element, itree)); + EXPECT_TRUE (t8_forest_element_is_leaf_or_ghost (forest, leaf_element, itree, 0)); /* Compute parent and first child of element and check that they are not in the tree */ const int element_level = scheme->t8_element_level (leaf_element); if (element_level > 0) { scheme->t8_element_parent (leaf_element, not_leaf); EXPECT_FALSE (t8_forest_element_is_leaf (forest, not_leaf, itree)); + EXPECT_FALSE (t8_forest_element_is_leaf_or_ghost (forest, not_leaf, itree, 0)); } if (element_level < scheme->t8_element_maxlevel ()) { scheme->t8_element_child (leaf_element, 0, not_leaf); EXPECT_FALSE (t8_forest_element_is_leaf (forest, not_leaf, itree)); + EXPECT_FALSE (t8_forest_element_is_leaf_or_ghost (forest, not_leaf, itree, 0)); } } scheme->t8_element_destroy (1, ¬_leaf); } } -TEST_P (element_is_leaf, element_is_leaf) +TEST_P (element_is_leaf_or_ghost, element_is_leaf) { t8_test_element_is_leaf_for_forest (forest); } -TEST_P (element_is_leaf, element_is_leaf_adapt) +TEST_P (element_is_leaf_or_ghost, element_is_leaf_adapt) +{ + t8_test_element_is_leaf_for_forest (forest_adapt); +} + +void +t8_test_element_is_ghost_for_forest (t8_forest_t forest) +{ + const t8_locidx_t num_ghost_trees = t8_forest_get_num_ghost_trees (forest); + + for (t8_locidx_t ighost_tree = 0; ighost_tree < num_ghost_trees; ++ighost_tree) { + const t8_locidx_t num_elements_in_tree = t8_forest_ghost_tree_num_elements (forest, ighost_tree); + const t8_eclass_t tree_class = t8_forest_get_tree_class (forest, ighost_tree); + const t8_eclass_scheme_c *scheme = t8_forest_get_eclass_scheme (forest, tree_class); + /* Allocate memory to build a non-ghost element. */ + t8_element_t *not_ghost; + scheme->t8_element_new (1, ¬_ghost); + /* Iterate over all the tree's ghost elements, check whether the ghost + * is correctly identified by t8_forest_element_is_ghost and t8_forest_element_is_leaf_or_ghost, + * build its parent and its first child (if they exist), and verify + * that t8_forest_element_is_leaf and t8_forest_element_is_leaf_or_ghost returns false. */ + for (t8_locidx_t ielement = 0; ielement < num_elements_in_tree; ++ielement) { + const t8_element_t *ghost_element = t8_forest_ghost_get_element (forest, ighost_tree, ielement); + EXPECT_TRUE (t8_forest_element_is_ghost (forest, ghost_element, ighost_tree)); + EXPECT_TRUE (t8_forest_element_is_leaf_or_ghost (forest, ghost_element, ighost_tree, 1)); + /* Compute parent and first child of element and check that they are not in the tree */ + const int element_level = scheme->t8_element_level (ghost_element); + if (element_level > 0) { + scheme->t8_element_parent (ghost_element, not_ghost); + EXPECT_FALSE (t8_forest_element_is_ghost (forest, not_ghost, ighost_tree)); + EXPECT_FALSE (t8_forest_element_is_leaf_or_ghost (forest, not_ghost, ighost_tree, 1)); + } + if (element_level < scheme->t8_element_maxlevel ()) { + scheme->t8_element_child (ghost_element, 0, not_ghost); + EXPECT_FALSE (t8_forest_element_is_ghost (forest, not_ghost, ighost_tree)); + EXPECT_FALSE (t8_forest_element_is_leaf_or_ghost (forest, not_ghost, ighost_tree, 1)); + } + } + scheme->t8_element_destroy (1, ¬_ghost); + } +} + +TEST_P (element_is_leaf_or_ghost, element_is_ghost) +{ + t8_test_element_is_leaf_for_forest (forest); +} + +TEST_P (element_is_leaf_or_ghost, element_is_ghost_adapt) { t8_test_element_is_leaf_for_forest (forest_adapt); } @@ -156,6 +207,6 @@ auto pretty_print_level_and_cmesh_params return name; }; -INSTANTIATE_TEST_SUITE_P (t8_gtest_element_is_leaf, element_is_leaf, +INSTANTIATE_TEST_SUITE_P (t8_gtest_element_is_leaf_or_ghost, element_is_leaf_or_ghost, testing::Combine (testing::Range (0, T8_IS_LEAF_MAX_LVL), AllCmeshsParam), pretty_print_level_and_cmesh_params); From 9402ee637e142f6fd97606a0dbd4583a9f571612 Mon Sep 17 00:00:00 2001 From: Johannes Holke Date: Thu, 14 Nov 2024 15:36:59 +0100 Subject: [PATCH 4/7] activate parallel testing for is leaf check --- test/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index ef9f9ba71a..bfd28922e3 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -101,7 +101,7 @@ add_t8_test( NAME t8_gtest_ghost_and_owner_parallel SOURCES t8_gtest_main.cx add_t8_test( NAME t8_gtest_balance_parallel SOURCES t8_gtest_main.cxx t8_forest/t8_gtest_balance.cxx ) add_t8_test( NAME t8_gtest_forest_commit_parallel SOURCES t8_gtest_main.cxx t8_forest/t8_gtest_forest_commit.cxx ) add_t8_test( NAME t8_gtest_forest_face_normal_serial SOURCES t8_gtest_main.cxx t8_forest/t8_gtest_forest_face_normal.cxx ) -add_t8_test( NAME t8_gtest_element_is_leaf_serial SOURCES t8_gtest_main.cxx t8_forest/t8_gtest_element_is_leaf.cxx ) +add_t8_test( NAME t8_gtest_element_is_leaf_parallel SOURCES t8_gtest_main.cxx t8_forest/t8_gtest_element_is_leaf.cxx ) add_t8_test( NAME t8_gtest_partition_data_parallel SOURCES t8_gtest_main.cxx t8_forest/t8_gtest_partition_data.cxx ) add_t8_test( NAME t8_gtest_permute_hole_serial SOURCES t8_gtest_main.cxx t8_forest_incomplete/t8_gtest_permute_hole.cxx ) From 562cd4a5e339f689c03389278037cb261bf09295 Mon Sep 17 00:00:00 2001 From: Johannes Holke Date: Thu, 14 Nov 2024 16:36:59 +0100 Subject: [PATCH 5/7] debug guards around check used only in debug mode --- src/t8_forest/t8_forest_ghost.cxx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/t8_forest/t8_forest_ghost.cxx b/src/t8_forest/t8_forest_ghost.cxx index d26cf7beb8..9075a16dea 100644 --- a/src/t8_forest/t8_forest_ghost.cxx +++ b/src/t8_forest/t8_forest_ghost.cxx @@ -263,6 +263,7 @@ t8_forest_ghost_num_trees (const t8_forest_t forest) return forest->ghosts->ghost_trees->elem_count; } +#if T8_ENABLE_DEBUG static bool t8_forest_tree_is_ghost (const t8_forest_t forest, const t8_locidx_t lghost_tree) { @@ -270,6 +271,7 @@ t8_forest_tree_is_ghost (const t8_forest_t forest, const t8_locidx_t lghost_tree return 0 <= lghost_tree && lghost_tree < t8_forest_get_num_ghost_trees (forest); } +#endif /* Given an index into the ghost_trees array return the ghost tree */ static t8_ghost_tree_t * From e97696a9d81467a8cd2d5eba559220ae6c0b6a81 Mon Sep 17 00:00:00 2001 From: Johannes Holke Date: Thu, 14 Nov 2024 16:43:36 +0100 Subject: [PATCH 6/7] typo --- test/t8_forest/t8_gtest_element_is_leaf.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/t8_forest/t8_gtest_element_is_leaf.cxx b/test/t8_forest/t8_gtest_element_is_leaf.cxx index bcb193122a..0c6c1faab4 100644 --- a/test/t8_forest/t8_gtest_element_is_leaf.cxx +++ b/test/t8_forest/t8_gtest_element_is_leaf.cxx @@ -196,7 +196,7 @@ TEST_P (element_is_leaf_or_ghost, element_is_ghost_adapt) t8_test_element_is_leaf_for_forest (forest_adapt); } -/* Define a lambda to beatify gtest output for tuples . +/* Define a lambda to beautify gtest output for tuples . * This will set the correct level and cmesh name as part of the test case name. */ auto pretty_print_level_and_cmesh_params = [] (const testing::TestParamInfo> &info) { From a3e7ec2ddb398bb4e99a7508dc59a065dea83527 Mon Sep 17 00:00:00 2001 From: Johannes Holke Date: Thu, 21 Nov 2024 23:17:11 +0100 Subject: [PATCH 7/7] is_leaf_or_ghost correct assertion --- src/t8_forest/t8_forest.cxx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/t8_forest/t8_forest.cxx b/src/t8_forest/t8_forest.cxx index ca2add47df..47b9a015c5 100644 --- a/src/t8_forest/t8_forest.cxx +++ b/src/t8_forest/t8_forest.cxx @@ -2045,7 +2045,14 @@ t8_forest_element_is_leaf_or_ghost (const t8_forest_t forest, const t8_element_t const int check_ghost) { T8_ASSERT (t8_forest_is_committed (forest)); - T8_ASSERT (t8_forest_tree_is_local (forest, local_tree)); +#if T8_ENABLE_DEBUG + if (!check_ghost) { + T8_ASSERT (t8_forest_tree_is_local (forest, local_tree)); + } + else { + T8_ASSERT (0 <= local_tree && local_tree < t8_forest_get_num_ghost_trees (forest)); + } +#endif /* We get the array of the tree's elements and then search in the array of elements for our * element candidate. */