libMesh
mesh_tetgen_wrapper.C
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2024 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3 
4 // This library is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU Lesser General Public
6 // License as published by the Free Software Foundation; either
7 // version 2.1 of the License, or (at your option) any later version.
8 
9 // This library is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // Lesser General Public License for more details.
13 
14 // You should have received a copy of the GNU Lesser General Public
15 // License along with this library; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 
18 #include "libmesh/libmesh_config.h"
19 #ifdef LIBMESH_HAVE_TETGEN
20 
21 // Local includes
22 #include "libmesh/libmesh_common.h"
23 #include "libmesh/mesh_tetgen_wrapper.h"
24 
25 // C++ includes
26 #include <iostream>
27 #include <memory>
28 
29 namespace libMesh
30 {
31 
33  tetgen_output(std::make_unique<tetgenio>())
34 {
35  this->tetgen_data.mesh_dim = 3;
36  this->tetgen_data.numberofpointattributes = 0;
37  this->tetgen_data.firstnumber = 0;
38 }
39 
40 
41 
43 
44 
45 
46 void TetGenWrapper::set_node(unsigned i, REAL x, REAL y, REAL z)
47 {
48  unsigned index = i*3;
49  tetgen_data.pointlist[index++] = x;
50  tetgen_data.pointlist[index++] = y;
51  tetgen_data.pointlist[index++] = z;
52 }
53 
54 
55 
56 void TetGenWrapper::set_hole(unsigned i, REAL x, REAL y, REAL z)
57 {
58  unsigned index = i*3;
59  tetgen_data.holelist[index++] = x;
60  tetgen_data.holelist[index++] = y;
61  tetgen_data.holelist[index++] = z;
62 }
63 
64 
65 
67 {
68  // This is an int in tetgen, so use an int here even though it should be unsigned
69  tetgen_data.numberofpoints = i;
70 }
71 
72 
73 
74 void TetGenWrapper::get_output_node(unsigned i, REAL & x, REAL & y, REAL & z)
75 {
76  // Bounds checking...
77  libmesh_error_msg_if(i >= static_cast<unsigned>(tetgen_output->numberofpoints),
78  "Error, requested point "
79  << i
80  << ", but there are only "
81  << tetgen_output->numberofpoints
82  << " points available.");
83 
84  x = tetgen_output->pointlist[3*i];
85  y = tetgen_output->pointlist[3*i+1];
86  z = tetgen_output->pointlist[3*i+2];
87 }
88 
89 
90 
92 {
93  return tetgen_output->numberoftetrahedra;
94 }
95 
96 
97 
99 {
100  return tetgen_output->numberoftrifaces;
101 }
102 
103 
104 
106 {
107  return tetgen_output->numberofpoints;
108 }
109 
110 
111 
112 int TetGenWrapper::get_element_node(unsigned i, unsigned j)
113 {
114  return tetgen_output->tetrahedronlist[i*4+j];
115 }
116 
117 
118 
119 int TetGenWrapper::get_triface_node(unsigned i, unsigned j)
120 {
121  return tetgen_output->trifacelist[i*3+j];
122 }
123 
124 
125 
127 {
128  libmesh_assert(tetgen_output->numberoftetrahedronattributes>0);
129  return tetgen_output->tetrahedronattributelist[tetgen_output->numberoftetrahedronattributes*i];
130 }
131 
132 
133 
135 {
136  // This is stored as an int in tetgen, so we store it that way as well.
137  this->set_numberofpoints(numofpoints);
138 
139  // Don't try to allocate an array of size zero, this is not portable...
140  if (this->tetgen_data.numberofpoints > 0)
141  {
142  // Is there previously-allocated memory here?
143  libmesh_error_msg_if(this->tetgen_data.pointlist != nullptr,
144  "Cannot allocate on top of previously allocated memory!");
145 
146  // We allocate memory here, the tetgenio destructor will delete it.
147  this->tetgen_data.pointlist = new REAL[this->tetgen_data.numberofpoints * 3];
148  }
149 }
150 
151 
152 
153 void TetGenWrapper::set_switches(std::string_view s)
154 {
155  // A temporary buffer for passing to the C API, it requires
156  // a char *, not a const char *...
157  char buffer[256];
158 
159  // Make sure char buffer has enough room
160  libmesh_error_msg_if(s.size() >= sizeof(buffer)-1,
161  "Fixed size buffer of length "
162  << sizeof(buffer)
163  << " not large enough to hold TetGen switches.");
164 
165  // Copy the string, don't forget to terminate!
166  buffer[ s.copy( buffer , sizeof( buffer ) - 1 ) ] = '\0' ;
167 
168  if (!tetgen_be.parse_commandline(buffer))
169  libMesh::out << "TetGen replies: Wrong switches!" << std::endl;
170 }
171 
172 
173 
175 {
176  // Call tetrahedralize from the TetGen library.
177  tetrahedralize(&tetgen_be, &tetgen_data, tetgen_output.get());
178 }
179 
180 
181 
183 {
184  // This is stored as an int in TetGen
185  this->tetgen_data.numberoffacets = i;
186 }
187 
188 
189 
191 {
192  // This is stored as an int in TetGen
193  this->tetgen_data.numberofholes = i;
194 }
195 
196 
197 
199 {
200  // This is stored as an int in TetGen
201  this->tetgen_data.numberofregions = i;
202 }
203 
204 
205 
206 void TetGenWrapper::allocate_facetlist(int numoffacets, int numofholes)
207 {
208  // These are both stored as ints in TetGen
209  this->set_numberoffacets(numoffacets);
210  this->set_numberofholes(numofholes);
211 
212  // Don't try to allocate an array of size zero, this is not portable...
213  if (this->tetgen_data.numberoffacets > 0)
214  {
215  // Is there previously-allocated memory here?
216  libmesh_error_msg_if(this->tetgen_data.facetlist != nullptr,
217  "Cannot allocate on top of previously allocated memory!");
218 
219  // We allocate memory here, the tetgenio destructor cleans it up.
220  this->tetgen_data.facetlist = new tetgenio::facet[this->tetgen_data.numberoffacets];
221 
222  for (int i=0; i<numoffacets; i++)
223  this->tetgen_data.init(&(this->tetgen_data.facetlist[i]));
224  }
225 
226 
227  // Don't try to allocate an array of size zero, this is not portable...
228  if (this->tetgen_data.numberofholes > 0)
229  {
230  // Is there previously-allocated memory here?
231  libmesh_error_msg_if(this->tetgen_data.holelist != nullptr,
232  "Cannot allocate on top of previously allocated memory!");
233 
234  this->tetgen_data.holelist = new REAL[this->tetgen_data.numberofholes * 3];
235  }
236 }
237 
238 
239 
241 {
242  this->set_numberofregions(numofregions);
243 
244  // Don't try to allocate an array of size zero, this is not portable...
245  if (this->tetgen_data.numberofregions > 0)
246  {
247  // Is there previously-allocated memory here?
248  libmesh_error_msg_if(this->tetgen_data.regionlist != nullptr,
249  "Cannot allocate on top of previously allocated memory!");
250 
251  // We allocate memory here, the tetgenio destructor cleans it up.
252  this->tetgen_data.regionlist = new REAL[this->tetgen_data.numberofregions * 5];
253  }
254 }
255 
256 
257 
259 {
260  // numberofpolygons is stored as an int in TetGen
261  this->tetgen_data.facetlist[i].numberofpolygons = num;
262 }
263 
264 
265 
266 void TetGenWrapper::set_facet_numberofholes(unsigned i, int num)
267 {
268  // numberofholes is stored as an int in TetGen
269  this->tetgen_data.facetlist[i].numberofholes = num;
270 }
271 
272 
273 
274 
275 void TetGenWrapper::allocate_facet_polygonlist(unsigned i, int numofpolygons)
276 {
277  this->set_facet_numberofpolygons(i, numofpolygons);
278  this->set_facet_numberofholes(i, 0);
279 
280  // Don't try to create an array of size zero, this isn't portable
281  if (numofpolygons > 0)
282  {
283  // Is there previously-allocated memory here?
284  libmesh_error_msg_if(this->tetgen_data.facetlist[i].polygonlist != nullptr,
285  "Cannot allocate on top of previously allocated memory!");
286 
287  // We allocate memory here, the tetgenio destructor cleans it up.
288  this->tetgen_data.facetlist[i].polygonlist = new tetgenio::polygon[numofpolygons];
289 
290  for (int j=0; j<this->tetgen_data.facetlist[i].numberofpolygons; j++)
291  this->tetgen_data.init(&(this->tetgen_data.facetlist[i].polygonlist[j]));
292  }
293 }
294 
295 
296 
297 void TetGenWrapper::set_polygon_numberofvertices(unsigned i, unsigned j, int num)
298 {
299  // numberofvertices is stored as an int in TetGen
300  this->tetgen_data.facetlist[i].polygonlist[j].numberofvertices = num;
301 }
302 
303 
304 
305 void TetGenWrapper::allocate_polygon_vertexlist(unsigned i, unsigned j, int numofvertices)
306 {
307  this->set_polygon_numberofvertices(i, j, numofvertices);
308 
309  // Don't try to create an array of size zero, this isn't portable
310  if (numofvertices > 0)
311  {
312  // Is there previously-allocated memory here?
313  libmesh_error_msg_if(this->tetgen_data.facetlist[i].polygonlist[j].vertexlist != nullptr,
314  "Cannot allocate on top of previously allocated memory!");
315 
316  // We allocate memory here, the tetgenio destructor cleans it up.
317  this->tetgen_data.facetlist[i].polygonlist[j].vertexlist = new int[numofvertices];
318  }
319 }
320 
321 
322 
323 
324 void TetGenWrapper::set_vertex(unsigned i, unsigned j, unsigned k, int nodeindex)
325 {
326  // vertexlist entries are stored as ints in TetGen
327  this->tetgen_data.facetlist[i].polygonlist[j].vertexlist[k] = nodeindex;
328 }
329 
330 
331 
332 void TetGenWrapper::set_region(unsigned i, REAL x, REAL y, REAL z,
333  REAL attribute, REAL vol_constraint)
334 {
335  unsigned index = i*5;
336  tetgen_data.regionlist[index++] = x;
337  tetgen_data.regionlist[index++] = y;
338  tetgen_data.regionlist[index++] = z;
339  tetgen_data.regionlist[index++] = attribute;
340  tetgen_data.regionlist[index++] = vol_constraint;
341 }
342 
343 } // namespace libMesh
344 
345 
346 #endif // LIBMESH_HAVE_TETGEN
void set_polygon_numberofvertices(unsigned i, unsigned j, int num)
Sets the number of vertices for polygon j, facet i in the TetGen input.
void set_numberofregions(int i)
Sets the number of regions in the TetGen input.
void set_numberofpoints(int i)
Sets the number of nodes in the TetGen input.
REAL get_element_attribute(unsigned i)
void set_facet_numberofpolygons(unsigned i, int num)
Sets the number of polygons for facet i in the TetGen input.
int get_element_node(unsigned i, unsigned j)
void get_output_node(unsigned i, REAL &x, REAL &y, REAL &z)
int get_triface_node(unsigned i, unsigned j)
void set_facet_numberofholes(unsigned i, int num)
Sets the number of holes for facet i in the TetGen input.
void set_numberoffacets(int i)
Sets the number of facets in the TetGen input.
void set_vertex(unsigned i, unsigned j, unsigned k, int nodeindex)
Sets index of ith facet, jth polygon, kth vertex in the TetGen input.
The libMesh namespace provides an interface to certain functionality in the library.
void allocate_polygon_vertexlist(unsigned i, unsigned j, int numofvertices)
Allocates memory, sets number of vertices for polygon j, facet i in the TetGen input.
void allocate_pointlist(int numofpoints)
Allocates memory, sets number of nodes in the TetGen input.
void set_node(unsigned i, REAL x, REAL y, REAL z)
Sets coordinates of point i in the TetGen input.
tetgenio tetgen_data
TetGen input structure.
libmesh_assert(ctx)
void run_tetgen()
Starts the triangulation.
std::unique_ptr< tetgenio > tetgen_output
TetGen output structure.
~TetGenWrapper()
Destructor.
void allocate_facet_polygonlist(unsigned i, int numofpolygons)
Allocates memory, sets number of polygons for facet i in the TetGen input.
void set_switches(std::string_view s)
Method to set TetGen commandline switches -p Tetrahedralizes a piecewise linear complex (...
void set_hole(unsigned i, REAL x, REAL y, REAL z)
Sets coordinates of hole i in the TetGen input.
void set_numberofholes(int i)
Sets the number of holes in the TetGen input.
void allocate_regionlist(int numofregions)
Allocates memory, sets number of regions in the TetGen input.
OStreamProxy out
tetgenbehavior tetgen_be
TetGen control class (from the TetGen library).
void set_region(unsigned i, REAL x, REAL y, REAL z, REAL attribute, REAL vol_constraint)
Sets coordinates, attribute, and volume constraint for region i in the TetGen input.
void allocate_facetlist(int numoffacets, int numofholes)
Allocates memory, sets number of facets, holes in the TetGen input.