$extrastylesheet
mesh_subdivision_support.C
Go to the documentation of this file.
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