From 2c56595888ff4b83374de44e1d25961361d69a90 Mon Sep 17 00:00:00 2001 From: Johannes Holke Date: Wed, 12 Nov 2025 15:13:55 +0100 Subject: [PATCH 01/10] Start implementation of ancestor_face helper function --- src/t8_schemes/t8_scheme_helpers.hxx | 46 ++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/src/t8_schemes/t8_scheme_helpers.hxx b/src/t8_schemes/t8_scheme_helpers.hxx index 318cc68eab..e509d2886d 100644 --- a/src/t8_schemes/t8_scheme_helpers.hxx +++ b/src/t8_schemes/t8_scheme_helpers.hxx @@ -63,6 +63,52 @@ 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. + * // TODO Check this note. is it still true? + */ + inline 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 + { + + const int element_level = scheme->element_get_level (tree_class, 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; + auto underlying_impl = this->underlying (); // Reference to the underlying scheme implementation + 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; + 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_neigh, temp_dual_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_neigh, parent); + temp_element = parent; + } + underlying_impl->element_destroy (1, &parent); + return temp_face; + } }; #endif /* T8_SCHEME_HELPERS_HXX */ From d67a93b9309084e8d8935004b148f3c8624240d9 Mon Sep 17 00:00:00 2001 From: Johannes Holke Date: Wed, 12 Nov 2025 15:29:25 +0100 Subject: [PATCH 02/10] add declaration of ancestor_face function to scheme --- src/t8_schemes/t8_scheme.hxx | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/t8_schemes/t8_scheme.hxx b/src/t8_schemes/t8_scheme.hxx index d892a95527..ed241505db 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. + */ + inline 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. From c89b612ffbc39523ab41b2e50f4e07e2a382b35d Mon Sep 17 00:00:00 2001 From: Johannes Holke Date: Wed, 12 Nov 2025 15:30:05 +0100 Subject: [PATCH 03/10] Change access to underlying impl. Not a pointer --- src/t8_schemes/t8_scheme_helpers.hxx | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/t8_schemes/t8_scheme_helpers.hxx b/src/t8_schemes/t8_scheme_helpers.hxx index e509d2886d..032a0e563c 100644 --- a/src/t8_schemes/t8_scheme_helpers.hxx +++ b/src/t8_schemes/t8_scheme_helpers.hxx @@ -75,14 +75,13 @@ class t8_scheme_helpers: public t8_crtp_basic { * \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. - * // TODO Check this note. is it still true? */ inline 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 + 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 = scheme->element_get_level (tree_class, element); + 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 @@ -90,23 +89,22 @@ class t8_scheme_helpers: public t8_crtp_basic { } // Allocate memory for a temporary element. t8_element_t *parent; - auto underlying_impl = this->underlying (); // Reference to the underlying scheme implementation - underlying_impl->element_new (1, &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; + 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_neigh, temp_dual_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); + underlying_impl.element_destroy (1, &parent); return -1; } - underlying_impl->element_get_parent (temp_neigh, parent); + underlying_impl.element_get_parent (temp_element, parent); temp_element = parent; } - underlying_impl->element_destroy (1, &parent); + underlying_impl.element_destroy (1, &parent); return temp_face; } }; From 70158694815d4824ecbc145554a3989f8c97361e Mon Sep 17 00:00:00 2001 From: Johannes Holke Date: Wed, 12 Nov 2025 15:30:35 +0100 Subject: [PATCH 04/10] Extend parent face test with two calls of ancestor face function --- test/t8_schemes/t8_gtest_child_parent_face.cxx | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test/t8_schemes/t8_gtest_child_parent_face.cxx b/test/t8_schemes/t8_gtest_child_parent_face.cxx index d0cc9415db..6377efe6b4 100644 --- a/test/t8_schemes/t8_gtest_child_parent_face.cxx +++ b/test/t8_schemes/t8_gtest_child_parent_face.cxx @@ -27,6 +27,9 @@ #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 */ + class class_child_parent_face: public TestDFS { void check_element () override @@ -49,6 +52,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 anc_face_same_level + = scheme->element_face_get_ancestor_face (eclass, children[ifacechild], element_level + 1, childface); + EXPECT_EQ (childface, anc_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 anc_face_one_level_higher + = scheme->element_face_get_ancestor_face (eclass, children[ifacechild], element_level, childface); + EXPECT_EQ (iface, anc_face_one_level_higher); } scheme->element_destroy (eclass, num_face_children, children); T8_TESTSUITE_FREE (children); From 058776f705b6b7fb45d3a0d5d61239e9f811f75e Mon Sep 17 00:00:00 2001 From: Johannes Holke Date: Mon, 17 Nov 2025 10:34:22 +0100 Subject: [PATCH 05/10] rename variables since typo script doesnt like them --- test/t8_schemes/t8_gtest_child_parent_face.cxx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/t8_schemes/t8_gtest_child_parent_face.cxx b/test/t8_schemes/t8_gtest_child_parent_face.cxx index 6377efe6b4..40ff2564a1 100644 --- a/test/t8_schemes/t8_gtest_child_parent_face.cxx +++ b/test/t8_schemes/t8_gtest_child_parent_face.cxx @@ -55,14 +55,14 @@ class class_child_parent_face: public TestDFS { 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 anc_face_same_level + const int ancestor_face_same_level = scheme->element_face_get_ancestor_face (eclass, children[ifacechild], element_level + 1, childface); - EXPECT_EQ (childface, anc_face_same_level); + 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 anc_face_one_level_higher + const int ancestor_face_one_level_higher = scheme->element_face_get_ancestor_face (eclass, children[ifacechild], element_level, childface); - EXPECT_EQ (iface, anc_face_one_level_higher); + EXPECT_EQ (iface, ancestor_face_one_level_higher); } scheme->element_destroy (eclass, num_face_children, children); T8_TESTSUITE_FREE (children); From 6bb176e4624d7e204069b39edcff996d3a6e692e Mon Sep 17 00:00:00 2001 From: Johannes Holke Date: Mon, 1 Dec 2025 12:56:10 +0100 Subject: [PATCH 06/10] Update src/t8_schemes/t8_scheme.hxx Co-authored-by: David Knapp --- src/t8_schemes/t8_scheme.hxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/t8_schemes/t8_scheme.hxx b/src/t8_schemes/t8_scheme.hxx index 55268826ad..4cd850ad4f 100644 --- a/src/t8_schemes/t8_scheme.hxx +++ b/src/t8_schemes/t8_scheme.hxx @@ -640,7 +640,7 @@ class t8_scheme { * the face number of this face. Otherwise -1. * \note For the root element this function always returns \a face. */ - inline int + 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 { From 1217441d1a90e5510d0f8b75c9aab15c6a9bfbe4 Mon Sep 17 00:00:00 2001 From: Johannes Holke Date: Mon, 1 Dec 2025 13:03:52 +0100 Subject: [PATCH 07/10] reference issue in TODO comment --- test/t8_schemes/t8_gtest_child_parent_face.cxx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/t8_schemes/t8_gtest_child_parent_face.cxx b/test/t8_schemes/t8_gtest_child_parent_face.cxx index 40ff2564a1..e392f521dd 100644 --- a/test/t8_schemes/t8_gtest_child_parent_face.cxx +++ b/test/t8_schemes/t8_gtest_child_parent_face.cxx @@ -28,7 +28,8 @@ #include /* TODO: extend this test or new test. On each level, - * go multiple levels below and check against ancestor face */ + * 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 From 91db711de01750cc1e8d62c7a7a2a7af63110248 Mon Sep 17 00:00:00 2001 From: Johannes Holke Date: Wed, 14 Jan 2026 16:00:56 +0100 Subject: [PATCH 08/10] Change declaration to constexpr to match scheme --- src/t8_schemes/t8_scheme.hxx | 2 +- src/t8_schemes/t8_scheme_helpers.hxx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/t8_schemes/t8_scheme.hxx b/src/t8_schemes/t8_scheme.hxx index 9b14f519a0..5d77cd4fc5 100644 --- a/src/t8_schemes/t8_scheme.hxx +++ b/src/t8_schemes/t8_scheme.hxx @@ -632,7 +632,7 @@ class t8_scheme { * 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] 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. diff --git a/src/t8_schemes/t8_scheme_helpers.hxx b/src/t8_schemes/t8_scheme_helpers.hxx index 032a0e563c..e5a2dad827 100644 --- a/src/t8_schemes/t8_scheme_helpers.hxx +++ b/src/t8_schemes/t8_scheme_helpers.hxx @@ -76,7 +76,7 @@ class t8_scheme_helpers: public t8_crtp_basic { * the face number of this face. Otherwise -1. * \note For the root element this function always returns \a face. */ - inline int + inline constexpr 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 From a8f2c583bcb62010d33a671cd36f27ff6ee5bb8f Mon Sep 17 00:00:00 2001 From: Johannes Holke Date: Wed, 14 Jan 2026 16:05:41 +0100 Subject: [PATCH 09/10] remove constexpr change since using [] is not constexpr and causes compiler error --- src/t8_schemes/t8_scheme.hxx | 2 +- src/t8_schemes/t8_scheme_helpers.hxx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/t8_schemes/t8_scheme.hxx b/src/t8_schemes/t8_scheme.hxx index 5d77cd4fc5..0e03fbf2f7 100644 --- a/src/t8_schemes/t8_scheme.hxx +++ b/src/t8_schemes/t8_scheme.hxx @@ -640,7 +640,7 @@ class t8_scheme { * the face number of this face. Otherwise -1. * \note For the root element this function always returns \a face. */ - constexpr int + 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 { diff --git a/src/t8_schemes/t8_scheme_helpers.hxx b/src/t8_schemes/t8_scheme_helpers.hxx index e5a2dad827..032a0e563c 100644 --- a/src/t8_schemes/t8_scheme_helpers.hxx +++ b/src/t8_schemes/t8_scheme_helpers.hxx @@ -76,7 +76,7 @@ class t8_scheme_helpers: public t8_crtp_basic { * the face number of this face. Otherwise -1. * \note For the root element this function always returns \a face. */ - inline constexpr int + 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 From 16f9f1c61c2beb66c381912f9f24390e125a76a6 Mon Sep 17 00:00:00 2001 From: Johannes Holke Date: Wed, 14 Jan 2026 16:17:38 +0100 Subject: [PATCH 10/10] fix documentation --- src/t8_schemes/t8_scheme_helpers.hxx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/t8_schemes/t8_scheme_helpers.hxx b/src/t8_schemes/t8_scheme_helpers.hxx index 032a0e563c..b8e22758a7 100644 --- a/src/t8_schemes/t8_scheme_helpers.hxx +++ b/src/t8_schemes/t8_scheme_helpers.hxx @@ -68,7 +68,6 @@ class t8_scheme_helpers: public t8_crtp_basic { * 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.