From ffc3f84a5b4d932867eaa28997068e45856cb32b Mon Sep 17 00:00:00 2001 From: Benedict Geihe Date: Thu, 16 Apr 2026 10:38:27 +0200 Subject: [PATCH 1/7] add new test --- test/CMakeLists.txt | 1 + .../t8_gtest_element_neighbor_eclass.cxx | 112 ++++++++++++++++++ 2 files changed, 113 insertions(+) create mode 100644 test/t8_forest/t8_gtest_element_neighbor_eclass.cxx diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 6aecf7f639..a945ee321b 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -160,6 +160,7 @@ add_t8_cpp_test( NAME t8_gtest_partition_data_parallel SOURCES t8_for add_t8_cpp_test( NAME t8_gtest_set_partition_offset_parallel SOURCES t8_forest/t8_gtest_set_partition_offset.cxx ) add_t8_cpp_test( NAME t8_gtest_partition_for_coarsening_parallel SOURCES t8_forest/t8_gtest_partition_for_coarsening.cxx ) add_t8_cpp_test( NAME t8_gtest_weighted_partitioning_parallel SOURCES t8_forest/t8_gtest_weighted_partitioning.cxx ) +add_t8_cpp_test( NAME t8_gtest_element_neighbor_eclass_parallel SOURCES t8_forest/t8_gtest_element_neighbor_eclass.cxx ) add_t8_cpp_test( NAME t8_gtest_element_is_leaf_parallel SOURCES t8_forest/t8_gtest_element_is_leaf.cxx t8_gtest_adapt_callbacks.cxx ) add_t8_cpp_test( NAME t8_gtest_permute_hole_serial SOURCES t8_forest_incomplete/t8_gtest_permute_hole.cxx ) diff --git a/test/t8_forest/t8_gtest_element_neighbor_eclass.cxx b/test/t8_forest/t8_gtest_element_neighbor_eclass.cxx new file mode 100644 index 0000000000..34c8e7456a --- /dev/null +++ b/test/t8_forest/t8_gtest_element_neighbor_eclass.cxx @@ -0,0 +1,112 @@ +/* + 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 +#include +#include +#include +#include +#include +#include +#include + +struct element_neighbor_eclass: public testing::TestWithParam +{ + protected: + void + SetUp () override + { + const int level = 1; + const int scheme_id = GetParam (); + scheme = create_from_scheme_id (scheme_id); + + // Construct a hybrid coarse mesh + t8_cmesh_t cmesh = t8_cmesh_new_full_hybrid (sc_MPI_COMM_WORLD); + + // Build a uniform forest + forest = t8_forest_new_uniform (cmesh, scheme, level, 0, sc_MPI_COMM_WORLD); + + // Go through all the trees in the forest and store their eclass + tree_eclass.resize( t8_forest_get_num_local_trees (forest) ); + for (t8_locidx_t itree = 0; itree < t8_forest_get_num_local_trees (forest); itree++) { + tree_eclass[itree] = t8_forest_get_tree_class (forest, itree); + std::cerr << "tree " << itree << " eclass " << tree_eclass[itree] << std::endl; + } + } + + void + TearDown () override + { + t8_forest_unref (&forest); + } + + t8_forest_t forest; + const t8_scheme *scheme; + std::vector tree_eclass; +}; + +TEST_P (element_neighbor_eclass, test_half_neighbors) +{ + // TODO: print scheme? + //t8_debugf ("Testing element neighbor eclass with eclass %s.\n", t8_eclass_to_string[eclass]); + + // Iterate over all trees + // TODO: ghost trees? + for (t8_locidx_t itree = 0; itree < t8_forest_get_num_local_trees (forest); itree++) { + const t8_eclass_t tree_class = t8_forest_get_eclass (forest, itree); + + // Iterate over all elements + for (t8_locidx_t ielement = 0; ielement < t8_forest_get_tree_num_leaf_elements (forest, itree); ielement++) { + const t8_element_t *element = t8_forest_get_leaf_element_in_tree (forest, itree, ielement); + + // Iterate over all faces + for (int iface = 0; iface < scheme->element_get_num_faces (tree_class, element); iface++) { + + // Get neighbor tree id + t8_cmesh_t cmesh = t8_forest_get_cmesh (forest); + t8_locidx_t const ltreeid_in_cmesh = t8_forest_ltreeid_to_cmesh_ltreeid (forest, itree); + t8_locidx_t const cmesh_dual_itree = t8_cmesh_get_face_neighbor (cmesh, ltreeid_in_cmesh, iface, nullptr, nullptr); + t8_locidx_t const forest_dual_itree = t8_forest_cmesh_ltreeid_to_ltreeid(forest, cmesh_dual_itree); + + // Get the eclass of the face neighbor + const t8_eclass_t neigh_class = t8_forest_element_neighbor_eclass (forest, itree, element, iface); + + if (forest_dual_itree > -1) { + // Compare + EXPECT_EQ (neigh_class, tree_eclass[forest_dual_itree]); + } + else { + // TODO: ? + } + } + } + } +} + +INSTANTIATE_TEST_SUITE_P (t8_gtest_element_neighbor_eclass, element_neighbor_eclass, AllSchemeCollections); From 6d71d8f692dd127d1e76363f944be6bd60147592 Mon Sep 17 00:00:00 2001 From: Benedict Geihe Date: Wed, 6 May 2026 08:12:12 +0200 Subject: [PATCH 2/7] make test run --- .../t8_gtest_element_neighbor_eclass.cxx | 98 +++++++++++-------- 1 file changed, 57 insertions(+), 41 deletions(-) diff --git a/test/t8_forest/t8_gtest_element_neighbor_eclass.cxx b/test/t8_forest/t8_gtest_element_neighbor_eclass.cxx index 34c8e7456a..9a07e0a394 100644 --- a/test/t8_forest/t8_gtest_element_neighbor_eclass.cxx +++ b/test/t8_forest/t8_gtest_element_neighbor_eclass.cxx @@ -21,20 +21,12 @@ */ #include -#include -#include - -#include -#include -#include -#include -#include -#include -#include + +#include + +#include #include -#include #include -#include struct element_neighbor_eclass: public testing::TestWithParam { @@ -43,20 +35,28 @@ struct element_neighbor_eclass: public testing::TestWithParam SetUp () override { const int level = 1; + const bool do_ghost = true; const int scheme_id = GetParam (); scheme = create_from_scheme_id (scheme_id); - + // Construct a hybrid coarse mesh - t8_cmesh_t cmesh = t8_cmesh_new_full_hybrid (sc_MPI_COMM_WORLD); + cmesh = t8_cmesh_new_full_hybrid (sc_MPI_COMM_WORLD); // Build a uniform forest - forest = t8_forest_new_uniform (cmesh, scheme, level, 0, sc_MPI_COMM_WORLD); + forest = t8_forest_new_uniform (cmesh, scheme, level, do_ghost, sc_MPI_COMM_WORLD); // Go through all the trees in the forest and store their eclass - tree_eclass.resize( t8_forest_get_num_local_trees (forest) ); - for (t8_locidx_t itree = 0; itree < t8_forest_get_num_local_trees (forest); itree++) { - tree_eclass[itree] = t8_forest_get_tree_class (forest, itree); - std::cerr << "tree " << itree << " eclass " << tree_eclass[itree] << std::endl; + tree_eclass_ref.resize (t8_cmesh_get_num_local_trees (cmesh)); + for (t8_locidx_t itree = 0; itree < t8_cmesh_get_num_local_trees (cmesh); itree++) { + tree_eclass_ref[itree] = t8_cmesh_get_tree_class (cmesh, itree); + std::cerr << "tree " << itree << " eclass " << tree_eclass_ref[itree] << std::endl; + } + + // Likewise for all ghost trees + ghost_eclass_ref.resize (t8_cmesh_get_num_ghosts (cmesh)); + for (t8_locidx_t ighost = 0; ighost < t8_cmesh_get_num_ghosts (cmesh); ighost++) { + ghost_eclass_ref[ighost] = t8_cmesh_get_ghost_class (cmesh, ighost); + std::cerr << "ghost " << ighost << " eclass " << tree_eclass_ref[ighost] << std::endl; } } @@ -66,43 +66,59 @@ struct element_neighbor_eclass: public testing::TestWithParam t8_forest_unref (&forest); } + t8_cmesh_t cmesh; t8_forest_t forest; const t8_scheme *scheme; - std::vector tree_eclass; + std::vector tree_eclass_ref; + std::vector ghost_eclass_ref; }; TEST_P (element_neighbor_eclass, test_half_neighbors) { - // TODO: print scheme? - //t8_debugf ("Testing element neighbor eclass with eclass %s.\n", t8_eclass_to_string[eclass]); + // Iterate over all trees (local and ghosts) + const t8_locidx_t num_local_trees = t8_forest_get_num_local_trees (forest); + const t8_locidx_t num_ghost_trees = t8_forest_get_num_ghost_trees (forest); - // Iterate over all trees - // TODO: ghost trees? - for (t8_locidx_t itree = 0; itree < t8_forest_get_num_local_trees (forest); itree++) { - const t8_eclass_t tree_class = t8_forest_get_eclass (forest, itree); + for (t8_locidx_t itree = 0; itree < num_local_trees + num_ghost_trees; itree++) { - // Iterate over all elements - for (t8_locidx_t ielement = 0; ielement < t8_forest_get_tree_num_leaf_elements (forest, itree); ielement++) { - const t8_element_t *element = t8_forest_get_leaf_element_in_tree (forest, itree, ielement); + const t8_eclass_t tree_eclass = t8_forest_get_tree_class (forest, itree); + const bool is_ghost = itree >= num_local_trees; + const t8_locidx_t ghost_tree_id = itree - num_local_trees; + const t8_element_array_t *leaf_elements = is_ghost ? t8_forest_ghost_get_tree_leaf_elements (forest, ghost_tree_id) + : t8_forest_get_tree_leaf_element_array (forest, itree); + const t8_locidx_t num_leaves = t8_element_array_get_count (leaf_elements); + const t8_locidx_t ltreeid_in_cmesh = t8_forest_ltreeid_to_cmesh_ltreeid (forest, itree); - // Iterate over all faces - for (int iface = 0; iface < scheme->element_get_num_faces (tree_class, element); iface++) { + // Iterate over all leaf elements + for (t8_locidx_t ileaf = 0; ileaf < num_leaves; ++ileaf) { - // Get neighbor tree id - t8_cmesh_t cmesh = t8_forest_get_cmesh (forest); - t8_locidx_t const ltreeid_in_cmesh = t8_forest_ltreeid_to_cmesh_ltreeid (forest, itree); - t8_locidx_t const cmesh_dual_itree = t8_cmesh_get_face_neighbor (cmesh, ltreeid_in_cmesh, iface, nullptr, nullptr); - t8_locidx_t const forest_dual_itree = t8_forest_cmesh_ltreeid_to_ltreeid(forest, cmesh_dual_itree); + const t8_element_t *element = t8_element_array_index_locidx (leaf_elements, ileaf); + + // Iterate over all faces + for (int iface = 0; iface < scheme->element_get_num_faces (tree_eclass, element); iface++) { - // Get the eclass of the face neighbor + // Get the eclass of the face neighbor (function to test) const t8_eclass_t neigh_class = t8_forest_element_neighbor_eclass (forest, itree, element, iface); - if (forest_dual_itree > -1) { - // Compare - EXPECT_EQ (neigh_class, tree_eclass[forest_dual_itree]); + // Inside the current tree + if (!scheme->element_is_root_boundary (tree_eclass, element, iface)) { + // We expect to get the same eclass + EXPECT_EQ (neigh_class, tree_eclass); } + // Crossing a tree boundary else { - // TODO: ? + // Get neighbor tree id + const int tree_face = scheme->element_get_tree_face (tree_eclass, element, iface); + t8_locidx_t const cmesh_dual_itree + = t8_cmesh_get_face_neighbor (cmesh, ltreeid_in_cmesh, tree_face, nullptr, nullptr); + + if (cmesh_dual_itree < 0) { + // No neighbor + EXPECT_EQ (neigh_class, T8_ECLASS_INVALID); + } + else { + EXPECT_EQ (neigh_class, tree_eclass_ref[cmesh_dual_itree]); + } } } } From c91fc2263a361b40c98c4f1a829c2dc94f674457 Mon Sep 17 00:00:00 2001 From: Benedict Geihe Date: Wed, 20 May 2026 09:55:04 +0200 Subject: [PATCH 3/7] typo --- src/t8_cmesh/t8_cmesh_examples.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/t8_cmesh/t8_cmesh_examples.h b/src/t8_cmesh/t8_cmesh_examples.h index 66bb1303b8..f66e6c8932 100644 --- a/src/t8_cmesh/t8_cmesh_examples.h +++ b/src/t8_cmesh/t8_cmesh_examples.h @@ -345,7 +345,7 @@ t8_cmesh_new_hybrid_gate (sc_MPI_Comm comm); t8_cmesh_t t8_cmesh_new_hybrid_gate_deformed (sc_MPI_Comm comm); -/** Construct a full hybrig cmesh, with 1 hex, 1 pyra, 1 prism and 1 tet +/** Construct a full hybrid cmesh, with 1 hex, 1 pyra, 1 prism and 1 tet * This cmesh is used for testing and debugging. * \param [in] comm The MPI communicator used to commit the cmesh. * \return A committed and replicated hybrid cmesh of 4 trees. From a8f3ae42f89cbd5e9e8f6e3670a7a0df28588fbc Mon Sep 17 00:00:00 2001 From: Benedict Geihe Date: Wed, 20 May 2026 09:55:55 +0200 Subject: [PATCH 4/7] test level 0..4 --- test/t8_forest/t8_gtest_element_neighbor_eclass.cxx | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/test/t8_forest/t8_gtest_element_neighbor_eclass.cxx b/test/t8_forest/t8_gtest_element_neighbor_eclass.cxx index 9a07e0a394..7f05f89ad5 100644 --- a/test/t8_forest/t8_gtest_element_neighbor_eclass.cxx +++ b/test/t8_forest/t8_gtest_element_neighbor_eclass.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) 2026 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 @@ -28,16 +28,16 @@ #include #include -struct element_neighbor_eclass: public testing::TestWithParam +struct element_neighbor_eclass: public testing::TestWithParam> { protected: void SetUp () override { - const int level = 1; const bool do_ghost = true; - const int scheme_id = GetParam (); + const int scheme_id = std::get<0> (GetParam ()); scheme = create_from_scheme_id (scheme_id); + const int level = std::get<1> (GetParam ()); // Construct a hybrid coarse mesh cmesh = t8_cmesh_new_full_hybrid (sc_MPI_COMM_WORLD); @@ -125,4 +125,5 @@ TEST_P (element_neighbor_eclass, test_half_neighbors) } } -INSTANTIATE_TEST_SUITE_P (t8_gtest_element_neighbor_eclass, element_neighbor_eclass, AllSchemeCollections); +INSTANTIATE_TEST_SUITE_P (t8_gtest_element_neighbor_eclass, element_neighbor_eclass, + testing::Combine (AllSchemeCollections, testing::Range (0, 4))); From 36f516f2be93f18b951753e5e00053ef418d1dd6 Mon Sep 17 00:00:00 2001 From: Benedict Geihe Date: Wed, 20 May 2026 10:58:39 +0200 Subject: [PATCH 5/7] add ghost eclass check --- .../t8_gtest_element_neighbor_eclass.cxx | 30 +++++++------------ 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/test/t8_forest/t8_gtest_element_neighbor_eclass.cxx b/test/t8_forest/t8_gtest_element_neighbor_eclass.cxx index 7f05f89ad5..ce4af6450b 100644 --- a/test/t8_forest/t8_gtest_element_neighbor_eclass.cxx +++ b/test/t8_forest/t8_gtest_element_neighbor_eclass.cxx @@ -44,20 +44,6 @@ struct element_neighbor_eclass: public testing::TestWithParam tree_eclass_ref; - std::vector ghost_eclass_ref; }; TEST_P (element_neighbor_eclass, test_half_neighbors) @@ -109,15 +93,23 @@ TEST_P (element_neighbor_eclass, test_half_neighbors) else { // Get neighbor tree id const int tree_face = scheme->element_get_tree_face (tree_eclass, element, iface); - t8_locidx_t const cmesh_dual_itree + t8_locidx_t const neighbor_id = t8_cmesh_get_face_neighbor (cmesh, ltreeid_in_cmesh, tree_face, nullptr, nullptr); - if (cmesh_dual_itree < 0) { + if (neighbor_id < 0) { // No neighbor EXPECT_EQ (neigh_class, T8_ECLASS_INVALID); } else { - EXPECT_EQ (neigh_class, tree_eclass_ref[cmesh_dual_itree]); + // Neighbor + const bool neighbor_is_ghost = t8_cmesh_treeid_is_ghost (cmesh, neighbor_id); + if (!neighbor_is_ghost) { + EXPECT_EQ (neigh_class, t8_cmesh_get_tree_class (cmesh, neighbor_id)); + } + else { + const t8_locidx_t lghost_neighbor_id = neighbor_id - t8_cmesh_get_num_local_trees (cmesh); + EXPECT_EQ (neigh_class, t8_cmesh_get_ghost_class (cmesh, lghost_neighbor_id)); + } } } } From 43c744a951645439b6f18a7941c95fc62eaa632c Mon Sep 17 00:00:00 2001 From: Benedict Geihe Date: Wed, 20 May 2026 14:39:18 +0200 Subject: [PATCH 6/7] only store the forest in the testing struct --- test/t8_forest/t8_gtest_element_neighbor_eclass.cxx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/t8_forest/t8_gtest_element_neighbor_eclass.cxx b/test/t8_forest/t8_gtest_element_neighbor_eclass.cxx index ce4af6450b..833eec446a 100644 --- a/test/t8_forest/t8_gtest_element_neighbor_eclass.cxx +++ b/test/t8_forest/t8_gtest_element_neighbor_eclass.cxx @@ -36,11 +36,11 @@ struct element_neighbor_eclass: public testing::TestWithParam (GetParam ()); - scheme = create_from_scheme_id (scheme_id); + const t8_scheme *scheme = create_from_scheme_id (scheme_id); const int level = std::get<1> (GetParam ()); // Construct a hybrid coarse mesh - cmesh = t8_cmesh_new_full_hybrid (sc_MPI_COMM_WORLD); + const t8_cmesh_t cmesh = t8_cmesh_new_full_hybrid (sc_MPI_COMM_WORLD); // Build a uniform forest forest = t8_forest_new_uniform (cmesh, scheme, level, do_ghost, sc_MPI_COMM_WORLD); @@ -52,17 +52,17 @@ struct element_neighbor_eclass: public testing::TestWithParamelement_get_tree_face (tree_eclass, element, iface); - t8_locidx_t const neighbor_id + const t8_locidx_t neighbor_id = t8_cmesh_get_face_neighbor (cmesh, ltreeid_in_cmesh, tree_face, nullptr, nullptr); if (neighbor_id < 0) { From 61b88470149cf22a87bb0fb9de4b8de251fe312f Mon Sep 17 00:00:00 2001 From: Benedict Geihe Date: Wed, 20 May 2026 15:12:46 +0200 Subject: [PATCH 7/7] add partition to full_hybrid cmesh --- src/t8_cmesh/t8_cmesh_examples.cxx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/t8_cmesh/t8_cmesh_examples.cxx b/src/t8_cmesh/t8_cmesh_examples.cxx index 42e6be850b..ae1f9a66a2 100644 --- a/src/t8_cmesh/t8_cmesh_examples.cxx +++ b/src/t8_cmesh/t8_cmesh_examples.cxx @@ -2628,6 +2628,8 @@ t8_cmesh_new_full_hybrid (sc_MPI_Comm comm) t8_cmesh_set_tree_vertices (cmesh, 3, vertices, 6); + t8_cmesh_examples_compute_and_set_partition_range (cmesh, 4, 3, comm); + t8_cmesh_commit (cmesh, comm); return cmesh; }