libMesh
miscellaneous_ex6.C
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2025 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 
19 
20 // <h1>Miscellaneous Example 6 - Meshing with LibMesh's TetGen and Triangle Interfaces</h1>
21 // \author John W. Peterson
22 // \date 2011
23 //
24 // LibMesh provides interfaces to both Triangle and TetGen for generating
25 // Delaunay triangulations and tetrahedralizations in two and three dimensions
26 // (respectively).
27 
28 // Local header files
29 #include "libmesh/elem.h"
30 #include "libmesh/face_tri3.h"
31 #include "libmesh/mesh.h"
32 #include "libmesh/mesh_generation.h"
33 #include "libmesh/mesh_tetgen_interface.h"
34 #include "libmesh/mesh_triangle_holes.h"
35 #include "libmesh/mesh_triangle_interface.h"
36 #include "libmesh/node.h"
37 #include "libmesh/replicated_mesh.h"
38 #include "libmesh/utility.h" // libmesh_map_find()
39 
40 // Bring in everything from the libMesh namespace
41 using namespace libMesh;
42 
43 // Major functions called by main
46 
47 // Helper routine for tetrahedralize_domain(). Adds the points and elements
48 // of a convex hull generated by TetGen to the input mesh
49 void add_cube_convex_hull_to_mesh(MeshBase & mesh, Point lower_limit, Point upper_limit);
50 
51 
52 
53 
54 // Begin the main program.
55 int main (int argc, char ** argv)
56 {
57  // Initialize libMesh and any dependent libraries, like in example 2.
58  LibMeshInit init (argc, argv);
59 
60  libmesh_example_requires(2 <= LIBMESH_DIM, "2D support");
61 
62  libMesh::out << "Triangulating an L-shaped domain with holes" << std::endl;
63 
64  // 1.) 2D triangulation of L-shaped domain with three holes of different shape
65  triangulate_domain(init.comm());
66 
67  libmesh_example_requires(3 <= LIBMESH_DIM, "3D support");
68 
69  libMesh::out << "Tetrahedralizing a prismatic domain with a hole" << std::endl;
70 
71  // 2.) 3D tetrahedralization of rectangular domain with hole.
73 
74  return 0;
75 }
76 
77 
78 
79 
81 {
82 #ifdef LIBMESH_HAVE_TRIANGLE
83  // Use typedefs for slightly less typing.
84  typedef TriangleInterface::Hole Hole;
85  typedef TriangleInterface::PolygonHole PolygonHole;
86  typedef TriangleInterface::ArbitraryHole ArbitraryHole;
87 
88  // Libmesh mesh that will eventually be created.
89  Mesh mesh(comm, 2);
90 
91  // The points which make up the L-shape:
92  mesh.add_point(Point(0., 0.));
93  mesh.add_point(Point(0., -1.));
94  mesh.add_point(Point(-1., -1.));
95  mesh.add_point(Point(-1., 1.));
96  mesh.add_point(Point(1., 1.));
97  mesh.add_point(Point(1., 0.));
98 
99  // Declare the TriangleInterface object. This is where
100  // we can set parameters of the triangulation and where the
101  // actual triangulate function lives.
103 
104  // Customize the variables for the triangulation
105  t.desired_area() = .01;
106 
107  // A Planar Straight Line Graph (PSLG) is essentially a list
108  // of segments which have to exist in the final triangulation.
109  // For an L-shaped domain, Triangle will compute the convex
110  // hull of boundary points if we do not specify the PSLG.
111  // The PSLG algorithm is also required for triangulating domains
112  // containing holes
114 
115  // Turn on/off Laplacian mesh smoothing after generation.
116  // By default this is on.
117  t.smooth_after_generating() = true;
118 
119  // Define holes...
120 
121  // hole_1 is a circle (discretized by 50 points)
122  PolygonHole hole_1(Point(-0.5, 0.5), // center
123  0.25, // radius
124  50); // n. points
125 
126  // hole_2 is itself a triangle
127  PolygonHole hole_2(Point(0.5, 0.5), // center
128  0.1, // radius
129  3); // n. points
130 
131  // hole_3 is an ellipse of 100 points which we define here
132  Point ellipse_center(-0.5, -0.5);
133  const unsigned int n_ellipse_points=100;
134  std::vector<Point> ellipse_points(n_ellipse_points);
135  const Real
136  dtheta = 2*libMesh::pi / static_cast<Real>(n_ellipse_points),
137  a = .1,
138  b = .2;
139 
140  for (unsigned int i=0; i<n_ellipse_points; ++i)
141  ellipse_points[i]= Point(ellipse_center(0)+a*cos(i*dtheta),
142  ellipse_center(1)+b*sin(i*dtheta));
143 
144  ArbitraryHole hole_3(ellipse_center, ellipse_points);
145 
146  // Create the vector of Hole*'s ...
147  std::vector<Hole *> holes;
148  holes.push_back(&hole_1);
149  holes.push_back(&hole_2);
150  holes.push_back(&hole_3);
151 
152  // ... and attach it to the triangulator object
153  t.attach_hole_list(&holes);
154 
155  // Triangulate!
156  t.triangulate();
157 
158 #ifdef LIBMESH_HAVE_EXODUS_API
159  // Write the result to file
160  mesh.write("delaunay_l_shaped_hole.e");
161 #endif
162 
163 #else
164  // Avoid compiler warnings
165  libmesh_ignore(comm);
166 #endif // LIBMESH_HAVE_TRIANGLE
167 }
168 
169 
170 
172 {
173 #ifdef LIBMESH_HAVE_TETGEN
174  // The algorithm is broken up into several steps:
175  // 1.) A convex hull is constructed for a rectangular hole.
176  // 2.) A convex hull is constructed for the domain exterior.
177  // 3.) Neighbor information is updated so TetGen knows there is a convex hull
178  // 4.) A vector of hole points is created.
179  // 5.) The domain is tetrahedralized, the mesh is written out, etc.
180 
181  // The mesh we will eventually generate
182  ReplicatedMesh mesh(comm, 3);
183 
184  // Lower and Upper bounding box limits for a rectangular hole within the unit cube.
185  Point hole_lower_limit(0.2, 0.2, 0.4);
186  Point hole_upper_limit(0.8, 0.8, 0.6);
187 
188  // 1.) Construct a convex hull for the hole
189  add_cube_convex_hull_to_mesh(mesh, hole_lower_limit, hole_upper_limit);
190 
191  // 2.) Generate elements comprising the outer boundary of the domain.
193  Point(0., 0., 0.),
194  Point(1., 1., 1.));
195 
196  // 3.) Update neighbor information so that TetGen can verify there is a convex hull.
198 
199  // 4.) Set up vector of hole points
200  std::vector<Point> hole(1);
201  hole[0] = Point(0.5*(hole_lower_limit + hole_upper_limit));
202 
203  // 5.) Set parameters and tetrahedralize the domain
204 
205  // 0 means "use TetGen default value"
206  double quality_constraint = 2.0;
207 
208  // The volume constraint determines the max-allowed tetrahedral
209  // volume in the Mesh. TetGen will split cells which are larger than
210  // this size
211  double volume_constraint = 0.001;
212 
213  // Construct the Delaunay tetrahedralization
215 
216  // In debug mode, set the tetgen switches
217  // -V (verbose) and
218  // -CC (check consistency and constrained Delaunay)
219  // In optimized mode, only switch Q (quiet) is set.
220  // For more options, see tetgen website:
221  // (http://wias-berlin.de/software/tetgen/1.5/doc/manual/manual005.html#cmd-m)
222 #ifdef DEBUG
223  t.set_switches("VCC");
224 #endif
226  quality_constraint,
227  volume_constraint);
228 
229  // Find neighbors, etc in preparation for writing out the Mesh
231 
232  // Finally, write out the result
233 #ifdef LIBMESH_HAVE_EXODUS_API
234  mesh.write("hole_3D.e");
235 #endif
236 
237 #else
238  // Avoid compiler warnings
239  libmesh_ignore(comm);
240 #endif // LIBMESH_HAVE_TETGEN
241 }
242 
243 
244 
245 
246 
247 
248 
249 
250 
251 
252 
253 
254 
256  Point lower_limit,
257  Point upper_limit)
258 {
259 #ifdef LIBMESH_HAVE_TETGEN
260  ReplicatedMesh cube_mesh(mesh.comm(), 3);
261 
262  unsigned n_elem = 1;
263 
265  n_elem, n_elem, n_elem, // n. elements in each direction
266  lower_limit(0), upper_limit(0),
267  lower_limit(1), upper_limit(1),
268  lower_limit(2), upper_limit(2),
269  HEX8);
270 
271  // The pointset_convexhull() algorithm will ignore the Hex8s
272  // in the Mesh, and just construct the triangulation
273  // of the convex hull.
274  TetGenMeshInterface t(cube_mesh);
276 
277  // Now add all nodes from the boundary of the cube_mesh to the input mesh.
278 
279  // Map from "node id in cube_mesh" -> "node id in mesh". Initially inserted
280  // with a dummy value, later to be assigned a value by the input mesh.
281  std::map<unsigned, unsigned> node_id_map;
282  typedef std::map<unsigned, unsigned>::iterator iterator;
283 
284  for (auto & elem : cube_mesh.element_ptr_range())
285  for (auto s : elem->side_index_range())
286  if (elem->neighbor_ptr(s) == nullptr)
287  {
288  // Add the node IDs of this side to the set
289  std::unique_ptr<Elem> side = elem->side_ptr(s);
290 
291  for (auto n : side->node_index_range())
292  node_id_map.emplace(side->node_id(n), /*dummy_value=*/0);
293  }
294 
295  // For each node in the map, insert it into the input mesh and keep
296  // track of the ID assigned.
297  for (iterator it=node_id_map.begin(); it != node_id_map.end(); ++it)
298  {
299  // Id of the node in the cube mesh
300  unsigned id = (*it).first;
301 
302  // Pointer to node in the cube mesh
303  Node & old_node = cube_mesh.node_ref(id);
304 
305  // Add geometric point to input mesh
306  Node * new_node = mesh.add_point (old_node);
307 
308  // Track ID value of new_node in map
309  (*it).second = new_node->id();
310  }
311 
312  // With the points added and the map data structure in place, we are
313  // ready to add each TRI3 element of the cube_mesh to the input Mesh
314  // with proper node assignments
315  for (auto & old_elem : cube_mesh.element_ptr_range())
316  if (old_elem->type() == TRI3)
317  {
318  Elem * new_elem = mesh.add_elem(Elem::build(TRI3));
319 
320  // Assign nodes in new elements. Since this is an example,
321  // we'll do it in several steps.
322  for (auto i : old_elem->node_index_range())
323  {
324  // Mapping to node ID in input mesh
325  unsigned int new_node_id = libmesh_map_find(node_id_map, old_elem->node_id(i));
326 
327  // Node pointer assigned from input mesh
328  new_elem->set_node(i, mesh.node_ptr(new_node_id));
329  }
330  }
331 #else
332  // Avoid compiler warnings
333  libmesh_ignore(mesh, lower_limit, upper_limit);
334 #endif // LIBMESH_HAVE_TETGEN
335 }
Class TetGenMeshInterface provides an interface for tetrahedralization of meshes using the TetGen lib...
virtual void triangulate() override
Internally, this calls Triangle&#39;s triangulate routine.
The ReplicatedMesh class is derived from the MeshBase class, and is used to store identical copies of...
virtual Node *& set_node(const unsigned int i)
Definition: elem.h:2558
A Node is like a Point, but with more information.
Definition: node.h:52
void set_switches(std::string new_switches)
Method to set switches to tetgen, allowing for different behaviours.
void add_cube_convex_hull_to_mesh(MeshBase &mesh, Point lower_limit, Point upper_limit)
dof_id_type n_elem(const MeshBase::const_element_iterator &begin, const MeshBase::const_element_iterator &end)
Count up the number of elements of a specific type (as defined by an iterator range).
Definition: mesh_tools.C:969
void prepare_for_use(const bool skip_renumber_nodes_and_elements, const bool skip_find_neighbors)
Prepare a newly ecreated (or read) mesh for use.
Definition: mesh_base.C:759
This is the base class from which all geometric element types are derived.
Definition: elem.h:94
MeshBase & mesh
const Parallel::Communicator & comm() const
The LibMeshInit class, when constructed, initializes the dependent libraries (e.g.
Definition: libmesh.h:90
The libMesh namespace provides an interface to certain functionality in the library.
virtual Node * add_point(const Point &p, const dof_id_type id=DofObject::invalid_id, const processor_id_type proc_id=DofObject::invalid_processor_id)=0
Add a new Node at Point p to the end of the vertex array, with processor_id procid.
This is the MeshBase class.
Definition: mesh_base.h:75
TriangulationType & triangulation_type()
Sets and/or gets the desired triangulation type.
void libmesh_ignore(const Args &...)
virtual void find_neighbors(const bool reset_remote_elements=false, const bool reset_current_list=true)=0
Locate element face (edge in 2D) neighbors.
dof_id_type id() const
Definition: dof_object.h:828
void attach_hole_list(const std::vector< Hole *> *holes)
Attaches a vector of Hole* pointers which will be meshed around.
void triangulate_conformingDelaunayMesh_carvehole(const std::vector< Point > &holes, double quality_constraint=0., double volume_constraint=0.)
Method invokes TetGen library to compute a Delaunay tetrahedralization from the nodes point set...
int main(int argc, char **argv)
virtual Elem * add_elem(Elem *e)=0
Add elem e to the end of the element array.
static std::unique_ptr< Elem > build(const ElemType type, Elem *p=nullptr)
Definition: elem.C:444
void init(triangulateio &t)
Initializes the fields of t to nullptr/0 as necessary.
virtual void write(const std::string &name) const =0
Real & desired_area()
Sets and/or gets the desired triangle area.
Triangulate the interior of a Planar Straight Line Graph, which is defined implicitly by the order of...
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
OStreamProxy out
void tetrahedralize_domain(const Parallel::Communicator &comm)
void pointset_convexhull()
Method invokes TetGen library to compute a Delaunay tetrahedralization from the nodes point set...
virtual const Node * node_ptr(const dof_id_type i) const =0
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
Definition: mesh.h:50
A C++ interface between LibMesh and the Triangle library written by J.R.
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:39
void build_cube(UnstructuredMesh &mesh, const unsigned int nx=0, const unsigned int ny=0, const unsigned int nz=0, const Real xmin=0., const Real xmax=1., const Real ymin=0., const Real ymax=1., const Real zmin=0., const Real zmax=1., const ElemType type=INVALID_ELEM, const bool gauss_lobatto_grid=false)
Builds a (elements) cube.
void triangulate_domain(const Parallel::Communicator &comm)
bool & smooth_after_generating()
Sets/gets flag which tells whether to do two steps of Laplace mesh smoothing after generating the gri...
const Real pi
.
Definition: libmesh.h:299