From 0ed878e3afe5f4f567ca601641e50539741dc193 Mon Sep 17 00:00:00 2001 From: Johannes Holke Date: Tue, 4 Jun 2024 15:13:01 +0200 Subject: [PATCH 01/24] implementation of t8_forest_tree_is_local --- src/t8_forest/t8_forest_cxx.cxx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/t8_forest/t8_forest_cxx.cxx b/src/t8_forest/t8_forest_cxx.cxx index b88ac67603..69ac3b5a1b 100644 --- a/src/t8_forest/t8_forest_cxx.cxx +++ b/src/t8_forest/t8_forest_cxx.cxx @@ -2022,6 +2022,13 @@ t8_forest_print_all_leaf_neighbors (t8_forest_t forest) } } +int +t8_forest_tree_is_local (const t8_forest_t forest, const t8_locidx_t local_tree) +{ + T8_ASSERT (t8_forest_is_committed (forest)); + return 0 <= local_tree && local_tree < t8_forest_get_num_local_trees (forest); +} + /* Check if an element is owned by a specific rank */ int t8_forest_element_check_owner (t8_forest_t forest, t8_element_t *element, t8_gloidx_t gtreeid, t8_eclass_t eclass, From ade6f035ab2d3c87e18490712bd730d8070255a4 Mon Sep 17 00:00:00 2001 From: Johannes Holke Date: Tue, 4 Jun 2024 15:13:44 +0200 Subject: [PATCH 02/24] implementation of t8_forest_element_is_leaf --- src/t8_forest/t8_forest_cxx.cxx | 35 +++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/t8_forest/t8_forest_cxx.cxx b/src/t8_forest/t8_forest_cxx.cxx index 69ac3b5a1b..06cc7aef7f 100644 --- a/src/t8_forest/t8_forest_cxx.cxx +++ b/src/t8_forest/t8_forest_cxx.cxx @@ -2029,6 +2029,41 @@ t8_forest_tree_is_local (const t8_forest_t forest, const t8_locidx_t local_tree) return 0 <= local_tree && local_tree < t8_forest_get_num_local_trees (forest); } +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)); + T8_ASSERT (t8_forest_tree_is_local (forest, local_tree)); + + /* 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); + T8_ASSERT (elements != NULL); + + /* In order to find the element, we need to compute its linear id. + * To do so, we need the scheme and the level of the element. */ + const t8_eclass_scheme_c * scheme = t8_element_array_get_scheme (elements); + const int element_level = scheme->t8_element_level (element); + /* Compute the linear id. */ + const t8_linearidx_t element_id = scheme->t8_element_get_linear_id (element, element_level); + /* Search for the element. + * The search returns the largest index i, + * such that the element at position i has a smaller id than the given one. + * If no such i exists, it returns -1. */ + const t8_locidx_t search_result = t8_forest_bin_search_lower (t8_element_array_t *elements, t8_linearidx_t element_id, int maxlevel); + if (search_result < 0) { + /* The element was not found. */ + return 0; + } + /* An element was found but it may not be the candidate element. + * To identify whether the element was found, we compare these two. */ + const t8_element_t * check_element = t8_element_array_index_locidx (elements, search_result); + T8_ASSERT (check_element != NULL); + /* If the compare function returns 0, the elements are equal and we return true. */ + return (scheme->t8_element_compare (element, check_element) == 0); +} + /* Check if an element is owned by a specific rank */ int t8_forest_element_check_owner (t8_forest_t forest, t8_element_t *element, t8_gloidx_t gtreeid, t8_eclass_t eclass, From 864eec95d62139f408a5bc36ed76d01d5ae82916 Mon Sep 17 00:00:00 2001 From: Johannes Holke Date: Tue, 4 Jun 2024 15:14:06 +0200 Subject: [PATCH 03/24] Implementation of t8_forest_leaf_is_boundary --- src/t8_forest/t8_forest_cxx.cxx | 54 +++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/src/t8_forest/t8_forest_cxx.cxx b/src/t8_forest/t8_forest_cxx.cxx index 06cc7aef7f..1127d9db15 100644 --- a/src/t8_forest/t8_forest_cxx.cxx +++ b/src/t8_forest/t8_forest_cxx.cxx @@ -2064,6 +2064,60 @@ t8_forest_element_is_leaf (const t8_forest_t forest, const t8_element_t *element return (scheme->t8_element_compare (element, check_element) == 0); } +int +t8_forest_leaf_is_boundary (const t8_forest_t forest, t8_locidx_t local_tree, const t8_element_t *leaf, int face) +{ + T8_ASSERT (t8_forest_is_committed (forest)); + T8_ASSERT (t8_forest_element_is_leaf (forest, leaf, local_tree)); + T8_ASSERT (element != NULL); + + const t8_eclass_t tree_class = t8_forest_get_tree_class (forest, local_tree); + const t8_eclass_scheme_c *scheme = t8_forest_get_eclass_scheme (forest, tree_class); + + /* Check whether this leaf is at the boundary of its tree. */ + const int is_root_boundary = scheme->t8_element_is_root_boundary (leaf, face); + + if (is_root_boundary) { + /* This leaf is at a tree's boundary. It is*/ + const int cmesh_face = scheme->t8_element_tree_face (leaf, face); + const t8_cmesh_t = t8_forest_get_cmesh (forest); + const t8_locidx_t cmesh_local_tree = t8_forest_ltreeid_to_cmesh_ltreeid (forest, local_tree); + int tree_boundary = t8_cmesh_tree_face_is_boundary (cmesh, cmesh_local_tree, cmesh_face); + if (tree_boundary) { + return 1; + } + } + + /* This leaf is not at the tree's boundary. + * If the forest has holes, we need to check whether this leaf is at an internal boundary.*/ + + if (!forest->incomplete_trees) { + /* The forest has no holes, thus the leaf cannot be a boundary leaf. */ + return 0; + } + /* we need to compute the face neihgbors to know whether the element is a boundary element. */ + const int is_balanced = t8_forest_is_balanced (forest); + int num_neighbors; + t8_element_t **neighbor_leaves; + t8_locidx_t *pelelement_indices; + t8_eclass_scheme_c *pneigh_scheme; + /* The forest has holes, the leaf could lie inside a tree but its neighbor was deleted. */ + t8_forest_leaf_face_neighbors (forest, local_tree, leaf, &neighbor_leaves, face, NULL, &num_neighbors, &pelement_indices, &pneigh_scheme, is_balanced); + + if (num_neighbors == 0) { + /* The element has no neighbors, it is a boundary element. */ + return 1; + } + else { + /* If neighbors were found, these arrays were allocated and need clean-up. */ + T8_FREE (neighbor_leaves); + T8_FREE (pelelement_indices); + /* This leaf is not a boundary leaf. */ + return 0; + } + +} + /* Check if an element is owned by a specific rank */ int t8_forest_element_check_owner (t8_forest_t forest, t8_element_t *element, t8_gloidx_t gtreeid, t8_eclass_t eclass, From 84aec4d7bede0a83ffe9a2b2f7d0fe43c6f61291 Mon Sep 17 00:00:00 2001 From: Johannes Holke Date: Tue, 4 Jun 2024 16:35:30 +0200 Subject: [PATCH 04/24] minor fixes --- src/t8_forest/t8_forest_cxx.cxx | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/t8_forest/t8_forest_cxx.cxx b/src/t8_forest/t8_forest_cxx.cxx index 95d625a0c6..d03b6ea09c 100644 --- a/src/t8_forest/t8_forest_cxx.cxx +++ b/src/t8_forest/t8_forest_cxx.cxx @@ -2031,6 +2031,7 @@ t8_forest_element_is_leaf (const t8_forest_t forest, const t8_element_t *element { T8_ASSERT (t8_forest_is_committed (forest)); T8_ASSERT (t8_forest_tree_is_local (forest, local_tree)); + T8_ASSERT (element != NULL); /* We get the array of the tree's elements and then search in the array of elements for our * element candidate. */ @@ -2048,7 +2049,7 @@ t8_forest_element_is_leaf (const t8_forest_t forest, const t8_element_t *element * The search returns the largest index i, * such that the element at position i has a smaller id than the given one. * If no such i exists, it returns -1. */ - const t8_locidx_t search_result = t8_forest_bin_search_lower (t8_element_array_t *elements, t8_linearidx_t element_id, int maxlevel); + const t8_locidx_t search_result = t8_forest_bin_search_lower (elements, element_id, element_level); if (search_result < 0) { /* The element was not found. */ return 0; @@ -2066,7 +2067,7 @@ t8_forest_leaf_is_boundary (const t8_forest_t forest, t8_locidx_t local_tree, co { T8_ASSERT (t8_forest_is_committed (forest)); T8_ASSERT (t8_forest_element_is_leaf (forest, leaf, local_tree)); - T8_ASSERT (element != NULL); + T8_ASSERT (leaf != NULL); const t8_eclass_t tree_class = t8_forest_get_tree_class (forest, local_tree); const t8_eclass_scheme_c *scheme = t8_forest_get_eclass_scheme (forest, tree_class); @@ -2077,7 +2078,7 @@ t8_forest_leaf_is_boundary (const t8_forest_t forest, t8_locidx_t local_tree, co if (is_root_boundary) { /* This leaf is at a tree's boundary. It is*/ const int cmesh_face = scheme->t8_element_tree_face (leaf, face); - const t8_cmesh_t = t8_forest_get_cmesh (forest); + const t8_cmesh_t cmesh = t8_forest_get_cmesh (forest); const t8_locidx_t cmesh_local_tree = t8_forest_ltreeid_to_cmesh_ltreeid (forest, local_tree); int tree_boundary = t8_cmesh_tree_face_is_boundary (cmesh, cmesh_local_tree, cmesh_face); if (tree_boundary) { @@ -2096,7 +2097,7 @@ t8_forest_leaf_is_boundary (const t8_forest_t forest, t8_locidx_t local_tree, co const int is_balanced = t8_forest_is_balanced (forest); int num_neighbors; t8_element_t **neighbor_leaves; - t8_locidx_t *pelelement_indices; + t8_locidx_t *pelement_indices; t8_eclass_scheme_c *pneigh_scheme; /* The forest has holes, the leaf could lie inside a tree but its neighbor was deleted. */ t8_forest_leaf_face_neighbors (forest, local_tree, leaf, &neighbor_leaves, face, NULL, &num_neighbors, &pelement_indices, &pneigh_scheme, is_balanced); @@ -2108,7 +2109,7 @@ t8_forest_leaf_is_boundary (const t8_forest_t forest, t8_locidx_t local_tree, co else { /* If neighbors were found, these arrays were allocated and need clean-up. */ T8_FREE (neighbor_leaves); - T8_FREE (pelelement_indices); + T8_FREE (pelement_indices); /* This leaf is not a boundary leaf. */ return 0; } From b9960345ad69bff195388a47682b8c34342606c1 Mon Sep 17 00:00:00 2001 From: Johannes Holke Date: Tue, 4 Jun 2024 16:35:52 +0200 Subject: [PATCH 05/24] Add declaration and documentation of new functions --- src/t8_forest/t8_forest_general.h | 24 ++++++++++++++++++++++++ src/t8_forest/t8_forest_geometrical.h | 11 +++++++++++ 2 files changed, 35 insertions(+) diff --git a/src/t8_forest/t8_forest_general.h b/src/t8_forest/t8_forest_general.h index 7e39fa9c45..a03fb308ef 100644 --- a/src/t8_forest/t8_forest_general.h +++ b/src/t8_forest/t8_forest_general.h @@ -436,6 +436,17 @@ t8_forest_get_num_ghosts (const t8_forest_t forest); t8_eclass_t t8_forest_get_eclass (const t8_forest_t forest, const t8_locidx_t ltreeid); +/** + * Check whether a given tree id belongs to a local tree in a forest. + * + * \param [in] forest The forest. + * \param [in] local_tree A tree id. + * \return True if and only if the id \a local_tree belongs to a local tree of \a forest. + * \a forest must be committed before calling this function. + */ +int +t8_forest_tree_is_local (const t8_forest_t forest, const t8_locidx_t local_tree); + /** Given a global tree id compute the forest local id of this tree. * If the tree is a local tree, then the local id is between 0 and the number * of local trees. If the tree is not a local tree, a negative number is returned. @@ -493,6 +504,19 @@ t8_forest_cmesh_ltreeid_to_ltreeid (t8_forest_t forest, t8_locidx_t lctreeid); t8_ctree_t t8_forest_get_coarse_tree (t8_forest_t forest, t8_locidx_t ltreeid); +/** + * Query whether a given element is a leaf 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. + * \return True (non-zero) if and only if \a element is a leaf in \a local_tree of \a forest. + * \note This does not query for ghost leafs. + * \note \a forest must be committed before calling this function. + */ +int +t8_forest_element_is_leaf (const t8_forest_t forest, const t8_element_t *element, const t8_locidx_t local_tree); + /** 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_geometrical.h b/src/t8_forest/t8_forest_geometrical.h index 5921e131fc..0be289b5be 100644 --- a/src/t8_forest/t8_forest_geometrical.h +++ b/src/t8_forest/t8_forest_geometrical.h @@ -161,6 +161,17 @@ void t8_forest_element_face_normal (t8_forest_t forest, t8_locidx_t ltreeid, const t8_element_t *element, int face, double normal[3]); +/** Compute whether a given face of a given leaf in a forest lies at the domain boundary. + * This includes inner boundaries if the forest has deleted elements. + * \param [in] forest The forest. + * \param [in] local_tree A local tree of \a forest. + * \param [in] leaf A leaf element of \a local_tree in \a forest. + * \param [in] face The face number of a face of \a leaf to check. + * \return True (non-zero) if face \a face of \a leaf lies at the domain boundary. +*/ +int +t8_forest_leaf_is_boundary (const t8_forest_t forest, t8_locidx_t local_tree, const t8_element_t *leaf, int face); + T8_EXTERN_C_END (); #endif /* !T8_FOREST_GEOMETRICAL_H */ From bd7d478ff2eaa3a623dd437cd0226bc7a313ecb3 Mon Sep 17 00:00:00 2001 From: Johannes Holke Date: Wed, 5 Jun 2024 13:56:14 +0200 Subject: [PATCH 06/24] Add test for element_is_leaf --- test/CMakeLists.txt | 1 + test/Makefile.am | 10 ++ test/t8_forest/t8_gtest_element_is_leaf.cxx | 155 ++++++++++++++++++++ 3 files changed, 166 insertions(+) create mode 100644 test/t8_forest/t8_gtest_element_is_leaf.cxx diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 8ca32c8ad0..722cb371d4 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -55,6 +55,7 @@ add_t8_test( NAME t8_gtest_ghost_and_owner SOURCES t8_gtest_main.cxx t add_t8_test( NAME t8_gtest_balance SOURCES t8_gtest_main.cxx t8_forest/t8_gtest_balance.cxx ) add_t8_test( NAME t8_gtest_forest_commit SOURCES t8_gtest_main.cxx t8_forest/t8_gtest_forest_commit.cxx ) add_t8_test( NAME t8_gtest_forest_face_normal SOURCES t8_gtest_main.cxx t8_forest/t8_gtest_forest_face_normal.cxx ) +add_t8_test( NAME t8_gtest_element_is_leaf SOURCES t8_gtest_main.cxx t8_forest/t8_gtest_element_is_leaf.cxx ) add_t8_test( NAME t8_gtest_permute_hole SOURCES t8_gtest_main.cxx t8_forest_incomplete/t8_gtest_permute_hole.cxx ) add_t8_test( NAME t8_gtest_recursive SOURCES t8_gtest_main.cxx t8_forest_incomplete/t8_gtest_recursive.cxx ) diff --git a/test/Makefile.am b/test/Makefile.am index eb7fbd33ee..a49c3df9da 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -77,6 +77,7 @@ t8code_googletest_programs = \ test/t8_forest/t8_gtest_ghost_and_owner \ test/t8_forest/t8_gtest_forest_commit \ test/t8_forest/t8_gtest_balance \ + test/t8_forest/t8_gtest_element_is_leaf \ test/t8_IO/t8_gtest_vtk_reader \ test/t8_forest_incomplete/t8_gtest_permute_hole \ test/t8_forest_incomplete/t8_gtest_recursive \ @@ -293,6 +294,10 @@ test_t8_forest_t8_gtest_balance_SOURCES = \ test/t8_gtest_main.cxx \ test/t8_forest/t8_gtest_balance.cxx +test_t8_forest_t8_gtest_element_is_leaf_SOURCES = \ + test/t8_gtest_main.cxx \ + test/t8_forest/t8_gtest_element_is_leaf.cxx + test_t8_forest_incomplete_t8_gtest_permute_hole_SOURCES = \ test/t8_gtest_main.cxx \ test/t8_forest_incomplete/t8_gtest_permute_hole.cxx @@ -545,6 +550,10 @@ test_t8_forest_t8_gtest_balance_LDADD = $(t8_gtest_target_ld_add) test_t8_forest_t8_gtest_balance_LDFLAGS = $(t8_gtest_target_ld_flags) test_t8_forest_t8_gtest_balance_CPPFLAGS = $(t8_gtest_target_cpp_flags) +test_t8_forest_t8_gtest_element_is_leaf_LDADD = $(t8_gtest_target_ld_add) +test_t8_forest_t8_gtest_element_is_leaf_LDFLAGS = $(t8_gtest_target_ld_flags) +test_t8_forest_t8_gtest_element_is_leaf_CPPFLAGS = $(t8_gtest_target_cpp_flags) + test_t8_IO_t8_gtest_vtk_reader_LDADD = $(t8_gtest_target_ld_add) test_t8_IO_t8_gtest_vtk_reader_LDFLAGS = $(t8_gtest_target_ld_flags) test_t8_IO_t8_gtest_vtk_reader_CPPFLAGS = $(t8_gtest_target_cpp_flags) @@ -645,6 +654,7 @@ test_t8_forest_t8_gtest_ghost_delete_CPPFLAGS += $(t8_gtest_target_mpi_cpp_flags test_t8_forest_t8_gtest_ghost_and_owner_CPPFLAGS += $(t8_gtest_target_mpi_cpp_flags) test_t8_forest_t8_gtest_forest_commit_CPPFLAGS += $(t8_gtest_target_mpi_cpp_flags) test_t8_forest_t8_gtest_balance_CPPFLAGS += $(t8_gtest_target_mpi_cpp_flags) +test_t8_forest_t8_gtest_element_is_leaf_CPPFLAGS += $(t8_gtest_target_mpi_cpp_flags) test_t8_IO_t8_gtest_vtk_reader_CPPFLAGS += $(t8_gtest_target_mpi_cpp_flags) test_t8_forest_incomplete_t8_gtest_permute_hole_CPPFLAGS += $(t8_gtest_target_mpi_cpp_flags) test_t8_forest_incomplete_t8_gtest_recursive_CPPFLAGS += $(t8_gtest_target_mpi_cpp_flags) diff --git a/test/t8_forest/t8_gtest_element_is_leaf.cxx b/test/t8_forest/t8_gtest_element_is_leaf.cxx new file mode 100644 index 0000000000..ef1ac574a6 --- /dev/null +++ b/test/t8_forest/t8_gtest_element_is_leaf.cxx @@ -0,0 +1,155 @@ +/* + This file is part of t8code. + t8code is a C library to manage a collection (a forest) of multiple + connected adaptive space-trees of general element classes in parallel. + + Copyright (C) 2015 the developers + + t8code is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + t8code is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with t8code; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include +#include +#include +#include +#include +#include +#include "test/t8_cmesh_generator/t8_cmesh_example_sets.hxx" +#include + + +/* In this test we check the t8_forest_element_is_leaf function. + * Iterating over all cmesh test cases, we creat a uniform and an adaptive forest. + * For each forest, we check that for each leaf element t8_forest_element_is_leaf returns true + * and that it returns false for the parent and the first child. + */ + + +/* Maximum uniform level for forest. */ +#define T8_IS_LEAF_MAX_LVL 4 + +/* Adapt a forest such that always the first child of a + * family is refined and no other elements. This results in a highly + * imbalanced forest. */ +static int +t8_test_adapt_first_child (t8_forest_t forest, t8_forest_t forest_from, t8_locidx_t which_tree, t8_locidx_t lelement_id, + t8_eclass_scheme_c *ts, const int is_family, const int num_elements, t8_element_t *elements[]) +{ + T8_ASSERT (!is_family || (is_family && num_elements == ts->t8_element_num_children (elements[0]))); + + int level = ts->t8_element_level (elements[0]); + + /* we set a maximum refinement level as forest user data */ + int maxlevel = *(int *) t8_forest_get_user_data (forest); + if (level >= maxlevel) { + /* Do not refine after the maxlevel */ + return 0; + } + int child_id = ts->t8_element_child_id (elements[0]); + if (child_id == 1) { + return 1; + } + return 0; +} + + +class element_is_leaf: public testing::TestWithParam> { + protected: + + void + SetUp () override + { + /* Construct a cmesh */ + const int level = std::get<0>(GetParam ()); + cmesh = std::get<1>(GetParam ())->cmesh_create (); + if (t8_cmesh_is_empty (cmesh)) { + /* forest_commit does not support empty cmeshes, we skip this case */ + GTEST_SKIP (); + } + /* 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); + t8_forest_ref (forest); + //const int maxlevel = t8_forest_get_maxlevel (forest); + int maxlevel = 7; + const int recursive_adapt = 1; + forest_adapt = t8_forest_new_adapt (forest, t8_test_adapt_first_child, recursive_adapt, 0, &maxlevel); + } + + void + TearDown () override + { + if (t8_cmesh_is_empty (cmesh)) { + t8_cmesh_destroy (&cmesh); + } + else { + t8_forest_unref (&forest); + t8_forest_unref (&forest_adapt); + } + } + + t8_cmesh_t cmesh; + t8_forest_t forest, forest_adapt; + t8_scheme_cxx_t *scheme; +}; + + +void +t8_test_element_is_leaf_for_forest (t8_forest_t forest) +{ + const t8_locidx_t num_local_trees = t8_forest_get_num_local_trees (forest); + + for (t8_locidx_t itree = 0;itree < num_local_trees; ++itree) { + const t8_locidx_t num_elements_in_tree = t8_forest_get_tree_num_elements (forest, itree); + const t8_eclass_t tree_class = t8_forest_get_tree_class (forest, itree); + const t8_eclass_scheme_c * scheme = t8_forest_get_eclass_scheme (forest, tree_class); + /* Allocate memory to build a non-leaf element. */ + t8_element_t *not_leaf; + scheme->t8_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, + * build its parent and its first child (if they exist), and verify + * that t8_forest_element_is_leaf 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)); + /* 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)); + } + 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)); + } + } + scheme->t8_element_destroy (1, ¬_leaf); + } +} + + +TEST_P (element_is_leaf, element_is_leaf) +{ + t8_test_element_is_leaf_for_forest (forest); +} + +TEST_P (element_is_leaf, element_is_leaf_adapt) +{ + t8_test_element_is_leaf_for_forest (forest_adapt); +} + +/* TODO: Figure out how to do pretty printing for the cmesh examples when they are in a combined parameter. */ +INSTANTIATE_TEST_SUITE_P (t8_gtest_element_is_leaf, element_is_leaf, testing::Combine (testing::Range (0, T8_IS_LEAF_MAX_LVL), AllCmeshsParam)); From 967cd102a79f1988e6c6dcdc384f0a7c897acfb3 Mon Sep 17 00:00:00 2001 From: Johannes Holke Date: Wed, 5 Jun 2024 15:34:31 +0200 Subject: [PATCH 07/24] fix merge mistake --- src/t8_forest/t8_forest_cxx.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/t8_forest/t8_forest_cxx.cxx b/src/t8_forest/t8_forest_cxx.cxx index 94c552a59f..10f94dc5ce 100644 --- a/src/t8_forest/t8_forest_cxx.cxx +++ b/src/t8_forest/t8_forest_cxx.cxx @@ -2050,7 +2050,7 @@ t8_forest_element_is_leaf (const t8_forest_t forest, const t8_element_t *element * such that the element at position i has a smaller id than the given one. * If no such i exists, it returns -1. */ const t8_locidx_t search_result - = t8_forest_bin_search_lower (t8_element_array_t * elements, t8_linearidx_t element_id, int maxlevel); + = t8_forest_bin_search_lower (elements, element_id, element_level); if (search_result < 0) { /* The element was not found. */ return 0; From ef7954c3afa35f118ff0bbbb5be0a528f397d567 Mon Sep 17 00:00:00 2001 From: Johannes Holke Date: Wed, 19 Jun 2024 16:13:52 +0200 Subject: [PATCH 08/24] Add test for is boundary - WIP --- test/Makefile.am | 10 + .../t8_gtest_element_is_boundary.cxx | 212 ++++++++++++++++++ test/t8_forest/t8_gtest_element_is_leaf.cxx | 2 +- 3 files changed, 223 insertions(+), 1 deletion(-) create mode 100644 test/t8_forest/t8_gtest_element_is_boundary.cxx diff --git a/test/Makefile.am b/test/Makefile.am index a49c3df9da..5623220c92 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -78,6 +78,7 @@ t8code_googletest_programs = \ test/t8_forest/t8_gtest_forest_commit \ test/t8_forest/t8_gtest_balance \ test/t8_forest/t8_gtest_element_is_leaf \ + test/t8_forest/t8_gtest_element_is_boundary \ test/t8_IO/t8_gtest_vtk_reader \ test/t8_forest_incomplete/t8_gtest_permute_hole \ test/t8_forest_incomplete/t8_gtest_recursive \ @@ -298,6 +299,10 @@ test_t8_forest_t8_gtest_element_is_leaf_SOURCES = \ test/t8_gtest_main.cxx \ test/t8_forest/t8_gtest_element_is_leaf.cxx +test_t8_forest_t8_gtest_element_is_boundary_SOURCES = \ + test/t8_gtest_main.cxx \ + test/t8_forest/t8_gtest_element_is_boundary.cxx + test_t8_forest_incomplete_t8_gtest_permute_hole_SOURCES = \ test/t8_gtest_main.cxx \ test/t8_forest_incomplete/t8_gtest_permute_hole.cxx @@ -554,6 +559,10 @@ test_t8_forest_t8_gtest_element_is_leaf_LDADD = $(t8_gtest_target_ld_add) test_t8_forest_t8_gtest_element_is_leaf_LDFLAGS = $(t8_gtest_target_ld_flags) test_t8_forest_t8_gtest_element_is_leaf_CPPFLAGS = $(t8_gtest_target_cpp_flags) +test_t8_forest_t8_gtest_element_is_boundary_LDADD = $(t8_gtest_target_ld_add) +test_t8_forest_t8_gtest_element_is_boundary_LDFLAGS = $(t8_gtest_target_ld_flags) +test_t8_forest_t8_gtest_element_is_boundary_CPPFLAGS = $(t8_gtest_target_cpp_flags) + test_t8_IO_t8_gtest_vtk_reader_LDADD = $(t8_gtest_target_ld_add) test_t8_IO_t8_gtest_vtk_reader_LDFLAGS = $(t8_gtest_target_ld_flags) test_t8_IO_t8_gtest_vtk_reader_CPPFLAGS = $(t8_gtest_target_cpp_flags) @@ -655,6 +664,7 @@ test_t8_forest_t8_gtest_ghost_and_owner_CPPFLAGS += $(t8_gtest_target_mpi_cpp_fl test_t8_forest_t8_gtest_forest_commit_CPPFLAGS += $(t8_gtest_target_mpi_cpp_flags) test_t8_forest_t8_gtest_balance_CPPFLAGS += $(t8_gtest_target_mpi_cpp_flags) test_t8_forest_t8_gtest_element_is_leaf_CPPFLAGS += $(t8_gtest_target_mpi_cpp_flags) +test_t8_forest_t8_gtest_element_is_boundary_CPPFLAGS += $(t8_gtest_target_mpi_cpp_flags) test_t8_IO_t8_gtest_vtk_reader_CPPFLAGS += $(t8_gtest_target_mpi_cpp_flags) test_t8_forest_incomplete_t8_gtest_permute_hole_CPPFLAGS += $(t8_gtest_target_mpi_cpp_flags) test_t8_forest_incomplete_t8_gtest_recursive_CPPFLAGS += $(t8_gtest_target_mpi_cpp_flags) diff --git a/test/t8_forest/t8_gtest_element_is_boundary.cxx b/test/t8_forest/t8_gtest_element_is_boundary.cxx new file mode 100644 index 0000000000..b21b452775 --- /dev/null +++ b/test/t8_forest/t8_gtest_element_is_boundary.cxx @@ -0,0 +1,212 @@ +/* + This file is part of t8code. + t8code is a C library to manage a collection (a forest) of multiple + connected adaptive space-trees of general element classes in parallel. + + Copyright (C) 2015 the developers + + t8code is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + t8code is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with t8code; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include +#include +#include +#include +#include +#include +#include "test/t8_cmesh_generator/t8_cmesh_example_sets.hxx" +#include + +/* In this test we check the t8_forest_element_is_boundary function. + * Iterating over all cmesh test cases, we create a uniform and an adaptive forest. + * For each forest, we check that for each element t8_forest_element_is_boundary returns true + * if and only if the element is at the domain boundary. + */ + +/* Maximum uniform level for forest. */ +#define T8_IS_BOUNDARY_MAX_LVL 3 + +/* Adapt a forest such that always the first child of a + * family is refined and no other elements. This results in a highly + * imbalanced forest. */ +static int +t8_test_adapt_first_child (t8_forest_t forest, t8_forest_t forest_from, t8_locidx_t which_tree, t8_locidx_t lelement_id, + t8_eclass_scheme_c *ts, const int is_family, const int num_elements, + t8_element_t *elements[]) +{ + int level = ts->t8_element_level (elements[0]); + + /* we set a maximum refinement level as forest user data */ + int maxlevel = *(int *) t8_forest_get_user_data (forest); + if (level >= maxlevel) { + /* Do not refine after the maxlevel */ + return 0; + } + int child_id = ts->t8_element_child_id (elements[0]); + if (child_id == 1) { + return 1; + } + return 0; +} + +/* In a quad forest remove the first and fourth child of each element. + * This will reside in a forest where each element and each face is a boundary element. + * */ +static int +t8_test_adapt_quad_remove_first_and_fourth_child (t8_forest_t forest, t8_forest_t forest_from, t8_locidx_t which_tree, t8_locidx_t lelement_id, + t8_eclass_scheme_c *ts, const int is_family, const int num_elements, + t8_element_t *elements[]) +{ + /* For the purpose of this test, this function should only get called with quad elements. */ + SC_CHECK_ABORT (ts->t8_element_shape (elements[0]) == T8_ECLASS_QUAD, "Special test adapt function must only be used on quad elements.\n"); + int child_id = ts->t8_element_child_id (elements[0]); + /* Remove child_id 0 and 3, do not change any other element. */ + if (child_id == 0 || child_id == 3) { + return -1; + } + return 0; +} + + +class element_is_boundary: public testing::TestWithParam> { + protected: + void + SetUp () override + { + GTEST_SKIP (); + /* Construct a cmesh */ + const int level = std::get<0> (GetParam ()); + cmesh = std::get<1> (GetParam ())->cmesh_create (); + if (t8_cmesh_is_empty (cmesh)) { + /* forest_commit does not support empty cmeshes, we skip this case */ + GTEST_SKIP (); + } + /* 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); + t8_forest_ref (forest); + //const int maxlevel = t8_forest_get_maxlevel (forest); + int maxlevel = 7; + const int recursive_adapt = 1; + forest_adapt = t8_forest_new_adapt (forest, t8_test_adapt_first_child, recursive_adapt, 0, &maxlevel); + } + + void + TearDown () override + { + GTEST_SKIP (); + if (t8_cmesh_is_empty (cmesh)) { + t8_cmesh_destroy (&cmesh); + } + else { + t8_forest_unref (&forest); + t8_forest_unref (&forest_adapt); + } + } + + t8_cmesh_t cmesh; + t8_forest_t forest, forest_adapt; + t8_scheme_cxx_t *scheme; +}; + +void +t8_test_element_is_boundary_for_forest (t8_forest_t forest, t8_cmesh_t cmesh, const int each_element_face_is_expected_boundary) +{ + const t8_locidx_t num_local_trees = t8_forest_get_num_local_trees (forest); + + + for (t8_locidx_t itree = 0; itree < num_local_trees; ++itree) { + const t8_locidx_t num_elements_in_tree = t8_forest_get_tree_num_elements (forest, itree); + const t8_eclass_t tree_class = t8_forest_get_tree_class (forest, itree); + const t8_eclass_scheme_c *scheme = t8_forest_get_eclass_scheme (forest, tree_class); + /* Iterate over all the tree's leaf elements, check whether the leaf + * is correctly identified by t8_forest_element_is_boundary, + * build its parent and its first child (if they exist), and verify + * that t8_forest_element_is_boundary 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); + const int num_element_faces = scheme->t8_element_num_faces (leaf_element); + for (int iface = 0;iface < num_element_faces;++iface) { + /* Iterate over all faces */ + int face_is_at_boundary = 0; + if (!each_element_face_is_expected_boundary) { + /* Manually check whether this element is at the boundary */ + if (scheme->t8_element_is_root_boundary (leaf_element, iface)) { + /* This face is at a tree boundary, so it might be at the domain boundary. */ + /* We check whether the tree is at the domain boundary. */ + const int tree_face = scheme->t8_element_tree_face (leaf_element, iface); + const t8_locidx_t cmesh_local_tree = t8_forest_ltreeid_to_cmesh_ltreeid (forest, itree); + if (t8_cmesh_tree_face_is_boundary (cmesh, cmesh_local_tree, tree_face)) { + /* This element is at the domain boundary. */ + face_is_at_boundary = 1; + } + } + } + else { + /* each element and face is an expected boundary */ + face_is_at_boundary = 1; + } + if (face_is_at_boundary) { + EXPECT_TRUE (t8_forest_leaf_is_boundary (forest, itree, leaf_element, iface)); + } + else { + EXPECT_FALSE (t8_forest_leaf_is_boundary (forest, itree, leaf_element, iface)); + } + } + } + } +} + +TEST_P (element_is_boundary, element_is_boundary) +{ + GTEST_SKIP (); + //t8_test_element_is_boundary_for_forest (forest, cmesh, 0); +} + +TEST_P (element_is_boundary, element_is_boundary_adapt) +{ + GTEST_SKIP (); + t8_test_element_is_boundary_for_forest (forest_adapt, cmesh, 0); +} + +TEST (element_is_boundary, quad_forest_with_holes) +{ + /* Create a 10 x 5 2D brick cmesh, periodic in x direction. */ + t8_cmesh_t cmesh = t8_cmesh_new_brick_2d (10, 5, 1, 0, sc_MPI_COMM_WORLD); + + t8_scheme_cxx_t *scheme = t8_scheme_new_default_cxx (); + t8_forest_t forest = t8_forest_new_uniform (cmesh, scheme, T8_IS_BOUNDARY_MAX_LVL, 0, sc_MPI_COMM_WORLD); + t8_forest_t forest_adapt = t8_forest_new_adapt (forest, t8_test_adapt_quad_remove_first_and_fourth_child, 0, 0, NULL); + + t8_forest_write_vtk (forest_adapt, "test_quad_w_holes"); + + t8_test_element_is_boundary_for_forest (forest_adapt, cmesh, 1); + t8_forest_unref (&forest_adapt); +} + +/* 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) { + std::string name = std::string ("Level_") + std::to_string (std::get<0> (info.param)); + std::string cmesh_name; + std::get<1> (info.param)->param_to_string (cmesh_name); + name += std::string ("_") + cmesh_name; + return name; + }; + +INSTANTIATE_TEST_SUITE_P (t8_gtest_element_is_boundary, element_is_boundary, + testing::Combine (testing::Range (0, T8_IS_BOUNDARY_MAX_LVL), AllCmeshsParam), + pretty_print_level_and_cmesh_params); diff --git a/test/t8_forest/t8_gtest_element_is_leaf.cxx b/test/t8_forest/t8_gtest_element_is_leaf.cxx index a0ef57b0f8..82aff9b4fd 100644 --- a/test/t8_forest/t8_gtest_element_is_leaf.cxx +++ b/test/t8_forest/t8_gtest_element_is_leaf.cxx @@ -146,7 +146,7 @@ TEST_P (element_is_leaf, element_is_leaf_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 a55765fcbb6cf909b775472d9d59b7003ddda582 Mon Sep 17 00:00:00 2001 From: Johannes Holke Date: Wed, 19 Jun 2024 16:22:47 +0200 Subject: [PATCH 09/24] Add error message when trying to compute with holes --- src/t8_forest/t8_forest_cxx.cxx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/t8_forest/t8_forest_cxx.cxx b/src/t8_forest/t8_forest_cxx.cxx index 0e4036e3f5..3a9dde3513 100644 --- a/src/t8_forest/t8_forest_cxx.cxx +++ b/src/t8_forest/t8_forest_cxx.cxx @@ -2102,7 +2102,10 @@ t8_forest_leaf_is_boundary (const t8_forest_t forest, t8_locidx_t local_tree, co /* The forest has no holes, thus the leaf cannot be a boundary leaf. */ return 0; } - /* we need to compute the face neihgbors to know whether the element is a boundary element. */ + else { + SC_ABORT ("This forest has holes and a computation of boundary elements is not supported. Once https://github.com/DLR-AMR/t8code/issues/825 is resolved, the function will be available.\n"); + } + /* we need to compute the face neighbors to know whether the element is a boundary element. */ const int is_balanced = t8_forest_is_balanced (forest); int num_neighbors; t8_element_t **neighbor_leaves; From 626f492867a4432490d07497918cd000d231c631 Mon Sep 17 00:00:00 2001 From: Johannes Holke Date: Wed, 19 Jun 2024 16:23:05 +0200 Subject: [PATCH 10/24] Add test with holes but it is skipped for now --- test/t8_forest/t8_gtest_element_is_boundary.cxx | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/test/t8_forest/t8_gtest_element_is_boundary.cxx b/test/t8_forest/t8_gtest_element_is_boundary.cxx index b21b452775..390b693f2c 100644 --- a/test/t8_forest/t8_gtest_element_is_boundary.cxx +++ b/test/t8_forest/t8_gtest_element_is_boundary.cxx @@ -74,7 +74,7 @@ t8_test_adapt_quad_remove_first_and_fourth_child (t8_forest_t forest, t8_forest_ int child_id = ts->t8_element_child_id (elements[0]); /* Remove child_id 0 and 3, do not change any other element. */ if (child_id == 0 || child_id == 3) { - return -1; + return -2; } return 0; } @@ -171,24 +171,28 @@ t8_test_element_is_boundary_for_forest (t8_forest_t forest, t8_cmesh_t cmesh, co TEST_P (element_is_boundary, element_is_boundary) { - GTEST_SKIP (); - //t8_test_element_is_boundary_for_forest (forest, cmesh, 0); + t8_test_element_is_boundary_for_forest (forest, cmesh, 0); } TEST_P (element_is_boundary, element_is_boundary_adapt) { - GTEST_SKIP (); t8_test_element_is_boundary_for_forest (forest_adapt, cmesh, 0); } TEST (element_is_boundary, quad_forest_with_holes) { + /* This test is deactivated as long as Ghost does not work in combination + * with deleted elements. + * Once this is fixed, reactivate this test. + * See https://github.com/DLR-AMR/t8code/issues/825 + */ + GTEST_SKIP (); /* Create a 10 x 5 2D brick cmesh, periodic in x direction. */ t8_cmesh_t cmesh = t8_cmesh_new_brick_2d (10, 5, 1, 0, sc_MPI_COMM_WORLD); t8_scheme_cxx_t *scheme = t8_scheme_new_default_cxx (); t8_forest_t forest = t8_forest_new_uniform (cmesh, scheme, T8_IS_BOUNDARY_MAX_LVL, 0, sc_MPI_COMM_WORLD); - t8_forest_t forest_adapt = t8_forest_new_adapt (forest, t8_test_adapt_quad_remove_first_and_fourth_child, 0, 0, NULL); + t8_forest_t forest_adapt = t8_forest_new_adapt (forest, t8_test_adapt_quad_remove_first_and_fourth_child, 0, 1, NULL); t8_forest_write_vtk (forest_adapt, "test_quad_w_holes"); From 47077ee21963d72a6c00a407b32ecb35f20e06f0 Mon Sep 17 00:00:00 2001 From: Johannes Holke Date: Wed, 19 Jun 2024 16:26:22 +0200 Subject: [PATCH 11/24] Add test to CMakeLists --- test/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 722cb371d4..917142c9c2 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -56,6 +56,7 @@ add_t8_test( NAME t8_gtest_balance SOURCES t8_gtest_main.cxx t add_t8_test( NAME t8_gtest_forest_commit SOURCES t8_gtest_main.cxx t8_forest/t8_gtest_forest_commit.cxx ) add_t8_test( NAME t8_gtest_forest_face_normal SOURCES t8_gtest_main.cxx t8_forest/t8_gtest_forest_face_normal.cxx ) add_t8_test( NAME t8_gtest_element_is_leaf SOURCES t8_gtest_main.cxx t8_forest/t8_gtest_element_is_leaf.cxx ) +add_t8_test( NAME t8_gtest_element_is_boudary SOURCES t8_gtest_main.cxx t8_forest/t8_gtest_element_is_boundary.cxx ) add_t8_test( NAME t8_gtest_permute_hole SOURCES t8_gtest_main.cxx t8_forest_incomplete/t8_gtest_permute_hole.cxx ) add_t8_test( NAME t8_gtest_recursive SOURCES t8_gtest_main.cxx t8_forest_incomplete/t8_gtest_recursive.cxx ) From 7aea37a8f3d3a8e6ea54452a0661e97555e6bed5 Mon Sep 17 00:00:00 2001 From: "Dreyer, Lukas" Date: Thu, 20 Jun 2024 11:26:08 +0200 Subject: [PATCH 12/24] Fix indentation and spelling --- src/t8_forest/t8_forest_cxx.cxx | 6 ++--- test/CMakeLists.txt | 2 +- .../t8_gtest_element_is_boundary.cxx | 24 +++++++++---------- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/t8_forest/t8_forest_cxx.cxx b/src/t8_forest/t8_forest_cxx.cxx index 3a9dde3513..c83c2dd29e 100644 --- a/src/t8_forest/t8_forest_cxx.cxx +++ b/src/t8_forest/t8_forest_cxx.cxx @@ -2058,8 +2058,7 @@ t8_forest_element_is_leaf (const t8_forest_t forest, const t8_element_t *element * The search returns the largest index i, * such that the element at position i has a smaller id than the given one. * If no such i exists, it returns -1. */ - const t8_locidx_t search_result - = t8_forest_bin_search_lower (elements, element_id, element_level); + const t8_locidx_t search_result = t8_forest_bin_search_lower (elements, element_id, element_level); if (search_result < 0) { /* The element was not found. */ return 0; @@ -2103,7 +2102,8 @@ t8_forest_leaf_is_boundary (const t8_forest_t forest, t8_locidx_t local_tree, co return 0; } else { - SC_ABORT ("This forest has holes and a computation of boundary elements is not supported. Once https://github.com/DLR-AMR/t8code/issues/825 is resolved, the function will be available.\n"); + SC_ABORT ("This forest has holes and a computation of boundary elements is not supported. Once " + "https://github.com/DLR-AMR/t8code/issues/825 is resolved, the function will be available.\n"); } /* we need to compute the face neighbors to know whether the element is a boundary element. */ const int is_balanced = t8_forest_is_balanced (forest); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 917142c9c2..e145bf2041 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -56,7 +56,7 @@ add_t8_test( NAME t8_gtest_balance SOURCES t8_gtest_main.cxx t add_t8_test( NAME t8_gtest_forest_commit SOURCES t8_gtest_main.cxx t8_forest/t8_gtest_forest_commit.cxx ) add_t8_test( NAME t8_gtest_forest_face_normal SOURCES t8_gtest_main.cxx t8_forest/t8_gtest_forest_face_normal.cxx ) add_t8_test( NAME t8_gtest_element_is_leaf SOURCES t8_gtest_main.cxx t8_forest/t8_gtest_element_is_leaf.cxx ) -add_t8_test( NAME t8_gtest_element_is_boudary SOURCES t8_gtest_main.cxx t8_forest/t8_gtest_element_is_boundary.cxx ) +add_t8_test( NAME t8_gtest_element_is_boundary SOURCES t8_gtest_main.cxx t8_forest/t8_gtest_element_is_boundary.cxx ) add_t8_test( NAME t8_gtest_permute_hole SOURCES t8_gtest_main.cxx t8_forest_incomplete/t8_gtest_permute_hole.cxx ) add_t8_test( NAME t8_gtest_recursive SOURCES t8_gtest_main.cxx t8_forest_incomplete/t8_gtest_recursive.cxx ) diff --git a/test/t8_forest/t8_gtest_element_is_boundary.cxx b/test/t8_forest/t8_gtest_element_is_boundary.cxx index 390b693f2c..135c51d673 100644 --- a/test/t8_forest/t8_gtest_element_is_boundary.cxx +++ b/test/t8_forest/t8_gtest_element_is_boundary.cxx @@ -65,12 +65,13 @@ t8_test_adapt_first_child (t8_forest_t forest, t8_forest_t forest_from, t8_locid * This will reside in a forest where each element and each face is a boundary element. * */ static int -t8_test_adapt_quad_remove_first_and_fourth_child (t8_forest_t forest, t8_forest_t forest_from, t8_locidx_t which_tree, t8_locidx_t lelement_id, - t8_eclass_scheme_c *ts, const int is_family, const int num_elements, - t8_element_t *elements[]) +t8_test_adapt_quad_remove_first_and_fourth_child (t8_forest_t forest, t8_forest_t forest_from, t8_locidx_t which_tree, + t8_locidx_t lelement_id, t8_eclass_scheme_c *ts, const int is_family, + const int num_elements, t8_element_t *elements[]) { /* For the purpose of this test, this function should only get called with quad elements. */ - SC_CHECK_ABORT (ts->t8_element_shape (elements[0]) == T8_ECLASS_QUAD, "Special test adapt function must only be used on quad elements.\n"); + SC_CHECK_ABORT (ts->t8_element_shape (elements[0]) == T8_ECLASS_QUAD, + "Special test adapt function must only be used on quad elements.\n"); int child_id = ts->t8_element_child_id (elements[0]); /* Remove child_id 0 and 3, do not change any other element. */ if (child_id == 0 || child_id == 3) { @@ -79,13 +80,12 @@ t8_test_adapt_quad_remove_first_and_fourth_child (t8_forest_t forest, t8_forest_ return 0; } - class element_is_boundary: public testing::TestWithParam> { protected: void SetUp () override { - GTEST_SKIP (); + GTEST_SKIP (); /* Construct a cmesh */ const int level = std::get<0> (GetParam ()); cmesh = std::get<1> (GetParam ())->cmesh_create (); @@ -106,7 +106,7 @@ class element_is_boundary: public testing::TestWithParamt8_element_num_faces (leaf_element); - for (int iface = 0;iface < num_element_faces;++iface) { + for (int iface = 0; iface < num_element_faces; ++iface) { /* Iterate over all faces */ int face_is_at_boundary = 0; if (!each_element_face_is_expected_boundary) { @@ -189,11 +189,11 @@ TEST (element_is_boundary, quad_forest_with_holes) GTEST_SKIP (); /* Create a 10 x 5 2D brick cmesh, periodic in x direction. */ t8_cmesh_t cmesh = t8_cmesh_new_brick_2d (10, 5, 1, 0, sc_MPI_COMM_WORLD); - + t8_scheme_cxx_t *scheme = t8_scheme_new_default_cxx (); t8_forest_t forest = t8_forest_new_uniform (cmesh, scheme, T8_IS_BOUNDARY_MAX_LVL, 0, sc_MPI_COMM_WORLD); t8_forest_t forest_adapt = t8_forest_new_adapt (forest, t8_test_adapt_quad_remove_first_and_fourth_child, 0, 1, NULL); - + t8_forest_write_vtk (forest_adapt, "test_quad_w_holes"); t8_test_element_is_boundary_for_forest (forest_adapt, cmesh, 1); From a40c02459170cf5e857e2be3119e36bffbf65eb6 Mon Sep 17 00:00:00 2001 From: Johannes Holke Date: Thu, 18 Jul 2024 15:16:37 +0200 Subject: [PATCH 13/24] Update test/t8_forest/t8_gtest_element_is_boundary.cxx Co-authored-by: lukasdreyer <58432628+lukasdreyer@users.noreply.github.com> --- test/t8_forest/t8_gtest_element_is_boundary.cxx | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/test/t8_forest/t8_gtest_element_is_boundary.cxx b/test/t8_forest/t8_gtest_element_is_boundary.cxx index 135c51d673..d29f494b73 100644 --- a/test/t8_forest/t8_gtest_element_is_boundary.cxx +++ b/test/t8_forest/t8_gtest_element_is_boundary.cxx @@ -158,12 +158,7 @@ t8_test_element_is_boundary_for_forest (t8_forest_t forest, t8_cmesh_t cmesh, /* each element and face is an expected boundary */ face_is_at_boundary = 1; } - if (face_is_at_boundary) { - EXPECT_TRUE (t8_forest_leaf_is_boundary (forest, itree, leaf_element, iface)); - } - else { - EXPECT_FALSE (t8_forest_leaf_is_boundary (forest, itree, leaf_element, iface)); - } + EXPECT_EQ (t8_forest_leaf_is_boundary (forest, itree, leaf_element, iface), face_is_at_boundary); } } } From c060042c7a88d74271632a85f4eb41ab15174563 Mon Sep 17 00:00:00 2001 From: Johannes Holke Date: Thu, 18 Jul 2024 15:16:48 +0200 Subject: [PATCH 14/24] Update test/t8_forest/t8_gtest_element_is_boundary.cxx Co-authored-by: lukasdreyer <58432628+lukasdreyer@users.noreply.github.com> --- test/t8_forest/t8_gtest_element_is_boundary.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/t8_forest/t8_gtest_element_is_boundary.cxx b/test/t8_forest/t8_gtest_element_is_boundary.cxx index d29f494b73..9de9ed2b29 100644 --- a/test/t8_forest/t8_gtest_element_is_boundary.cxx +++ b/test/t8_forest/t8_gtest_element_is_boundary.cxx @@ -3,7 +3,7 @@ t8code is a C library to manage a collection (a forest) of multiple connected adaptive space-trees of general element classes in parallel. - Copyright (C) 2015 the developers + Copyright (C) 2024 the developers t8code is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by From 018083c72fbc59ac72699154407d7948621823f7 Mon Sep 17 00:00:00 2001 From: Johannes Holke Date: Thu, 18 Jul 2024 16:07:08 +0200 Subject: [PATCH 15/24] Add a new test with known boundaries --- .../t8_gtest_element_is_boundary.cxx | 48 +++++++++++++++++-- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/test/t8_forest/t8_gtest_element_is_boundary.cxx b/test/t8_forest/t8_gtest_element_is_boundary.cxx index 9de9ed2b29..5f3b22cb5f 100644 --- a/test/t8_forest/t8_gtest_element_is_boundary.cxx +++ b/test/t8_forest/t8_gtest_element_is_boundary.cxx @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include "test/t8_cmesh_generator/t8_cmesh_example_sets.hxx" #include @@ -85,7 +85,6 @@ class element_is_boundary: public testing::TestWithParam (GetParam ()); cmesh = std::get<1> (GetParam ())->cmesh_create (); @@ -106,7 +105,6 @@ class element_is_boundary: public testing::TestWithParam { +protected: + void + SetUp () override + { + eclass = GetParam(); + cmesh = t8_cmesh_new_from_class (eclass, sc_MPI_COMM_WORLD); + t8_scheme_cxx_t *scheme = t8_scheme_new_default_cxx (); + forest = t8_forest_new_uniform (cmesh, scheme, 0, 0, sc_MPI_COMM_WORLD); + } + + void + TearDown () override + { + t8_forest_unref (&forest); + } + + t8_cmesh_t cmesh; + t8_forest_t forest; + t8_eclass_t eclass; +}; + +/* For a level 0 forest of a single class cmesh all faces should + * be at the boundary. */ +TEST_P (element_is_boundary_known_boundary, level_0) { + const t8_locidx_t num_elements = t8_forest_get_local_num_elements (forest); + if (num_elements > 0) { + T8_ASSERT (num_elements == 1); + const t8_element_t * element = t8_forest_get_element_in_tree (forest, 0, 0); + const t8_eclass_scheme_c * scheme = t8_forest_get_eclass_scheme (forest, eclass); + const int num_faces = scheme->t8_element_num_faces (element); + for (int iface = 0;iface < num_faces;++iface) { + EXPECT_TRUE (t8_forest_leaf_is_boundary (forest, 0, element, iface)); + } + } +} + /* 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 @@ -209,3 +247,7 @@ auto pretty_print_level_and_cmesh_params INSTANTIATE_TEST_SUITE_P (t8_gtest_element_is_boundary, element_is_boundary, testing::Combine (testing::Range (0, T8_IS_BOUNDARY_MAX_LVL), AllCmeshsParam), pretty_print_level_and_cmesh_params); + + +INSTANTIATE_TEST_SUITE_P (t8_gtest_element_is_boundary, element_is_boundary_known_boundary, + AllEclasses, print_eclass); \ No newline at end of file From 039be05c540bc94d4e1253a7596f69e42336f404 Mon Sep 17 00:00:00 2001 From: Johannes Holke Date: Thu, 18 Jul 2024 16:26:41 +0200 Subject: [PATCH 16/24] comment --- src/t8_forest/t8_forest.cxx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/t8_forest/t8_forest.cxx b/src/t8_forest/t8_forest.cxx index 85c655c839..eec4ce695e 100644 --- a/src/t8_forest/t8_forest.cxx +++ b/src/t8_forest/t8_forest.cxx @@ -2091,8 +2091,11 @@ t8_forest_leaf_is_boundary (const t8_forest_t forest, t8_locidx_t local_tree, co const int is_root_boundary = scheme->t8_element_is_root_boundary (leaf, face); if (is_root_boundary) { - /* This leaf is at a tree's boundary. It is*/ - const int cmesh_face = scheme->t8_element_tree_face (leaf, face); + /* This leaf is at a tree's boundary. + * If the respective tree face is at the domain boundary, + * then the element is as well. + * If the tree face is not at the domain boundary, the element's face + * could still be at an inner boundary. */ const int cmesh_face = scheme->t8_element_tree_face (leaf, face); const t8_cmesh_t cmesh = t8_forest_get_cmesh (forest); const t8_locidx_t cmesh_local_tree = t8_forest_ltreeid_to_cmesh_ltreeid (forest, local_tree); int tree_boundary = t8_cmesh_tree_face_is_boundary (cmesh, cmesh_local_tree, cmesh_face); From 72e64fcf5ddc44c6d370b7b38984b30b6fea93dc Mon Sep 17 00:00:00 2001 From: Johannes Holke Date: Thu, 18 Jul 2024 16:27:16 +0200 Subject: [PATCH 17/24] indent --- .../t8_gtest_element_is_boundary.cxx | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/test/t8_forest/t8_gtest_element_is_boundary.cxx b/test/t8_forest/t8_gtest_element_is_boundary.cxx index 5f3b22cb5f..3fc62bdb0d 100644 --- a/test/t8_forest/t8_gtest_element_is_boundary.cxx +++ b/test/t8_forest/t8_gtest_element_is_boundary.cxx @@ -197,11 +197,11 @@ TEST (element_is_boundary, quad_forest_with_holes) * builds a uniform level 0 forest on it. * For the single element in that forest all faces lie on the boundary. */ class element_is_boundary_known_boundary: public testing::TestWithParam { -protected: + protected: void SetUp () override { - eclass = GetParam(); + eclass = GetParam (); cmesh = t8_cmesh_new_from_class (eclass, sc_MPI_COMM_WORLD); t8_scheme_cxx_t *scheme = t8_scheme_new_default_cxx (); forest = t8_forest_new_uniform (cmesh, scheme, 0, 0, sc_MPI_COMM_WORLD); @@ -214,20 +214,21 @@ class element_is_boundary_known_boundary: public testing::TestWithParam 0) { T8_ASSERT (num_elements == 1); - const t8_element_t * element = t8_forest_get_element_in_tree (forest, 0, 0); - const t8_eclass_scheme_c * scheme = t8_forest_get_eclass_scheme (forest, eclass); + const t8_element_t *element = t8_forest_get_element_in_tree (forest, 0, 0); + const t8_eclass_scheme_c *scheme = t8_forest_get_eclass_scheme (forest, eclass); const int num_faces = scheme->t8_element_num_faces (element); - for (int iface = 0;iface < num_faces;++iface) { + for (int iface = 0; iface < num_faces; ++iface) { EXPECT_TRUE (t8_forest_leaf_is_boundary (forest, 0, element, iface)); } } @@ -248,6 +249,4 @@ INSTANTIATE_TEST_SUITE_P (t8_gtest_element_is_boundary, element_is_boundary, testing::Combine (testing::Range (0, T8_IS_BOUNDARY_MAX_LVL), AllCmeshsParam), pretty_print_level_and_cmesh_params); - -INSTANTIATE_TEST_SUITE_P (t8_gtest_element_is_boundary, element_is_boundary_known_boundary, - AllEclasses, print_eclass); \ No newline at end of file +INSTANTIATE_TEST_SUITE_P (t8_gtest_element_is_boundary, element_is_boundary_known_boundary, AllEclasses, print_eclass); \ No newline at end of file From f711584db6a2e76730baf9a6094e0ff0d713a4c8 Mon Sep 17 00:00:00 2001 From: Johannes Holke Date: Thu, 18 Jul 2024 16:29:03 +0200 Subject: [PATCH 18/24] indent --- src/t8_forest/t8_forest.cxx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/t8_forest/t8_forest.cxx b/src/t8_forest/t8_forest.cxx index eec4ce695e..4f90153b4f 100644 --- a/src/t8_forest/t8_forest.cxx +++ b/src/t8_forest/t8_forest.cxx @@ -2095,7 +2095,8 @@ t8_forest_leaf_is_boundary (const t8_forest_t forest, t8_locidx_t local_tree, co * If the respective tree face is at the domain boundary, * then the element is as well. * If the tree face is not at the domain boundary, the element's face - * could still be at an inner boundary. */ const int cmesh_face = scheme->t8_element_tree_face (leaf, face); + * could still be at an inner boundary. */ + const int cmesh_face = scheme->t8_element_tree_face (leaf, face); const t8_cmesh_t cmesh = t8_forest_get_cmesh (forest); const t8_locidx_t cmesh_local_tree = t8_forest_ltreeid_to_cmesh_ltreeid (forest, local_tree); int tree_boundary = t8_cmesh_tree_face_is_boundary (cmesh, cmesh_local_tree, cmesh_face); From 28dbad89781aeb5d1a6cf9a5bfa5d8f6ae0bc5ce Mon Sep 17 00:00:00 2001 From: Johannes Holke Date: Fri, 16 Aug 2024 14:46:18 +0200 Subject: [PATCH 19/24] indent --- test/t8_forest/t8_gtest_element_is_boundary.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/t8_forest/t8_gtest_element_is_boundary.cxx b/test/t8_forest/t8_gtest_element_is_boundary.cxx index 3fc62bdb0d..74a091977c 100644 --- a/test/t8_forest/t8_gtest_element_is_boundary.cxx +++ b/test/t8_forest/t8_gtest_element_is_boundary.cxx @@ -249,4 +249,4 @@ INSTANTIATE_TEST_SUITE_P (t8_gtest_element_is_boundary, element_is_boundary, testing::Combine (testing::Range (0, T8_IS_BOUNDARY_MAX_LVL), AllCmeshsParam), pretty_print_level_and_cmesh_params); -INSTANTIATE_TEST_SUITE_P (t8_gtest_element_is_boundary, element_is_boundary_known_boundary, AllEclasses, print_eclass); \ No newline at end of file +INSTANTIATE_TEST_SUITE_P (t8_gtest_element_is_boundary, element_is_boundary_known_boundary, AllEclasses, print_eclass); From 6c10153f629168b74ef2af26ce19fcc1703c9719 Mon Sep 17 00:00:00 2001 From: Johannes Holke Date: Wed, 16 Oct 2024 16:07:46 +0200 Subject: [PATCH 20/24] deleted old commented code --- test/t8_forest/t8_gtest_element_is_boundary.cxx | 1 - 1 file changed, 1 deletion(-) diff --git a/test/t8_forest/t8_gtest_element_is_boundary.cxx b/test/t8_forest/t8_gtest_element_is_boundary.cxx index 74a091977c..2b5529d723 100644 --- a/test/t8_forest/t8_gtest_element_is_boundary.cxx +++ b/test/t8_forest/t8_gtest_element_is_boundary.cxx @@ -96,7 +96,6 @@ class element_is_boundary: public testing::TestWithParam Date: Wed, 16 Oct 2024 16:12:23 +0200 Subject: [PATCH 21/24] Remove holes else block and add descriptive comment --- src/t8_forest/t8_forest.cxx | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/t8_forest/t8_forest.cxx b/src/t8_forest/t8_forest.cxx index 4000b11c72..34592f67d8 100644 --- a/src/t8_forest/t8_forest.cxx +++ b/src/t8_forest/t8_forest.cxx @@ -2112,10 +2112,17 @@ t8_forest_leaf_is_boundary (const t8_forest_t forest, t8_locidx_t local_tree, co /* The forest has no holes, thus the leaf cannot be a boundary leaf. */ return 0; } - else { - SC_ABORT ("This forest has holes and a computation of boundary elements is not supported. Once " - "https://github.com/DLR-AMR/t8code/issues/825 is resolved, the function will be available.\n"); - } + + /* + * The remaining code handles the case that the forest has holes and the element may thus + * be an inner boundary. + * This case is not yet support due to issue #825. Hence, we currently abort. + * Once the issue is resolved, the abort message can be removed and the code should work. + * */ + + SC_ABORT ("This forest has holes and a computation of boundary elements is not supported. Once " + "https://github.com/DLR-AMR/t8code/issues/825 is resolved, the function will be available.\n"); + /* we need to compute the face neighbors to know whether the element is a boundary element. */ const int is_balanced = t8_forest_is_balanced (forest); int num_neighbors; From f391fc450e138da0e3114a35d41645912517d152 Mon Sep 17 00:00:00 2001 From: Johannes Holke Date: Fri, 18 Oct 2024 11:17:44 +0200 Subject: [PATCH 22/24] needed to update cmesh in test. Not doing so caused an abort since the original cmesh was deleted. --- test/t8_forest/t8_gtest_element_is_boundary.cxx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/t8_forest/t8_gtest_element_is_boundary.cxx b/test/t8_forest/t8_gtest_element_is_boundary.cxx index 2b5529d723..51fbba8310 100644 --- a/test/t8_forest/t8_gtest_element_is_boundary.cxx +++ b/test/t8_forest/t8_gtest_element_is_boundary.cxx @@ -99,6 +99,10 @@ class element_is_boundary: public testing::TestWithParam Date: Fri, 18 Oct 2024 11:20:29 +0200 Subject: [PATCH 23/24] Add parallel test case version --- test/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 1820bade23..d5fc58bad2 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -103,6 +103,7 @@ add_t8_test( NAME t8_gtest_forest_commit_parallel SOURCES t8_gtest_main.cx 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_boundary_serial SOURCES t8_gtest_main.cxx t8_forest/t8_gtest_element_is_boundary.cxx ) +add_t8_test( NAME t8_gtest_element_is_boundary_parallel SOURCES t8_gtest_main.cxx t8_forest/t8_gtest_element_is_boundary.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 c6c3e21ed071315379653d00e621ac2a981825f6 Mon Sep 17 00:00:00 2001 From: Johannes Holke Date: Fri, 18 Oct 2024 13:14:22 +0200 Subject: [PATCH 24/24] remove serial test --- test/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index d5fc58bad2..b4fb049c97 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -102,7 +102,6 @@ add_t8_test( NAME t8_gtest_balance_parallel SOURCES t8_gtest_main.cx 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_boundary_serial SOURCES t8_gtest_main.cxx t8_forest/t8_gtest_element_is_boundary.cxx ) add_t8_test( NAME t8_gtest_element_is_boundary_parallel SOURCES t8_gtest_main.cxx t8_forest/t8_gtest_element_is_boundary.cxx ) add_t8_test( NAME t8_gtest_partition_data_parallel SOURCES t8_gtest_main.cxx t8_forest/t8_gtest_partition_data.cxx )