LCOV - code coverage report
Current view: top level - src/mesh - mesh_refinement.C (source / functions) Hit Total Coverage
Test: libMesh/libmesh: #4283 (f95625) with base 739e36 Lines: 607 690 88.0 %
Date: 2025-10-30 15:32:02 Functions: 24 27 88.9 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // The libMesh Finite Element Library.
       2             : // Copyright (C) 2002-2025 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
       3             : 
       4             : // This library is free software; you can redistribute it and/or
       5             : // modify it under the terms of the GNU Lesser General Public
       6             : // License as published by the Free Software Foundation; either
       7             : // version 2.1 of the License, or (at your option) any later version.
       8             : 
       9             : // This library is distributed in the hope that it will be useful,
      10             : // but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12             : // Lesser General Public License for more details.
      13             : 
      14             : // You should have received a copy of the GNU Lesser General Public
      15             : // License along with this library; if not, write to the Free Software
      16             : // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
      17             : 
      18             : 
      19             : // C++ includes
      20             : #include <cstdlib> // *must* precede <cmath> for proper std:abs() on PGI, Sun Studio CC
      21             : #include <cmath> // for isnan(), when it's defined
      22             : #include <limits>
      23             : 
      24             : // Local includes
      25             : #include "libmesh/libmesh_config.h"
      26             : 
      27             : // only compile these functions if the user requests AMR support
      28             : #ifdef LIBMESH_ENABLE_AMR
      29             : 
      30             : #include "libmesh/boundary_info.h"
      31             : #include "libmesh/error_vector.h"
      32             : #include "libmesh/libmesh_logging.h"
      33             : #include "libmesh/mesh_base.h"
      34             : #include "libmesh/mesh_communication.h"
      35             : #include "libmesh/mesh_refinement.h"
      36             : #include "libmesh/parallel.h"
      37             : #include "libmesh/parallel_ghost_sync.h"
      38             : #include "libmesh/partitioner.h"
      39             : #include "libmesh/remote_elem.h"
      40             : #include "libmesh/sync_refinement_flags.h"
      41             : #include "libmesh/int_range.h"
      42             : 
      43             : #ifdef DEBUG
      44             : // Some extra validation for DistributedMesh
      45             : #include "libmesh/mesh_tools.h"
      46             : #endif // DEBUG
      47             : 
      48             : #ifdef LIBMESH_ENABLE_PERIODIC
      49             : #include "libmesh/periodic_boundaries.h"
      50             : #endif
      51             : 
      52             : 
      53             : 
      54             : // Anonymous namespace for helper functions
      55             : // namespace {
      56             : //
      57             : // using namespace libMesh;
      58             : //
      59             : // struct SyncCoarsenInactive
      60             : // {
      61             : //   bool operator() (const Elem * elem) const {
      62             : //     // If we're not an ancestor, there's no chance our coarsening
      63             : //     // settings need to be changed.
      64             : //     if (!elem->ancestor())
      65             : //       return false;
      66             : //
      67             : //     // If we don't have any remote children, we already know enough to
      68             : //     // determine the correct refinement flag ourselves.
      69             : //     //
      70             : //     // If we know we have a child that isn't being coarsened, that
      71             : //     // also forces a specific flag.
      72             : //     //
      73             : //     // Either way there's nothing we need to communicate.
      74             : //     bool found_remote_child = false;
      75             : //     for (auto & child : elem->child_ref_range())
      76             : //       {
      77             : //         if (child.refinement_flag() != Elem::COARSEN)
      78             : //           return false;
      79             : //         if (&child == remote_elem)
      80             : //           found_remote_child = true;
      81             : //       }
      82             : //     return found_remote_child;
      83             : //   }
      84             : // };
      85             : // }
      86             : 
      87             : 
      88             : 
      89             : namespace libMesh
      90             : {
      91             : 
      92             : //-----------------------------------------------------------------
      93             : // Mesh refinement methods
      94      302003 : MeshRefinement::MeshRefinement (MeshBase & m) :
      95             :   ParallelObject(m),
      96      284403 :   _mesh(m),
      97      284403 :   _use_member_parameters(false),
      98      284403 :   _coarsen_by_parents(false),
      99      284403 :   _refine_fraction(0.3),
     100      284403 :   _coarsen_fraction(0.0),
     101      284403 :   _max_h_level(libMesh::invalid_uint),
     102      284403 :   _coarsen_threshold(10),
     103      284403 :   _nelem_target(0),
     104      284403 :   _absolute_global_tolerance(0.0),
     105      284403 :   _face_level_mismatch_limit(1),
     106      284403 :   _edge_level_mismatch_limit(0),
     107      284403 :   _node_level_mismatch_limit(0),
     108      284403 :   _overrefined_boundary_limit(0),
     109      284403 :   _underrefined_boundary_limit(0),
     110      284403 :   _allow_unrefined_patches(false),
     111      284403 :   _enforce_mismatch_limit_prior_to_refinement(false)
     112             : #ifdef LIBMESH_ENABLE_PERIODIC
     113      310803 :   , _periodic_boundaries(nullptr)
     114             : #endif
     115             : {
     116      302003 : }
     117             : 
     118             : 
     119             : 
     120             : #ifdef LIBMESH_ENABLE_PERIODIC
     121          10 : void MeshRefinement::set_periodic_boundaries_ptr(PeriodicBoundaries * pb_ptr)
     122             : {
     123          10 :   _periodic_boundaries = pb_ptr;
     124          10 : }
     125             : #endif
     126             : 
     127             : 
     128             : 
     129      285870 : MeshRefinement::~MeshRefinement () = default;
     130             : 
     131             : 
     132             : 
     133       54499 : void MeshRefinement::clear ()
     134             : {
     135        1858 :   _new_nodes_map.clear();
     136       54499 : }
     137             : 
     138             : 
     139             : 
     140    45223437 : Node * MeshRefinement::add_node(Elem & parent,
     141             :                                 unsigned int child,
     142             :                                 unsigned int node,
     143             :                                 processor_id_type proc_id)
     144             : {
     145     5208360 :   LOG_SCOPE("add_node()", "MeshRefinement");
     146             : 
     147    45223437 :   unsigned int parent_n = parent.as_parent_node(child, node);
     148             : 
     149    45223437 :   if (parent_n != libMesh::invalid_uint)
     150    13997398 :     return parent.node_ptr(parent_n);
     151             : 
     152             :   const std::vector<std::pair<dof_id_type, dof_id_type>>
     153    33830195 :     bracketing_nodes = parent.bracketing_nodes(child, node);
     154             : 
     155             :   // If we're not a parent node, we *must* be bracketed by at least
     156             :   // one pair of parent nodes
     157     1860248 :   libmesh_assert(bracketing_nodes.size());
     158             : 
     159             :   // Return the node if it already exists.
     160             :   //
     161             :   // We'll leave the processor_id untouched in this case - if we're
     162             :   // repartitioning later or if this is a new unpartitioned node,
     163             :   // we'll update it then, and if not then we don't want to update it.
     164    31969947 :   if (const auto new_node_id = _new_nodes_map.find(bracketing_nodes);
     165             :       new_node_id != DofObject::invalid_id)
     166    23050885 :     return _mesh.node_ptr(new_node_id);
     167             : 
     168             :   // Otherwise we need to add a new node.
     169             :   //
     170             :   // Figure out where to add the point:
     171             : 
     172      507937 :   Point p; // defaults to 0,0,0
     173             : 
     174   111475218 :   for (auto n : parent.node_index_range())
     175             :     {
     176             :       // The value from the embedding matrix
     177   102556156 :       const Real em_val = parent.embedding_matrix(child,node,n);
     178             : 
     179   102556156 :       if (em_val != 0.)
     180             :         {
     181    50944400 :           p.add_scaled (parent.point(n), em_val);
     182             : 
     183             :           // If we'd already found the node we shouldn't be here
     184     2665982 :           libmesh_assert_not_equal_to (em_val, 1);
     185             :         }
     186             :     }
     187             : 
     188             :   // Although we're leaving new nodes unpartitioned at first, with a
     189             :   // DistributedMesh we would need a default id based on the numbering
     190             :   // scheme for the requested processor_id.
     191     8919062 :   Node * new_node = _mesh.add_point (p, DofObject::invalid_id, proc_id);
     192             : 
     193      507937 :   libmesh_assert(new_node);
     194             : 
     195             :   // But then we'll make sure this node is marked as unpartitioned.
     196     8919062 :   new_node->processor_id() = DofObject::invalid_processor_id;
     197             : 
     198             :   // Add the node to the map.
     199     8919062 :   _new_nodes_map.add_node(*new_node, bracketing_nodes);
     200             : 
     201             :   // Return the address of the new node
     202      507937 :   return new_node;
     203             : }
     204             : 
     205             : 
     206             : 
     207           0 : Elem * MeshRefinement::add_elem (Elem * elem)
     208             : {
     209           0 :   libmesh_assert(elem);
     210           0 :   return _mesh.add_elem (elem);
     211             : }
     212             : 
     213     6223237 : Elem * MeshRefinement::add_elem (std::unique_ptr<Elem> elem)
     214             : {
     215      380326 :   libmesh_assert(elem);
     216     6983865 :   return _mesh.add_elem(std::move(elem));
     217             : }
     218             : 
     219             : 
     220        1590 : void MeshRefinement::create_parent_error_vector(const ErrorVector & error_per_cell,
     221             :                                                 ErrorVector & error_per_parent,
     222             :                                                 Real & parent_error_min,
     223             :                                                 Real & parent_error_max)
     224             : {
     225             :   // This function must be run on all processors at once
     226          82 :   parallel_object_only();
     227             : 
     228             :   // Make sure the input error vector is valid
     229             : #ifdef DEBUG
     230       11662 :   for (const auto & val : error_per_cell)
     231             :     {
     232       11580 :       libmesh_assert_greater_equal (val, 0);
     233             :       // isnan() isn't standard C++ yet
     234             : #ifdef isnan
     235             :       libmesh_assert(!isnan(val));
     236             : #endif
     237             :     }
     238             : 
     239             :   // Use a reference to std::vector to avoid confusing
     240             :   // this->comm().verify
     241          82 :   std::vector<ErrorVectorReal> & epc = error_per_parent;
     242          82 :   libmesh_assert(this->comm().verify(epc));
     243             : #endif // #ifdef DEBUG
     244             : 
     245             :   // error values on uncoarsenable elements will be left at -1
     246        1590 :   error_per_parent.clear();
     247        1672 :   error_per_parent.resize(error_per_cell.size(), 0.0);
     248             : 
     249             :   {
     250             :     // Find which elements are uncoarsenable
     251       79026 :     for (auto & elem : _mesh.active_local_element_ptr_range())
     252             :       {
     253       42484 :         Elem * parent = elem->parent();
     254             : 
     255             :         // Active elements are uncoarsenable
     256       47004 :         error_per_parent[elem->id()] = -1.0;
     257             : 
     258             :         // Grandparents and up are uncoarsenable
     259      121906 :         while (parent)
     260             :           {
     261       22576 :             parent = parent->parent();
     262      107694 :             if (parent)
     263             :               {
     264       14584 :                 const dof_id_type parentid  = parent->id();
     265        7292 :                 libmesh_assert_less (parentid, error_per_parent.size());
     266       78722 :                 error_per_parent[parentid] = -1.0;
     267             :               }
     268             :           }
     269        1426 :       }
     270             : 
     271             :     // Sync between processors.
     272             :     // Use a reference to std::vector to avoid confusing
     273             :     // this->comm().min
     274          82 :     std::vector<ErrorVectorReal> & epp = error_per_parent;
     275        1590 :     this->comm().min(epp);
     276             :   }
     277             : 
     278             :   // The parent's error is defined as the square root of the
     279             :   // sum of the children's errors squared, so errors that are
     280             :   // Hilbert norms remain Hilbert norms.
     281             :   //
     282             :   // Because the children may be on different processors, we
     283             :   // calculate local contributions to the parents' errors squared
     284             :   // first, then sum across processors and take the square roots
     285             :   // second.
     286       79026 :   for (auto & elem : _mesh.active_local_element_ptr_range())
     287             :     {
     288       42484 :       Elem * parent = elem->parent();
     289             : 
     290             :       // Calculate each contribution to parent cells
     291       42484 :       if (parent)
     292             :         {
     293        7992 :           const dof_id_type parentid  = parent->id();
     294        3996 :           libmesh_assert_less (parentid, error_per_parent.size());
     295             : 
     296             :           // If the parent has grandchildren we won't be able to
     297             :           // coarsen it, so forget it.  Otherwise, add this child's
     298             :           // contribution to the sum of the squared child errors
     299       40260 :           if (error_per_parent[parentid] != -1.0)
     300       38452 :             error_per_parent[parentid] += (error_per_cell[elem->id()] *
     301        3456 :                                            error_per_cell[elem->id()]);
     302             :         }
     303        1426 :     }
     304             : 
     305             :   // Sum the vector across all processors
     306        1590 :   this->comm().sum(static_cast<std::vector<ErrorVectorReal> &>(error_per_parent));
     307             : 
     308             :   // Calculate the min and max as we loop
     309        1590 :   parent_error_min = std::numeric_limits<double>::max();
     310        1590 :   parent_error_max = 0.;
     311             : 
     312      302928 :   for (auto i : index_range(error_per_parent))
     313             :     {
     314             :       // If this element isn't a coarsenable parent with error, we
     315             :       // have nothing to do.  Just flag it as -1 and move on
     316             :       // Note that this->comm().sum might have left uncoarsenable
     317             :       // elements with error_per_parent=-n_proc, so reset it to
     318             :       // error_per_parent=-1
     319      312918 :       if (error_per_parent[i] < 0.)
     320             :         {
     321      257344 :           error_per_parent[i] = -1.;
     322      257344 :           continue;
     323             :         }
     324             : 
     325             :       // The error estimator might have already given us an
     326             :       // estimate on the coarsenable parent elements; if so then
     327             :       // we want to retain that estimate
     328       45746 :       if (error_per_cell[i])
     329             :         {
     330           0 :           error_per_parent[i] = error_per_cell[i];
     331           0 :           continue;
     332             :         }
     333             :       // if not, then e_parent = sqrt(sum(e_child^2))
     334             :       else
     335       43994 :         error_per_parent[i] = std::sqrt(error_per_parent[i]);
     336             : 
     337       43994 :       parent_error_min = std::min (parent_error_min,
     338        1744 :                                    error_per_parent[i]);
     339       50719 :       parent_error_max = std::max (parent_error_max,
     340        1744 :                                    error_per_parent[i]);
     341             :     }
     342        1590 : }
     343             : 
     344             : 
     345             : 
     346       54499 : void MeshRefinement::update_nodes_map ()
     347             : {
     348       54499 :   this->_new_nodes_map.init(_mesh);
     349       54499 : }
     350             : 
     351             : 
     352             : 
     353        1196 : bool MeshRefinement::test_level_one (bool libmesh_dbg_var(libmesh_assert_pass)) const
     354             : {
     355             :   // This function must be run on all processors at once
     356        1196 :   parallel_object_only();
     357             : 
     358             :   // We may need a PointLocator for topological_neighbor() tests
     359             :   // later, which we need to make sure gets constructed on all
     360             :   // processors at once.
     361        1196 :   std::unique_ptr<PointLocatorBase> point_locator;
     362             : 
     363             : #ifdef LIBMESH_ENABLE_PERIODIC
     364             :   bool has_periodic_boundaries =
     365        1196 :     _periodic_boundaries && !_periodic_boundaries->empty();
     366        1196 :   libmesh_assert(this->comm().verify(has_periodic_boundaries));
     367             : 
     368        1196 :   if (has_periodic_boundaries)
     369         200 :     point_locator = _mesh.sub_point_locator();
     370             : #endif
     371             : 
     372        1196 :   bool failure = false;
     373             : 
     374             : #ifndef NDEBUG
     375        1196 :   Elem * failed_elem = nullptr;
     376        1196 :   Elem * failed_neighbor = nullptr;
     377             : #endif // !NDEBUG
     378             : 
     379      251935 :   for (auto & elem : _mesh.active_local_element_ptr_range())
     380     1222937 :     for (auto n : elem->side_index_range())
     381             :       {
     382             :         Elem * neighbor =
     383      972198 :           topological_neighbor(elem, point_locator.get(), n);
     384             : 
     385     1849249 :         if (!neighbor || !neighbor->active() ||
     386      877051 :             neighbor == remote_elem)
     387       95147 :           continue;
     388             : 
     389      877051 :         if ((neighbor->level() + 1 < elem->level()) ||
     390     1754102 :             (neighbor->p_level() + 1 < elem->p_level()) ||
     391      877051 :             (neighbor->p_level() > elem->p_level() + 1))
     392             :           {
     393           0 :             failure = true;
     394             : #ifndef NDEBUG
     395           0 :             failed_elem = elem;
     396           0 :             failed_neighbor = neighbor;
     397             : #endif // !NDEBUG
     398           0 :             break;
     399             :           }
     400           0 :       }
     401             : 
     402             :   // If any processor failed, we failed globally
     403        1196 :   this->comm().max(failure);
     404             : 
     405        1196 :   if (failure)
     406             :     {
     407             :       // We didn't pass the level one test, so libmesh_assert that
     408             :       // we're allowed not to
     409             : #ifndef NDEBUG
     410           0 :       if (libmesh_assert_pass)
     411             :         {
     412           0 :           libMesh::out << "MeshRefinement Level one failure, element: "
     413           0 :                        << *failed_elem
     414           0 :                        << std::endl;
     415           0 :           libMesh::out << "MeshRefinement Level one failure, neighbor: "
     416           0 :                        << *failed_neighbor
     417           0 :                        << std::endl;
     418             :         }
     419             : #endif // !NDEBUG
     420           0 :       libmesh_assert(!libmesh_assert_pass);
     421           0 :       return false;
     422             :     }
     423        1196 :   return true;
     424           0 : }
     425             : 
     426             : 
     427             : 
     428         554 : bool MeshRefinement::test_unflagged (bool libmesh_dbg_var(libmesh_assert_pass)) const
     429             : {
     430             :   // This function must be run on all processors at once
     431         554 :   parallel_object_only();
     432             : 
     433         554 :   bool found_flag = false;
     434             : 
     435             : #ifndef NDEBUG
     436         554 :   Elem * failed_elem = nullptr;
     437             : #endif
     438             : 
     439             :   // Search for local flags
     440      118937 :   for (auto & elem : _mesh.active_local_element_ptr_range())
     441      118383 :     if (elem->refinement_flag() == Elem::REFINE ||
     442      118383 :         elem->refinement_flag() == Elem::COARSEN ||
     443      355149 :         elem->p_refinement_flag() == Elem::REFINE ||
     444      118383 :         elem->p_refinement_flag() == Elem::COARSEN)
     445             :       {
     446           0 :         found_flag = true;
     447             : #ifndef NDEBUG
     448           0 :         failed_elem = elem;
     449             : #endif
     450           0 :         break;
     451           0 :       }
     452             : 
     453             :   // If we found a flag on any processor, it counts
     454         554 :   this->comm().max(found_flag);
     455             : 
     456         554 :   if (found_flag)
     457             :     {
     458             : #ifndef NDEBUG
     459           0 :       if (libmesh_assert_pass)
     460             :         {
     461             :           libMesh::out <<
     462           0 :             "MeshRefinement test_unflagged failure, element: " <<
     463           0 :             *failed_elem << std::endl;
     464             :         }
     465             : #endif
     466             :       // We didn't pass the "elements are unflagged" test,
     467             :       // so libmesh_assert that we're allowed not to
     468           0 :       libmesh_assert(!libmesh_assert_pass);
     469           0 :       return false;
     470             :     }
     471         554 :   return true;
     472             : }
     473             : 
     474             : 
     475             : 
     476       15906 : bool MeshRefinement::refine_and_coarsen_elements ()
     477             : {
     478             :   // This function must be run on all processors at once
     479         582 :   parallel_object_only();
     480             : 
     481             :   // We can't yet turn a non-level-one mesh into a level-one mesh
     482         582 :   if (_face_level_mismatch_limit)
     483         582 :     libmesh_assert(test_level_one(true));
     484             : 
     485             :   // Possibly clean up the refinement flags from
     486             :   // a previous step.  While we're at it, see if this method should be
     487             :   // a no-op.
     488       15906 :   bool elements_flagged = false;
     489             : 
     490    13057646 :   for (auto & elem : _mesh.element_ptr_range())
     491             :     {
     492             :       // This might be left over from the last step
     493     6818606 :       const Elem::RefinementState flag = elem->refinement_flag();
     494             : 
     495             :       // Set refinement flag to INACTIVE if the
     496             :       // element isn't active
     497      305398 :       if ( !elem->active())
     498             :         {
     499       74858 :           elem->set_refinement_flag(Elem::INACTIVE);
     500       74858 :           elem->set_p_refinement_flag(Elem::INACTIVE);
     501             :         }
     502     5119567 :       else if (flag == Elem::JUST_REFINED)
     503           0 :         elem->set_refinement_flag(Elem::DO_NOTHING);
     504     5119567 :       else if (!elements_flagged)
     505             :         {
     506       42943 :           if (flag == Elem::REFINE || flag == Elem::COARSEN)
     507       11271 :             elements_flagged = true;
     508             :           else
     509             :             {
     510             :               const Elem::RefinementState pflag =
     511        2230 :                 elem->p_refinement_flag();
     512       31672 :               if (pflag == Elem::REFINE || pflag == Elem::COARSEN)
     513         639 :                 elements_flagged = true;
     514             :             }
     515             :         }
     516       14742 :     }
     517             : 
     518             :   // Did *any* processor find elements flagged for AMR/C?
     519       15906 :   _mesh.comm().max(elements_flagged);
     520             : 
     521             :   // If we have nothing to do, let's not bother verifying that nothing
     522             :   // is compatible with nothing.
     523       15906 :   if (!elements_flagged)
     524          28 :     return false;
     525             : 
     526             :   // Parallel consistency has to come first, or coarsening
     527             :   // along processor boundaries might occasionally be falsely
     528             :   // prevented
     529             : #ifdef DEBUG
     530         554 :   bool flags_were_consistent = this->make_flags_parallel_consistent();
     531             : 
     532         554 :   libmesh_assert (flags_were_consistent);
     533             : #endif
     534             : 
     535             :   // Smooth refinement and coarsening flags
     536       14912 :   _smooth_flags(true, true);
     537             : 
     538             :   // First coarsen the flagged elements.
     539             :   const bool coarsening_changed_mesh =
     540       14912 :     this->_coarsen_elements ();
     541             : 
     542             :   // First coarsen the flagged elements.
     543             :   // FIXME: test_level_one now tests consistency across periodic
     544             :   // boundaries, which requires a point_locator, which just got
     545             :   // invalidated by _coarsen_elements() and hasn't yet been cleared by
     546             :   // prepare_for_use().
     547             : 
     548             :   //  libmesh_assert(this->make_coarsening_compatible());
     549             :   //  libmesh_assert(this->make_refinement_compatible());
     550             : 
     551             :   // FIXME: This won't pass unless we add a redundant find_neighbors()
     552             :   // call or replace find_neighbors() with on-the-fly neighbor updating
     553             :   // libmesh_assert(!this->eliminate_unrefined_patches());
     554             : 
     555             :   // We can't contract the mesh ourselves anymore - a System might
     556             :   // need to restrict old coefficient vectors first
     557             :   // _mesh.contract();
     558             : 
     559             :   // First coarsen the flagged elements.
     560             :   // Now refine the flagged elements.  This will
     561             :   // take up some space, maybe more than what was freed.
     562             :   const bool refining_changed_mesh =
     563       14912 :     this->_refine_elements();
     564             : 
     565             :   // First coarsen the flagged elements.
     566             :   // Finally, the new mesh needs to be prepared for use
     567       14912 :   if (coarsening_changed_mesh || refining_changed_mesh)
     568             :     {
     569             : #ifdef DEBUG
     570         554 :       _mesh.libmesh_assert_valid_parallel_ids();
     571             : #endif
     572             : 
     573       14912 :       _mesh.prepare_for_use ();
     574             : 
     575         554 :       if (_face_level_mismatch_limit)
     576         554 :         libmesh_assert(test_level_one(true));
     577         554 :       libmesh_assert(test_unflagged(true));
     578         554 :       libmesh_assert(this->make_coarsening_compatible());
     579         554 :       libmesh_assert(this->make_refinement_compatible());
     580             :       // FIXME: This won't pass unless we add a redundant find_neighbors()
     581             :       // call or replace find_neighbors() with on-the-fly neighbor updating
     582             :       // libmesh_assert(!this->eliminate_unrefined_patches());
     583             : 
     584       14912 :       return true;
     585             :     }
     586             :   else
     587             :     {
     588           0 :       if (_face_level_mismatch_limit)
     589           0 :         libmesh_assert(test_level_one(true));
     590           0 :       libmesh_assert(test_unflagged(true));
     591           0 :       libmesh_assert(this->make_coarsening_compatible());
     592           0 :       libmesh_assert(this->make_refinement_compatible());
     593             :     }
     594             : 
     595             :   // Otherwise there was no change in the mesh,
     596             :   // let the user know.  Also, there is no need
     597             :   // to prepare the mesh for use since it did not change.
     598           0 :   return false;
     599             : 
     600             : }
     601             : 
     602             : 
     603             : 
     604             : 
     605             : 
     606             : 
     607             : 
     608       22188 : bool MeshRefinement::coarsen_elements ()
     609             : {
     610             :   // This function must be run on all processors at once
     611         754 :   parallel_object_only();
     612             : 
     613             :   // We can't yet turn a non-level-one mesh into a level-one mesh
     614         754 :   if (_face_level_mismatch_limit)
     615           4 :     libmesh_assert(test_level_one(true));
     616             : 
     617             :   // Possibly clean up the refinement flags from
     618             :   // a previous step
     619    16522636 :   for (auto & elem : _mesh.element_ptr_range())
     620             :     {
     621             :       // Set refinement flag to INACTIVE if the
     622             :       // element isn't active
     623     8737603 :       if (!elem->active())
     624             :         {
     625      169654 :           elem->set_refinement_flag(Elem::INACTIVE);
     626      169654 :           elem->set_p_refinement_flag(Elem::INACTIVE);
     627             :         }
     628             : 
     629             :       // This might be left over from the last step
     630     8737603 :       if (elem->refinement_flag() == Elem::JUST_REFINED)
     631      131024 :         elem->set_refinement_flag(Elem::DO_NOTHING);
     632       20680 :     }
     633             : 
     634             :   // Parallel consistency has to come first, or coarsening
     635             :   // along processor boundaries might occasionally be falsely
     636             :   // prevented
     637       22188 :   bool flags_were_consistent = this->make_flags_parallel_consistent();
     638             : 
     639             :   // In theory, we should be able to remove the above call, which can
     640             :   // be expensive and should be unnecessary.  In practice, doing
     641             :   // consistent flagging in parallel is hard, it's impossible to
     642             :   // verify at the library level if it's being done by user code, and
     643             :   // we don't want to abort large parallel runs in opt mode... but we
     644             :   // do want to warn that they should be fixed.
     645         754 :   libmesh_assert(flags_were_consistent);
     646             : 
     647         754 :   if (!flags_were_consistent)
     648             :     libmesh_warning("Warning: Refinement flags were not consistent between processors! "
     649             :                     "Correcting and continuing.\n");
     650             : 
     651             :   // Smooth coarsening flags
     652       22188 :   _smooth_flags(false, true);
     653             : 
     654             :   // Coarsen the flagged elements.
     655             :   const bool mesh_changed =
     656       22188 :     this->_coarsen_elements ();
     657             : 
     658         754 :   if (_face_level_mismatch_limit)
     659           4 :     libmesh_assert(test_level_one(true));
     660         754 :   libmesh_assert(this->make_coarsening_compatible());
     661             :   // FIXME: This won't pass unless we add a redundant find_neighbors()
     662             :   // call or replace find_neighbors() with on-the-fly neighbor updating
     663             :   // libmesh_assert(!this->eliminate_unrefined_patches());
     664             : 
     665             :   // We can't contract the mesh ourselves anymore - a System might
     666             :   // need to restrict old coefficient vectors first
     667             :   // _mesh.contract();
     668             : 
     669             :   // Finally, the new mesh may need to be prepared for use
     670       22188 :   if (mesh_changed)
     671         142 :     _mesh.prepare_for_use ();
     672             : 
     673       22188 :   return mesh_changed;
     674             : }
     675             : 
     676             : 
     677             : 
     678             : 
     679             : 
     680             : 
     681             : 
     682       23103 : bool MeshRefinement::refine_elements ()
     683             : {
     684             :   // This function must be run on all processors at once
     685         778 :   parallel_object_only();
     686             : 
     687             :   // Prevent refinement when the mesh has disconnected boundaries.
     688             :   //
     689             :   // Disconnected boundary interfaces violate the topological continuity
     690             :   // assumed by the refinement algorithm. Refinement on such meshes can
     691             :   // produce invalid neighbor relationships (for example reverse indices
     692             :   // equal to invalid_uint), which may trigger assertions like
     693             :   // `rev < neigh->n_neighbors()` or corrupt neighbor data.
     694             :   //
     695             :   // For safety, refinement is disabled while disconnected boundaries are
     696             :   // present.
     697       23103 :   if (_mesh.get_disconnected_boundaries())
     698             :     {
     699         142 :       libmesh_error_msg(
     700             :         "Mesh contains disconnected boundary interfaces; refinement is disabled.\n"
     701             :         "MeshRefinement::refine_elements() cannot proceed because disconnected\n"
     702             :         "boundaries may produce invalid neighbor relations. Please remove or\n"
     703             :         "repair disconnected boundary interfaces before attempting refinement.");
     704             :     }
     705             : 
     706         776 :   if (_face_level_mismatch_limit)
     707          26 :     libmesh_assert(test_level_one(true));
     708             : 
     709             :   // Possibly clean up the refinement flags from
     710             :   // a previous step
     711    14248472 :   for (auto & elem : _mesh.element_ptr_range())
     712             :     {
     713             :       // Set refinement flag to INACTIVE if the
     714             :       // element isn't active
     715     7544284 :       if (!elem->active())
     716             :         {
     717      103754 :           elem->set_refinement_flag(Elem::INACTIVE);
     718      103754 :           elem->set_p_refinement_flag(Elem::INACTIVE);
     719             :         }
     720             : 
     721             :       // This might be left over from the last step
     722     7544284 :       if (elem->refinement_flag() == Elem::JUST_REFINED)
     723           6 :         elem->set_refinement_flag(Elem::DO_NOTHING);
     724       21480 :     }
     725             : 
     726             :   // Parallel consistency has to come first, or coarsening
     727             :   // along processor boundaries might occasionally be falsely
     728             :   // prevented
     729       23032 :   bool flags_were_consistent = this->make_flags_parallel_consistent();
     730             : 
     731             :   // In theory, we should be able to remove the above call, which can
     732             :   // be expensive and should be unnecessary.  In practice, doing
     733             :   // consistent flagging in parallel is hard, it's impossible to
     734             :   // verify at the library level if it's being done by user code, and
     735             :   // we don't want to abort large parallel runs in opt mode... but we
     736             :   // do want to warn that they should be fixed.
     737         776 :   libmesh_assert(flags_were_consistent);
     738             : 
     739         776 :   if (!flags_were_consistent)
     740             :     libmesh_warning("Warning: Refinement flags were not consistent between processors! "
     741             :                     "Correcting and continuing.\n");
     742             : 
     743             :   // Smooth refinement flags
     744       23032 :   _smooth_flags(true, false);
     745             : 
     746             :   // Now refine the flagged elements.  This will
     747             :   // take up some space, maybe more than what was freed.
     748             :   const bool mesh_changed =
     749       23032 :     this->_refine_elements();
     750             : 
     751         776 :   if (_face_level_mismatch_limit)
     752          26 :     libmesh_assert(test_level_one(true));
     753         776 :   libmesh_assert(this->make_refinement_compatible());
     754             : 
     755             :   // FIXME: This won't pass unless we add a redundant find_neighbors()
     756             :   // call or replace find_neighbors() with on-the-fly neighbor updating
     757             :   // libmesh_assert(!this->eliminate_unrefined_patches());
     758             : 
     759             :   // Finally, the new mesh needs to be prepared for use
     760       23032 :   if (mesh_changed)
     761        2193 :     _mesh.prepare_for_use ();
     762             : 
     763       23032 :   return mesh_changed;
     764             : }
     765             : 
     766             : 
     767             : 
     768       89607 : bool MeshRefinement::make_flags_parallel_consistent()
     769             : {
     770             :   // This function must be run on all processors at once
     771        2126 :   parallel_object_only();
     772             : 
     773        2126 :   LOG_SCOPE ("make_flags_parallel_consistent()", "MeshRefinement");
     774             : 
     775             :   SyncRefinementFlags hsync(_mesh, &Elem::refinement_flag,
     776       89607 :                             &Elem::set_refinement_flag);
     777             :   Parallel::sync_dofobject_data_by_id
     778      177088 :     (this->comm(), _mesh.elements_begin(), _mesh.elements_end(), hsync);
     779             : 
     780             :   SyncRefinementFlags psync(_mesh, &Elem::p_refinement_flag,
     781       89607 :                             &Elem::set_p_refinement_flag);
     782             :   Parallel::sync_dofobject_data_by_id
     783      177088 :     (this->comm(), _mesh.elements_begin(), _mesh.elements_end(), psync);
     784             : 
     785             :   // If we weren't consistent in both h and p on every processor then
     786             :   // we weren't globally consistent
     787      177404 :   bool parallel_consistent = hsync.parallel_consistent &&
     788       89358 :     psync.parallel_consistent;
     789       89607 :   this->comm().min(parallel_consistent);
     790             : 
     791       91733 :   return parallel_consistent;
     792             : }
     793             : 
     794             : 
     795             : 
     796       45498 : bool MeshRefinement::make_coarsening_compatible()
     797             : {
     798             :   // This function must be run on all processors at once
     799        2780 :   parallel_object_only();
     800             : 
     801             :   // We may need a PointLocator for topological_neighbor() tests
     802             :   // later, which we need to make sure gets constructed on all
     803             :   // processors at once.
     804       44026 :   std::unique_ptr<PointLocatorBase> point_locator;
     805             : 
     806             : #ifdef LIBMESH_ENABLE_PERIODIC
     807             :   bool has_periodic_boundaries =
     808       45498 :     _periodic_boundaries && !_periodic_boundaries->empty();
     809        2780 :   libmesh_assert(this->comm().verify(has_periodic_boundaries));
     810             : 
     811        2780 :   if (has_periodic_boundaries)
     812         532 :     point_locator = _mesh.sub_point_locator();
     813             : #endif
     814             : 
     815        5560 :   LOG_SCOPE ("make_coarsening_compatible()", "MeshRefinement");
     816             : 
     817             :   // Unless we encounter a specific situation level-one
     818             :   // will be satisfied after executing this loop just once
     819        2780 :   bool level_one_satisfied = true;
     820             : 
     821             : 
     822             :   // Unless we encounter a specific situation we will be compatible
     823             :   // with any selected refinement flags
     824       45498 :   bool compatible_with_refinement = true;
     825             : 
     826             : 
     827             :   // find the maximum h and p levels in the mesh
     828       45498 :   unsigned int max_level = 0;
     829       45498 :   unsigned int max_p_level = 0;
     830             : 
     831             :   {
     832             :     // First we look at all the active level-0 elements.  Since it doesn't make
     833             :     // sense to coarsen them we must un-set their coarsen flags if
     834             :     // they are set.
     835    26163104 :     for (auto & elem : _mesh.active_element_ptr_range())
     836             :       {
     837    13985444 :         max_level = std::max(max_level, elem->level());
     838    13985444 :         max_p_level =
     839    13985444 :           std::max(max_p_level,
     840    14650840 :                    static_cast<unsigned int>(elem->p_level()));
     841             : 
     842    13998152 :         if ((elem->level() == 0) &&
     843      107667 :             (elem->refinement_flag() == Elem::COARSEN))
     844         850 :           elem->set_refinement_flag(Elem::DO_NOTHING);
     845             : 
     846    15210862 :         if ((elem->p_level() == 0) &&
     847     1225418 :             (elem->p_refinement_flag() == Elem::COARSEN))
     848          10 :           elem->set_p_refinement_flag(Elem::DO_NOTHING);
     849       41246 :       }
     850             :   }
     851             : 
     852             :   // Even if there are no refined elements on this processor then
     853             :   // there may still be work for us to do on e.g. ancestor elements.
     854             :   // At the very least we need to be in the loop if a distributed mesh
     855             :   // needs to synchronize data.
     856             : #if 0
     857             :   if (max_level == 0 && max_p_level == 0)
     858             :     {
     859             :       // But we still have to check with other processors
     860             :       this->comm().min(compatible_with_refinement);
     861             : 
     862             :       return compatible_with_refinement;
     863             :     }
     864             : #endif
     865             : 
     866             :   // Loop over all the active elements.  If an element is marked
     867             :   // for coarsening we better check its neighbors.  If ANY of these neighbors
     868             :   // are marked for refinement AND are at the same level then there is a
     869             :   // conflict.  By convention refinement wins, so we un-mark the element for
     870             :   // coarsening.  Level-one would be violated in this case so we need to re-run
     871             :   // the loop.
     872       45498 :   if (_face_level_mismatch_limit)
     873             :     {
     874             : 
     875       22631 :     repeat:
     876        1550 :       level_one_satisfied = true;
     877             : 
     878         276 :       do
     879             :         {
     880        1826 :           level_one_satisfied = true;
     881             : 
     882    32804114 :           for (auto & elem : _mesh.active_element_ptr_range())
     883             :             {
     884      969368 :               bool my_flag_changed = false;
     885             : 
     886    17952310 :               if (elem->refinement_flag() == Elem::COARSEN) // If the element is active and
     887             :                 // the coarsen flag is set
     888             :                 {
     889     3719062 :                   const unsigned int my_level = elem->level();
     890             : 
     891    15922974 :                   for (auto n : elem->side_index_range())
     892             :                     {
     893             :                       const Elem * neighbor =
     894    12182974 :                         topological_neighbor(elem, point_locator.get(), n);
     895             : 
     896    12182974 :                       if (neighbor != nullptr &&      // I have a
     897    11960635 :                           neighbor != remote_elem) // neighbor here
     898             :                         {
     899     1043756 :                           if (neighbor->active()) // and it is active
     900             :                             {
     901    12280832 :                               if ((neighbor->level() == my_level) &&
     902      455326 :                                   (neighbor->refinement_flag() == Elem::REFINE)) // the neighbor is at my level
     903             :                                 // and wants to be refined
     904             :                                 {
     905       11656 :                                   elem->set_refinement_flag(Elem::DO_NOTHING);
     906         740 :                                   my_flag_changed = true;
     907       11656 :                                   break;
     908             :                                 }
     909             :                             }
     910             :                           else // I have a neighbor and it is not active. That means it has children.
     911             :                             {  // While it _may_ be possible to coarsen us if all the children of
     912             :                               // that element want to be coarsened, it is impossible to know at this
     913             :                               // stage.  Forget about it for the moment...  This can be handled in
     914             :                               // two steps.
     915      119730 :                               elem->set_refinement_flag(Elem::DO_NOTHING);
     916        6592 :                               my_flag_changed = true;
     917      119730 :                               break;
     918             :                             }
     919             :                         }
     920             :                     }
     921             :                 }
     922    17952310 :               if (elem->p_refinement_flag() == Elem::COARSEN) // If
     923             :                 // the element is active and the order reduction flag is set
     924             :                 {
     925         164 :                   const unsigned int my_p_level = elem->p_level();
     926             : 
     927        7129 :                   for (auto n : elem->side_index_range())
     928             :                     {
     929             :                       const Elem * neighbor =
     930        5896 :                         topological_neighbor(elem, point_locator.get(), n);
     931             : 
     932        5896 :                       if (neighbor != nullptr &&      // I have a
     933        4637 :                           neighbor != remote_elem) // neighbor here
     934             :                         {
     935         388 :                           if (neighbor->active()) // and it is active
     936             :                             {
     937         348 :                               if ((neighbor->p_level() > my_p_level &&
     938           0 :                                    neighbor->p_refinement_flag() != Elem::COARSEN)
     939        3772 :                                   || (neighbor->p_level() == my_p_level &&
     940         116 :                                       neighbor->p_refinement_flag() == Elem::REFINE))
     941             :                                 {
     942         217 :                                   elem->set_p_refinement_flag(Elem::DO_NOTHING);
     943          14 :                                   my_flag_changed = true;
     944          14 :                                   break;
     945             :                                 }
     946             :                             }
     947             :                           else // I have a neighbor and it is not active.
     948             :                             {  // We need to find which of its children
     949             :                               // have me as a neighbor, and maintain
     950             :                               // level one p compatibility with them.
     951             :                               // Because we currently have level one h
     952             :                               // compatibility, we don't need to check
     953             :                               // grandchildren
     954             : 
     955          20 :                               libmesh_assert(neighbor->has_children());
     956        1616 :                               for (auto & subneighbor : neighbor->child_ref_range())
     957        1513 :                                 if (&subneighbor != remote_elem &&
     958        2362 :                                     subneighbor.active() &&
     959         973 :                                     has_topological_neighbor(&subneighbor, point_locator.get(), elem))
     960         598 :                                   if ((subneighbor.p_level() > my_p_level &&
     961          34 :                                        subneighbor.p_refinement_flag() != Elem::COARSEN)
     962        1014 :                                       || (subneighbor.p_level() == my_p_level &&
     963           0 :                                           subneighbor.p_refinement_flag() == Elem::REFINE))
     964             :                                     {
     965         194 :                                       elem->set_p_refinement_flag(Elem::DO_NOTHING);
     966          12 :                                       my_flag_changed = true;
     967          12 :                                       break;
     968             :                                     }
     969         239 :                               if (my_flag_changed)
     970          20 :                                 break;
     971             :                             }
     972             :                         }
     973             :                     }
     974             :                 }
     975             : 
     976             :               // If the current element's flag changed, we hadn't
     977             :               // satisfied the level one rule.
     978    17219513 :               if (my_flag_changed)
     979        7340 :                 level_one_satisfied = false;
     980             : 
     981             :               // Additionally, if it has non-local neighbors, and
     982             :               // we're not in serial, then we'll eventually have to
     983             :               // return compatible_with_refinement = false, because
     984             :               // our change has to propagate to neighboring
     985             :               // processors.
     986     1818779 :               if (my_flag_changed && !_mesh.is_serial())
     987       15951 :                 for (auto n : elem->side_index_range())
     988             :                   {
     989             :                     Elem * neigh =
     990       14885 :                       topological_neighbor(elem, point_locator.get(), n);
     991             : 
     992       14885 :                     if (!neigh)
     993        2931 :                       continue;
     994       11954 :                     if (neigh == remote_elem ||
     995       10998 :                         neigh->processor_id() !=
     996           0 :                         this->processor_id())
     997             :                       {
     998        5342 :                         compatible_with_refinement = false;
     999        5342 :                         break;
    1000             :                       }
    1001             :                     // FIXME - for non-level one meshes we should
    1002             :                     // test all descendants
    1003           0 :                     if (neigh->has_children())
    1004        2074 :                       for (auto & child : neigh->child_ref_range())
    1005        1732 :                         if (&child == remote_elem ||
    1006        1732 :                             child.processor_id() !=
    1007           0 :                             this->processor_id())
    1008             :                           {
    1009         258 :                             compatible_with_refinement = false;
    1010         258 :                             break;
    1011             :                           }
    1012             :                   }
    1013       31141 :             }
    1014             :         }
    1015       34235 :       while (!level_one_satisfied);
    1016             : 
    1017             :     } // end if (_face_level_mismatch_limit)
    1018             : 
    1019             : 
    1020             :   // Next we look at all of the ancestor cells.
    1021             :   // If there is a parent cell with all of its children
    1022             :   // wanting to be unrefined then the element is a candidate
    1023             :   // for unrefinement.  If all the children don't
    1024             :   // all want to be unrefined then ALL of them need to have their
    1025             :   // unrefinement flags cleared.
    1026      246496 :   for (int level = max_level; level >= 0; level--)
    1027    50098546 :     for (auto & elem : as_range(_mesh.level_elements_begin(level), _mesh.level_elements_end(level)))
    1028    26385808 :       if (elem->ancestor())
    1029             :         {
    1030             :           // right now the element hasn't been disqualified
    1031             :           // as a candidate for unrefinement
    1032      460104 :           bool is_a_candidate = true;
    1033      460104 :           bool found_remote_child = false;
    1034             : 
    1035    31987157 :           for (auto & child : elem->child_ref_range())
    1036             :             {
    1037    25413056 :               if (&child == remote_elem)
    1038          40 :                 found_remote_child = true;
    1039    24976131 :               else if ((child.refinement_flag() != Elem::COARSEN) ||
    1040      109666 :                        !child.active() )
    1041     1760130 :                 is_a_candidate = false;
    1042             :             }
    1043             : 
    1044     6291389 :           if (!is_a_candidate && !found_remote_child)
    1045             :             {
    1046     5516346 :               elem->set_refinement_flag(Elem::INACTIVE);
    1047             : 
    1048    27680682 :               for (auto & child : elem->child_ref_range())
    1049             :                 {
    1050    22164336 :                   if (&child == remote_elem)
    1051           0 :                     continue;
    1052    22164336 :                   if (child.refinement_flag() == Elem::COARSEN)
    1053             :                     {
    1054       20714 :                       level_one_satisfied = false;
    1055       20714 :                       child.set_refinement_flag(Elem::DO_NOTHING);
    1056             :                     }
    1057             :                 }
    1058             :             }
    1059      174154 :         }
    1060             : 
    1061       51338 :   if (!level_one_satisfied && _face_level_mismatch_limit) goto repeat;
    1062             : 
    1063             : 
    1064             :   // If all the children of a parent are set to be coarsened
    1065             :   // then flag the parent so that they can kill their kids.
    1066             : 
    1067             :   // On a distributed mesh, we won't always be able to determine this
    1068             :   // on parent elements with remote children, even if we own the
    1069             :   // parent, without communication.
    1070             :   //
    1071             :   // We'll first communicate *to* parents' owners when we determine
    1072             :   // they cannot be coarsened, then we'll sync the final refinement
    1073             :   // flag *from* the parents.
    1074             : 
    1075             :   // uncoarsenable_parents[p] live on processor id p
    1076       45498 :   const processor_id_type n_proc     = _mesh.n_processors();
    1077        2780 :   const processor_id_type my_proc_id = _mesh.processor_id();
    1078       45498 :   const bool distributed_mesh = !_mesh.is_replicated();
    1079             : 
    1080             :   std::vector<std::vector<dof_id_type>>
    1081       45498 :     uncoarsenable_parents(n_proc);
    1082             : 
    1083     8847346 :   for (auto & elem : as_range(_mesh.ancestor_elements_begin(), _mesh.ancestor_elements_end()))
    1084             :     {
    1085             :       // Presume all the children are flagged for coarsening and
    1086             :       // then look for a contradiction
    1087      390504 :       bool all_children_flagged_for_coarsening = true;
    1088             : 
    1089     7619053 :       for (auto & child : elem->child_ref_range())
    1090             :         {
    1091     7207383 :           if (&child != remote_elem &&
    1092      425348 :               child.refinement_flag() != Elem::COARSEN)
    1093             :             {
    1094      379092 :               all_children_flagged_for_coarsening = false;
    1095     5123085 :               if (!distributed_mesh)
    1096      378940 :                 break;
    1097     1184162 :               if (child.processor_id() != elem->processor_id())
    1098             :                 {
    1099       97185 :                   uncoarsenable_parents[elem->processor_id()].push_back(elem->id());
    1100           0 :                   break;
    1101             :                 }
    1102             :             }
    1103             :         }
    1104             : 
    1105     4562829 :       if (all_children_flagged_for_coarsening)
    1106      301654 :         elem->set_refinement_flag(Elem::COARSEN_INACTIVE);
    1107             :       else
    1108     4358360 :         elem->set_refinement_flag(Elem::INACTIVE);
    1109       41246 :     }
    1110             : 
    1111             :   // If we have a distributed mesh, we might need to sync up
    1112             :   // INACTIVE vs. COARSEN_INACTIVE flags.
    1113       45498 :   if (distributed_mesh)
    1114             :     {
    1115             :       // We'd better still be in sync here
    1116           8 :       parallel_object_only();
    1117             : 
    1118             :       Parallel::MessageTag
    1119       29436 :         uncoarsenable_tag = this->comm().get_unique_tag();
    1120       29424 :       std::vector<Parallel::Request> uncoarsenable_push_requests(n_proc-1);
    1121             : 
    1122      342314 :       for (processor_id_type p = 0; p != n_proc; ++p)
    1123             :         {
    1124      312890 :           if (p == my_proc_id)
    1125       29420 :             continue;
    1126             : 
    1127             :           Parallel::Request &request =
    1128      283466 :             uncoarsenable_push_requests[p - (p > my_proc_id)];
    1129             : 
    1130      283466 :           _mesh.comm().send
    1131      283466 :             (p, uncoarsenable_parents[p], request, uncoarsenable_tag);
    1132             :         }
    1133             : 
    1134      312890 :       for (processor_id_type p = 1; p != n_proc; ++p)
    1135             :         {
    1136          16 :           std::vector<dof_id_type> my_uncoarsenable_parents;
    1137      283466 :           _mesh.comm().receive
    1138      283466 :             (Parallel::any_source, my_uncoarsenable_parents,
    1139          12 :              uncoarsenable_tag);
    1140             : 
    1141      355541 :           for (const auto & id : my_uncoarsenable_parents)
    1142             :             {
    1143       72075 :               Elem & elem = _mesh.elem_ref(id);
    1144           0 :               libmesh_assert(elem.refinement_flag() == Elem::INACTIVE ||
    1145             :                              elem.refinement_flag() == Elem::COARSEN_INACTIVE);
    1146           0 :               elem.set_refinement_flag(Elem::INACTIVE);
    1147             :             }
    1148             :         }
    1149             : 
    1150       29424 :       Parallel::wait(uncoarsenable_push_requests);
    1151             : 
    1152             :       SyncRefinementFlags hsync(_mesh, &Elem::refinement_flag,
    1153       29424 :                                 &Elem::set_refinement_flag);
    1154             :       sync_dofobject_data_by_id
    1155       58840 :         (this->comm(), _mesh.not_local_elements_begin(),
    1156       29436 :          _mesh.not_local_elements_end(),
    1157             :          // We'd like a smaller sync, but this leads to bugs?
    1158             :          // SyncCoarsenInactive(),
    1159             :          hsync);
    1160       29412 :     }
    1161             : 
    1162             :   // If one processor finds an incompatibility, we're globally
    1163             :   // incompatible
    1164       45498 :   this->comm().min(compatible_with_refinement);
    1165             : 
    1166       90996 :   return compatible_with_refinement;
    1167       41246 : }
    1168             : 
    1169             : 
    1170             : 
    1171             : 
    1172             : 
    1173             : 
    1174             : 
    1175             : 
    1176       46488 : bool MeshRefinement::make_refinement_compatible()
    1177             : {
    1178             :   // This function must be run on all processors at once
    1179        2826 :   parallel_object_only();
    1180             : 
    1181             :   // We may need a PointLocator for topological_neighbor() tests
    1182             :   // later, which we need to make sure gets constructed on all
    1183             :   // processors at once.
    1184       44992 :   std::unique_ptr<PointLocatorBase> point_locator;
    1185             : 
    1186             : #ifdef LIBMESH_ENABLE_PERIODIC
    1187             :   bool has_periodic_boundaries =
    1188       46488 :     _periodic_boundaries && !_periodic_boundaries->empty();
    1189        2826 :   libmesh_assert(this->comm().verify(has_periodic_boundaries));
    1190             : 
    1191        2826 :   if (has_periodic_boundaries)
    1192         532 :     point_locator = _mesh.sub_point_locator();
    1193             : #endif
    1194             : 
    1195        2826 :   LOG_SCOPE ("make_refinement_compatible()", "MeshRefinement");
    1196             : 
    1197             :   // Unless we encounter a specific situation we will be compatible
    1198             :   // with any selected coarsening flags
    1199       46488 :   bool compatible_with_coarsening = true;
    1200             : 
    1201             :   // This loop enforces the level-1 rule.  We should only
    1202             :   // execute it if the user indeed wants level-1 satisfied!
    1203       46488 :   if (_face_level_mismatch_limit)
    1204             :     {
    1205             :       // Unless we encounter a specific situation level-one
    1206             :       // will be satisfied after executing this loop just once
    1207        1326 :       bool level_one_satisfied = true;
    1208             : 
    1209         190 :       do
    1210             :         {
    1211        1516 :           level_one_satisfied = true;
    1212             : 
    1213    22171276 :           for (auto & elem : _mesh.active_element_ptr_range())
    1214             :             {
    1215    11674175 :               const unsigned short n_sides = elem->n_sides();
    1216             : 
    1217    12159389 :               if (elem->refinement_flag() == Elem::REFINE)  // If the element is active and the
    1218             :                 // h refinement flag is set
    1219             :                 {
    1220      362482 :                   const unsigned int my_level = elem->level();
    1221             : 
    1222     1799102 :                   for (unsigned short side = 0; side != n_sides;
    1223             :                        ++side)
    1224             :                     {
    1225             :                       Elem * neighbor =
    1226     1436620 :                         topological_neighbor(elem, point_locator.get(), side);
    1227             : 
    1228     1437052 :                       if (neighbor != nullptr        && // I have a
    1229     1511278 :                           neighbor != remote_elem && // neighbor here
    1230      149298 :                           neighbor->active()) // and it is active
    1231             :                         {
    1232             :                           // Case 1:  The neighbor is at the same level I am.
    1233             :                           //        1a: The neighbor will be refined       -> NO PROBLEM
    1234             :                           //        1b: The neighbor won't be refined      -> NO PROBLEM
    1235             :                           //        1c: The neighbor wants to be coarsened -> PROBLEM
    1236     1020525 :                           if (neighbor->level() == my_level)
    1237             :                             {
    1238      927092 :                               if (neighbor->refinement_flag() == Elem::COARSEN)
    1239             :                                 {
    1240           0 :                                   neighbor->set_refinement_flag(Elem::DO_NOTHING);
    1241           7 :                                   if (neighbor->parent())
    1242           0 :                                     neighbor->parent()->set_refinement_flag(Elem::INACTIVE);
    1243           7 :                                   compatible_with_coarsening = false;
    1244           0 :                                   level_one_satisfied = false;
    1245             :                                 }
    1246             :                             }
    1247             : 
    1248             : 
    1249             :                           // Case 2: The neighbor is one level lower than I am.
    1250             :                           //         The neighbor thus MUST be refined to satisfy
    1251             :                           //         the level-one rule, regardless of whether it
    1252             :                           //         was originally flagged for refinement. If it
    1253             :                           //         wasn't flagged already we need to repeat
    1254             :                           //         this process.
    1255       93433 :                           else if ((neighbor->level()+1) == my_level)
    1256             :                             {
    1257       93433 :                               if (neighbor->refinement_flag() != Elem::REFINE)
    1258             :                                 {
    1259         570 :                                   neighbor->set_refinement_flag(Elem::REFINE);
    1260       11188 :                                   if (neighbor->parent())
    1261         424 :                                     neighbor->parent()->set_refinement_flag(Elem::INACTIVE);
    1262       10618 :                                   compatible_with_coarsening = false;
    1263         570 :                                   level_one_satisfied = false;
    1264             :                                 }
    1265             :                             }
    1266             : #ifdef DEBUG
    1267             :                           // Note that the only other possibility is that the
    1268             :                           // neighbor is already refined, in which case it isn't
    1269             :                           // active and we should never get here.
    1270             :                           else
    1271           0 :                             libmesh_error_msg("ERROR: Neighbor level must be equal or 1 higher than mine.");
    1272             : #endif
    1273             :                         }
    1274             :                     }
    1275             :                 }
    1276    12159389 :               if (elem->p_refinement_flag() == Elem::REFINE)  // If the element is active and the
    1277             :                 // p refinement flag is set
    1278             :                 {
    1279        2814 :                   const unsigned int my_p_level = elem->p_level();
    1280             : 
    1281      129865 :                   for (unsigned int side=0; side != n_sides; side++)
    1282             :                     {
    1283             :                       Elem * neighbor =
    1284      109624 :                         topological_neighbor(elem, point_locator.get(), side);
    1285             : 
    1286      109624 :                       if (neighbor != nullptr &&      // I have a
    1287       90723 :                           neighbor != remote_elem) // neighbor here
    1288             :                         {
    1289       11932 :                           if (neighbor->active()) // and it is active
    1290             :                             {
    1291       86155 :                               if (neighbor->p_level() < my_p_level &&
    1292          24 :                                   neighbor->p_refinement_flag() != Elem::REFINE)
    1293             :                                 {
    1294           4 :                                   neighbor->set_p_refinement_flag(Elem::REFINE);
    1295           4 :                                   level_one_satisfied = false;
    1296          22 :                                   compatible_with_coarsening = false;
    1297             :                                 }
    1298       91943 :                               if (neighbor->p_level() == my_p_level &&
    1299        5812 :                                   neighbor->p_refinement_flag() == Elem::COARSEN)
    1300             :                                 {
    1301           0 :                                   neighbor->set_p_refinement_flag(Elem::DO_NOTHING);
    1302           0 :                                   level_one_satisfied = false;
    1303           0 :                                   compatible_with_coarsening = false;
    1304             :                                 }
    1305             :                             }
    1306             :                           else // I have an inactive neighbor
    1307             :                             {
    1308          62 :                               libmesh_assert(neighbor->has_children());
    1309        1842 :                               for (auto & subneighbor : neighbor->child_ref_range())
    1310        2251 :                                 if (&subneighbor != remote_elem && subneighbor.active() &&
    1311        1023 :                                     has_topological_neighbor(&subneighbor, point_locator.get(), elem))
    1312             :                                   {
    1313         720 :                                     if (subneighbor.p_level() < my_p_level &&
    1314          44 :                                         subneighbor.p_refinement_flag() != Elem::REFINE)
    1315             :                                       {
    1316             :                                         // We should already be level one
    1317             :                                         // compatible
    1318           6 :                                         libmesh_assert_greater (subneighbor.p_level() + 2u,
    1319             :                                                                 my_p_level);
    1320           6 :                                         subneighbor.set_p_refinement_flag(Elem::REFINE);
    1321           6 :                                         level_one_satisfied = false;
    1322          70 :                                         compatible_with_coarsening = false;
    1323             :                                       }
    1324         694 :                                     if (subneighbor.p_level() == my_p_level &&
    1325          18 :                                         subneighbor.p_refinement_flag() == Elem::COARSEN)
    1326             :                                       {
    1327           0 :                                         subneighbor.set_p_refinement_flag(Elem::DO_NOTHING);
    1328           0 :                                         level_one_satisfied = false;
    1329           0 :                                         compatible_with_coarsening = false;
    1330             :                                       }
    1331             :                                   }
    1332             :                             }
    1333             :                         }
    1334             :                     }
    1335             :                 }
    1336       25180 :             }
    1337             :         }
    1338             : 
    1339       27632 :       while (!level_one_satisfied);
    1340             :     } // end if (_face_level_mismatch_limit)
    1341             : 
    1342             :   // If we're not compatible on one processor, we're globally not
    1343             :   // compatible
    1344       46488 :   this->comm().min(compatible_with_coarsening);
    1345             : 
    1346       50810 :   return compatible_with_coarsening;
    1347       42166 : }
    1348             : 
    1349             : 
    1350             : 
    1351             : 
    1352       38232 : bool MeshRefinement::_coarsen_elements ()
    1353             : {
    1354             :   // This function must be run on all processors at once
    1355        1340 :   parallel_object_only();
    1356             : 
    1357        1340 :   LOG_SCOPE ("_coarsen_elements()", "MeshRefinement");
    1358             : 
    1359             :   // Flags indicating if this call actually changes the mesh
    1360       38232 :   bool mesh_changed = false;
    1361       38232 :   bool mesh_p_changed = false;
    1362             : 
    1363             :   // Clear the unused_elements data structure.
    1364             :   // The elements have been packed since it was built,
    1365             :   // so there are _no_ unused elements.  We cannot trust
    1366             :   // any iterators currently in this data structure.
    1367             :   // _unused_elements.clear();
    1368             : 
    1369             :   // Loop over the elements first to determine if the mesh will
    1370             :   // undergo h-coarsening.  If it will, then we'll need to communicate
    1371             :   // more ghosted elements.  We need to communicate them *before* we
    1372             :   // do the coarsening; otherwise it is possible to coarsen away a
    1373             :   // one-element-thick layer partition and leave the partitions on
    1374             :   // either side unable to figure out how to talk to each other.
    1375    19605926 :   for (auto & elem : _mesh.element_ptr_range())
    1376    10938996 :     if (elem->refinement_flag() == Elem::COARSEN)
    1377             :       {
    1378        4914 :         mesh_changed = true;
    1379        4914 :         break;
    1380       35552 :       }
    1381             : 
    1382             :   // If the mesh changed on any processor, it changed globally
    1383       38232 :   this->comm().max(mesh_changed);
    1384             : 
    1385             :   // And then we may need to widen the ghosting layers.
    1386       38232 :   if (mesh_changed)
    1387        4992 :     MeshCommunication().send_coarse_ghosts(_mesh);
    1388             : 
    1389    30328752 :   for (auto & elem : _mesh.element_ptr_range())
    1390             :     {
    1391             :       // Make sure we transfer the children's boundary id(s)
    1392             :       // up to its parent when necessary before coarsening.
    1393    16805756 :       _mesh.get_boundary_info().transfer_boundary_ids_from_children(elem);
    1394             : 
    1395             :       // active elements flagged for coarsening will
    1396             :       // no longer be deleted until MeshRefinement::contract()
    1397    16805756 :       if (elem->refinement_flag() == Elem::COARSEN)
    1398             :         {
    1399             :           // Huh?  no level-0 element should be active
    1400             :           // and flagged for coarsening.
    1401           0 :           libmesh_assert_not_equal_to (elem->level(), 0);
    1402             : 
    1403             :           // Remove this element from any neighbor
    1404             :           // lists that point to it.
    1405           0 :           elem->nullify_neighbors();
    1406             : 
    1407             :           // Remove any boundary information associated
    1408             :           // with this element if we do not allow children to have boundary info.
    1409             :           // Otherwise, we will do the removal in `transfer_boundary_ids_from_children`
    1410             :           // to make sure we don't delete the information before it is transferred
    1411           0 :           if (!_mesh.get_boundary_info().is_children_on_boundary_side())
    1412           0 :             _mesh.get_boundary_info().remove (elem);
    1413             : 
    1414             :           // Add this iterator to the _unused_elements
    1415             :           // data structure so we might fill it.
    1416             :           // The _unused_elements optimization is currently off.
    1417             :           // _unused_elements.push_back (it);
    1418             : 
    1419             :           // Don't delete the element until
    1420             :           // MeshRefinement::contract()
    1421             :           // _mesh.delete_elem(elem);
    1422             :         }
    1423             : 
    1424             :       // inactive elements flagged for coarsening
    1425             :       // will become active
    1426    15966288 :       else if (elem->refinement_flag() == Elem::COARSEN_INACTIVE)
    1427             :         {
    1428      345905 :           elem->coarsen();
    1429       17078 :           libmesh_assert (elem->active());
    1430             : 
    1431             :           // the mesh has certainly changed
    1432      345905 :           mesh_changed = true;
    1433             :         }
    1434    16805756 :       if (elem->p_refinement_flag() == Elem::COARSEN)
    1435             :         {
    1436         220 :           if (elem->p_level() > 0)
    1437             :             {
    1438          14 :               elem->set_p_refinement_flag(Elem::JUST_COARSENED);
    1439         206 :               elem->set_p_level(elem->p_level() - 1);
    1440         206 :               mesh_p_changed = true;
    1441             :             }
    1442             :           else
    1443             :             {
    1444           0 :               elem->set_p_refinement_flag(Elem::DO_NOTHING);
    1445             :             }
    1446             :         }
    1447       35552 :     }
    1448             : 
    1449       38232 :   this->comm().max(mesh_p_changed);
    1450             : 
    1451             :   // And we may need to update DistributedMesh values reflecting the changes
    1452       38232 :   if (mesh_changed)
    1453        4992 :     _mesh.update_parallel_id_counts();
    1454             : 
    1455             :   // Node processor ids may need to change if an element of that id
    1456             :   // was coarsened away
    1457       38232 :   if (mesh_changed && !_mesh.is_serial())
    1458             :     {
    1459             :       // Update the _new_nodes_map so that processors can
    1460             :       // find requested nodes
    1461        1164 :       this->update_nodes_map ();
    1462             : 
    1463        1164 :       MeshCommunication().make_nodes_parallel_consistent (_mesh);
    1464             : 
    1465             :       // Clear the _new_nodes_map
    1466        1164 :       this->clear();
    1467             : 
    1468             : #ifdef DEBUG
    1469           4 :       MeshTools::libmesh_assert_valid_procids<Node>(_mesh);
    1470             : #endif
    1471             :     }
    1472             : 
    1473             :   // If p levels changed all we need to do is make sure that parent p
    1474             :   // levels changed in sync
    1475       38232 :   if (mesh_p_changed && !_mesh.is_serial())
    1476             :     {
    1477         192 :       MeshCommunication().make_p_levels_parallel_consistent (_mesh);
    1478             :     }
    1479             : 
    1480       40912 :   return (mesh_changed || mesh_p_changed);
    1481             : }
    1482             : 
    1483             : 
    1484             : 
    1485       53335 : bool MeshRefinement::_refine_elements ()
    1486             : {
    1487        1854 :   libmesh_assert(_mesh.is_prepared() || _mesh.is_replicated());
    1488             : 
    1489             :   // This function must be run on all processors at once
    1490        1854 :   parallel_object_only();
    1491             : 
    1492             :   // Update the _new_nodes_map so that elements can
    1493             :   // find nodes to connect to.
    1494       53335 :   this->update_nodes_map ();
    1495             : 
    1496        3708 :   LOG_SCOPE ("_refine_elements()", "MeshRefinement");
    1497             : 
    1498             :   // Iterate over the elements, counting the elements
    1499             :   // flagged for h refinement.
    1500        1854 :   dof_id_type n_elems_flagged = 0;
    1501             : 
    1502    29877848 :   for (auto & elem : _mesh.element_ptr_range())
    1503    16541058 :     if (elem->refinement_flag() == Elem::REFINE)
    1504     1227148 :       n_elems_flagged++;
    1505             : 
    1506             :   // Construct a local vector of Elem * which have been
    1507             :   // previously marked for refinement.  We reserve enough
    1508             :   // space to allow for every element to be refined.
    1509        1854 :   std::vector<Elem *> local_copy_of_elements;
    1510       53335 :   local_copy_of_elements.reserve(n_elems_flagged);
    1511             : 
    1512             :   // If mesh p levels changed, we might need to synchronize parent p
    1513             :   // levels on a distributed mesh.
    1514       53335 :   bool mesh_p_changed = false;
    1515             : 
    1516             :   // Iterate over the elements, looking for elements flagged for
    1517             :   // refinement.
    1518             : 
    1519             :   // If we are on a ReplicatedMesh, then we just do the refinement in
    1520             :   // the same order on every processor and everything stays in sync.
    1521             : 
    1522             :   // If we are on a DistributedMesh, that's impossible.
    1523             :   //
    1524             :   // If the mesh is distributed, we need to make sure that if we end
    1525             :   // up as the owner of a new node, which might happen if that node is
    1526             :   // attached to one of our own elements, then we have given it a
    1527             :   // legitimate node id and our own processor id.  We generate
    1528             :   // legitimate node ids and use our own processor id when we are
    1529             :   // refining our own elements but not when we refine others'
    1530             :   // elements.  Therefore we want to refine our own elements *first*,
    1531             :   // thereby generating all nodes which might belong to us, and then
    1532             :   // refine others' elements *after*, thereby generating nodes with
    1533             :   // temporary ids which we know we will discard.
    1534             :   //
    1535             :   // Even if the DistributedMesh is serialized, we can't just treat it
    1536             :   // like a ReplicatedMesh, because DistributedMesh doesn't *trust*
    1537             :   // users to refine partitioned elements in a serialized way, so it
    1538             :   // assigns temporary ids, so we need to synchronize ids afterward to
    1539             :   // be safe anyway, so we might as well use the distributed mesh code
    1540             :   // path.
    1541    19351966 :   for (auto & elem : _mesh.is_replicated() ? _mesh.active_element_ptr_range() : _mesh.active_local_element_ptr_range())
    1542             :     {
    1543    10817660 :       if (elem->refinement_flag() == Elem::REFINE)
    1544      771922 :         local_copy_of_elements.push_back(elem);
    1545    10818968 :       if (elem->p_refinement_flag() == Elem::REFINE &&
    1546        2610 :           elem->active())
    1547             :         {
    1548       11045 :           elem->set_p_level(elem->p_level()+1);
    1549        9743 :           elem->set_p_refinement_flag(Elem::JUST_REFINED);
    1550        9743 :           mesh_p_changed = true;
    1551             :         }
    1552       49627 :     }
    1553             : 
    1554       53335 :   if (!_mesh.is_replicated())
    1555             :     {
    1556       75120 :       for (auto & elem : as_range(_mesh.active_not_local_elements_begin(),
    1557     1609478 :                                   _mesh.active_not_local_elements_end()))
    1558             :         {
    1559      730249 :           if (elem->refinement_flag() == Elem::REFINE)
    1560      405599 :             local_copy_of_elements.push_back(elem);
    1561      730249 :           if (elem->p_refinement_flag() == Elem::REFINE &&
    1562           0 :               elem->active())
    1563             :             {
    1564        8163 :               elem->set_p_level(elem->p_level()+1);
    1565        8163 :               elem->set_p_refinement_flag(Elem::JUST_REFINED);
    1566        8163 :               mesh_p_changed = true;
    1567             :             }
    1568       37371 :         }
    1569             :     }
    1570             : 
    1571             :   // Now iterate over the local copies and refine each one.
    1572             :   // This may resize the mesh's internal container and invalidate
    1573             :   // any existing iterators.
    1574     1230856 :   for (auto & elem : local_copy_of_elements)
    1575     1177521 :     elem->refine(*this);
    1576             : 
    1577             :   // The mesh changed if there were elements h refined
    1578       53335 :   bool mesh_changed = !local_copy_of_elements.empty();
    1579             : 
    1580             :   // If the mesh changed on any processor, it changed globally
    1581       53335 :   this->comm().max(mesh_changed);
    1582       53335 :   this->comm().max(mesh_p_changed);
    1583             : 
    1584             :   // And we may need to update DistributedMesh values reflecting the changes
    1585       53335 :   if (mesh_changed)
    1586       31071 :     _mesh.update_parallel_id_counts();
    1587             : 
    1588       53335 :   if (mesh_changed && !_mesh.is_replicated())
    1589             :     {
    1590       21505 :       MeshCommunication().make_elems_parallel_consistent (_mesh);
    1591       21505 :       MeshCommunication().make_new_nodes_parallel_consistent (_mesh);
    1592             : #ifdef DEBUG
    1593          38 :       _mesh.libmesh_assert_valid_parallel_ids();
    1594             : #endif
    1595             :     }
    1596             : 
    1597             :   // If we're refining a ReplicatedMesh, then we haven't yet assigned
    1598             :   // node processor ids.  But if we're refining a partitioned
    1599             :   // ReplicatedMesh, then we *need* to assign node processor ids.
    1600       55451 :   if (mesh_changed && _mesh.is_replicated() &&
    1601       62901 :       (_mesh.unpartitioned_elements_begin() ==
    1602       71409 :        _mesh.unpartitioned_elements_end()))
    1603        9252 :     Partitioner::set_node_processor_ids(_mesh);
    1604             : 
    1605       53335 :   if (mesh_p_changed && !_mesh.is_replicated())
    1606             :     {
    1607        2368 :       MeshCommunication().make_p_levels_parallel_consistent (_mesh);
    1608             :     }
    1609             : 
    1610             :   // Clear the _new_nodes_map and _unused_elements data structures.
    1611       53335 :   this->clear();
    1612             : 
    1613      106670 :   return (mesh_changed || mesh_p_changed);
    1614             : }
    1615             : 
    1616             : 
    1617       60132 : void MeshRefinement::_smooth_flags(bool refining, bool coarsening)
    1618             : {
    1619             :   // Smoothing can break in weird ways on a mesh with broken topology
    1620             : #ifdef DEBUG
    1621        2084 :   MeshTools::libmesh_assert_valid_neighbors(_mesh);
    1622             : #endif
    1623             : 
    1624             :   // Repeat until flag changes match on every processor
    1625           0 :   do
    1626             :     {
    1627             :       // Repeat until coarsening & refinement flags jive
    1628        2084 :       bool satisfied = false;
    1629         166 :       do
    1630             :         {
    1631             :           // If we're refining or coarsening, hit the corresponding
    1632             :           // face level test code.  Short-circuiting || is our friend
    1633             :           const bool coarsening_satisfied =
    1634      111607 :             !coarsening ||
    1635       44190 :             this->make_coarsening_compatible();
    1636             : 
    1637             :           const bool refinement_satisfied =
    1638      112575 :             !refining ||
    1639       45158 :             this->make_refinement_compatible();
    1640             : 
    1641             :           bool smoothing_satisfied =
    1642       67417 :             !this->eliminate_unrefined_patches();// &&
    1643             : 
    1644       67417 :           if (_edge_level_mismatch_limit)
    1645           0 :             smoothing_satisfied = smoothing_satisfied &&
    1646           0 :               !this->limit_level_mismatch_at_edge (_edge_level_mismatch_limit);
    1647             : 
    1648       67417 :           if (_node_level_mismatch_limit)
    1649           0 :             smoothing_satisfied = smoothing_satisfied &&
    1650           0 :               !this->limit_level_mismatch_at_node (_node_level_mismatch_limit);
    1651             : 
    1652       67417 :           if (_overrefined_boundary_limit>=0)
    1653       45190 :             smoothing_satisfied = smoothing_satisfied &&
    1654       21936 :               !this->limit_overrefined_boundary(_overrefined_boundary_limit);
    1655             : 
    1656       67417 :           if (_underrefined_boundary_limit>=0)
    1657       44622 :             smoothing_satisfied = smoothing_satisfied &&
    1658       21368 :               !this->limit_underrefined_boundary(_underrefined_boundary_limit);
    1659             : 
    1660       67417 :           satisfied = (coarsening_satisfied &&
    1661       69667 :                        refinement_satisfied &&
    1662             :                        smoothing_satisfied);
    1663             : 
    1664        2250 :           libmesh_assert(this->comm().verify(satisfied));
    1665             :         }
    1666       65167 :       while (!satisfied);
    1667             :     }
    1668      116518 :   while (!_mesh.is_serial() && !this->make_flags_parallel_consistent());
    1669       60132 : }
    1670             : 
    1671             : 
    1672           0 : void MeshRefinement::uniformly_p_refine (unsigned int n)
    1673             : {
    1674             :   // Refine n times
    1675           0 :   for (unsigned int rstep=0; rstep<n; rstep++)
    1676           0 :     for (auto & elem : _mesh.active_element_ptr_range())
    1677             :       {
    1678             :         // P refine all the active elements
    1679           0 :         elem->set_p_level(elem->p_level()+1);
    1680           0 :         elem->set_p_refinement_flag(Elem::JUST_REFINED);
    1681           0 :       }
    1682           0 : }
    1683             : 
    1684             : 
    1685             : 
    1686           0 : void MeshRefinement::uniformly_p_coarsen (unsigned int n)
    1687             : {
    1688             :   // Coarsen p times
    1689           0 :   for (unsigned int rstep=0; rstep<n; rstep++)
    1690           0 :     for (auto & elem : _mesh.active_element_ptr_range())
    1691           0 :       if (elem->p_level() > 0)
    1692             :         {
    1693             :           // P coarsen all the active elements
    1694           0 :           elem->set_p_level(elem->p_level()-1);
    1695           0 :           elem->set_p_refinement_flag(Elem::JUST_COARSENED);
    1696           0 :         }
    1697           0 : }
    1698             : 
    1699             : 
    1700             : 
    1701       13372 : void MeshRefinement::uniformly_refine (unsigned int n)
    1702             : {
    1703             :   // Refine n times
    1704             :   // FIXME - this won't work if n>1 and the mesh
    1705             :   // has already been attached to an equation system
    1706       28763 :   for (unsigned int rstep=0; rstep<n; rstep++)
    1707             :     {
    1708             :       // Clean up the refinement flags
    1709       15391 :       this->clean_refinement_flags();
    1710             : 
    1711             :       // Flag all the active elements for refinement.
    1712     1888224 :       for (auto & elem : _mesh.active_element_ptr_range())
    1713     1003696 :         elem->set_refinement_flag(Elem::REFINE);
    1714             : 
    1715             :       // Refine all the elements we just flagged.
    1716       15391 :       this->_refine_elements();
    1717             :     }
    1718             : 
    1719             :   // Finally, the new mesh probably needs to be prepared for use
    1720       13372 :   if (n > 0)
    1721       12167 :     _mesh.prepare_for_use ();
    1722       13372 : }
    1723             : 
    1724             : 
    1725             : 
    1726        1132 : void MeshRefinement::uniformly_coarsen (unsigned int n)
    1727             : {
    1728             :   // Coarsen n times
    1729        2264 :   for (unsigned int rstep=0; rstep<n; rstep++)
    1730             :     {
    1731             :       // Clean up the refinement flags
    1732        1132 :       this->clean_refinement_flags();
    1733             : 
    1734             :       // Flag all the active elements for coarsening.
    1735      471746 :       for (auto & elem : _mesh.active_element_ptr_range())
    1736             :         {
    1737      260509 :           elem->set_refinement_flag(Elem::COARSEN);
    1738      286261 :           if (elem->parent())
    1739       25752 :             elem->parent()->set_refinement_flag(Elem::COARSEN_INACTIVE);
    1740        1068 :         }
    1741             : 
    1742             :       // On a distributed mesh, we may have parent elements with
    1743             :       // remote active children.  To keep flags consistent, we'll need
    1744             :       // a communication step.
    1745        1132 :       if (!_mesh.is_replicated())
    1746             :         {
    1747         908 :           const processor_id_type n_proc = _mesh.n_processors();
    1748           4 :           const processor_id_type my_proc_id = _mesh.processor_id();
    1749             : 
    1750             :           std::vector<std::vector<dof_id_type>>
    1751         916 :             parents_to_coarsen(n_proc);
    1752             : 
    1753      117848 :           for (const auto & elem : as_range(_mesh.ancestor_elements_begin(), _mesh.ancestor_elements_end()))
    1754       57878 :             if (elem->processor_id() != my_proc_id &&
    1755          48 :                 elem->refinement_flag() == Elem::COARSEN_INACTIVE)
    1756       14280 :               parents_to_coarsen[elem->processor_id()].push_back(elem->id());
    1757             : 
    1758             :           Parallel::MessageTag
    1759         916 :             coarsen_tag = this->comm().get_unique_tag();
    1760         908 :           std::vector<Parallel::Request> coarsen_push_requests(n_proc-1);
    1761             : 
    1762       10452 :           for (processor_id_type p = 0; p != n_proc; ++p)
    1763             :             {
    1764        9544 :               if (p == my_proc_id)
    1765         904 :                 continue;
    1766             : 
    1767             :               Parallel::Request &request =
    1768        8636 :                 coarsen_push_requests[p - (p > my_proc_id)];
    1769             : 
    1770        8636 :               _mesh.comm().send
    1771        8636 :                 (p, parents_to_coarsen[p], request, coarsen_tag);
    1772             :             }
    1773             : 
    1774        9544 :           for (processor_id_type p = 1; p != n_proc; ++p)
    1775             :             {
    1776           8 :               std::vector<dof_id_type> my_parents_to_coarsen;
    1777        8636 :               _mesh.comm().receive
    1778        8636 :                 (Parallel::any_source, my_parents_to_coarsen,
    1779           8 :                  coarsen_tag);
    1780             : 
    1781       21980 :               for (const auto & id : my_parents_to_coarsen)
    1782             :                 {
    1783       13344 :                   Elem & elem = _mesh.elem_ref(id);
    1784          36 :                   libmesh_assert(elem.refinement_flag() == Elem::INACTIVE ||
    1785             :                                  elem.refinement_flag() == Elem::COARSEN_INACTIVE);
    1786          36 :                   elem.set_refinement_flag(Elem::COARSEN_INACTIVE);
    1787             :                 }
    1788             :             }
    1789             : 
    1790         908 :           Parallel::wait(coarsen_push_requests);
    1791             : 
    1792             :           SyncRefinementFlags hsync(_mesh, &Elem::refinement_flag,
    1793         908 :                                     &Elem::set_refinement_flag);
    1794             :           sync_dofobject_data_by_id
    1795        1812 :             (this->comm(), _mesh.not_local_elements_begin(),
    1796         916 :              _mesh.not_local_elements_end(),
    1797             :              // We'd like a smaller sync, but this leads to bugs?
    1798             :              // SyncCoarsenInactive(),
    1799             :              hsync);
    1800         900 :         }
    1801             : 
    1802             :       // Coarsen all the elements we just flagged.
    1803        1132 :       this->_coarsen_elements();
    1804             :     }
    1805             : 
    1806             : 
    1807             :   // Finally, the new mesh probably needs to be prepared for use
    1808        1132 :   if (n > 0)
    1809        1132 :     _mesh.prepare_for_use ();
    1810        1132 : }
    1811             : 
    1812             : 
    1813             : 
    1814    14722197 : Elem * MeshRefinement::topological_neighbor(Elem * elem,
    1815             :                                             const PointLocatorBase * point_locator,
    1816             :                                             const unsigned int side) const
    1817             : {
    1818             : #ifdef LIBMESH_ENABLE_PERIODIC
    1819    14722197 :   if (_periodic_boundaries && !_periodic_boundaries->empty())
    1820             :     {
    1821      488472 :       libmesh_assert(point_locator);
    1822      786435 :       return elem->topological_neighbor(side, _mesh, *point_locator, _periodic_boundaries);
    1823             :     }
    1824             : #endif
    1825    14353474 :   return elem->neighbor_ptr(side);
    1826             : }
    1827             : 
    1828             : 
    1829             : 
    1830        1996 : bool MeshRefinement::has_topological_neighbor(const Elem * elem,
    1831             :                                               const PointLocatorBase * point_locator,
    1832             :                                               const Elem * neighbor) const
    1833             : {
    1834             : #ifdef LIBMESH_ENABLE_PERIODIC
    1835        1996 :   if (_periodic_boundaries && !_periodic_boundaries->empty())
    1836             :     {
    1837           0 :       libmesh_assert(point_locator);
    1838           0 :       return elem->has_topological_neighbor(neighbor, _mesh, *point_locator, _periodic_boundaries);
    1839             :     }
    1840             : #endif
    1841        1824 :   return elem->has_neighbor(neighbor);
    1842             : }
    1843             : 
    1844             : 
    1845             : 
    1846             : } // namespace libMesh
    1847             : 
    1848             : 
    1849             : #endif

Generated by: LCOV version 1.14