From 7a483e40715c565d39fded7ff32ca00c760c1a88 Mon Sep 17 00:00:00 2001 From: "Nguyen Xuan, Tu" Date: Wed, 29 Jan 2025 13:37:09 +0100 Subject: [PATCH 01/22] Created a component test for vtk writer and reader --- benchmarks/time_partition.cxx | 2 +- src/t8_cmesh.h | 34 ++-- src/t8_cmesh/t8_cmesh.cxx | 186 ++++++------------ src/t8_cmesh/t8_cmesh_commit.cxx | 2 +- src/t8_cmesh/t8_cmesh_readmshfile.cxx | 118 ----------- src/t8_cmesh/t8_cmesh_trees.cxx | 165 ++++++++++------ src/t8_cmesh/t8_cmesh_trees.h | 2 +- src/t8_cmesh/t8_cmesh_triangle.cxx | 15 -- src/t8_cmesh/t8_cmesh_vtk_mesh_reader.hxx | 33 ++++ src/t8_geometry/t8_geometry.cxx | 9 + src/t8_geometry/t8_geometry.h | 9 + src/t8_vtk/t8_vtk_reader.cxx | 63 ------ src/t8_vtk/t8_vtk_write_ASCII.cxx | 18 ++ src/t8_vtk/t8_vtk_writer.cxx | 19 +- src/t8_vtk/t8_vtk_writer.hxx | 13 ++ test/CMakeLists.txt | 2 +- test/t8_IO/t8_gtest_vtk_write_read.cxx | 95 +++++++++ test/t8_cmesh/t8_gtest_cmesh_partition.cxx | 2 +- ...st_cmesh_tree_vertices_negative_volume.cxx | 153 -------------- .../t8_gtest_geometry_lagrange.cxx | 6 +- .../t8_gtest_geometry_linear.cxx | 4 +- 21 files changed, 375 insertions(+), 575 deletions(-) create mode 100644 src/t8_cmesh/t8_cmesh_vtk_mesh_reader.hxx create mode 100644 test/t8_IO/t8_gtest_vtk_write_read.cxx delete mode 100644 test/t8_cmesh/t8_gtest_cmesh_tree_vertices_negative_volume.cxx diff --git a/benchmarks/time_partition.cxx b/benchmarks/time_partition.cxx index 0a37576257..42d80d94ee 100644 --- a/benchmarks/time_partition.cxx +++ b/benchmarks/time_partition.cxx @@ -76,7 +76,7 @@ t8_time_cmesh_translate_coordinates (t8_cmesh_t cmesh, double x, sc_MPI_Comm com SC_CHECK_MPI (mpiret); for (itree = 0; itree < t8_cmesh_get_num_local_trees (cmesh); itree++) { /* loop over all trees and get a pointer to their vertices */ - vertices = (double *) t8_cmesh_get_attribute (cmesh, t8_get_package_id (), 0, itree); + vertices = (double *) t8_cmesh_get_attribute (cmesh, t8_get_package_id (), T8_CMESH_VERTICES_ATTRIBUTE_KEY, itree); eclass = t8_cmesh_get_tree_class (cmesh, itree); for (ivertex = 0; ivertex < t8_eclass_num_vertices[eclass]; ivertex++) { /* For each tree vertex, translate its x-coordinate */ diff --git a/src/t8_cmesh.h b/src/t8_cmesh.h index e31642d013..6f1d6cd983 100644 --- a/src/t8_cmesh.h +++ b/src/t8_cmesh.h @@ -99,31 +99,16 @@ int t8_cmesh_is_committed (const t8_cmesh_t cmesh); #ifdef T8_ENABLE_DEBUG -/** Check the geometry of the mesh for validity. - * \param [in] cmesh This cmesh is examined. - * \return True if the geometry of the cmesh is valid. +/** Check the geometry of the mesh for validity, this means checking if trees and their geometries + * are compatible and if they have negative volume. + * \param [in] cmesh This cmesh is examined. + * \param [in] check_for_negative_volume Enable the negative volume check. + * \return True if the geometry of the cmesh is valid. */ int -t8_cmesh_validate_geometry (const t8_cmesh_t cmesh); +t8_cmesh_validate_geometry (const t8_cmesh_t cmesh, const int check_for_negative_volume); #endif -/** Given a set of vertex coordinates for a tree of a given eclass. - * Query whether the geometric volume of the tree with this coordinates - * would be negative. - * \param [in] eclass The eclass of a tree. - * \param [in] vertices The coordinates of the tree's vertices. - * \param [in] num_vertices The number of vertices. \a vertices must hold - * 3 * \a num_vertices many doubles. - * \a num_vertices must match \ref t8_eclass_num_vertices[\a eclass] - * \return True if the geometric volume describe by \a vertices is negative. - * False otherwise. - * Returns true if a tree of the given eclass with the given vertex - * coordinates does have negative volume. - */ -/* TODO: write a test for this function */ -int -t8_cmesh_tree_vertices_negative_volume (const t8_eclass_t eclass, const double *vertices, const int num_vertices); - /* TODO: Currently it is not possible to destroy set_from before * cmesh is destroyed. */ /** This function sets a cmesh to be derived from. @@ -350,13 +335,18 @@ t8_cmesh_set_profiling (t8_cmesh_t cmesh, int set_profiling); * Orders, sequences, equivalences? * This function works on committed and uncommitted cmeshes. */ + int -t8_cmesh_is_equal (t8_cmesh_t cmesh_a, t8_cmesh_t cmesh_b); +t8_cmesh_is_equal_ext (const t8_cmesh_t cmesh_a, const t8_cmesh_t cmesh_b, const int same_tree_order); /** Check whether a cmesh is empty on all processes. * \param [in] cmesh A committed cmesh. * \return True (non-zero) if and only if the cmesh has trees at all. */ + +int +t8_cmesh_is_equal (const t8_cmesh_t cmesh_a, const t8_cmesh_t cmesh_b); + int t8_cmesh_is_empty (t8_cmesh_t cmesh); diff --git a/src/t8_cmesh/t8_cmesh.cxx b/src/t8_cmesh/t8_cmesh.cxx index 38c7e7b9e3..e7399cbee6 100644 --- a/src/t8_cmesh/t8_cmesh.cxx +++ b/src/t8_cmesh/t8_cmesh.cxx @@ -125,7 +125,7 @@ t8_cmesh_is_committed (const t8_cmesh_t cmesh) #if T8_ENABLE_DEBUG int -t8_cmesh_validate_geometry (const t8_cmesh_t cmesh) +t8_cmesh_validate_geometry (const t8_cmesh_t cmesh, const int check_for_negative_volume) { /* After a cmesh is committed, check whether all trees in a cmesh are compatible * with their geometry and if they have positive volume. @@ -150,7 +150,7 @@ t8_cmesh_validate_geometry (const t8_cmesh_t cmesh) t8_debugf ("Detected incompatible geometry for tree %li\n", (long) itree); return false; } - if (geometry_compatible) { + else if (check_for_negative_volume){ /* Check for negative volume. This only makes sense if the geometry is valid for the tree. */ const int negative_volume = cmesh->geometry_handler->tree_negative_volume (cmesh, t8_cmesh_get_global_id (cmesh, itree)); @@ -509,107 +509,6 @@ t8_cmesh_set_tree_class (t8_cmesh_t cmesh, const t8_gloidx_t gtree_id, const t8_ #endif } -/* Given a set of vertex coordinates for a tree of a given eclass. - * Query whether the geometric volume of the tree with this coordinates - * would be negative. - * Returns true if a tree of the given eclass with the given vertex - * coordinates does have negative volume. - */ -int -t8_cmesh_tree_vertices_negative_volume (const t8_eclass_t eclass, const double *vertices, const int num_vertices) -{ - T8_ASSERT (num_vertices == t8_eclass_num_vertices[eclass]); - - /* Points and lines do not have a volume orientation. */ - if (t8_eclass_to_dimension[eclass] < 2) { - return 0; - } - - T8_ASSERT (eclass == T8_ECLASS_TRIANGLE || eclass == T8_ECLASS_QUAD || eclass == T8_ECLASS_TET - || eclass == T8_ECLASS_HEX || eclass == T8_ECLASS_PRISM || eclass == T8_ECLASS_PYRAMID); - - /* Skip negative volume check (orientation of face normal) of 2D elements - * when z-coordinates are not (almost) zero. */ - if (t8_eclass_to_dimension[eclass] < 3) { - for (int ivert = 0; ivert < num_vertices; ivert++) { - const double z_coordinate = vertices[3 * ivert + 2]; - if (std::abs (z_coordinate) > 10 * T8_PRECISION_EPS) { - return false; - } - } - } - - /* - * z For 2D meshes we enforce the right-hand-rule in terms - * | of node ordering. The volume is defined by the parallelepiped - * | 2- - -(3) spanned by the vectors between nodes 0:1 and 0:2 as well as the - * |/____ / unit vector in z-direction. This definition works for both triangles and quads. - * 0 1 - * - * 6 ______ 7 For Hexes and pyramids, if the vertex 4 is below the 0-1-2-3 plane, - * /| / the volume is negative. This is the case if and only if - * 4 /_____5/| the scalar product of v_4 with the cross product of v_1 and v_2 is - * | | _ |_| smaller 0: - * | 2 | / 3 < v_4, v_1 x v_2 > < 0 - * |/____|/ - * 0 1 - * - * - * For tets/prisms, if the vertex 3 is below/above the 0-1-2 plane, the volume - * is negative. This is the case if and only if - * the scalar product of v_3 with the cross product of v_1 and v_2 is - * greater 0: - * - * < v_3, v_1 x v_2 > > 0 - * - */ - - /* Build the vectors v_i as vertices_i - vertices_0. */ - double v_1[3], v_2[3], v_j[3], cross[3], sc_prod; - - if (eclass == T8_ECLASS_TRIANGLE || eclass == T8_ECLASS_QUAD) { - for (int i = 0; i < 3; i++) { - v_1[i] = vertices[3 + i] - vertices[i]; - v_2[i] = vertices[6 + i] - vertices[i]; - } - - /* Unit vector in z-direction. */ - v_j[0] = 0.0; - v_j[1] = 0.0; - v_j[2] = 1.0; - - /* Compute cross = v_1 x v_2. */ - t8_vec_cross (v_1, v_2, cross); - /* Compute sc_prod = . */ - sc_prod = t8_vec_dot (v_j, cross); - - T8_ASSERT (sc_prod != 0); - return sc_prod < 0; - } - - int j; - if (eclass == T8_ECLASS_TET || eclass == T8_ECLASS_PRISM) { - /* In the tet/prism case, the third vector is v_3 */ - j = 3; - } - else { - /* For pyramids and Hexes, the third vector is v_4 */ - j = 4; - } - for (int i = 0; i < 3; i++) { - v_1[i] = vertices[3 + i] - vertices[i]; - v_2[i] = vertices[6 + i] - vertices[i]; - v_j[i] = vertices[3 * j + i] - vertices[i]; - } - /* compute cross = v_1 x v_2 */ - t8_vec_cross (v_1, v_2, cross); - /* Compute sc_prod = */ - sc_prod = t8_vec_dot (v_j, cross); - - T8_ASSERT (sc_prod != 0); - return eclass == T8_ECLASS_TET ? sc_prod > 0 : sc_prod < 0; -} - void t8_cmesh_set_tree_vertices (t8_cmesh_t cmesh, const t8_gloidx_t gtree_id, const double *vertices, const int num_vertices) @@ -672,57 +571,86 @@ t8_cmesh_set_profiling (t8_cmesh_t cmesh, const int set_profiling) } } -/* returns true if cmesh_a equals cmesh_b */ int t8_cmesh_is_equal (const t8_cmesh_t cmesh_a, const t8_cmesh_t cmesh_b) +{ + return t8_cmesh_is_equal_ext (cmesh_a, cmesh_b, 1); +}; + +/* returns true if cmesh_a equals cmesh_b */ +int +t8_cmesh_is_equal_ext (const t8_cmesh_t cmesh_a, const t8_cmesh_t cmesh_b, const int same_tree_order) /* TODO: rewrite */ { - int is_equal; T8_ASSERT (cmesh_a != NULL && cmesh_b != NULL); if (cmesh_a == cmesh_b) { return 1; } /* check entries that are numbers */ - is_equal = cmesh_a->committed != cmesh_b->committed || cmesh_a->dimension != cmesh_b->dimension + if (cmesh_a->committed != cmesh_b->committed || cmesh_a->dimension != cmesh_b->dimension || cmesh_a->set_partition != cmesh_b->set_partition || cmesh_a->mpirank != cmesh_b->mpirank || cmesh_a->mpisize != cmesh_b->mpisize || cmesh_a->num_trees != cmesh_b->num_trees || cmesh_a->num_local_trees != cmesh_b->num_local_trees || cmesh_a->num_ghosts != cmesh_b->num_ghosts - || cmesh_a->first_tree != cmesh_b->first_tree; - if (is_equal != 0) { + || cmesh_a->first_tree != cmesh_b->first_tree) + { return 0; } /* check arrays */ - is_equal - = memcmp (cmesh_a->num_trees_per_eclass, cmesh_b->num_trees_per_eclass, T8_ECLASS_COUNT * sizeof (t8_gloidx_t)); - is_equal = is_equal - || memcmp (cmesh_a->num_local_trees_per_eclass, cmesh_b->num_local_trees_per_eclass, - T8_ECLASS_COUNT * sizeof (t8_locidx_t)); - - /* check tree_offsets */ - if (cmesh_a->tree_offsets != NULL) { - if (cmesh_b->tree_offsets == NULL) { - return 0; - } - else { - is_equal = is_equal || !t8_shmem_array_is_equal (cmesh_a->tree_offsets, cmesh_b->tree_offsets); - } + if (memcmp (cmesh_a->num_trees_per_eclass, cmesh_b->num_trees_per_eclass, T8_ECLASS_COUNT * sizeof (t8_gloidx_t))) + { + return 0; } - if (is_equal != 0) { + + if (memcmp (cmesh_a->num_local_trees_per_eclass, cmesh_b->num_local_trees_per_eclass, + T8_ECLASS_COUNT * sizeof (t8_locidx_t))) + { return 0; } + + if (same_tree_order){ + /* check tree_offsets */ + if (cmesh_a->tree_offsets != NULL) { + if (cmesh_b->tree_offsets == NULL) { + return 0; + } + else { + if (!t8_shmem_array_is_equal (cmesh_a->tree_offsets, cmesh_b->tree_offsets)) + return 0; + } + } + } /* check trees */ - if (cmesh_a->committed && !t8_cmesh_trees_is_equal (cmesh_a, cmesh_a->trees, cmesh_b->trees)) { - /* if we have committed check tree arrays */ - return 0; + if (same_tree_order) + { + if (cmesh_a->committed && !t8_cmesh_trees_is_equal (cmesh_a, cmesh_a->trees, cmesh_b->trees, 1)) { + /* if we have committed check tree arrays */ + t8_global_productionf("Failed on equal trees"); + return 0; + } + else { + if (!cmesh_a->committed && !t8_stash_is_equal (cmesh_a->stash, cmesh_b->stash)) { + /* if we have not committed check stash arrays */ + return 0; + } + } } - else { - if (!cmesh_a->committed && !t8_stash_is_equal (cmesh_a->stash, cmesh_b->stash)) { + else{ + if (cmesh_a->committed && !t8_cmesh_trees_is_equal (cmesh_a, cmesh_a->trees, cmesh_b->trees, 0)) { + /* if we have committed check tree arrays */ + t8_global_productionf("Failed on equal trees %i", t8_cmesh_trees_is_equal (cmesh_a, cmesh_a->trees, cmesh_b->trees, 0)); + return 0; + } + else { + if (!cmesh_a->committed && !t8_stash_is_equal (cmesh_a->stash, cmesh_b->stash)) { /* if we have not committed check stash arrays */ return 0; + } } } - return 1; + + return 1; + } int diff --git a/src/t8_cmesh/t8_cmesh_commit.cxx b/src/t8_cmesh/t8_cmesh_commit.cxx index 1e2abb2089..baa6762385 100644 --- a/src/t8_cmesh/t8_cmesh_commit.cxx +++ b/src/t8_cmesh/t8_cmesh_commit.cxx @@ -605,7 +605,7 @@ t8_cmesh_commit (t8_cmesh_t cmesh, sc_MPI_Comm comm) (long) cmesh->num_local_trees, (long long) cmesh->num_trees, (long) cmesh->num_ghosts); T8_ASSERT (t8_cmesh_is_committed (cmesh)); - T8_ASSERT (t8_cmesh_validate_geometry (cmesh)); + T8_ASSERT (t8_cmesh_validate_geometry (cmesh, 0)); /* If profiling is enabled, we measure the runtime of commit. */ if (cmesh->profile != NULL) { cmesh->profile->commit_runtime = sc_MPI_Wtime () - cmesh->profile->commit_runtime; diff --git a/src/t8_cmesh/t8_cmesh_readmshfile.cxx b/src/t8_cmesh/t8_cmesh_readmshfile.cxx index 034b4139be..319c317ab0 100644 --- a/src/t8_cmesh/t8_cmesh_readmshfile.cxx +++ b/src/t8_cmesh/t8_cmesh_readmshfile.cxx @@ -622,63 +622,6 @@ t8_cmesh_msh_file_2_read_eles (t8_cmesh_t cmesh, FILE *fp, sc_hash_t *vertices, tree_vertices[3 * t8_vertex_num + 1] = (*found_node)->coordinates[1]; tree_vertices[3 * t8_vertex_num + 2] = (*found_node)->coordinates[2]; } - /* Detect and correct negative volumes */ - if (t8_cmesh_tree_vertices_negative_volume (eclass, tree_vertices, num_nodes)) { - /* The volume described is negative. We need to change vertices. - * For tets we switch 0 and 3. - * For prisms we switch 0 and 3, 1 and 4, 2 and 5. - * For hexahedra we switch 0 and 4, 1 and 5, 2 and 6, 3 and 7. - * For pyramids we switch 0 and 4 */ - double temp; - int num_switches = 0; - int switch_indices[4] = { 0 }; - int iswitch; - T8_ASSERT (t8_eclass_to_dimension[eclass] > 1); - t8_debugf ("Correcting negative volume of tree %li\n", static_cast (tree_count)); - switch (eclass) { - case T8_ECLASS_TRIANGLE: - case T8_ECLASS_QUAD: - /* We switch vertex 1 and vertex 2. */ - num_switches = 2; - switch_indices[0] = 0; - switch_indices[1] = 2; - break; - case T8_ECLASS_TET: - /* We switch vertex 0 and vertex 3 */ - num_switches = 1; - switch_indices[0] = 3; - break; - case T8_ECLASS_PRISM: - num_switches = 3; - switch_indices[0] = 3; - switch_indices[1] = 4; - switch_indices[2] = 5; - break; - case T8_ECLASS_HEX: - num_switches = 4; - switch_indices[0] = 4; - switch_indices[1] = 5; - switch_indices[2] = 6; - switch_indices[3] = 7; - break; - case T8_ECLASS_PYRAMID: - num_switches = 1; - switch_indices[0] = 4; - break; - default: - SC_ABORT_NOT_REACHED (); - } - - for (iswitch = 0; iswitch < num_switches; ++iswitch) { - /* We switch vertex 0 + iswitch and vertex switch_indices[iswitch] */ - for (i = 0; i < 3; i++) { - temp = tree_vertices[3 * iswitch + i]; - tree_vertices[3 * iswitch + i] = tree_vertices[3 * switch_indices[iswitch] + i]; - tree_vertices[3 * switch_indices[iswitch] + i] = temp; - } - } - T8_ASSERT (!t8_cmesh_tree_vertices_negative_volume (eclass, tree_vertices, num_nodes)); - } /* End of negative volume handling */ /* Set the vertices of this tree */ t8_cmesh_set_tree_vertices (cmesh, tree_count, tree_vertices, num_nodes); /* If wished, we store the vertex indices of that tree. */ @@ -960,67 +903,6 @@ t8_cmesh_msh_file_4_read_eles (t8_cmesh_t cmesh, FILE *fp, sc_hash_t *vertices, tree_vertices[3 * t8_vertex_num + 1] = (*found_node)->coordinates[1]; tree_vertices[3 * t8_vertex_num + 2] = (*found_node)->coordinates[2]; } - /* Detect and correct negative volumes */ - if (t8_cmesh_tree_vertices_negative_volume (eclass, tree_vertices, num_nodes)) { - /* The volume described is negative. We need to change vertices. - * For tets we switch 0 and 3. - * For prisms we switch 0 and 3, 1 and 4, 2 and 5. - * For hexahedra we switch 0 and 4, 1 and 5, 2 and 6, 3 and 7. - * For pyramids we switch 0 and 4 */ - double temp; - t8_msh_file_node_parametric_t temp_node; - int num_switches = 0; - int switch_indices[4] = { 0 }; - int iswitch; - T8_ASSERT (t8_eclass_to_dimension[eclass] > 1); - t8_debugf ("Correcting negative volume of tree %li\n", static_cast (tree_count)); - switch (eclass) { - case T8_ECLASS_TRIANGLE: - case T8_ECLASS_QUAD: - /* We switch vertex 1 and vertex 2. */ - num_switches = 2; - switch_indices[0] = 0; - switch_indices[1] = 2; - break; - case T8_ECLASS_TET: - /* We switch vertex 0 and vertex 3. */ - num_switches = 1; - switch_indices[0] = 3; - break; - case T8_ECLASS_PRISM: - num_switches = 3; - switch_indices[0] = 3; - switch_indices[1] = 4; - switch_indices[2] = 5; - break; - case T8_ECLASS_HEX: - num_switches = 4; - switch_indices[0] = 4; - switch_indices[1] = 5; - switch_indices[2] = 6; - switch_indices[3] = 7; - break; - case T8_ECLASS_PYRAMID: - num_switches = 1; - switch_indices[0] = 4; - break; - default: - SC_ABORT_NOT_REACHED (); - } - - for (iswitch = 0; iswitch < num_switches; ++iswitch) { - /* We switch vertex 0 + iswitch and vertex switch_indices[iswitch] */ - for (i = 0; i < 3; i++) { - temp = tree_vertices[3 * iswitch + i]; - tree_vertices[3 * iswitch + i] = tree_vertices[3 * switch_indices[iswitch] + i]; - tree_vertices[3 * switch_indices[iswitch] + i] = temp; - } - temp_node = tree_nodes[iswitch]; - tree_nodes[iswitch] = tree_nodes[switch_indices[iswitch]]; - tree_nodes[switch_indices[iswitch]] = temp_node; - } - T8_ASSERT (!t8_cmesh_tree_vertices_negative_volume (eclass, tree_vertices, num_nodes)); - } /* End of negative volume handling */ /* Set the vertices of this tree */ t8_cmesh_set_tree_vertices (cmesh, tree_count, tree_vertices, num_nodes); /* If wished, we store the vertex indices of that tree. */ diff --git a/src/t8_cmesh/t8_cmesh_trees.cxx b/src/t8_cmesh/t8_cmesh_trees.cxx index 9c136c554f..8df075df66 100644 --- a/src/t8_cmesh/t8_cmesh_trees.cxx +++ b/src/t8_cmesh/t8_cmesh_trees.cxx @@ -1172,11 +1172,57 @@ t8_cmesh_trees_is_face_consistent (const t8_cmesh_t cmesh, const t8_cmesh_trees_ return ret; } +static bool t8_cmesh_tree_is_equal(const t8_gloidx_t tree_id_a, const t8_gloidx_t tree_id_b, const t8_cmesh_trees_t trees_a, const t8_cmesh_trees_t trees_b, const bool check_face_neighbors) +{ + /* Get the treea and their face neighbors */ + + t8_locidx_t *face_neighborsa, *face_neighborsb; + int8_t *ttfa, *ttfb; + size_t attsizea, attsizeb; + t8_attribute_info_struct_t *first_atta, *first_attb; + char *atta, *attb; + + const t8_ctree_t treea = t8_cmesh_trees_get_tree_ext (trees_a, tree_id_a, &face_neighborsa, &ttfa); + const t8_ctree_t treeb = t8_cmesh_trees_get_tree_ext (trees_b, tree_id_b, &face_neighborsb, &ttfb); + /* Compare tree entries */ + if (!(treea->eclass == treeb->eclass && treea->num_attributes == treeb->num_attributes + && treea->treeid == treeb->treeid)) + { + return 0; + } + t8_eclass_t eclass = treea->eclass; + /* Compare face neighbors */ + if (check_face_neighbors){ + if (memcmp (face_neighborsa, face_neighborsb, t8_eclass_num_faces[eclass] * sizeof (t8_locidx_t)) + || memcmp (ttfa, ttfb, t8_eclass_num_faces[eclass] * sizeof (int8_t))) + { + return 0; + } + } + /* Compare attributes */ + attsizea = t8_cmesh_trees_attribute_size (treea); + attsizeb = t8_cmesh_trees_attribute_size (treeb); + if (attsizea != attsizeb) { + return 0; + } + if (attsizea > 0) { + /* Get pointers to all attributes */ + first_atta = T8_TREE_ATTR_INFO (treea, 0); + first_attb = T8_TREE_ATTR_INFO (treeb, 0); + atta = (char *) T8_TREE_ATTR (treea, first_atta); + attb = (char *) T8_TREE_ATTR (treeb, first_attb); + if (memcmp (atta, attb, attsizea)) { + return 0; + } + } + return 1; +} + int -t8_cmesh_trees_is_equal (const t8_cmesh_t cmesh, const t8_cmesh_trees_t trees_a, const t8_cmesh_trees_t trees_b) +t8_cmesh_trees_is_equal (const t8_cmesh_t cmesh, const t8_cmesh_trees_t trees_a, const t8_cmesh_trees_t trees_b, const int same_tree_order) { int is_equal; - t8_locidx_t num_trees, num_ghost, itree, ighost; + t8_locidx_t num_trees, num_ghost, ighost; t8_ctree_t treea, treeb; t8_cghost_t ghosta, ghostb; t8_locidx_t *face_neighborsa, *face_neighborsb; @@ -1199,73 +1245,66 @@ t8_cmesh_trees_is_equal (const t8_cmesh_t cmesh, const t8_cmesh_trees_t trees_a, num_ghost = cmesh->num_ghosts; /* We now compare all trees and their attributes */ - for (itree = 0; itree < num_trees; itree++) { - /* Get the treea and their face neighbors */ - treea = t8_cmesh_trees_get_tree_ext (trees_a, itree, &face_neighborsa, &ttfa); - treeb = t8_cmesh_trees_get_tree_ext (trees_b, itree, &face_neighborsb, &ttfb); - /* Compare tree entries */ - is_equal = treea->eclass == treeb->eclass && treea->num_attributes == treeb->num_attributes - && treea->treeid == treeb->treeid; - if (!is_equal) { - return 0; - } - eclass = treea->eclass; - /* Compare face neighbors */ - is_equal = !memcmp (face_neighborsa, face_neighborsb, t8_eclass_num_faces[eclass] * sizeof (t8_locidx_t)) - && !memcmp (ttfa, ttfb, t8_eclass_num_faces[eclass] * sizeof (int8_t)); - if (!is_equal) { - return 0; - } - /* Compare attributes */ - attsizea = t8_cmesh_trees_attribute_size (treea); - attsizeb = t8_cmesh_trees_attribute_size (treeb); - if (attsizea != attsizeb) { - return 0; + if(!same_tree_order){ + for (t8_locidx_t itree = 0; itree < num_trees; itree++) { + for (t8_locidx_t jtree = 0; jtree < num_trees; jtree++){ + if (t8_cmesh_tree_is_equal(itree, jtree, trees_a, trees_b, false)){ + break; + } + else if(jtree == num_trees){ + return 0; + } + } } - if (attsizea > 0) { - /* Get pointers to all attributes */ - first_atta = T8_TREE_ATTR_INFO (treea, 0); - first_attb = T8_TREE_ATTR_INFO (treeb, 0); - atta = (char *) T8_TREE_ATTR (treea, first_atta); - attb = (char *) T8_TREE_ATTR (treeb, first_attb); - if (memcmp (atta, attb, attsizea)) { + } + else + { + for (t8_locidx_t itree = 0; itree < num_trees; itree++) + { + if (!t8_cmesh_tree_is_equal(itree, itree, trees_a, trees_b, true)) + { return 0; } } - } - /* We now compare all ghosts and their attributes */ - for (ighost = 0; ighost < num_ghost; ighost++) { - /* Get the treea and their face neighbors */ - ghosta = t8_cmesh_trees_get_ghost_ext (trees_a, ighost, &gface_neighborsa, &ttfa); - ghostb = t8_cmesh_trees_get_ghost_ext (trees_b, ighost, &gface_neighborsb, &ttfb); - /* Compare ghost entries */ - is_equal = ghosta->eclass == ghostb->eclass && ghosta->num_attributes == ghostb->num_attributes - && ghosta->treeid == ghostb->treeid; - if (!is_equal) { - return 0; - } - eclass = ghosta->eclass; - /* Compare face neighbors */ - is_equal = !memcmp (gface_neighborsa, gface_neighborsb, t8_eclass_num_faces[eclass] * sizeof (t8_gloidx_t)) - && !memcmp (ttfa, ttfb, t8_eclass_num_faces[eclass] * sizeof (int8_t)); - if (!is_equal) { - return 0; - } - /* Compare attributes */ - attsizea = t8_cmesh_trees_ghost_attribute_size (ghosta); - attsizeb = t8_cmesh_trees_ghost_attribute_size (ghostb); - if (attsizea != attsizeb) { - return 0; - } - if (attsizea > 0) { - /* Get pointers to all attributes */ - first_atta = T8_GHOST_ATTR_INFO (ghosta, 0); - first_attb = T8_GHOST_ATTR_INFO (ghostb, 0); - atta = (char *) T8_GHOST_ATTR (ghosta, first_atta); - attb = (char *) T8_GHOST_ATTR (ghostb, first_attb); - if (memcmp (atta, attb, attsizea)) { + /* We now compare all ghosts and their attributes */ + for (ighost = 0; ighost < num_ghost; ighost++) { + /* Get the treea and their face neighbors */ + ghosta = t8_cmesh_trees_get_ghost_ext (trees_a, ighost, &gface_neighborsa, &ttfa); + ghostb = t8_cmesh_trees_get_ghost_ext (trees_b, ighost, &gface_neighborsb, &ttfb); + /* Compare ghost entries */ + is_equal = ghosta->eclass == ghostb->eclass && ghosta->num_attributes == ghostb->num_attributes + && ghosta->treeid == ghostb->treeid; + if (!is_equal) + { + return 0; + } + eclass = ghosta->eclass; + /* Compare face neighbors */ + is_equal = !memcmp (gface_neighborsa, gface_neighborsb, t8_eclass_num_faces[eclass] * sizeof (t8_gloidx_t)) + && !memcmp (ttfa, ttfb, t8_eclass_num_faces[eclass] * sizeof (int8_t)); + if (!is_equal) + { + return 0; + } + /* Compare attributes */ + attsizea = t8_cmesh_trees_ghost_attribute_size (ghosta); + attsizeb = t8_cmesh_trees_ghost_attribute_size (ghostb); + if (attsizea != attsizeb) + { return 0; } + if (attsizea > 0) + { + /* Get pointers to all attributes */ + first_atta = T8_GHOST_ATTR_INFO (ghosta, 0); + first_attb = T8_GHOST_ATTR_INFO (ghostb, 0); + atta = (char *) T8_GHOST_ATTR (ghosta, first_atta); + attb = (char *) T8_GHOST_ATTR (ghostb, first_attb); + if (memcmp (atta, attb, attsizea)) + { + return 0; + } + } } } return 1; diff --git a/src/t8_cmesh/t8_cmesh_trees.h b/src/t8_cmesh/t8_cmesh_trees.h index 60bbc74ac7..b1780f1247 100644 --- a/src/t8_cmesh/t8_cmesh_trees.h +++ b/src/t8_cmesh/t8_cmesh_trees.h @@ -514,7 +514,7 @@ int t8_cmesh_trees_is_face_consistent (t8_cmesh_t cmesh, t8_cmesh_trees_t trees); int -t8_cmesh_trees_is_equal (t8_cmesh_t cmesh, t8_cmesh_trees_t trees_a, t8_cmesh_trees_t trees_b); +t8_cmesh_trees_is_equal (t8_cmesh_t cmesh, t8_cmesh_trees_t trees_a, t8_cmesh_trees_t trees_b, int same_tree_order); /** Free all memory allocated with a trees structure. * This means that all coarse trees and ghosts, their face neighbor entries diff --git a/src/t8_cmesh/t8_cmesh_triangle.cxx b/src/t8_cmesh/t8_cmesh_triangle.cxx index 63badde55c..c2876e4b89 100644 --- a/src/t8_cmesh/t8_cmesh_triangle.cxx +++ b/src/t8_cmesh/t8_cmesh_triangle.cxx @@ -256,21 +256,6 @@ t8_cmesh_triangle_read_eles (t8_cmesh_t cmesh, int corner_offset, char *filename tree_vertices[3 * i + 1] = vertices[dim * tcorners[i] + 1]; tree_vertices[3 * i + 2] = dim == 2 ? 0 : vertices[dim * tcorners[i] + 2]; } - if (dim == 3 && t8_cmesh_tree_vertices_negative_volume (T8_ECLASS_TET, tree_vertices, dim + 1)) { - /* The volume described is negative. We need to switch two - * vertices. */ - double temp; - - T8_ASSERT (dim == 3); - t8_debugf ("Correcting negative volume of tree %li\n", static_cast (triangle - triangle_offset)); - /* We switch vertex 0 and vertex 1 */ - for (i = 0; i < 3; i++) { - temp = tree_vertices[i]; - tree_vertices[i] = tree_vertices[3 + i]; - tree_vertices[3 + i] = temp; - } - T8_ASSERT (!t8_cmesh_tree_vertices_negative_volume (T8_ECLASS_TET, tree_vertices, dim + 1)); - } t8_cmesh_set_tree_vertices (cmesh, triangle - triangle_offset, tree_vertices, dim + 1); } fclose (fp); diff --git a/src/t8_cmesh/t8_cmesh_vtk_mesh_reader.hxx b/src/t8_cmesh/t8_cmesh_vtk_mesh_reader.hxx new file mode 100644 index 0000000000..877e92347c --- /dev/null +++ b/src/t8_cmesh/t8_cmesh_vtk_mesh_reader.hxx @@ -0,0 +1,33 @@ +/* + 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) 2025 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. +*/ + +/** \file t8_cmesh_save.h + * + * Document what the file does + */ + +#ifndef T8_CMESH_SAVE_HXX +#define T8_CMESH_SAVE_HXX + + + +#endif /* T8_CMESH_SAVE_HXX */ \ No newline at end of file diff --git a/src/t8_geometry/t8_geometry.cxx b/src/t8_geometry/t8_geometry.cxx index 33396a962b..df8ce0c030 100644 --- a/src/t8_geometry/t8_geometry.cxx +++ b/src/t8_geometry/t8_geometry.cxx @@ -69,3 +69,12 @@ t8_geometry_tree_negative_volume (const t8_cmesh_t cmesh, const t8_gloidx_t gtre { return cmesh->geometry_handler->tree_negative_volume (cmesh, gtreeid); } + +int +t8_geometry_get_num_geometries (const t8_cmesh_t cmesh) +{ + if (cmesh->geometry_handler == nullptr){ + return 0; + } + return cmesh->geometry_handler->get_num_geometries (); +} diff --git a/src/t8_geometry/t8_geometry.h b/src/t8_geometry/t8_geometry.h index 0edc3e5a96..37e80420fe 100644 --- a/src/t8_geometry/t8_geometry.h +++ b/src/t8_geometry/t8_geometry.h @@ -111,6 +111,15 @@ t8_geometry_get_type (t8_cmesh_t cmesh, t8_gloidx_t gtreeid); int t8_geometry_tree_negative_volume (const t8_cmesh_t cmesh, const t8_gloidx_t gtreeid); +/** + * Returns the number of geometries in a cmesh. + * + * \param [in] cmesh The cmesh. + * \return The number of geometries. + */ +int +t8_geometry_get_num_geometries (const t8_cmesh_t cmesh); + T8_EXTERN_C_END (); #endif /* !T8_GEOMETRY_H */ diff --git a/src/t8_vtk/t8_vtk_reader.cxx b/src/t8_vtk/t8_vtk_reader.cxx index 059bcc711e..d310989663 100644 --- a/src/t8_vtk/t8_vtk_reader.cxx +++ b/src/t8_vtk/t8_vtk_reader.cxx @@ -49,65 +49,6 @@ T8_EXTERN_C_BEGIN (); -/** - * If the vertices of a tree describe a negative \param, - * permute the tree vertices. - * - * \param[in, out] tree_vertices The vertices of a tree - * \param[in] eclass The eclass of the tree. - */ -void -t8_cmesh_correct_volume (double *tree_vertices, t8_eclass_t eclass) -{ - /* The \param described is negative. We need to change vertices. - * For tets we switch 0 and 3. - * For prisms we switch 0 and 3, 1 and 4, 2 and 5. - * For hexahedra we switch 0 and 4, 1 and 5, 2 and 6, 3 and 7. - * For pyramids we switch 0 and 4 */ - double temp; - int num_switches = 0; - int switch_indices[4] = { 0 }; - int iswitch; - T8_ASSERT (t8_eclass_to_dimension[eclass] == 3); - t8_debugf ("Correcting negative volume.\n"); - switch (eclass) { - case T8_ECLASS_TET: - /* We switch vertex 0 and vertex 3 */ - num_switches = 1; - switch_indices[0] = 3; - break; - case T8_ECLASS_PRISM: - num_switches = 3; - switch_indices[0] = 3; - switch_indices[1] = 4; - switch_indices[2] = 5; - break; - case T8_ECLASS_HEX: - num_switches = 4; - switch_indices[0] = 4; - switch_indices[1] = 5; - switch_indices[2] = 6; - switch_indices[3] = 7; - break; - case T8_ECLASS_PYRAMID: - num_switches = 1; - switch_indices[0] = 4; - break; - default: - SC_ABORT_NOT_REACHED (); - } - - for (iswitch = 0; iswitch < num_switches; ++iswitch) { - /* We switch vertex 0 + iswitch and vertex switch_indices[iswitch] */ - for (int i = 0; i < 3; i++) { - temp = tree_vertices[3 * iswitch + i]; - tree_vertices[3 * iswitch + i] = tree_vertices[3 * switch_indices[iswitch] + i]; - tree_vertices[3 * switch_indices[iswitch] + i] = temp; - } - } - T8_ASSERT (!t8_cmesh_tree_vertices_negative_volume (eclass, tree_vertices, t8_eclass_num_vertices[eclass])); -} - #if T8_WITH_VTK vtk_read_success_t @@ -272,10 +213,6 @@ t8_vtk_iterate_cells (vtkSmartPointer vtkGrid, t8_cmesh_t cmesh, con for (int ipoint = 0; ipoint < num_points; ipoint++) { points->GetPoint (t8_element_shape_vtk_corner_number (cell_type, ipoint), &vertices[3 * ipoint]); } - /* The order of the vertices in vtk might give a tree with negative \param */ - if (t8_cmesh_tree_vertices_negative_volume (cell_type, vertices, num_points)) { - t8_cmesh_correct_volume (vertices, cell_type); - } t8_cmesh_set_tree_vertices (cmesh, tree_id, vertices, num_points); /* TODO: Avoid magic numbers in the attribute setting. */ diff --git a/src/t8_vtk/t8_vtk_write_ASCII.cxx b/src/t8_vtk/t8_vtk_write_ASCII.cxx index 1f345ed60e..06c6d80787 100644 --- a/src/t8_vtk/t8_vtk_write_ASCII.cxx +++ b/src/t8_vtk/t8_vtk_write_ASCII.cxx @@ -29,6 +29,7 @@ #include "t8_cmesh/t8_cmesh_trees.h" #include "t8_cmesh/t8_cmesh_types.h" #include +#include /* TODO: Currently we only use ASCII mode and no data compression. * We also do not use sc_io to buffer our output stream. */ @@ -792,6 +793,14 @@ t8_forest_vtk_write_ASCII (t8_forest_t forest, const char *fileprefix, const int T8_ASSERT (forest != NULL); T8_ASSERT (t8_forest_is_committed (forest)); T8_ASSERT (fileprefix != NULL); + if (forest->cmesh->geometry_handler == nullptr){ + t8_errorf("Error: Forest could not be written as vtk since it does not have geometries.\n"); + return false; + } + if (forest->cmesh->geometry_handler->get_num_geometries() == 0){ + t8_errorf("Error: Forest could not be written as vtk since it does not have geometries.\n"); + return false; + } if (forest->ghosts == NULL || forest->ghosts->num_ghosts_elements == 0) { /* Never write ghost elements if there aren't any */ write_ghosts = 0; @@ -931,6 +940,15 @@ t8_cmesh_vtk_write_file_ext (const t8_cmesh_t cmesh, const char *fileprefix, con T8_ASSERT (t8_cmesh_is_committed (cmesh)); T8_ASSERT (fileprefix != NULL); + if (cmesh->geometry_handler == nullptr){ + t8_errorf("Error: Cmesh could not be written as vtk since it does not have geometries.\n"); + return false; + } + if (cmesh->geometry_handler->get_num_geometries() == 0){ + t8_errorf("Error: Cmesh could not be written as vtk since it does not have geometries.\n"); + return false; + } + if (cmesh->mpirank == 0) { /* Write the pvtu header file. */ int num_ranks_that_write = cmesh->set_partition ? cmesh->mpisize : 1; diff --git a/src/t8_vtk/t8_vtk_writer.cxx b/src/t8_vtk/t8_vtk_writer.cxx index 67f0172982..759f805f1a 100644 --- a/src/t8_vtk/t8_vtk_writer.cxx +++ b/src/t8_vtk/t8_vtk_writer.cxx @@ -100,9 +100,9 @@ vtk_writer::write_ASCII (const t8_forest_t forest) template <> bool -vtk_writer::write_ASCII (const t8_cmesh_t forest) +vtk_writer::write_ASCII (const t8_cmesh_t cmesh) { - return t8_cmesh_vtk_write_ASCII (forest, this->fileprefix.c_str ()); + return t8_cmesh_vtk_write_ASCII (cmesh, this->fileprefix.c_str ()); } /* Implementation of the c-interface */ @@ -158,3 +158,18 @@ t8_forest_to_vtkUnstructuredGrid (const t8_forest_t forest, vtkSmartPointer +bool +vtk_writer::grid_has_geometry(const t8_cmesh_t cmesh) +{ + return t8_geometry_get_num_geometries (cmesh); +} + +template <> +bool +vtk_writer::grid_has_geometry(const t8_forest_t forest) +{ + const t8_cmesh_t cmesh = t8_forest_get_cmesh(forest); + return t8_geometry_get_num_geometries (cmesh); +} diff --git a/src/t8_vtk/t8_vtk_writer.hxx b/src/t8_vtk/t8_vtk_writer.hxx index d7b1325307..4254df4a6d 100644 --- a/src/t8_vtk/t8_vtk_writer.hxx +++ b/src/t8_vtk/t8_vtk_writer.hxx @@ -427,6 +427,10 @@ class vtk_writer { { #if T8_WITH_VTK T8_ASSERT (!fileprefix.empty ()); + if (!grid_has_geometry(grid)){ + t8_errorf("Error: Grid could not be written as vtk since it does not have geometries.\n"); + return false; + } /* * Write file: First we construct the unstructured Grid that will store the points and elements. It requires @@ -512,6 +516,15 @@ class vtk_writer { #endif } + /** + * Checks if a grid has a geometry. + * \param [in] grid The grid + * \return Returns true if the grid has at least one geometry. + * + */ + bool + grid_has_geometry(const grid_t grid); + bool write_treeid = false; bool write_mpirank = false; bool write_level = false; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index ef9f9ba71a..4e1edf0bdf 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -82,7 +82,6 @@ add_t8_test( NAME t8_gtest_cmesh_partition_parallel SOURCES add_t8_test( NAME t8_gtest_cmesh_set_partition_offsets_parallel SOURCES t8_gtest_main.cxx t8_cmesh/t8_gtest_cmesh_set_partition_offsets.cxx ) add_t8_test( NAME t8_gtest_cmesh_set_join_by_vertices_serial SOURCES t8_gtest_main.cxx t8_cmesh/t8_gtest_cmesh_set_join_by_vertices.cxx ) add_t8_test( NAME t8_gtest_cmesh_add_attributes_when_derive_parallel SOURCES t8_gtest_main.cxx t8_cmesh/t8_gtest_cmesh_add_attributes_when_derive.cxx ) -add_t8_test( NAME t8_gtest_cmesh_tree_vertices_negative_volume_serial SOURCES t8_gtest_main.cxx t8_cmesh/t8_gtest_cmesh_tree_vertices_negative_volume.cxx ) add_t8_test( NAME t8_gtest_multiple_attributes_parallel SOURCES t8_gtest_main.cxx t8_cmesh/t8_gtest_multiple_attributes.cxx ) add_t8_test( NAME t8_gtest_attribute_gloidx_array_serial SOURCES t8_gtest_main.cxx t8_cmesh/t8_gtest_attribute_gloidx_array.cxx ) @@ -119,6 +118,7 @@ add_t8_test( NAME t8_gtest_point_inside_serial SOURCES t8_g add_t8_test( NAME t8_gtest_vtk_reader_parallel SOURCES t8_gtest_main.cxx t8_IO/t8_gtest_vtk_reader.cxx ) add_t8_test( NAME t8_gtest_vtk_writer_parallel SOURCES t8_gtest_main.cxx t8_IO/t8_gtest_vtk_writer.cxx ) +add_t8_test( NAME t8_gtest_vtk_write_read SOURCES t8_gtest_main.cxx t8_IO/t8_gtest_vtk_write_read.cxx ) add_t8_test( NAME t8_gtest_nca_serial SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_nca.cxx ) add_t8_test( NAME t8_gtest_pyra_connectivity_serial SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_pyra_connectivity.cxx ) diff --git a/test/t8_IO/t8_gtest_vtk_write_read.cxx b/test/t8_IO/t8_gtest_vtk_write_read.cxx new file mode 100644 index 0000000000..eeb157c179 --- /dev/null +++ b/test/t8_IO/t8_gtest_vtk_write_read.cxx @@ -0,0 +1,95 @@ +/* + 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) 2024 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 "test/t8_cmesh_generator/t8_cmesh_example_sets.hxx" +#include + +#include +#include + +class vtk_write_read_test: public testing::TestWithParam { + protected: + void + SetUp () override + { + cmesh = GetParam ()->cmesh_create (); //create a cmesh from example base + } + + void + TearDown () override + { + std::remove("test_vtk_0.vtu"); + std::remove("test_vtk.pvtu"); //delete files after test finished + } + t8_cmesh_t cmesh; +}; + +TEST_P (vtk_write_read_test, write_read_vtk) +{ + t8_cmesh_t unpartitioned_cmesh_read, unpartitioned_cmesh_write; + + const int write_success = t8_cmesh_vtk_write_file_via_API (cmesh, "test_vtk", sc_MPI_COMM_WORLD); + const bool partitioned = t8_cmesh_is_partitioned(cmesh); + t8_cmesh_t cmesh2 = t8_vtk_reader_cmesh ("test_vtk.pvtu", partitioned, 0, sc_MPI_COMM_WORLD, VTK_SERIAL_FILE); + ASSERT_EQ(cmesh2!=NULL, write_success); + + if (cmesh2 != NULL){ + if (partitioned){ //repartition if cmesh is partitioned + t8_cmesh_init (&unpartitioned_cmesh_write); + t8_cmesh_set_derive (unpartitioned_cmesh_write, cmesh); + t8_cmesh_set_partition_offsets (unpartitioned_cmesh_write, t8_cmesh_offset_percent(cmesh, sc_MPI_COMM_WORLD, 100)); + t8_cmesh_commit(unpartitioned_cmesh_write, sc_MPI_COMM_WORLD); + t8_cmesh_init (&unpartitioned_cmesh_read); + t8_cmesh_set_derive (unpartitioned_cmesh_read, cmesh2); + t8_cmesh_set_partition_offsets (unpartitioned_cmesh_read, t8_cmesh_offset_percent(cmesh2, sc_MPI_COMM_WORLD, 100)); + t8_cmesh_commit(unpartitioned_cmesh_read, sc_MPI_COMM_WORLD); + + //check equality of repartioned cmeshes + t8_gloidx_t num_trees_cmesh_1 = t8_cmesh_get_num_trees(unpartitioned_cmesh_write); + t8_gloidx_t num_trees_cmesh_2 = t8_cmesh_get_num_trees(unpartitioned_cmesh_read); + ASSERT_EQ(num_trees_cmesh_1, num_trees_cmesh_2); + EXPECT_TRUE(t8_cmesh_is_equal_ext(unpartitioned_cmesh_write, unpartitioned_cmesh_read, 0)); + + //destroy both cmeshes + t8_cmesh_unref(&unpartitioned_cmesh_read); + t8_cmesh_unref(&unpartitioned_cmesh_write); + } + else{ //continue normally without repartitioning + t8_gloidx_t num_trees_cmesh_1 = t8_cmesh_get_num_trees(cmesh); + t8_gloidx_t num_trees_cmesh_2 = t8_cmesh_get_num_trees(cmesh2); + ASSERT_EQ(num_trees_cmesh_1, num_trees_cmesh_2); + EXPECT_TRUE(t8_cmesh_is_equal_ext(cmesh, cmesh2, 0)); + t8_cmesh_unref(&cmesh2); + t8_cmesh_unref (&cmesh); + } + } +} + +INSTANTIATE_TEST_SUITE_P (Test_vtk_write_read, vtk_write_read_test, AllCmeshsParam, pretty_print_base_example); + + diff --git a/test/t8_cmesh/t8_gtest_cmesh_partition.cxx b/test/t8_cmesh/t8_gtest_cmesh_partition.cxx index 9376cb60f0..6551723b17 100644 --- a/test/t8_cmesh/t8_gtest_cmesh_partition.cxx +++ b/test/t8_cmesh/t8_gtest_cmesh_partition.cxx @@ -122,7 +122,7 @@ TEST_P (t8_cmesh_partition_class, test_cmesh_partition_concentrate) t8_cmesh_commit (cmesh_partition_new2, sc_MPI_COMM_WORLD); cmesh_partition_new1 = cmesh_partition_new2; } - ASSERT_TRUE (t8_cmesh_is_equal (cmesh_partition_new2, cmesh_partition)) << "Cmesh equality check failed."; + ASSERT_TRUE (t8_cmesh_is_equal(cmesh_partition_new2, cmesh_partition)) << "Cmesh equality check failed."; t8_cmesh_destroy (&cmesh_partition_new2); t8_cmesh_destroy (&cmesh_partition); } diff --git a/test/t8_cmesh/t8_gtest_cmesh_tree_vertices_negative_volume.cxx b/test/t8_cmesh/t8_gtest_cmesh_tree_vertices_negative_volume.cxx deleted file mode 100644 index 2bc9644a7d..0000000000 --- a/test/t8_cmesh/t8_gtest_cmesh_tree_vertices_negative_volume.cxx +++ /dev/null @@ -1,153 +0,0 @@ -/* - 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) 2023 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. -*/ - -/** \file t8_gtest_cmesh_tree_vertices_negative_volume.cxx -* Provide tests to check the functionality of the t8_cmesh_tree_vertices_negative_volume function -* for every eclass. -*/ - -#include -#include -#include - -/** - * Given an eclass fill \a vertices_ids with the corner_ids of a cube [0,1]^3, such that - * the volume is positive - * \param[in] eclass The eclass to use - * \param[in, out] 8 ints on input, filled with the corner ids to use for i-th vertex of the element on output - */ -static void -get_vertices_ids (const t8_eclass_t eclass, int vertices_ids[T8_ECLASS_MAX_CORNERS]) -{ - /* For Hex, Quads and Lines we set the remaining vertices by - * not breaking at the end of the case. - * The same is done for Prisms and Triangles. */ - switch (eclass) { - case T8_ECLASS_HEX: - vertices_ids[4] = 4; - vertices_ids[5] = 5; - vertices_ids[6] = 6; - vertices_ids[7] = 7; - case T8_ECLASS_QUAD: - vertices_ids[3] = 3; - vertices_ids[2] = 2; - case T8_ECLASS_LINE: - vertices_ids[1] = 1; - case T8_ECLASS_VERTEX: - vertices_ids[0] = 0; - break; - case T8_ECLASS_PRISM: - vertices_ids[3] = 4; - vertices_ids[4] = 5; - vertices_ids[5] = 7; - case T8_ECLASS_TRIANGLE: - vertices_ids[0] = 0; - vertices_ids[1] = 1; - vertices_ids[2] = 3; - break; - case T8_ECLASS_TET: - vertices_ids[0] = 0; - vertices_ids[1] = 1; - vertices_ids[2] = 5; - vertices_ids[3] = 7; - break; - case T8_ECLASS_PYRAMID: - vertices_ids[0] = 1; - vertices_ids[1] = 3; - vertices_ids[2] = 0; - vertices_ids[3] = 2; - vertices_ids[4] = 7; - break; - default: - break; - } -} - -class tree_vertices_negative_volume: public testing::TestWithParam { - protected: - void - SetUp () override - { - tree_class = GetParam (); - num_vertices = t8_eclass_num_vertices[tree_class]; - get_vertices_ids (tree_class, vertices_ids); - } - void - TearDown () override - { - } - t8_eclass_t tree_class; - int num_vertices; - int vertices_ids[T8_ECLASS_MAX_CORNERS]; -}; - -/* Test if positive volume is detected correctly */ -TEST_P (tree_vertices_negative_volume, positive_volume) -{ - /* clang-format off */ - const double vertices_coords[24] = { - 0, 0, 0, - 1, 0, 0, - 0, 1, 0, - 1, 1, 0, - 0, 0, 1, - 1, 0, 1, - 0, 1, 1, - 1, 1, 1 - }; - /* clang-format on */ - double *elem_vertices = T8_ALLOC (double, 3 * num_vertices); - t8_cmesh_new_translate_vertices_to_attributes (vertices_ids, vertices_coords, elem_vertices, num_vertices); - - EXPECT_FALSE (t8_cmesh_tree_vertices_negative_volume (tree_class, elem_vertices, num_vertices)); - T8_FREE (elem_vertices); -} - -/* Test if negative volume is detected correctly */ -TEST_P (tree_vertices_negative_volume, negative_volume) -{ - /* clang-format off */ - /* Same nodes as above, but inverted. All 3D elements will have negative volume*/ - const double vertices_coords[24] = { - 0, 0, 1, - 1, 0, 1, - 0, 1, 1, - 1, 1, 1, - 0, 0, 0, - 1, 0, 0, - 0, 1, 0, - 1, 1, 0 - }; - /* clang-format on */ - double *elem_vertices = T8_ALLOC (double, 3 * num_vertices); - t8_cmesh_new_translate_vertices_to_attributes (vertices_ids, vertices_coords, elem_vertices, num_vertices); - if (t8_eclass_to_dimension[tree_class] <= 2) { - EXPECT_FALSE (t8_cmesh_tree_vertices_negative_volume (tree_class, elem_vertices, num_vertices)); - } - else { - EXPECT_TRUE (t8_cmesh_tree_vertices_negative_volume (tree_class, elem_vertices, num_vertices)); - } - T8_FREE (elem_vertices); -} - -INSTANTIATE_TEST_SUITE_P (t8_gtest_cmesh_tree_vertices_negative_volume, tree_vertices_negative_volume, - testing::Range (T8_ECLASS_ZERO, T8_ECLASS_PYRAMID)); diff --git a/test/t8_geometry/t8_geometry_implementations/t8_gtest_geometry_lagrange.cxx b/test/t8_geometry/t8_geometry_implementations/t8_gtest_geometry_lagrange.cxx index 07beda39b4..289d9f833c 100644 --- a/test/t8_geometry/t8_geometry_implementations/t8_gtest_geometry_lagrange.cxx +++ b/test/t8_geometry/t8_geometry_implementations/t8_gtest_geometry_lagrange.cxx @@ -274,7 +274,7 @@ TEST (test_geometry_lagrange, incompatible_geometry) /* Register the t8_geometry_lagrange geometry to this cmesh. */ t8_cmesh_register_geometry (cmesh); /* Should return true since the t8_geometry_lagrange geometry is compatible with quads. */ - ASSERT_TRUE (t8_cmesh_validate_geometry (cmesh)); + ASSERT_TRUE (t8_cmesh_validate_geometry (cmesh, 0)); t8_cmesh_destroy (&cmesh); /* Build a simple set geometries for the tree. */ @@ -294,7 +294,7 @@ TEST (test_geometry_lagrange, incompatible_geometry) t8_cmesh_register_geometry (cmesh); /* Check validity after committing to circumvent the assertion. * Should return false since the t8_geometry_lagrange geometry is not compatible with prisms. */ - ASSERT_FALSE (t8_cmesh_validate_geometry (cmesh)); + ASSERT_FALSE (t8_cmesh_validate_geometry (cmesh, 0)); t8_cmesh_destroy (&cmesh); degree = T8_GEOMETRY_MAX_POLYNOMIAL_DEGREE + 1; @@ -311,7 +311,7 @@ TEST (test_geometry_lagrange, incompatible_geometry) t8_cmesh_register_geometry (cmesh); /* Check validity after committing to circumvent the assertion. * Should return false since the maximum polynomial degree is exceeded. */ - ASSERT_FALSE (t8_cmesh_validate_geometry (cmesh)); + ASSERT_FALSE (t8_cmesh_validate_geometry (cmesh, 0)); t8_cmesh_destroy (&cmesh); } #endif /* T8_ENABLE_DEBUG */ diff --git a/test/t8_geometry/t8_geometry_implementations/t8_gtest_geometry_linear.cxx b/test/t8_geometry/t8_geometry_implementations/t8_gtest_geometry_linear.cxx index ee453aadce..148700b26d 100644 --- a/test/t8_geometry/t8_geometry_implementations/t8_gtest_geometry_linear.cxx +++ b/test/t8_geometry/t8_geometry_implementations/t8_gtest_geometry_linear.cxx @@ -177,7 +177,7 @@ TEST (test_geometry_linear, incompatible_geometry) /* Register the t8_geometry_linear_axis_aligned geometry to this cmesh. */ t8_cmesh_register_geometry (cmesh); /* Should return true since the t8_geometry_linear_axis_aligned geometry is compatible with quads. */ - ASSERT_TRUE (t8_cmesh_validate_geometry (cmesh)); + ASSERT_TRUE (t8_cmesh_validate_geometry (cmesh, 0)); t8_cmesh_destroy (&cmesh); /* Build a simple set geometries for the tree. */ @@ -193,7 +193,7 @@ TEST (test_geometry_linear, incompatible_geometry) t8_cmesh_register_geometry (cmesh); /* Check validity after committing to circumvent the assertion. * Should return false since the t8_geometry_linear_axis_aligned geometry is not compatible with triangles. */ - ASSERT_FALSE (t8_cmesh_validate_geometry (cmesh)); + ASSERT_FALSE (t8_cmesh_validate_geometry (cmesh, 0)); t8_cmesh_destroy (&cmesh); } #endif /* T8_ENABLE_DEBUG */ From 9f91688cf6de27b16c9112eb9d072deb74dc7ed8 Mon Sep 17 00:00:00 2001 From: "Nguyen Xuan, Tu" Date: Thu, 30 Jan 2025 09:53:19 +0100 Subject: [PATCH 02/22] Merged with main --- p4est | 2 +- sc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/p4est b/p4est index 851774a0c9..8206f0e56d 160000 --- a/p4est +++ b/p4est @@ -1 +1 @@ -Subproject commit 851774a0c993aaf6f1719da6fd62c2f3acd761ee +Subproject commit 8206f0e56d536d6d7f2e1d106c491b8c9386e28f diff --git a/sc b/sc index 1b127f01c5..2b209eab18 160000 --- a/sc +++ b/sc @@ -1 +1 @@ -Subproject commit 1b127f01c5e472039e938f61201ae0611fb25bad +Subproject commit 2b209eab184d2feee7bd146ee580ae3c983b85f4 From af477444c1e1e0596b01db12bb1b3bbe857b7fad Mon Sep 17 00:00:00 2001 From: "Nguyen Xuan, Tu" Date: Thu, 30 Jan 2025 10:32:06 +0100 Subject: [PATCH 03/22] Fixed indentation --- src/t8_cmesh/t8_cmesh.cxx | 44 ++++---- src/t8_cmesh/t8_cmesh_trees.cxx | 113 ++++++++++----------- src/t8_cmesh/t8_cmesh_vtk_mesh_reader.hxx | 4 +- src/t8_geometry/t8_geometry.cxx | 2 +- src/t8_vtk/t8_vtk_write_ASCII.cxx | 28 ++--- test/t8_IO/t8_gtest_vtk_write_read.cxx | 58 +++++------ test/t8_cmesh/t8_gtest_cmesh_partition.cxx | 2 +- 7 files changed, 119 insertions(+), 132 deletions(-) diff --git a/src/t8_cmesh/t8_cmesh.cxx b/src/t8_cmesh/t8_cmesh.cxx index b2b3104a3a..9cf75cfc8b 100644 --- a/src/t8_cmesh/t8_cmesh.cxx +++ b/src/t8_cmesh/t8_cmesh.cxx @@ -150,7 +150,7 @@ t8_cmesh_validate_geometry (const t8_cmesh_t cmesh, const int check_for_negative t8_debugf ("Detected incompatible geometry for tree %li\n", (long) itree); return false; } - else if (check_for_negative_volume){ + else if (check_for_negative_volume) { /* Check for negative volume. This only makes sense if the geometry is valid for the tree. */ const int negative_volume = cmesh->geometry_handler->tree_negative_volume (cmesh, t8_cmesh_get_global_id (cmesh, itree)); @@ -589,26 +589,23 @@ t8_cmesh_is_equal_ext (const t8_cmesh_t cmesh_a, const t8_cmesh_t cmesh_b, const } /* check entries that are numbers */ if (cmesh_a->committed != cmesh_b->committed || cmesh_a->dimension != cmesh_b->dimension - || cmesh_a->set_partition != cmesh_b->set_partition || cmesh_a->mpirank != cmesh_b->mpirank - || cmesh_a->mpisize != cmesh_b->mpisize || cmesh_a->num_trees != cmesh_b->num_trees - || cmesh_a->num_local_trees != cmesh_b->num_local_trees || cmesh_a->num_ghosts != cmesh_b->num_ghosts - || cmesh_a->first_tree != cmesh_b->first_tree) - { + || cmesh_a->set_partition != cmesh_b->set_partition || cmesh_a->mpirank != cmesh_b->mpirank + || cmesh_a->mpisize != cmesh_b->mpisize || cmesh_a->num_trees != cmesh_b->num_trees + || cmesh_a->num_local_trees != cmesh_b->num_local_trees || cmesh_a->num_ghosts != cmesh_b->num_ghosts + || cmesh_a->first_tree != cmesh_b->first_tree) { return 0; } /* check arrays */ - if (memcmp (cmesh_a->num_trees_per_eclass, cmesh_b->num_trees_per_eclass, T8_ECLASS_COUNT * sizeof (t8_gloidx_t))) - { + if (memcmp (cmesh_a->num_trees_per_eclass, cmesh_b->num_trees_per_eclass, T8_ECLASS_COUNT * sizeof (t8_gloidx_t))) { return 0; } if (memcmp (cmesh_a->num_local_trees_per_eclass, cmesh_b->num_local_trees_per_eclass, - T8_ECLASS_COUNT * sizeof (t8_locidx_t))) - { + T8_ECLASS_COUNT * sizeof (t8_locidx_t))) { return 0; } - if (same_tree_order){ + if (same_tree_order) { /* check tree_offsets */ if (cmesh_a->tree_offsets != NULL) { if (cmesh_b->tree_offsets == NULL) { @@ -616,41 +613,40 @@ t8_cmesh_is_equal_ext (const t8_cmesh_t cmesh_a, const t8_cmesh_t cmesh_b, const } else { if (!t8_shmem_array_is_equal (cmesh_a->tree_offsets, cmesh_b->tree_offsets)) - return 0; + return 0; } } } /* check trees */ - if (same_tree_order) - { + if (same_tree_order) { if (cmesh_a->committed && !t8_cmesh_trees_is_equal (cmesh_a, cmesh_a->trees, cmesh_b->trees, 1)) { /* if we have committed check tree arrays */ - t8_global_productionf("Failed on equal trees"); + t8_global_productionf ("Failed on equal trees"); return 0; } else { if (!cmesh_a->committed && !t8_stash_is_equal (cmesh_a->stash, cmesh_b->stash)) { - /* if we have not committed check stash arrays */ - return 0; + /* if we have not committed check stash arrays */ + return 0; } } } - else{ + else { if (cmesh_a->committed && !t8_cmesh_trees_is_equal (cmesh_a, cmesh_a->trees, cmesh_b->trees, 0)) { /* if we have committed check tree arrays */ - t8_global_productionf("Failed on equal trees %i", t8_cmesh_trees_is_equal (cmesh_a, cmesh_a->trees, cmesh_b->trees, 0)); + t8_global_productionf ("Failed on equal trees %i", + t8_cmesh_trees_is_equal (cmesh_a, cmesh_a->trees, cmesh_b->trees, 0)); return 0; } else { if (!cmesh_a->committed && !t8_stash_is_equal (cmesh_a->stash, cmesh_b->stash)) { - /* if we have not committed check stash arrays */ - return 0; + /* if we have not committed check stash arrays */ + return 0; } } } - - return 1; - + + return 1; } int diff --git a/src/t8_cmesh/t8_cmesh_trees.cxx b/src/t8_cmesh/t8_cmesh_trees.cxx index 8df075df66..4835e59335 100644 --- a/src/t8_cmesh/t8_cmesh_trees.cxx +++ b/src/t8_cmesh/t8_cmesh_trees.cxx @@ -1172,54 +1172,55 @@ t8_cmesh_trees_is_face_consistent (const t8_cmesh_t cmesh, const t8_cmesh_trees_ return ret; } -static bool t8_cmesh_tree_is_equal(const t8_gloidx_t tree_id_a, const t8_gloidx_t tree_id_b, const t8_cmesh_trees_t trees_a, const t8_cmesh_trees_t trees_b, const bool check_face_neighbors) +static bool +t8_cmesh_tree_is_equal (const t8_gloidx_t tree_id_a, const t8_gloidx_t tree_id_b, const t8_cmesh_trees_t trees_a, + const t8_cmesh_trees_t trees_b, const bool check_face_neighbors) { /* Get the treea and their face neighbors */ - t8_locidx_t *face_neighborsa, *face_neighborsb; - int8_t *ttfa, *ttfb; - size_t attsizea, attsizeb; - t8_attribute_info_struct_t *first_atta, *first_attb; - char *atta, *attb; - - const t8_ctree_t treea = t8_cmesh_trees_get_tree_ext (trees_a, tree_id_a, &face_neighborsa, &ttfa); - const t8_ctree_t treeb = t8_cmesh_trees_get_tree_ext (trees_b, tree_id_b, &face_neighborsb, &ttfb); - /* Compare tree entries */ - if (!(treea->eclass == treeb->eclass && treea->num_attributes == treeb->num_attributes - && treea->treeid == treeb->treeid)) - { + t8_locidx_t *face_neighborsa, *face_neighborsb; + int8_t *ttfa, *ttfb; + size_t attsizea, attsizeb; + t8_attribute_info_struct_t *first_atta, *first_attb; + char *atta, *attb; + + const t8_ctree_t treea = t8_cmesh_trees_get_tree_ext (trees_a, tree_id_a, &face_neighborsa, &ttfa); + const t8_ctree_t treeb = t8_cmesh_trees_get_tree_ext (trees_b, tree_id_b, &face_neighborsb, &ttfb); + /* Compare tree entries */ + if (!(treea->eclass == treeb->eclass && treea->num_attributes == treeb->num_attributes + && treea->treeid == treeb->treeid)) { + return 0; + } + t8_eclass_t eclass = treea->eclass; + /* Compare face neighbors */ + if (check_face_neighbors) { + if (memcmp (face_neighborsa, face_neighborsb, t8_eclass_num_faces[eclass] * sizeof (t8_locidx_t)) + || memcmp (ttfa, ttfb, t8_eclass_num_faces[eclass] * sizeof (int8_t))) { return 0; } - t8_eclass_t eclass = treea->eclass; - /* Compare face neighbors */ - if (check_face_neighbors){ - if (memcmp (face_neighborsa, face_neighborsb, t8_eclass_num_faces[eclass] * sizeof (t8_locidx_t)) - || memcmp (ttfa, ttfb, t8_eclass_num_faces[eclass] * sizeof (int8_t))) - { - return 0; - } - } - /* Compare attributes */ - attsizea = t8_cmesh_trees_attribute_size (treea); - attsizeb = t8_cmesh_trees_attribute_size (treeb); - if (attsizea != attsizeb) { + } + /* Compare attributes */ + attsizea = t8_cmesh_trees_attribute_size (treea); + attsizeb = t8_cmesh_trees_attribute_size (treeb); + if (attsizea != attsizeb) { + return 0; + } + if (attsizea > 0) { + /* Get pointers to all attributes */ + first_atta = T8_TREE_ATTR_INFO (treea, 0); + first_attb = T8_TREE_ATTR_INFO (treeb, 0); + atta = (char *) T8_TREE_ATTR (treea, first_atta); + attb = (char *) T8_TREE_ATTR (treeb, first_attb); + if (memcmp (atta, attb, attsizea)) { return 0; } - if (attsizea > 0) { - /* Get pointers to all attributes */ - first_atta = T8_TREE_ATTR_INFO (treea, 0); - first_attb = T8_TREE_ATTR_INFO (treeb, 0); - atta = (char *) T8_TREE_ATTR (treea, first_atta); - attb = (char *) T8_TREE_ATTR (treeb, first_attb); - if (memcmp (atta, attb, attsizea)) { - return 0; - } - } + } return 1; } int -t8_cmesh_trees_is_equal (const t8_cmesh_t cmesh, const t8_cmesh_trees_t trees_a, const t8_cmesh_trees_t trees_b, const int same_tree_order) +t8_cmesh_trees_is_equal (const t8_cmesh_t cmesh, const t8_cmesh_trees_t trees_a, const t8_cmesh_trees_t trees_b, + const int same_tree_order) { int is_equal; t8_locidx_t num_trees, num_ghost, ighost; @@ -1245,24 +1246,21 @@ t8_cmesh_trees_is_equal (const t8_cmesh_t cmesh, const t8_cmesh_trees_t trees_a, num_ghost = cmesh->num_ghosts; /* We now compare all trees and their attributes */ - if(!same_tree_order){ + if (!same_tree_order) { for (t8_locidx_t itree = 0; itree < num_trees; itree++) { - for (t8_locidx_t jtree = 0; jtree < num_trees; jtree++){ - if (t8_cmesh_tree_is_equal(itree, jtree, trees_a, trees_b, false)){ + for (t8_locidx_t jtree = 0; jtree < num_trees; jtree++) { + if (t8_cmesh_tree_is_equal (itree, jtree, trees_a, trees_b, false)) { break; } - else if(jtree == num_trees){ + else if (jtree == num_trees) { return 0; } } } - } - else - { - for (t8_locidx_t itree = 0; itree < num_trees; itree++) - { - if (!t8_cmesh_tree_is_equal(itree, itree, trees_a, trees_b, true)) - { + } + else { + for (t8_locidx_t itree = 0; itree < num_trees; itree++) { + if (!t8_cmesh_tree_is_equal (itree, itree, trees_a, trees_b, true)) { return 0; } } @@ -1273,35 +1271,30 @@ t8_cmesh_trees_is_equal (const t8_cmesh_t cmesh, const t8_cmesh_trees_t trees_a, ghostb = t8_cmesh_trees_get_ghost_ext (trees_b, ighost, &gface_neighborsb, &ttfb); /* Compare ghost entries */ is_equal = ghosta->eclass == ghostb->eclass && ghosta->num_attributes == ghostb->num_attributes - && ghosta->treeid == ghostb->treeid; - if (!is_equal) - { + && ghosta->treeid == ghostb->treeid; + if (!is_equal) { return 0; } eclass = ghosta->eclass; /* Compare face neighbors */ is_equal = !memcmp (gface_neighborsa, gface_neighborsb, t8_eclass_num_faces[eclass] * sizeof (t8_gloidx_t)) - && !memcmp (ttfa, ttfb, t8_eclass_num_faces[eclass] * sizeof (int8_t)); - if (!is_equal) - { + && !memcmp (ttfa, ttfb, t8_eclass_num_faces[eclass] * sizeof (int8_t)); + if (!is_equal) { return 0; } /* Compare attributes */ attsizea = t8_cmesh_trees_ghost_attribute_size (ghosta); attsizeb = t8_cmesh_trees_ghost_attribute_size (ghostb); - if (attsizea != attsizeb) - { + if (attsizea != attsizeb) { return 0; } - if (attsizea > 0) - { + if (attsizea > 0) { /* Get pointers to all attributes */ first_atta = T8_GHOST_ATTR_INFO (ghosta, 0); first_attb = T8_GHOST_ATTR_INFO (ghostb, 0); atta = (char *) T8_GHOST_ATTR (ghosta, first_atta); attb = (char *) T8_GHOST_ATTR (ghostb, first_attb); - if (memcmp (atta, attb, attsizea)) - { + if (memcmp (atta, attb, attsizea)) { return 0; } } diff --git a/src/t8_cmesh/t8_cmesh_vtk_mesh_reader.hxx b/src/t8_cmesh/t8_cmesh_vtk_mesh_reader.hxx index 877e92347c..c1cb65213c 100644 --- a/src/t8_cmesh/t8_cmesh_vtk_mesh_reader.hxx +++ b/src/t8_cmesh/t8_cmesh_vtk_mesh_reader.hxx @@ -28,6 +28,4 @@ #ifndef T8_CMESH_SAVE_HXX #define T8_CMESH_SAVE_HXX - - -#endif /* T8_CMESH_SAVE_HXX */ \ No newline at end of file +#endif /* T8_CMESH_SAVE_HXX */ diff --git a/src/t8_geometry/t8_geometry.cxx b/src/t8_geometry/t8_geometry.cxx index df8ce0c030..7fc9d8f1c7 100644 --- a/src/t8_geometry/t8_geometry.cxx +++ b/src/t8_geometry/t8_geometry.cxx @@ -73,7 +73,7 @@ t8_geometry_tree_negative_volume (const t8_cmesh_t cmesh, const t8_gloidx_t gtre int t8_geometry_get_num_geometries (const t8_cmesh_t cmesh) { - if (cmesh->geometry_handler == nullptr){ + if (cmesh->geometry_handler == nullptr) { return 0; } return cmesh->geometry_handler->get_num_geometries (); diff --git a/src/t8_vtk/t8_vtk_write_ASCII.cxx b/src/t8_vtk/t8_vtk_write_ASCII.cxx index 06c6d80787..49ba06ab17 100644 --- a/src/t8_vtk/t8_vtk_write_ASCII.cxx +++ b/src/t8_vtk/t8_vtk_write_ASCII.cxx @@ -793,13 +793,13 @@ t8_forest_vtk_write_ASCII (t8_forest_t forest, const char *fileprefix, const int T8_ASSERT (forest != NULL); T8_ASSERT (t8_forest_is_committed (forest)); T8_ASSERT (fileprefix != NULL); - if (forest->cmesh->geometry_handler == nullptr){ - t8_errorf("Error: Forest could not be written as vtk since it does not have geometries.\n"); - return false; - } - if (forest->cmesh->geometry_handler->get_num_geometries() == 0){ - t8_errorf("Error: Forest could not be written as vtk since it does not have geometries.\n"); - return false; + if (forest->cmesh->geometry_handler == nullptr) { + t8_errorf ("Error: Forest could not be written as vtk since it does not have geometries.\n"); + return false; + } + if (forest->cmesh->geometry_handler->get_num_geometries () == 0) { + t8_errorf ("Error: Forest could not be written as vtk since it does not have geometries.\n"); + return false; } if (forest->ghosts == NULL || forest->ghosts->num_ghosts_elements == 0) { /* Never write ghost elements if there aren't any */ @@ -940,13 +940,13 @@ t8_cmesh_vtk_write_file_ext (const t8_cmesh_t cmesh, const char *fileprefix, con T8_ASSERT (t8_cmesh_is_committed (cmesh)); T8_ASSERT (fileprefix != NULL); - if (cmesh->geometry_handler == nullptr){ - t8_errorf("Error: Cmesh could not be written as vtk since it does not have geometries.\n"); - return false; - } - if (cmesh->geometry_handler->get_num_geometries() == 0){ - t8_errorf("Error: Cmesh could not be written as vtk since it does not have geometries.\n"); - return false; + if (cmesh->geometry_handler == nullptr) { + t8_errorf ("Error: Cmesh could not be written as vtk since it does not have geometries.\n"); + return false; + } + if (cmesh->geometry_handler->get_num_geometries () == 0) { + t8_errorf ("Error: Cmesh could not be written as vtk since it does not have geometries.\n"); + return false; } if (cmesh->mpirank == 0) { diff --git a/test/t8_IO/t8_gtest_vtk_write_read.cxx b/test/t8_IO/t8_gtest_vtk_write_read.cxx index eeb157c179..3040261cdc 100644 --- a/test/t8_IO/t8_gtest_vtk_write_read.cxx +++ b/test/t8_IO/t8_gtest_vtk_write_read.cxx @@ -37,14 +37,14 @@ class vtk_write_read_test: public testing::TestWithParam { void SetUp () override { - cmesh = GetParam ()->cmesh_create (); //create a cmesh from example base + cmesh = GetParam ()->cmesh_create (); /* create a cmesh from example base */ } void TearDown () override { - std::remove("test_vtk_0.vtu"); - std::remove("test_vtk.pvtu"); //delete files after test finished + std::remove ("test_vtk_0.vtu"); + std::remove ("test_vtk.pvtu"); /* delete files after test finished */ } t8_cmesh_t cmesh; }; @@ -53,43 +53,43 @@ TEST_P (vtk_write_read_test, write_read_vtk) { t8_cmesh_t unpartitioned_cmesh_read, unpartitioned_cmesh_write; - const int write_success = t8_cmesh_vtk_write_file_via_API (cmesh, "test_vtk", sc_MPI_COMM_WORLD); - const bool partitioned = t8_cmesh_is_partitioned(cmesh); + const int write_success = t8_cmesh_vtk_write_file_via_API (cmesh, "test_vtk", sc_MPI_COMM_WORLD); + const bool partitioned = t8_cmesh_is_partitioned (cmesh); t8_cmesh_t cmesh2 = t8_vtk_reader_cmesh ("test_vtk.pvtu", partitioned, 0, sc_MPI_COMM_WORLD, VTK_SERIAL_FILE); - ASSERT_EQ(cmesh2!=NULL, write_success); + ASSERT_EQ (cmesh2 != NULL, write_success); - if (cmesh2 != NULL){ - if (partitioned){ //repartition if cmesh is partitioned + if (cmesh2 != NULL) { + if (partitioned) { /* repartition if cmesh is partitioned */ t8_cmesh_init (&unpartitioned_cmesh_write); t8_cmesh_set_derive (unpartitioned_cmesh_write, cmesh); - t8_cmesh_set_partition_offsets (unpartitioned_cmesh_write, t8_cmesh_offset_percent(cmesh, sc_MPI_COMM_WORLD, 100)); - t8_cmesh_commit(unpartitioned_cmesh_write, sc_MPI_COMM_WORLD); + t8_cmesh_set_partition_offsets (unpartitioned_cmesh_write, + t8_cmesh_offset_percent (cmesh, sc_MPI_COMM_WORLD, 100)); + t8_cmesh_commit (unpartitioned_cmesh_write, sc_MPI_COMM_WORLD); t8_cmesh_init (&unpartitioned_cmesh_read); t8_cmesh_set_derive (unpartitioned_cmesh_read, cmesh2); - t8_cmesh_set_partition_offsets (unpartitioned_cmesh_read, t8_cmesh_offset_percent(cmesh2, sc_MPI_COMM_WORLD, 100)); - t8_cmesh_commit(unpartitioned_cmesh_read, sc_MPI_COMM_WORLD); - - //check equality of repartioned cmeshes - t8_gloidx_t num_trees_cmesh_1 = t8_cmesh_get_num_trees(unpartitioned_cmesh_write); - t8_gloidx_t num_trees_cmesh_2 = t8_cmesh_get_num_trees(unpartitioned_cmesh_read); - ASSERT_EQ(num_trees_cmesh_1, num_trees_cmesh_2); - EXPECT_TRUE(t8_cmesh_is_equal_ext(unpartitioned_cmesh_write, unpartitioned_cmesh_read, 0)); + t8_cmesh_set_partition_offsets (unpartitioned_cmesh_read, + t8_cmesh_offset_percent (cmesh2, sc_MPI_COMM_WORLD, 100)); + t8_cmesh_commit (unpartitioned_cmesh_read, sc_MPI_COMM_WORLD); - //destroy both cmeshes - t8_cmesh_unref(&unpartitioned_cmesh_read); - t8_cmesh_unref(&unpartitioned_cmesh_write); + /* check equality of repartioned cmeshes */ + t8_gloidx_t num_trees_cmesh_1 = t8_cmesh_get_num_trees (unpartitioned_cmesh_write); + t8_gloidx_t num_trees_cmesh_2 = t8_cmesh_get_num_trees (unpartitioned_cmesh_read); + ASSERT_EQ (num_trees_cmesh_1, num_trees_cmesh_2); + EXPECT_TRUE (t8_cmesh_is_equal_ext (unpartitioned_cmesh_write, unpartitioned_cmesh_read, 0)); + + /* destroy both cmeshes */ + t8_cmesh_unref (&unpartitioned_cmesh_read); + t8_cmesh_unref (&unpartitioned_cmesh_write); } - else{ //continue normally without repartitioning - t8_gloidx_t num_trees_cmesh_1 = t8_cmesh_get_num_trees(cmesh); - t8_gloidx_t num_trees_cmesh_2 = t8_cmesh_get_num_trees(cmesh2); - ASSERT_EQ(num_trees_cmesh_1, num_trees_cmesh_2); - EXPECT_TRUE(t8_cmesh_is_equal_ext(cmesh, cmesh2, 0)); - t8_cmesh_unref(&cmesh2); + else { /* continue normally without repartitioning */ + t8_gloidx_t num_trees_cmesh_1 = t8_cmesh_get_num_trees (cmesh); + t8_gloidx_t num_trees_cmesh_2 = t8_cmesh_get_num_trees (cmesh2); + ASSERT_EQ (num_trees_cmesh_1, num_trees_cmesh_2); + EXPECT_TRUE (t8_cmesh_is_equal_ext (cmesh, cmesh2, 0)); + t8_cmesh_unref (&cmesh2); t8_cmesh_unref (&cmesh); } } } INSTANTIATE_TEST_SUITE_P (Test_vtk_write_read, vtk_write_read_test, AllCmeshsParam, pretty_print_base_example); - - diff --git a/test/t8_cmesh/t8_gtest_cmesh_partition.cxx b/test/t8_cmesh/t8_gtest_cmesh_partition.cxx index 6551723b17..9376cb60f0 100644 --- a/test/t8_cmesh/t8_gtest_cmesh_partition.cxx +++ b/test/t8_cmesh/t8_gtest_cmesh_partition.cxx @@ -122,7 +122,7 @@ TEST_P (t8_cmesh_partition_class, test_cmesh_partition_concentrate) t8_cmesh_commit (cmesh_partition_new2, sc_MPI_COMM_WORLD); cmesh_partition_new1 = cmesh_partition_new2; } - ASSERT_TRUE (t8_cmesh_is_equal(cmesh_partition_new2, cmesh_partition)) << "Cmesh equality check failed."; + ASSERT_TRUE (t8_cmesh_is_equal (cmesh_partition_new2, cmesh_partition)) << "Cmesh equality check failed."; t8_cmesh_destroy (&cmesh_partition_new2); t8_cmesh_destroy (&cmesh_partition); } From f96276240aa3c76799644a3edd495392558ca736 Mon Sep 17 00:00:00 2001 From: Hannes Brandt Date: Wed, 30 Oct 2024 15:17:00 +0100 Subject: [PATCH 04/22] search partition: add interface for replicated partition search --- src/t8_forest/t8_forest_iterate.cxx | 6 ++++ src/t8_forest/t8_forest_iterate.h | 55 +++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/src/t8_forest/t8_forest_iterate.cxx b/src/t8_forest/t8_forest_iterate.cxx index 6be23a5621..008cce7b54 100644 --- a/src/t8_forest/t8_forest_iterate.cxx +++ b/src/t8_forest/t8_forest_iterate.cxx @@ -537,4 +537,10 @@ t8_forest_iterate_replace (t8_forest_t forest_new, t8_forest_t forest_old, t8_fo t8_global_productionf ("Done t8_forest_iterate_replace\n"); } +void +t8_forest_search_partition (t8_forest_t forest, t8_forest_partition_search_fn search_fn, + t8_forest_partition_query_fn query_fn, sc_array_t *queries) +{ +} + T8_EXTERN_C_END (); diff --git a/src/t8_forest/t8_forest_iterate.h b/src/t8_forest/t8_forest_iterate.h index 5f1ac2f27b..bdf5191032 100644 --- a/src/t8_forest/t8_forest_iterate.h +++ b/src/t8_forest/t8_forest_iterate.h @@ -79,6 +79,48 @@ typedef void (*t8_forest_query_fn) (t8_forest_t forest, const t8_locidx_t ltreei const int is_leaf, const t8_element_array_t *leaf_elements, const t8_locidx_t tree_leaf_index, sc_array_t *queries, sc_array_t *query_indices, int *query_matches, const size_t num_active_queries); +/** + * A call-back function used by \ref t8_forest_search_partition describing a search-criterion. Is called on an element + * and the search criterion should be checked on that element. Return true if the search criterion is met, false + * otherwise. + * + * \param[in] forest the forest + * \param[in] ltreeid the local tree id of the current tree in the cmesh. Since the cmesh has to be + * replicated, it coincides with the global tree id. + * \param[in] element the element for which the search criterion is checked + * \param[in] pfirst the lowest processor that owns part of \a element. Guaranteed to be non-empty. + * \param[in] plast the highest processor that owns part of \a element. Guaranteed to be non-empty. + * \returns non-zero if the search criterion is met, zero otherwise. + */ +typedef int (*t8_forest_partition_search_fn) (t8_forest_t forest, const t8_locidx_t ltreeid, + const t8_element_t *element, const int pfirst, const int plast); + +/** + * A call-back function used by \ref t8_forest_search_partition for queries. Is called on an element and all queries are + * checked on that element. All positive queries are passed further down to the children of the element. The results of + * the check are stored in \a query_matches. + * + * \param[in] forest the forest + * \param[in] ltreeid the local tree id of the current tree in the cmesh. Since the cmesh has to be + * replicated, it coincides with the global tree id. + * \param[in] element the element for which the query is executed + * \param[in] pfirst the lowest processor that owns part of \a element. Guaranteed to be non-empty. + * \param[in] plast the highest processor that owns part of \a element. Guaranteed to be non-empty. + * if this is equal to \a pfirst, then the recursion will stop for + * \a element's branch after this function returns. + * \param[in] queries an array of queries that are checked by the function + * \param[in] query_indices an array of size_t entries, where each entry is an index of a query in \a queries. + * \param[in, out] query_matches an array of length \a num_active_queries. + * If the element is not a leaf must be set to true or false at the i-th index for + * each query, specifying whether the element 'matches' the query of the i-th query + * index or not. When the element is a leaf we can return before all entries are set. + * \param[in] num_active_queries The number of currently active queries (equals the number of entries of + * \a query_matches and entries of \a query_indices). + */ +typedef int (*t8_forest_partition_query_fn) (t8_forest_t forest, const t8_locidx_t ltreeid, const t8_element_t *element, + const int pfirst, const int plast, void *queries, + sc_array_t *query_indices, int *query_matches, + const size_t num_active_queries); T8_EXTERN_C_BEGIN (); @@ -134,6 +176,19 @@ t8_forest_search (t8_forest_t forest, t8_forest_search_fn search_fn, t8_forest_q void t8_forest_iterate_replace (t8_forest_t forest_new, t8_forest_t forest_old, t8_forest_replace_t replace_fn); +/* Perform a top-down search of the global partition, executing a callback on + * each intermediate element. The search will enter each tree at least once. + * The recursion will only go down branches that are split between multiple processors. + * This is not a collective function. It does not communicate. + * The function expects the coarse mesh to be replicated. + * If the callback returns false for an element, its descendants + * are not further searched. + * To pass user data to \b search_fn function use \ref t8_forest_set_user_data + */ +void +t8_forest_search_partition (t8_forest_t forest, t8_forest_partition_search_fn search_fn, + t8_forest_partition_query_fn query_fn, sc_array_t *queries); + T8_EXTERN_C_END (); #endif /* !T8_FOREST_ITERATE_H */ From 5e96f639f443167232566448e471e077150095e2 Mon Sep 17 00:00:00 2001 From: Hannes Brandt Date: Tue, 5 Nov 2024 11:43:49 +0100 Subject: [PATCH 05/22] search partition: add author file --- doc/author_brandt.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 doc/author_brandt.txt diff --git a/doc/author_brandt.txt b/doc/author_brandt.txt new file mode 100644 index 0000000000..095dab52be --- /dev/null +++ b/doc/author_brandt.txt @@ -0,0 +1 @@ +I place my contributions to t8code under the FreeBSD license. Hannes Brandt (brandt@ins.uni-bonn.de) From d9b7f604e53623e9a53a8c1541c22a5b04dab73e Mon Sep 17 00:00:00 2001 From: Hannes Brandt Date: Tue, 5 Nov 2024 12:19:23 +0100 Subject: [PATCH 06/22] search partition: const forest and comments --- src/t8_forest/t8_forest_iterate.cxx | 3 ++- src/t8_forest/t8_forest_iterate.h | 26 ++++++++++++++++---------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/t8_forest/t8_forest_iterate.cxx b/src/t8_forest/t8_forest_iterate.cxx index 008cce7b54..e4db3bca7e 100644 --- a/src/t8_forest/t8_forest_iterate.cxx +++ b/src/t8_forest/t8_forest_iterate.cxx @@ -538,9 +538,10 @@ t8_forest_iterate_replace (t8_forest_t forest_new, t8_forest_t forest_old, t8_fo } void -t8_forest_search_partition (t8_forest_t forest, t8_forest_partition_search_fn search_fn, +t8_forest_search_partition (const t8_forest_t forest, t8_forest_partition_search_fn search_fn, t8_forest_partition_query_fn query_fn, sc_array_t *queries) { + T8_ASSERT (0); /* not implemented yet */ } T8_EXTERN_C_END (); diff --git a/src/t8_forest/t8_forest_iterate.h b/src/t8_forest/t8_forest_iterate.h index bdf5191032..5623806261 100644 --- a/src/t8_forest/t8_forest_iterate.h +++ b/src/t8_forest/t8_forest_iterate.h @@ -88,11 +88,11 @@ typedef void (*t8_forest_query_fn) (t8_forest_t forest, const t8_locidx_t ltreei * \param[in] ltreeid the local tree id of the current tree in the cmesh. Since the cmesh has to be * replicated, it coincides with the global tree id. * \param[in] element the element for which the search criterion is checked - * \param[in] pfirst the lowest processor that owns part of \a element. Guaranteed to be non-empty. - * \param[in] plast the highest processor that owns part of \a element. Guaranteed to be non-empty. + * \param[in] pfirst the first processor that owns part of \a element. Guaranteed to be non-empty. + * \param[in] plast the last processor that owns part of \a element. Guaranteed to be non-empty. * \returns non-zero if the search criterion is met, zero otherwise. */ -typedef int (*t8_forest_partition_search_fn) (t8_forest_t forest, const t8_locidx_t ltreeid, +typedef int (*t8_forest_partition_search_fn) (const t8_forest_t forest, const t8_locidx_t ltreeid, const t8_element_t *element, const int pfirst, const int plast); /** @@ -104,8 +104,8 @@ typedef int (*t8_forest_partition_search_fn) (t8_forest_t forest, const t8_locid * \param[in] ltreeid the local tree id of the current tree in the cmesh. Since the cmesh has to be * replicated, it coincides with the global tree id. * \param[in] element the element for which the query is executed - * \param[in] pfirst the lowest processor that owns part of \a element. Guaranteed to be non-empty. - * \param[in] plast the highest processor that owns part of \a element. Guaranteed to be non-empty. + * \param[in] pfirst the first processor that owns part of \a element. Guaranteed to be non-empty. + * \param[in] plast the last processor that owns part of \a element. Guaranteed to be non-empty. * if this is equal to \a pfirst, then the recursion will stop for * \a element's branch after this function returns. * \param[in] queries an array of queries that are checked by the function @@ -117,9 +117,9 @@ typedef int (*t8_forest_partition_search_fn) (t8_forest_t forest, const t8_locid * \param[in] num_active_queries The number of currently active queries (equals the number of entries of * \a query_matches and entries of \a query_indices). */ -typedef int (*t8_forest_partition_query_fn) (t8_forest_t forest, const t8_locidx_t ltreeid, const t8_element_t *element, - const int pfirst, const int plast, void *queries, - sc_array_t *query_indices, int *query_matches, +typedef int (*t8_forest_partition_query_fn) (const t8_forest_t forest, const t8_locidx_t ltreeid, + const t8_element_t *element, const int pfirst, const int plast, + void *queries, sc_array_t *query_indices, int *query_matches, const size_t num_active_queries); T8_EXTERN_C_BEGIN (); @@ -176,7 +176,8 @@ t8_forest_search (t8_forest_t forest, t8_forest_search_fn search_fn, t8_forest_q void t8_forest_iterate_replace (t8_forest_t forest_new, t8_forest_t forest_old, t8_forest_replace_t replace_fn); -/* Perform a top-down search of the global partition, executing a callback on +/** + * Perform a top-down search of the global partition, executing a callback on * each intermediate element. The search will enter each tree at least once. * The recursion will only go down branches that are split between multiple processors. * This is not a collective function. It does not communicate. @@ -184,9 +185,14 @@ t8_forest_iterate_replace (t8_forest_t forest_new, t8_forest_t forest_old, t8_fo * If the callback returns false for an element, its descendants * are not further searched. * To pass user data to \b search_fn function use \ref t8_forest_set_user_data + * + * \param[in] forest the forest to be searched + * \param[in] search_fn a search callback function called on elements + * \param[in] query_fn a query callback function called for all active queries of an element + * \param[in,out] queries an array of queries that are checked by the function */ void -t8_forest_search_partition (t8_forest_t forest, t8_forest_partition_search_fn search_fn, +t8_forest_search_partition (const t8_forest_t forest, t8_forest_partition_search_fn search_fn, t8_forest_partition_query_fn query_fn, sc_array_t *queries); T8_EXTERN_C_END (); From 75861d19f3270093bef641065e355489cbd1e4f2 Mon Sep 17 00:00:00 2001 From: Johannes Holke Date: Fri, 8 Nov 2024 12:16:56 +0100 Subject: [PATCH 07/22] Design a C++ interface for search We declare an interface for the search functionality. It is yet not implemented. A new templated search class and search_with_queries class that inherits from it. --- src/CMakeLists.txt | 1 + .../t8_forest_search/t8_forest_search.hxx | 141 ++++++++++++++++++ 2 files changed, 142 insertions(+) create mode 100644 src/t8_forest/t8_forest_search/t8_forest_search.hxx diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 73494a5ce7..d9bcfec1de 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -196,6 +196,7 @@ install( FILES t8_element.h t8_element_shape.h t8_forest_netcdf.h + t8_forest_search.hxx t8_mat.h t8_mesh.h t8_netcdf.h diff --git a/src/t8_forest/t8_forest_search/t8_forest_search.hxx b/src/t8_forest/t8_forest_search/t8_forest_search.hxx new file mode 100644 index 0000000000..b82b4ed41d --- /dev/null +++ b/src/t8_forest/t8_forest_search/t8_forest_search.hxx @@ -0,0 +1,141 @@ +/* + 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) 2024 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. +*/ + +/** \file We declare a modern C++ interface for the search functionality. */ + +#ifndef T8_FOREST_SEARCH_HXX +#define T8_FOREST_SEARCH_HXX + +#include +#include +#include + +/* + * Discussion about C++ callback handling https://stackoverflow.com/questions/2298242/callback-functions-in-c + * We decided for option 4, using std::function together with templates. +*/ + +template +using t8_search_element_callback + = std::function; + +template +using t8_search_queries_callback = std::function &queries, + std::vector &active_query_indices, std::vector &query_matches, Udata &user_data)>; + +template +class search { + public: + search (t8_search_element_callback element_callback, const t8_forest_t forest = nullptr); + + void + update_forest (const t8_forest_t forest); + void + update_user_data (const Udata &udata); + + ~search (); + + void + do_search (); + + private: + void + search_tree (); + void + search_recursion (); + + t8_search_element_callback element_callback; + + const t8_forest_t &forest; + const Udata &user_data; +}; + +template +class search_with_queries: public search { + public: + search_with_queries (t8_search_element_callback element_callback, + t8_search_queries_callback queries_callback, std::vector &queries, + const t8_forest_t forest = nullptr); + + ~search_with_queries (); + + private: + t8_search_queries_callback queries_callback; + const std::vector &queries; +}; + +#if 0 +//General shape of search + +template +void +do_search () ( + // init queries + for each tree { + search_tree { + // init NCA and get elements + element = NCA; + search_recursion(element) { + if (stop_due_to_queries) { + return; + } + ret = element_callback(element); + if (!ret) return; + do_queries (); + + // Prepare recursion + for all children search_recursion (child[i]); + } + // delete NCA and elements + } + } + // delete queries +} + +search::do_queries () +{ + return; +} + +search::stop_due_to_queries () { + return false; +} + search_with_queries::do_queries () +{ + if (queries) { + if (!leaf) // Init new query array + query_callback (element, queries, query_matches); + if (!leaf) // Fill new query array + } +} + search_with_queries::stop_due_to_queries () { + if (queries != NULL && num_active == 0) { + /* There are no queries left. We stop the recursion */ + return true; + } +} +#endif + +#endif // T8_FOREST_SEARCH_HXX From ee066831e5d5ac6f0316bdfa411717c3e6add917 Mon Sep 17 00:00:00 2001 From: Johannes Holke Date: Fri, 8 Nov 2024 12:39:06 +0100 Subject: [PATCH 08/22] Add C Interface for search C++ --- .../t8_forest_search_c_interface.cxx | 466 ++++++++++++++++++ .../t8_forest_search_c_interface.h | 82 +++ 2 files changed, 548 insertions(+) create mode 100644 src/t8_forest/t8_forest_search/t8_forest_search_c_interface.cxx create mode 100644 src/t8_forest/t8_forest_search/t8_forest_search_c_interface.h diff --git a/src/t8_forest/t8_forest_search/t8_forest_search_c_interface.cxx b/src/t8_forest/t8_forest_search/t8_forest_search_c_interface.cxx new file mode 100644 index 0000000000..88d57e5f65 --- /dev/null +++ b/src/t8_forest/t8_forest_search/t8_forest_search_c_interface.cxx @@ -0,0 +1,466 @@ +/* + 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. +*/ + +/* In this file we implement a C interface for the member functions of the + * t8_eclass_scheme_c class. + * With this interface you can use these member functions from a C file + * without the need of compiling it with C++. + */ + +#include +#include +#include + +size_t +t8_element_size (const t8_eclass_scheme_c *ts) +{ + T8_ASSERT (ts != NULL); + + return ts->t8_element_size (); +} + +int +t8_element_refines_irregular (const t8_eclass_scheme_c *ts) +{ + T8_ASSERT (ts != NULL); + + return ts->t8_element_refines_irregular (); +} + +int +t8_element_maxlevel (const t8_eclass_scheme_c *ts) +{ + T8_ASSERT (ts != NULL); + + return ts->t8_element_maxlevel (); +} + +int +t8_element_level (const t8_eclass_scheme_c *ts, const t8_element_t *elem) +{ + T8_ASSERT (ts != NULL); + + return ts->t8_element_level (elem); +} + +void +t8_element_copy (const t8_eclass_scheme_c *ts, const t8_element_t *source, t8_element_t *dest) +{ + T8_ASSERT (ts != NULL); + + ts->t8_element_copy (source, dest); +} + +int +t8_element_compare (const t8_eclass_scheme_c *ts, const t8_element_t *elem1, const t8_element_t *elem2) +{ + T8_ASSERT (ts != NULL); + + return ts->t8_element_compare (elem1, elem2); +} + +int +t8_element_equal (const t8_eclass_scheme_c *ts, const t8_element_t *elem1, const t8_element_t *elem2) +{ + T8_ASSERT (ts != NULL); + + return ts->t8_element_equal (elem1, elem2); +} + +void +t8_element_parent (const t8_eclass_scheme_c *ts, const t8_element_t *elem, t8_element_t *parent) +{ + T8_ASSERT (ts != NULL); + + ts->t8_element_parent (elem, parent); +} + +int +t8_element_num_siblings (const t8_eclass_scheme_c *ts, const t8_element_t *elem) +{ + T8_ASSERT (ts != NULL); + + return ts->t8_element_num_siblings (elem); +} + +void +t8_element_sibling (const t8_eclass_scheme_c *ts, const t8_element_t *elem, int sibid, t8_element_t *sibling) +{ + T8_ASSERT (ts != NULL); + + ts->t8_element_sibling (elem, sibid, sibling); +} + +int +t8_element_num_corners (const t8_eclass_scheme_c *ts, const t8_element_t *elem) +{ + T8_ASSERT (ts != NULL); + + return ts->t8_element_num_corners (elem); +} + +int +t8_element_num_faces (const t8_eclass_scheme_c *ts, const t8_element_t *elem) +{ + T8_ASSERT (ts != NULL); + + return ts->t8_element_num_faces (elem); +} + +int +t8_element_max_num_faces (const t8_eclass_scheme_c *ts, const t8_element_t *elem) +{ + T8_ASSERT (ts != NULL); + + return ts->t8_element_max_num_faces (elem); +} + +int +t8_element_num_children (const t8_eclass_scheme_c *ts, const t8_element_t *elem) +{ + T8_ASSERT (ts != NULL); + + return ts->t8_element_num_children (elem); +} + +int +t8_element_num_face_children (const t8_eclass_scheme_c *ts, const t8_element_t *elem, int face) +{ + T8_ASSERT (ts != NULL); + + return ts->t8_element_num_face_children (elem, face); +} + +int +t8_element_get_face_corner (const t8_eclass_scheme_c *ts, const t8_element_t *elem, int face, int corner) +{ + T8_ASSERT (ts != NULL); + + return ts->t8_element_get_face_corner (elem, face, corner); +} + +int +t8_element_get_corner_face (const t8_eclass_scheme_c *ts, const t8_element_t *elem, int corner, int face) +{ + T8_ASSERT (ts != NULL); + + return ts->t8_element_get_corner_face (elem, corner, face); +} + +void +t8_element_child (const t8_eclass_scheme_c *ts, const t8_element_t *elem, int childid, t8_element_t *child) +{ + T8_ASSERT (ts != NULL); + + ts->t8_element_child (elem, childid, child); +} + +void +t8_element_children (const t8_eclass_scheme_c *ts, const t8_element_t *elem, int length, t8_element_t *c[]) +{ + T8_ASSERT (ts != NULL); + + ts->t8_element_children (elem, length, c); +} + +int +t8_element_child_id (const t8_eclass_scheme_c *ts, const t8_element_t *elem) +{ + T8_ASSERT (ts != NULL); + + return ts->t8_element_child_id (elem); +} + +int +t8_element_ancestor_id (const t8_eclass_scheme_c *ts, const t8_element_t *elem, int level) +{ + T8_ASSERT (ts != NULL); + + return ts->t8_element_ancestor_id (elem, level); +} + +int +t8_element_is_family (const t8_eclass_scheme_c *ts, t8_element_t *const *fam) +{ + T8_ASSERT (ts != NULL); + + return ts->t8_element_is_family (fam); +} + +void +t8_element_nca (const t8_eclass_scheme_c *ts, const t8_element_t *elem1, const t8_element_t *elem2, t8_element_t *nca) +{ + T8_ASSERT (ts != NULL); + + ts->t8_element_nca (elem1, elem2, nca); +} + +t8_element_shape_t +t8_element_face_shape (const t8_eclass_scheme_c *ts, const t8_element_t *elem, int face) +{ + T8_ASSERT (ts != NULL); + + return ts->t8_element_face_shape (elem, face); +} + +void +t8_element_children_at_face (const t8_eclass_scheme_c *ts, const t8_element_t *elem, int face, t8_element_t *children[], + int num_children, int *child_indices) +{ + T8_ASSERT (ts != NULL); + + ts->t8_element_children_at_face (elem, face, children, num_children, child_indices); +} + +int +t8_element_face_child_face (const t8_eclass_scheme_c *ts, const t8_element_t *elem, int face, int face_child) +{ + T8_ASSERT (ts != NULL); + + return ts->t8_element_face_child_face (elem, face, face_child); +} + +int +t8_element_face_parent_face (const t8_eclass_scheme_c *ts, const t8_element_t *elem, int face) +{ + T8_ASSERT (ts != NULL); + + return ts->t8_element_face_parent_face (elem, face); +} + +int +t8_element_tree_face (const t8_eclass_scheme_c *ts, const t8_element_t *elem, int face) +{ + T8_ASSERT (ts != NULL); + + return ts->t8_element_tree_face (elem, face); +} + +void +t8_element_transform_face (const t8_eclass_scheme_c *ts, const t8_element_t *elem1, t8_element_t *elem2, + int orientation, int sign, int is_smaller_face) +{ + T8_ASSERT (ts != NULL); + + ts->t8_element_transform_face (elem1, elem2, orientation, sign, is_smaller_face); +} + +int +t8_element_extrude_face (const t8_eclass_scheme_c *ts, const t8_element_t *face, const t8_eclass_scheme_c *face_scheme, + t8_element_t *elem, int root_face) +{ + T8_ASSERT (ts != NULL); + + return ts->t8_element_extrude_face (face, face_scheme, elem, root_face); +} + +void +t8_element_boundary_face (const t8_eclass_scheme_c *ts, const t8_element_t *elem, int face, t8_element_t *boundary, + const t8_eclass_scheme_c *boundary_scheme) +{ + T8_ASSERT (ts != NULL); + + ts->t8_element_boundary_face (elem, face, boundary, boundary_scheme); +} + +void +t8_element_first_descendant_face (const t8_eclass_scheme_c *ts, const t8_element_t *elem, int face, + t8_element_t *first_desc, int level) +{ + T8_ASSERT (ts != NULL); + + ts->t8_element_first_descendant_face (elem, face, first_desc, level); +} + +void +t8_element_last_descendant_face (const t8_eclass_scheme_c *ts, const t8_element_t *elem, int face, + t8_element_t *last_desc, int level) +{ + T8_ASSERT (ts != NULL); + + ts->t8_element_last_descendant_face (elem, face, last_desc, level); +} + +void +t8_element_set_linear_id (const t8_eclass_scheme_c *ts, t8_element_t *elem, int level, t8_linearidx_t id) +{ + T8_ASSERT (ts != NULL); + + ts->t8_element_set_linear_id (elem, level, id); +} + +int +t8_element_is_root_boundary (const t8_eclass_scheme_c *ts, const t8_element_t *elem, int face) +{ + T8_ASSERT (ts != NULL); + + return ts->t8_element_is_root_boundary (elem, face); +} + +int +t8_element_face_neighbor_inside (const t8_eclass_scheme_c *ts, const t8_element_t *elem, t8_element_t *neigh, int face, + int *neigh_face) +{ + T8_ASSERT (ts != NULL); + + return ts->t8_element_face_neighbor_inside (elem, neigh, face, neigh_face); +} + +t8_element_shape_t +t8_element_shape (const t8_eclass_scheme_c *ts, const t8_element_t *elem) +{ + T8_ASSERT (ts != NULL); + + return ts->t8_element_shape (elem); +} + +t8_linearidx_t +t8_element_get_linear_id (const t8_eclass_scheme_c *ts, const t8_element_t *elem, int level) +{ + T8_ASSERT (ts != NULL); + + return ts->t8_element_get_linear_id (elem, level); +} + +void +t8_element_first_descendant (const t8_eclass_scheme_c *ts, const t8_element_t *elem, t8_element_t *desc, int level) +{ + T8_ASSERT (ts != NULL); + + ts->t8_element_first_descendant (elem, desc, level); +} + +void +t8_element_last_descendant (const t8_eclass_scheme_c *ts, const t8_element_t *elem, t8_element_t *desc, int level) +{ + T8_ASSERT (ts != NULL); + + ts->t8_element_last_descendant (elem, desc, level); +} + +void +t8_element_successor (const t8_eclass_scheme_c *ts, const t8_element_t *elem1, t8_element_t *elem2) +{ + T8_ASSERT (ts != NULL); + + ts->t8_element_successor (elem1, elem2); +} + +void +t8_element_vertex_reference_coords (const t8_eclass_scheme_c *ts, const t8_element_t *t, const int vertex, + double coords[]) +{ + T8_ASSERT (ts != NULL); + + ts->t8_element_vertex_reference_coords (t, vertex, coords); +} + +t8_gloidx_t +t8_element_count_leaves (const t8_eclass_scheme_c *ts, const t8_element_t *t, int level) +{ + T8_ASSERT (ts != NULL); + + return ts->t8_element_count_leaves (t, level); +} + +t8_gloidx_t +t8_element_count_leaves_from_root (const t8_eclass_scheme_c *ts, int level) +{ + T8_ASSERT (ts != NULL); + + return ts->t8_element_count_leaves_from_root (level); +} + +#ifdef T8_ENABLE_DEBUG +int +t8_element_is_valid (const t8_eclass_scheme_c *ts, const t8_element_t *elem) +{ + T8_ASSERT (ts != NULL); + + return ts->t8_element_is_valid (elem); +} + +void +t8_element_debug_print (const t8_eclass_scheme_c *ts, const t8_element_t *elem) +{ + T8_ASSERT (ts != NULL); + + return ts->t8_element_debug_print (elem); +} + +void +t8_element_to_string (const t8_eclass_scheme_c *ts, const t8_element_t *elem, char *debug_string, const int string_size) +{ + T8_ASSERT (ts != NULL); + T8_ASSERT (debug_string != NULL); + + ts->t8_element_to_string (elem, debug_string, string_size); +} +#endif + +void +t8_element_new (const t8_eclass_scheme_c *ts, int length, t8_element_t **elems) +{ + T8_ASSERT (ts != NULL); + + ts->t8_element_new (length, elems); +} + +void +t8_element_destroy (const t8_eclass_scheme_c *ts, int length, t8_element_t **elems) +{ + T8_ASSERT (ts != NULL); + + ts->t8_element_destroy (length, elems); +} + +void +t8_element_root (const t8_eclass_scheme_c *ts, t8_element_t *elem) +{ + T8_ASSERT (ts != NULL); + + ts->t8_element_root (elem); +} + +void +t8_element_MPI_Pack (const t8_eclass_scheme_c *ts, t8_element_t **const elements, const unsigned int count, + void *send_buffer, const int buffer_size, int *position, sc_MPI_Comm comm) +{ + T8_ASSERT (ts != NULL); + + return ts->t8_element_MPI_Pack (elements, count, send_buffer, buffer_size, position, comm); +} + +void +t8_element_MPI_Pack_size (const t8_eclass_scheme_c *ts, const unsigned int count, sc_MPI_Comm comm, int *pack_size) +{ + T8_ASSERT (ts != NULL); + return ts->t8_element_MPI_Pack_size (count, comm, pack_size); +} + +void +t8_element_MPI_Unpack (const t8_eclass_scheme_c *ts, void *recvbuf, const int buffer_size, int *position, + t8_element_t **elements, const unsigned int count, sc_MPI_Comm comm) +{ + T8_ASSERT (ts != NULL); + return ts->t8_element_MPI_Unpack (recvbuf, buffer_size, position, elements, count, comm); +} diff --git a/src/t8_forest/t8_forest_search/t8_forest_search_c_interface.h b/src/t8_forest/t8_forest_search/t8_forest_search_c_interface.h new file mode 100644 index 0000000000..36eca9d20a --- /dev/null +++ b/src/t8_forest/t8_forest_search/t8_forest_search_c_interface.h @@ -0,0 +1,82 @@ +/* + 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) 2024 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. +*/ + +/** \file We declare a modern C++ interface for the search functionality. */ + +#ifndef T8_FOREST_SEARCH_C_INTERFACE_H +#define T8_FOREST_SEARCH_C_INTERFACE_H + +#include +#include + +/* + * Discussion about C++ callback handling https://stackoverflow.com/questions/2298242/callback-functions-in-c + * We decided for option 4, using std::function together with templates. +*/ + +typedef int (*t8_search_element_callback_c_wrapper) (t8_forest_t forest, const t8_locidx_t ltreeid, + const t8_element_t *element, const int is_leaf, + const t8_element_array_t *leaf_elements, + const t8_locidx_t tree_leaf_index, void *user_data) + + typedef void (*t8_search_queries_callback_c_wrapper) (t8_forest_t forest, const t8_locidx_t ltreeid, + const t8_element_t *element, const int is_leaf, + const t8_element_array_t *leaf_elements, + const t8_locidx_t tree_leaf_index, sc_array_t *queries, + sc_array_t *active_query_indices, int *query_matches, + void *user_data); + +typedef struct t8_forest_search_c_wrapper *t8_forest_search; + +void +t8_forest_c_init_search (t8_forest_search_c_wrapper *search, t8_search_element_callback_c element_callback, + const t8_forest_t forest); +void +t8_forest_c_search_update_forest (t8_forest_search_c_wrapper search, const t8_forest_t forest); +void +t8_forest_c_search_update_user_data (t8_forest_search_c_wrapper search, const void *udata); +void +t8_forest_c_search_destroy (t8_forest_search_c_wrapper *search); +void +t8_forest_c_search_do_search (t8_forest_search_c_wrapper search); + +typedef struct t8_forest_search_c_wrapper *t8_forest_search; + +void +t8_forest_c_init_search_with_queries (t8_forest_search_with_queries_c_wrapper *search_with_queries, + t8_search_element_callback_c_wrapper element_callback, + t8_search_queries_callback_c_wrapper queries_callback, const t8_forest_t forest); +void +t8_forest_c_search_with_queries_update_forest (t8_forest_search_with_queries_c_wrapper search_with_queries, + const t8_forest_t forest); +void +t8_forest_c_search_with_queries_update_user_data (t8_forest_search_with_queries_c_wrapper search_with_queries, + const void *udata); +void +t8_forest_c_search_with_queries_update_queries (t8_forest_search_with_queries_c_wrapper search_with_queries, + const void *queries); +void +t8_forest_c_search_with_queries_destroy (t8_forest_search_with_queries_c_wrapper *search); +void +t8_forest_c_search_with_queries_do_search (t8_forest_search_with_queries_c_wrapper *search); + +#endif // T8_FOREST_SEARCH_C_INTERFACE_H From 118f8bae4f68bd5f34080bf6d92442be53f6407a Mon Sep 17 00:00:00 2001 From: David Knapp Date: Fri, 8 Nov 2024 14:11:45 +0100 Subject: [PATCH 09/22] Add documentation Added the documentation of the search and search with query-class. Also started to implement the constructor, destructor and some convenience-functions --- .../t8_forest_search/t8_forest_search.hxx | 158 +++++++++++++++++- 1 file changed, 150 insertions(+), 8 deletions(-) diff --git a/src/t8_forest/t8_forest_search/t8_forest_search.hxx b/src/t8_forest/t8_forest_search/t8_forest_search.hxx index b82b4ed41d..e53466089f 100644 --- a/src/t8_forest/t8_forest_search/t8_forest_search.hxx +++ b/src/t8_forest/t8_forest_search/t8_forest_search.hxx @@ -34,35 +34,142 @@ * We decided for option 4, using std::function together with templates. */ +/** + * \typedef t8_search_element_callback + * \brief A callback function type used for searching elements in a forest. + * + * This callback function is invoked during the search process in a forest. It allows + * custom operations to be performed on each element encountered during the search. + * + * \tparam Udata The type of user data passed to the callback. Defaults to void. + * + * \param[in] forest The forest in which the search is being performed. + * \param[in] ltreeid The local tree ID of the current element. + * \param[in] element A pointer to the current element being processed. + * \param[in] is_leaf A bool indicating whether the current element is a leaf (non-zero) or not (zero). + * \param[in] leaf_elements A pointer to an array of leaf elements. + * \param[in] tree_leaf_index The index of the current leaf element within the tree. + * \param[in] user_data A reference to user-defined data passed to the callback. + * + * \return An integer result code. The meaning of the result code is defined by the specific implementation of the callback. + */ template using t8_search_element_callback - = std::function; +/** + * \typedef t8_search_queries_callback + * \brief A callback function type used for search queries within a forest. + * + * \tparam Query_T The type of the query. + * \tparam Udata The type of user data, defaults to void. + * + * \param[in] forest The forest in which the search is performed. + * \param[in] ltreeid The local tree ID within the forest. + * \param[in] element The element being queried. + * \param[in] is_leaf A flag indicating if the element is a leaf. + * \param[in] leaf_elements The array of leaf elements. + * \param[in] tree_leaf_index The index of the leaf within the tree. + * \param[in] queries A vector of queries to be processed. + * \param[in, out] active_query_indices A vector of indices of active queries. + * \param[in, out] query_matches A vector of query matches. Each entry corresponds to a query in the queries vector. + * \param[in] user_data User-defined data passed to the callback. + */ template using t8_search_queries_callback = std::function &queries, - std::vector &active_query_indices, std::vector &query_matches, Udata &user_data)>; + std::vector &active_query_indices, std::vector &query_matches, Udata &user_data)>; +/** + * @brief A class to search for elements in a forest. A user-defined callback function is invoked for each element + * to allow for custom search operations. + * + * @tparam Udata + */ template class search { public: - search (t8_search_element_callback element_callback, const t8_forest_t forest = nullptr); + /** + * \brief Constructor of the search class. Sets the element callback, forest, and user data. + * \param[in] element_callback The callback function to be invoked for each element during the search. + * \param[in] forest The forest in which the search is performed. + * \param[in] user_data The user-defined data to be passed to the callback. + */ + search (t8_search_element_callback element_callback, const t8_forest_t forest = nullptr, + const Udata &user_data = nullptr) + : element_callback (element_callback), user_data (user_data) + { + t8_forest_ref (forest); + this->forest = forest; + }; + /** + * \brief Updates the forest reference in the current object. + * + * This function updates the forest reference by dereferencing the current forest + * and assigning the new forest to the object's forest member. + * + * \param forest The new forest to be assigned. + */ void - update_forest (const t8_forest_t forest); + update_forest (const t8_forest_t forest) + { + t8_forest_unref (this->forest); + t8_forest_ref (forest); + this->forest = forest; + } + + /** + * \brief Updates the user data with the provided data. + * + * This function sets the user data to the given value. + * + * \param[in] udata The new user data to be set. + */ void - update_user_data (const Udata &udata); + update_user_data (const Udata &udata) + { + this->user_data = udata; + } - ~search (); + /** + * \brief Destructor for the search class. + * + * This destructor is responsible for unreferencing the forest object + * associated with the search instance. It ensures that the resources + * held by the forest object are only released if no further references exist. + */ + ~search () + { + t8_forest_unref (this->forest); + }; + /** + * @brief Performs the search operation within the forest. + * + * This function executes the search algorithm to locate specific elements + * within the forest structure. It performs a depth-first search on the forest, the criterion + * to search for elements is defined by the element callback function. + */ void do_search (); private: + /** + * \brief Searches the tree for specific elements or conditions. + * + * This function performs a search operation on the tree. + */ void search_tree (); + + /** + * \brief Recursively searches for elements in the forest. + * + * This function performs a recursive search operation, used on each tree in the forest. + */ void search_recursion (); @@ -75,11 +182,46 @@ class search { template class search_with_queries: public search { public: + /** + * \brief Constructor for the search_with_queries class. + * + * This constructor initializes a search_with_queries object with the provided element callback, + * queries callback, and a list of queries. It also optionally takes a forest object. + * + * \tparam Udata The type of user data. + * \tparam Query_T The type of the query. + * \param[in] element_callback A callback function for processing elements. + * \param[in] queries_callback A callback function for processing queries. + * \param[in] queries A vector containing the queries to be processed. + * \param[in] forest An optional forest object. Defaults to nullptr. + */ search_with_queries (t8_search_element_callback element_callback, t8_search_queries_callback queries_callback, std::vector &queries, - const t8_forest_t forest = nullptr); + const t8_forest_t forest = nullptr) + : search (element_callback, forest), queries_callback (queries_callback), queries (queries) + { + t8_forest_ref (forest); + this->forest = forest; + }; + + /** + * \brief Updates the list of queries with the provided queries. + * + * This function replaces the current list of queries with the new list + * provided as the parameter. + * + * \param queries A vector containing the new queries to be set. + */ + void + update_queries (const std::vector &queries) + { + this->queries = queries; + } - ~search_with_queries (); + ~search_with_queries () + { + t8_forest_unref (this->forest); + }; private: t8_search_queries_callback queries_callback; From 6b9a9282821197ab8bb70a644aece205e71e946c Mon Sep 17 00:00:00 2001 From: David Knapp Date: Fri, 8 Nov 2024 16:15:51 +0100 Subject: [PATCH 10/22] started implementation of search-class wip, does not compile at the moment. updated t8_gtest_search to use the new interface c-interface is currently untested, will probably need some changes for the callbacks. --- .../t8_forest_search/t8_forest_search.hxx | 87 +++- .../t8_forest_search_c_interface.cxx | 451 +++--------------- .../t8_forest_search_c_interface.h | 22 +- test/t8_forest/t8_gtest_search.cxx | 74 ++- 4 files changed, 166 insertions(+), 468 deletions(-) diff --git a/src/t8_forest/t8_forest_search/t8_forest_search.hxx b/src/t8_forest/t8_forest_search/t8_forest_search.hxx index e53466089f..8a64cd68e3 100644 --- a/src/t8_forest/t8_forest_search/t8_forest_search.hxx +++ b/src/t8_forest/t8_forest_search/t8_forest_search.hxx @@ -28,6 +28,7 @@ #include #include #include +#include /* * Discussion about C++ callback handling https://stackoverflow.com/questions/2298242/callback-functions-in-c @@ -51,12 +52,12 @@ * \param[in] tree_leaf_index The index of the current leaf element within the tree. * \param[in] user_data A reference to user-defined data passed to the callback. * - * \return An integer result code. The meaning of the result code is defined by the specific implementation of the callback. + * \return True if the search should continue, false otherwise. */ template using t8_search_element_callback - = std::function; + = std::function; /** * \typedef t8_search_queries_callback @@ -78,7 +79,7 @@ using t8_search_element_callback */ template using t8_search_queries_callback = std::function &queries, std::vector &active_query_indices, std::vector &query_matches, Udata &user_data)>; @@ -89,7 +90,7 @@ using t8_search_queries_callback = std::function -class search { +class t8_search { public: /** * \brief Constructor of the search class. Sets the element callback, forest, and user data. @@ -97,8 +98,8 @@ class search { * \param[in] forest The forest in which the search is performed. * \param[in] user_data The user-defined data to be passed to the callback. */ - search (t8_search_element_callback element_callback, const t8_forest_t forest = nullptr, - const Udata &user_data = nullptr) + t8_search (t8_search_element_callback element_callback, const t8_forest_t forest = nullptr, + const Udata &user_data = nullptr) : element_callback (element_callback), user_data (user_data) { t8_forest_ref (forest); @@ -116,7 +117,7 @@ class search { void update_forest (const t8_forest_t forest) { - t8_forest_unref (this->forest); + t8_forest_unref (&(this->forest)); t8_forest_ref (forest); this->forest = forest; } @@ -141,9 +142,9 @@ class search { * associated with the search instance. It ensures that the resources * held by the forest object are only released if no further references exist. */ - ~search () + ~t8_search () { - t8_forest_unref (this->forest); + t8_forest_unref (&(this->forest)); }; /** @@ -163,15 +164,31 @@ class search { * This function performs a search operation on the tree. */ void - search_tree (); + search_tree (const t8_locidx_t ltreeid); - /** + /**{ + +} * \brief Recursively searches for elements in the forest. * * This function performs a recursive search operation, used on each tree in the forest. */ void - search_recursion (); + search_recursion (const t8_locidx_t ltreeid, t8_element_t *element, const t8_eclass_scheme_c *ts, + t8_element_array_t *leaf_elements, const t8_locidx_t tree_lindex_of_first_leaf); + + bool + stop_due_to_queries () + { + return false; + } + + void + check_queries (const t8_locidx_t ltreeid, const t8_element_t *element, const bool is_leaf, + const t8_element_array_t *leaf_elements, const t8_locidx_t tree_leaf_index) + { + return; + } t8_search_element_callback element_callback; @@ -180,7 +197,7 @@ class search { }; template -class search_with_queries: public search { +class t8_search_with_queries: public t8_search { public: /** * \brief Constructor for the search_with_queries class. @@ -195,13 +212,12 @@ class search_with_queries: public search { * \param[in] queries A vector containing the queries to be processed. * \param[in] forest An optional forest object. Defaults to nullptr. */ - search_with_queries (t8_search_element_callback element_callback, - t8_search_queries_callback queries_callback, std::vector &queries, - const t8_forest_t forest = nullptr) + t8_search_with_queries (t8_search_element_callback element_callback, + t8_search_queries_callback queries_callback, std::vector &queries, + const t8_forest_t forest = nullptr) : search (element_callback, forest), queries_callback (queries_callback), queries (queries) { - t8_forest_ref (forest); - this->forest = forest; + std::iota (this->active_queries.begin (), this->active_queries.end (), 0); }; /** @@ -218,15 +234,40 @@ class search_with_queries: public search { this->queries = queries; } - ~search_with_queries () + ~t8_search_with_queries () { t8_forest_unref (this->forest); }; private: - t8_search_queries_callback queries_callback; - const std::vector &queries; -}; + bool + stop_due_to_queries () + { + return active_queries.empty (); + } + + void + check_queries (std::vector new_active_queries, const t8_locidx_t ltreeid, const t8_element_t *element, + const bool is_leaf, const t8_element_array_t *leaf_elements, const t8_locidx_t tree_leaf_index) + { + T8_ASSERT (new_active_queries.empty ()); + if (!active_queries.empty ()) { + std::vector query_matches (active_queries.size ()); + queries_callback (forest, ltreeid, element, is_leaf, leaf_elements, tree_leaf_index, queries, active_queries, + query_matches, user_data); + if (!is_leaf) { + std::for_each (active_queries.begin (), active_queries.end (), [&] (size_t iactive) { + if (query_matches[iactive]) { + new_active_queries.push_back (iactive); + } + }); + } + } + + t8_search_queries_callback queries_callback; + const std::vector &queries; + std::vector active_queries; + }; #if 0 //General shape of search diff --git a/src/t8_forest/t8_forest_search/t8_forest_search_c_interface.cxx b/src/t8_forest/t8_forest_search/t8_forest_search_c_interface.cxx index 88d57e5f65..604c84dd59 100644 --- a/src/t8_forest/t8_forest_search/t8_forest_search_c_interface.cxx +++ b/src/t8_forest/t8_forest_search/t8_forest_search_c_interface.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) 2024 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 @@ -20,447 +20,112 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -/* In this file we implement a C interface for the member functions of the - * t8_eclass_scheme_c class. - * With this interface you can use these member functions from a C file - * without the need of compiling it with C++. - */ +#include +#include -#include -#include -#include +T8_EXTERN_C_BEGIN (); -size_t -t8_element_size (const t8_eclass_scheme_c *ts) +struct t8_forest_search { - T8_ASSERT (ts != NULL); - - return ts->t8_element_size (); -} - -int -t8_element_refines_irregular (const t8_eclass_scheme_c *ts) -{ - T8_ASSERT (ts != NULL); - - return ts->t8_element_refines_irregular (); -} - -int -t8_element_maxlevel (const t8_eclass_scheme_c *ts) -{ - T8_ASSERT (ts != NULL); - - return ts->t8_element_maxlevel (); -} - -int -t8_element_level (const t8_eclass_scheme_c *ts, const t8_element_t *elem) -{ - T8_ASSERT (ts != NULL); - - return ts->t8_element_level (elem); + t8_search *c_search; } void -t8_element_copy (const t8_eclass_scheme_c *ts, const t8_element_t *source, t8_element_t *dest) -{ - T8_ASSERT (ts != NULL); - - ts->t8_element_copy (source, dest); -} - -int -t8_element_compare (const t8_eclass_scheme_c *ts, const t8_element_t *elem1, const t8_element_t *elem2) +t8_forest_c_init_search (t8_forest_search_c_wrapper *search, t8_search_element_callback_c element_callback, + const t8_forest_t forest) { - T8_ASSERT (ts != NULL); - - return ts->t8_element_compare (elem1, elem2); -} - -int -t8_element_equal (const t8_eclass_scheme_c *ts, const t8_element_t *elem1, const t8_element_t *elem2) -{ - T8_ASSERT (ts != NULL); - - return ts->t8_element_equal (elem1, elem2); + T8_ASSERT (search != NULL); + T8_ASSERT (element_callback != NULL); + search->c_search = new t8_search (forest, element_callback); } void -t8_element_parent (const t8_eclass_scheme_c *ts, const t8_element_t *elem, t8_element_t *parent) -{ - T8_ASSERT (ts != NULL); - - ts->t8_element_parent (elem, parent); -} - -int -t8_element_num_siblings (const t8_eclass_scheme_c *ts, const t8_element_t *elem) +t8_forest_c_search_update_forest (t8_forest_search_c_wrapper search, const t8_forest_t forest) { - T8_ASSERT (ts != NULL); - - return ts->t8_element_num_siblings (elem); + T8_ASSERT (search != NULL); + T8_ASSERT (forest != NULL); + search->c_search->update_forest (forest); } void -t8_element_sibling (const t8_eclass_scheme_c *ts, const t8_element_t *elem, int sibid, t8_element_t *sibling) -{ - T8_ASSERT (ts != NULL); - - ts->t8_element_sibling (elem, sibid, sibling); -} - -int -t8_element_num_corners (const t8_eclass_scheme_c *ts, const t8_element_t *elem) -{ - T8_ASSERT (ts != NULL); - - return ts->t8_element_num_corners (elem); -} - -int -t8_element_num_faces (const t8_eclass_scheme_c *ts, const t8_element_t *elem) -{ - T8_ASSERT (ts != NULL); - - return ts->t8_element_num_faces (elem); -} - -int -t8_element_max_num_faces (const t8_eclass_scheme_c *ts, const t8_element_t *elem) -{ - T8_ASSERT (ts != NULL); - - return ts->t8_element_max_num_faces (elem); -} - -int -t8_element_num_children (const t8_eclass_scheme_c *ts, const t8_element_t *elem) -{ - T8_ASSERT (ts != NULL); - - return ts->t8_element_num_children (elem); -} - -int -t8_element_num_face_children (const t8_eclass_scheme_c *ts, const t8_element_t *elem, int face) -{ - T8_ASSERT (ts != NULL); - - return ts->t8_element_num_face_children (elem, face); -} - -int -t8_element_get_face_corner (const t8_eclass_scheme_c *ts, const t8_element_t *elem, int face, int corner) -{ - T8_ASSERT (ts != NULL); - - return ts->t8_element_get_face_corner (elem, face, corner); -} - -int -t8_element_get_corner_face (const t8_eclass_scheme_c *ts, const t8_element_t *elem, int corner, int face) +t8_forest_c_search_update_user_data (t8_forest_search_c_wrapper search, const void *udata) { - T8_ASSERT (ts != NULL); - - return ts->t8_element_get_corner_face (elem, corner, face); + T8_ASSERT (search != NULL); + T8_ASSERT (udata != NULL); + search->c_search->update_user_data (udata); } void -t8_element_child (const t8_eclass_scheme_c *ts, const t8_element_t *elem, int childid, t8_element_t *child) +t8_forest_c_search_do_search (t8_forest_search_c_wrapper search) { - T8_ASSERT (ts != NULL); - - ts->t8_element_child (elem, childid, child); + T8_ASSERT (search != NULL); + search->c_search->do_search (); } void -t8_element_children (const t8_eclass_scheme_c *ts, const t8_element_t *elem, int length, t8_element_t *c[]) +t8_forest_c_search_destroy (t8_forest_search_c_wrapper *search) { - T8_ASSERT (ts != NULL); - - ts->t8_element_children (elem, length, c); + T8_ASSERT (search != NULL); + delete search->c_search; + search->c_search = NULL; } -int -t8_element_child_id (const t8_eclass_scheme_c *ts, const t8_element_t *elem) +struct t8_forest_search_with_queries { - T8_ASSERT (ts != NULL); - - return ts->t8_element_child_id (elem); -} - -int -t8_element_ancestor_id (const t8_eclass_scheme_c *ts, const t8_element_t *elem, int level) -{ - T8_ASSERT (ts != NULL); - - return ts->t8_element_ancestor_id (elem, level); -} - -int -t8_element_is_family (const t8_eclass_scheme_c *ts, t8_element_t *const *fam) -{ - T8_ASSERT (ts != NULL); - - return ts->t8_element_is_family (fam); + t8_search_with_queries *c_search; } void -t8_element_nca (const t8_eclass_scheme_c *ts, const t8_element_t *elem1, const t8_element_t *elem2, t8_element_t *nca) -{ - T8_ASSERT (ts != NULL); - - ts->t8_element_nca (elem1, elem2, nca); -} - -t8_element_shape_t -t8_element_face_shape (const t8_eclass_scheme_c *ts, const t8_element_t *elem, int face) +t8_forest_c_init_search_with_queries (t8_forest_search_with_queries_c_wrapper *search_with_queries, + t8_search_element_callback_c_wrapper element_callback, + t8_search_queries_callback_c_wrapper queries_callback, const t8_forest_t forest) { - T8_ASSERT (ts != NULL); + T8_ASSERT (search_with_queries != NULL); + T8_ASSERT (element_callback != NULL); + T8_ASSERT (queries_callback != NULL); + T8_ASSERT (forest != NULL); - return ts->t8_element_face_shape (elem, face); + search_with_queries->c_search = new t8_search_with_queries (forest, element_callback, queries_callback); } void -t8_element_children_at_face (const t8_eclass_scheme_c *ts, const t8_element_t *elem, int face, t8_element_t *children[], - int num_children, int *child_indices) -{ - T8_ASSERT (ts != NULL); - - ts->t8_element_children_at_face (elem, face, children, num_children, child_indices); -} - -int -t8_element_face_child_face (const t8_eclass_scheme_c *ts, const t8_element_t *elem, int face, int face_child) +t8_forest_c_search_with_queries_update_forest (t8_forest_search_with_queries_c_wrapper search_with_queries, + const t8_forest_t forest) { - T8_ASSERT (ts != NULL); - - return ts->t8_element_face_child_face (elem, face, face_child); -} - -int -t8_element_face_parent_face (const t8_eclass_scheme_c *ts, const t8_element_t *elem, int face) -{ - T8_ASSERT (ts != NULL); - - return ts->t8_element_face_parent_face (elem, face); -} - -int -t8_element_tree_face (const t8_eclass_scheme_c *ts, const t8_element_t *elem, int face) -{ - T8_ASSERT (ts != NULL); - - return ts->t8_element_tree_face (elem, face); + T8_ASSERT (search_with_queries != NULL); + T8_ASSERT (forest != NULL); + search_with_queries->c_search->update_forest (forest); } void -t8_element_transform_face (const t8_eclass_scheme_c *ts, const t8_element_t *elem1, t8_element_t *elem2, - int orientation, int sign, int is_smaller_face) +t8_forest_c_search_with_queries_update_user_data (t8_forest_search_with_queries_c_wrapper search_with_queries, + const void *udata) { - T8_ASSERT (ts != NULL); - - ts->t8_element_transform_face (elem1, elem2, orientation, sign, is_smaller_face); -} - -int -t8_element_extrude_face (const t8_eclass_scheme_c *ts, const t8_element_t *face, const t8_eclass_scheme_c *face_scheme, - t8_element_t *elem, int root_face) -{ - T8_ASSERT (ts != NULL); - - return ts->t8_element_extrude_face (face, face_scheme, elem, root_face); + T8_ASSERT (search_with_queries != NULL); + T8_ASSERT (udata != NULL); + search_with_queries->c_search->update_user_data (udata); } void -t8_element_boundary_face (const t8_eclass_scheme_c *ts, const t8_element_t *elem, int face, t8_element_t *boundary, - const t8_eclass_scheme_c *boundary_scheme) +t8_forest_c_search_with_queries_update_queries (t8_forest_search_with_queries_c_wrapper search_with_queries, + const void *queries) { - T8_ASSERT (ts != NULL); - - ts->t8_element_boundary_face (elem, face, boundary, boundary_scheme); -} - -void -t8_element_first_descendant_face (const t8_eclass_scheme_c *ts, const t8_element_t *elem, int face, - t8_element_t *first_desc, int level) -{ - T8_ASSERT (ts != NULL); - - ts->t8_element_first_descendant_face (elem, face, first_desc, level); -} - -void -t8_element_last_descendant_face (const t8_eclass_scheme_c *ts, const t8_element_t *elem, int face, - t8_element_t *last_desc, int level) -{ - T8_ASSERT (ts != NULL); - - ts->t8_element_last_descendant_face (elem, face, last_desc, level); -} - -void -t8_element_set_linear_id (const t8_eclass_scheme_c *ts, t8_element_t *elem, int level, t8_linearidx_t id) -{ - T8_ASSERT (ts != NULL); - - ts->t8_element_set_linear_id (elem, level, id); -} - -int -t8_element_is_root_boundary (const t8_eclass_scheme_c *ts, const t8_element_t *elem, int face) -{ - T8_ASSERT (ts != NULL); - - return ts->t8_element_is_root_boundary (elem, face); -} - -int -t8_element_face_neighbor_inside (const t8_eclass_scheme_c *ts, const t8_element_t *elem, t8_element_t *neigh, int face, - int *neigh_face) -{ - T8_ASSERT (ts != NULL); - - return ts->t8_element_face_neighbor_inside (elem, neigh, face, neigh_face); -} - -t8_element_shape_t -t8_element_shape (const t8_eclass_scheme_c *ts, const t8_element_t *elem) -{ - T8_ASSERT (ts != NULL); - - return ts->t8_element_shape (elem); -} - -t8_linearidx_t -t8_element_get_linear_id (const t8_eclass_scheme_c *ts, const t8_element_t *elem, int level) -{ - T8_ASSERT (ts != NULL); - - return ts->t8_element_get_linear_id (elem, level); -} - -void -t8_element_first_descendant (const t8_eclass_scheme_c *ts, const t8_element_t *elem, t8_element_t *desc, int level) -{ - T8_ASSERT (ts != NULL); - - ts->t8_element_first_descendant (elem, desc, level); -} - -void -t8_element_last_descendant (const t8_eclass_scheme_c *ts, const t8_element_t *elem, t8_element_t *desc, int level) -{ - T8_ASSERT (ts != NULL); - - ts->t8_element_last_descendant (elem, desc, level); -} - -void -t8_element_successor (const t8_eclass_scheme_c *ts, const t8_element_t *elem1, t8_element_t *elem2) -{ - T8_ASSERT (ts != NULL); - - ts->t8_element_successor (elem1, elem2); -} - -void -t8_element_vertex_reference_coords (const t8_eclass_scheme_c *ts, const t8_element_t *t, const int vertex, - double coords[]) -{ - T8_ASSERT (ts != NULL); - - ts->t8_element_vertex_reference_coords (t, vertex, coords); -} - -t8_gloidx_t -t8_element_count_leaves (const t8_eclass_scheme_c *ts, const t8_element_t *t, int level) -{ - T8_ASSERT (ts != NULL); - - return ts->t8_element_count_leaves (t, level); -} - -t8_gloidx_t -t8_element_count_leaves_from_root (const t8_eclass_scheme_c *ts, int level) -{ - T8_ASSERT (ts != NULL); - - return ts->t8_element_count_leaves_from_root (level); -} - -#ifdef T8_ENABLE_DEBUG -int -t8_element_is_valid (const t8_eclass_scheme_c *ts, const t8_element_t *elem) -{ - T8_ASSERT (ts != NULL); - - return ts->t8_element_is_valid (elem); -} - -void -t8_element_debug_print (const t8_eclass_scheme_c *ts, const t8_element_t *elem) -{ - T8_ASSERT (ts != NULL); - - return ts->t8_element_debug_print (elem); -} - -void -t8_element_to_string (const t8_eclass_scheme_c *ts, const t8_element_t *elem, char *debug_string, const int string_size) -{ - T8_ASSERT (ts != NULL); - T8_ASSERT (debug_string != NULL); - - ts->t8_element_to_string (elem, debug_string, string_size); -} -#endif - -void -t8_element_new (const t8_eclass_scheme_c *ts, int length, t8_element_t **elems) -{ - T8_ASSERT (ts != NULL); - - ts->t8_element_new (length, elems); -} - -void -t8_element_destroy (const t8_eclass_scheme_c *ts, int length, t8_element_t **elems) -{ - T8_ASSERT (ts != NULL); - - ts->t8_element_destroy (length, elems); -} - -void -t8_element_root (const t8_eclass_scheme_c *ts, t8_element_t *elem) -{ - T8_ASSERT (ts != NULL); - - ts->t8_element_root (elem); -} - -void -t8_element_MPI_Pack (const t8_eclass_scheme_c *ts, t8_element_t **const elements, const unsigned int count, - void *send_buffer, const int buffer_size, int *position, sc_MPI_Comm comm) -{ - T8_ASSERT (ts != NULL); - - return ts->t8_element_MPI_Pack (elements, count, send_buffer, buffer_size, position, comm); + T8_ASSERT (search_with_queries != NULL); + T8_ASSERT (queries != NULL); + search_with_queries->c_search->update_queries (queries); } void -t8_element_MPI_Pack_size (const t8_eclass_scheme_c *ts, const unsigned int count, sc_MPI_Comm comm, int *pack_size) +t8_forest_c_search_with_queries_do_search (t8_forest_search_with_queries_c_wrapper *search) { - T8_ASSERT (ts != NULL); - return ts->t8_element_MPI_Pack_size (count, comm, pack_size); + T8_ASSERT (search != NULL); + search->c_search->do_search (); } void -t8_element_MPI_Unpack (const t8_eclass_scheme_c *ts, void *recvbuf, const int buffer_size, int *position, - t8_element_t **elements, const unsigned int count, sc_MPI_Comm comm) +t8_forest_c_search_with_queries_destroy (t8_forest_search_with_queries_c_wrapper *search) { - T8_ASSERT (ts != NULL); - return ts->t8_element_MPI_Unpack (recvbuf, buffer_size, position, elements, count, comm); + T8_ASSERT (search != NULL); + delete search->c_search; + search->c_search = NULL; } diff --git a/src/t8_forest/t8_forest_search/t8_forest_search_c_interface.h b/src/t8_forest/t8_forest_search/t8_forest_search_c_interface.h index 36eca9d20a..bda73ba1a3 100644 --- a/src/t8_forest/t8_forest_search/t8_forest_search_c_interface.h +++ b/src/t8_forest/t8_forest_search/t8_forest_search_c_interface.h @@ -36,30 +36,30 @@ typedef int (*t8_search_element_callback_c_wrapper) (t8_forest_t forest, const t8_locidx_t ltreeid, const t8_element_t *element, const int is_leaf, const t8_element_array_t *leaf_elements, - const t8_locidx_t tree_leaf_index, void *user_data) + const t8_locidx_t tree_leaf_index, void *user_data); - typedef void (*t8_search_queries_callback_c_wrapper) (t8_forest_t forest, const t8_locidx_t ltreeid, - const t8_element_t *element, const int is_leaf, - const t8_element_array_t *leaf_elements, - const t8_locidx_t tree_leaf_index, sc_array_t *queries, - sc_array_t *active_query_indices, int *query_matches, - void *user_data); +typedef void (*t8_search_queries_callback_c_wrapper) (t8_forest_t forest, const t8_locidx_t ltreeid, + const t8_element_t *element, const int is_leaf, + const t8_element_array_t *leaf_elements, + const t8_locidx_t tree_leaf_index, sc_array_t *queries, + sc_array_t *active_query_indices, int *query_matches, + void *user_data); typedef struct t8_forest_search_c_wrapper *t8_forest_search; void -t8_forest_c_init_search (t8_forest_search_c_wrapper *search, t8_search_element_callback_c element_callback, +t8_forest_c_init_search (t8_forest_search_c_wrapper *search, t8_search_element_callback_c_wrapper element_callback, const t8_forest_t forest); void t8_forest_c_search_update_forest (t8_forest_search_c_wrapper search, const t8_forest_t forest); void t8_forest_c_search_update_user_data (t8_forest_search_c_wrapper search, const void *udata); void -t8_forest_c_search_destroy (t8_forest_search_c_wrapper *search); -void t8_forest_c_search_do_search (t8_forest_search_c_wrapper search); +void +t8_forest_c_search_destroy (t8_forest_search_c_wrapper *search); -typedef struct t8_forest_search_c_wrapper *t8_forest_search; +typedef struct t8_forest_search_with_queries_c_wrapper *t8_forest_search_with_queries; void t8_forest_c_init_search_with_queries (t8_forest_search_with_queries_c_wrapper *search_with_queries, diff --git a/test/t8_forest/t8_gtest_search.cxx b/test/t8_forest/t8_gtest_search.cxx index 9cb5deabf6..27970eb419 100644 --- a/test/t8_forest/t8_gtest_search.cxx +++ b/test/t8_forest/t8_gtest_search.cxx @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -60,11 +61,11 @@ class forest_search: public testing::TestWithParam> { * with one int for each local leaf. * If this function is called for a leaf, it sets the corresponding entry to 1. */ -static int -t8_test_search_all_fn (t8_forest_t forest, const t8_locidx_t ltreeid, const t8_element_t *element, const int is_leaf, - const t8_element_array_t *leaf_elements, const t8_locidx_t tree_leaf_index) +static bool +t8_test_search_all_fn (t8_forest_t forest, const t8_locidx_t ltreeid, const t8_element_t *element, const bool is_leaf, + const t8_element_array_t *leaf_elements, const t8_locidx_t tree_leaf_index, + std::vector &user_data) { - sc_array_t *matched_leaves = (sc_array_t *) t8_forest_get_user_data (forest); if (is_leaf) { t8_locidx_t test_ltreeid; const t8_eclass_t tree_class = t8_forest_get_tree_class (forest, ltreeid); @@ -72,80 +73,71 @@ t8_test_search_all_fn (t8_forest_t forest, const t8_locidx_t ltreeid, const t8_e const t8_locidx_t tree_offset = t8_forest_get_tree_element_offset (forest, ltreeid); /* Set the corresponding entry to 1 */ - *(int *) t8_sc_array_index_locidx (matched_leaves, tree_offset + tree_leaf_index) = 1; + user_data[tree_offset + tree_leaf_index] = true; /* Test whether tree_leaf_index is actually the index of the element */ const t8_element_t *test_element = t8_forest_get_element (forest, tree_offset + tree_leaf_index, &test_ltreeid); EXPECT_ELEM_EQ (scheme, tree_class, element, test_element); EXPECT_EQ (ltreeid, test_ltreeid) << "Tree mismatch in search."; } - return 1; + return true; } static void -t8_test_search_query_all_fn (t8_forest_t forest, t8_locidx_t ltreeid, const t8_element_t *element, const int is_leaf, - const t8_element_array_t *leaf_elements, const t8_locidx_t tree_leaf_index, - sc_array_t *queries, sc_array_t *query_indices, int *query_matches, - const size_t num_active_queries) +t8_test_search_query_all_fn (const t8_forest_t forest, const t8_locidx_t ltreeid, const t8_element_t *element, + const bool is_leaf, const t8_element_array_t *leaf_elements, + const t8_locidx_t tree_leaf_index, std::vector &queries, + std::vector &active_query_indices, std::vector &query_matches, + std::vector &user_data) { - EXPECT_TRUE (queries != NULL) << "query callback must be called with queries argument. "; - EXPECT_EQ (num_active_queries, (long unsigned int) 1) << "Wrong number of active queries passed to query callback."; - for (size_t iquery = 0; iquery < num_active_queries; iquery++) { - void *query = sc_array_index_int (queries, iquery); - /* The query callback is always called with a query */ - EXPECT_TRUE (query != NULL) << "query " << iquery << " is NULL."; + EXPECT_FALSE (queries.empty ()) << "query callback must be called with queries argument. "; + EXPECT_EQ (active_query_indices.size (), (long unsigned int) 1) + << "Wrong number of active queries passed to query callback."; + for (int iquery : active_query_indices) { /* The query is an int with value 42 (see below) */ - EXPECT_EQ (*(int *) query, 42) << "Wrong query argument passed to query callback."; + EXPECT_EQ (iquery, 42) << "Wrong query argument passed to query callback."; if (is_leaf) { /* Test whether tree_leaf_index is actually the index of the element */ - t8_locidx_t test_ltreeid; + const t8_locidx_t test_ltreeid; const t8_eclass_t tree_class = t8_forest_get_tree_class (forest, ltreeid); - const t8_scheme *scheme = t8_forest_get_scheme (forest); + const t8_eclass_scheme_c *ts = t8_forest_get_eclass_scheme (forest, tree_class); - t8_locidx_t tree_offset = t8_forest_get_tree_element_offset (forest, ltreeid); - t8_element_t *test_element = t8_forest_get_element (forest, tree_offset + tree_leaf_index, &test_ltreeid); - EXPECT_ELEM_EQ (scheme, tree_class, element, test_element); + const t8_locidx_t tree_offset = t8_forest_get_tree_element_offset (forest, ltreeid); + const t8_element_t *test_element = t8_forest_get_element (forest, tree_offset + tree_leaf_index, &test_ltreeid); + EXPECT_ELEM_EQ (ts, element, test_element); EXPECT_EQ (ltreeid, test_ltreeid) << "Tree mismatch in search."; } - query_matches[iquery] = 1; + query_matches[iquery] = true; } } TEST_P (forest_search, test_search_one_query_matches_all) { const int query = 42; - sc_array_t queries; - sc_array_t matched_leaves; /* set up a single query containing our query */ - sc_array_init_size (&queries, sizeof (int), 1); - *(int *) sc_array_index (&queries, 0) = query; + std::vector queries = { 1 }; t8_locidx_t num_elements = t8_forest_get_local_num_elements (forest); /* set up an array in which we flag whether an element was matched in the * search */ - sc_array_init_size (&matched_leaves, sizeof (int), num_elements); - /* write 0 in every entry */ - for (t8_locidx_t ielement = 0; ielement < num_elements; ++ielement) { - *(int *) t8_sc_array_index_locidx (&matched_leaves, ielement) = 0; - } + std::vector matched_leaves (num_elements, false); - /* Set the array as user data so that we can access it in the search callback */ - t8_forest_set_user_data (forest, &matched_leaves); /* Call search. This search matches all elements. After this call we expect * all entries in the matched_leaves array to be set to 1. */ - t8_forest_search (forest, t8_test_search_all_fn, t8_test_search_query_all_fn, &queries); + t8_search::search_with_queries> search (t8_test_search_all_fn, t8_test_search_query_all_fn); + + search.update_queries (queries); + search.update_user_data (matched_leaves); + search.update_forest (forest); + search.do_search (); /* Check whether matched_leaves entries are all 1 */ - for (t8_locidx_t ielement = 0; ielement < num_elements; ++ielement) { - ASSERT_TRUE (*(int *) t8_sc_array_index_locidx (&matched_leaves, ielement)) - << "Search did not match all leaves. First mismatch at leaf " << ielement; - } + std::for_each (matched_leaves.begin (), matched_leaves.end (), + [] (bool b) { ASSERT_TRUE (b) << "Search did not match all leaves. First mismatch at leaf " << b; }); t8_forest_unref (&forest); - sc_array_reset (&matched_leaves); - sc_array_reset (&queries); } INSTANTIATE_TEST_SUITE_P (t8_gtest_search, forest_search, testing::Combine (AllEclasses, testing::Range (0, 6))); From 3e4afc46d3c9255380a69aa75b9f30ef7ab8c23c Mon Sep 17 00:00:00 2001 From: David Knapp Date: Mon, 11 Nov 2024 08:58:24 +0100 Subject: [PATCH 11/22] Add file for search-implementation --- .../t8_forest_search/t8_forest_search.cxx | 144 ++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 src/t8_forest/t8_forest_search/t8_forest_search.cxx diff --git a/src/t8_forest/t8_forest_search/t8_forest_search.cxx b/src/t8_forest/t8_forest_search/t8_forest_search.cxx new file mode 100644 index 0000000000..2680952bc9 --- /dev/null +++ b/src/t8_forest/t8_forest_search/t8_forest_search.cxx @@ -0,0 +1,144 @@ +/* +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) 2024 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 + +void +t8_search::search_recursion (const t8_locidx_t ltreeid, t8_element_t *element, const t8_eclass_scheme_c *ts, + t8_element_array_t *leaf_elements, const t8_locidx_t tree_lindex_of_first_leaf) +{ + /* Assertions to check for necessary requirements */ + /* The forest must be committed */ + T8_ASSERT (t8_forest_is_committed (forest)); + /* The tree must be local */ + T8_ASSERT (0 <= ltreeid && ltreeid < t8_forest_get_num_local_trees (forest)); + /* If we have queries, we also must have a query function */ + T8_ASSERT ((queries == NULL) == (query_fn == NULL)); + + const size_t elem_count = t8_element_array_get_count (leaf_elements); + if (elem_count == 0) { + /* There are no leaves left, so we have nothing to do */ + return; + } + + if (this->stop_due_to_queries ()) { + return; + } + + int is_leaf = 0; + if (elem_count == 1) { + /* There is only one leaf left, we check whether it is the same as element and if so call the callback function */ + const t8_element_t *leaf = t8_element_array_index_locidx (leaf_elements, 0); + + SC_CHECK_ABORT (ts->t8_element_level (element) <= ts->t8_element_level (leaf), + "Search: element level greater than leaf level\n"); + if (ts->t8_element_level (element) == ts->t8_element_level (leaf)) { + T8_ASSERT (t8_forest_element_is_leaf (forest, leaf, ltreeid)); + T8_ASSERT (ts->t8_element_equal (element, leaf)); + /* The element is the leaf */ + is_leaf = 1; + } + } + /* Call the callback function for the element */ + const bool ret + = this->element_callback (forest, ltreeid, element, is_leaf, leaf_elements, tree_lindex_of_first_leaf, user_data); + + if (!ret) { + /* The function returned false. We abort the recursion */ + return; + } + std::vector new_active_queries; + this->check_queries (new_active_queries, ltreeid, element, is_leaf, leaf_elements, tree_lindex_of_first_leaf); + + if (is_leaf) { + return; + } + + /* Enter the recursion (the element is definitely not a leaf at this point) */ + /* We compute all children of E, compute their leaf arrays and call search_recursion */ + /* allocate the memory to store the children */ + const int num_children = ts->t8_element_num_children (element); + t8_element_t **children = T8_ALLOC (t8_element_t *, num_children); + ts->t8_element_new (num_children, children); + /* Memory for the indices that split the leaf_elements array */ + size_t *split_offsets = T8_ALLOC (size_t, num_children + 1); + /* Compute the children */ + ts->t8_element_children (element, num_children, children); + /* Split the leaves array in portions belonging to the children of element */ + t8_forest_split_array (element, leaf_elements, split_offsets); + for (int ichild = 0; ichild < num_children; ichild++) { + /* Check if there are any leaf elements for this child */ + const size_t indexa = split_offsets[ichild]; /* first leaf of this child */ + const size_t indexb = split_offsets[ichild + 1]; /* first leaf of next child */ + if (indexa < indexb) { + t8_element_array_t child_leaves; + /* There exist leaves of this child in leaf_elements, + * we construct an array of these leaves */ + t8_element_array_init_view (&child_leaves, leaf_elements, indexa, indexb - indexa); + /* Enter the recursion */ + t8_forest_search_recursion (forest, ltreeid, children[ichild], ts, &child_leaves, + indexa + tree_lindex_of_first_leaf, search_fn, query_fn, queries, new_active_queries); + } + } + + /* clean-up */ + ts->t8_element_destroy (num_children, children); + T8_FREE (children); + T8_FREE (split_offsets); +} + +void +t8_search::search_tree (const t8_locidx_t ltreeid) +{ + const t8_eclass_t eclass = t8_forest_get_eclass (forest, ltreeid); + const t8_eclass_scheme_c *ts = t8_forest_get_eclass_scheme (forest, eclass); + t8_element_array_t *leaf_elements = t8_forest_tree_get_leaves (forest, ltreeid); + + /* assert for empty tree */ + T8_ASSERT (t8_element_array_get_count (leaf_elements) >= 0); + /* Get the first and last leaf of this tree */ + const t8_element_t *first_el = t8_element_array_index_locidx (leaf_elements, 0); + const t8_element_t *last_el + = t8_element_array_index_locidx (leaf_elements, t8_element_array_get_count (leaf_elements) - 1); + /* Compute their nearest common ancestor */ + t8_element_t *nca; + ts->t8_element_new (1, &nca); + ts->t8_element_nca (first_el, last_el, nca); + + /* Start the top-down search */ + this->search_recursion (ltreeid, nca, ts, leaf_elements, 0, search_fn, query_fn, queries, active_queries); + + ts->t8_element_destroy (1, &nca); +} + +void +t8_search::do_search () +{ + const t8_locidx_t num_local_trees = t8_forest_get_num_local_trees (forest); + for (t8_locidx_t itree = 0; itree < num_local_trees; itree++) { + this->search_tree (itree); + } +} From fc2f9b14842cee5ca92fe98ff6ba4c9566b1e623 Mon Sep 17 00:00:00 2001 From: David Knapp Date: Mon, 11 Nov 2024 09:21:49 +0100 Subject: [PATCH 12/22] bug fixes --- .../t8_forest_search/t8_forest_search.cxx | 2 +- .../t8_forest_search/t8_forest_search.hxx | 27 ++++++++++--------- .../t8_forest_search_c_interface.cxx | 3 --- .../t8_forest_search_c_interface.h | 4 ++- test/t8_forest/t8_gtest_search.cxx | 7 ++--- 5 files changed, 22 insertions(+), 21 deletions(-) diff --git a/src/t8_forest/t8_forest_search/t8_forest_search.cxx b/src/t8_forest/t8_forest_search/t8_forest_search.cxx index 2680952bc9..54bf356114 100644 --- a/src/t8_forest/t8_forest_search/t8_forest_search.cxx +++ b/src/t8_forest/t8_forest_search/t8_forest_search.cxx @@ -71,7 +71,7 @@ t8_search::search_recursion (const t8_locidx_t ltreeid, t8_element_t *element, c return; } std::vector new_active_queries; - this->check_queries (new_active_queries, ltreeid, element, is_leaf, leaf_elements, tree_lindex_of_first_leaf); + this->check_queries (forest, new_active_queries, ltreeid, element, is_leaf, leaf_elements, tree_lindex_of_first_leaf); if (is_leaf) { return; diff --git a/src/t8_forest/t8_forest_search/t8_forest_search.hxx b/src/t8_forest/t8_forest_search/t8_forest_search.hxx index 8a64cd68e3..6744d5acff 100644 --- a/src/t8_forest/t8_forest_search/t8_forest_search.hxx +++ b/src/t8_forest/t8_forest_search/t8_forest_search.hxx @@ -215,7 +215,7 @@ class t8_search_with_queries: public t8_search { t8_search_with_queries (t8_search_element_callback element_callback, t8_search_queries_callback queries_callback, std::vector &queries, const t8_forest_t forest = nullptr) - : search (element_callback, forest), queries_callback (queries_callback), queries (queries) + : t8_search (element_callback, forest), queries_callback (queries_callback), queries (queries) { std::iota (this->active_queries.begin (), this->active_queries.end (), 0); }; @@ -243,32 +243,33 @@ class t8_search_with_queries: public t8_search { bool stop_due_to_queries () { - return active_queries.empty (); + return this->active_queries.empty (); } void - check_queries (std::vector new_active_queries, const t8_locidx_t ltreeid, const t8_element_t *element, - const bool is_leaf, const t8_element_array_t *leaf_elements, const t8_locidx_t tree_leaf_index) + check_queries (t8_forest_t forest, std::vector new_active_queries, const t8_locidx_t ltreeid, + const t8_element_t *element, const bool is_leaf, const t8_element_array_t *leaf_elements, + const t8_locidx_t tree_leaf_index) { T8_ASSERT (new_active_queries.empty ()); - if (!active_queries.empty ()) { + if (!this->active_queries.empty ()) { std::vector query_matches (active_queries.size ()); - queries_callback (forest, ltreeid, element, is_leaf, leaf_elements, tree_leaf_index, queries, active_queries, - query_matches, user_data); + queries_callback (forest, ltreeid, element, is_leaf, leaf_elements, tree_leaf_index, this->queries, + this->active_queries, query_matches, this->user_data); if (!is_leaf) { - std::for_each (active_queries.begin (), active_queries.end (), [&] (size_t iactive) { + std::for_each (this->active_queries.begin (), this->active_queries.end (), [&] (size_t iactive) { if (query_matches[iactive]) { new_active_queries.push_back (iactive); } }); } } + } - t8_search_queries_callback queries_callback; - const std::vector &queries; - std::vector active_queries; - }; - + t8_search_queries_callback queries_callback; + const std::vector &queries; + std::vector active_queries; +}; #if 0 //General shape of search diff --git a/src/t8_forest/t8_forest_search/t8_forest_search_c_interface.cxx b/src/t8_forest/t8_forest_search/t8_forest_search_c_interface.cxx index 604c84dd59..e1646077c5 100644 --- a/src/t8_forest/t8_forest_search/t8_forest_search_c_interface.cxx +++ b/src/t8_forest/t8_forest_search/t8_forest_search_c_interface.cxx @@ -20,11 +20,8 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include #include -T8_EXTERN_C_BEGIN (); - struct t8_forest_search { t8_search *c_search; diff --git a/src/t8_forest/t8_forest_search/t8_forest_search_c_interface.h b/src/t8_forest/t8_forest_search/t8_forest_search_c_interface.h index bda73ba1a3..d861349b64 100644 --- a/src/t8_forest/t8_forest_search/t8_forest_search_c_interface.h +++ b/src/t8_forest/t8_forest_search/t8_forest_search_c_interface.h @@ -26,8 +26,8 @@ #define T8_FOREST_SEARCH_C_INTERFACE_H #include -#include +T8_EXTERN_C_BEGIN (); /* * Discussion about C++ callback handling https://stackoverflow.com/questions/2298242/callback-functions-in-c * We decided for option 4, using std::function together with templates. @@ -79,4 +79,6 @@ t8_forest_c_search_with_queries_destroy (t8_forest_search_with_queries_c_wrapper void t8_forest_c_search_with_queries_do_search (t8_forest_search_with_queries_c_wrapper *search); +T8_EXTERN_C_END (); + #endif // T8_FOREST_SEARCH_C_INTERFACE_H diff --git a/test/t8_forest/t8_gtest_search.cxx b/test/t8_forest/t8_gtest_search.cxx index 27970eb419..b1cbeaa40f 100644 --- a/test/t8_forest/t8_gtest_search.cxx +++ b/test/t8_forest/t8_gtest_search.cxx @@ -67,14 +67,15 @@ t8_test_search_all_fn (t8_forest_t forest, const t8_locidx_t ltreeid, const t8_e std::vector &user_data) { if (is_leaf) { - t8_locidx_t test_ltreeid; const t8_eclass_t tree_class = t8_forest_get_tree_class (forest, ltreeid); - const t8_scheme *scheme = t8_forest_get_scheme (forest); + t8_eclass_scheme_c *ts = t8_forest_get_eclass_scheme (forest, tree_class); + const t8_locidx_t tree_offset = t8_forest_get_tree_element_offset (forest, ltreeid); const t8_locidx_t tree_offset = t8_forest_get_tree_element_offset (forest, ltreeid); /* Set the corresponding entry to 1 */ user_data[tree_offset + tree_leaf_index] = true; /* Test whether tree_leaf_index is actually the index of the element */ + t8_locidx_t test_ltreeid; const t8_element_t *test_element = t8_forest_get_element (forest, tree_offset + tree_leaf_index, &test_ltreeid); EXPECT_ELEM_EQ (scheme, tree_class, element, test_element); @@ -98,7 +99,7 @@ t8_test_search_query_all_fn (const t8_forest_t forest, const t8_locidx_t ltreeid EXPECT_EQ (iquery, 42) << "Wrong query argument passed to query callback."; if (is_leaf) { /* Test whether tree_leaf_index is actually the index of the element */ - const t8_locidx_t test_ltreeid; + t8_locidx_t test_ltreeid; const t8_eclass_t tree_class = t8_forest_get_tree_class (forest, ltreeid); const t8_eclass_scheme_c *ts = t8_forest_get_eclass_scheme (forest, tree_class); From 4dff9fceca8651eec68c0b74058a9abe23179563 Mon Sep 17 00:00:00 2001 From: David Knapp Date: Mon, 11 Nov 2024 13:55:29 +0100 Subject: [PATCH 13/22] compiling, but buggy in the callback the function t8_forest_get_tree_class throws an assertion. in the constructor of the test the same function is successfull. --- src/CMakeLists.txt | 3 +- src/t8_forest/t8_forest.cxx | 1 - .../t8_forest_search/t8_forest_search.cxx | 37 ++-- .../t8_forest_search/t8_forest_search.hxx | 162 +++++++++++------- test/t8_forest/t8_gtest_search.cxx | 23 +-- 5 files changed, 129 insertions(+), 97 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d9bcfec1de..be24a76a79 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -122,7 +122,8 @@ target_sources( T8 PRIVATE t8_forest/t8_forest_ghost.cxx t8_forest/t8_forest_iterate.cxx t8_forest/t8_forest_balance.cxx - t8_forest/t8_forest_netcdf.cxx + t8_forest/t8_forest_netcdf.cxx + t8_forest/t8_forest_search/t8_forest_search.cxx t8_geometry/t8_geometry.cxx t8_geometry/t8_geometry_helpers.c t8_geometry/t8_geometry_base.cxx diff --git a/src/t8_forest/t8_forest.cxx b/src/t8_forest/t8_forest.cxx index f3e6e5638b..680f49b4fa 100644 --- a/src/t8_forest/t8_forest.cxx +++ b/src/t8_forest/t8_forest.cxx @@ -3690,7 +3690,6 @@ t8_eclass_t t8_forest_get_tree_class (const t8_forest_t forest, const t8_locidx_t ltreeid) { t8_locidx_t num_local_trees = t8_forest_get_num_local_trees (forest); - T8_ASSERT (0 <= ltreeid && ltreeid < num_local_trees + t8_forest_get_num_ghost_trees (forest)); if (ltreeid < num_local_trees) { /* The id belongs to a local tree */ diff --git a/src/t8_forest/t8_forest_search/t8_forest_search.cxx b/src/t8_forest/t8_forest_search/t8_forest_search.cxx index 54bf356114..912698a39e 100644 --- a/src/t8_forest/t8_forest_search/t8_forest_search.cxx +++ b/src/t8_forest/t8_forest_search/t8_forest_search.cxx @@ -20,23 +20,21 @@ along with t8code; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include +#include "t8_forest/t8_forest_search/t8_forest_search.hxx" #include #include #include #include void -t8_search::search_recursion (const t8_locidx_t ltreeid, t8_element_t *element, const t8_eclass_scheme_c *ts, - t8_element_array_t *leaf_elements, const t8_locidx_t tree_lindex_of_first_leaf) +t8_search_base::search_recursion (const t8_locidx_t ltreeid, t8_element_t *element, const t8_eclass_scheme_c *ts, + t8_element_array_t *leaf_elements, const t8_locidx_t tree_lindex_of_first_leaf) { /* Assertions to check for necessary requirements */ /* The forest must be committed */ - T8_ASSERT (t8_forest_is_committed (forest)); + T8_ASSERT (t8_forest_is_committed (this->forest)); /* The tree must be local */ - T8_ASSERT (0 <= ltreeid && ltreeid < t8_forest_get_num_local_trees (forest)); - /* If we have queries, we also must have a query function */ - T8_ASSERT ((queries == NULL) == (query_fn == NULL)); + T8_ASSERT (0 <= ltreeid && ltreeid < t8_forest_get_num_local_trees (this->forest)); const size_t elem_count = t8_element_array_get_count (leaf_elements); if (elem_count == 0) { @@ -56,22 +54,21 @@ t8_search::search_recursion (const t8_locidx_t ltreeid, t8_element_t *element, c SC_CHECK_ABORT (ts->t8_element_level (element) <= ts->t8_element_level (leaf), "Search: element level greater than leaf level\n"); if (ts->t8_element_level (element) == ts->t8_element_level (leaf)) { - T8_ASSERT (t8_forest_element_is_leaf (forest, leaf, ltreeid)); + T8_ASSERT (t8_forest_element_is_leaf (this->forest, leaf, ltreeid)); T8_ASSERT (ts->t8_element_equal (element, leaf)); /* The element is the leaf */ is_leaf = 1; } } /* Call the callback function for the element */ - const bool ret - = this->element_callback (forest, ltreeid, element, is_leaf, leaf_elements, tree_lindex_of_first_leaf, user_data); + const bool ret = this->check_element (ltreeid, element, is_leaf, leaf_elements, tree_lindex_of_first_leaf); if (!ret) { /* The function returned false. We abort the recursion */ return; } std::vector new_active_queries; - this->check_queries (forest, new_active_queries, ltreeid, element, is_leaf, leaf_elements, tree_lindex_of_first_leaf); + this->check_queries (new_active_queries, ltreeid, element, is_leaf, leaf_elements, tree_lindex_of_first_leaf); if (is_leaf) { return; @@ -99,8 +96,7 @@ t8_search::search_recursion (const t8_locidx_t ltreeid, t8_element_t *element, c * we construct an array of these leaves */ t8_element_array_init_view (&child_leaves, leaf_elements, indexa, indexb - indexa); /* Enter the recursion */ - t8_forest_search_recursion (forest, ltreeid, children[ichild], ts, &child_leaves, - indexa + tree_lindex_of_first_leaf, search_fn, query_fn, queries, new_active_queries); + search_recursion (ltreeid, children[ichild], ts, &child_leaves, indexa + tree_lindex_of_first_leaf); } } @@ -111,11 +107,11 @@ t8_search::search_recursion (const t8_locidx_t ltreeid, t8_element_t *element, c } void -t8_search::search_tree (const t8_locidx_t ltreeid) +t8_search_base::search_tree (const t8_locidx_t ltreeid) { - const t8_eclass_t eclass = t8_forest_get_eclass (forest, ltreeid); - const t8_eclass_scheme_c *ts = t8_forest_get_eclass_scheme (forest, eclass); - t8_element_array_t *leaf_elements = t8_forest_tree_get_leaves (forest, ltreeid); + const t8_eclass_t eclass = t8_forest_get_eclass (this->forest, ltreeid); + const t8_eclass_scheme_c *ts = t8_forest_get_eclass_scheme (this->forest, eclass); + t8_element_array_t *leaf_elements = t8_forest_tree_get_leaves (this->forest, ltreeid); /* assert for empty tree */ T8_ASSERT (t8_element_array_get_count (leaf_elements) >= 0); @@ -129,15 +125,16 @@ t8_search::search_tree (const t8_locidx_t ltreeid) ts->t8_element_nca (first_el, last_el, nca); /* Start the top-down search */ - this->search_recursion (ltreeid, nca, ts, leaf_elements, 0, search_fn, query_fn, queries, active_queries); + this->search_recursion (ltreeid, nca, ts, leaf_elements, 0); ts->t8_element_destroy (1, &nca); } void -t8_search::do_search () +t8_search_base::do_search () { - const t8_locidx_t num_local_trees = t8_forest_get_num_local_trees (forest); + T8_ASSERT (t8_forest_is_committed (forest)); + const t8_locidx_t num_local_trees = t8_forest_get_num_local_trees (this->forest); for (t8_locidx_t itree = 0; itree < num_local_trees; itree++) { this->search_tree (itree); } diff --git a/src/t8_forest/t8_forest_search/t8_forest_search.hxx b/src/t8_forest/t8_forest_search/t8_forest_search.hxx index 6744d5acff..8946274c2a 100644 --- a/src/t8_forest/t8_forest_search/t8_forest_search.hxx +++ b/src/t8_forest/t8_forest_search/t8_forest_search.hxx @@ -57,7 +57,7 @@ template using t8_search_element_callback = std::function; + const t8_element_array_t *leaf_elements, const t8_locidx_t tree_leaf_index, Udata *user_data)>; /** * \typedef t8_search_queries_callback @@ -81,28 +81,15 @@ template using t8_search_queries_callback = std::function &queries, - std::vector &active_query_indices, std::vector &query_matches, Udata &user_data)>; + std::vector &active_query_indices, std::vector &query_matches, Udata *user_data)>; -/** - * @brief A class to search for elements in a forest. A user-defined callback function is invoked for each element - * to allow for custom search operations. - * - * @tparam Udata - */ -template -class t8_search { +class t8_search_base { public: - /** - * \brief Constructor of the search class. Sets the element callback, forest, and user data. - * \param[in] element_callback The callback function to be invoked for each element during the search. - * \param[in] forest The forest in which the search is performed. - * \param[in] user_data The user-defined data to be passed to the callback. - */ - t8_search (t8_search_element_callback element_callback, const t8_forest_t forest = nullptr, - const Udata &user_data = nullptr) - : element_callback (element_callback), user_data (user_data) + t8_search_base (t8_forest_t forest = nullptr) { - t8_forest_ref (forest); + if (forest != nullptr) { + t8_forest_ref (forest); + } this->forest = forest; }; @@ -115,26 +102,16 @@ class t8_search { * \param forest The new forest to be assigned. */ void - update_forest (const t8_forest_t forest) + update_forest (t8_forest_t forest) { - t8_forest_unref (&(this->forest)); + if (this->forest != nullptr) { + t8_forest_unref (&(this->forest)); + } + T8_ASSERT (forest != nullptr); t8_forest_ref (forest); this->forest = forest; } - /** - * \brief Updates the user data with the provided data. - * - * This function sets the user data to the given value. - * - * \param[in] udata The new user data to be set. - */ - void - update_user_data (const Udata &udata) - { - this->user_data = udata; - } - /** * \brief Destructor for the search class. * @@ -142,9 +119,11 @@ class t8_search { * associated with the search instance. It ensures that the resources * held by the forest object are only released if no further references exist. */ - ~t8_search () + ~t8_search_base () { - t8_forest_unref (&(this->forest)); + if (this->forest != nullptr) { + t8_forest_unref (&(this->forest)); + } }; /** @@ -159,41 +138,97 @@ class t8_search { private: /** - * \brief Searches the tree for specific elements or conditions. - * - * This function performs a search operation on the tree. - */ + * \brief Searches the tree for specific elements or conditions. + * + * This function performs a search operation on the tree. + */ void search_tree (const t8_locidx_t ltreeid); - /**{ + /** + * \brief Recursively searches for elements in the forest. + * + * This function performs a recursive search operation, used on each tree in the forest. + */ + void + search_recursion (const t8_locidx_t ltreeid, t8_element_t *element, const t8_eclass_scheme_c *ts, + t8_element_array_t *leaf_elements, const t8_locidx_t tree_lindex_of_first_leaf); + + virtual bool + stop_due_to_queries () + = 0; -} - * \brief Recursively searches for elements in the forest. + virtual bool + check_element (const t8_locidx_t ltreeid, const t8_element_t *element, const bool is_leaf, + const t8_element_array_t *leaf_elements, const t8_locidx_t tree_leaf_index) + = 0; + + virtual void + check_queries (std::vector &new_active_queries, const t8_locidx_t ltreeid, const t8_element_t *element, + const bool is_leaf, const t8_element_array_t *leaf_elements, const t8_locidx_t tree_leaf_index) + = 0; + + t8_forest_t forest; +}; + +/** + * @brief A class to search for elements in a forest. A user-defined callback function is invoked for each element + * to allow for custom search operations. + * + * @tparam Udata + */ +template +class t8_search: public t8_search_base { + public: + /** + * \brief Constructor of the search class. Sets the element callback, forest, and user data. + * \param[in] element_callback The callback function to be invoked for each element during the search. + * \param[in] forest The forest in which the search is performed. + * \param[in] user_data The user-defined data to be passed to the callback. + */ + t8_search (t8_search_element_callback element_callback, t8_forest_t forest = nullptr, + Udata *user_data = nullptr) + : t8_search_base (forest), element_callback (element_callback), user_data (user_data) {}; + + /** + * \brief Updates the user data with the provided data. * - * This function performs a recursive search operation, used on each tree in the forest. + * This function sets the user data to the given value. + * + * \param[in] udata The new user data to be set. */ void - search_recursion (const t8_locidx_t ltreeid, t8_element_t *element, const t8_eclass_scheme_c *ts, - t8_element_array_t *leaf_elements, const t8_locidx_t tree_lindex_of_first_leaf); + update_user_data (Udata *udata) + { + this->user_data = udata; + } + Udata *user_data; + t8_forest_t forest; + + private: bool stop_due_to_queries () { return false; } - void - check_queries (const t8_locidx_t ltreeid, const t8_element_t *element, const bool is_leaf, + bool + check_element (const t8_locidx_t ltreeid, const t8_element_t *element, const bool is_leaf, const t8_element_array_t *leaf_elements, const t8_locidx_t tree_leaf_index) + { + return this->element_callback (this->forest, ltreeid, element, is_leaf, leaf_elements, tree_leaf_index, + this->user_data); + } + + void + check_queries (std::vector &new_active_queries, const t8_locidx_t ltreeid, const t8_element_t *element, + const bool is_leaf, const t8_element_array_t *leaf_elements, const t8_locidx_t tree_leaf_index) { return; } t8_search_element_callback element_callback; - - const t8_forest_t &forest; - const Udata &user_data; }; template @@ -214,9 +249,10 @@ class t8_search_with_queries: public t8_search { */ t8_search_with_queries (t8_search_element_callback element_callback, t8_search_queries_callback queries_callback, std::vector &queries, - const t8_forest_t forest = nullptr) - : t8_search (element_callback, forest), queries_callback (queries_callback), queries (queries) + const t8_forest_t forest = nullptr, Udata *user_data = nullptr) + : t8_search (element_callback, forest, user_data), queries_callback (queries_callback), queries (queries) { + this->active_queries.resize (queries.size ()); std::iota (this->active_queries.begin (), this->active_queries.end (), 0); }; @@ -229,15 +265,12 @@ class t8_search_with_queries: public t8_search { * \param queries A vector containing the new queries to be set. */ void - update_queries (const std::vector &queries) + update_queries (std::vector &queries) { this->queries = queries; } - ~t8_search_with_queries () - { - t8_forest_unref (this->forest); - }; + ~t8_search_with_queries () {}; private: bool @@ -247,15 +280,14 @@ class t8_search_with_queries: public t8_search { } void - check_queries (t8_forest_t forest, std::vector new_active_queries, const t8_locidx_t ltreeid, - const t8_element_t *element, const bool is_leaf, const t8_element_array_t *leaf_elements, - const t8_locidx_t tree_leaf_index) + check_queries (std::vector &new_active_queries, const t8_locidx_t ltreeid, const t8_element_t *element, + const bool is_leaf, const t8_element_array_t *leaf_elements, const t8_locidx_t tree_leaf_index) { T8_ASSERT (new_active_queries.empty ()); if (!this->active_queries.empty ()) { std::vector query_matches (active_queries.size ()); - queries_callback (forest, ltreeid, element, is_leaf, leaf_elements, tree_leaf_index, this->queries, - this->active_queries, query_matches, this->user_data); + this->queries_callback (this->forest, ltreeid, element, is_leaf, leaf_elements, tree_leaf_index, this->queries, + this->active_queries, query_matches, this->user_data); if (!is_leaf) { std::for_each (this->active_queries.begin (), this->active_queries.end (), [&] (size_t iactive) { if (query_matches[iactive]) { @@ -267,7 +299,7 @@ class t8_search_with_queries: public t8_search { } t8_search_queries_callback queries_callback; - const std::vector &queries; + std::vector &queries; std::vector active_queries; }; #if 0 diff --git a/test/t8_forest/t8_gtest_search.cxx b/test/t8_forest/t8_gtest_search.cxx index b1cbeaa40f..04028d31d2 100644 --- a/test/t8_forest/t8_gtest_search.cxx +++ b/test/t8_forest/t8_gtest_search.cxx @@ -44,6 +44,8 @@ class forest_search: public testing::TestWithParam> { cmesh = t8_cmesh_new_hypercube (eclass, sc_MPI_COMM_WORLD, 0, 0, 0); /* Build a uniform forest */ forest = t8_forest_new_uniform (cmesh, default_scheme, level, 0, sc_MPI_COMM_WORLD); + const t8_eclass_t eclass = t8_forest_get_tree_class (forest, 0); + t8_debugf ("[D] eclass %d\n", eclass); } void TearDown () override @@ -61,19 +63,20 @@ class forest_search: public testing::TestWithParam> { * with one int for each local leaf. * If this function is called for a leaf, it sets the corresponding entry to 1. */ -static bool +bool t8_test_search_all_fn (t8_forest_t forest, const t8_locidx_t ltreeid, const t8_element_t *element, const bool is_leaf, const t8_element_array_t *leaf_elements, const t8_locidx_t tree_leaf_index, - std::vector &user_data) + std::vector *user_data) { if (is_leaf) { + t8_debugf ("[D] ltreeid %d\n", ltreeid); + fflush (stdout); const t8_eclass_t tree_class = t8_forest_get_tree_class (forest, ltreeid); t8_eclass_scheme_c *ts = t8_forest_get_eclass_scheme (forest, tree_class); - const t8_locidx_t tree_offset = t8_forest_get_tree_element_offset (forest, ltreeid); const t8_locidx_t tree_offset = t8_forest_get_tree_element_offset (forest, ltreeid); /* Set the corresponding entry to 1 */ - user_data[tree_offset + tree_leaf_index] = true; + (*user_data)[tree_offset + tree_leaf_index] = true; /* Test whether tree_leaf_index is actually the index of the element */ t8_locidx_t test_ltreeid; const t8_element_t *test_element = t8_forest_get_element (forest, tree_offset + tree_leaf_index, &test_ltreeid); @@ -84,12 +87,12 @@ t8_test_search_all_fn (t8_forest_t forest, const t8_locidx_t ltreeid, const t8_e return true; } -static void -t8_test_search_query_all_fn (const t8_forest_t forest, const t8_locidx_t ltreeid, const t8_element_t *element, +void +t8_test_search_query_all_fn (t8_forest_t forest, const t8_locidx_t ltreeid, const t8_element_t *element, const bool is_leaf, const t8_element_array_t *leaf_elements, const t8_locidx_t tree_leaf_index, std::vector &queries, - std::vector &active_query_indices, std::vector &query_matches, - std::vector &user_data) + std::vector &active_query_indices, std::vector &query_matches, + std::vector *user_data) { EXPECT_FALSE (queries.empty ()) << "query callback must be called with queries argument. "; EXPECT_EQ (active_query_indices.size (), (long unsigned int) 1) @@ -127,10 +130,10 @@ TEST_P (forest_search, test_search_one_query_matches_all) /* Call search. This search matches all elements. After this call we expect * all entries in the matched_leaves array to be set to 1. */ - t8_search::search_with_queries> search (t8_test_search_all_fn, t8_test_search_query_all_fn); + t8_search_with_queries> search (t8_test_search_all_fn, t8_test_search_query_all_fn, queries); search.update_queries (queries); - search.update_user_data (matched_leaves); + search.update_user_data (&matched_leaves); search.update_forest (forest); search.do_search (); From fa0f49907f9cd6640b4636ecf2938dc029393f2f Mon Sep 17 00:00:00 2001 From: David Knapp Date: Mon, 11 Nov 2024 16:49:03 +0100 Subject: [PATCH 14/22] Fixed bug. pass forest explicitly --- .../t8_forest_search/t8_forest_search.cxx | 9 +++-- .../t8_forest_search/t8_forest_search.hxx | 38 ++++++++++--------- test/t8_forest/t8_gtest_search.cxx | 17 +++------ 3 files changed, 32 insertions(+), 32 deletions(-) diff --git a/src/t8_forest/t8_forest_search/t8_forest_search.cxx b/src/t8_forest/t8_forest_search/t8_forest_search.cxx index 912698a39e..13db7e48ba 100644 --- a/src/t8_forest/t8_forest_search/t8_forest_search.cxx +++ b/src/t8_forest/t8_forest_search/t8_forest_search.cxx @@ -46,7 +46,7 @@ t8_search_base::search_recursion (const t8_locidx_t ltreeid, t8_element_t *eleme return; } - int is_leaf = 0; + bool is_leaf = false; if (elem_count == 1) { /* There is only one leaf left, we check whether it is the same as element and if so call the callback function */ const t8_element_t *leaf = t8_element_array_index_locidx (leaf_elements, 0); @@ -57,18 +57,19 @@ t8_search_base::search_recursion (const t8_locidx_t ltreeid, t8_element_t *eleme T8_ASSERT (t8_forest_element_is_leaf (this->forest, leaf, ltreeid)); T8_ASSERT (ts->t8_element_equal (element, leaf)); /* The element is the leaf */ - is_leaf = 1; + is_leaf = true; } } /* Call the callback function for the element */ - const bool ret = this->check_element (ltreeid, element, is_leaf, leaf_elements, tree_lindex_of_first_leaf); + const bool ret = check_element (this->forest, ltreeid, element, is_leaf, leaf_elements, tree_lindex_of_first_leaf); if (!ret) { /* The function returned false. We abort the recursion */ return; } std::vector new_active_queries; - this->check_queries (new_active_queries, ltreeid, element, is_leaf, leaf_elements, tree_lindex_of_first_leaf); + this->check_queries (this->forest, new_active_queries, ltreeid, element, is_leaf, leaf_elements, + tree_lindex_of_first_leaf); if (is_leaf) { return; diff --git a/src/t8_forest/t8_forest_search/t8_forest_search.hxx b/src/t8_forest/t8_forest_search/t8_forest_search.hxx index 8946274c2a..cc292c10da 100644 --- a/src/t8_forest/t8_forest_search/t8_forest_search.hxx +++ b/src/t8_forest/t8_forest_search/t8_forest_search.hxx @@ -27,6 +27,7 @@ #include #include +#include // Ensure t8_forest_t is defined #include #include @@ -55,9 +56,9 @@ * \return True if the search should continue, false otherwise. */ template -using t8_search_element_callback - = std::function; +using t8_search_element_callback = std::function; /** * \typedef t8_search_queries_callback @@ -79,7 +80,7 @@ using t8_search_element_callback */ template using t8_search_queries_callback = std::function &queries, std::vector &active_query_indices, std::vector &query_matches, Udata *user_data)>; @@ -159,13 +160,14 @@ class t8_search_base { = 0; virtual bool - check_element (const t8_locidx_t ltreeid, const t8_element_t *element, const bool is_leaf, - const t8_element_array_t *leaf_elements, const t8_locidx_t tree_leaf_index) + check_element (const t8_forest_t forest_check, const t8_locidx_t ltreeid, const t8_element_t *element, + const bool is_leaf, const t8_element_array_t *leaf_elements, const t8_locidx_t tree_leaf_index) = 0; virtual void - check_queries (std::vector &new_active_queries, const t8_locidx_t ltreeid, const t8_element_t *element, - const bool is_leaf, const t8_element_array_t *leaf_elements, const t8_locidx_t tree_leaf_index) + check_queries (const t8_forest_t forest_check, std::vector &new_active_queries, const t8_locidx_t ltreeid, + const t8_element_t *element, const bool is_leaf, const t8_element_array_t *leaf_elements, + const t8_locidx_t tree_leaf_index) = 0; t8_forest_t forest; @@ -214,16 +216,17 @@ class t8_search: public t8_search_base { } bool - check_element (const t8_locidx_t ltreeid, const t8_element_t *element, const bool is_leaf, - const t8_element_array_t *leaf_elements, const t8_locidx_t tree_leaf_index) + check_element (const t8_forest_t forest_check, const t8_locidx_t ltreeid, const t8_element_t *element, + const bool is_leaf, const t8_element_array_t *leaf_elements, const t8_locidx_t tree_leaf_index) { - return this->element_callback (this->forest, ltreeid, element, is_leaf, leaf_elements, tree_leaf_index, - this->user_data); + T8_ASSERT (t8_forest_is_committed (forest_check)); + return this->element_callback (forest_check, ltreeid, element, is_leaf, leaf_elements, tree_leaf_index, user_data); } void - check_queries (std::vector &new_active_queries, const t8_locidx_t ltreeid, const t8_element_t *element, - const bool is_leaf, const t8_element_array_t *leaf_elements, const t8_locidx_t tree_leaf_index) + check_queries (const t8_forest_t forest_check, std::vector &new_active_queries, const t8_locidx_t ltreeid, + const t8_element_t *element, const bool is_leaf, const t8_element_array_t *leaf_elements, + const t8_locidx_t tree_leaf_index) { return; } @@ -280,13 +283,14 @@ class t8_search_with_queries: public t8_search { } void - check_queries (std::vector &new_active_queries, const t8_locidx_t ltreeid, const t8_element_t *element, - const bool is_leaf, const t8_element_array_t *leaf_elements, const t8_locidx_t tree_leaf_index) + check_queries (const t8_forest_t forest_check, std::vector &new_active_queries, const t8_locidx_t ltreeid, + const t8_element_t *element, const bool is_leaf, const t8_element_array_t *leaf_elements, + const t8_locidx_t tree_leaf_index) { T8_ASSERT (new_active_queries.empty ()); if (!this->active_queries.empty ()) { std::vector query_matches (active_queries.size ()); - this->queries_callback (this->forest, ltreeid, element, is_leaf, leaf_elements, tree_leaf_index, this->queries, + this->queries_callback (forest_check, ltreeid, element, is_leaf, leaf_elements, tree_leaf_index, this->queries, this->active_queries, query_matches, this->user_data); if (!is_leaf) { std::for_each (this->active_queries.begin (), this->active_queries.end (), [&] (size_t iactive) { diff --git a/test/t8_forest/t8_gtest_search.cxx b/test/t8_forest/t8_gtest_search.cxx index 04028d31d2..39da42acc8 100644 --- a/test/t8_forest/t8_gtest_search.cxx +++ b/test/t8_forest/t8_gtest_search.cxx @@ -44,8 +44,6 @@ class forest_search: public testing::TestWithParam> { cmesh = t8_cmesh_new_hypercube (eclass, sc_MPI_COMM_WORLD, 0, 0, 0); /* Build a uniform forest */ forest = t8_forest_new_uniform (cmesh, default_scheme, level, 0, sc_MPI_COMM_WORLD); - const t8_eclass_t eclass = t8_forest_get_tree_class (forest, 0); - t8_debugf ("[D] eclass %d\n", eclass); } void TearDown () override @@ -64,13 +62,12 @@ class forest_search: public testing::TestWithParam> { * If this function is called for a leaf, it sets the corresponding entry to 1. */ bool -t8_test_search_all_fn (t8_forest_t forest, const t8_locidx_t ltreeid, const t8_element_t *element, const bool is_leaf, - const t8_element_array_t *leaf_elements, const t8_locidx_t tree_leaf_index, +t8_test_search_all_fn (const t8_forest_t forest, const t8_locidx_t ltreeid, const t8_element_t *element, + const bool is_leaf, const t8_element_array_t *leaf_elements, const t8_locidx_t tree_leaf_index, std::vector *user_data) { + T8_ASSERT (t8_forest_is_committed (forest)); if (is_leaf) { - t8_debugf ("[D] ltreeid %d\n", ltreeid); - fflush (stdout); const t8_eclass_t tree_class = t8_forest_get_tree_class (forest, ltreeid); t8_eclass_scheme_c *ts = t8_forest_get_eclass_scheme (forest, tree_class); const t8_locidx_t tree_offset = t8_forest_get_tree_element_offset (forest, ltreeid); @@ -88,7 +85,7 @@ t8_test_search_all_fn (t8_forest_t forest, const t8_locidx_t ltreeid, const t8_e } void -t8_test_search_query_all_fn (t8_forest_t forest, const t8_locidx_t ltreeid, const t8_element_t *element, +t8_test_search_query_all_fn (const t8_forest_t forest, const t8_locidx_t ltreeid, const t8_element_t *element, const bool is_leaf, const t8_element_array_t *leaf_elements, const t8_locidx_t tree_leaf_index, std::vector &queries, std::vector &active_query_indices, std::vector &query_matches, @@ -99,7 +96,7 @@ t8_test_search_query_all_fn (t8_forest_t forest, const t8_locidx_t ltreeid, cons << "Wrong number of active queries passed to query callback."; for (int iquery : active_query_indices) { /* The query is an int with value 42 (see below) */ - EXPECT_EQ (iquery, 42) << "Wrong query argument passed to query callback."; + EXPECT_EQ (queries[iquery], 42) << "Wrong query argument passed to query callback."; if (is_leaf) { /* Test whether tree_leaf_index is actually the index of the element */ t8_locidx_t test_ltreeid; @@ -117,10 +114,8 @@ t8_test_search_query_all_fn (t8_forest_t forest, const t8_locidx_t ltreeid, cons TEST_P (forest_search, test_search_one_query_matches_all) { - const int query = 42; - /* set up a single query containing our query */ - std::vector queries = { 1 }; + std::vector queries = { 42 }; t8_locidx_t num_elements = t8_forest_get_local_num_elements (forest); /* set up an array in which we flag whether an element was matched in the From 9e746583ea82dd09e121c9ee22c53f9e2109cb73 Mon Sep 17 00:00:00 2001 From: David Knapp Date: Mon, 11 Nov 2024 17:07:26 +0100 Subject: [PATCH 15/22] minimize example to fix memory bug run with valgrind for more information --- .../t8_forest_search/t8_forest_search.cxx | 5 +-- .../t8_forest_search/t8_forest_search.hxx | 45 +++++++++---------- test/t8_forest/t8_gtest_search.cxx | 3 +- 3 files changed, 24 insertions(+), 29 deletions(-) diff --git a/src/t8_forest/t8_forest_search/t8_forest_search.cxx b/src/t8_forest/t8_forest_search/t8_forest_search.cxx index 13db7e48ba..6ea1c3c9f9 100644 --- a/src/t8_forest/t8_forest_search/t8_forest_search.cxx +++ b/src/t8_forest/t8_forest_search/t8_forest_search.cxx @@ -61,15 +61,14 @@ t8_search_base::search_recursion (const t8_locidx_t ltreeid, t8_element_t *eleme } } /* Call the callback function for the element */ - const bool ret = check_element (this->forest, ltreeid, element, is_leaf, leaf_elements, tree_lindex_of_first_leaf); + const bool ret = check_element (ltreeid, element, is_leaf, leaf_elements, tree_lindex_of_first_leaf); if (!ret) { /* The function returned false. We abort the recursion */ return; } std::vector new_active_queries; - this->check_queries (this->forest, new_active_queries, ltreeid, element, is_leaf, leaf_elements, - tree_lindex_of_first_leaf); + this->check_queries (new_active_queries, ltreeid, element, is_leaf, leaf_elements, tree_lindex_of_first_leaf); if (is_leaf) { return; diff --git a/src/t8_forest/t8_forest_search/t8_forest_search.hxx b/src/t8_forest/t8_forest_search/t8_forest_search.hxx index cc292c10da..be5ab94002 100644 --- a/src/t8_forest/t8_forest_search/t8_forest_search.hxx +++ b/src/t8_forest/t8_forest_search/t8_forest_search.hxx @@ -120,11 +120,8 @@ class t8_search_base { * associated with the search instance. It ensures that the resources * held by the forest object are only released if no further references exist. */ - ~t8_search_base () - { - if (this->forest != nullptr) { - t8_forest_unref (&(this->forest)); - } + ~t8_search_base () { + }; /** @@ -137,6 +134,8 @@ class t8_search_base { void do_search (); + t8_forest_t forest; + private: /** * \brief Searches the tree for specific elements or conditions. @@ -160,17 +159,14 @@ class t8_search_base { = 0; virtual bool - check_element (const t8_forest_t forest_check, const t8_locidx_t ltreeid, const t8_element_t *element, - const bool is_leaf, const t8_element_array_t *leaf_elements, const t8_locidx_t tree_leaf_index) + check_element (const t8_locidx_t ltreeid, const t8_element_t *element, const bool is_leaf, + const t8_element_array_t *leaf_elements, const t8_locidx_t tree_leaf_index) = 0; virtual void - check_queries (const t8_forest_t forest_check, std::vector &new_active_queries, const t8_locidx_t ltreeid, - const t8_element_t *element, const bool is_leaf, const t8_element_array_t *leaf_elements, - const t8_locidx_t tree_leaf_index) + check_queries (std::vector &new_active_queries, const t8_locidx_t ltreeid, const t8_element_t *element, + const bool is_leaf, const t8_element_array_t *leaf_elements, const t8_locidx_t tree_leaf_index) = 0; - - t8_forest_t forest; }; /** @@ -190,7 +186,9 @@ class t8_search: public t8_search_base { */ t8_search (t8_search_element_callback element_callback, t8_forest_t forest = nullptr, Udata *user_data = nullptr) - : t8_search_base (forest), element_callback (element_callback), user_data (user_data) {}; + : element_callback (element_callback), user_data (user_data) { + + }; /** * \brief Updates the user data with the provided data. @@ -206,7 +204,6 @@ class t8_search: public t8_search_base { } Udata *user_data; - t8_forest_t forest; private: bool @@ -216,17 +213,16 @@ class t8_search: public t8_search_base { } bool - check_element (const t8_forest_t forest_check, const t8_locidx_t ltreeid, const t8_element_t *element, - const bool is_leaf, const t8_element_array_t *leaf_elements, const t8_locidx_t tree_leaf_index) + check_element (const t8_locidx_t ltreeid, const t8_element_t *element, const bool is_leaf, + const t8_element_array_t *leaf_elements, const t8_locidx_t tree_leaf_index) { - T8_ASSERT (t8_forest_is_committed (forest_check)); - return this->element_callback (forest_check, ltreeid, element, is_leaf, leaf_elements, tree_leaf_index, user_data); + T8_ASSERT (t8_forest_is_committed (this->forest)); + return this->element_callback (this->forest, ltreeid, element, is_leaf, leaf_elements, tree_leaf_index, user_data); } void - check_queries (const t8_forest_t forest_check, std::vector &new_active_queries, const t8_locidx_t ltreeid, - const t8_element_t *element, const bool is_leaf, const t8_element_array_t *leaf_elements, - const t8_locidx_t tree_leaf_index) + check_queries (std::vector &new_active_queries, const t8_locidx_t ltreeid, const t8_element_t *element, + const bool is_leaf, const t8_element_array_t *leaf_elements, const t8_locidx_t tree_leaf_index) { return; } @@ -283,14 +279,13 @@ class t8_search_with_queries: public t8_search { } void - check_queries (const t8_forest_t forest_check, std::vector &new_active_queries, const t8_locidx_t ltreeid, - const t8_element_t *element, const bool is_leaf, const t8_element_array_t *leaf_elements, - const t8_locidx_t tree_leaf_index) + check_queries (std::vector &new_active_queries, const t8_locidx_t ltreeid, const t8_element_t *element, + const bool is_leaf, const t8_element_array_t *leaf_elements, const t8_locidx_t tree_leaf_index) { T8_ASSERT (new_active_queries.empty ()); if (!this->active_queries.empty ()) { std::vector query_matches (active_queries.size ()); - this->queries_callback (forest_check, ltreeid, element, is_leaf, leaf_elements, tree_leaf_index, this->queries, + this->queries_callback (this->forest, ltreeid, element, is_leaf, leaf_elements, tree_leaf_index, this->queries, this->active_queries, query_matches, this->user_data); if (!is_leaf) { std::for_each (this->active_queries.begin (), this->active_queries.end (), [&] (size_t iactive) { diff --git a/test/t8_forest/t8_gtest_search.cxx b/test/t8_forest/t8_gtest_search.cxx index 39da42acc8..f947479027 100644 --- a/test/t8_forest/t8_gtest_search.cxx +++ b/test/t8_forest/t8_gtest_search.cxx @@ -139,4 +139,5 @@ TEST_P (forest_search, test_search_one_query_matches_all) t8_forest_unref (&forest); } -INSTANTIATE_TEST_SUITE_P (t8_gtest_search, forest_search, testing::Combine (AllEclasses, testing::Range (0, 6))); +INSTANTIATE_TEST_SUITE_P (t8_gtest_search, forest_search, + testing::Combine (testing::Values (T8_ECLASS_QUAD), testing::Range (0, 6))); From aee133f15a9ca97e2bfcf2b10a0c0de261db1146 Mon Sep 17 00:00:00 2001 From: David Knapp Date: Tue, 12 Nov 2024 08:20:15 +0100 Subject: [PATCH 16/22] Fix Memory bug. unref as destructor --- src/t8_forest/t8_forest_search/t8_forest_search.hxx | 9 +++++++-- test/t8_forest/t8_gtest_search.cxx | 3 +-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/t8_forest/t8_forest_search/t8_forest_search.hxx b/src/t8_forest/t8_forest_search/t8_forest_search.hxx index be5ab94002..063118d6f4 100644 --- a/src/t8_forest/t8_forest_search/t8_forest_search.hxx +++ b/src/t8_forest/t8_forest_search/t8_forest_search.hxx @@ -90,6 +90,7 @@ class t8_search_base { { if (forest != nullptr) { t8_forest_ref (forest); + T8_ASSERT (t8_forest_is_committed (forest)); } this->forest = forest; }; @@ -109,6 +110,7 @@ class t8_search_base { t8_forest_unref (&(this->forest)); } T8_ASSERT (forest != nullptr); + T8_ASSERT (t8_forest_is_committed (forest)); t8_forest_ref (forest); this->forest = forest; } @@ -120,8 +122,11 @@ class t8_search_base { * associated with the search instance. It ensures that the resources * held by the forest object are only released if no further references exist. */ - ~t8_search_base () { - + ~t8_search_base () + { + if (this->forest != nullptr) { + t8_forest_unref (&(this->forest)); + } }; /** diff --git a/test/t8_forest/t8_gtest_search.cxx b/test/t8_forest/t8_gtest_search.cxx index f947479027..39da42acc8 100644 --- a/test/t8_forest/t8_gtest_search.cxx +++ b/test/t8_forest/t8_gtest_search.cxx @@ -139,5 +139,4 @@ TEST_P (forest_search, test_search_one_query_matches_all) t8_forest_unref (&forest); } -INSTANTIATE_TEST_SUITE_P (t8_gtest_search, forest_search, - testing::Combine (testing::Values (T8_ECLASS_QUAD), testing::Range (0, 6))); +INSTANTIATE_TEST_SUITE_P (t8_gtest_search, forest_search, testing::Combine (AllEclasses, testing::Range (0, 6))); From 40e1d397964fd8b53edc6f754f9006216efbfff0 Mon Sep 17 00:00:00 2001 From: David Knapp Date: Tue, 12 Nov 2024 08:33:15 +0100 Subject: [PATCH 17/22] Delete obsolete code --- .../t8_forest_search/t8_forest_search.hxx | 51 ------------------- 1 file changed, 51 deletions(-) diff --git a/src/t8_forest/t8_forest_search/t8_forest_search.hxx b/src/t8_forest/t8_forest_search/t8_forest_search.hxx index 063118d6f4..6104b2ecec 100644 --- a/src/t8_forest/t8_forest_search/t8_forest_search.hxx +++ b/src/t8_forest/t8_forest_search/t8_forest_search.hxx @@ -306,56 +306,5 @@ class t8_search_with_queries: public t8_search { std::vector &queries; std::vector active_queries; }; -#if 0 -//General shape of search - -template -void -do_search () ( - // init queries - for each tree { - search_tree { - // init NCA and get elements - element = NCA; - search_recursion(element) { - if (stop_due_to_queries) { - return; - } - ret = element_callback(element); - if (!ret) return; - do_queries (); - - // Prepare recursion - for all children search_recursion (child[i]); - } - // delete NCA and elements - } - } - // delete queries -} - -search::do_queries () -{ - return; -} - -search::stop_due_to_queries () { - return false; -} - search_with_queries::do_queries () -{ - if (queries) { - if (!leaf) // Init new query array - query_callback (element, queries, query_matches); - if (!leaf) // Fill new query array - } -} - search_with_queries::stop_due_to_queries () { - if (queries != NULL && num_active == 0) { - /* There are no queries left. We stop the recursion */ - return true; - } -} -#endif #endif // T8_FOREST_SEARCH_HXX From 3791f71deea25267663d16daf4acf93bfe9601b8 Mon Sep 17 00:00:00 2001 From: David Knapp Date: Tue, 12 Nov 2024 08:51:40 +0100 Subject: [PATCH 18/22] More documentation --- .../t8_forest_search/t8_forest_search.hxx | 165 +++++++++--------- 1 file changed, 87 insertions(+), 78 deletions(-) diff --git a/src/t8_forest/t8_forest_search/t8_forest_search.hxx b/src/t8_forest/t8_forest_search/t8_forest_search.hxx index 6104b2ecec..751efdaa8f 100644 --- a/src/t8_forest/t8_forest_search/t8_forest_search.hxx +++ b/src/t8_forest/t8_forest_search/t8_forest_search.hxx @@ -86,22 +86,30 @@ using t8_search_queries_callback = std::functionforest = forest; - }; + } - /** - * \brief Updates the forest reference in the current object. + /** \brief Update the forest for the search. * - * This function updates the forest reference by dereferencing the current forest - * and assigning the new forest to the object's forest member. + * This function updates the forest for the search. If the current forest is not null, + * it decrements the reference count of the forest. It then asserts that the new forest + * is not null and is committed. Finally, it increments the reference count of the new forest. * - * \param forest The new forest to be assigned. + * \param[in] forest A pointer to a t8_forest_t object. */ void update_forest (t8_forest_t forest) @@ -115,26 +123,20 @@ class t8_search_base { this->forest = forest; } - /** - * \brief Destructor for the search class. + /** \brief Destructor for the t8_search_base class. * - * This destructor is responsible for unreferencing the forest object - * associated with the search instance. It ensures that the resources - * held by the forest object are only released if no further references exist. + * This destructor decrements the reference count of the forest if it is not null. */ ~t8_search_base () { if (this->forest != nullptr) { t8_forest_unref (&(this->forest)); } - }; + } - /** - * @brief Performs the search operation within the forest. + /** \brief Perform the search. * - * This function executes the search algorithm to locate specific elements - * within the forest structure. It performs a depth-first search on the forest, the criterion - * to search for elements is defined by the element callback function. + * This function performs the search in the forest. */ void do_search (); @@ -142,65 +144,89 @@ class t8_search_base { t8_forest_t forest; private: - /** - * \brief Searches the tree for specific elements or conditions. - * - * This function performs a search operation on the tree. - */ + /** @brief Searches a tree within the forest. + * + * This function performs a search operation on a tree identified by the given local tree ID. + * It uses the \a search_recursion function to perform the search. + * + * \param[in] ltreeid The local tree ID of the tree to be searched. + */ void search_tree (const t8_locidx_t ltreeid); - /** - * \brief Recursively searches for elements in the forest. - * - * This function performs a recursive search operation, used on each tree in the forest. - */ + /** \brief Recursively searches the tree. + * + * This function performs a recursive search operation on the tree identified by the given local tree ID. + * It uses the given \a element_callback function to process each element encountered during the search. + * If a query_callback function is provided, it is used to process queries during the search. + * + * \param[in] ltreeid The local tree ID of the tree to be searched. + * \param[in] element The element to be searched. + * \param[in] ts The element class scheme. + * \param[in] leaf_elements The array of leaf elements. + * \param[in] tree_lindex_of_first_leaf The index of the first leaf in the tree. + */ void search_recursion (const t8_locidx_t ltreeid, t8_element_t *element, const t8_eclass_scheme_c *ts, t8_element_array_t *leaf_elements, const t8_locidx_t tree_lindex_of_first_leaf); + /** \brief Checks if the search should stop due to empty queries. + * + */ virtual bool stop_due_to_queries () = 0; + /** \brief Checks an element during the search. + * + * This function is called for each element encountered during the search. + * It passes the arguments to the callback function provided by the user. + * + * \param[in] ltreeid The local tree ID of the current element. + * \param[in] element A pointer to the current element being processed. + * \param[in] is_leaf A bool indicating whether the current element is a leaf (non-zero) or not (zero). + * \param[in] leaf_elements A pointer to an array of leaf elements. + * \param[in] tree_leaf_index The index of the current leaf element within the tree. + * + * \return True if the search should continue, false otherwise. + */ virtual bool check_element (const t8_locidx_t ltreeid, const t8_element_t *element, const bool is_leaf, const t8_element_array_t *leaf_elements, const t8_locidx_t tree_leaf_index) = 0; + /** \brief Checks queries during the search. + * + * This function is called to check queries during the search. + * It passes the arguments to the callback function provided by the user. + * + * \param[in] new_active_queries A vector of indices of active queries. + * \param[in] ltreeid The local tree ID of the current element. + * \param[in] element A pointer to the current element being processed. + * \param[in] is_leaf A bool indicating whether the current element is a leaf (non-zero) or not (zero). + * \param[in] leaf_elements A pointer to an array of leaf elements. + * \param[in] tree_leaf_index The index of the current leaf element within the tree. + */ virtual void check_queries (std::vector &new_active_queries, const t8_locidx_t ltreeid, const t8_element_t *element, const bool is_leaf, const t8_element_array_t *leaf_elements, const t8_locidx_t tree_leaf_index) = 0; }; -/** - * @brief A class to search for elements in a forest. A user-defined callback function is invoked for each element - * to allow for custom search operations. - * - * @tparam Udata - */ template class t8_search: public t8_search_base { public: - /** - * \brief Constructor of the search class. Sets the element callback, forest, and user data. - * \param[in] element_callback The callback function to be invoked for each element during the search. - * \param[in] forest The forest in which the search is performed. - * \param[in] user_data The user-defined data to be passed to the callback. - */ t8_search (t8_search_element_callback element_callback, t8_forest_t forest = nullptr, Udata *user_data = nullptr) - : element_callback (element_callback), user_data (user_data) { - - }; + : t8_search_base (forest), element_callback (element_callback), user_data (user_data) + { + } - /** - * \brief Updates the user data with the provided data. + /** \brief Updates the user data associated with the object. * - * This function sets the user data to the given value. + * This function sets the user data pointer to the provided Udata object. * - * \param[in] udata The new user data to be set. + * \param[in] udata A pointer to the Udata object to be set as the user data. */ void update_user_data (Udata *udata) @@ -212,14 +238,14 @@ class t8_search: public t8_search_base { private: bool - stop_due_to_queries () + stop_due_to_queries () override { return false; } bool check_element (const t8_locidx_t ltreeid, const t8_element_t *element, const bool is_leaf, - const t8_element_array_t *leaf_elements, const t8_locidx_t tree_leaf_index) + const t8_element_array_t *leaf_elements, const t8_locidx_t tree_leaf_index) override { T8_ASSERT (t8_forest_is_committed (this->forest)); return this->element_callback (this->forest, ltreeid, element, is_leaf, leaf_elements, tree_leaf_index, user_data); @@ -227,7 +253,8 @@ class t8_search: public t8_search_base { void check_queries (std::vector &new_active_queries, const t8_locidx_t ltreeid, const t8_element_t *element, - const bool is_leaf, const t8_element_array_t *leaf_elements, const t8_locidx_t tree_leaf_index) + const bool is_leaf, const t8_element_array_t *leaf_elements, + const t8_locidx_t tree_leaf_index) override { return; } @@ -238,19 +265,6 @@ class t8_search: public t8_search_base { template class t8_search_with_queries: public t8_search { public: - /** - * \brief Constructor for the search_with_queries class. - * - * This constructor initializes a search_with_queries object with the provided element callback, - * queries callback, and a list of queries. It also optionally takes a forest object. - * - * \tparam Udata The type of user data. - * \tparam Query_T The type of the query. - * \param[in] element_callback A callback function for processing elements. - * \param[in] queries_callback A callback function for processing queries. - * \param[in] queries A vector containing the queries to be processed. - * \param[in] forest An optional forest object. Defaults to nullptr. - */ t8_search_with_queries (t8_search_element_callback element_callback, t8_search_queries_callback queries_callback, std::vector &queries, const t8_forest_t forest = nullptr, Udata *user_data = nullptr) @@ -258,34 +272,29 @@ class t8_search_with_queries: public t8_search { { this->active_queries.resize (queries.size ()); std::iota (this->active_queries.begin (), this->active_queries.end (), 0); - }; + } - /** - * \brief Updates the list of queries with the provided queries. - * - * This function replaces the current list of queries with the new list - * provided as the parameter. - * - * \param queries A vector containing the new queries to be set. - */ void update_queries (std::vector &queries) { this->queries = queries; } - ~t8_search_with_queries () {}; + ~t8_search_with_queries () + { + } private: bool - stop_due_to_queries () + stop_due_to_queries () override { return this->active_queries.empty (); } void check_queries (std::vector &new_active_queries, const t8_locidx_t ltreeid, const t8_element_t *element, - const bool is_leaf, const t8_element_array_t *leaf_elements, const t8_locidx_t tree_leaf_index) + const bool is_leaf, const t8_element_array_t *leaf_elements, + const t8_locidx_t tree_leaf_index) override { T8_ASSERT (new_active_queries.empty ()); if (!this->active_queries.empty ()) { @@ -293,11 +302,11 @@ class t8_search_with_queries: public t8_search { this->queries_callback (this->forest, ltreeid, element, is_leaf, leaf_elements, tree_leaf_index, this->queries, this->active_queries, query_matches, this->user_data); if (!is_leaf) { - std::for_each (this->active_queries.begin (), this->active_queries.end (), [&] (size_t iactive) { + for (size_t iactive : this->active_queries) { if (query_matches[iactive]) { new_active_queries.push_back (iactive); } - }); + } } } } From 29f8a792aa3d9321e8645c6ddf5cb47078f62f92 Mon Sep 17 00:00:00 2001 From: David Knapp Date: Tue, 12 Nov 2024 11:06:53 +0100 Subject: [PATCH 19/22] reorder initializer list when compiled with -pedantic reordering is forbidden --- src/t8_forest/t8_forest_search/t8_forest_search.hxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/t8_forest/t8_forest_search/t8_forest_search.hxx b/src/t8_forest/t8_forest_search/t8_forest_search.hxx index 751efdaa8f..68be280657 100644 --- a/src/t8_forest/t8_forest_search/t8_forest_search.hxx +++ b/src/t8_forest/t8_forest_search/t8_forest_search.hxx @@ -218,7 +218,7 @@ class t8_search: public t8_search_base { public: t8_search (t8_search_element_callback element_callback, t8_forest_t forest = nullptr, Udata *user_data = nullptr) - : t8_search_base (forest), element_callback (element_callback), user_data (user_data) + : t8_search_base (forest), user_data (user_data), element_callback (element_callback) { } From 3d4f8c57e8b051369211c3ba39fb7c8f99e8250b Mon Sep 17 00:00:00 2001 From: David Knapp Date: Tue, 12 Nov 2024 11:24:21 +0100 Subject: [PATCH 20/22] Should be implicitly installed via installed directories --- src/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index be24a76a79..3fe47b5e40 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -197,7 +197,6 @@ install( FILES t8_element.h t8_element_shape.h t8_forest_netcdf.h - t8_forest_search.hxx t8_mat.h t8_mesh.h t8_netcdf.h From f29be47b39f1ba5b69aa7e2383ef08eb4a215444 Mon Sep 17 00:00:00 2001 From: David Knapp Date: Tue, 12 Nov 2024 11:42:08 +0100 Subject: [PATCH 21/22] Test search without queries seperatly. --- test/t8_forest/t8_gtest_search.cxx | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/test/t8_forest/t8_gtest_search.cxx b/test/t8_forest/t8_gtest_search.cxx index 39da42acc8..524d6658fb 100644 --- a/test/t8_forest/t8_gtest_search.cxx +++ b/test/t8_forest/t8_gtest_search.cxx @@ -112,6 +112,29 @@ t8_test_search_query_all_fn (const t8_forest_t forest, const t8_locidx_t ltreeid } } +TEST_P (forest_search, t8_test_search_all_fn) +{ + t8_locidx_t num_elements = t8_forest_get_local_num_elements (forest); + /* set up an array in which we flag whether an element was matched in the + * search */ + std::vector matched_leaves (num_elements, false); + + /* Call search. This search matches all elements. After this call we expect + * all entries in the matched_leaves array to be set to 1. */ + + t8_search> search (t8_test_search_all_fn); + + search.update_user_data (&matched_leaves); + search.update_forest (forest); + search.do_search (); + + /* Check whether matched_leaves entries are all 1 */ + std::for_each (matched_leaves.begin (), matched_leaves.end (), + [] (bool b) { ASSERT_TRUE (b) << "Search did not match all leaves. First mismatch at leaf " << b; }); + + t8_forest_unref (&forest); +} + TEST_P (forest_search, test_search_one_query_matches_all) { /* set up a single query containing our query */ From df9ceda3e4037ea13ff843792ea6dcb1788eddff Mon Sep 17 00:00:00 2001 From: "Nguyen Xuan, Tu" Date: Fri, 31 Jan 2025 10:27:28 +0100 Subject: [PATCH 22/22] Removed unused variable --- src/t8_cmesh/t8_cmesh_trees.cxx | 2 -- test/CMakeLists.txt | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/t8_cmesh/t8_cmesh_trees.cxx b/src/t8_cmesh/t8_cmesh_trees.cxx index 4835e59335..de22b966f9 100644 --- a/src/t8_cmesh/t8_cmesh_trees.cxx +++ b/src/t8_cmesh/t8_cmesh_trees.cxx @@ -1224,9 +1224,7 @@ t8_cmesh_trees_is_equal (const t8_cmesh_t cmesh, const t8_cmesh_trees_t trees_a, { int is_equal; t8_locidx_t num_trees, num_ghost, ighost; - t8_ctree_t treea, treeb; t8_cghost_t ghosta, ghostb; - t8_locidx_t *face_neighborsa, *face_neighborsb; t8_gloidx_t *gface_neighborsa, *gface_neighborsb; int8_t *ttfa, *ttfb; t8_eclass_t eclass; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 786d1176f1..d0375e747e 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -118,7 +118,7 @@ add_t8_test( NAME t8_gtest_point_inside_serial SOURCES t8_g add_t8_test( NAME t8_gtest_vtk_reader_parallel SOURCES t8_gtest_main.cxx t8_IO/t8_gtest_vtk_reader.cxx ) add_t8_test( NAME t8_gtest_vtk_writer_parallel SOURCES t8_gtest_main.cxx t8_IO/t8_gtest_vtk_writer.cxx ) -add_t8_test( NAME t8_gtest_vtk_write_read SOURCES t8_gtest_main.cxx t8_IO/t8_gtest_vtk_write_read.cxx ) +add_t8_test( NAME t8_gtest_vtk_write_read SOURCES t8_gtest_main.cxx t8_IO/t8_gtest_vtk_write_read.cxx ) add_t8_test( NAME t8_gtest_nca_serial SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_nca.cxx ) add_t8_test( NAME t8_gtest_pyra_connectivity_serial SOURCES t8_gtest_main.cxx t8_schemes/t8_gtest_pyra_connectivity.cxx )