$extrastylesheet
00001 // The libMesh Finite Element Library. 00002 // Copyright (C) 2002-2013 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner 00003 00004 // This library is free software; you can redistribute it and/or 00005 // modify it under the terms of the GNU Lesser General Public 00006 // License as published by the Free Software Foundation; either 00007 // version 2.1 of the License, or (at your option) any later version. 00008 00009 // This library is distributed in the hope that it will be useful, 00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 // Lesser General Public License for more details. 00013 00014 // You should have received a copy of the GNU Lesser General Public 00015 // License along with this library; if not, write to the Free Software 00016 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00017 00018 00019 #include "libmesh/libmesh_config.h" 00020 #if defined(LIBMESH_HAVE_TRIANGLE) && defined(LIBMESH_HAVE_TETGEN) 00021 00022 // Local includes 00023 #include "libmesh/elem_cutter.h" 00024 #include "libmesh/elem.h" 00025 #include "libmesh/serial_mesh.h" 00026 #include "libmesh/mesh_triangle_interface.h" 00027 #include "libmesh/mesh_tetgen_interface.h" 00028 00029 // C++ includes 00030 00031 namespace 00032 { 00033 unsigned int cut_cntr; 00034 } 00035 00036 namespace libMesh 00037 { 00038 00039 // ------------------------------------------------------------ 00040 // ElemCutter implementation 00041 ElemCutter::ElemCutter() 00042 { 00043 _inside_mesh_2D.reset (new SerialMesh(_comm_self,2)); _triangle_inside.reset (new TriangleInterface (*_inside_mesh_2D)); 00044 _outside_mesh_2D.reset (new SerialMesh(_comm_self,2)); _triangle_outside.reset (new TriangleInterface (*_outside_mesh_2D)); 00045 00046 _inside_mesh_3D.reset (new SerialMesh(_comm_self,3)); _tetgen_inside.reset (new TetGenMeshInterface (*_inside_mesh_3D)); 00047 _outside_mesh_3D.reset (new SerialMesh(_comm_self,3)); _tetgen_outside.reset (new TetGenMeshInterface (*_outside_mesh_3D)); 00048 00049 cut_cntr = 0; 00050 } 00051 00052 00053 00054 ElemCutter::~ElemCutter() 00055 {} 00056 00057 00058 00059 bool ElemCutter::is_inside (const Elem &elem, 00060 const std::vector<Real> &vertex_distance_func) const 00061 { 00062 libmesh_assert_equal_to (elem.n_vertices(), vertex_distance_func.size()); 00063 00064 for (std::vector<Real>::const_iterator it=vertex_distance_func.begin(); 00065 it!=vertex_distance_func.end(); ++it) 00066 if (*it > 0.) return false; 00067 00068 // if the distance function is nonpositive, we are outside 00069 return true; 00070 } 00071 00072 00073 00074 bool ElemCutter::is_outside (const Elem &elem, 00075 const std::vector<Real> &vertex_distance_func) const 00076 { 00077 libmesh_assert_equal_to (elem.n_vertices(), vertex_distance_func.size()); 00078 00079 for (std::vector<Real>::const_iterator it=vertex_distance_func.begin(); 00080 it!=vertex_distance_func.end(); ++it) 00081 if (*it < 0.) return false; 00082 00083 // if the distance function is nonnegative, we are outside 00084 return true; 00085 } 00086 00087 00088 00089 bool ElemCutter::is_cut (const Elem &elem, 00090 const std::vector<Real> &vertex_distance_func) const 00091 { 00092 libmesh_assert_equal_to (elem.n_vertices(), vertex_distance_func.size()); 00093 00094 Real 00095 vmin = vertex_distance_func.front(), 00096 vmax = vmin; 00097 00098 for (std::vector<Real>::const_iterator it=vertex_distance_func.begin(); 00099 it!=vertex_distance_func.end(); ++it) 00100 { 00101 vmin = std::min (vmin, *it); 00102 vmax = std::max (vmax, *it); 00103 } 00104 00105 // if the distance function changes sign, we're cut. 00106 return (vmin*vmax < 0.); 00107 } 00108 00109 00110 00111 void ElemCutter::operator()(const Elem &elem, 00112 const std::vector<Real> &vertex_distance_func) 00113 00114 { 00115 libmesh_assert_equal_to (vertex_distance_func.size(), elem.n_vertices()); 00116 00117 _inside_elem.clear(); 00118 _outside_elem.clear(); 00119 00120 // check for quick return? 00121 { 00122 // completely outside? 00123 if (this->is_outside(elem, vertex_distance_func)) 00124 { 00125 //std::cout << "element completely outside\n"; 00126 _outside_elem.push_back(&elem); 00127 return; 00128 } 00129 00130 // completely inside? 00131 else if (this->is_inside(elem, vertex_distance_func)) 00132 { 00133 //std::cout << "element completely inside\n"; 00134 _inside_elem.push_back(&elem); 00135 return; 00136 } 00137 00138 libmesh_assert (this->is_cut (elem, vertex_distance_func)); 00139 } 00140 00141 // we now know we are in a cut element, find the intersecting points. 00142 this->find_intersection_points (elem, vertex_distance_func); 00143 00144 // and then dispatch the proper method 00145 switch (elem.dim()) 00146 { 00147 case 1: this->cut_1D(elem, vertex_distance_func); break; 00148 case 2: this->cut_2D(elem, vertex_distance_func); break; 00149 case 3: this->cut_3D(elem, vertex_distance_func); break; 00150 default: libmesh_error_msg("Invalid element dimension: " << elem.dim()); 00151 } 00152 } 00153 00154 00155 00156 void ElemCutter::find_intersection_points(const Elem &elem, 00157 const std::vector<Real> &vertex_distance_func) 00158 { 00159 _intersection_pts.clear(); 00160 00161 for (unsigned int e=0; e<elem.n_edges(); e++) 00162 { 00163 UniquePtr<Elem> edge (elem.build_edge(e)); 00164 00165 // find the element nodes el0, el1 that map 00166 unsigned int 00167 el0 = elem.get_node_index(edge->get_node(0)), 00168 el1 = elem.get_node_index(edge->get_node(1)); 00169 00170 libmesh_assert (elem.is_vertex(el0)); 00171 libmesh_assert (elem.is_vertex(el1)); 00172 libmesh_assert_less (el0, vertex_distance_func.size()); 00173 libmesh_assert_less (el1, vertex_distance_func.size()); 00174 00175 const Real 00176 d0 = vertex_distance_func[el0], 00177 d1 = vertex_distance_func[el1]; 00178 00179 // if this egde has a 0 crossing 00180 if (d0*d1 < 0.) 00181 { 00182 libmesh_assert_not_equal_to (d0, d1); 00183 00184 // then find d_star in [0,1], the 00185 // distance from el0 to el1 where the 0 lives. 00186 const Real d_star = d0 / (d0 - d1); 00187 00188 00189 // Prevent adding nodes trivially close to existing 00190 // nodes. 00191 const Real endpoint_tol = 0.01; 00192 00193 if ( (d_star > endpoint_tol) && 00194 (d_star < (1.-endpoint_tol)) ) 00195 { 00196 const Point x_star = (edge->point(0)*(1.-d_star) + 00197 edge->point(1)*d_star); 00198 00199 std::cout << "adding cut point (d_star, x_star) = " 00200 << d_star << " , " << x_star << std::endl; 00201 00202 _intersection_pts.push_back (x_star); 00203 } 00204 } 00205 } 00206 } 00207 00208 00209 00210 00211 void ElemCutter::cut_1D (const Elem & /*elem*/, 00212 const std::vector<Real> &/*vertex_distance_func*/) 00213 { 00214 libmesh_not_implemented(); 00215 } 00216 00217 00218 00219 void ElemCutter::cut_2D (const Elem &elem, 00220 const std::vector<Real> &vertex_distance_func) 00221 { 00222 #ifndef LIBMESH_HAVE_TRIANGLE 00223 00224 // current implementation requires triangle! 00225 libMesh::err << "ERROR: current libMesh ElemCutter 2D implementation requires\n" 00226 << " the \"triangle\" library!\n" 00227 << std::endl; 00228 libmesh_not_implemented(); 00229 00230 #else // OK, LIBMESH_HAVE_TRIANGLE 00231 00232 std::cout << "Inside cut face element!\n"; 00233 00234 libmesh_assert (_inside_mesh_2D.get() != NULL); 00235 libmesh_assert (_outside_mesh_2D.get() != NULL); 00236 00237 _inside_mesh_2D->clear(); 00238 _outside_mesh_2D->clear(); 00239 00240 for (unsigned int v=0; v<elem.n_vertices(); v++) 00241 { 00242 if (vertex_distance_func[v] >= 0.) 00243 _outside_mesh_2D->add_point (elem.point(v)); 00244 00245 if (vertex_distance_func[v] <= 0.) 00246 _inside_mesh_2D->add_point (elem.point(v)); 00247 } 00248 00249 for (std::vector<Point>::const_iterator it=_intersection_pts.begin(); 00250 it != _intersection_pts.end(); ++it) 00251 { 00252 _inside_mesh_2D->add_point(*it); 00253 _outside_mesh_2D->add_point(*it); 00254 } 00255 00256 00257 // Customize the variables for the triangulation 00258 // we will be cutting reference cell, and want as few triangles 00259 // as possible, so jack this up larger than the area we will be 00260 // triangulating so we are governed only by accurately defining 00261 // the boundaries. 00262 _triangle_inside->desired_area() = 100.; 00263 _triangle_outside->desired_area() = 100.; 00264 00265 // allow for small angles 00266 _triangle_inside->minimum_angle() = 5.; 00267 _triangle_outside->minimum_angle() = 5.; 00268 00269 // Turn off Laplacian mesh smoothing after generation. 00270 _triangle_inside->smooth_after_generating() = false; 00271 _triangle_outside->smooth_after_generating() = false; 00272 00273 // Triangulate! 00274 _triangle_inside->triangulate(); 00275 _triangle_outside->triangulate(); 00276 00277 // std::ostringstream name; 00278 00279 // name << "cut_face_" 00280 // << cut_cntr++ 00281 // << ".dat"; 00282 // _inside_mesh_2D->write ("in_" + name.str()); 00283 // _outside_mesh_2D->write ("out_" + name.str()); 00284 00285 // finally, add the elements to our lists. 00286 { 00287 _inside_elem.clear(); _outside_elem.clear(); 00288 00289 MeshBase::const_element_iterator 00290 it = _inside_mesh_2D->elements_begin(), 00291 end = _inside_mesh_2D->elements_end(); 00292 00293 for (; it!=end; ++it) 00294 _inside_elem.push_back (*it); 00295 00296 it = _outside_mesh_2D->elements_begin(); 00297 end = _outside_mesh_2D->elements_end(); 00298 00299 for (; it!=end; ++it) 00300 _outside_elem.push_back (*it); 00301 } 00302 00303 #endif 00304 } 00305 00306 00307 00308 void ElemCutter::cut_3D (const Elem &elem, 00309 const std::vector<Real> &vertex_distance_func) 00310 { 00311 #ifndef LIBMESH_HAVE_TETGEN 00312 00313 // current implementation requires tetgen! 00314 libMesh::err << "ERROR: current libMesh ElemCutter 3D implementation requires\n" 00315 << " the \"tetgen\" library!\n" 00316 << std::endl; 00317 libmesh_not_implemented(); 00318 00319 #else // OK, LIBMESH_HAVE_TETGEN 00320 00321 std::cout << "Inside cut cell element!\n"; 00322 00323 libmesh_assert (_inside_mesh_3D.get() != NULL); 00324 libmesh_assert (_outside_mesh_3D.get() != NULL); 00325 00326 _inside_mesh_3D->clear(); 00327 _outside_mesh_3D->clear(); 00328 00329 for (unsigned int v=0; v<elem.n_vertices(); v++) 00330 { 00331 if (vertex_distance_func[v] >= 0.) 00332 _outside_mesh_3D->add_point (elem.point(v)); 00333 00334 if (vertex_distance_func[v] <= 0.) 00335 _inside_mesh_3D->add_point (elem.point(v)); 00336 } 00337 00338 for (std::vector<Point>::const_iterator it=_intersection_pts.begin(); 00339 it != _intersection_pts.end(); ++it) 00340 { 00341 _inside_mesh_3D->add_point(*it); 00342 _outside_mesh_3D->add_point(*it); 00343 } 00344 00345 00346 // Triangulate! 00347 _tetgen_inside->triangulate_pointset(); 00348 //_inside_mesh_3D->print_info(); 00349 _tetgen_outside->triangulate_pointset(); 00350 //_outside_mesh_3D->print_info(); 00351 00352 00353 // (below generates some horribly expensive meshes, 00354 // but seems immune to the 0 volume problem). 00355 // _tetgen_inside->pointset_convexhull(); 00356 // _inside_mesh_3D->find_neighbors(); 00357 // _inside_mesh_3D->print_info(); 00358 // _tetgen_inside->triangulate_conformingDelaunayMesh (1.e3, 100.); 00359 // _inside_mesh_3D->print_info(); 00360 00361 // _tetgen_outside->pointset_convexhull(); 00362 // _outside_mesh_3D->find_neighbors(); 00363 // _outside_mesh_3D->print_info(); 00364 // _tetgen_outside->triangulate_conformingDelaunayMesh (1.e3, 100.); 00365 // _outside_mesh_3D->print_info(); 00366 00367 std::ostringstream name; 00368 00369 name << "cut_cell_" 00370 << cut_cntr++ 00371 << ".dat"; 00372 _inside_mesh_3D->write ("in_" + name.str()); 00373 _outside_mesh_3D->write ("out_" + name.str()); 00374 00375 // finally, add the elements to our lists. 00376 { 00377 _inside_elem.clear(); _outside_elem.clear(); 00378 00379 MeshBase::const_element_iterator 00380 it = _inside_mesh_3D->elements_begin(), 00381 end = _inside_mesh_3D->elements_end(); 00382 00383 for (; it!=end; ++it) 00384 if ((*it)->volume() > std::numeric_limits<Real>::epsilon()) 00385 _inside_elem.push_back (*it); 00386 00387 it = _outside_mesh_3D->elements_begin(); 00388 end = _outside_mesh_3D->elements_end(); 00389 00390 for (; it!=end; ++it) 00391 if ((*it)->volume() > std::numeric_limits<Real>::epsilon()) 00392 _outside_elem.push_back (*it); 00393 } 00394 00395 #endif 00396 } 00397 00398 00399 00400 } // namespace libMesh 00401 00402 #endif // LIBMESH_HAVE_TRIANGLE && LIBMESH_HAVE_TETGEN