elem_cutter.C
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2013 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 #include "libmesh/libmesh_config.h"
20 #if defined(LIBMESH_HAVE_TRIANGLE) && defined(LIBMESH_HAVE_TETGEN)
21 
22 // Local includes
23 #include "libmesh/elem_cutter.h"
24 #include "libmesh/elem.h"
28 #include "libmesh/auto_ptr.h" // libmesh_make_unique
29 
30 namespace
31 {
32 unsigned int cut_cntr;
33 }
34 
35 namespace libMesh
36 {
37 
39  _inside_mesh_2D(libmesh_make_unique<ReplicatedMesh>(_comm_self,2)),
40  _triangle_inside(libmesh_make_unique<TriangleInterface>(*_inside_mesh_2D)),
41  _outside_mesh_2D(libmesh_make_unique<ReplicatedMesh>(_comm_self,2)),
42  _triangle_outside(libmesh_make_unique<TriangleInterface>(*_outside_mesh_2D)),
43  _inside_mesh_3D(libmesh_make_unique<ReplicatedMesh>(_comm_self,3)),
44  _tetgen_inside(libmesh_make_unique<TetGenMeshInterface>(*_inside_mesh_3D)),
45  _outside_mesh_3D(libmesh_make_unique<ReplicatedMesh>(_comm_self,3)),
46  _tetgen_outside(libmesh_make_unique<TetGenMeshInterface>(*_outside_mesh_3D))
47 {
48  cut_cntr = 0;
49 }
50 
51 
52 
54 {}
55 
56 
57 
58 bool ElemCutter::is_inside (const Elem & libmesh_dbg_var(elem),
59  const std::vector<Real> & vertex_distance_func) const
60 {
61  libmesh_assert_equal_to (elem.n_vertices(), vertex_distance_func.size());
62 
63  for (const auto & val : vertex_distance_func)
64  if (val > 0.)
65  return false;
66 
67  // if the distance function is nonpositive, we are outside
68  return true;
69 }
70 
71 
72 
73 bool ElemCutter::is_outside (const Elem & libmesh_dbg_var(elem),
74  const std::vector<Real> & vertex_distance_func) const
75 {
76  libmesh_assert_equal_to (elem.n_vertices(), vertex_distance_func.size());
77 
78  for (const auto & val : vertex_distance_func)
79  if (val < 0.)
80  return false;
81 
82  // if the distance function is nonnegative, we are outside
83  return true;
84 }
85 
86 
87 
88 bool ElemCutter::is_cut (const Elem & libmesh_dbg_var(elem),
89  const std::vector<Real> & vertex_distance_func) const
90 {
91  libmesh_assert_equal_to (elem.n_vertices(), vertex_distance_func.size());
92 
93  Real
94  vmin = vertex_distance_func.front(),
95  vmax = vmin;
96 
97  for (const auto & val : vertex_distance_func)
98  {
99  vmin = std::min (vmin, val);
100  vmax = std::max (vmax, val);
101  }
102 
103  // if the distance function changes sign, we're cut.
104  return (vmin*vmax < 0.);
105 }
106 
107 
108 
109 void ElemCutter::operator()(const Elem & elem,
110  const std::vector<Real> & vertex_distance_func)
111 
112 {
113  libmesh_assert_equal_to (vertex_distance_func.size(), elem.n_vertices());
114 
115  _inside_elem.clear();
116  _outside_elem.clear();
117 
118  // check for quick return?
119  {
120  // completely outside?
121  if (this->is_outside(elem, vertex_distance_func))
122  {
123  //std::cout << "element completely outside\n";
124  _outside_elem.push_back(& elem);
125  return;
126  }
127 
128  // completely inside?
129  else if (this->is_inside(elem, vertex_distance_func))
130  {
131  //std::cout << "element completely inside\n";
132  _inside_elem.push_back(&elem);
133  return;
134  }
135 
136  libmesh_assert (this->is_cut (elem, vertex_distance_func));
137  }
138 
139  // we now know we are in a cut element, find the intersecting points.
140  this->find_intersection_points (elem, vertex_distance_func);
141 
142  // and then dispatch the proper method
143  switch (elem.dim())
144  {
145  case 1: this->cut_1D(elem, vertex_distance_func); break;
146  case 2: this->cut_2D(elem, vertex_distance_func); break;
147  case 3: this->cut_3D(elem, vertex_distance_func); break;
148  default: libmesh_error_msg("Invalid element dimension: " << elem.dim());
149  }
150 }
151 
152 
153 
155  const std::vector<Real> & vertex_distance_func)
156 {
157  _intersection_pts.clear();
158 
159  for (unsigned int e=0; e<elem.n_edges(); e++)
160  {
161  std::unique_ptr<const Elem> edge (elem.build_edge_ptr(e));
162 
163  // find the element nodes el0, el1 that map
164  unsigned int
165  el0 = elem.get_node_index(edge->node_ptr(0)),
166  el1 = elem.get_node_index(edge->node_ptr(1));
167 
168  libmesh_assert (elem.is_vertex(el0));
169  libmesh_assert (elem.is_vertex(el1));
170  libmesh_assert_less (el0, vertex_distance_func.size());
171  libmesh_assert_less (el1, vertex_distance_func.size());
172 
173  const Real
174  d0 = vertex_distance_func[el0],
175  d1 = vertex_distance_func[el1];
176 
177  // if this egde has a 0 crossing
178  if (d0*d1 < 0.)
179  {
180  libmesh_assert_not_equal_to (d0, d1);
181 
182  // then find d_star in [0,1], the
183  // distance from el0 to el1 where the 0 lives.
184  const Real d_star = d0 / (d0 - d1);
185 
186 
187  // Prevent adding nodes trivially close to existing
188  // nodes.
189  const Real endpoint_tol = 0.01;
190 
191  if ( (d_star > endpoint_tol) &&
192  (d_star < (1.-endpoint_tol)) )
193  {
194  const Point x_star = (edge->point(0)*(1-d_star) +
195  edge->point(1)*d_star);
196 
197  std::cout << "adding cut point (d_star, x_star) = "
198  << d_star << " , " << x_star << std::endl;
199 
200  _intersection_pts.push_back (x_star);
201  }
202  }
203  }
204 }
205 
206 
207 
208 
209 void ElemCutter::cut_1D (const Elem & /*elem*/,
210  const std::vector<Real> &/*vertex_distance_func*/)
211 {
212  libmesh_not_implemented();
213 }
214 
215 
216 
217 void ElemCutter::cut_2D (const Elem & elem,
218  const std::vector<Real> & vertex_distance_func)
219 {
220 #ifndef LIBMESH_HAVE_TRIANGLE
221 
222  // current implementation requires triangle!
223  libMesh::err << "ERROR: current libMesh ElemCutter 2D implementation requires\n"
224  << " the \"triangle\" library!\n"
225  << std::endl;
226  libmesh_not_implemented();
227 
228 #else // OK, LIBMESH_HAVE_TRIANGLE
229 
230  std::cout << "Inside cut face element!\n";
231 
232  libmesh_assert (_inside_mesh_2D.get() != nullptr);
233  libmesh_assert (_outside_mesh_2D.get() != nullptr);
234 
235  _inside_mesh_2D->clear();
236  _outside_mesh_2D->clear();
237 
238  for (unsigned int v=0; v<elem.n_vertices(); v++)
239  {
240  if (vertex_distance_func[v] >= 0.)
241  _outside_mesh_2D->add_point (elem.point(v));
242 
243  if (vertex_distance_func[v] <= 0.)
244  _inside_mesh_2D->add_point (elem.point(v));
245  }
246 
247  for (const auto & pt : _intersection_pts)
248  {
249  _inside_mesh_2D->add_point(pt);
250  _outside_mesh_2D->add_point(pt);
251  }
252 
253 
254  // Customize the variables for the triangulation
255  // we will be cutting reference cell, and want as few triangles
256  // as possible, so jack this up larger than the area we will be
257  // triangulating so we are governed only by accurately defining
258  // the boundaries.
259  _triangle_inside->desired_area() = 100.;
260  _triangle_outside->desired_area() = 100.;
261 
262  // allow for small angles
263  _triangle_inside->minimum_angle() = 5.;
264  _triangle_outside->minimum_angle() = 5.;
265 
266  // Turn off Laplacian mesh smoothing after generation.
267  _triangle_inside->smooth_after_generating() = false;
268  _triangle_outside->smooth_after_generating() = false;
269 
270  // Triangulate!
271  _triangle_inside->triangulate();
272  _triangle_outside->triangulate();
273 
274  // std::ostringstream name;
275 
276  // name << "cut_face_"
277  // << cut_cntr++
278  // << ".dat";
279  // _inside_mesh_2D->write ("in_" + name.str());
280  // _outside_mesh_2D->write ("out_" + name.str());
281 
282  // finally, add the elements to our lists.
283  _inside_elem.clear();
284  _outside_elem.clear();
285 
286  for (const auto & elem : _inside_mesh_2D->element_ptr_range())
287  _inside_elem.push_back (elem);
288 
289  for (const auto & elem : _outside_mesh_2D->element_ptr_range())
290  _outside_elem.push_back (elem);
291 
292 #endif
293 }
294 
295 
296 
297 void ElemCutter::cut_3D (const Elem & elem,
298  const std::vector<Real> & vertex_distance_func)
299 {
300 #ifndef LIBMESH_HAVE_TETGEN
301 
302  // current implementation requires tetgen!
303  libMesh::err << "ERROR: current libMesh ElemCutter 3D implementation requires\n"
304  << " the \"tetgen\" library!\n"
305  << std::endl;
306  libmesh_not_implemented();
307 
308 #else // OK, LIBMESH_HAVE_TETGEN
309 
310  std::cout << "Inside cut cell element!\n";
311 
312  libmesh_assert (_inside_mesh_3D.get() != nullptr);
313  libmesh_assert (_outside_mesh_3D.get() != nullptr);
314 
315  _inside_mesh_3D->clear();
316  _outside_mesh_3D->clear();
317 
318  for (unsigned int v=0; v<elem.n_vertices(); v++)
319  {
320  if (vertex_distance_func[v] >= 0.)
321  _outside_mesh_3D->add_point (elem.point(v));
322 
323  if (vertex_distance_func[v] <= 0.)
324  _inside_mesh_3D->add_point (elem.point(v));
325  }
326 
327  for (const auto & pt : _intersection_pts)
328  {
329  _inside_mesh_3D->add_point(pt);
330  _outside_mesh_3D->add_point(pt);
331  }
332 
333 
334  // Triangulate!
335  _tetgen_inside->triangulate_pointset();
336  //_inside_mesh_3D->print_info();
337  _tetgen_outside->triangulate_pointset();
338  //_outside_mesh_3D->print_info();
339 
340 
341  // (below generates some horribly expensive meshes,
342  // but seems immune to the 0 volume problem).
343  // _tetgen_inside->pointset_convexhull();
344  // _inside_mesh_3D->find_neighbors();
345  // _inside_mesh_3D->print_info();
346  // _tetgen_inside->triangulate_conformingDelaunayMesh (1.e3, 100.);
347  // _inside_mesh_3D->print_info();
348 
349  // _tetgen_outside->pointset_convexhull();
350  // _outside_mesh_3D->find_neighbors();
351  // _outside_mesh_3D->print_info();
352  // _tetgen_outside->triangulate_conformingDelaunayMesh (1.e3, 100.);
353  // _outside_mesh_3D->print_info();
354 
355  std::ostringstream name;
356 
357  name << "cut_cell_"
358  << cut_cntr++
359  << ".dat";
360  _inside_mesh_3D->write ("in_" + name.str());
361  _outside_mesh_3D->write ("out_" + name.str());
362 
363  // finally, add the elements to our lists.
364  _inside_elem.clear();
365  _outside_elem.clear();
366 
367  for (const auto & elem : _inside_mesh_3D->element_ptr_range())
368  if (elem->volume() > std::numeric_limits<Real>::epsilon())
369  _inside_elem.push_back (elem);
370 
371  for (const auto & elem : _outside_mesh_3D->element_ptr_range())
372  if (elem->volume() > std::numeric_limits<Real>::epsilon())
373  _outside_elem.push_back (elem);
374 
375 #endif
376 }
377 
378 
379 
380 } // namespace libMesh
381 
382 #endif // LIBMESH_HAVE_TRIANGLE && LIBMESH_HAVE_TETGEN
std::string name(const ElemQuality q)
Definition: elem_quality.C:42
std::unique_ptr< ReplicatedMesh > _inside_mesh_3D
Definition: elem_cutter.h:165
Mesh data structure replicated on all processors.
std::unique_ptr< ReplicatedMesh > _inside_mesh_2D
Definition: elem_cutter.h:159
void find_intersection_points(const Elem &elem, const std::vector< Real > &vertex_distance_func)
Definition: elem_cutter.C:154
std::vector< Point > _intersection_pts
Definition: elem_cutter.h:171
std::unique_ptr< TriangleInterface > _triangle_outside
Definition: elem_cutter.h:163
unsigned int get_node_index(const Node *node_ptr) const
Definition: elem.h:2012
void cut_1D(const Elem &elem, const std::vector< Real > &vertex_distance_func)
Definition: elem_cutter.C:209
void operator()(const Elem &elem_in, const std::vector< Real > &vertex_distance_func)
Definition: elem_cutter.C:109
The base class for all geometric element types.
Definition: elem.h:100
long double max(long double a, double b)
bool is_cut(const Elem &elem, const std::vector< Real > &vertex_distance_func) const
Definition: elem_cutter.C:88
void cut_2D(const Elem &elem, const std::vector< Real > &vertex_distance_func)
Definition: elem_cutter.C:217
std::vector< Elem const * > _inside_elem
Definition: elem_cutter.h:154
std::unique_ptr< ReplicatedMesh > _outside_mesh_3D
Definition: elem_cutter.h:168
std::unique_ptr< TriangleInterface > _triangle_inside
Definition: elem_cutter.h:160
void cut_3D(const Elem &elem, const std::vector< Real > &vertex_distance_func)
Definition: elem_cutter.C:297
OStreamProxy err(std::cerr)
std::unique_ptr< TetGenMeshInterface > _tetgen_inside
Definition: elem_cutter.h:166
virtual unsigned int n_edges() const =0
std::unique_ptr< TetGenMeshInterface > _tetgen_outside
Definition: elem_cutter.h:169
bool is_outside(const Elem &elem, const std::vector< Real > &vertex_distance_func) const
Definition: elem_cutter.C:73
bool is_inside(const Elem &elem, const std::vector< Real > &vertex_distance_func) const
Definition: elem_cutter.C:58
std::vector< Elem const * > _outside_elem
Definition: elem_cutter.h:155
virtual unsigned int n_vertices() const =0
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
virtual unsigned short dim() const =0
virtual bool is_vertex(const unsigned int i) const =0
virtual Real volume() const
Definition: elem.C:2826
std::unique_ptr< ReplicatedMesh > _outside_mesh_2D
Definition: elem_cutter.h:162
virtual std::unique_ptr< Elem > build_edge_ptr(const unsigned int i)=0
long double min(long double a, double b)
A geometric point in (x,y,z) space.
Definition: point.h:38
const Point & point(const unsigned int i) const
Definition: elem.h:1892