$extrastylesheet
00001 // The libMesh Finite Element Library. 00002 // Copyright (C) 2002-2014 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 00020 // C++ includes 00021 00022 // Local includes 00023 #include "libmesh/mesh_tools.h" 00024 #include "libmesh/mesh_subdivision_support.h" 00025 #include "libmesh/boundary_info.h" 00026 00027 namespace libMesh 00028 { 00029 00030 00031 void MeshTools::Subdivision::find_one_ring(const Tri3Subdivision* elem, std::vector<Node*>& nodes) 00032 { 00033 libmesh_assert(elem->is_subdivision_updated()); 00034 libmesh_assert(elem->get_ordered_node(0)); 00035 00036 unsigned int valence = elem->get_ordered_valence(0); 00037 nodes.resize(valence + 6); 00038 00039 // The first three vertices in the patch are the ones from the element triangle 00040 nodes[0] = elem->get_ordered_node(0); 00041 nodes[1] = elem->get_ordered_node(1); 00042 nodes[valence] = elem->get_ordered_node(2); 00043 00044 const unsigned int nn0 = elem->local_node_number(nodes[0]->id()); 00045 00046 Tri3Subdivision* nb = dynamic_cast<Tri3Subdivision*>(elem->neighbor(nn0)); 00047 libmesh_assert(nb); 00048 00049 unsigned int j, i = 1; 00050 00051 do 00052 { 00053 ++i; 00054 j = nb->local_node_number(nodes[0]->id()); 00055 nodes[i] = nb->get_node(next[j]); 00056 nb = static_cast<Tri3Subdivision*>(nb->neighbor(j)); 00057 } while (nb != elem); 00058 00059 /* for nodes connected with N (= valence[0]) */ 00060 nb = static_cast<Tri3Subdivision*>(elem->neighbor(next[nn0])); 00061 j = nb->local_node_number(nodes[1]->id()); 00062 nodes[valence+1] = nb->get_node(next[j]); 00063 00064 nb = static_cast<Tri3Subdivision*>(nb->neighbor(next[j])); 00065 j = nb->local_node_number(nodes[valence+1]->id()); 00066 nodes[valence+4] = nb->get_node(next[j]); 00067 00068 nb = static_cast<Tri3Subdivision*>(nb->neighbor(next[j])); 00069 j = nb->local_node_number(nodes[valence+4]->id()); 00070 nodes[valence+5] = nb->get_node(next[j]); 00071 00072 /* for nodes connected with 1 */ 00073 nb = static_cast<Tri3Subdivision*>(elem->neighbor(next[nn0])); 00074 j = nb->local_node_number(nodes[1]->id()); 00075 // nodes[valence+1] has been determined already 00076 00077 nb = static_cast<Tri3Subdivision*>(nb->neighbor(j)); 00078 j = nb->local_node_number(nodes[1]->id()); 00079 nodes[valence+2] = nb->get_node(next[j]); 00080 00081 nb = static_cast<Tri3Subdivision*>(nb->neighbor(j)); 00082 j = nb->local_node_number(nodes[1]->id()); 00083 nodes[valence+3] = nb->get_node(next[j]); 00084 00085 return; 00086 } 00087 00088 00089 void MeshTools::Subdivision::all_subdivision(MeshBase& mesh) 00090 { 00091 std::vector<Elem*> new_elements; 00092 new_elements.reserve(mesh.n_elem()); 00093 const bool mesh_has_boundary_data = 00094 (mesh.get_boundary_info().n_boundary_ids() > 0); 00095 00096 std::vector<Elem*> new_boundary_elements; 00097 std::vector<short int> new_boundary_sides; 00098 std::vector<boundary_id_type> new_boundary_ids; 00099 00100 MeshBase::const_element_iterator el = mesh.elements_begin(); 00101 const MeshBase::const_element_iterator end_el = mesh.elements_end(); 00102 for (; el != end_el; ++el) 00103 { 00104 const Elem* elem = *el; 00105 libmesh_assert_equal_to(elem->type(), TRI3); 00106 00107 Elem* tri = new Tri3Subdivision; 00108 tri->set_id(elem->id()); 00109 tri->set_node(0) = (*el)->get_node(0); 00110 tri->set_node(1) = (*el)->get_node(1); 00111 tri->set_node(2) = (*el)->get_node(2); 00112 00113 if (mesh_has_boundary_data) 00114 { 00115 for (unsigned short side = 0; side < elem->n_sides(); ++side) 00116 { 00117 const boundary_id_type boundary_id = 00118 mesh.get_boundary_info().boundary_id(elem, side); 00119 if (boundary_id != BoundaryInfo::invalid_id) 00120 { 00121 // add the boundary id to the list of new boundary ids 00122 new_boundary_ids.push_back(boundary_id); 00123 new_boundary_elements.push_back(tri); 00124 new_boundary_sides.push_back(side); 00125 } 00126 } 00127 00128 // remove the original element from the BoundaryInfo structure 00129 mesh.get_boundary_info().remove(elem); 00130 } 00131 00132 new_elements.push_back(tri); 00133 mesh.insert_elem(tri); 00134 } 00135 mesh.prepare_for_use(); 00136 00137 if (mesh_has_boundary_data) 00138 { 00139 // If the old mesh had boundary data, the new mesh better have some too. 00140 libmesh_assert_greater(new_boundary_elements.size(), 0); 00141 00142 // We should also be sure that the lengths of the new boundary data vectors 00143 // are all the same. 00144 libmesh_assert_equal_to(new_boundary_sides.size(), new_boundary_elements.size()); 00145 libmesh_assert_equal_to(new_boundary_sides.size(), new_boundary_ids.size()); 00146 00147 // Add the new boundary info to the mesh. 00148 for (unsigned int s = 0; s < new_boundary_elements.size(); ++s) 00149 mesh.get_boundary_info().add_side(new_boundary_elements[s], 00150 new_boundary_sides[s], 00151 new_boundary_ids[s]); 00152 } 00153 00154 mesh.prepare_for_use(); 00155 } 00156 00157 00158 void MeshTools::Subdivision::prepare_subdivision_mesh(MeshBase& mesh, bool ghosted) 00159 { 00160 mesh.prepare_for_use(); 00161 00162 // convert all mesh elements to subdivision elements 00163 all_subdivision(mesh); 00164 00165 if (!ghosted) 00166 { 00167 // add the ghost elements for the boundaries 00168 add_boundary_ghosts(mesh); 00169 } 00170 else 00171 { 00172 // This assumes that the mesh already has the ghosts. Only tagging them is required here. 00173 tag_boundary_ghosts(mesh); 00174 } 00175 00176 mesh.prepare_for_use(); 00177 00178 std::vector<std::vector<const Elem*> > nodes_to_elem_map; 00179 MeshTools::build_nodes_to_elem_map(mesh, nodes_to_elem_map); 00180 00181 // compute the node valences 00182 MeshBase::const_node_iterator nd = mesh.nodes_begin(); 00183 const MeshBase::const_node_iterator end_nd = mesh.nodes_end(); 00184 for (; nd != end_nd; ++nd) 00185 { 00186 Node* node = *nd; 00187 std::vector<const Node*> neighbors; 00188 MeshTools::find_nodal_neighbors(mesh, *node, nodes_to_elem_map, neighbors); 00189 const unsigned int valence = 00190 cast_int<unsigned int>(neighbors.size()); 00191 libmesh_assert_greater(valence, 1); 00192 node->set_valence(valence); 00193 } 00194 00195 MeshBase::const_element_iterator el = mesh.elements_begin(); 00196 const MeshBase::const_element_iterator end_el = mesh.elements_end(); 00197 for (; el != end_el; ++el) 00198 { 00199 Tri3Subdivision* elem = dynamic_cast<Tri3Subdivision*>(*el); 00200 libmesh_assert(elem); 00201 if (!elem->is_ghost()) 00202 elem->prepare_subdivision_properties(); 00203 } 00204 } 00205 00206 00207 void MeshTools::Subdivision::tag_boundary_ghosts(MeshBase& mesh) 00208 { 00209 MeshBase::element_iterator el = mesh.elements_begin(); 00210 const MeshBase::element_iterator end_el = mesh.elements_end(); 00211 for (; el != end_el; ++el) 00212 { 00213 Elem* elem = *el; 00214 libmesh_assert_equal_to(elem->type(), TRI3SUBDIVISION); 00215 00216 Tri3Subdivision* sd_elem = static_cast<Tri3Subdivision*>(elem); 00217 for (unsigned int i = 0; i < elem->n_sides(); ++i) 00218 { 00219 if (elem->neighbor(i) == NULL) 00220 { 00221 sd_elem->set_ghost(true); 00222 // set all other neighbors to ghosts as well 00223 if (elem->neighbor(next[i])) 00224 { 00225 Tri3Subdivision* nb = static_cast<Tri3Subdivision*>(elem->neighbor(next[i])); 00226 nb->set_ghost(true); 00227 } 00228 if (elem->neighbor(prev[i])) 00229 { 00230 Tri3Subdivision* nb = static_cast<Tri3Subdivision*>(elem->neighbor(prev[i])); 00231 nb->set_ghost(true); 00232 } 00233 } 00234 } 00235 } 00236 } 00237 00238 00239 void MeshTools::Subdivision::add_boundary_ghosts(MeshBase& mesh) 00240 { 00241 static const Real tol = 1e-5; 00242 00243 // add the mirrored ghost elements (without using iterators, because the mesh is modified in the course) 00244 std::vector<Tri3Subdivision*> ghost_elems; 00245 std::vector<Node*> ghost_nodes; 00246 const unsigned int n_elem = mesh.n_elem(); 00247 for (unsigned int eid = 0; eid < n_elem; ++eid) 00248 { 00249 Elem* elem = mesh.elem(eid); 00250 libmesh_assert_equal_to(elem->type(), TRI3SUBDIVISION); 00251 00252 for (unsigned int i = 0; i < elem->n_sides(); ++i) 00253 { 00254 libmesh_assert_not_equal_to(elem->neighbor(i), elem); 00255 if (elem->neighbor(i) == NULL) 00256 { 00257 // this is the vertex to be mirrored 00258 Point point = elem->point(i) + elem->point(next[i]) - elem->point(prev[i]); 00259 00260 // Check if the proposed vertex doesn't coincide with one of the existing vertices. 00261 // This is necessary because for some triangulations, it can happen that two mirrored 00262 // ghost vertices coincide, which would then lead to a zero size ghost element below. 00263 Node* node = NULL; 00264 for (unsigned int j = 0; j < ghost_nodes.size(); ++j) 00265 { 00266 if ((*ghost_nodes[j] - point).size() < tol * (elem->point(i) - point).size()) 00267 { 00268 node = ghost_nodes[j]; 00269 break; 00270 } 00271 } 00272 00273 // add the new vertex only if no other is nearby 00274 if (node == NULL) 00275 { 00276 node = mesh.add_point(point); 00277 ghost_nodes.push_back(node); 00278 } 00279 00280 Tri3Subdivision* newelem = new Tri3Subdivision(); 00281 ghost_elems.push_back(newelem); 00282 00283 newelem->set_node(0) = elem->get_node(next[i]); 00284 newelem->set_node(1) = elem->get_node(i); 00285 newelem->set_node(2) = node; 00286 newelem->set_neighbor(0,elem); 00287 newelem->set_ghost(true); 00288 elem->set_neighbor(i,newelem); 00289 00290 mesh.add_elem(newelem); 00291 mesh.get_boundary_info().add_node(elem->get_node(i), 1); 00292 mesh.get_boundary_info().add_node(elem->get_node(next[i]), 1); 00293 mesh.get_boundary_info().add_node(elem->get_node(prev[i]), 1); 00294 mesh.get_boundary_info().add_node(node, 1); 00295 } 00296 } 00297 } 00298 00299 // add the missing ghost elements (connecting new ghost nodes) 00300 std::vector<Tri3Subdivision*> missing_ghost_elems; 00301 std::vector<Tri3Subdivision*>::iterator ghost_el = ghost_elems.begin(); 00302 const std::vector<Tri3Subdivision*>::iterator end_ghost_el = ghost_elems.end(); 00303 for (; ghost_el != end_ghost_el; ++ghost_el) 00304 { 00305 Tri3Subdivision *elem = *ghost_el; 00306 libmesh_assert(elem->is_ghost()); 00307 00308 for (unsigned int i = 0; i < elem->n_sides(); ++i) 00309 { 00310 if (elem->neighbor(i) == NULL && elem->neighbor(prev[i]) != NULL) 00311 { 00312 // go around counter-clockwise 00313 Tri3Subdivision *nb1 = static_cast<Tri3Subdivision *>(elem->neighbor(prev[i])); 00314 Tri3Subdivision *nb2 = nb1; 00315 unsigned int j = i; 00316 while (nb1 != NULL && nb1->id() != elem->id()) 00317 { 00318 j = nb1->local_node_number(elem->node(i)); 00319 nb2 = nb1; 00320 nb1 = static_cast<Tri3Subdivision *>(nb1->neighbor(prev[j])); 00321 libmesh_assert(nb1 == NULL || nb1->id() != nb2->id()); 00322 } 00323 00324 libmesh_assert_not_equal_to(nb2->id(), elem->id()); 00325 00326 // Above, we merged coinciding ghost vertices. Therefore, we need 00327 // to exclude the case where there is no ghost element to add between 00328 // these two (identical) ghost nodes. 00329 if (elem->get_node(next[i])->id() == nb2->get_node(prev[j])->id()) 00330 break; 00331 00332 Tri3Subdivision *newelem = new Tri3Subdivision(); 00333 newelem->set_node(0) = elem->get_node(next[i]); 00334 newelem->set_node(1) = elem->get_node(i); 00335 newelem->set_node(2) = nb2->get_node(prev[j]); 00336 newelem->set_neighbor(0,elem); 00337 newelem->set_neighbor(1,nb2); 00338 newelem->set_neighbor(2,NULL); 00339 newelem->set_ghost(true); 00340 00341 elem->set_neighbor(i,newelem); 00342 nb2->set_neighbor(prev[j],newelem); 00343 00344 missing_ghost_elems.push_back(newelem); 00345 break; 00346 } 00347 } // end side loop 00348 } // end ghost element loop 00349 00350 // add the missing ghost elements to the mesh 00351 std::vector<Tri3Subdivision*>::iterator missing_el = missing_ghost_elems.begin(); 00352 const std::vector<Tri3Subdivision*>::iterator end_missing_el = missing_ghost_elems.end(); 00353 for (; missing_el != end_missing_el; ++missing_el) 00354 mesh.add_elem(*missing_el); 00355 } 00356 00357 } // namespace libMesh