Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,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 )
Expand Down
128 changes: 128 additions & 0 deletions test/t8_forest/t8_gtest_element_neighbor_eclass.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
/*
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
Comment thread
benegee marked this conversation as resolved.
Outdated

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 <gtest/gtest.h>

#include <test/t8_gtest_schemes.hxx>

#include <t8_forest/t8_forest_ghost.h>
#include <t8_cmesh/t8_cmesh_examples.h>
#include <t8_forest/t8_forest_private.h>

struct element_neighbor_eclass: public testing::TestWithParam<int>
{
protected:
void
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
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);

// Go through all the trees in the forest and store their eclass
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;
}
}

void
TearDown () override
{
t8_forest_unref (&forest);
}

t8_cmesh_t cmesh;
t8_forest_t forest;
const t8_scheme *scheme;
std::vector<t8_eclass_t> tree_eclass_ref;
std::vector<t8_eclass_t> ghost_eclass_ref;
};

TEST_P (element_neighbor_eclass, test_half_neighbors)
{
// 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);

for (t8_locidx_t itree = 0; itree < num_local_trees + num_ghost_trees; itree++) {

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 leaf elements
for (t8_locidx_t ileaf = 0; ileaf < num_leaves; ++ileaf) {

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 (function to test)
const t8_eclass_t neigh_class = t8_forest_element_neighbor_eclass (forest, itree, element, iface);

// 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 {
// 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]);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not too happy with the tree_eclass_ref-vector here. I am not sure if this is the way neighbor-information should be handled, as it causes additional memory in the size of of O(trees). I understand that is is possibly cheaper (in runtime) to use this approach, which is why I think it is ok to use it for testing.
however we should know that our tests can be used as examples to users, therefore we should at least add a comment that a decision about the tradeoff between memory/runtime has been made here.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed! This is not something anyone should consider a how to. If you want to query eclasses of your neighbors you should use t8_forest_element_neighbor_eclass.

In fact, I wanted to write a consistency check, which somehow fiddles out the same information as provided by t8_forest_element_neighbor_eclass, but in a different way. I failed in doing so. If you replace line 120 by a call to t8_cmesh_get_tree_class, you get essentially what it currently done inside t8_forest_element_neighbor_eclass.

Copy link
Copy Markdown
Collaborator Author

@benegee benegee May 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That being said, I now removed the ref arrays, as there were not useful.

In doing so I realized I had actually not considered ghost trees, i.e. I iterated over all local and ghost trees, but always used t8_cmesh_get_tree_class, never t8_cmesh_get_ghost_class. I now do it hopefully correctly

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));

but it makes me wonder why it had worked before.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know why it had worked before.

}
}
}
}
}
}

INSTANTIATE_TEST_SUITE_P (t8_gtest_element_neighbor_eclass, element_neighbor_eclass, AllSchemeCollections);
Comment thread
Davknapp marked this conversation as resolved.
Outdated
Loading