Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add t8_element_is_ghost function #1301

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 20 additions & 2 deletions src/t8_forest/t8_forest.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -2035,13 +2035,31 @@ 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)
{
T8_ASSERT (t8_forest_is_committed (forest));
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)
Comment on lines +2043 to +2045
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like your idea of seperating the functionality of choosing the element array and searching the element array.

But I think this approach can be done even stricter, by passing the element_array as argument to the helper function.

t8_forest_element_is_leaf and t8_forest_element_is_ghost then have the task to chose the correct element array, which they then pass to the helper function, which determines if the element is included in the element array.

{
T8_ASSERT (t8_forest_is_committed (forest));
#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. */
/* 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.
Expand Down
19 changes: 19 additions & 0 deletions src/t8_forest/t8_forest_general.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
20 changes: 19 additions & 1 deletion src/t8_forest/t8_forest_ghost.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,16 @@ 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)
{
T8_ASSERT (t8_forest_is_committed (forest));

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 *
t8_forest_ghost_get_tree (const t8_forest_t forest, const t8_locidx_t lghost_tree)
Expand All @@ -274,7 +284,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;
Expand Down Expand Up @@ -365,6 +375,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,
Expand Down
14 changes: 13 additions & 1 deletion src/t8_forest/t8_forest_ghost.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -108,6 +108,18 @@ 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.
Expand Down
2 changes: 1 addition & 1 deletion test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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 )
Expand Down
67 changes: 59 additions & 8 deletions test/t8_forest/t8_gtest_element_is_leaf.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include <t8_eclass.h>
#include <t8_cmesh.h>
#include <t8_forest/t8_forest_general.h>
#include <t8_forest/t8_forest_ghost.h>
#include <t8_schemes/t8_default/t8_default.hxx>
#include "test/t8_cmesh_generator/t8_cmesh_example_sets.hxx"
#include <test/t8_gtest_macros.hxx>
Expand Down Expand Up @@ -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<std::tuple<int, cmesh_example_base *>> {
class element_is_leaf_or_ghost: public testing::TestWithParam<std::tuple<int, cmesh_example_base *>> {
protected:
void
SetUp () override
Expand All @@ -77,7 +78,7 @@ class element_is_leaf: public testing::TestWithParam<std::tuple<int, cmesh_examp
}
/* Build the default scheme (TODO: Test this with all schemes) */
scheme = t8_scheme_new_default_cxx ();
forest = t8_forest_new_uniform (cmesh, scheme, level, 0, sc_MPI_COMM_WORLD);
forest = t8_forest_new_uniform (cmesh, scheme, level, 1, sc_MPI_COMM_WORLD);
t8_forest_ref (forest);
//const int maxlevel = t8_forest_get_maxlevel (forest);
int maxlevel = 7;
Expand Down Expand Up @@ -114,38 +115,88 @@ t8_test_element_is_leaf_for_forest (t8_forest_t forest)
t8_element_t *not_leaf;
scheme->t8_element_new (1, &not_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, &not_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);
}

/* Define a lambda to beatify gtest output for tuples <level, cmesh>.
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, &not_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, &not_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);
}

/* Define a lambda to beautify gtest output for tuples <level, cmesh>.
* 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<std::tuple<int, cmesh_example_base *>> &info) {
Expand All @@ -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);