diff --git a/src/t8_cmesh.h b/src/t8_cmesh.h index 7e89711312..a24d4dcb90 100644 --- a/src/t8_cmesh.h +++ b/src/t8_cmesh.h @@ -682,6 +682,18 @@ t8_locidx_t t8_cmesh_get_face_neighbor (const t8_cmesh_t cmesh, const t8_locidx_t ltreeid, const int face, int *dual_face, int *orientation); +/** + * Given a local tree id (of a local tree or ghost tree) and a face compute the eclass of the + * tree's face neighbor. + * + * \param [in] cmesh The cmesh to be considered. + * \param [in] ltreeid The local id of a tree or a ghost. + * \param [in] face A face number of the tree/ghost. + * \return The eclass of a neighbor tree of \a ltreeid across \a face. T8_ECLASS_INVALID if no neighbor exists. + */ +t8_eclass_t +t8_cmesh_get_tree_face_neighbor_eclass (const t8_cmesh_t cmesh, const t8_locidx_t ltreeid, const int face); + /** Print the collected statistics from a cmesh profile. * \param [in] cmesh The cmesh. * diff --git a/src/t8_cmesh/t8_cmesh.cxx b/src/t8_cmesh/t8_cmesh.cxx index 177a147d96..6539b71d7c 100644 --- a/src/t8_cmesh/t8_cmesh.cxx +++ b/src/t8_cmesh/t8_cmesh.cxx @@ -1198,6 +1198,36 @@ t8_cmesh_get_face_neighbor (const t8_cmesh_t cmesh, const t8_locidx_t ltreeid, c return face_neigh; } +t8_eclass_t +t8_cmesh_get_tree_face_neighbor_eclass (const t8_cmesh_t cmesh, const t8_locidx_t ltreeid, const int face) +{ + T8_ASSERT (t8_cmesh_is_committed (cmesh)); + T8_ASSERT (t8_cmesh_treeid_is_local_tree (cmesh, ltreeid) || t8_cmesh_treeid_is_ghost (cmesh, ltreeid)); + T8_ASSERT (0 <= face); + + const t8_locidx_t neighbor_id = t8_cmesh_get_face_neighbor (cmesh, ltreeid, face, NULL, NULL); + if (neighbor_id < 0) { + // No neighbor was found. + return T8_ECLASS_INVALID; + } + const bool neighbor_is_ghost = t8_cmesh_treeid_is_ghost (cmesh, neighbor_id); + if (!neighbor_is_ghost) { + // Neighbor was found and is a local tree + return t8_cmesh_get_tree_class (cmesh, neighbor_id); + } + else { + // Neighbor was found and is a ghost. + // Translate ltreeid from range num_local_trees <= ltreeid < num_local_trees + num_ghost_trees + // into 0 <= lghost_id < num_ghost_trees + const t8_locidx_t lghost_neihgbor_id = neighbor_id - t8_cmesh_get_num_local_trees (cmesh); + + t8_debugf ("in: %i out: %i, num t: %i num g: %i\n", neighbor_id, lghost_neihgbor_id, + t8_cmesh_get_num_local_trees (cmesh), t8_cmesh_get_num_ghosts (cmesh)); + // Look up ghost tree class + return t8_cmesh_get_ghost_class (cmesh, lghost_neihgbor_id); + } +} + void t8_cmesh_print_profile (const t8_cmesh_t cmesh) { diff --git a/test/t8_cmesh/t8_gtest_cmesh_face_is_boundary.cxx b/test/t8_cmesh/t8_gtest_cmesh_face_is_boundary.cxx index 379e0e9b78..640806686c 100644 --- a/test/t8_cmesh/t8_gtest_cmesh_face_is_boundary.cxx +++ b/test/t8_cmesh/t8_gtest_cmesh_face_is_boundary.cxx @@ -61,6 +61,9 @@ TEST_P (cmesh_face_boundary_one_tree, check_face_is_boundary_one_tree) ASSERT_TRUE (t8_cmesh_tree_face_is_boundary (cmesh, 0, iface)) << "Face is not detected as a boundary"; ASSERT_LT (t8_cmesh_get_face_neighbor (cmesh, 0, iface, NULL, NULL), 0) << "Face neighbor on boundary face detected"; + const t8_eclass_t should_be_invalid = t8_cmesh_get_tree_face_neighbor_eclass (cmesh, 0, iface); + EXPECT_EQ (should_be_invalid, T8_ECLASS_INVALID) + << "eclass of non-existing face neighbor should be invalid but is not."; } } @@ -162,6 +165,12 @@ TEST_P (cmesh_face_boundary_two_trees, check_face_is_boundary_two_trees) << "Face neighbor on boundary face detected. Tree 0 face " << checkface << "."; ASSERT_LT (t8_cmesh_get_face_neighbor (cmesh, 1, checkface, NULL, NULL), 0) << "Face neighbor on boundary face detected. Tree 1 face " << checkface << "."; + const t8_eclass_t should_be_invalid_tree0 = t8_cmesh_get_tree_face_neighbor_eclass (cmesh, 0, checkface); + EXPECT_EQ (should_be_invalid_tree0, T8_ECLASS_INVALID) + << "eclass of non-existing face neighbor should be invalid but is not."; + const t8_eclass_t should_be_invalid_tree1 = t8_cmesh_get_tree_face_neighbor_eclass (cmesh, 1, checkface); + EXPECT_EQ (should_be_invalid_tree1, T8_ECLASS_INVALID) + << "eclass of non-existing face neighbor should be invalid but is not."; } else { /* checkface == iface @@ -178,6 +187,9 @@ TEST_P (cmesh_face_boundary_two_trees, check_face_is_boundary_two_trees) ASSERT_TRUE (face_neighbor) << "Wrong face neighbor computed. Expected 1 got" << face_neighbor << "."; ASSERT_EQ (dual_face, checkface) << "Wrong dual face. Expected " << checkface << " got " << dual_face << "."; ASSERT_EQ (orientation, 0) << "Wrong orientation. Expected 0 got " << orientation << "."; + // Check t8_cmesh_get_tree_face_neighbor_eclass + const t8_eclass_t neighbor_class_tree0 = t8_cmesh_get_tree_face_neighbor_eclass (cmesh, 0, iface); + EXPECT_EQ (neighbor_class_tree0, eclass) << "Wrong eclass of face neighbor computed."; /* Check that tree 1 face is not a boundary */ ASSERT_FALSE (t8_cmesh_tree_face_is_boundary (cmesh, 1, checkface)) << "Face is wrongly detected as a boundary."; @@ -191,6 +203,9 @@ TEST_P (cmesh_face_boundary_two_trees, check_face_is_boundary_two_trees) ASSERT_EQ (face_neighbor, 0) << "Wrong face neighbor computed. Expected 0 got " << face_neighbor << "."; ASSERT_EQ (dual_face, checkface) << "Wrong dual face. Expected " << checkface << " got " << dual_face << "."; ASSERT_EQ (orientation, 0) << "Wrong orientation. Expected 0 got " << orientation << "."; + // Check t8_cmesh_get_tree_face_neighbor_eclass + const t8_eclass_t neighbor_class_tree1 = t8_cmesh_get_tree_face_neighbor_eclass (cmesh, 1, checkface); + EXPECT_EQ (neighbor_class_tree1, eclass) << "Wrong eclass of face neighbor computed."; } } t8_cmesh_destroy (&cmesh); diff --git a/test/t8_cmesh/t8_gtest_cmesh_readmshfile.cxx b/test/t8_cmesh/t8_gtest_cmesh_readmshfile.cxx index 12ae892bd2..52a41b3f16 100644 --- a/test/t8_cmesh/t8_gtest_cmesh_readmshfile.cxx +++ b/test/t8_cmesh/t8_gtest_cmesh_readmshfile.cxx @@ -83,6 +83,11 @@ t8_supported_msh_file (t8_cmesh_t cmesh) ltree_id = t8_cmesh_get_face_neighbor (cmesh, ltree_it, i, NULL, NULL); ASSERT_EQ (ltree_id, face_neigh_elem[ltree_it][i]) << "The face neighbor element in the example test file was not read correctly."; + const t8_eclass_t neighbor_eclass = t8_cmesh_get_tree_face_neighbor_eclass (cmesh, ltree_it, i); + // If a face neighbor exists, the return value must match the element type, otherwise it must + // be T8_ECLASS_INVALID + const t8_eclass_t reference_value = face_neigh_elem[ltree_it][i] == -1 ? T8_ECLASS_INVALID : elem_type; + EXPECT_EQ (neighbor_eclass, reference_value) << "mismatch in face neighbor eclass."; } } }