Skip to content

Commit ec16899

Browse files
Merge pull request #960 from DLR-AMR/feature-cmesh_vertex_connectivity
Feature cmesh vertex connectivity
2 parents d9ed159 + c23baa6 commit ec16899

17 files changed

Lines changed: 2190 additions & 4 deletions

src/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,9 @@ target_sources( T8 PRIVATE
133133
t8_cmesh/t8_cmesh_examples.cxx
134134
t8_cmesh/t8_cmesh_helpers.cxx
135135
t8_cmesh/t8_cmesh_offset.c
136+
t8_cmesh/t8_cmesh_vertex_connectivity/t8_cmesh_vertex_conn_tree_to_vertex.cxx
137+
t8_cmesh/t8_cmesh_vertex_connectivity/t8_cmesh_vertex_conn_vertex_to_tree.cxx
138+
t8_cmesh/t8_cmesh_vertex_connectivity/t8_cmesh_vertex_connectivity.cxx
136139
t8_cmesh/t8_cmesh_readmshfile.cxx
137140
t8_data/t8_shmem.c
138141
t8_data/t8_containers.cxx

src/Makefile.am

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,9 @@ libt8_internal_headers = \
9898
src/t8_cmesh/t8_cmesh_trees.h src/t8_cmesh/t8_cmesh_partition.h \
9999
src/t8_cmesh/t8_cmesh_copy.h \
100100
src/t8_cmesh/t8_cmesh_offset.h \
101+
src/t8_cmesh/t8_cmesh_vertex_connectivity.hxx \
102+
src/t8_cmesh/t8_cmesh_vertex_conn_tree_to_vertex.hxx \
103+
src/t8_cmesh/t8_cmesh_vertex_conn_vertex_to_tree.hxx \
101104
src/t8_vtk/t8_vtk_polydata.hxx \
102105
src/t8_vtk/t8_vtk_unstructured.hxx \
103106
src/t8_vtk/t8_vtk_parallel.hxx \
@@ -119,7 +122,10 @@ libt8_compiled_sources = \
119122
src/t8_cmesh/t8_cmesh_save.cxx \
120123
src/t8_cmesh/t8_cmesh_netcdf.c \
121124
src/t8_cmesh/t8_cmesh_trees.cxx src/t8_cmesh/t8_cmesh_commit.cxx \
122-
src/t8_cmesh/t8_cmesh_partition.cxx\
125+
src/t8_cmesh/t8_cmesh_vertex_conn_tree_to_vertex.cxx \
126+
src/t8_cmesh/t8_cmesh_vertex_conn_vertex_to_tree.cxx \
127+
src/t8_cmesh/t8_cmesh_vertex_connectivity.cxx \
128+
src/t8_cmesh/t8_cmesh_partition.cxx \
123129
src/t8_cmesh/t8_cmesh_copy.c src/t8_data/t8_shmem.c \
124130
src/t8_cmesh/t8_cmesh_geometry.cxx \
125131
src/t8_cmesh/t8_cmesh_examples.cxx \

src/t8_cmesh/t8_cmesh.cxx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include <t8_cmesh.h>
2525
#include <t8_cmesh/t8_cmesh_geometry.h>
2626
#include <t8_geometry/t8_geometry_handler.hxx>
27+
#include <t8_cmesh/t8_cmesh_vertex_connectivity/t8_cmesh_vertex_connectivity.hxx>
2728
#include <t8_geometry/t8_geometry_implementations/t8_geometry_linear.h>
2829
#include <t8_geometry/t8_geometry_implementations/t8_geometry_linear_axis_aligned.h>
2930
#include <t8_schemes/t8_scheme.hxx>
@@ -204,6 +205,7 @@ t8_cmesh_init (t8_cmesh_t *pcmesh)
204205
* It will get initialized either when a geometry is registered
205206
* or when the cmesh gets committed. */
206207
cmesh->geometry_handler = NULL;
208+
cmesh->vertex_connectivity = new t8_cmesh_vertex_connectivity ();
207209

208210
T8_ASSERT (t8_cmesh_is_initialized (cmesh));
209211
}

src/t8_cmesh/t8_cmesh_commit.cxx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include <t8_cmesh/t8_cmesh_copy.h>
3737
#include <t8_cmesh/t8_cmesh_geometry.h>
3838
#include <t8_geometry/t8_geometry_handler.hxx>
39+
#include <t8_cmesh/t8_cmesh_vertex_connectivity/t8_cmesh_vertex_connectivity.hxx>
3940

4041
typedef struct ghost_facejoins_struct
4142
{
@@ -582,6 +583,15 @@ t8_cmesh_commit (t8_cmesh_t cmesh, sc_MPI_Comm comm)
582583
}
583584
T8_ASSERT (cmesh->set_partition || cmesh->tree_offsets == NULL);
584585

586+
/* Build vertex_to_tree instance from the cmesh and a tree_to_vertex instance,
587+
* but only if the vertex_to_tree instance is not yet committed
588+
* and if the tree_to_vertex instance is not empty.
589+
*/
590+
if (cmesh->vertex_connectivity->get_vertex_to_tree_state () == 0
591+
&& cmesh->vertex_connectivity->get_tree_to_vertex_state () == 1) {
592+
cmesh->vertex_connectivity->build_vertex_to_tree (cmesh);
593+
}
594+
585595
#if T8_ENABLE_DEBUG
586596
t8_debugf ("Cmesh is %spartitioned.\n", cmesh->set_partition ? "" : "not ");
587597
if (cmesh->set_partition) {

src/t8_cmesh/t8_cmesh_types.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include <t8_refcount.h>
2828
#include <t8_data/t8_shmem.h>
2929
#include <t8_geometry/t8_geometry.h>
30+
#include <t8_cmesh/t8_cmesh_vertex_connectivity/t8_cmesh_vertex_connectivity.h>
3031
#include "t8_cmesh_stash.h"
3132
#include "t8_element.h"
3233

@@ -51,9 +52,10 @@ typedef struct t8_cprofile t8_cprofile_t; /* Defined below */
5152
/* Definitions for attribute identifiers that are reserved for a special purpose.
5253
* T8_CMESH_NEXT_POSSIBLE_KEY is the first unused key, hence it can be repurposed for different attributes.*/
5354
#define T8_CMESH_VERTICES_ATTRIBUTE_KEY 0 /* Used to store vertex coordinates. */
54-
#define T8_CMESH_GEOMETRY_ATTRIBUTE_KEY 1 /* Used to store the name of a tree's geometry. */
55-
#define T8_CMESH_CAD_EDGE_ATTRIBUTE_KEY 2 /* Used to store which edge is linked to which geometry */
56-
#define T8_CMESH_CAD_EDGE_PARAMETERS_ATTRIBUTE_KEY 3 /* Used to store edge parameters */
55+
#define T8_CMESH_GLOBAL_VERTICES_ATTRIBUTE_KEY 1 /* Used to store global vertex ids. */
56+
#define T8_CMESH_GEOMETRY_ATTRIBUTE_KEY 2 /* Used to store the name of a tree's geometry. */
57+
#define T8_CMESH_CAD_EDGE_ATTRIBUTE_KEY 3 /* Used to store which edge is linked to which geometry */
58+
#define T8_CMESH_CAD_EDGE_PARAMETERS_ATTRIBUTE_KEY 4 /* Used to store edge parameters */
5759
#define T8_CMESH_CAD_FACE_ATTRIBUTE_KEY \
5860
T8_CMESH_CAD_EDGE_PARAMETERS_ATTRIBUTE_KEY \
5961
+T8_ECLASS_MAX_EDGES /* Used to store which face is linked to which surface */
@@ -137,6 +139,9 @@ typedef struct t8_cmesh
137139

138140
t8_geometry_handler_c *geometry_handler; /**< Handles all geometries that are used by trees in this cmesh. */
139141

142+
struct t8_cmesh_vertex_connectivity
143+
*vertex_connectivity; /**< Structure that manages tree_to_vertex and vertex_to_tree connectivity. */
144+
140145
#if T8_ENABLE_DEBUG
141146
t8_locidx_t inserted_trees; /**< Count the number of inserted trees to
142147
check at commit if it equals the total number. */
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/*
2+
This file is part of t8code.
3+
t8code is a C library to manage a collection (a forest) of multiple
4+
connected adaptive space-trees of general element classes in parallel.
5+
6+
Copyright (C) 2025 the developers
7+
8+
t8code is free software; you can redistribute it and/or modify
9+
it under the terms of the GNU General Public License as published by
10+
the Free Software Foundation; either version 2 of the License, or
11+
(at your option) any later version.
12+
13+
t8code is distributed in the hope that it will be useful,
14+
but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16+
GNU General Public License for more details.
17+
18+
You should have received a copy of the GNU General Public License
19+
along with t8code; if not, write to the Free Software Foundation, Inc.,
20+
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21+
*/
22+
23+
/** \file t8_cmesh_conn_tree_to_vertex.cxx
24+
* This file implements the routines for the t8_cmesh_conn_tree_to_vertex struct.
25+
*/
26+
27+
#include <t8_cmesh.h>
28+
#include <t8_cmesh/t8_cmesh_types.h>
29+
#include <t8_cmesh/t8_cmesh_vertex_connectivity/t8_cmesh_vertex_conn_tree_to_vertex.hxx>
30+
31+
/* constructor from a given vertex to tree list. */
32+
t8_cmesh_vertex_conn_tree_to_vertex::t8_cmesh_vertex_conn_tree_to_vertex (
33+
const t8_cmesh_t cmesh_from, const t8_cmesh_t cmesh, const t8_cmesh_vertex_conn_vertex_to_tree &vtt)
34+
: t8_cmesh_vertex_conn_tree_to_vertex ()
35+
{
36+
T8_ASSERT (t8_cmesh_is_committed (cmesh_from));
37+
T8_ASSERT (t8_cmesh_is_initialized (cmesh));
38+
T8_ASSERT (vtt.is_committed ());
39+
40+
/* Since we need to collect all global ids of a tree before we can add the tree,
41+
* we need a temporary buffer structure.
42+
* Note that this is very memory intensive, doubling the required memory. */
43+
44+
const t8_locidx_t num_local_trees = t8_cmesh_get_num_local_trees (cmesh_from);
45+
const t8_locidx_t num_ghosts = t8_cmesh_get_num_ghosts (cmesh_from);
46+
const t8_locidx_t num_local_trees_and_ghosts = num_local_trees + num_ghosts;
47+
48+
/* Stores an array of local indices and mapped global vertices for each tree.
49+
* We need to store the local indices as well, since they will not be
50+
* sorted. Hence we need to sort later. */
51+
using global_local_index_pair = std::pair<t8_gloidx_t, t8_locidx_t>;
52+
std::vector<std::vector<global_local_index_pair>> global_ids_per_tree (num_local_trees_and_ghosts);
53+
54+
/* Iterate over all entries of the vertex to tree list. */
55+
for (auto &[global_vertex, vertex_list] : vtt) {
56+
/* Iterate over all entries of the vertex list,
57+
* thus, each entry is a local tree id and vertex index. */
58+
for (auto &[tree_index, vertex_index] : vertex_list) {
59+
global_local_index_pair new_pair (global_vertex, vertex_index);
60+
global_ids_per_tree[tree_index].push_back (new_pair);
61+
}
62+
}
63+
/* Now sort the list and add the global indices of each tree. */
64+
for (t8_locidx_t itree = 0; itree < num_local_trees_and_ghosts; ++itree) {
65+
auto &tree_indices = global_ids_per_tree[itree];
66+
/* Sort according to local index. */
67+
std::sort (tree_indices.begin (), tree_indices.end (),
68+
[] (global_local_index_pair &a, global_local_index_pair &b) { return a.second < b.second; });
69+
70+
/* Compute number of vertices of this tree. */
71+
/* Get the trees class depending on whether it is a local tree or ghost. */
72+
const t8_eclass_t tree_class = itree < num_local_trees
73+
? t8_cmesh_get_tree_class (cmesh_from, itree)
74+
: t8_cmesh_get_ghost_class (cmesh_from, itree - num_local_trees);
75+
76+
const int num_tree_vertices = t8_eclass_num_vertices[tree_class];
77+
78+
/* Size of list must match number of tree vertices. */
79+
SC_CHECK_ABORTF (
80+
tree_indices.size () == (size_t) num_tree_vertices,
81+
"ERROR. Number of mapped local tree vertices for tree %i does not equal number of tree vertices. %zu != %i\n",
82+
itree, tree_indices.size (), num_tree_vertices);
83+
/* We now build the array of global indices of this tree, sorted
84+
* by the trees local indices. */
85+
t8_gloidx_t *global_tree_indices = T8_ALLOC (t8_gloidx_t, num_tree_vertices);
86+
for (int ivertex = 0; ivertex < num_tree_vertices; ++ivertex) {
87+
global_tree_indices[ivertex] = tree_indices[ivertex].first;
88+
}
89+
const t8_gloidx_t global_tree_id = t8_cmesh_get_global_id (cmesh_from, itree);
90+
set_global_vertex_ids_of_tree_vertices (cmesh, global_tree_id, global_tree_indices, num_tree_vertices);
91+
T8_FREE (global_tree_indices);
92+
}
93+
}
Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
/*
2+
This file is part of t8code.
3+
t8code is a C library to manage a collection (a forest) of multiple
4+
connected adaptive space-trees of general element classes in parallel.
5+
6+
Copyright (C) 2025 the developers
7+
8+
t8code is free software; you can redistribute it and/or modify
9+
it under the terms of the GNU General Public License as published by
10+
the Free Software Foundation; either version 2 of the License, or
11+
(at your option) any later version.
12+
13+
t8code is distributed in the hope that it will be useful,
14+
but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16+
GNU General Public License for more details.
17+
18+
You should have received a copy of the GNU General Public License
19+
along with t8code; if not, write to the Free Software Foundation, Inc.,
20+
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21+
*/
22+
23+
/** \file t8_cmesh_vertex_conn_tree_to_vertex.hxx
24+
* Class to save data structure for tree_to_vertex_lists of the cmesh.
25+
* When the cmesh stores global vertex numbers, we require a lookup that
26+
* matches a tree and its local vertex to a global vertex id.
27+
* This lookup is encoded in the t8_cmesh_vertex_conn_tree_to_vertex struct.
28+
*/
29+
30+
/* TODO:
31+
* It is probably best to set all global ids of a single tree as one attribute.
32+
* That way we can store it as a single arrays of id's.
33+
* We will probably most often want to access all ids of one tree, so a function returning an array of ids
34+
* is a good idea anyway and if we already store them as such then we do not need to do any data movement
35+
* when accessing.
36+
*
37+
* On the downside we will only have a "set all ids of a tree" function and no "set this single id for this tree and this vertex" function.
38+
*/
39+
40+
#ifndef T8_CMESH_VERTEX_CONN_TREE_TO_VERTEX_HXX
41+
#define T8_CMESH_VERTEX_CONN_TREE_TO_VERTEX_HXX
42+
43+
#include <algorithm>
44+
#include <t8_cmesh.h>
45+
#include <t8_cmesh/t8_cmesh_types.h>
46+
#include <t8_cmesh/t8_cmesh_vertex_connectivity/t8_cmesh_vertex_conn_vertex_to_tree.hxx>
47+
48+
/* forward declaration of ttv class needed since the two class headers include each other. */
49+
class t8_cmesh_vertex_conn_vertex_to_tree;
50+
51+
class t8_cmesh_vertex_conn_tree_to_vertex {
52+
public:
53+
/** Standard constructor. Does nothing. */
54+
t8_cmesh_vertex_conn_tree_to_vertex (): state (EMPTY)
55+
{
56+
}
57+
58+
/** Constructor from a cmesh where all the attributes are set.
59+
* Currently unclear if we implement this eventually.
60+
* If we do so: Should the cmesh be already committed, or in pre-commit state but attributes set?
61+
*
62+
* \note This function is not implemented yet.
63+
*/
64+
t8_cmesh_vertex_conn_tree_to_vertex ([[maybe_unused]] const t8_cmesh_t cmesh)
65+
{
66+
// TODO: Remove the [[maybe unused]] qualifier when implemented
67+
SC_ABORT ("not implemented.");
68+
}
69+
70+
/** Constructor from a cmesh and a given vertex to tree connectivity.
71+
*
72+
* \param [in] cmesh_from A committed cmesh.
73+
* \param [in] cmesh An initialized but not committed cmesh that is to be derived from \a cmesh_from.
74+
* \param [in] vtt A committed vertex to tree connectivity for \a cmesh_from.
75+
*
76+
* As a result a tree to vertec connectivity for \a cmesh will be constructed.
77+
* \note \a cmesh_from must be committed.
78+
* \note \a cmesh must not be committed.
79+
* \note \a vtt must be committed.
80+
* \note This does not work until issue #923 https://github.com/DLR-AMR/t8code/issues/923 is resolved.
81+
*/
82+
t8_cmesh_vertex_conn_tree_to_vertex (const t8_cmesh_t cmesh_from, const t8_cmesh_t cmesh,
83+
const struct t8_cmesh_vertex_conn_vertex_to_tree &vtt);
84+
85+
/* Setter functions */
86+
/** Set all global vertex ids of a local tree.
87+
* \param [in] cmesh The considered cmesh
88+
* \param [in] local_tree A local tree id of \a cmesh
89+
* \param [in] global_vertex_id The ids of the global vertices in order of \a local_tree's vertices.
90+
* \param [in] num_vertices Must match the number of vertices of \a local_tree
91+
*
92+
* \note \a cmesh must not be committed.
93+
*/
94+
inline void
95+
set_global_vertex_ids_of_tree_vertices (const t8_cmesh_t cmesh, const t8_gloidx_t global_tree,
96+
const t8_gloidx_t *global_tree_vertices, const int num_vertices)
97+
{
98+
T8_ASSERT (t8_cmesh_is_initialized (cmesh));
99+
T8_ASSERT (num_vertices >= 0);
100+
T8_ASSERT (global_tree_vertices != NULL);
101+
102+
/* TODO: we currently do not check whether the num_vertices argument
103+
* matches the number of vertices of the tree.
104+
* We cannot do it here, since this function call happens before commit,
105+
* thus we might not even know the eclass of the tree.
106+
* Maybe it is possible to check this during t8_cmesh_add_attributes?
107+
*/
108+
109+
/* We copy the data directly, hence set data_persiss to 0 */
110+
const int data_persists = 0;
111+
t8_debugf ("Setting %i global vertices for global tree %li.\n", num_vertices, global_tree);
112+
t8_cmesh_set_attribute_gloidx_array (cmesh, global_tree, t8_get_package_id (),
113+
T8_CMESH_GLOBAL_VERTICES_ATTRIBUTE_KEY, global_tree_vertices, num_vertices,
114+
data_persists);
115+
state = FILLED;
116+
}
117+
118+
/* TODO: What if the attribute is not set? error handling */
119+
/** Return the global vertex indices of a local tree.
120+
* \param [in] cmesh A committed cmesh.
121+
* \param [in] local_tree A local tree in \a cmesh.
122+
* \param [in] num_vertices The count of local vertices of \a local_tree
123+
* \return An array of length \a num_vertices containing the global vertex ids of \a local_tree's vertices.
124+
*/
125+
inline const t8_gloidx_t *
126+
get_global_vertices (const t8_cmesh_t cmesh, const t8_locidx_t local_tree, const int num_vertices) const
127+
{
128+
T8_ASSERT (t8_cmesh_is_committed (cmesh));
129+
130+
#if T8_ENABLE_DEBUG
131+
/* Verify that num_vertices matches the number of tree vertices */
132+
const t8_eclass_t tree_class = t8_cmesh_get_tree_class (cmesh, local_tree);
133+
const int num_tree_vertices = t8_eclass_num_vertices[tree_class];
134+
135+
T8_ASSERT (num_vertices == num_tree_vertices);
136+
#endif
137+
138+
t8_debugf ("Getting %i global vertices for local tree %i.\n", num_vertices, local_tree);
139+
const t8_gloidx_t *global_vertices = t8_cmesh_get_attribute_gloidx_array (
140+
cmesh, t8_get_package_id (), T8_CMESH_GLOBAL_VERTICES_ATTRIBUTE_KEY, local_tree, num_vertices);
141+
T8_ASSERT (global_vertices != NULL);
142+
return global_vertices;
143+
}
144+
145+
/* TODO: What if the attribute is not set? error handling */
146+
/** Return a single global vertex id of a single local vertex.
147+
*
148+
*
149+
* \param [in] cmesh A committed cmesh.
150+
* \param [in] local_tree A local tree of \a cmesh.
151+
* \param [in] local_tree_vertex A local vertex of \a local_tree
152+
* \param [in] num_tree_vertices The count of vertices of \a local_tree
153+
* \return The global id of the local vertex \a local_tree_vertex of \a local_tree.
154+
*/
155+
t8_gloidx_t
156+
get_global_vertex (const t8_cmesh_t cmesh, const t8_locidx_t local_tree, const int local_tree_vertex,
157+
const int num_tree_vertices) const
158+
{
159+
T8_ASSERT (t8_cmesh_is_committed (cmesh));
160+
161+
/* Verify that local_tree_vertex is in fact a local vertex of the tree */
162+
/* Note: We only perform this check in debugging mode.
163+
* In non-debugging mode, using a vertex index beyond the trees index allows
164+
* for a potential attacker to gain access to memory possibly not owned by the caller.
165+
* We do not check in non-debugging mode for (obvious) performance reasons. */
166+
T8_ASSERT (0 <= local_tree_vertex);
167+
T8_ASSERT (local_tree_vertex < num_tree_vertices);
168+
169+
return get_global_vertices (cmesh, local_tree, num_tree_vertices)[local_tree_vertex];
170+
}
171+
172+
friend struct t8_cmesh_vertex_connectivity;
173+
174+
private:
175+
enum state {
176+
EMPTY, /*< Is initialized but empty. */
177+
FILLED /*< Is filled with at least one entry. */
178+
} state;
179+
180+
/** Return the state of this object. */
181+
inline enum state
182+
get_state ()
183+
{
184+
return state;
185+
}
186+
};
187+
188+
#endif /* !T8_CMESH_VERTEX_CONN_TREE_TO_VERTEX_HXX */

0 commit comments

Comments
 (0)