GCC Code Coverage Report


Directory: ./
File: lib/geogram/mesh/mesh_partition.cpp
Date: 2026-09-07 02:25:23
Exec Total Coverage
Lines: 25 76 32.9%
Functions: 3 6 50.0%
Branches: 7 86 8.1%

Line Branch Exec Source
1 /*
2 * Copyright (c) 2000-2022 Inria
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * * Neither the name of the ALICE Project-Team nor the names of its
14 * contributors may be used to endorse or promote products derived from this
15 * software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 *
29 * Contact: Bruno Levy
30 *
31 * https://www.inria.fr/fr/bruno-levy
32 *
33 * Inria,
34 * Domaine de Voluceau,
35 * 78150 Le Chesnay - Rocquencourt
36 * FRANCE
37 *
38 */
39
40 #include <geogram/mesh/mesh_partition.h>
41 #include <geogram/mesh/mesh.h>
42 #include <geogram/mesh/mesh_reorder.h>
43 #include <geogram/basic/permutation.h>
44 #include <stack>
45
46 namespace {
47
48 using namespace GEO;
49
50 /**
51 * \brief Partitions a surface using Hilbert ordering.
52 * \details Reorders the surface facets using Hilber order then
53 * extracts index slices of equal sizes.
54 * \param[in,out] M the mesh to be partitioned
55 * \param[out] facet_ptr the facet pointers of the parts.
56 * Facets indices of part \p p are: facet_ptr[p],...,facet_ptr[p+1].
57 * \param[in] nb_parts number of parts to generate
58 */
59 10 void partition_Hilbert_surface(
60 Mesh& M,
61 vector<index_t>& facet_ptr,
62 index_t nb_parts
63 ) {
64 10 mesh_reorder(M, MESH_ORDER_HILBERT);
65 10 index_t part_size = M.facets.nb() / nb_parts;
66 10 facet_ptr.resize(nb_parts + 1);
67 10 facet_ptr[0] = 0;
68
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 10 times.
40 for(index_t i = 1; i < nb_parts; i++) {
69 30 facet_ptr[i] = facet_ptr[i - 1] + part_size;
70 }
71 10 facet_ptr[nb_parts] = M.facets.nb();
72 10 }
73
74 /**
75 * \brief Partitions a surface and a volume using Hilbert ordering.
76 * \details Reorders the surface facets and tetrahedra
77 * using Hilber order then extracts index slices of equal sizes.
78 * \param[in,out] M the mesh to be partitioned
79 * \param[out] facet_ptr the facet pointers of the parts.
80 * Facets indices of part \p p are: facet_ptr[p],...,facet_ptr[p+1].
81 * \param[out] tet_ptr the tetrahedra pointers of the parts.
82 * Tets indices of part \p p are: tet_ptr[p],...,tet_ptr[p+1].
83 * \param[in] nb_parts number of parts to generate
84 */
85 10 void partition_Hilbert_surface_and_volume(
86 Mesh& M,
87 vector<index_t>& facet_ptr,
88 vector<index_t>& tet_ptr,
89 index_t nb_parts
90 ) {
91 10 partition_Hilbert_surface(M, facet_ptr, nb_parts);
92
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 6 times.
10 if(M.cells.nb() != 0) {
93 4 index_t part_size = M.cells.nb() / nb_parts;
94 4 tet_ptr.resize(nb_parts + 1);
95 4 tet_ptr[0] = 0;
96
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 4 times.
16 for(index_t i = 1; i < nb_parts; i++) {
97 12 tet_ptr[i] = tet_ptr[i - 1] + part_size;
98 }
99 4 tet_ptr[nb_parts] = M.cells.nb();
100 }
101 10 }
102
103 /**
104 * \brief Partitions a surface into its connected components.
105 * \param[in,out] M the mesh to be partitioned. Its facets are
106 * reorder in such a way that the facets that correspond to
107 * the same connected component have contiguous indices
108 * \param[out] facet_ptr the facet pointers of the parts.
109 * Facets indices of part \p p are: facet_ptr[p],...,facet_ptr[p+1].
110 */
111 void partition_surface_connected_components(
112 Mesh& M,
113 vector<index_t>& facet_ptr
114 ) {
115 static constexpr index_t UNVISITED = NO_INDEX;
116
117 vector<index_t> new_index(M.facets.nb(), UNVISITED);
118 std::stack<index_t> S;
119 index_t new_cur_index = 0;
120 for(index_t f: M.facets) {
121 if(new_index[f] == UNVISITED) {
122 facet_ptr.push_back(new_cur_index);
123 new_index[f] = new_cur_index;
124 new_cur_index++;
125 S.push(f);
126 }
127 while(!S.empty()) {
128 index_t ftop = S.top();
129 S.pop();
130 for(index_t c: M.facets.corners(ftop)) {
131 index_t g = M.facet_corners.adjacent_facet(c);
132 if(g != NO_FACET && new_index[g] == UNVISITED) {
133 new_index[g] = new_cur_index;
134 new_cur_index++;
135 S.push(index_t(g));
136 }
137 }
138 }
139 }
140 geo_assert(new_cur_index == M.facets.nb());
141 facet_ptr.push_back(new_cur_index);
142 Permutation::invert(new_index);
143 M.facets.permute_elements(new_index);
144 }
145
146 /**
147 * \brief Partitions a volume into its connected components.
148 * \param[in,out] M the mesh to be partitioned. Its tets are
149 * reorder in such a way that the tets that correspond to
150 * the same connected component have contiguous indices
151 * \param[out] tet_ptr the tetrahedra pointers of the parts.
152 * Tets indices of part \p p are: tet_ptr[p],...,tet_ptr[p+1].
153 */
154 void partition_volume_connected_components(
155 Mesh& M,
156 vector<index_t>& tet_ptr
157 ) {
158 static constexpr index_t UNVISITED = NO_INDEX;
159
160 vector<index_t> new_index(M.cells.nb(), UNVISITED);
161 std::stack<index_t> S;
162 index_t new_cur_index = 0;
163 for(index_t t: M.cells) {
164 if(new_index[t] == UNVISITED) {
165 tet_ptr.push_back(new_cur_index);
166 new_index[t] = new_cur_index;
167 new_cur_index++;
168 S.push(t);
169 }
170 while(!S.empty()) {
171 index_t t1 = S.top();
172 S.pop();
173 for(index_t lf = 0; lf < 4; lf++) {
174 index_t t2 = M.cells.adjacent(t1, lf);
175 if(t2 != NO_CELL && new_index[t2] == UNVISITED) {
176 new_index[t2] = new_cur_index;
177 new_cur_index++;
178 S.push(index_t(t2));
179 }
180 }
181 }
182 }
183 geo_assert(new_cur_index == M.cells.nb());
184 tet_ptr.push_back(new_cur_index);
185 Permutation::invert(new_index);
186 M.cells.permute_elements(new_index);
187 }
188 }
189
190 /****************************************************************************/
191
192 namespace GEO {
193
194 void mesh_partition(
195 Mesh& M,
196 MeshPartitionMode mode,
197 vector<index_t>& facet_ptr,
198 index_t nb_parts
199 ) {
200 switch(mode) {
201 case MESH_PARTITION_HILBERT:
202 partition_Hilbert_surface(M, facet_ptr, nb_parts);
203 break;
204 case MESH_PARTITION_CONNECTED_COMPONENTS:
205 partition_surface_connected_components(M, facet_ptr);
206 break;
207 }
208 }
209
210 10 void mesh_partition(
211 Mesh& M,
212 MeshPartitionMode mode,
213 vector<index_t>& facet_ptr,
214 vector<index_t>& tet_ptr,
215 index_t nb_parts
216 ) {
217
1/3
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
10 switch(mode) {
218 10 case MESH_PARTITION_HILBERT:
219 10 partition_Hilbert_surface_and_volume(
220 M, facet_ptr, tet_ptr, nb_parts
221 );
222 10 break;
223 case MESH_PARTITION_CONNECTED_COMPONENTS:
224 partition_surface_connected_components(M, facet_ptr);
225 if(M.cells.nb() != 0) {
226 partition_volume_connected_components(M, tet_ptr);
227 }
228 break;
229 }
230 10 }
231 }
232