$extrastylesheet
mesh_modification.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 #include <cstdlib> // *must* precede <cmath> for proper std:abs() on PGI, Sun Studio CC
00022 #include <cmath> // for std::acos()
00023 #include <algorithm>
00024 #include <limits>
00025 #include <map>
00026 
00027 // Local includes
00028 #include "libmesh/boundary_info.h"
00029 #include "libmesh/function_base.h"
00030 #include "libmesh/face_tri3.h"
00031 #include "libmesh/face_tri6.h"
00032 #include "libmesh/libmesh_logging.h"
00033 #include "libmesh/mesh_communication.h"
00034 #include "libmesh/mesh_modification.h"
00035 #include "libmesh/mesh_tools.h"
00036 #include "libmesh/parallel.h"
00037 #include "libmesh/remote_elem.h"
00038 #include "libmesh/string_to_enum.h"
00039 #include "libmesh/unstructured_mesh.h"
00040 
00041 namespace libMesh
00042 {
00043 
00044 
00045 // ------------------------------------------------------------
00046 // MeshTools::Modification functions for mesh modification
00047 void MeshTools::Modification::distort (MeshBase& mesh,
00048                                        const Real factor,
00049                                        const bool perturb_boundary)
00050 {
00051   libmesh_assert (mesh.n_nodes());
00052   libmesh_assert (mesh.n_elem());
00053   libmesh_assert ((factor >= 0.) && (factor <= 1.));
00054 
00055   START_LOG("distort()", "MeshTools::Modification");
00056 
00057 
00058 
00059   // First find nodes on the boundary and flag them
00060   // so that we don't move them
00061   // on_boundary holds false (not on boundary) and true (on boundary)
00062   std::vector<bool> on_boundary (mesh.n_nodes(), false);
00063 
00064   if (!perturb_boundary) MeshTools::find_boundary_nodes (mesh, on_boundary);
00065 
00066   // Now calculate the minimum distance to
00067   // neighboring nodes for each node.
00068   // hmin holds these distances.
00069   std::vector<float> hmin (mesh.n_nodes(),
00070                            std::numeric_limits<float>::max());
00071 
00072   MeshBase::element_iterator       el  = mesh.active_elements_begin();
00073   const MeshBase::element_iterator end = mesh.active_elements_end();
00074 
00075   for (; el!=end; ++el)
00076     for (unsigned int n=0; n<(*el)->n_nodes(); n++)
00077       hmin[(*el)->node(n)] = std::min(hmin[(*el)->node(n)],
00078                                       static_cast<float>((*el)->hmin()));
00079 
00080 
00081   // Now actually move the nodes
00082   {
00083     const unsigned int seed = 123456;
00084 
00085     // seed the random number generator.
00086     // We'll loop from 1 to n_nodes on every processor, even those
00087     // that don't have a particular node, so that the pseudorandom
00088     // numbers will be the same everywhere.
00089     std::srand(seed);
00090 
00091     // If the node is on the boundary or
00092     // the node is not used by any element (hmin[n]<1.e20)
00093     // then we should not move it.
00094     // [Note: Testing for (in)equality might be wrong
00095     // (different types, namely float and double)]
00096     for (unsigned int n=0; n<mesh.n_nodes(); n++)
00097       if (!on_boundary[n] && (hmin[n] < 1.e20) )
00098         {
00099           // the direction, random but unit normalized
00100 
00101           Point dir( static_cast<Real>(std::rand())/static_cast<Real>(RAND_MAX),
00102                      (mesh.mesh_dimension() > 1) ?
00103                      static_cast<Real>(std::rand())/static_cast<Real>(RAND_MAX)
00104                      : 0.,
00105                      ((mesh.mesh_dimension() == 3) ?
00106                       static_cast<Real>(std::rand())/static_cast<Real>(RAND_MAX)
00107                       : 0.)
00108                      );
00109 
00110           dir(0) = (dir(0)-.5)*2.;
00111           if (mesh.mesh_dimension() > 1)
00112             dir(1) = (dir(1)-.5)*2.;
00113           if (mesh.mesh_dimension() == 3)
00114             dir(2) = (dir(2)-.5)*2.;
00115 
00116           dir = dir.unit();
00117 
00118           Node *node = mesh.node_ptr(n);
00119           if (!node)
00120             continue;
00121 
00122           (*node)(0) += dir(0)*factor*hmin[n];
00123           if (mesh.mesh_dimension() > 1)
00124             (*node)(1) += dir(1)*factor*hmin[n];
00125           if (mesh.mesh_dimension() == 3)
00126             (*node)(2) += dir(2)*factor*hmin[n];
00127         }
00128   }
00129 
00130 
00131   // All done
00132   STOP_LOG("distort()", "MeshTools::Modification");
00133 }
00134 
00135 
00136 
00137 void MeshTools::Modification::redistribute (MeshBase& mesh,
00138                                             const FunctionBase<Real> &mapfunc)
00139 {
00140   libmesh_assert (mesh.n_nodes());
00141   libmesh_assert (mesh.n_elem());
00142 
00143   START_LOG("redistribute()", "MeshTools::Modification");
00144 
00145   DenseVector<Real> output_vec(LIBMESH_DIM);
00146 
00147   // FIXME - we should thread this later.
00148   UniquePtr<FunctionBase<Real> > myfunc = mapfunc.clone();
00149 
00150   MeshBase::node_iterator       it  = mesh.nodes_begin();
00151   const MeshBase::node_iterator end = mesh.nodes_end();
00152 
00153   for (; it != end; ++it)
00154     {
00155       Node *node = *it;
00156 
00157       (*myfunc)(*node, output_vec);
00158 
00159       (*node)(0) = output_vec(0);
00160 #if LIBMESH_DIM > 1
00161       (*node)(1) = output_vec(1);
00162 #endif
00163 #if LIBMESH_DIM > 2
00164       (*node)(2) = output_vec(2);
00165 #endif
00166     }
00167 
00168   // All done
00169   STOP_LOG("redistribute()", "MeshTools::Modification");
00170 }
00171 
00172 
00173 
00174 void MeshTools::Modification::translate (MeshBase& mesh,
00175                                          const Real xt,
00176                                          const Real yt,
00177                                          const Real zt)
00178 {
00179   const Point p(xt, yt, zt);
00180 
00181   const MeshBase::node_iterator nd_end = mesh.nodes_end();
00182 
00183   for (MeshBase::node_iterator nd = mesh.nodes_begin();
00184        nd != nd_end; ++nd)
00185     **nd += p;
00186 }
00187 
00188 
00189 // void MeshTools::Modification::rotate2D (MeshBase& mesh,
00190 //                                         const Real alpha)
00191 // {
00192 //   libmesh_assert_not_equal_to (mesh.mesh_dimension(), 1);
00193 
00194 //   const Real pi = std::acos(-1);
00195 //   const Real  a = alpha/180.*pi;
00196 //   for (unsigned int n=0; n<mesh.n_nodes(); n++)
00197 //     {
00198 //       const Point p = mesh.node(n);
00199 //       const Real  x = p(0);
00200 //       const Real  y = p(1);
00201 //       const Real  z = p(2);
00202 //       mesh.node(n) = Point(std::cos(a)*x - std::sin(a)*y,
00203 //                            std::sin(a)*x + std::cos(a)*y,
00204 //                            z);
00205 //     }
00206 
00207 // }
00208 
00209 
00210 
00211 void MeshTools::Modification::rotate (MeshBase& mesh,
00212                                       const Real phi,
00213                                       const Real theta,
00214                                       const Real psi)
00215 {
00216 #if LIBMESH_DIM == 3
00217   const Real  p = -phi/180.*libMesh::pi;
00218   const Real  t = -theta/180.*libMesh::pi;
00219   const Real  s = -psi/180.*libMesh::pi;
00220   const Real sp = std::sin(p), cp = std::cos(p);
00221   const Real st = std::sin(t), ct = std::cos(t);
00222   const Real ss = std::sin(s), cs = std::cos(s);
00223 
00224   // We follow the convention described at http://mathworld.wolfram.com/EulerAngles.html
00225   // (equations 6-14 give the entries of the composite transformation matrix).
00226   // The rotations are performed sequentially about the z, x, and z axes, in that order.
00227   // A positive angle yields a counter-clockwise rotation about the axis in question.
00228   const MeshBase::node_iterator nd_end = mesh.nodes_end();
00229 
00230   for (MeshBase::node_iterator nd = mesh.nodes_begin();
00231        nd != nd_end; ++nd)
00232     {
00233       const Point pt = **nd;
00234       const Real  x  = pt(0);
00235       const Real  y  = pt(1);
00236       const Real  z  = pt(2);
00237       **nd = Point(( cp*cs-sp*ct*ss)*x + ( sp*cs+cp*ct*ss)*y + (st*ss)*z,
00238                    (-cp*ss-sp*ct*cs)*x + (-sp*ss+cp*ct*cs)*y + (st*cs)*z,
00239                    ( sp*st)*x          + (-cp*st)*y          + (ct)*z   );
00240     }
00241 #else
00242   libmesh_error_msg("MeshTools::Modification::rotate() requires libMesh to be compiled with LIBMESH_DIM==3");
00243 #endif
00244 }
00245 
00246 
00247 void MeshTools::Modification::scale (MeshBase& mesh,
00248                                      const Real xs,
00249                                      const Real ys,
00250                                      const Real zs)
00251 {
00252   const Real x_scale = xs;
00253   Real y_scale       = ys;
00254   Real z_scale       = zs;
00255 
00256   if (ys == 0.)
00257     {
00258       libmesh_assert_equal_to (zs, 0.);
00259 
00260       y_scale = z_scale = x_scale;
00261     }
00262 
00263   // Scale the x coordinate in all dimensions
00264   const MeshBase::node_iterator nd_end = mesh.nodes_end();
00265 
00266   for (MeshBase::node_iterator nd = mesh.nodes_begin();
00267        nd != nd_end; ++nd)
00268     (**nd)(0) *= x_scale;
00269 
00270 
00271   // Only scale the y coordinate in 2 and 3D
00272   if (mesh.spatial_dimension() < 2)
00273     return;
00274 
00275   for (MeshBase::node_iterator nd = mesh.nodes_begin();
00276        nd != nd_end; ++nd)
00277     (**nd)(1) *= y_scale;
00278 
00279   // Only scale the z coordinate in 3D
00280   if (mesh.spatial_dimension() < 3)
00281     return;
00282 
00283   for (MeshBase::node_iterator nd = mesh.nodes_begin();
00284        nd != nd_end; ++nd)
00285     (**nd)(2) *= z_scale;
00286 }
00287 
00288 
00289 
00290 
00291 // ------------------------------------------------------------
00292 // UnstructuredMesh class member functions for mesh modification
00293 void UnstructuredMesh::all_first_order ()
00294 {
00295   /*
00296    * when the mesh is not prepared,
00297    * at least renumber the nodes and
00298    * elements, so that the node ids
00299    * are correct
00300    */
00301   if (!this->_is_prepared)
00302     this->renumber_nodes_and_elements ();
00303 
00304   START_LOG("all_first_order()", "Mesh");
00305 
00309   std::vector<bool> node_touched_by_me(this->max_node_id(), false);
00310 
00316   element_iterator endit = elements_end();
00317   for (element_iterator it = elements_begin();
00318        it != endit; ++it)
00319     {
00320       Elem* so_elem = *it;
00321 
00322       libmesh_assert(so_elem);
00323 
00324       /*
00325        * build the first-order equivalent, add to
00326        * the new_elements list.
00327        */
00328       Elem* lo_elem = Elem::build
00329         (Elem::first_order_equivalent_type
00330          (so_elem->type()), so_elem->parent()).release();
00331 
00332       for (unsigned int s=0; s != so_elem->n_sides(); ++s)
00333         if (so_elem->neighbor(s) == remote_elem)
00334           lo_elem->set_neighbor(s, const_cast<RemoteElem*>(remote_elem));
00335 
00336 #ifdef LIBMESH_ENABLE_AMR
00337       /*
00338        * Reset the parent links of any child elements
00339        */
00340       if (so_elem->has_children())
00341         for (unsigned int c=0; c != so_elem->n_children(); ++c)
00342           {
00343             so_elem->child(c)->set_parent(lo_elem);
00344             lo_elem->add_child(so_elem->child(c), c);
00345           }
00346 
00347       /*
00348        * Reset the child link of any parent element
00349        */
00350       if (so_elem->parent())
00351         {
00352           unsigned int c =
00353             so_elem->parent()->which_child_am_i(so_elem);
00354           lo_elem->parent()->replace_child(lo_elem, c);
00355         }
00356 
00357       /*
00358        * Copy as much data to the new element as makes sense
00359        */
00360       lo_elem->set_p_level(so_elem->p_level());
00361       lo_elem->set_refinement_flag(so_elem->refinement_flag());
00362       lo_elem->set_p_refinement_flag(so_elem->p_refinement_flag());
00363 #endif
00364 
00365       libmesh_assert_equal_to (lo_elem->n_vertices(), so_elem->n_vertices());
00366 
00367       /*
00368        * By definition the vertices of the linear and
00369        * second order element are identically numbered.
00370        * transfer these.
00371        */
00372       for (unsigned int v=0; v < so_elem->n_vertices(); v++)
00373         {
00374           lo_elem->set_node(v) = so_elem->get_node(v);
00375           node_touched_by_me[lo_elem->node(v)] = true;
00376         }
00377 
00384       libmesh_assert_equal_to (lo_elem->n_sides(), so_elem->n_sides());
00385 
00386       for (unsigned short s=0; s<so_elem->n_sides(); s++)
00387         {
00388           const std::vector<boundary_id_type> boundary_ids =
00389             this->get_boundary_info().raw_boundary_ids (so_elem, s);
00390 
00391           this->get_boundary_info().add_side (lo_elem, s, boundary_ids);
00392         }
00393 
00394       /*
00395        * The new first-order element is ready.
00396        * Inserting it into the mesh will replace and delete
00397        * the second-order element.
00398        */
00399       lo_elem->set_id(so_elem->id());
00400       lo_elem->processor_id() = so_elem->processor_id();
00401       lo_elem->subdomain_id() = so_elem->subdomain_id();
00402       this->insert_elem(lo_elem);
00403     }
00404 
00405   const MeshBase::node_iterator nd_end = this->nodes_end();
00406   MeshBase::node_iterator nd = this->nodes_begin();
00407   while (nd != nd_end)
00408     {
00409       Node *the_node = *nd;
00410       ++nd;
00411       if (!node_touched_by_me[the_node->id()])
00412         this->delete_node(the_node);
00413     }
00414 
00415   STOP_LOG("all_first_order()", "Mesh");
00416 
00417   // On hanging nodes that used to also be second order nodes, we
00418   // might now have an invalid nodal processor_id()
00419   Partitioner::set_node_processor_ids(*this);
00420 
00421   // delete or renumber nodes, etc
00422   this->prepare_for_use(/*skip_renumber =*/ false);
00423 }
00424 
00425 
00426 
00427 void UnstructuredMesh::all_second_order (const bool full_ordered)
00428 {
00429   // This function must be run on all processors at once
00430   parallel_object_only();
00431 
00432   /*
00433    * when the mesh is not prepared,
00434    * at least renumber the nodes and
00435    * elements, so that the node ids
00436    * are correct
00437    */
00438   if (!this->_is_prepared)
00439     this->renumber_nodes_and_elements ();
00440 
00441   /*
00442    * If the mesh is empty
00443    * then we have nothing to do
00444    */
00445   if (!this->n_elem())
00446     return;
00447 
00448   /*
00449    * If the mesh is already second order
00450    * then we have nothing to do.
00451    * We have to test for this in a round-about way to avoid
00452    * a bug on distributed parallel meshes with more processors
00453    * than elements.
00454    */
00455   bool already_second_order = false;
00456   if (this->elements_begin() != this->elements_end() &&
00457       (*(this->elements_begin()))->default_order() != FIRST)
00458     already_second_order = true;
00459   this->comm().max(already_second_order);
00460   if (already_second_order)
00461     return;
00462 
00463   START_LOG("all_second_order()", "Mesh");
00464 
00465   /*
00466    * this map helps in identifying second order
00467    * nodes.  Namely, a second-order node:
00468    * - edge node
00469    * - face node
00470    * - bubble node
00471    * is uniquely defined through a set of adjacent
00472    * vertices.  This set of adjacent vertices is
00473    * used to identify already added higher-order
00474    * nodes.  We are safe to use node id's since we
00475    * make sure that these are correctly numbered.
00476    */
00477   std::map<std::vector<dof_id_type>, Node*> adj_vertices_to_so_nodes;
00478 
00479   /*
00480    * for speed-up of the \p add_point() method, we
00481    * can reserve memory.  Guess the number of additional
00482    * nodes for different dimensions
00483    */
00484   switch (this->mesh_dimension())
00485     {
00486     case 1:
00487       /*
00488        * in 1D, there can only be order-increase from Edge2
00489        * to Edge3.  Something like 1/2 of n_nodes() have
00490        * to be added
00491        */
00492       this->reserve_nodes(static_cast<unsigned int>
00493                           (1.5*static_cast<double>(this->n_nodes())));
00494       break;
00495 
00496     case 2:
00497       /*
00498        * in 2D, either refine from Tri3 to Tri6 (double the nodes)
00499        * or from Quad4 to Quad8 (again, double) or Quad9 (2.25 that much)
00500        */
00501       this->reserve_nodes(static_cast<unsigned int>
00502                           (2*static_cast<double>(this->n_nodes())));
00503       break;
00504 
00505 
00506     case 3:
00507       /*
00508        * in 3D, either refine from Tet4 to Tet10 (factor = 2.5) up to
00509        * Hex8 to Hex27 (something  > 3).  Since in 3D there _are_ already
00510        * quite some nodes, and since we do not want to overburden the memory by
00511        * a too conservative guess, use the lower bound
00512        */
00513       this->reserve_nodes(static_cast<unsigned int>
00514                           (2.5*static_cast<double>(this->n_nodes())));
00515       break;
00516 
00517     default:
00518       // Hm?
00519       libmesh_error_msg("Unknown mesh dimension " << this->mesh_dimension());
00520     }
00521 
00522 
00523 
00524   /*
00525    * form a vector that will hold the node id's of
00526    * the vertices that are adjacent to the son-th
00527    * second-order node.  Pull this outside of the
00528    * loop so that silly compilers don't repeatedly
00529    * create and destroy the vector.
00530    */
00531   std::vector<dof_id_type> adjacent_vertices_ids;
00532 
00539   const_element_iterator endit = elements_end();
00540   for (const_element_iterator it = elements_begin();
00541        it != endit; ++it)
00542     {
00543       // the linear-order element
00544       const Elem* lo_elem = *it;
00545 
00546       libmesh_assert(lo_elem);
00547 
00548       // make sure it is linear order
00549       if (lo_elem->default_order() != FIRST)
00550         libmesh_error_msg("ERROR: This is not a linear element: type=" << lo_elem->type());
00551 
00552       // this does _not_ work for refined elements
00553       libmesh_assert_equal_to (lo_elem->level (), 0);
00554 
00555       /*
00556        * build the second-order equivalent, add to
00557        * the new_elements list.  Note that this here
00558        * is the only point where \p full_ordered
00559        * is necessary.  The remaining code works well
00560        * for either type of seconrd-order equivalent, e.g.
00561        * Hex20 or Hex27, as equivalents for Hex8
00562        */
00563       Elem* so_elem =
00564         Elem::build (Elem::second_order_equivalent_type(lo_elem->type(),
00565                                                         full_ordered) ).release();
00566 
00567       libmesh_assert_equal_to (lo_elem->n_vertices(), so_elem->n_vertices());
00568 
00569 
00570       /*
00571        * By definition the vertices of the linear and
00572        * second order element are identically numbered.
00573        * transfer these.
00574        */
00575       for (unsigned int v=0; v < lo_elem->n_vertices(); v++)
00576         so_elem->set_node(v) = lo_elem->get_node(v);
00577 
00578       /*
00579        * Now handle the additional mid-side nodes.  This
00580        * is simply handled through a map that remembers
00581        * the already-added nodes.  This map maps the global
00582        * ids of the vertices (that uniquely define this
00583        * higher-order node) to the new node.
00584        * Notation: son = second-order node
00585        */
00586       const unsigned int son_begin = so_elem->n_vertices();
00587       const unsigned int son_end   = so_elem->n_nodes();
00588 
00589 
00590       for (unsigned int son=son_begin; son<son_end; son++)
00591         {
00592           const unsigned int n_adjacent_vertices =
00593             so_elem->n_second_order_adjacent_vertices(son);
00594 
00595           adjacent_vertices_ids.resize(n_adjacent_vertices);
00596 
00597           for (unsigned int v=0; v<n_adjacent_vertices; v++)
00598             adjacent_vertices_ids[v] =
00599               so_elem->node( so_elem->second_order_adjacent_vertex(son,v) );
00600 
00601           /*
00602            * \p adjacent_vertices_ids is now in order of the current
00603            * side.  sort it, so that comparisons  with the
00604            * \p adjacent_vertices_ids created through other elements'
00605            * sides can match
00606            */
00607           std::sort(adjacent_vertices_ids.begin(),
00608                     adjacent_vertices_ids.end());
00609 
00610 
00611           // does this set of vertices already has a mid-node added?
00612           std::pair<std::map<std::vector<dof_id_type>, Node*>::iterator,
00613             std::map<std::vector<dof_id_type>, Node*>::iterator>
00614             pos = adj_vertices_to_so_nodes.equal_range (adjacent_vertices_ids);
00615 
00616           // no, not added yet
00617           if (pos.first == pos.second)
00618             {
00619               /*
00620                * for this set of vertices, there is no
00621                * second_order node yet.  Add it.
00622                *
00623                * compute the location of the new node as
00624                * the average over the adjacent vertices.
00625                */
00626               Point new_location = this->point(adjacent_vertices_ids[0]);
00627               for (unsigned int v=1; v<n_adjacent_vertices; v++)
00628                 new_location += this->point(adjacent_vertices_ids[v]);
00629 
00630               new_location /= static_cast<Real>(n_adjacent_vertices);
00631 
00632               /* Add the new point to the mesh, giving it a globally
00633                * well-defined processor id.
00634                */
00635               Node* so_node = this->add_point
00636                 (new_location, DofObject::invalid_id,
00637                  this->node(adjacent_vertices_ids[0]).processor_id());
00638 
00639               /*
00640                * insert the new node with its defining vertex
00641                * set into the map, and relocate pos to this
00642                * new entry, so that the so_elem can use
00643                * \p pos for inserting the node
00644                */
00645               adj_vertices_to_so_nodes.insert(pos.first,
00646                                               std::make_pair(adjacent_vertices_ids,
00647                                                              so_node));
00648 
00649               so_elem->set_node(son) = so_node;
00650             }
00651           // yes, already added.
00652           else
00653             {
00654               libmesh_assert(pos.first->second);
00655 
00656               so_elem->set_node(son) = pos.first->second;
00657             }
00658         }
00659 
00660 
00672       libmesh_assert_equal_to (lo_elem->n_sides(), so_elem->n_sides());
00673 
00674       for (unsigned short s=0; s<lo_elem->n_sides(); s++)
00675         {
00676           const std::vector<boundary_id_type> boundary_ids =
00677             this->get_boundary_info().raw_boundary_ids (lo_elem, s);
00678 
00679           this->get_boundary_info().add_side (so_elem, s, boundary_ids);
00680 
00681           if (lo_elem->neighbor(s) == remote_elem)
00682             so_elem->set_neighbor(s, const_cast<RemoteElem*>(remote_elem));
00683         }
00684 
00685       /*
00686        * The new second-order element is ready.
00687        * Inserting it into the mesh will replace and delete
00688        * the first-order element.
00689        */
00690       so_elem->set_id(lo_elem->id());
00691       so_elem->processor_id() = lo_elem->processor_id();
00692       so_elem->subdomain_id() = lo_elem->subdomain_id();
00693       this->insert_elem(so_elem);
00694     }
00695 
00696   // we can clear the map
00697   adj_vertices_to_so_nodes.clear();
00698 
00699 
00700   STOP_LOG("all_second_order()", "Mesh");
00701 
00702   // In a ParallelMesh our ghost node processor ids may be bad and
00703   // the ids of nodes touching remote elements may be inconsistent.
00704   // Fix them.
00705   if (!this->is_serial())
00706     MeshCommunication().make_nodes_parallel_consistent (*this);
00707 
00708   // renumber nodes, elements etc
00709   this->prepare_for_use(/*skip_renumber =*/ false);
00710 }
00711 
00712 
00713 
00714 
00715 
00716 
00717 void MeshTools::Modification::all_tri (MeshBase& mesh)
00718 {
00719   // The number of elements in the original mesh before any additions
00720   // or deletions.
00721   const dof_id_type n_orig_elem = mesh.n_elem();
00722 
00723   // We store pointers to the newly created elements in a vector
00724   // until they are ready to be added to the mesh.  This is because
00725   // adding new elements on the fly can cause reallocation and invalidation
00726   // of existing iterators.
00727   std::vector<Elem*> new_elements;
00728   new_elements.reserve (2*n_orig_elem);
00729 
00730   // If the original mesh has boundary data, we carry that over
00731   // to the new mesh with triangular elements.
00732   const bool mesh_has_boundary_data = (mesh.get_boundary_info().n_boundary_ids() > 0);
00733 
00734   // Temporary vectors to store the new boundary element pointers, side numbers, and boundary ids
00735   std::vector<Elem*> new_bndry_elements;
00736   std::vector<unsigned short int> new_bndry_sides;
00737   std::vector<boundary_id_type> new_bndry_ids;
00738 
00739   // Iterate over the elements, splitting QUADS into
00740   // pairs of conforming triangles.
00741   // FIXME: This algorithm does not work on refined grids!
00742   {
00743     MeshBase::element_iterator       el  = mesh.elements_begin();
00744     const MeshBase::element_iterator end = mesh.elements_end();
00745 
00746     for (; el!=end; ++el)
00747       {
00748         Elem* elem = *el;
00749 
00750         const ElemType etype = elem->type();
00751 
00752         // all_tri currently only works on coarse meshes
00753         libmesh_assert (!elem->parent());
00754 
00755         // We split the quads using the shorter of the two diagonals
00756         // to maintain the best angle properties.
00757         bool edge_swap = false;
00758 
00759         // True if we actually split the current element.
00760         bool split_elem = false;
00761 
00762         // The two new triangular elements we will split the quad into.
00763         Elem* tri0 = NULL;
00764         Elem* tri1 = NULL;
00765 
00766 
00767         switch (etype)
00768           {
00769           case QUAD4:
00770             {
00771               split_elem = true;
00772 
00773               tri0 = new Tri3;
00774               tri1 = new Tri3;
00775 
00776               // Check for possible edge swap
00777               if ((elem->point(0) - elem->point(2)).size() <
00778                   (elem->point(1) - elem->point(3)).size())
00779                 {
00780                   tri0->set_node(0) = elem->get_node(0);
00781                   tri0->set_node(1) = elem->get_node(1);
00782                   tri0->set_node(2) = elem->get_node(2);
00783 
00784                   tri1->set_node(0) = elem->get_node(0);
00785                   tri1->set_node(1) = elem->get_node(2);
00786                   tri1->set_node(2) = elem->get_node(3);
00787                 }
00788 
00789               else
00790                 {
00791                   edge_swap=true;
00792 
00793                   tri0->set_node(0) = elem->get_node(0);
00794                   tri0->set_node(1) = elem->get_node(1);
00795                   tri0->set_node(2) = elem->get_node(3);
00796 
00797                   tri1->set_node(0) = elem->get_node(1);
00798                   tri1->set_node(1) = elem->get_node(2);
00799                   tri1->set_node(2) = elem->get_node(3);
00800                 }
00801 
00802 
00803               break;
00804             }
00805 
00806           case QUAD8:
00807             {
00808               split_elem =  true;
00809 
00810               tri0 = new Tri6;
00811               tri1 = new Tri6;
00812 
00813               Node* new_node = mesh.add_point( (mesh.node(elem->node(0)) +
00814                                                 mesh.node(elem->node(1)) +
00815                                                 mesh.node(elem->node(2)) +
00816                                                 mesh.node(elem->node(3)) / 4)
00817                                                );
00818 
00819               // Check for possible edge swap
00820               if ((elem->point(0) - elem->point(2)).size() <
00821                   (elem->point(1) - elem->point(3)).size())
00822                 {
00823                   tri0->set_node(0) = elem->get_node(0);
00824                   tri0->set_node(1) = elem->get_node(1);
00825                   tri0->set_node(2) = elem->get_node(2);
00826                   tri0->set_node(3) = elem->get_node(4);
00827                   tri0->set_node(4) = elem->get_node(5);
00828                   tri0->set_node(5) = new_node;
00829 
00830                   tri1->set_node(0) = elem->get_node(0);
00831                   tri1->set_node(1) = elem->get_node(2);
00832                   tri1->set_node(2) = elem->get_node(3);
00833                   tri1->set_node(3) = new_node;
00834                   tri1->set_node(4) = elem->get_node(6);
00835                   tri1->set_node(5) = elem->get_node(7);
00836 
00837                 }
00838 
00839               else
00840                 {
00841                   edge_swap=true;
00842 
00843                   tri0->set_node(0) = elem->get_node(3);
00844                   tri0->set_node(1) = elem->get_node(0);
00845                   tri0->set_node(2) = elem->get_node(1);
00846                   tri0->set_node(3) = elem->get_node(7);
00847                   tri0->set_node(4) = elem->get_node(4);
00848                   tri0->set_node(5) = new_node;
00849 
00850                   tri1->set_node(0) = elem->get_node(1);
00851                   tri1->set_node(1) = elem->get_node(2);
00852                   tri1->set_node(2) = elem->get_node(3);
00853                   tri1->set_node(3) = elem->get_node(5);
00854                   tri1->set_node(4) = elem->get_node(6);
00855                   tri1->set_node(5) = new_node;
00856                 }
00857 
00858               break;
00859             }
00860 
00861           case QUAD9:
00862             {
00863               split_elem =  true;
00864 
00865               tri0 = new Tri6;
00866               tri1 = new Tri6;
00867 
00868               // Check for possible edge swap
00869               if ((elem->point(0) - elem->point(2)).size() <
00870                   (elem->point(1) - elem->point(3)).size())
00871                 {
00872                   tri0->set_node(0) = elem->get_node(0);
00873                   tri0->set_node(1) = elem->get_node(1);
00874                   tri0->set_node(2) = elem->get_node(2);
00875                   tri0->set_node(3) = elem->get_node(4);
00876                   tri0->set_node(4) = elem->get_node(5);
00877                   tri0->set_node(5) = elem->get_node(8);
00878 
00879                   tri1->set_node(0) = elem->get_node(0);
00880                   tri1->set_node(1) = elem->get_node(2);
00881                   tri1->set_node(2) = elem->get_node(3);
00882                   tri1->set_node(3) = elem->get_node(8);
00883                   tri1->set_node(4) = elem->get_node(6);
00884                   tri1->set_node(5) = elem->get_node(7);
00885                 }
00886 
00887               else
00888                 {
00889                   edge_swap=true;
00890 
00891                   tri0->set_node(0) = elem->get_node(0);
00892                   tri0->set_node(1) = elem->get_node(1);
00893                   tri0->set_node(2) = elem->get_node(3);
00894                   tri0->set_node(3) = elem->get_node(4);
00895                   tri0->set_node(4) = elem->get_node(8);
00896                   tri0->set_node(5) = elem->get_node(7);
00897 
00898                   tri1->set_node(0) = elem->get_node(1);
00899                   tri1->set_node(1) = elem->get_node(2);
00900                   tri1->set_node(2) = elem->get_node(3);
00901                   tri1->set_node(3) = elem->get_node(5);
00902                   tri1->set_node(4) = elem->get_node(6);
00903                   tri1->set_node(5) = elem->get_node(8);
00904                 }
00905 
00906               break;
00907             }
00908             // No need to split elements that are already triangles
00909           case TRI3:
00910           case TRI6:
00911             continue;
00912             // Try to ignore non-2D elements for now
00913           default:
00914             {
00915               libMesh::err << "Warning, encountered non-2D element "
00916                            << Utility::enum_to_string<ElemType>(etype)
00917                            << " in MeshTools::Modification::all_tri(), hope that's OK..."
00918                            << std::endl;
00919             }
00920           } // end switch (etype)
00921 
00922 
00923 
00924         if (split_elem)
00925           {
00926             // Be sure the correct ID's are also set for tri0 and
00927             // tri1.
00928             tri0->processor_id() = elem->processor_id();
00929             tri0->subdomain_id() = elem->subdomain_id();
00930             tri1->processor_id() = elem->processor_id();
00931             tri1->subdomain_id() = elem->subdomain_id();
00932 
00933             if (mesh_has_boundary_data)
00934               {
00935                 for (unsigned short sn=0; sn<elem->n_sides(); ++sn)
00936                   {
00937                     const std::vector<boundary_id_type>& bc_ids =
00938                       mesh.get_boundary_info().boundary_ids(*el, sn);
00939                     for (std::vector<boundary_id_type>::const_iterator id_it=bc_ids.begin(); id_it!=bc_ids.end(); ++id_it)
00940                       {
00941                         const boundary_id_type b_id = *id_it;
00942 
00943                         if (b_id != BoundaryInfo::invalid_id)
00944                           {
00945                             // Add the boundary ID to the list of new boundary ids
00946                             new_bndry_ids.push_back(b_id);
00947 
00948                             // Convert the boundary side information of the old element to
00949                             // boundary side information for the new element.
00950                             if (!edge_swap)
00951                               {
00952                                 switch (sn)
00953                                   {
00954                                   case 0:
00955                                     {
00956                                       // New boundary side is Tri 0, side 0
00957                                       new_bndry_elements.push_back(tri0);
00958                                       new_bndry_sides.push_back(0);
00959                                       break;
00960                                     }
00961                                   case 1:
00962                                     {
00963                                       // New boundary side is Tri 0, side 1
00964                                       new_bndry_elements.push_back(tri0);
00965                                       new_bndry_sides.push_back(1);
00966                                       break;
00967                                     }
00968                                   case 2:
00969                                     {
00970                                       // New boundary side is Tri 1, side 1
00971                                       new_bndry_elements.push_back(tri1);
00972                                       new_bndry_sides.push_back(1);
00973                                       break;
00974                                     }
00975                                   case 3:
00976                                     {
00977                                       // New boundary side is Tri 1, side 2
00978                                       new_bndry_elements.push_back(tri1);
00979                                       new_bndry_sides.push_back(2);
00980                                       break;
00981                                     }
00982 
00983                                   default:
00984                                     libmesh_error_msg("Quad4/8/9 cannot have more than 4 sides.");
00985                                   }
00986                               }
00987 
00988                             else // edge_swap==true
00989                               {
00990                                 switch (sn)
00991                                   {
00992                                   case 0:
00993                                     {
00994                                       // New boundary side is Tri 0, side 0
00995                                       new_bndry_elements.push_back(tri0);
00996                                       new_bndry_sides.push_back(0);
00997                                       break;
00998                                     }
00999                                   case 1:
01000                                     {
01001                                       // New boundary side is Tri 1, side 0
01002                                       new_bndry_elements.push_back(tri1);
01003                                       new_bndry_sides.push_back(0);
01004                                       break;
01005                                     }
01006                                   case 2:
01007                                     {
01008                                       // New boundary side is Tri 1, side 1
01009                                       new_bndry_elements.push_back(tri1);
01010                                       new_bndry_sides.push_back(1);
01011                                       break;
01012                                     }
01013                                   case 3:
01014                                     {
01015                                       // New boundary side is Tri 0, side 2
01016                                       new_bndry_elements.push_back(tri0);
01017                                       new_bndry_sides.push_back(2);
01018                                       break;
01019                                     }
01020 
01021                                   default:
01022                                     libmesh_error_msg("Quad4/8/9 cannot have more than 4 sides.");
01023                                   }
01024                               } // end edge_swap==true
01025                           } // end if (b_id != BoundaryInfo::invalid_id)
01026                       } // end for loop over boundary IDs
01027                   } // end for loop over sides
01028 
01029                 // Remove the original element from the BoundaryInfo structure.
01030                 mesh.get_boundary_info().remove(elem);
01031 
01032               } // end if (mesh_has_boundary_data)
01033 
01034 
01035             // On a distributed mesh, we need to preserve remote_elem
01036             // links, since prepare_for_use can't reconstruct them for
01037             // us.
01038             for (unsigned int sn=0; sn<elem->n_sides(); ++sn)
01039               {
01040                 if (elem->neighbor(sn) == remote_elem)
01041                   {
01042                     // Create a remote_elem link on one of the new
01043                     // elements corresponding to the link from the old
01044                     // element.
01045                     if (!edge_swap)
01046                       {
01047                         switch (sn)
01048                           {
01049                           case 0:
01050                             {
01051                               // New remote side is Tri 0, side 0
01052                               tri0->set_neighbor(0, const_cast<RemoteElem*>(remote_elem));
01053                               break;
01054                             }
01055                           case 1:
01056                             {
01057                               // New remote side is Tri 0, side 1
01058                               tri0->set_neighbor(1, const_cast<RemoteElem*>(remote_elem));
01059                               break;
01060                             }
01061                           case 2:
01062                             {
01063                               // New remote side is Tri 1, side 1
01064                               tri1->set_neighbor(1, const_cast<RemoteElem*>(remote_elem));
01065                               break;
01066                             }
01067                           case 3:
01068                             {
01069                               // New remote side is Tri 1, side 2
01070                               tri1->set_neighbor(2, const_cast<RemoteElem*>(remote_elem));
01071                               break;
01072                             }
01073 
01074                           default:
01075                             libmesh_error_msg("Quad4/8/9 cannot have more than 4 sides.");
01076                           }
01077                       }
01078 
01079                     else // edge_swap==true
01080                       {
01081                         switch (sn)
01082                           {
01083                           case 0:
01084                             {
01085                               // New remote side is Tri 0, side 0
01086                               tri0->set_neighbor(0, const_cast<RemoteElem*>(remote_elem));
01087                               break;
01088                             }
01089                           case 1:
01090                             {
01091                               // New remote side is Tri 1, side 0
01092                               tri1->set_neighbor(0, const_cast<RemoteElem*>(remote_elem));
01093                               break;
01094                             }
01095                           case 2:
01096                             {
01097                               // New remote side is Tri 1, side 1
01098                               tri1->set_neighbor(1, const_cast<RemoteElem*>(remote_elem));
01099                               break;
01100                             }
01101                           case 3:
01102                             {
01103                               // New remote side is Tri 0, side 2
01104                               tri0->set_neighbor(2, const_cast<RemoteElem*>(remote_elem));
01105                               break;
01106                             }
01107 
01108                           default:
01109                             libmesh_error_msg("Quad4/8/9 cannot have more than 4 sides.");
01110                           }
01111                       } // end edge_swap==true
01112                   } // end if (elem->neighbor(sn) == remote_elem)
01113               } // end for loop over sides
01114 
01115             // Determine new IDs for the split elements which will be
01116             // the same on all processors, therefore keeping the Mesh
01117             // in sync.  Note: we offset the new IDs by n_orig_elem to
01118             // avoid overwriting any of the original IDs, this assumes
01119             // they were contiguously-numbered to begin with...
01120             tri0->set_id( n_orig_elem + 2*elem->id() + 0 );
01121             tri1->set_id( n_orig_elem + 2*elem->id() + 1 );
01122 
01123             // Add the newly-created triangles to the temporary vector of new elements.
01124             new_elements.push_back(tri0);
01125             new_elements.push_back(tri1);
01126 
01127             // Delete the original element
01128             mesh.delete_elem(elem);
01129           } // end if (split_elem)
01130       } // End for loop over elements
01131   } // end scope
01132 
01133 
01134   // Now, iterate over the new elements vector, and add them each to
01135   // the Mesh.
01136   {
01137     std::vector<Elem*>::iterator el        = new_elements.begin();
01138     const std::vector<Elem*>::iterator end = new_elements.end();
01139     for (; el != end; ++el)
01140       mesh.add_elem(*el);
01141   }
01142 
01143   if (mesh_has_boundary_data)
01144     {
01145       // By this time, we should have removed all of the original boundary sides
01146       // - except on a hybrid mesh, where we can't "start from a blank slate"! - RHS
01147       // libmesh_assert_equal_to (mesh.get_boundary_info().n_boundary_conds(), 0);
01148 
01149       // Clear the boundary info, to be sure and start from a blank slate.
01150       // mesh.get_boundary_info().clear();
01151 
01152       // If the old mesh had boundary data, the new mesh better have some.
01153       libmesh_assert_greater (new_bndry_elements.size(), 0);
01154 
01155       // We should also be sure that the lengths of the new boundary data vectors
01156       // are all the same.
01157       libmesh_assert_equal_to (new_bndry_elements.size(), new_bndry_sides.size());
01158       libmesh_assert_equal_to (new_bndry_sides.size(), new_bndry_ids.size());
01159 
01160       // Add the new boundary info to the mesh
01161       for (unsigned int s=0; s<new_bndry_elements.size(); ++s)
01162         mesh.get_boundary_info().add_side(new_bndry_elements[s],
01163                                           new_bndry_sides[s],
01164                                           new_bndry_ids[s]);
01165     }
01166 
01167 
01168   // Prepare the newly created mesh for use.
01169   mesh.prepare_for_use(/*skip_renumber =*/ false);
01170 
01171   // Let the new_elements and new_bndry_elements vectors go out of scope.
01172 }
01173 
01174 
01175 void MeshTools::Modification::smooth (MeshBase& mesh,
01176                                       const unsigned int n_iterations,
01177                                       const Real power)
01178 {
01182   libmesh_assert_equal_to (mesh.mesh_dimension(), 2);
01183 
01184   /*
01185    * find the boundary nodes
01186    */
01187   std::vector<bool>  on_boundary;
01188   MeshTools::find_boundary_nodes(mesh, on_boundary);
01189 
01190   for (unsigned int iter=0; iter<n_iterations; iter++)
01191 
01192     {
01193       /*
01194        * loop over the mesh refinement level
01195        */
01196       unsigned int n_levels = MeshTools::n_levels(mesh);
01197       for (unsigned int refinement_level=0; refinement_level != n_levels;
01198            refinement_level++)
01199         {
01200           // initialize the storage (have to do it on every level to get empty vectors
01201           std::vector<Point> new_positions;
01202           std::vector<Real>   weight;
01203           new_positions.resize(mesh.n_nodes());
01204           weight.resize(mesh.n_nodes());
01205 
01206           {
01207             /*
01208              * Loop over the elements to calculate new node positions
01209              */
01210             MeshBase::element_iterator       el  = mesh.level_elements_begin(refinement_level);
01211             const MeshBase::element_iterator end = mesh.level_elements_end(refinement_level);
01212 
01213             for (; el != end; ++el)
01214               {
01215                 /*
01216                  * Constant handle for the element
01217                  */
01218                 const Elem* elem = *el;
01219 
01220                 /*
01221                  * We relax all nodes on level 0 first
01222                  * If the element is refined (level > 0), we interpolate the
01223                  * parents nodes with help of the embedding matrix
01224                  */
01225                 if (refinement_level == 0)
01226                   {
01227                     for (unsigned int s=0; s<elem->n_neighbors(); s++)
01228                       {
01229                         /*
01230                          * Only operate on sides which are on the
01231                          * boundary or for which the current element's
01232                          * id is greater than its neighbor's.
01233                          * Sides get only built once.
01234                          */
01235                         if ((elem->neighbor(s) != NULL) &&
01236                             (elem->id() > elem->neighbor(s)->id()) )
01237                           {
01238                             UniquePtr<Elem> side(elem->build_side(s));
01239 
01240                             Node* node0 = side->get_node(0);
01241                             Node* node1 = side->get_node(1);
01242 
01243                             Real node_weight = 1.;
01244                             // calculate the weight of the nodes
01245                             if (power > 0)
01246                               {
01247                                 Point diff = (*node0)-(*node1);
01248                                 node_weight = std::pow( diff.size(), power );
01249                               }
01250 
01251                             const dof_id_type id0 = node0->id(), id1 = node1->id();
01252                             new_positions[id0].add_scaled( *node1, node_weight );
01253                             new_positions[id1].add_scaled( *node0, node_weight );
01254                             weight[id0] += node_weight;
01255                             weight[id1] += node_weight;
01256                           }
01257                       } // element neighbor loop
01258                   }
01259 #ifdef LIBMESH_ENABLE_AMR
01260                 else   // refinement_level > 0
01261                   {
01262                     /*
01263                      * Find the positions of the hanging nodes of refined elements.
01264                      * We do this by calculating their position based on the parent
01265                      * (one level less refined) element, and the embedding matrix
01266                      */
01267 
01268                     const Elem* parent = elem->parent();
01269 
01270                     /*
01271                      * find out which child I am
01272                      */
01273                     for (unsigned int c=0; c < parent->n_children(); c++)
01274                       {
01275                         if (parent->child(c) == elem)
01276                           {
01277                             /*
01278                              *loop over the childs (that is, the current elements) nodes
01279                              */
01280                             for (unsigned int nc=0; nc < elem->n_nodes(); nc++)
01281                               {
01282                                 /*
01283                                  * the new position of the node
01284                                  */
01285                                 Point point;
01286                                 for (unsigned int n=0; n<parent->n_nodes(); n++)
01287                                   {
01288                                     /*
01289                                      * The value from the embedding matrix
01290                                      */
01291                                     const float em_val = parent->embedding_matrix(c,nc,n);
01292 
01293                                     if (em_val != 0.)
01294                                       point.add_scaled (parent->point(n), em_val);
01295                                   }
01296 
01297                                 const dof_id_type id = elem->get_node(nc)->id();
01298                                 new_positions[id] = point;
01299                                 weight[id] = 1.;
01300                               }
01301 
01302                           } // if parent->child == elem
01303                       } // for parent->n_children
01304                   } // if element refinement_level
01305 #endif // #ifdef LIBMESH_ENABLE_AMR
01306 
01307               } // element loop
01308 
01309             /*
01310              * finally reposition the vertex nodes
01311              */
01312             for (unsigned int nid=0; nid<mesh.n_nodes(); ++nid)
01313               if (!on_boundary[nid] && weight[nid] > 0.)
01314                 mesh.node(nid) = new_positions[nid]/weight[nid];
01315           }
01316 
01317           {
01318             /*
01319              * Now handle the additional second_order nodes by calculating
01320              * their position based on the vertex postitions
01321              * we do a second loop over the level elements
01322              */
01323             MeshBase::element_iterator       el  = mesh.level_elements_begin(refinement_level);
01324             const MeshBase::element_iterator end = mesh.level_elements_end(refinement_level);
01325 
01326             for (; el != end; ++el)
01327               {
01328                 /*
01329                  * Constant handle for the element
01330                  */
01331                 const Elem* elem = *el;
01332                 const unsigned int son_begin = elem->n_vertices();
01333                 const unsigned int son_end   = elem->n_nodes();
01334                 for (unsigned int n=son_begin; n<son_end; n++)
01335                   {
01336                     const unsigned int n_adjacent_vertices =
01337                       elem->n_second_order_adjacent_vertices(n);
01338 
01339                     Point point;
01340                     for (unsigned int v=0; v<n_adjacent_vertices; v++)
01341                       point.add(elem->point( elem->second_order_adjacent_vertex(n,v) ));
01342 
01343                     const dof_id_type id = elem->get_node(n)->id();
01344                     mesh.node(id) = point/n_adjacent_vertices;
01345                   }
01346               }
01347           }
01348 
01349         } // refinement_level loop
01350 
01351     } // end iteration
01352 }
01353 
01354 
01355 
01356 #ifdef LIBMESH_ENABLE_AMR
01357 void MeshTools::Modification::flatten(MeshBase& mesh)
01358 {
01359   // Algorithm:
01360   // .) For each active element in the mesh: construct a
01361   //    copy which is the same in every way *except* it is
01362   //    a level 0 element.  Store the pointers to these in
01363   //    a separate vector. Save any boundary information as well.
01364   //    Delete the active element from the mesh.
01365   // .) Loop over all (remaining) elements in the mesh, delete them.
01366   // .) Add the level-0 copies back to the mesh
01367 
01368   // Temporary storage for new element pointers
01369   std::vector<Elem*> new_elements;
01370 
01371   // BoundaryInfo Storage for element ids, sides, and BC ids
01372   std::vector<Elem*>              saved_boundary_elements;
01373   std::vector<boundary_id_type>   saved_bc_ids;
01374   std::vector<unsigned short int> saved_bc_sides;
01375 
01376   // Reserve a reasonable amt. of space for each
01377   new_elements.reserve(mesh.n_active_elem());
01378   saved_boundary_elements.reserve(mesh.get_boundary_info().n_boundary_conds());
01379   saved_bc_ids.reserve(mesh.get_boundary_info().n_boundary_conds());
01380   saved_bc_sides.reserve(mesh.get_boundary_info().n_boundary_conds());
01381   {
01382     MeshBase::element_iterator       it  = mesh.active_elements_begin();
01383     const MeshBase::element_iterator end = mesh.active_elements_end();
01384 
01385     for (; it != end; ++it)
01386       {
01387         Elem* elem = *it;
01388 
01389         // Make a new element of the same type
01390         Elem* copy = Elem::build(elem->type()).release();
01391 
01392         // Set node pointers (they still point to nodes in the original mesh)
01393         for(unsigned int n=0; n<elem->n_nodes(); n++)
01394           copy->set_node(n) = elem->get_node(n);
01395 
01396         // Copy over ids
01397         copy->processor_id() = elem->processor_id();
01398         copy->subdomain_id() = elem->subdomain_id();
01399 
01400         // Retain the original element's ID as well, otherwise ParallelMesh will
01401         // try to create one for you...
01402         copy->set_id( elem->id() );
01403 
01404         // This element could have boundary info or ParallelMesh
01405         // remote_elem links as well.  We need to save the (elem,
01406         // side, bc_id) triples and those links
01407         for (unsigned short s=0; s<elem->n_sides(); s++)
01408           {
01409             if (elem->neighbor(s) == remote_elem)
01410               copy->set_neighbor(s, const_cast<RemoteElem*>(remote_elem));
01411 
01412             const std::vector<boundary_id_type>& bc_ids =
01413               mesh.get_boundary_info().boundary_ids(elem,s);
01414             for (std::vector<boundary_id_type>::const_iterator id_it=bc_ids.begin(); id_it!=bc_ids.end(); ++id_it)
01415               {
01416                 const boundary_id_type bc_id = *id_it;
01417 
01418                 if (bc_id != BoundaryInfo::invalid_id)
01419                   {
01420                     saved_boundary_elements.push_back(copy);
01421                     saved_bc_ids.push_back(bc_id);
01422                     saved_bc_sides.push_back(s);
01423                   }
01424               }
01425           }
01426 
01427 
01428         // We're done with this element
01429         mesh.delete_elem(elem);
01430 
01431         // But save the copy
01432         new_elements.push_back(copy);
01433       }
01434 
01435     // Make sure we saved the same number of boundary conditions
01436     // in each vector.
01437     libmesh_assert_equal_to (saved_boundary_elements.size(), saved_bc_ids.size());
01438     libmesh_assert_equal_to (saved_bc_ids.size(), saved_bc_sides.size());
01439   }
01440 
01441 
01442   // Loop again, delete any remaining elements
01443   {
01444     MeshBase::element_iterator       it  = mesh.elements_begin();
01445     const MeshBase::element_iterator end = mesh.elements_end();
01446 
01447     for (; it != end; ++it)
01448       mesh.delete_elem( *it );
01449   }
01450 
01451 
01452   // Add the copied (now level-0) elements back to the mesh
01453   {
01454     for (std::vector<Elem*>::iterator it = new_elements.begin();
01455          it != new_elements.end();
01456          ++it)
01457       {
01458 #ifndef NDEBUG
01459         dof_id_type orig_id = (*it)->id();
01460 
01461         // ugly mid-statement endif to avoid unused variable warnings
01462         Elem* added_elem =
01463 #endif
01464           mesh.add_elem(*it);
01465 
01466 #ifndef NDEBUG
01467         dof_id_type added_id = added_elem->id();
01468 #endif
01469 
01470         // If the Elem, as it was re-added to the mesh, now has a
01471         // different ID (this is unlikely, so it's just an assert)
01472         // the boundary information will no longer be correct.
01473         libmesh_assert_equal_to (orig_id, added_id);
01474       }
01475   }
01476 
01477   // Finally, also add back the saved boundary information
01478   for (unsigned int e=0; e<saved_boundary_elements.size(); ++e)
01479     mesh.get_boundary_info().add_side(saved_boundary_elements[e],
01480                                       saved_bc_sides[e],
01481                                       saved_bc_ids[e]);
01482 
01483   // Trim unused and renumber nodes and elements
01484   mesh.prepare_for_use(/*skip_renumber =*/ false);
01485 }
01486 #endif // #ifdef LIBMESH_ENABLE_AMR
01487 
01488 
01489 
01490 void MeshTools::Modification::change_boundary_id (MeshBase& mesh,
01491                                                   const boundary_id_type old_id,
01492                                                   const boundary_id_type new_id)
01493 {
01494   // Only level-0 elements store BCs.  Loop over them.
01495   MeshBase::element_iterator           el = mesh.level_elements_begin(0);
01496   const MeshBase::element_iterator end_el = mesh.level_elements_end(0);
01497   for (; el != end_el; ++el)
01498     {
01499       Elem *elem = *el;
01500 
01501       unsigned int n_nodes = elem->n_nodes();
01502       for (unsigned int n=0; n != n_nodes; ++n)
01503         {
01504           const std::vector<boundary_id_type>& old_ids =
01505             mesh.get_boundary_info().boundary_ids(elem->get_node(n));
01506           if (std::find(old_ids.begin(), old_ids.end(), old_id) != old_ids.end())
01507             {
01508               std::vector<boundary_id_type> new_ids(old_ids);
01509               std::replace(new_ids.begin(), new_ids.end(), old_id, new_id);
01510               mesh.get_boundary_info().remove(elem->get_node(n));
01511               mesh.get_boundary_info().add_node(elem->get_node(n), new_ids);
01512             }
01513         }
01514 
01515       unsigned int n_edges = elem->n_edges();
01516       for (unsigned short edge=0; edge != n_edges; ++edge)
01517         {
01518           const std::vector<boundary_id_type>& old_ids =
01519             mesh.get_boundary_info().edge_boundary_ids(elem, edge);
01520           if (std::find(old_ids.begin(), old_ids.end(), old_id) != old_ids.end())
01521             {
01522               std::vector<boundary_id_type> new_ids(old_ids);
01523               std::replace(new_ids.begin(), new_ids.end(), old_id, new_id);
01524               mesh.get_boundary_info().remove_edge(elem, edge);
01525               mesh.get_boundary_info().add_edge(elem, edge, new_ids);
01526             }
01527         }
01528 
01529       unsigned int n_sides = elem->n_sides();
01530       for (unsigned short s=0; s != n_sides; ++s)
01531         {
01532           const std::vector<boundary_id_type>& old_ids =
01533             mesh.get_boundary_info().boundary_ids(elem, s);
01534           if (std::find(old_ids.begin(), old_ids.end(), old_id) != old_ids.end())
01535             {
01536               std::vector<boundary_id_type> new_ids(old_ids);
01537               std::replace(new_ids.begin(), new_ids.end(), old_id, new_id);
01538               mesh.get_boundary_info().remove_side(elem, s);
01539               mesh.get_boundary_info().add_side(elem, s, new_ids);
01540             }
01541         }
01542     }
01543 }
01544 
01545 
01546 
01547 void MeshTools::Modification::change_subdomain_id (MeshBase& mesh,
01548                                                    const subdomain_id_type old_id,
01549                                                    const subdomain_id_type new_id)
01550 {
01551   MeshBase::element_iterator           el = mesh.elements_begin();
01552   const MeshBase::element_iterator end_el = mesh.elements_end();
01553 
01554   for (; el != end_el; ++el)
01555     {
01556       Elem *elem = *el;
01557 
01558       if (elem->subdomain_id() == old_id)
01559         elem->subdomain_id() = new_id;
01560     }
01561 }
01562 
01563 
01564 } // namespace libMesh