$extrastylesheet
mesh_refinement_smoothing.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 // Local includes
00021 #include "libmesh/libmesh_config.h"
00022 
00023 // only compile these functions if the user requests AMR support
00024 #ifdef LIBMESH_ENABLE_AMR
00025 
00026 #include "libmesh/elem.h"
00027 #include "libmesh/mesh_base.h"
00028 #include "libmesh/mesh_refinement.h"
00029 #include "libmesh/parallel.h"
00030 #include "libmesh/remote_elem.h"
00031 
00032 namespace libMesh
00033 {
00034 
00035 
00036 
00037 //-----------------------------------------------------------------
00038 // Mesh refinement methods
00039 bool MeshRefinement::limit_level_mismatch_at_node (const unsigned int max_mismatch)
00040 {
00041   // This function must be run on all processors at once
00042   parallel_object_only();
00043 
00044   bool flags_changed = false;
00045 
00046 
00047   // Vector holding the maximum element level that touches a node.
00048   std::vector<unsigned char> max_level_at_node (_mesh.n_nodes(), 0);
00049   std::vector<unsigned char> max_p_level_at_node (_mesh.n_nodes(), 0);
00050 
00051   // Loop over all the active elements & fill the vector
00052   {
00053     MeshBase::element_iterator       elem_it  = _mesh.active_elements_begin();
00054     const MeshBase::element_iterator elem_end = _mesh.active_elements_end();
00055 
00056     for (; elem_it != elem_end; ++elem_it)
00057       {
00058         const Elem* elem = *elem_it;
00059         const unsigned char elem_level =
00060           cast_int<unsigned char>(elem->level() +
00061                                   ((elem->refinement_flag() == Elem::REFINE) ? 1 : 0));
00062         const unsigned char elem_p_level =
00063           cast_int<unsigned char>(elem->p_level() +
00064                                   ((elem->p_refinement_flag() == Elem::REFINE) ? 1 : 0));
00065 
00066         // Set the max_level at each node
00067         for (unsigned int n=0; n<elem->n_nodes(); n++)
00068           {
00069             const dof_id_type node_number = elem->node(n);
00070 
00071             libmesh_assert_less (node_number, max_level_at_node.size());
00072 
00073             max_level_at_node[node_number] =
00074               std::max (max_level_at_node[node_number], elem_level);
00075             max_p_level_at_node[node_number] =
00076               std::max (max_p_level_at_node[node_number], elem_p_level);
00077           }
00078       }
00079   }
00080 
00081 
00082   // Now loop over the active elements and flag the elements
00083   // who violate the requested level mismatch. Alternatively, if
00084   // _enforce_mismatch_limit_prior_to_refinement is true, swap refinement flags
00085   // accordingly.
00086   {
00087     MeshBase::element_iterator       elem_it  = _mesh.active_elements_begin();
00088     const MeshBase::element_iterator elem_end = _mesh.active_elements_end();
00089 
00090     for (; elem_it != elem_end; ++elem_it)
00091       {
00092         Elem* elem = *elem_it;
00093         const unsigned int elem_level = elem->level();
00094         const unsigned int elem_p_level = elem->p_level();
00095 
00096         // Skip the element if it is already fully flagged
00097         // unless we are enforcing mismatch prior to refienemnt and may need to
00098         // remove the refinement flag(s)
00099         if (elem->refinement_flag() == Elem::REFINE &&
00100             elem->p_refinement_flag() == Elem::REFINE
00101             && !_enforce_mismatch_limit_prior_to_refinement)
00102           continue;
00103 
00104         // Loop over the nodes, check for possible mismatch
00105         for (unsigned int n=0; n<elem->n_nodes(); n++)
00106           {
00107             const dof_id_type node_number = elem->node(n);
00108 
00109             // Flag the element for refinement if it violates
00110             // the requested level mismatch
00111             if ((elem_level + max_mismatch) < max_level_at_node[node_number]
00112                 && elem->refinement_flag() != Elem::REFINE)
00113               {
00114                 elem->set_refinement_flag (Elem::REFINE);
00115                 flags_changed = true;
00116               }
00117             if ((elem_p_level + max_mismatch) < max_p_level_at_node[node_number]
00118                 && elem->p_refinement_flag() != Elem::REFINE)
00119               {
00120                 elem->set_p_refinement_flag (Elem::REFINE);
00121                 flags_changed = true;
00122               }
00123 
00124             // Possibly enforce limit mismatch prior to refinement
00125             flags_changed |= this->enforce_mismatch_limit_prior_to_refinement(elem, POINT, max_mismatch);
00126           }
00127       }
00128   }
00129 
00130   // If flags changed on any processor then they changed globally
00131   this->comm().max(flags_changed);
00132 
00133   return flags_changed;
00134 }
00135 
00136 
00137 
00138 //-----------------------------------------------------------------
00139 // Mesh refinement methods
00140 bool MeshRefinement::limit_level_mismatch_at_edge (const unsigned int max_mismatch)
00141 {
00142   // This function must be run on all processors at once
00143   parallel_object_only();
00144 
00145   bool flags_changed = false;
00146 
00147 
00148   // Maps holding the maximum element level that touches an edge
00149   std::map<std::pair<unsigned int, unsigned int>, unsigned char>
00150     max_level_at_edge;
00151   std::map<std::pair<unsigned int, unsigned int>, unsigned char>
00152     max_p_level_at_edge;
00153 
00154   // Loop over all the active elements & fill the maps
00155   {
00156     MeshBase::element_iterator       elem_it  = _mesh.active_elements_begin();
00157     const MeshBase::element_iterator elem_end = _mesh.active_elements_end();
00158 
00159     for (; elem_it != elem_end; ++elem_it)
00160       {
00161         const Elem* elem = *elem_it;
00162         const unsigned char elem_level =
00163           cast_int<unsigned char>(elem->level() +
00164                                   ((elem->refinement_flag() == Elem::REFINE) ? 1 : 0));
00165         const unsigned char elem_p_level =
00166           cast_int<unsigned char>(elem->p_level() +
00167                                   ((elem->p_refinement_flag() == Elem::REFINE) ? 1 : 0));
00168 
00169         // Set the max_level at each edge
00170         for (unsigned int n=0; n<elem->n_edges(); n++)
00171           {
00172             UniquePtr<Elem> edge = elem->build_edge(n);
00173             dof_id_type childnode0 = edge->node(0);
00174             dof_id_type childnode1 = edge->node(1);
00175             if (childnode1 < childnode0)
00176               std::swap(childnode0, childnode1);
00177 
00178             for (const Elem *p = elem; p != NULL; p = p->parent())
00179               {
00180                 UniquePtr<Elem> pedge = p->build_edge(n);
00181                 dof_id_type node0 = pedge->node(0);
00182                 dof_id_type node1 = pedge->node(1);
00183 
00184                 if (node1 < node0)
00185                   std::swap(node0, node1);
00186 
00187                 // If elem does not share this edge with its ancestor
00188                 // p, refinement levels of elements sharing p's edge
00189                 // are not restricted by refinement levels of elem.
00190                 // Furthermore, elem will not share this edge with any
00191                 // of p's ancestors, so we can safely break out of the
00192                 // for loop early.
00193                 if (node0 != childnode0 && node1 != childnode1)
00194                   break;
00195 
00196                 childnode0 = node0;
00197                 childnode1 = node1;
00198 
00199                 std::pair<unsigned int, unsigned int> edge_key =
00200                   std::make_pair(node0, node1);
00201 
00202                 if (max_level_at_edge.find(edge_key) ==
00203                     max_level_at_edge.end())
00204                   {
00205                     max_level_at_edge[edge_key] = elem_level;
00206                     max_p_level_at_edge[edge_key] = elem_p_level;
00207                   }
00208                 else
00209                   {
00210                     max_level_at_edge[edge_key] =
00211                       std::max (max_level_at_edge[edge_key], elem_level);
00212                     max_p_level_at_edge[edge_key] =
00213                       std::max (max_p_level_at_edge[edge_key], elem_p_level);
00214                   }
00215               }
00216           }
00217       }
00218   }
00219 
00220 
00221   // Now loop over the active elements and flag the elements
00222   // who violate the requested level mismatch
00223   {
00224     MeshBase::element_iterator       elem_it  = _mesh.active_elements_begin();
00225     const MeshBase::element_iterator elem_end = _mesh.active_elements_end();
00226 
00227     for (; elem_it != elem_end; ++elem_it)
00228       {
00229         Elem* elem = *elem_it;
00230         const unsigned int elem_level = elem->level();
00231         const unsigned int elem_p_level = elem->p_level();
00232 
00233         // Skip the element if it is already fully flagged
00234         if (elem->refinement_flag() == Elem::REFINE &&
00235             elem->p_refinement_flag() == Elem::REFINE
00236             && !_enforce_mismatch_limit_prior_to_refinement)
00237           continue;
00238 
00239         // Loop over the nodes, check for possible mismatch
00240         for (unsigned int n=0; n<elem->n_edges(); n++)
00241           {
00242             UniquePtr<Elem> edge = elem->build_edge(n);
00243             dof_id_type node0 = edge->node(0);
00244             dof_id_type node1 = edge->node(1);
00245             if (node1 < node0)
00246               std::swap(node0, node1);
00247 
00248             std::pair<dof_id_type, dof_id_type> edge_key =
00249               std::make_pair(node0, node1);
00250 
00251             // Flag the element for refinement if it violates
00252             // the requested level mismatch
00253             if ((elem_level + max_mismatch) < max_level_at_edge[edge_key]
00254                 && elem->refinement_flag() != Elem::REFINE)
00255               {
00256                 elem->set_refinement_flag (Elem::REFINE);
00257                 flags_changed = true;
00258               }
00259 
00260             if ((elem_p_level + max_mismatch) < max_p_level_at_edge[edge_key]
00261                 && elem->p_refinement_flag() != Elem::REFINE)
00262               {
00263                 elem->set_p_refinement_flag (Elem::REFINE);
00264                 flags_changed = true;
00265               }
00266 
00267             // Possibly enforce limit mismatch prior to refinement
00268             flags_changed |= this->enforce_mismatch_limit_prior_to_refinement(elem, EDGE, max_mismatch);
00269           } // loop over edges
00270       } // loop over active elements
00271   }
00272 
00273   // If flags changed on any processor then they changed globally
00274   this->comm().max(flags_changed);
00275 
00276   return flags_changed;
00277 }
00278 
00279 
00280 
00281 
00282 bool MeshRefinement::eliminate_unrefined_patches ()
00283 {
00284   // This function must be run on all processors at once
00285   parallel_object_only();
00286 
00287   bool flags_changed = false;
00288 
00289   MeshBase::element_iterator       elem_it  = _mesh.active_elements_begin();
00290   const MeshBase::element_iterator elem_end = _mesh.active_elements_end();
00291 
00292   for (; elem_it != elem_end; ++elem_it)
00293     {
00294       Elem* elem = *elem_it;
00295       // First assume that we'll have to flag this element for both h
00296       // and p refinement, then change our minds if we see any
00297       // neighbors that are as coarse or coarser than us.
00298       bool h_flag_me = true,
00299         p_flag_me = true;
00300 
00301 
00302       // Skip the element if it is already fully flagged for refinement
00303       if (elem->p_refinement_flag() == Elem::REFINE)
00304         p_flag_me = false;
00305       if (elem->refinement_flag() == Elem::REFINE)
00306         {
00307           h_flag_me = false;
00308           if (!p_flag_me)
00309             continue;
00310         }
00311       // Test the parent if that is already flagged for coarsening
00312       else if (elem->refinement_flag() == Elem::COARSEN)
00313         {
00314           libmesh_assert(elem->parent());
00315           elem = elem->parent();
00316           // FIXME - this doesn't seem right - RHS
00317           if (elem->refinement_flag() != Elem::COARSEN_INACTIVE)
00318             continue;
00319           p_flag_me = false;
00320         }
00321 
00322       const unsigned int my_level = elem->level();
00323       int my_p_adjustment = 0;
00324       if (elem->p_refinement_flag() == Elem::REFINE)
00325         my_p_adjustment = 1;
00326       else if (elem->p_refinement_flag() == Elem::COARSEN)
00327         {
00328           libmesh_assert_greater (elem->p_level(), 0);
00329           my_p_adjustment = -1;
00330         }
00331       const unsigned int my_new_p_level = elem->p_level() +
00332         my_p_adjustment;
00333 
00334       // Check all the element neighbors
00335       for (unsigned int n=0; n<elem->n_neighbors(); n++)
00336         {
00337           const Elem *neighbor = elem->neighbor(n);
00338           // Quit if the element is on a local boundary
00339           if (neighbor == NULL || neighbor == remote_elem)
00340             {
00341               h_flag_me = false;
00342               p_flag_me = false;
00343               break;
00344             }
00345           // if the neighbor will be equally or less refined than
00346           // we are, then we will not become an unrefined island.
00347           // So if we are still considering h refinement:
00348           if (h_flag_me &&
00349               // If our neighbor is already at a lower level,
00350               // it can't end up at a higher level even if it
00351               // is flagged for refinement once
00352               ((neighbor->level() < my_level) ||
00353                // If our neighbor is at the same level but isn't
00354                // flagged for refinement, it won't end up at a
00355                // higher level
00356                ((neighbor->active()) &&
00357                 (neighbor->refinement_flag() != Elem::REFINE)) ||
00358                // If our neighbor is currently more refined but is
00359                // a parent flagged for coarsening, it will end up
00360                // at the same level.
00361                (neighbor->refinement_flag() == Elem::COARSEN_INACTIVE)))
00362             {
00363               // We've proven we won't become an unrefined island,
00364               // so don't h refine to avoid that.
00365               h_flag_me = false;
00366 
00367               // If we've also proven we don't need to p refine,
00368               // we don't need to check more neighbors
00369               if (!p_flag_me)
00370                 break;
00371             }
00372           if (p_flag_me)
00373             {
00374               // if active neighbors will have a p level
00375               // equal to or lower than ours, then we do not need to p
00376               // refine ourselves.
00377               if (neighbor->active())
00378                 {
00379                   int p_adjustment = 0;
00380                   if (neighbor->p_refinement_flag() == Elem::REFINE)
00381                     p_adjustment = 1;
00382                   else if (neighbor->p_refinement_flag() == Elem::COARSEN)
00383                     {
00384                       libmesh_assert_greater (neighbor->p_level(), 0);
00385                       p_adjustment = -1;
00386                     }
00387                   if (my_new_p_level >= neighbor->p_level() + p_adjustment)
00388                     {
00389                       p_flag_me = false;
00390                       if (!h_flag_me)
00391                         break;
00392                     }
00393                 }
00394               // If we have inactive neighbors, we need to
00395               // test all their active descendants which neighbor us
00396               else if (neighbor->ancestor())
00397                 {
00398                   if (neighbor->min_new_p_level_by_neighbor(elem,
00399                                                             my_new_p_level + 2) <= my_new_p_level)
00400                     {
00401                       p_flag_me = false;
00402                       if (!h_flag_me)
00403                         break;
00404                     }
00405                 }
00406             }
00407         }
00408 
00409       if (h_flag_me)
00410         {
00411           // Parents that would create islands should no longer
00412           // coarsen
00413           if (elem->refinement_flag() == Elem::COARSEN_INACTIVE)
00414             {
00415               for (unsigned int c=0; c<elem->n_children(); c++)
00416                 {
00417                   libmesh_assert_equal_to (elem->child(c)->refinement_flag(),
00418                                            Elem::COARSEN);
00419                   elem->child(c)->set_refinement_flag(Elem::DO_NOTHING);
00420                 }
00421               elem->set_refinement_flag(Elem::INACTIVE);
00422             }
00423           else
00424             elem->set_refinement_flag(Elem::REFINE);
00425           flags_changed = true;
00426         }
00427       if (p_flag_me)
00428         {
00429           if (elem->p_refinement_flag() == Elem::COARSEN)
00430             elem->set_p_refinement_flag(Elem::DO_NOTHING);
00431           else
00432             elem->set_p_refinement_flag(Elem::REFINE);
00433           flags_changed = true;
00434         }
00435     }
00436 
00437   // If flags changed on any processor then they changed globally
00438   this->comm().max(flags_changed);
00439 
00440   return flags_changed;
00441 }
00442 
00443 
00444 
00445 bool MeshRefinement::enforce_mismatch_limit_prior_to_refinement(Elem* elem,
00446                                                                 NeighborType nt,
00447                                                                 unsigned max_mismatch)
00448 {
00449   // Eventual return value
00450   bool flags_changed = false;
00451 
00452   // If we are enforcing the limit prior to refinement then we
00453   // need to remove flags from any elements marked for refinement that
00454   // would cause a mismatch
00455   if (_enforce_mismatch_limit_prior_to_refinement
00456       && elem->refinement_flag() == Elem::REFINE)
00457     {
00458       // get all the POINT neighbors since we may have to refine
00459       // elements off the corner as well
00460       std::set<const Elem*> neighbor_set;
00461 
00462       if (nt == POINT)
00463         elem->find_point_neighbors(neighbor_set);
00464       else if (nt == EDGE)
00465         elem->find_edge_neighbors(neighbor_set);
00466       else
00467         libmesh_error_msg("Unrecognized NeighborType: " << nt);
00468 
00469       // Loop over the neighbors of element e
00470       std::set<const Elem*>::iterator n_it = neighbor_set.begin();
00471       for (; n_it != neighbor_set.end(); ++n_it)
00472         {
00473           const Elem* neighbor = *n_it;
00474 
00475           if ((elem->level() + 1 - max_mismatch) > neighbor->level())
00476             {
00477               elem->set_refinement_flag(Elem::DO_NOTHING);
00478               flags_changed = true;
00479             }
00480           if ((elem->p_level() + 1 - max_mismatch) > neighbor->p_level())
00481             {
00482               elem->set_p_refinement_flag(Elem::DO_NOTHING);
00483               flags_changed = true;
00484             }
00485         } // loop over edge/point neighbors
00486     } // if _enforce_mismatch_limit_prior_to_refinement
00487 
00488   return flags_changed;
00489 }
00490 
00491 } // namespace libMesh
00492 
00493 
00494 #endif