diff --git a/src/t8_schemes/t8_scheme.hxx b/src/t8_schemes/t8_scheme.hxx index 7e5f7aabb5..9b14f519a0 100644 --- a/src/t8_schemes/t8_scheme.hxx +++ b/src/t8_schemes/t8_scheme.hxx @@ -628,6 +628,27 @@ class t8_scheme { eclass_schemes[tree_class]); }; + /** Given a face of an element and a level coarser than (or equal to) + * the element's level, return the face number + * of the ancestor of the element that matches the element's face. Or return -1 if + * no face of the ancestor matches the face. + * \param [in] tree_class The eclass of the current tree. + * \param [in] element The element. + * \param [in] ancestor_level A refinement level smaller than (or equal to) \a element's level. + * \param [in] face Then number of a face of \a element. + * \return If \a face of \a element is a subface of a face of \a element's ancestor at level \a ancestor_level, + * the face number of this face. Otherwise -1. + * \note For the root element this function always returns \a face. + */ + constexpr int + element_face_get_ancestor_face (const t8_eclass_t tree_class, const t8_element_t *element, const int ancestor_level, + const int face) const + { + return std::visit ( + [&] (auto &&scheme) { return scheme.element_face_get_ancestor_face (element, ancestor_level, face); }, + eclass_schemes[tree_class]); + } + /** Given an element and a face of this element. If the face lies on the * tree boundary, return the face number of the tree face. * If not the return value is arbitrary. diff --git a/src/t8_schemes/t8_scheme_helpers.hxx b/src/t8_schemes/t8_scheme_helpers.hxx index 318cc68eab..032a0e563c 100644 --- a/src/t8_schemes/t8_scheme_helpers.hxx +++ b/src/t8_schemes/t8_scheme_helpers.hxx @@ -63,6 +63,50 @@ class t8_scheme_helpers: public t8_crtp_basic { { return TEclass; } + + /** Given a face of an element and a level coarser than (or equal to) + * the element's level, return the face number + * of the ancestor of the element that matches the element's face. Or return -1 if + * no face of the ancestor matches the face. + * \param [in] tree_class The eclass of the current tree. + * \param [in] element The element. + * \param [in] ancestor_level A refinement level smaller than (or equal to) \a element's level. + * \param [in] face Then number of a face of \a element. + * \return If \a face of \a element is a subface of a face of \a element's ancestor at level \a ancestor_level, + * the face number of this face. Otherwise -1. + * \note For the root element this function always returns \a face. + */ + inline int + element_face_get_ancestor_face (const t8_element_t *element, const int ancestor_level, const int face) const + { + auto underlying_impl = this->underlying (); // Reference to the underlying scheme implementation + + const int element_level = underlying_impl.element_get_level (element); + T8_ASSERT (element_level >= ancestor_level); + if (element_level == ancestor_level) { + // On the same level, the return value is the face itself + return face; + } + // Allocate memory for a temporary element. + t8_element_t *parent; + underlying_impl.element_new (1, &parent); + // Pointer to a temoporary element, that will move up the refinement hierarchy + const t8_element_t *temp_element = element; + int temp_face = face; + for (int ilevel = element_level; ilevel > ancestor_level; --ilevel) { + // Go one level up in the refinement hierarchy with the face + temp_face = underlying_impl.element_face_get_parent_face (temp_element, temp_face); + if (temp_face == -1) { + // This face is not a subface of an ancestor face. + underlying_impl.element_destroy (1, &parent); + return -1; + } + underlying_impl.element_get_parent (temp_element, parent); + temp_element = parent; + } + underlying_impl.element_destroy (1, &parent); + return temp_face; + } }; #endif /* T8_SCHEME_HELPERS_HXX */ diff --git a/test/t8_schemes/t8_gtest_child_parent_face.cxx b/test/t8_schemes/t8_gtest_child_parent_face.cxx index d0cc9415db..e392f521dd 100644 --- a/test/t8_schemes/t8_gtest_child_parent_face.cxx +++ b/test/t8_schemes/t8_gtest_child_parent_face.cxx @@ -27,6 +27,10 @@ #include "t8_gtest_dfs_base.hxx" #include +/* TODO: extend this test or new test. On each level, + * go multiple levels below and check against ancestor face. + * See https://github.com/DLR-AMR/t8code/issues/2011 */ + class class_child_parent_face: public TestDFS { void check_element () override @@ -49,6 +53,17 @@ class class_child_parent_face: public TestDFS { const int parentface = scheme->element_face_get_parent_face (eclass, children[ifacechild], childface); /* Check, that this is equal to the face that we started with */ EXPECT_EQ (iface, parentface); + const int element_level = scheme->element_get_level (eclass, element); + // Check the ancestor face function when input is the child and the level of the child. + // We expect the output face to be the input face + const int ancestor_face_same_level + = scheme->element_face_get_ancestor_face (eclass, children[ifacechild], element_level + 1, childface); + EXPECT_EQ (childface, ancestor_face_same_level); + // Check the ancestor face function when input is the element level/ + // We expect the output face to be the original face + const int ancestor_face_one_level_higher + = scheme->element_face_get_ancestor_face (eclass, children[ifacechild], element_level, childface); + EXPECT_EQ (iface, ancestor_face_one_level_higher); } scheme->element_destroy (eclass, num_face_children, children); T8_TESTSUITE_FREE (children);