LCOV - code coverage report
Current view: top level - src/mesh - mesh_communication.C (source / functions) Hit Total Coverage
Test: libMesh/libmesh: #4513 (c53953) with base e77e8c Lines: 702 765 91.8 %
Date: 2026-08-07 20:41:44 Functions: 67 76 88.2 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // The libMesh Finite Element Library.
       2             : // Copyright (C) 2002-2026 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             : 
      20             : // Local Includes
      21             : #include "libmesh/boundary_info.h"
      22             : #include "libmesh/distributed_mesh.h"
      23             : #include "libmesh/elem.h"
      24             : #include "libmesh/ghosting_functor.h"
      25             : #include "libmesh/libmesh_config.h"
      26             : #include "libmesh/libmesh_common.h"
      27             : #include "libmesh/libmesh_logging.h"
      28             : #include "libmesh/mesh_base.h"
      29             : #include "libmesh/mesh_communication.h"
      30             : #include "libmesh/null_output_iterator.h"
      31             : #include "libmesh/mesh_tools.h"
      32             : #include "libmesh/parallel.h"
      33             : #include "libmesh/parallel_elem.h"
      34             : #include "libmesh/parallel_node.h"
      35             : #include "libmesh/parallel_ghost_sync.h"
      36             : #include "libmesh/utility.h"
      37             : #include "libmesh/remote_elem.h"
      38             : #include "libmesh/int_range.h"
      39             : #include "libmesh/elem_side_builder.h"
      40             : 
      41             : // C++ Includes
      42             : #include <numeric>
      43             : #include <set>
      44             : #include <unordered_set>
      45             : #include <unordered_map>
      46             : 
      47             : 
      48             : 
      49             : //-----------------------------------------------
      50             : // anonymous namespace for implementation details
      51             : namespace {
      52             : 
      53             : using namespace libMesh;
      54             : 
      55             : struct SyncNeighbors
      56             : {
      57             :   typedef std::vector<dof_id_type> datum;
      58             : 
      59         414 :   SyncNeighbors(MeshBase & _mesh) :
      60         414 :     mesh(_mesh) {}
      61             : 
      62             :   MeshBase & mesh;
      63             : 
      64             :   // Find the neighbor ids for each requested element
      65         490 :   void gather_data (const std::vector<dof_id_type> & ids,
      66             :                     std::vector<datum> & neighbors) const
      67             :   {
      68         490 :     neighbors.resize(ids.size());
      69             : 
      70        1232 :     for (auto i : index_range(ids))
      71             :       {
      72             :         // Look for this element in the mesh
      73             :         // We'd better find every element we're asked for
      74         742 :         const Elem & elem = mesh.elem_ref(ids[i]);
      75             : 
      76             :         // Return the element's neighbors
      77          38 :         const unsigned int n_neigh = elem.n_neighbors();
      78         742 :         neighbors[i].resize(n_neigh);
      79        3692 :         for (unsigned int n = 0; n != n_neigh; ++n)
      80             :           {
      81         150 :             const Elem * neigh = elem.neighbor_ptr(n);
      82        2950 :             if (neigh)
      83             :               {
      84          98 :                 libmesh_assert_not_equal_to(neigh, remote_elem);
      85        2066 :                 neighbors[i][n] = neigh->id();
      86             :               }
      87             :             else
      88         884 :               neighbors[i][n] = DofObject::invalid_id;
      89             :           }
      90             :       }
      91         490 :   }
      92             : 
      93         490 :   void act_on_data (const std::vector<dof_id_type> & ids,
      94             :                     const std::vector<datum> & neighbors) const
      95             :   {
      96        1232 :     for (auto i : index_range(ids))
      97             :       {
      98         742 :         Elem & elem = mesh.elem_ref(ids[i]);
      99             : 
     100          38 :         const datum & new_neigh = neighbors[i];
     101             : 
     102          38 :         const unsigned int n_neigh = elem.n_neighbors();
     103          38 :         libmesh_assert_equal_to (n_neigh, new_neigh.size());
     104             : 
     105        3692 :         for (unsigned int n = 0; n != n_neigh; ++n)
     106             :           {
     107        2950 :             const dof_id_type new_neigh_id = new_neigh[n];
     108         150 :             const Elem * old_neigh = elem.neighbor_ptr(n);
     109        2950 :             if (old_neigh && old_neigh != remote_elem)
     110             :               {
     111          98 :                 libmesh_assert_equal_to(old_neigh->id(), new_neigh_id);
     112             :               }
     113        1236 :             else if (new_neigh_id == DofObject::invalid_id)
     114             :               {
     115          52 :                 libmesh_assert (!old_neigh);
     116             :               }
     117             :             else
     118             :               {
     119         352 :                 Elem * neigh = mesh.query_elem_ptr(new_neigh_id);
     120         352 :                 if (neigh)
     121           0 :                   elem.set_neighbor(n, neigh);
     122             :                 else
     123         352 :                   elem.set_neighbor(n, const_cast<RemoteElem *>(remote_elem));
     124             :               }
     125             :           }
     126             :       }
     127         490 :   }
     128             : };
     129             : 
     130             : 
     131             : void
     132     1296337 : connect_element_families(const connected_elem_set_type & connected_elements,
     133             :                          const connected_elem_set_type & new_connected_elements,
     134             :                          connected_elem_set_type & newer_connected_elements,
     135             :                          const MeshBase * mesh)
     136             : {
     137             :   // mesh was an optional parameter for API backwards compatibility
     138     1296337 :   if (mesh && !mesh->get_constraint_rows().empty())
     139             :     {
     140             :       // We start with the constraint connections, not ancestors,
     141             :       // because we don't need constraining nodes of elements'
     142             :       // ancestors' constrained nodes.
     143           0 :       const auto & constraint_rows = mesh->get_constraint_rows();
     144             : 
     145           0 :       std::unordered_set<const Elem *> constraining_nodes_elems;
     146      670627 :       for (const Elem * elem : connected_elements)
     147             :         {
     148     3092267 :           for (const Node & node : elem->node_ref_range())
     149             :             {
     150             :               // Retain all elements containing constraining nodes
     151     2433718 :               if (const auto it = constraint_rows.find(&node);
     152           0 :                   it != constraint_rows.end())
     153    25963289 :                 for (auto & p : it->second)
     154             :                   {
     155    23754246 :                     const Elem * constraining_elem = p.first.first;
     156           0 :                     libmesh_assert(constraining_elem ==
     157             :                                    mesh->elem_ptr(constraining_elem->id()));
     158           0 :                     if (!connected_elements.count(constraining_elem) &&
     159           0 :                         !new_connected_elements.count(constraining_elem))
     160           0 :                       constraining_nodes_elems.insert(constraining_elem);
     161             :                   }
     162             :             }
     163             :         }
     164             : 
     165       12078 :       newer_connected_elements.insert(constraining_nodes_elems.begin(),
     166             :                                       constraining_nodes_elems.end());
     167             :     }
     168             : 
     169             : #ifdef LIBMESH_ENABLE_AMR
     170             : 
     171             :   // Because our set is sorted by ascending level, we can traverse it
     172             :   // in reverse order, adding parents as we go, and end up with all
     173             :   // ancestors added.  This is safe for std::set where insert doesn't
     174             :   // invalidate iterators.
     175             :   //
     176             :   // This only works because we do *not* cache
     177             :   // connected_elements.rend(), whose value can change when we insert
     178             :   // elements which are sorted before the original rend.
     179             :   //
     180             :   // We're also going to get subactive descendents here, when any
     181             :   // exist.  We're iterating in the wrong direction to do that
     182             :   // non-recursively, so we'll cop out and rely on total_family_tree.
     183             :   // Iterating backwards does mean that we won't be querying the newly
     184             :   // inserted subactive elements redundantly.
     185             : 
     186             :   connected_elem_set_type::reverse_iterator
     187        1086 :     elem_rit  = new_connected_elements.rbegin();
     188             : 
     189    31169461 :   for (; elem_rit != new_connected_elements.rend(); ++elem_rit)
     190             :     {
     191    29873124 :       const Elem * elem = *elem_rit;
     192       25240 :       libmesh_assert(elem);
     193             : 
     194             :       // We let ghosting functors worry about only active elements,
     195             :       // but the remote processor needs all its semilocal elements'
     196             :       // ancestors and active semilocal elements' descendants too.
     197    64452856 :       for (const Elem * parent = elem->parent(); parent;
     198    34568176 :            parent = parent->parent())
     199       27368 :         if (!connected_elements.count(parent) &&
     200       13684 :             !new_connected_elements.count(parent))
     201    18807926 :           newer_connected_elements.insert (parent);
     202             : 
     203             :       auto total_family_insert =
     204    29822644 :         [&connected_elements, &new_connected_elements,
     205             :          &newer_connected_elements]
     206      384568 :         (const Elem * e)
     207             :         {
     208       25240 :           if (e->active() && e->has_children())
     209             :             {
     210           0 :               std::vector<const Elem *> subactive_family;
     211       37868 :               e->total_family_tree(subactive_family);
     212      204912 :               for (const auto & f : subactive_family)
     213             :                 {
     214           0 :                   libmesh_assert(f != remote_elem);
     215           0 :                   if (!connected_elements.count(f) &&
     216           0 :                       !new_connected_elements.count(f))
     217       31032 :                     newer_connected_elements.insert(f);
     218             :                 }
     219             :             }
     220    29873124 :         };
     221             : 
     222    29873124 :       total_family_insert(elem);
     223             : 
     224             :       // We also need any interior parents on this mesh, which will
     225             :       // then need their own ancestors and descendants.
     226    29873124 :       const Elem * interior_parent = elem->interior_parent();
     227             : 
     228             :       // Don't try to grab interior parents from other meshes, e.g. if
     229             :       // this was a BoundaryMesh associated with a separate Mesh.
     230             : 
     231             :       // We can't test this if someone's using the pre-mesh-ptr API
     232       25240 :       libmesh_assert(!interior_parent || mesh);
     233             : 
     234       43644 :       if (interior_parent &&
     235       18404 :           interior_parent == mesh->query_elem_ptr(interior_parent->id()) &&
     236    29873218 :           !connected_elements.count(interior_parent) &&
     237           0 :           !new_connected_elements.count(interior_parent))
     238             :         {
     239           0 :           newer_connected_elements.insert (interior_parent);
     240           0 :           total_family_insert(interior_parent);
     241             :         }
     242             :     }
     243             : 
     244             : #  ifdef DEBUG
     245             :   // Let's be paranoid and make sure that all our ancestors
     246             :   // really did get inserted.  I screwed this up the first time
     247             :   // by caching rend, and I can easily imagine screwing it up in
     248             :   // the future by changing containers.
     249             :   auto check_elem =
     250             :     [&connected_elements,
     251             :      &new_connected_elements,
     252             :      &newer_connected_elements]
     253       91848 :     (const Elem * elem)
     254             :     {
     255       54730 :       libmesh_assert(elem);
     256       54730 :       const Elem * parent = elem->parent();
     257       54730 :       if (parent)
     258       20106 :         libmesh_assert(connected_elements.count(parent) ||
     259             :                        new_connected_elements.count(parent) ||
     260             :                        newer_connected_elements.count(parent));
     261       54730 :     };
     262             : 
     263       29632 :   for (const auto & elem : connected_elements)
     264       28546 :     check_elem(elem);
     265       26326 :   for (const auto & elem : new_connected_elements)
     266       25240 :     check_elem(elem);
     267        2030 :   for (const auto & elem : newer_connected_elements)
     268         944 :     check_elem(elem);
     269             : #  endif // DEBUG
     270             : 
     271             : #endif // LIBMESH_ENABLE_AMR
     272     1296337 : }
     273             : 
     274             : 
     275             : 
     276     1296337 : void connect_nodes (const connected_elem_set_type & new_connected_elements,
     277             :                     const connected_node_set_type & connected_nodes,
     278             :                     const connected_node_set_type & new_connected_nodes,
     279             :                     connected_node_set_type & newer_connected_nodes)
     280             : {
     281    31169461 :   for (const auto & elem : new_connected_elements)
     282   322421687 :     for (auto & n : elem->node_ref_range())
     283   292774448 :       if (!connected_nodes.count(&n) &&
     284   303310385 :           !new_connected_nodes.count(&n))
     285   281973156 :         newer_connected_nodes.insert(&n);
     286     1296337 : }
     287             : 
     288             : 
     289             : } // anonymous namespace
     290             : 
     291             : 
     292             : 
     293             : namespace libMesh
     294             : {
     295             : 
     296             : 
     297     1182599 : void query_ghosting_functors(const MeshBase & mesh,
     298             :                              processor_id_type pid,
     299             :                              MeshBase::const_element_iterator elem_it,
     300             :                              MeshBase::const_element_iterator elem_end,
     301             :                              connected_elem_set_type & connected_elements)
     302             : {
     303     1181822 :   for (auto & gf :
     304         913 :          as_range(mesh.ghosting_functors_begin(),
     305     2779067 :                   mesh.ghosting_functors_end()))
     306             :     {
     307        2098 :       GhostingFunctor::map_type elements_to_ghost;
     308        1049 :       libmesh_assert(gf);
     309     1594506 :       (*gf)(elem_it, elem_end, pid, elements_to_ghost);
     310             : 
     311             :       // We can ignore the CouplingMatrix in ->second, but we
     312             :       // need to ghost all the elements in ->first.
     313    19053967 :       for (auto & pr : elements_to_ghost)
     314             :         {
     315    17459461 :           const Elem * elem = pr.first;
     316        8651 :           libmesh_assert(elem != remote_elem);
     317        8651 :           libmesh_assert(mesh.elem_ptr(elem->id()) == elem);
     318    17450810 :           connected_elements.insert(elem);
     319             :         }
     320             :     }
     321             : 
     322             :   // The GhostingFunctors won't be telling us about the elements from
     323             :   // pid; we need to add those ourselves.
     324    20727705 :   for (; elem_it != elem_end; ++elem_it)
     325     9787413 :     connected_elements.insert(*elem_it);
     326     1182599 : }
     327             : 
     328             : 
     329     1182599 : void connect_children(const MeshBase & mesh,
     330             :                       MeshBase::const_element_iterator elem_it,
     331             :                       MeshBase::const_element_iterator elem_end,
     332             :                       connected_elem_set_type & connected_elements)
     333             : {
     334             :   // None of these parameters are used when !LIBMESH_ENABLE_AMR.
     335         913 :   libmesh_ignore(mesh, elem_it, elem_end, connected_elements);
     336             : 
     337             : #ifdef LIBMESH_ENABLE_AMR
     338             :   // Our XdrIO output needs inactive local elements to not have any
     339             :   // remote_elem children.  Let's make sure that doesn't happen.
     340             :   //
     341    25370119 :   for (const auto & elem : as_range(elem_it, elem_end))
     342             :     {
     343    11518803 :       if (elem->has_children())
     344     9652900 :         for (auto & child : elem->child_ref_range())
     345     7995290 :           if (&child != remote_elem)
     346     7720444 :             connected_elements.insert(&child);
     347     1180773 :     }
     348             : #endif // LIBMESH_ENABLE_AMR
     349     1182599 : }
     350             : 
     351             : 
     352           0 : void reconnect_nodes (connected_elem_set_type & connected_elements,
     353             :                       connected_node_set_type & connected_nodes)
     354             : {
     355             :   // We're done using the nodes list for element decisions; now
     356             :   // let's reuse it for nodes of the elements we've decided on.
     357           0 :   connected_nodes.clear();
     358             : 
     359             :   // Use the newer API
     360           0 :   connect_nodes(connected_elements, connected_nodes, connected_nodes,
     361             :                 connected_nodes);
     362           0 : }
     363             : 
     364             : 
     365      778301 : void connect_element_dependencies(const MeshBase & mesh,
     366             :                                   connected_elem_set_type & connected_elements,
     367             :                                   connected_node_set_type & connected_nodes)
     368             : {
     369             :   // We haven't examined any of these inputs for dependencies yet, so
     370             :   // let's mark them all as to be examined now.
     371        1082 :   connected_elem_set_type new_connected_elements;
     372        1082 :   connected_node_set_type new_connected_nodes;
     373         541 :   new_connected_elements.swap(connected_elements);
     374         541 :   new_connected_nodes.swap(connected_nodes);
     375             : 
     376     2075627 :   while (!new_connected_elements.empty() ||
     377         989 :          !new_connected_nodes.empty())
     378             :     {
     379             :       auto [newer_connected_elements,
     380        1086 :             newer_connected_nodes] =
     381             :         connect_element_dependencies
     382             :           (mesh, connected_elements, connected_nodes,
     383     1298509 :            new_connected_elements, new_connected_nodes);
     384             : 
     385             :       // These have now been examined
     386        1086 :       connected_elements.merge(new_connected_elements);
     387        1086 :       connected_nodes.merge(new_connected_nodes);
     388             : 
     389             :       // merge() doesn't guarantee empty() unless there are no
     390             :       // duplicates, which there shouldn't be
     391        1086 :       libmesh_assert(new_connected_elements.empty());
     392        1086 :       libmesh_assert(new_connected_nodes.empty());
     393             : 
     394             :       // These now need to be examined
     395        1086 :       new_connected_elements.swap(newer_connected_elements);
     396        1086 :       new_connected_nodes.swap(newer_connected_nodes);
     397     1294165 :     }
     398      778301 : }
     399             : 
     400             : 
     401             : std::pair<connected_elem_set_type, connected_node_set_type>
     402     1296337 : connect_element_dependencies(const MeshBase & mesh,
     403             :                              const connected_elem_set_type & connected_elements,
     404             :                              const connected_node_set_type & connected_nodes,
     405             :                              const connected_elem_set_type & new_connected_elements,
     406             :                              const connected_node_set_type & new_connected_nodes)
     407             : {
     408        1086 :   std::pair<connected_elem_set_type, connected_node_set_type> returnval;
     409        1086 :   auto & [newer_connected_elements, newer_connected_nodes] = returnval;
     410     1296337 :   connect_element_families(connected_elements, new_connected_elements,
     411             :                            newer_connected_elements, &mesh);
     412             : 
     413     1296337 :   connect_nodes(new_connected_elements, connected_nodes,
     414             :                 new_connected_nodes, newer_connected_nodes);
     415             : 
     416     1296337 :   return returnval;
     417           0 : }
     418             : 
     419             : 
     420             : 
     421             : 
     422             : // ------------------------------------------------------------
     423             : // MeshCommunication class members
     424           0 : void MeshCommunication::clear ()
     425             : {
     426             :   //  _neighboring_processors.clear();
     427           0 : }
     428             : 
     429             : 
     430             : 
     431             : #ifndef LIBMESH_HAVE_MPI // avoid spurious gcc warnings
     432             : // ------------------------------------------------------------
     433             : void MeshCommunication::redistribute (DistributedMesh &, bool) const
     434             : {
     435             :   // no MPI == one processor, no redistribution
     436             :   return;
     437             : }
     438             : 
     439             : #else
     440             : // ------------------------------------------------------------
     441       68322 : void MeshCommunication::redistribute (DistributedMesh & mesh,
     442             :                                       bool newly_coarsened_only) const
     443             : {
     444             :   // This method will be called after a new partitioning has been
     445             :   // assigned to the elements.  This partitioning was defined in
     446             :   // terms of the active elements, and "trickled down" to the
     447             :   // parents and nodes as to be consistent.
     448             :   //
     449             :   // The point is that the entire concept of local elements is
     450             :   // kinda shaky in this method.  Elements which were previously
     451             :   // local may now be assigned to other processors, so we need to
     452             :   // send those off.  Similarly, we need to accept elements from
     453             :   // other processors.
     454             : 
     455             :   // This method is also useful in the more limited case of
     456             :   // post-coarsening redistribution: if elements are only ghosting
     457             :   // neighbors of their active elements, but adaptive coarsening
     458             :   // causes an inactive element to become active, then we may need a
     459             :   // copy of that inactive element's neighbors.
     460             : 
     461             :   // The approach is as follows:
     462             :   // (1) send all relevant elements we have stored to their proper homes
     463             :   // (2) receive elements from all processors, watching for duplicates
     464             :   // (3) deleting all nonlocal elements elements
     465             :   // (4) obtaining required ghost elements from neighboring processors
     466         136 :   libmesh_parallel_only(mesh.comm());
     467         136 :   libmesh_assert (!mesh.is_serial());
     468         136 :   libmesh_assert (MeshTools::n_elem(mesh.unpartitioned_elements_begin(),
     469             :                                     mesh.unpartitioned_elements_end()) == 0);
     470             : 
     471         272 :   LOG_SCOPE("redistribute()", "MeshCommunication");
     472             : 
     473             :   // Be compatible with both deprecated and corrected MeshBase iterator types
     474             :   typedef std::remove_const<MeshBase::const_element_iterator::value_type>::type nc_v_t;
     475             : 
     476             :   // We're going to sort elements-to-send by pid in one pass, to avoid
     477             :   // sending predicated iterators through the whole mesh N_p times
     478         272 :   std::unordered_map<processor_id_type, std::vector<nc_v_t>> send_to_pid;
     479             : 
     480             :   const MeshBase::const_element_iterator send_elems_begin =
     481             : #ifdef LIBMESH_ENABLE_AMR
     482       68322 :     newly_coarsened_only ?
     483             :       mesh.flagged_elements_begin(Elem::JUST_COARSENED) :
     484             : #endif
     485         272 :       mesh.active_elements_begin();
     486             : 
     487             :   const MeshBase::const_element_iterator send_elems_end =
     488             : #ifdef LIBMESH_ENABLE_AMR
     489       68322 :     newly_coarsened_only ?
     490             :       mesh.flagged_elements_end(Elem::JUST_COARSENED) :
     491             : #endif
     492         272 :       mesh.active_elements_end();
     493             : 
     494             :   // See what should get sent where.  We don't send to ourselves.
     495    10319026 :   for (auto & elem : as_range(send_elems_begin, send_elems_end))
     496     5114267 :     if (elem->processor_id() != mesh.processor_id())
     497     3735281 :       send_to_pid[elem->processor_id()].push_back(elem);
     498             : 
     499         272 :   std::map<processor_id_type, std::vector<const Node *>> all_nodes_to_send;
     500         272 :   std::map<processor_id_type, std::vector<const Elem *>> all_elems_to_send;
     501             : 
     502             :   // We may need to send constraint rows too.
     503         136 :   auto & constraint_rows = mesh.get_constraint_rows();
     504       68322 :   bool have_constraint_rows = !constraint_rows.empty();
     505       68322 :   mesh.comm().broadcast(have_constraint_rows);
     506             : 
     507             : #ifdef DEBUG
     508             :   const dof_id_type n_constraint_rows =
     509         136 :     have_constraint_rows ? mesh.n_constraint_rows() : 0;
     510             : #endif
     511             : 
     512             :   typedef std::vector<std::pair<std::pair<dof_id_type, unsigned int>, Real>>
     513             :     serialized_row_type;
     514             :   std::unordered_map<processor_id_type,
     515             :                      std::vector<std::pair<dof_id_type, serialized_row_type>>>
     516         272 :     all_constraint_rows_to_send;
     517             : 
     518             :   // If we don't have any just-coarsened elements to send to a
     519             :   // pid, then there won't be any nodes or any elements pulled
     520             :   // in by ghosting either, and we're done with this pid.
     521      441689 :   for (const auto & [pid, p_elements] : send_to_pid)
     522             :     {
     523             :       // Build up a list of nodes and elements to send to processor pid.
     524             :       // We will certainly send all the elements assigned to this processor,
     525             :       // but we will also ship off any elements which are required
     526             :       // to be ghosted and any nodes which are used by any of the
     527             :       // above.
     528             : 
     529         133 :       libmesh_assert(!p_elements.empty());
     530             : 
     531             :       // Be compatible with both deprecated and
     532             :       // corrected MeshBase iterator types
     533             :       typedef MeshBase::const_element_iterator::value_type v_t;
     534             : 
     535      373367 :       v_t * elempp = p_elements.data();
     536      373367 :       v_t * elemend = elempp + p_elements.size();
     537             : 
     538             : #ifndef LIBMESH_ENABLE_AMR
     539             :       // This parameter is not used when !LIBMESH_ENABLE_AMR.
     540             :       libmesh_ignore(newly_coarsened_only);
     541             :       libmesh_assert(!newly_coarsened_only);
     542             : #endif
     543             : 
     544             :       MeshBase::const_element_iterator elem_it =
     545             :         MeshBase::const_element_iterator
     546      373500 :           (elempp, elemend, Predicates::NotNull<v_t *>());
     547             : 
     548             :       const MeshBase::const_element_iterator elem_end =
     549             :         MeshBase::const_element_iterator
     550      746734 :           (elemend, elemend, Predicates::NotNull<v_t *>());
     551             : 
     552         266 :       connected_elem_set_type elements_to_send;
     553             : 
     554             :       // See which to-be-ghosted elements we need to send
     555      746601 :       query_ghosting_functors (mesh, pid, elem_it, elem_end,
     556             :                                elements_to_send);
     557             : 
     558             :       // The inactive elements we need to send should have their
     559             :       // immediate children present.
     560     1119835 :       connect_children(mesh, mesh.pid_elements_begin(pid),
     561      746734 :                        mesh.pid_elements_end(pid),
     562             :                        elements_to_send);
     563             : 
     564             :       // Now see which other elements and nodes they depend on
     565         266 :       connected_node_set_type connected_nodes;
     566      373367 :       connect_element_dependencies(mesh, elements_to_send,
     567             :                                    connected_nodes);
     568             : 
     569      373367 :       all_nodes_to_send[pid].assign(connected_nodes.begin(),
     570             :                                     connected_nodes.end());
     571             : 
     572      373367 :       all_elems_to_send[pid].assign(elements_to_send.begin(),
     573             :                                     elements_to_send.end());
     574             : 
     575      462672 :       for (auto & [node, row] : constraint_rows)
     576             :         {
     577       29047 :           if (!connected_nodes.count(node))
     578       29047 :             continue;
     579             : 
     580           0 :           serialized_row_type serialized_row;
     581      641035 :           for (auto [elem_and_node, coef] : row)
     582      580777 :             serialized_row.emplace_back(std::make_pair(elem_and_node.first->id(),
     583           0 :                                                        elem_and_node.second),
     584           0 :                                         coef);
     585             : 
     586           0 :           all_constraint_rows_to_send[pid].emplace_back
     587       60258 :             (node->id(), std::move(serialized_row));
     588             :         }
     589             :     }
     590             : 
     591             :   // Elem/Node unpack() automatically adds them to the given mesh
     592         133 :   auto null_node_action = [](processor_id_type, const std::vector<const Node*>&){};
     593         133 :   auto null_elem_action = [](processor_id_type, const std::vector<const Elem*>&){};
     594             : 
     595             :   // Communicate nodes first since elements will need to attach to them
     596       68322 :   TIMPI::push_parallel_packed_range(mesh.comm(), all_nodes_to_send, &mesh,
     597             :                                     null_node_action);
     598             : 
     599       68322 :   TIMPI::push_parallel_packed_range(mesh.comm(), all_elems_to_send, &mesh,
     600             :                                     null_elem_action);
     601             : 
     602             :   // At this point we have all the nodes and elems we need, so we can
     603             :   // communicate any constraint rows that our targets will need.
     604       68322 :   if (have_constraint_rows)
     605             :     {
     606             :       auto constraint_row_action =
     607        1712 :         [&mesh, &constraint_rows]
     608             :         (processor_id_type /* src_pid */,
     609      640447 :          const std::vector<std::pair<dof_id_type, serialized_row_type>> rows)
     610             :         {
     611       61774 :           for (auto & [node_id, serialized_row] : rows)
     612             :             {
     613           0 :               MeshBase::constraint_rows_mapped_type row;
     614      640447 :               for (auto [elem_and_node, coef] : serialized_row)
     615      580385 :                 row.emplace_back(std::make_pair(mesh.elem_ptr(elem_and_node.first),
     616           0 :                                                 elem_and_node.second),
     617           0 :                                  coef);
     618             : 
     619       60062 :               constraint_rows[mesh.node_ptr(node_id)] = row;
     620             :             }
     621        1931 :         };
     622             : 
     623         219 :       TIMPI::push_parallel_vector_data(mesh.comm(),
     624             :                                        all_constraint_rows_to_send,
     625             :                                        constraint_row_action);
     626             : 
     627             :     }
     628             : 
     629             :   // Check on the redistribution consistency
     630             : #ifdef DEBUG
     631         136 :   MeshTools::libmesh_assert_equal_n_systems(mesh);
     632             : 
     633         136 :   MeshTools::libmesh_assert_valid_refinement_tree(mesh);
     634             : 
     635             :   const dof_id_type new_n_constraint_rows =
     636         136 :     have_constraint_rows ? mesh.n_constraint_rows() : 0;
     637             : 
     638         136 :   libmesh_assert_equal_to(n_constraint_rows, new_n_constraint_rows);
     639             : 
     640         136 :   MeshTools::libmesh_assert_valid_constraint_rows(mesh);
     641             : #endif
     642             : 
     643             :   // If we had a point locator, it's invalid now that there are new
     644             :   // elements it can't locate.
     645       68322 :   mesh.clear_point_locator();
     646             : 
     647             :   // Let the mesh handle any other post-redistribute() tasks, like
     648             :   // notifying GhostingFunctors.  Be sure we're just calling the base
     649             :   // class method so we don't recurse back into ourselves here.
     650       68322 :   mesh.MeshBase::redistribute();
     651       68322 : }
     652             : #endif // LIBMESH_HAVE_MPI
     653             : 
     654             : 
     655             : 
     656             : #ifndef LIBMESH_HAVE_MPI // avoid spurious gcc warnings
     657             : // ------------------------------------------------------------
     658             : void MeshCommunication::gather_neighboring_elements (DistributedMesh &) const
     659             : {
     660             :   // no MPI == one processor, no need for this method...
     661             :   return;
     662             : }
     663             : #else
     664             : // ------------------------------------------------------------
     665         425 : void MeshCommunication::gather_neighboring_elements (DistributedMesh & mesh) const
     666             : {
     667             :   // Don't need to do anything if there is
     668             :   // only one processor.
     669         437 :   if (mesh.n_processors() == 1)
     670          11 :     return;
     671             : 
     672             :   // This function must be run on all processors at once
     673          12 :   libmesh_parallel_only(mesh.comm());
     674             : 
     675          24 :   LOG_SCOPE("gather_neighboring_elements()", "MeshCommunication");
     676             : 
     677             :   //------------------------------------------------------------------
     678             :   // The purpose of this function is to provide neighbor data structure
     679             :   // consistency for a parallel, distributed mesh.  In libMesh we require
     680             :   // that each local element have access to a full set of valid face
     681             :   // neighbors.  In some cases this requires us to store "ghost elements" -
     682             :   // elements that belong to other processors but we store to provide
     683             :   // data structure consistency.  Also, it is assumed that any element
     684             :   // with a nullptr neighbor resides on a physical domain boundary.  So,
     685             :   // even our "ghost elements" must have non-nullptr neighbors.  To handle
     686             :   // this the concept of "RemoteElem" is used - a special construct which
     687             :   // is used to denote that an element has a face neighbor, but we do
     688             :   // not actually store detailed information about that neighbor.  This
     689             :   // is required to prevent data structure explosion.
     690             :   //
     691             :   // So when this method is called we should have only local elements.
     692             :   // These local elements will then find neighbors among the local
     693             :   // element set.  After this is completed, any element with a nullptr
     694             :   // neighbor has either (i) a face on the physical boundary of the mesh,
     695             :   // or (ii) a neighboring element which lives on a remote processor.
     696             :   // To handle case (ii), we communicate the global node indices connected
     697             :   // to all such faces to our neighboring processors.  They then send us
     698             :   // all their elements with a nullptr neighbor that are connected to any
     699             :   // of the nodes in our list.
     700             :   //------------------------------------------------------------------
     701             : 
     702             :   // Let's begin with finding consistent neighbor data information
     703             :   // for all the elements we currently have.  We'll use a clean
     704             :   // slate here - clear any existing information, including RemoteElem's.
     705         438 :   mesh.find_neighbors (/* reset_remote_elements = */ true,
     706          24 :                        /* reset_current_list    = */ true);
     707             : 
     708             :   // Get a unique message tag to use in communications
     709             :   Parallel::MessageTag
     710         438 :     element_neighbors_tag = mesh.comm().get_unique_tag();
     711             : 
     712             :   // Now any element with a nullptr neighbor either
     713             :   // (i) lives on the physical domain boundary, or
     714             :   // (ii) lives on an inter-processor boundary.
     715             :   // We will now gather all the elements from adjacent processors
     716             :   // which are of the same state, which should address all the type (ii)
     717             :   // elements.
     718             : 
     719             :   // A list of all the processors which *may* contain neighboring elements.
     720             :   // (for development simplicity, just make this the identity map)
     721          24 :   std::vector<processor_id_type> adjacent_processors;
     722        4560 :   for (auto pid : make_range(mesh.n_processors()))
     723        4170 :     if (pid != mesh.processor_id())
     724        3732 :       adjacent_processors.push_back (pid);
     725             : 
     726             : 
     727             :   const processor_id_type n_adjacent_processors =
     728          24 :     cast_int<processor_id_type>(adjacent_processors.size());
     729             : 
     730             :   //-------------------------------------------------------------------------
     731             :   // Let's build a list of all nodes which live on nullptr-neighbor sides.
     732             :   // For simplicity, we will use a set to build the list, then transfer
     733             :   // it to a vector for communication.
     734          24 :   std::vector<dof_id_type> my_interface_node_list;
     735          24 :   std::vector<const Elem *>  my_interface_elements;
     736             :   {
     737          24 :     std::set<dof_id_type> my_interface_node_set;
     738             : 
     739             :     // For avoiding extraneous element side construction
     740          12 :     ElemSideBuilder side_builder;
     741             : 
     742             :     // since parent nodes are a subset of children nodes, this should be sufficient
     743        1518 :     for (const auto & elem : mesh.active_local_element_ptr_range())
     744             :       {
     745          39 :         libmesh_assert(elem);
     746             : 
     747         429 :         if (elem->on_boundary()) // denotes *any* side has a nullptr neighbor
     748             :           {
     749         390 :             my_interface_elements.push_back(elem); // add the element, but only once, even
     750             :             // if there are multiple nullptr neighbors
     751        1969 :             for (auto s : elem->side_index_range())
     752        1694 :               if (elem->neighbor_ptr(s) == nullptr)
     753             :                 {
     754        1140 :                   const Elem & side = side_builder(*elem, s);
     755             : 
     756        3420 :                   for (auto n : make_range(side.n_vertices()))
     757        2476 :                     my_interface_node_set.insert (side.node_id(n));
     758             :                 }
     759             :           }
     760         390 :       }
     761             : 
     762         414 :     my_interface_node_list.reserve (my_interface_node_set.size());
     763         402 :     my_interface_node_list.insert  (my_interface_node_list.end(),
     764             :                                     my_interface_node_set.begin(),
     765          36 :                                     my_interface_node_set.end());
     766             :   }
     767             : 
     768             :   // we will now send my_interface_node_list to all of the adjacent processors.
     769             :   // note that for the time being we will copy the list to a unique buffer for
     770             :   // each processor so that we can use a nonblocking send and not access the
     771             :   // buffer again until the send completes.  it is my understanding that the
     772             :   // MPI 2.1 standard seeks to remove this restriction as unnecessary, so in
     773             :   // the future we should change this to send the same buffer to each of the
     774             :   // adjacent processors. - BSK 11/17/2008
     775             :   std::vector<std::vector<dof_id_type>>
     776         438 :     my_interface_node_xfer_buffers (n_adjacent_processors, my_interface_node_list);
     777          24 :   std::map<processor_id_type, unsigned char> n_comm_steps;
     778             : 
     779         438 :   std::vector<Parallel::Request> send_requests (3*n_adjacent_processors);
     780          12 :   unsigned int current_request = 0;
     781             : 
     782        4146 :   for (unsigned int comm_step=0; comm_step<n_adjacent_processors; comm_step++)
     783             :     {
     784        3744 :       n_comm_steps[adjacent_processors[comm_step]]=1;
     785        3756 :       mesh.comm().send (adjacent_processors[comm_step],
     786          24 :                         my_interface_node_xfer_buffers[comm_step],
     787        3732 :                         send_requests[current_request++],
     788             :                         element_neighbors_tag);
     789             :     }
     790             : 
     791             :   //-------------------------------------------------------------------------
     792             :   // processor pairings are symmetric - I expect to receive an interface node
     793             :   // list from each processor in adjacent_processors as well!
     794             :   // now we will catch an incoming node list for each of our adjacent processors.
     795             :   //
     796             :   // we are done with the adjacent_processors list - note that it is in general
     797             :   // a superset of the processors we truly share elements with.  so let's
     798             :   // clear the superset list, and we will fill it with the true list.
     799          12 :   adjacent_processors.clear();
     800             : 
     801          12 :   std::vector<dof_id_type> common_interface_node_list;
     802             : 
     803             :   // we expect two classes of messages -
     804             :   // (1) incoming interface node lists, to which we will reply with our elements
     805             :   //     touching nodes in the list, and
     806             :   // (2) replies from the requests we sent off previously.
     807             :   //  (2.a) - nodes
     808             :   //  (2.b) - elements
     809             :   // so we expect 3 communications from each adjacent processor.
     810             :   // by structuring the communication in this way we hopefully impose no
     811             :   // order on the handling of the arriving messages.  in particular, we
     812             :   // should be able to handle the case where we receive a request and
     813             :   // all replies from processor A before even receiving a request from
     814             :   // processor B.
     815             : 
     816       11610 :   for (unsigned int comm_step=0; comm_step<3*n_adjacent_processors; comm_step++)
     817             :     {
     818             :       //------------------------------------------------------------------
     819             :       // catch incoming node list
     820             :       Parallel::Status
     821       11196 :         status(mesh.comm().probe (Parallel::any_source,
     822          72 :                                   element_neighbors_tag));
     823             :       const processor_id_type
     824       11196 :         source_pid_idx = cast_int<processor_id_type>(status.source()),
     825          36 :         dest_pid_idx   = source_pid_idx;
     826             : 
     827             :       //------------------------------------------------------------------
     828             :       // first time - incoming request
     829       11196 :       if (n_comm_steps[source_pid_idx] == 1)
     830             :         {
     831        3732 :           n_comm_steps[source_pid_idx]++;
     832             : 
     833        3732 :           mesh.comm().receive (source_pid_idx,
     834             :                                common_interface_node_list,
     835          24 :                                element_neighbors_tag);
     836             : 
     837             :           // const std::size_t
     838             :           //   their_interface_node_list_size = common_interface_node_list.size();
     839             : 
     840             :           // we now have the interface node list from processor source_pid_idx.
     841             :           // now we can find all of our elements which touch any of these nodes
     842             :           // and send copies back to this processor.  however, we can make our
     843             :           // search more efficient by first excluding all the nodes in
     844             :           // their list which are not also contained in
     845             :           // my_interface_node_list.  we can do this in place as a set
     846             :           // intersection.
     847             :           common_interface_node_list.erase
     848        3708 :             (std::set_intersection (my_interface_node_list.begin(),
     849             :                                     my_interface_node_list.end(),
     850             :                                     common_interface_node_list.begin(),
     851             :                                     common_interface_node_list.end(),
     852          12 :                                     common_interface_node_list.begin()),
     853          24 :              common_interface_node_list.end());
     854             : 
     855             :           // if (false)
     856             :           //   libMesh::out << "[" << mesh.processor_id() << "] "
     857             :           //                << "my_interface_node_list.size()="       << my_interface_node_list.size()
     858             :           //                << ", [" << source_pid_idx << "] "
     859             :           //                << "their_interface_node_list.size()="    << their_interface_node_list_size
     860             :           //                << ", common_interface_node_list.size()=" << common_interface_node_list.size()
     861             :           //                << std::endl;
     862             : 
     863             :           // Now we need to see which of our elements touch the nodes in the list.
     864             :           // We will certainly send all the active elements which intersect source_pid_idx,
     865             :           // but we will also ship off the other elements in the same family tree
     866             :           // as the active ones for data structure consistency.
     867             :           //
     868             :           // FIXME - shipping full family trees is unnecessary and inefficient.
     869             :           //
     870             :           // We also ship any nodes connected to these elements.  Note
     871             :           // some of these nodes and elements may be replicated from
     872             :           // other processors, but that is OK.
     873          12 :           connected_elem_set_type elements_to_send;
     874             : 
     875             :           // Technically we're not doing reconnect_nodes on this, but
     876             :           // we might as well use the same data structure since the
     877             :           // performance questions ought to be similar
     878          12 :           connected_node_set_type connected_nodes;
     879             : 
     880             :           // Check for quick return?
     881        6960 :           if (common_interface_node_list.empty())
     882             :             {
     883             :               // let's try to be smart here - if we have no nodes in common,
     884             :               // we cannot share elements.  so post the messages expected
     885             :               // from us here and go on about our business.
     886             :               // note that even though these are nonblocking sends
     887             :               // they should complete essentially instantly, because
     888             :               // in all cases the send buffers are empty
     889        3234 :               mesh.comm().send_packed_range (dest_pid_idx,
     890             :                                              &mesh,
     891             :                                              connected_nodes.begin(),
     892             :                                              connected_nodes.end(),
     893        3232 :                                              send_requests[current_request++],
     894             :                                              element_neighbors_tag);
     895             : 
     896        3234 :               mesh.comm().send_packed_range (dest_pid_idx,
     897             :                                              &mesh,
     898             :                                              elements_to_send.begin(),
     899             :                                              elements_to_send.end(),
     900        3232 :                                              send_requests[current_request++],
     901             :                                              element_neighbors_tag);
     902             : 
     903           2 :               continue;
     904             :             }
     905             :           // otherwise, this really *is* an adjacent processor.
     906         500 :           adjacent_processors.push_back(source_pid_idx);
     907             : 
     908          20 :           std::vector<const Elem *> family_tree;
     909             : 
     910        1408 :           for (auto & elem : my_interface_elements)
     911             :             {
     912          38 :               std::size_t n_shared_nodes = 0;
     913             : 
     914        2136 :               for (auto n : make_range(elem->n_vertices()))
     915        2008 :                 if (std::binary_search (common_interface_node_list.begin(),
     916             :                                         common_interface_node_list.end(),
     917        2124 :                                         elem->node_id(n)))
     918             :                   {
     919          38 :                     n_shared_nodes++;
     920             : 
     921             :                     // TBD - how many nodes do we need to share
     922             :                     // before we care?  certainly 2, but 1?  not
     923             :                     // sure, so let's play it safe...
     924          38 :                     if (n_shared_nodes > 0) break;
     925             :                   }
     926             : 
     927         908 :               if (n_shared_nodes) // share at least one node?
     928             :                 {
     929        1522 :                   elem = elem->top_parent();
     930             : 
     931             :                   // avoid a lot of duplicated effort -- if we already have elem
     932             :                   // in the set its entire family tree is already in the set.
     933          38 :                   if (!elements_to_send.count(elem))
     934             :                     {
     935             : #ifdef LIBMESH_ENABLE_AMR
     936         780 :                       elem->family_tree(family_tree);
     937             : #else
     938             :                       family_tree.clear();
     939             :                       family_tree.push_back(elem);
     940             : #endif
     941        1560 :                       for (const auto & f : family_tree)
     942             :                         {
     943         780 :                           elem = f;
     944         742 :                           elements_to_send.insert (elem);
     945             : 
     946        3978 :                           for (auto & n : elem->node_ref_range())
     947        3160 :                             connected_nodes.insert (&n);
     948             :                         }
     949             :                     }
     950             :                 }
     951             :             }
     952             : 
     953             :           // The elements_to_send and connected_nodes sets now contain all
     954             :           // the elements and nodes we need to send to this processor.
     955             :           // All that remains is to pack up the objects (along with
     956             :           // any boundary conditions) and send the messages off.
     957             :           {
     958          10 :             libmesh_assert (connected_nodes.empty() || !elements_to_send.empty());
     959          10 :             libmesh_assert (!connected_nodes.empty() || elements_to_send.empty());
     960             : 
     961             :             // send the nodes off to the destination processor
     962         510 :             mesh.comm().send_packed_range (dest_pid_idx,
     963             :                                            &mesh,
     964             :                                            connected_nodes.begin(),
     965             :                                            connected_nodes.end(),
     966         500 :                                            send_requests[current_request++],
     967             :                                            element_neighbors_tag);
     968             : 
     969             :             // send the elements off to the destination processor
     970         510 :             mesh.comm().send_packed_range (dest_pid_idx,
     971             :                                            &mesh,
     972             :                                            elements_to_send.begin(),
     973             :                                            elements_to_send.end(),
     974         500 :                                            send_requests[current_request++],
     975             :                                            element_neighbors_tag);
     976             :           }
     977             :         }
     978             :       //------------------------------------------------------------------
     979             :       // second time - reply of nodes
     980        7464 :       else if (n_comm_steps[source_pid_idx] == 2)
     981             :         {
     982        3732 :           n_comm_steps[source_pid_idx]++;
     983             : 
     984        3732 :           mesh.comm().receive_packed_range (source_pid_idx,
     985             :                                             &mesh,
     986             :                                             null_output_iterator<Node>(),
     987             :                                             (Node**)nullptr,
     988             :                                             element_neighbors_tag);
     989             :         }
     990             :       //------------------------------------------------------------------
     991             :       // third time - reply of elements
     992        3732 :       else if (n_comm_steps[source_pid_idx] == 3)
     993             :         {
     994        3732 :           n_comm_steps[source_pid_idx]++;
     995             : 
     996        3732 :           mesh.comm().receive_packed_range (source_pid_idx,
     997             :                                             &mesh,
     998             :                                             null_output_iterator<Elem>(),
     999             :                                             (Elem**)nullptr,
    1000             :                                             element_neighbors_tag);
    1001             :         }
    1002             :       //------------------------------------------------------------------
    1003             :       // fourth time - shouldn't happen
    1004             :       else
    1005             :         {
    1006           0 :           libMesh::err << "ERROR:  unexpected number of replies: "
    1007           0 :                        << n_comm_steps[source_pid_idx]
    1008           0 :                        << std::endl;
    1009             :         }
    1010             :     } // done catching & processing replies associated with tag ~ 100,000pi
    1011             : 
    1012             :   // allow any pending requests to complete
    1013         414 :   Parallel::wait (send_requests);
    1014             : 
    1015             :   // If we had a point locator, it's invalid now that there are new
    1016             :   // elements it can't locate.
    1017         414 :   mesh.clear_point_locator();
    1018             : 
    1019             :   // We can now find neighbor information for the interfaces between
    1020             :   // local elements and ghost elements.
    1021         426 :   mesh.find_neighbors (/* reset_remote_elements = */ true,
    1022          24 :                        /* reset_current_list    = */ false);
    1023             : 
    1024             :   // Ghost elements may not have correct remote_elem neighbor links,
    1025             :   // and we may not be able to locally infer correct neighbor links to
    1026             :   // remote elements.  So we synchronize ghost element neighbor links.
    1027          12 :   SyncNeighbors nsync(mesh);
    1028             : 
    1029             :   Parallel::sync_dofobject_data_by_id
    1030         816 :     (mesh.comm(), mesh.elements_begin(), mesh.elements_end(), nsync);
    1031        1170 : }
    1032             : #endif // LIBMESH_HAVE_MPI
    1033             : 
    1034             : 
    1035             : #ifndef LIBMESH_HAVE_MPI // avoid spurious gcc warnings
    1036             : // ------------------------------------------------------------
    1037             : void MeshCommunication::send_coarse_ghosts(MeshBase &) const
    1038             : {
    1039             :   // no MPI == one processor, no need for this method...
    1040             :   return;
    1041             : }
    1042             : #else
    1043        7086 : void MeshCommunication::send_coarse_ghosts(MeshBase & mesh) const
    1044             : {
    1045             : 
    1046             :   // Don't need to do anything if all processors already ghost all non-local
    1047             :   // elements.
    1048        7086 :   if (mesh.is_serial())
    1049        5858 :     return;
    1050             : 
    1051             :   // This algorithm uses the MeshBase::flagged_pid_elements_begin/end iterators
    1052             :   // which are only available when AMR is enabled.
    1053             : #ifndef LIBMESH_ENABLE_AMR
    1054             :   libmesh_error_msg("Calling MeshCommunication::send_coarse_ghosts() requires AMR to be enabled. "
    1055             :                     "Please configure libmesh with --enable-amr.");
    1056             : #else
    1057             :   // When we coarsen elements on a DistributedMesh, we make their
    1058             :   // parents active.  This may increase the ghosting requirements on
    1059             :   // the processor which owns the newly-activated parent element.  To
    1060             :   // ensure ghosting requirements are satisfied, processors which
    1061             :   // coarsen an element will send all the associated ghosted elements
    1062             :   // to all processors which own any of the coarsened-away-element's
    1063             :   // siblings.
    1064             :   typedef std::unordered_map<processor_id_type, std::vector<Elem *>> ghost_map;
    1065           8 :   ghost_map coarsening_elements_to_ghost;
    1066             : 
    1067           8 :   const processor_id_type proc_id = mesh.processor_id();
    1068             :   // Look for just-coarsened elements
    1069        3172 :   for (auto elem : as_range(mesh.flagged_pid_elements_begin(Elem::COARSEN, proc_id),
    1070      212965 :                             mesh.flagged_pid_elements_end(Elem::COARSEN, proc_id)))
    1071             :     {
    1072             :       // If it's flagged for coarsening it had better have a parent
    1073         720 :       libmesh_assert(elem->parent());
    1074             : 
    1075             :       // On a distributed mesh:
    1076             :       // If we don't own this element's parent but we do own it, then
    1077             :       // there is a chance that we are aware of ghost elements which
    1078             :       // the parent's owner needs us to send them.
    1079      104048 :       const processor_id_type their_proc_id = elem->parent()->processor_id();
    1080      104048 :       if (their_proc_id != proc_id)
    1081         685 :         coarsening_elements_to_ghost[their_proc_id].push_back(elem);
    1082        1220 :     }
    1083             : 
    1084           8 :   std::map<processor_id_type, std::vector<const Node *>> all_nodes_to_send;
    1085           8 :   std::map<processor_id_type, std::vector<const Elem *>> all_elems_to_send;
    1086             : 
    1087           8 :   const processor_id_type n_proc = mesh.n_processors();
    1088             : 
    1089       14172 :   for (processor_id_type p=0; p != n_proc; ++p)
    1090             :     {
    1091       12944 :       if (p == proc_id)
    1092        1228 :         continue;
    1093             : 
    1094           8 :       connected_elem_set_type elements_to_send;
    1095           8 :       std::set<const Node *> nodes_to_send;
    1096             : 
    1097       11716 :       if (const auto it = std::as_const(coarsening_elements_to_ghost).find(p);
    1098           4 :           it != coarsening_elements_to_ghost.end())
    1099             :         {
    1100           0 :           const std::vector<Elem *> & elems = it->second;
    1101           0 :           libmesh_assert(elems.size());
    1102             : 
    1103             :           // Make some fake element iterators defining this vector of
    1104             :           // elements
    1105         230 :           Elem * const * elempp = const_cast<Elem * const *>(elems.data());
    1106         230 :           Elem * const * elemend = elempp+elems.size();
    1107             :           const MeshBase::const_element_iterator elem_it =
    1108         230 :             MeshBase::const_element_iterator(elempp, elemend, Predicates::NotNull<Elem * const *>());
    1109             :           const MeshBase::const_element_iterator elem_end =
    1110         460 :             MeshBase::const_element_iterator(elemend, elemend, Predicates::NotNull<Elem * const *>());
    1111             : 
    1112         230 :           for (auto & gf : as_range(mesh.ghosting_functors_begin(),
    1113         944 :                                     mesh.ghosting_functors_end()))
    1114             :             {
    1115           0 :               GhostingFunctor::map_type elements_to_ghost;
    1116           0 :               libmesh_assert(gf);
    1117         714 :               (*gf)(elem_it, elem_end, p, elements_to_ghost);
    1118             : 
    1119             :               // We can ignore the CouplingMatrix in ->second, but we
    1120             :               // need to ghost all the elements in ->first.
    1121        5429 :               for (auto & pr : elements_to_ghost)
    1122             :                 {
    1123        4715 :                   const Elem * elem = pr.first;
    1124           0 :                   libmesh_assert(elem);
    1125       16262 :                   while (elem)
    1126             :                     {
    1127           0 :                       libmesh_assert(elem != remote_elem);
    1128       11547 :                       elements_to_send.insert(elem);
    1129      108958 :                       for (auto & n : elem->node_ref_range())
    1130       97411 :                         nodes_to_send.insert(&n);
    1131       11547 :                       elem = elem->parent();
    1132             :                     }
    1133             :                 }
    1134             :             }
    1135             : 
    1136         230 :           all_nodes_to_send[p].assign(nodes_to_send.begin(), nodes_to_send.end());
    1137         230 :           all_elems_to_send[p].assign(elements_to_send.begin(), elements_to_send.end());
    1138             :         }
    1139             :     }
    1140             : 
    1141             :   // Elem/Node unpack() automatically adds them to the given mesh
    1142           0 :   auto null_node_action = [](processor_id_type, const std::vector<const Node*>&){};
    1143           0 :   auto null_elem_action = [](processor_id_type, const std::vector<const Elem*>&){};
    1144             : 
    1145             :   // Communicate nodes first since elements will need to attach to them
    1146        1228 :   TIMPI::push_parallel_packed_range(mesh.comm(), all_nodes_to_send, &mesh,
    1147             :                                     null_node_action);
    1148             : 
    1149        1228 :   TIMPI::push_parallel_packed_range(mesh.comm(), all_elems_to_send, &mesh,
    1150             :                                     null_elem_action);
    1151             : 
    1152             : #endif // LIBMESH_ENABLE_AMR
    1153             : }
    1154             : 
    1155             : #endif // LIBMESH_HAVE_MPI
    1156             : 
    1157             : #ifndef LIBMESH_HAVE_MPI // avoid spurious gcc warnings
    1158             : // ------------------------------------------------------------
    1159             : void MeshCommunication::broadcast (MeshBase &) const
    1160             : {
    1161             :   // no MPI == one processor, no need for this method...
    1162             :   return;
    1163             : }
    1164             : #else
    1165             : // ------------------------------------------------------------
    1166       15024 : void MeshCommunication::broadcast (MeshBase & mesh) const
    1167             : {
    1168             :   // Don't need to do anything if there is
    1169             :   // only one processor.
    1170       15456 :   if (mesh.n_processors() == 1)
    1171         431 :     return;
    1172             : 
    1173             :   // This function must be run on all processors at once
    1174         428 :   libmesh_parallel_only(mesh.comm());
    1175             : 
    1176         856 :   LOG_SCOPE("broadcast()", "MeshCommunication");
    1177             : 
    1178             :   // Explicitly clear the mesh on all but processor 0.
    1179       15021 :   if (mesh.processor_id() != 0)
    1180       12466 :     mesh.clear();
    1181             : 
    1182             :   // We may have set extra data only on processor 0 in a read()
    1183       14593 :   mesh.comm().broadcast(mesh._node_integer_names);
    1184       14593 :   mesh.comm().broadcast(mesh._node_integer_default_values);
    1185       14593 :   mesh.comm().broadcast(mesh._elem_integer_names);
    1186       14593 :   mesh.comm().broadcast(mesh._elem_integer_default_values);
    1187             : 
    1188             :   // We may have set mapping data only on processor 0 in a read()
    1189       14593 :   unsigned char map_type = mesh.default_mapping_type();
    1190       14593 :   unsigned char map_data = mesh.default_mapping_data();
    1191       14593 :   mesh.comm().broadcast(map_type);
    1192       14593 :   mesh.comm().broadcast(map_data);
    1193       14593 :   mesh.set_default_mapping_type(ElemMappingType(map_type));
    1194       14593 :   mesh.set_default_mapping_data(map_data);
    1195             : 
    1196             :   // Broadcast nodes
    1197       15021 :   mesh.comm().broadcast_packed_range(&mesh,
    1198       29186 :                                      mesh.nodes_begin(),
    1199       15021 :                                      mesh.nodes_end(),
    1200             :                                      &mesh,
    1201             :                                      null_output_iterator<Node>());
    1202             : 
    1203             :   // Broadcast elements from coarsest to finest, so that child
    1204             :   // elements will see their parents already in place.
    1205             :   //
    1206             :   // When restarting from a checkpoint, we may have elements which are
    1207             :   // assigned to a processor but which have not yet been sent to that
    1208             :   // processor, so we need to use a paranoid n_levels() count and not
    1209             :   // the usual fast algorithm.
    1210       14593 :   const unsigned int n_levels = MeshTools::paranoid_n_levels(mesh);
    1211             : 
    1212       29186 :   for (unsigned int l=0; l != n_levels; ++l)
    1213       15021 :     mesh.comm().broadcast_packed_range(&mesh,
    1214       29186 :                                        mesh.level_elements_begin(l),
    1215       29186 :                                        mesh.level_elements_end(l),
    1216             :                                        &mesh,
    1217             :                                        null_output_iterator<Elem>());
    1218             : 
    1219             :   // Make sure mesh_dimension and elem_dimensions are consistent.
    1220       14593 :   mesh.cache_elem_data();
    1221             : 
    1222             :   // Make sure mesh id counts are consistent.
    1223       14593 :   mesh.update_parallel_id_counts();
    1224             : 
    1225             :   // We may have constraint rows on IsoGeometric Analysis meshes.  We
    1226             :   // don't want to send these along with constrained nodes (like we
    1227             :   // send boundary info for those nodes) because the associated rows'
    1228             :   // elements may not exist at that point.
    1229         428 :   auto & constraint_rows = mesh.get_constraint_rows();
    1230       14593 :   bool have_constraint_rows = !constraint_rows.empty();
    1231       14593 :   mesh.comm().broadcast(have_constraint_rows);
    1232       14593 :   if (have_constraint_rows)
    1233             :     {
    1234             :       std::map<dof_id_type,
    1235             :                std::vector<std::tuple<dof_id_type, unsigned int, Real>>>
    1236          40 :         serialized_rows;
    1237             : 
    1238       60074 :       for (auto & row : constraint_rows)
    1239             :         {
    1240       59366 :           const Node * node = row.first;
    1241       59366 :           const dof_id_type rowid = node->id();
    1242        5850 :           libmesh_assert(node == mesh.node_ptr(rowid));
    1243             : 
    1244             :           std::vector<std::tuple<dof_id_type, unsigned int, Real>>
    1245       11700 :             serialized_row;
    1246      183373 :           for (auto & entry : row.second)
    1247             :             serialized_row.push_back
    1248      124007 :               (std::make_tuple(entry.first.first->id(),
    1249       12215 :                                entry.first.second, entry.second));
    1250             : 
    1251       53516 :           serialized_rows.emplace(rowid, std::move(serialized_row));
    1252             :         }
    1253             : 
    1254         708 :       mesh.comm().broadcast(serialized_rows);
    1255         728 :       if (mesh.processor_id() != 0)
    1256             :         {
    1257          10 :           constraint_rows.clear();
    1258             : 
    1259      346615 :           for (auto & row : serialized_rows)
    1260             :             {
    1261      346016 :               const dof_id_type rowid = row.first;
    1262      346016 :               const Node * node = mesh.node_ptr(rowid);
    1263             : 
    1264             :               std::vector<std::pair<std::pair<const Elem *, unsigned int>, Real>>
    1265       11700 :                 deserialized_row;
    1266     1068558 :               for (auto & entry : row.second)
    1267             :                 deserialized_row.push_back
    1268     1445084 :                   (std::make_pair(std::make_pair(mesh.elem_ptr(std::get<0>(entry)),
    1269       36645 :                                                  std::get<1>(entry)),
    1270       36645 :                                                  std::get<2>(entry)));
    1271             : 
    1272      340166 :               constraint_rows.emplace(node, deserialized_row);
    1273             :             }
    1274             :         }
    1275             :     }
    1276             : 
    1277             :   // Broadcast all of the named entity information
    1278       14593 :   mesh.comm().broadcast(mesh.set_subdomain_name_map());
    1279       14593 :   mesh.comm().broadcast(mesh.get_boundary_info().set_sideset_name_map());
    1280       14593 :   mesh.comm().broadcast(mesh.get_boundary_info().set_nodeset_name_map());
    1281             : 
    1282             :   // If we had a point locator, it's invalid now that there are new
    1283             :   // elements it can't locate.
    1284       14593 :   mesh.clear_point_locator();
    1285             : 
    1286         428 :   libmesh_assert (mesh.comm().verify(mesh.n_elem()));
    1287         428 :   libmesh_assert (mesh.comm().verify(mesh.max_elem_id()));
    1288         428 :   libmesh_assert (mesh.comm().verify(mesh.n_nodes()));
    1289         428 :   libmesh_assert (mesh.comm().verify(mesh.max_node_id()));
    1290             : 
    1291             : #ifdef DEBUG
    1292         428 :   MeshTools::libmesh_assert_valid_procids<Elem>(mesh);
    1293         428 :   MeshTools::libmesh_assert_valid_procids<Node>(mesh);
    1294             : #endif
    1295             : }
    1296             : #endif // LIBMESH_HAVE_MPI
    1297             : 
    1298             : 
    1299             : 
    1300             : #ifndef LIBMESH_HAVE_MPI // avoid spurious gcc warnings
    1301             : // ------------------------------------------------------------
    1302             : void MeshCommunication::gather (const processor_id_type, MeshBase &) const
    1303             : {
    1304             :   // no MPI == one processor, no need for this method...
    1305             :   return;
    1306             : }
    1307             : #else
    1308             : // ------------------------------------------------------------
    1309      111747 : void MeshCommunication::gather (const processor_id_type root_id, MeshBase & mesh) const
    1310             : {
    1311             :   // Check for quick return
    1312      111819 :   if (mesh.n_processors() == 1)
    1313        1099 :     return;
    1314             : 
    1315             :   // This function must be run on all processors at once
    1316          72 :   libmesh_parallel_only(mesh.comm());
    1317             : 
    1318         144 :   LOG_SCOPE("(all)gather()", "MeshCommunication");
    1319             : 
    1320             :   // Ensure we don't build too big a buffer at once
    1321             :   static const std::size_t approx_total_buffer_size = 1e8;
    1322             :   const std::size_t approx_each_buffer_size =
    1323      110648 :     approx_total_buffer_size / mesh.comm().size();
    1324             : 
    1325      110648 :   (root_id == DofObject::invalid_processor_id) ?
    1326             : 
    1327       96820 :     mesh.comm().allgather_packed_range (&mesh,
    1328       96820 :                                         mesh.nodes_begin(),
    1329      207406 :                                         mesh.nodes_end(),
    1330             :                                         null_output_iterator<Node>(),
    1331             :                                         approx_each_buffer_size) :
    1332             : 
    1333       13900 :     mesh.comm().gather_packed_range (root_id,
    1334             :                                      &mesh,
    1335      124538 :                                      mesh.nodes_begin(),
    1336      138418 :                                      mesh.nodes_end(),
    1337             :                                      null_output_iterator<Node>(),
    1338             :                                      approx_each_buffer_size);
    1339             : 
    1340             :   // Gather elements from coarsest to finest, so that child
    1341             :   // elements will see their parents already in place.
    1342      110648 :   const unsigned int n_levels = MeshTools::n_levels(mesh);
    1343             : 
    1344      301070 :   for (unsigned int l=0; l != n_levels; ++l)
    1345      190422 :     (root_id == DofObject::invalid_processor_id) ?
    1346             : 
    1347      169916 :       mesh.comm().allgather_packed_range (&mesh,
    1348      169916 :                                           mesh.level_elements_begin(l),
    1349      530032 :                                           mesh.level_elements_end(l),
    1350             :                                           null_output_iterator<Elem>(),
    1351             :                                           approx_each_buffer_size) :
    1352             : 
    1353       20594 :       mesh.comm().gather_packed_range (root_id,
    1354             :                                        &mesh,
    1355      211002 :                                        mesh.level_elements_begin(l),
    1356      231568 :                                        mesh.level_elements_end(l),
    1357             :                                        null_output_iterator<Elem>(),
    1358             :                                        approx_each_buffer_size);
    1359             : 
    1360             :   // If we had a point locator, it's invalid now that there are new
    1361             :   // elements it can't locate.
    1362      110648 :   mesh.clear_point_locator();
    1363             : 
    1364             :   // We may have constraint rows on IsoGeometric Analysis meshes.  We
    1365             :   // don't want to send these along with constrained nodes (like we
    1366             :   // send boundary info for those nodes) because the associated rows'
    1367             :   // elements may not exist at that point.
    1368          72 :   auto & constraint_rows = mesh.get_constraint_rows();
    1369      110648 :   bool have_constraint_rows = !constraint_rows.empty();
    1370      110648 :   mesh.comm().max(have_constraint_rows);
    1371      110648 :   if (have_constraint_rows)
    1372             :     {
    1373             :       std::map<dof_id_type,
    1374             :                std::vector<std::tuple<dof_id_type, unsigned int, Real>>>
    1375           0 :         serialized_rows;
    1376             : 
    1377         361 :       for (auto & row : constraint_rows)
    1378             :         {
    1379         238 :           const Node * node = row.first;
    1380         238 :           const dof_id_type rowid = node->id();
    1381           0 :           libmesh_assert(node == mesh.node_ptr(rowid));
    1382             : 
    1383             :           std::vector<std::tuple<dof_id_type, unsigned int, Real>>
    1384           0 :             serialized_row;
    1385         714 :           for (auto & entry : row.second)
    1386             :             serialized_row.push_back
    1387         476 :               (std::make_tuple(entry.first.first->id(),
    1388           0 :                                entry.first.second, entry.second));
    1389             : 
    1390         238 :           serialized_rows.emplace(rowid, std::move(serialized_row));
    1391             :         }
    1392             : 
    1393         123 :       if (root_id == DofObject::invalid_processor_id)
    1394         123 :         mesh.comm().set_union(serialized_rows);
    1395             :       else
    1396           0 :         mesh.comm().set_union(serialized_rows, root_id);
    1397             : 
    1398         123 :       if (root_id == DofObject::invalid_processor_id ||
    1399           0 :           root_id == mesh.processor_id())
    1400             :         {
    1401         918 :           for (auto & row : serialized_rows)
    1402             :             {
    1403         795 :               const dof_id_type rowid = row.first;
    1404         795 :               const Node * node = mesh.node_ptr(rowid);
    1405             : 
    1406             :               std::vector<std::pair<std::pair<const Elem *, unsigned int>, Real>>
    1407           0 :                 deserialized_row;
    1408        2385 :               for (auto & entry : row.second)
    1409             :                 deserialized_row.push_back
    1410        3180 :                   (std::make_pair(std::make_pair(mesh.elem_ptr(std::get<0>(entry)),
    1411           0 :                                                  std::get<1>(entry)),
    1412           0 :                                                  std::get<2>(entry)));
    1413             : 
    1414         795 :               constraint_rows.emplace(node, deserialized_row);
    1415             :             }
    1416             :         }
    1417             : #ifdef DEBUG
    1418           0 :       MeshTools::libmesh_assert_valid_constraint_rows(mesh);
    1419             : #endif
    1420             :     }
    1421             : 
    1422             : 
    1423             :   // If we are doing an allgather(), perform sanity check on the result.
    1424          72 :   if (root_id == DofObject::invalid_processor_id)
    1425             :     {
    1426          62 :       libmesh_assert (mesh.comm().verify(mesh.n_elem()));
    1427          62 :       libmesh_assert (mesh.comm().verify(mesh.n_nodes()));
    1428             :     }
    1429             : 
    1430             :   // Inform new elements of their neighbors,
    1431             :   // while resetting all remote_elem links on
    1432             :   // the ranks which did the gather.
    1433      110648 :   if (mesh.allow_find_neighbors())
    1434      198532 :     mesh.find_neighbors(root_id == DofObject::invalid_processor_id ||
    1435         144 :                         root_id == mesh.processor_id());
    1436             : 
    1437             :   // All done, but let's make sure it's done correctly
    1438             : 
    1439             : #ifdef DEBUG
    1440          72 :   MeshTools::libmesh_assert_valid_boundary_ids(mesh);
    1441             : #endif
    1442             : }
    1443             : #endif // LIBMESH_HAVE_MPI
    1444             : 
    1445             : 
    1446             : 
    1447             : // Functor for make_elems_parallel_consistent and
    1448             : // make_node_ids_parallel_consistent
    1449             : namespace {
    1450             : 
    1451             : struct SyncIds
    1452             : {
    1453             :   typedef dof_id_type datum;
    1454             :   typedef void (MeshBase::*renumber_obj)(dof_id_type, dof_id_type);
    1455             : 
    1456       22593 :   SyncIds(MeshBase & _mesh, renumber_obj _renumberer) :
    1457       22517 :     mesh(_mesh),
    1458       22593 :     renumber(_renumberer) {}
    1459             : 
    1460             :   MeshBase & mesh;
    1461             :   renumber_obj renumber;
    1462             :   // renumber_obj & renumber;
    1463             : 
    1464             :   // Find the id of each requested DofObject -
    1465             :   // Parallel::sync_* already did the work for us
    1466          34 :   void gather_data (const std::vector<dof_id_type> & ids,
    1467             :                     std::vector<datum> & ids_out) const
    1468             :   {
    1469       67936 :     ids_out = ids;
    1470       67902 :   }
    1471             : 
    1472       67936 :   void act_on_data (const std::vector<dof_id_type> & old_ids,
    1473             :                     const std::vector<datum> & new_ids) const
    1474             :   {
    1475     2753559 :     for (auto i : index_range(old_ids))
    1476     2688087 :       if (old_ids[i] != new_ids[i])
    1477     2640426 :         (mesh.*renumber)(old_ids[i], new_ids[i]);
    1478       67936 :   }
    1479             : };
    1480             : 
    1481             : 
    1482       31234 : struct SyncNodeIds
    1483             : {
    1484             :   typedef dof_id_type datum;
    1485             : 
    1486       31282 :   SyncNodeIds(MeshBase & _mesh) :
    1487       31282 :     mesh(_mesh) {}
    1488             : 
    1489             :   MeshBase & mesh;
    1490             : 
    1491             :   // We only know a Node id() is definitive if we own the Node or if
    1492             :   // we're told it's definitive.  We keep track of the latter cases by
    1493             :   // putting definitively id'd ghost nodes into this set.
    1494             :   typedef std::unordered_set<const Node *> uset_type;
    1495             :   uset_type definitive_ids;
    1496             : 
    1497             :   // We should never be told two different definitive ids for the same
    1498             :   // node, but let's check on that in debug mode.
    1499             : #ifdef DEBUG
    1500             :   typedef std::unordered_map<dof_id_type, dof_id_type> umap_type;
    1501             :   umap_type definitive_renumbering;
    1502             : #endif
    1503             : 
    1504             :   // Find the id of each requested DofObject -
    1505             :   // Parallel::sync_* already tried to do the work for us, but we can
    1506             :   // only say the result is definitive if we own the DofObject or if
    1507             :   // we were given the definitive result from another processor.
    1508      299412 :   void gather_data (const std::vector<dof_id_type> & ids,
    1509             :                     std::vector<datum> & ids_out) const
    1510             :   {
    1511         132 :     ids_out.clear();
    1512      299544 :     ids_out.resize(ids.size(), DofObject::invalid_id);
    1513             : 
    1514    61270860 :     for (auto i : index_range(ids))
    1515             :       {
    1516    60971448 :         const dof_id_type id = ids[i];
    1517    60971448 :         const Node * node = mesh.query_node_ptr(id);
    1518    60971448 :         if (node && (node->processor_id() == mesh.processor_id() ||
    1519       33924 :                      definitive_ids.count(node)))
    1520    61005088 :           ids_out[i] = id;
    1521             :       }
    1522      299412 :   }
    1523             : 
    1524      299412 :   bool act_on_data (const std::vector<dof_id_type> & old_ids,
    1525             :                     const std::vector<datum> & new_ids)
    1526             :   {
    1527         132 :     bool data_changed = false;
    1528    61270860 :     for (auto i : index_range(old_ids))
    1529             :       {
    1530    60971448 :         const dof_id_type new_id = new_ids[i];
    1531             : 
    1532    60971448 :         const dof_id_type old_id = old_ids[i];
    1533             : 
    1534    60971448 :         Node * node = mesh.query_node_ptr(old_id);
    1535             : 
    1536             :         // If we can't find the node we were asking about, another
    1537             :         // processor must have already given us the definitive id
    1538             :         // for it
    1539    60971448 :         if (!node)
    1540             :           {
    1541             :             // But let's check anyway in debug mode
    1542             : #ifdef DEBUG
    1543        5626 :             libmesh_assert
    1544             :               (definitive_renumbering.count(old_id));
    1545        5626 :             libmesh_assert_equal_to
    1546             :               (new_id, definitive_renumbering[old_id]);
    1547             : #endif
    1548    11661690 :             continue;
    1549             :           }
    1550             : 
    1551             :         // If we asked for an id but there's no definitive id ready
    1552             :         // for us yet, then we can't quit trying to sync yet.
    1553    49304132 :         if (new_id == DofObject::invalid_id)
    1554             :           {
    1555             :             // But we might have gotten a definitive id from a
    1556             :             // different request
    1557         284 :             if (!definitive_ids.count(mesh.node_ptr(old_id)))
    1558           0 :               data_changed = true;
    1559             :           }
    1560             :         else
    1561             :           {
    1562    49332146 :             if (node->processor_id() != mesh.processor_id())
    1563       46812 :               definitive_ids.insert(node);
    1564    49303848 :             if (old_id != new_id)
    1565             :               {
    1566             : #ifdef DEBUG
    1567        3234 :                 libmesh_assert
    1568             :                   (!definitive_renumbering.count(old_id));
    1569        3234 :                 definitive_renumbering[old_id] = new_id;
    1570             : #endif
    1571     4938833 :                 mesh.renumber_node(old_id, new_id);
    1572        3234 :                 data_changed = true;
    1573             :               }
    1574             :           }
    1575             :       }
    1576      299412 :     return data_changed;
    1577             :   }
    1578             : };
    1579             : 
    1580             : 
    1581             : #ifdef LIBMESH_ENABLE_AMR
    1582             : struct SyncPLevels
    1583             : {
    1584             :   typedef std::pair<unsigned char,unsigned char> datum;
    1585             : 
    1586        2560 :   SyncPLevels(MeshBase & _mesh) :
    1587        2560 :     mesh(_mesh) {}
    1588             : 
    1589             :   MeshBase & mesh;
    1590             : 
    1591             :   // Find the p_level of each requested Elem
    1592        3346 :   void gather_data (const std::vector<dof_id_type> & ids,
    1593             :                     std::vector<datum> & ids_out) const
    1594             :   {
    1595        3346 :     ids_out.reserve(ids.size());
    1596             : 
    1597       18571 :     for (const auto & id : ids)
    1598             :       {
    1599       15225 :         Elem & elem = mesh.elem_ref(id);
    1600             :         ids_out.push_back
    1601       15225 :           (std::make_pair(cast_int<unsigned char>(elem.p_level()),
    1602           0 :                           static_cast<unsigned char>(elem.p_refinement_flag())));
    1603             :       }
    1604        3346 :   }
    1605             : 
    1606        3346 :   void act_on_data (const std::vector<dof_id_type> & old_ids,
    1607             :                     const std::vector<datum> & new_p_levels) const
    1608             :   {
    1609       18571 :     for (auto i : index_range(old_ids))
    1610             :       {
    1611       15225 :         Elem & elem = mesh.elem_ref(old_ids[i]);
    1612             :         // Make sure these are consistent
    1613             :         elem.hack_p_level_and_refinement_flag
    1614       15225 :           (new_p_levels[i].first,
    1615       15225 :            static_cast<Elem::RefinementState>(new_p_levels[i].second));
    1616             :         // Make sure parents' levels are consistent
    1617       15225 :         elem.set_p_level(new_p_levels[i].first);
    1618             :       }
    1619        3346 :   }
    1620             : };
    1621             : #endif // LIBMESH_ENABLE_AMR
    1622             : 
    1623             : 
    1624             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
    1625             : template <typename DofObjSubclass>
    1626             : struct SyncUniqueIds
    1627             : {
    1628             :   typedef unique_id_type datum;
    1629             :   typedef DofObjSubclass* (MeshBase::*query_obj)(const dof_id_type);
    1630             : 
    1631       57334 :   SyncUniqueIds(MeshBase &_mesh, query_obj _querier) :
    1632       57086 :     mesh(_mesh),
    1633       57334 :     query(_querier) {}
    1634             : 
    1635             :   MeshBase & mesh;
    1636             :   query_obj query;
    1637             : 
    1638             :   // Find the id of each requested DofObject -
    1639             :   // Parallel::sync_* already did the work for us
    1640      214449 :   void gather_data (const std::vector<dof_id_type> & ids,
    1641             :                     std::vector<datum> & ids_out) const
    1642             :   {
    1643      214545 :     ids_out.reserve(ids.size());
    1644             : 
    1645     9990463 :     for (const auto & id : ids)
    1646             :       {
    1647     9776014 :         DofObjSubclass * d = (mesh.*query)(id);
    1648        6712 :         libmesh_assert(d);
    1649     9776014 :         ids_out.push_back(d->unique_id());
    1650             :       }
    1651      214449 :   }
    1652             : 
    1653      214449 :   void act_on_data (const std::vector<dof_id_type> & ids,
    1654             :                     const std::vector<datum> & unique_ids) const
    1655             :   {
    1656     9990463 :     for (auto i : index_range(ids))
    1657             :       {
    1658     9776014 :         DofObjSubclass * d = (mesh.*query)(ids[i]);
    1659        6712 :         libmesh_assert(d);
    1660     9782726 :         d->set_unique_id(unique_ids[i]);
    1661             :       }
    1662      214449 :   }
    1663             : };
    1664             : #endif // LIBMESH_ENABLE_UNIQUE_ID
    1665             : 
    1666             : template <typename DofObjSubclass>
    1667             : struct SyncBCIds
    1668             : {
    1669             :   typedef std::vector<boundary_id_type> datum;
    1670             : 
    1671       22593 :   SyncBCIds(MeshBase &_mesh) :
    1672       22593 :     mesh(_mesh) {}
    1673             : 
    1674             :   MeshBase & mesh;
    1675             : 
    1676             :   // Find the id of each requested DofObject -
    1677             :   // Parallel::sync_* already did the work for us
    1678       92767 :   void gather_data (const std::vector<dof_id_type> & ids,
    1679             :                     std::vector<datum> & ids_out) const
    1680             :   {
    1681       92767 :     ids_out.reserve(ids.size());
    1682             : 
    1683       92767 :     const BoundaryInfo & boundary_info = mesh.get_boundary_info();
    1684             : 
    1685     6177453 :     for (const auto & id : ids)
    1686             :       {
    1687     6084686 :         Node * n = mesh.query_node_ptr(id);
    1688        2981 :         libmesh_assert(n);
    1689        5962 :         std::vector<boundary_id_type> bcids;
    1690     6084686 :         boundary_info.boundary_ids(n, bcids);
    1691        2981 :         ids_out.push_back(std::move(bcids));
    1692             :       }
    1693       92767 :   }
    1694             : 
    1695       92767 :   void act_on_data (const std::vector<dof_id_type> & ids,
    1696             :                     const std::vector<datum> & bcids) const
    1697             :   {
    1698       92767 :     BoundaryInfo & boundary_info = mesh.get_boundary_info();
    1699             : 
    1700     6177453 :     for (auto i : index_range(ids))
    1701             :       {
    1702     6084686 :         Node * n = mesh.query_node_ptr(ids[i]);
    1703        2981 :         libmesh_assert(n);
    1704     6084686 :         boundary_info.add_node(n, bcids[i]);
    1705             :       }
    1706       92767 :   }
    1707             : };
    1708             : 
    1709             : }
    1710             : 
    1711             : 
    1712             : 
    1713             : // ------------------------------------------------------------
    1714       31282 : void MeshCommunication::make_node_ids_parallel_consistent (MeshBase & mesh)
    1715             : {
    1716             :   // This function must be run on all processors at once
    1717          48 :   libmesh_parallel_only(mesh.comm());
    1718             : 
    1719             :   // We need to agree on which processor owns every node, but we can't
    1720             :   // easily assert that here because we don't currently agree on which
    1721             :   // id every node has, and some of our temporary ids on unrelated
    1722             :   // nodes will "overlap".
    1723             : //#ifdef DEBUG
    1724             : //  MeshTools::libmesh_assert_parallel_consistent_procids<Node> (mesh);
    1725             : //#endif // DEBUG
    1726             : 
    1727          96 :   LOG_SCOPE ("make_node_ids_parallel_consistent()", "MeshCommunication");
    1728             : 
    1729          96 :   SyncNodeIds syncids(mesh);
    1730             :   Parallel::sync_node_data_by_element_id
    1731       93750 :     (mesh, mesh.elements_begin(), mesh.elements_end(),
    1732       31234 :      Parallel::SyncEverything(), Parallel::SyncEverything(), syncids);
    1733             : 
    1734             :   // At this point, with both ids and processor ids synced, we can
    1735             :   // finally check for topological consistency of node processor ids.
    1736             : #ifdef DEBUG
    1737          48 :   MeshTools::libmesh_assert_topology_consistent_procids<Node> (mesh);
    1738             : #endif
    1739       31282 : }
    1740             : 
    1741             : 
    1742             : 
    1743       34741 : void MeshCommunication::make_node_unique_ids_parallel_consistent (MeshBase & mesh)
    1744             : {
    1745             :   // Avoid unused variable warnings if unique ids aren't enabled.
    1746          86 :   libmesh_ignore(mesh);
    1747             : 
    1748             :   // This function must be run on all processors at once
    1749          86 :   libmesh_parallel_only(mesh.comm());
    1750             : 
    1751             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
    1752          86 :   LOG_SCOPE ("make_node_unique_ids_parallel_consistent()", "MeshCommunication");
    1753             : 
    1754          86 :   SyncUniqueIds<Node> syncuniqueids(mesh, &MeshBase::query_node_ptr);
    1755         172 :   Parallel::sync_dofobject_data_by_id(mesh.comm(),
    1756       69482 :                                       mesh.nodes_begin(),
    1757       34913 :                                       mesh.nodes_end(),
    1758             :                                       syncuniqueids);
    1759             : 
    1760             : #endif
    1761       34741 : }
    1762             : 
    1763             : 
    1764       22593 : void MeshCommunication::make_node_bcids_parallel_consistent (MeshBase & mesh)
    1765             : {
    1766             :   // Avoid unused variable warnings if unique ids aren't enabled.
    1767          38 :   libmesh_ignore(mesh);
    1768             : 
    1769             :   // This function must be run on all processors at once
    1770          38 :   libmesh_parallel_only(mesh.comm());
    1771             : 
    1772          38 :   LOG_SCOPE ("make_node_bcids_parallel_consistent()", "MeshCommunication");
    1773             : 
    1774          38 :   SyncBCIds<Node> syncbcids(mesh);
    1775          76 :   Parallel::sync_dofobject_data_by_id(mesh.comm(),
    1776       45186 :                                       mesh.nodes_begin(),
    1777       22669 :                                       mesh.nodes_end(),
    1778             :                                       syncbcids);
    1779       22593 : }
    1780             : 
    1781             : 
    1782             : 
    1783             : 
    1784             : 
    1785             : // ------------------------------------------------------------
    1786       22593 : void MeshCommunication::make_elems_parallel_consistent(MeshBase & mesh)
    1787             : {
    1788             :   // This function must be run on all processors at once
    1789          38 :   libmesh_parallel_only(mesh.comm());
    1790             : 
    1791          38 :   LOG_SCOPE ("make_elems_parallel_consistent()", "MeshCommunication");
    1792             : 
    1793          38 :   SyncIds syncids(mesh, &MeshBase::renumber_elem);
    1794             :   Parallel::sync_element_data_by_parent_id
    1795       45148 :     (mesh, mesh.active_elements_begin(),
    1796       22631 :      mesh.active_elements_end(), syncids);
    1797             : 
    1798             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
    1799          38 :   SyncUniqueIds<Elem> syncuniqueids(mesh, &MeshBase::query_elem_ptr);
    1800             :   Parallel::sync_dofobject_data_by_id
    1801       45148 :     (mesh.comm(), mesh.active_elements_begin(),
    1802       22669 :      mesh.active_elements_end(), syncuniqueids);
    1803             : #endif
    1804       22593 : }
    1805             : 
    1806             : 
    1807             : 
    1808             : // ------------------------------------------------------------
    1809             : #ifdef LIBMESH_ENABLE_AMR
    1810        2560 : void MeshCommunication::make_p_levels_parallel_consistent(MeshBase & mesh)
    1811             : {
    1812             :   // This function must be run on all processors at once
    1813           0 :   libmesh_parallel_only(mesh.comm());
    1814             : 
    1815           0 :   LOG_SCOPE ("make_p_levels_parallel_consistent()", "MeshCommunication");
    1816             : 
    1817           0 :   SyncPLevels syncplevels(mesh);
    1818             :   Parallel::sync_dofobject_data_by_id
    1819        5120 :     (mesh.comm(), mesh.elements_begin(), mesh.elements_end(),
    1820             :      syncplevels);
    1821        2560 : }
    1822             : #endif // LIBMESH_ENABLE_AMR
    1823             : 
    1824             : 
    1825             : 
    1826             : // Functors for make_node_proc_ids_parallel_consistent
    1827             : namespace {
    1828             : 
    1829             : struct SyncProcIds
    1830             : {
    1831             :   typedef processor_id_type datum;
    1832             : 
    1833       31282 :   SyncProcIds(MeshBase & _mesh) : mesh(_mesh) {}
    1834             : 
    1835             :   MeshBase & mesh;
    1836             : 
    1837             :   // ------------------------------------------------------------
    1838      250607 :   void gather_data (const std::vector<dof_id_type> & ids,
    1839             :                     std::vector<datum> & data)
    1840             :   {
    1841             :     // Find the processor id of each requested node
    1842      250607 :     data.resize(ids.size());
    1843             : 
    1844    51099503 :     for (auto i : index_range(ids))
    1845             :       {
    1846             :         // Look for this point in the mesh
    1847    50848896 :         if (ids[i] != DofObject::invalid_id)
    1848             :           {
    1849    50848896 :             Node & node = mesh.node_ref(ids[i]);
    1850             : 
    1851             :             // Return the node's correct processor id,
    1852    50848896 :             data[i] = node.processor_id();
    1853             :           }
    1854             :         else
    1855           0 :           data[i] = DofObject::invalid_processor_id;
    1856             :       }
    1857      250607 :   }
    1858             : 
    1859             :   // ------------------------------------------------------------
    1860      250607 :   bool act_on_data (const std::vector<dof_id_type> & ids,
    1861             :                     const std::vector<datum> proc_ids)
    1862             :   {
    1863          86 :     bool data_changed = false;
    1864             : 
    1865             :     // Set the ghost node processor ids we've now been informed of
    1866    51099503 :     for (auto i : index_range(ids))
    1867             :       {
    1868    50848896 :         Node & node = mesh.node_ref(ids[i]);
    1869             : 
    1870             :         // We may not have ids synched when this synchronization is done, so we
    1871             :         // *can't* use id to load-balance processor id properly; we have to use
    1872             :         // the old heuristic of choosing the smallest valid processor id.
    1873             :         //
    1874             :         // If someone tells us our node processor id is too low, then
    1875             :         // they're wrong.  If they tell us our node processor id is
    1876             :         // too high, then we're wrong.
    1877    50848896 :         if (node.processor_id() > proc_ids[i])
    1878             :           {
    1879           0 :             data_changed = true;
    1880       87746 :             node.processor_id() = proc_ids[i];
    1881             :           }
    1882             :       }
    1883             : 
    1884      250607 :     return data_changed;
    1885             :   }
    1886             : };
    1887             : 
    1888             : 
    1889             : struct ElemNodesMaybeNew
    1890             : {
    1891          38 :   ElemNodesMaybeNew() {}
    1892             : 
    1893    16932826 :   bool operator() (const Elem * elem) const
    1894             :   {
    1895             :     // If this element was just refined then it may have new nodes we
    1896             :     // need to work on
    1897             : #ifdef LIBMESH_ENABLE_AMR
    1898    16932826 :     if (elem->refinement_flag() == Elem::JUST_REFINED)
    1899        7896 :       return true;
    1900             : #endif
    1901             : 
    1902             :     // If this element has remote_elem neighbors then there may have
    1903             :     // been refinement of those neighbors that affect its nodes'
    1904             :     // processor_id()
    1905    14025472 :     for (auto neigh : elem->neighbor_ptr_range())
    1906    11681498 :       if (neigh == remote_elem)
    1907      896658 :         return true;
    1908     2343974 :     return false;
    1909             :   }
    1910             : };
    1911             : 
    1912             : 
    1913       22555 : struct NodeWasNew
    1914             : {
    1915       22593 :   NodeWasNew(const MeshBase & mesh)
    1916       22593 :   {
    1917    17271536 :     for (const auto & node : mesh.node_ptr_range())
    1918     8625540 :       if (node->processor_id() == DofObject::invalid_processor_id)
    1919       32995 :         was_new.insert(node);
    1920       22593 :   }
    1921             : 
    1922    95031556 :   bool operator() (const Elem * elem, unsigned int local_node_num) const
    1923             :   {
    1924    95031556 :     if (was_new.count(elem->node_ptr(local_node_num)))
    1925    61754718 :       return true;
    1926        9602 :     return false;
    1927             :   }
    1928             : 
    1929             :   std::unordered_set<const Node *> was_new;
    1930             : };
    1931             : 
    1932             : }
    1933             : 
    1934             : 
    1935             : 
    1936             : // ------------------------------------------------------------
    1937        8689 : void MeshCommunication::make_node_proc_ids_parallel_consistent(MeshBase & mesh)
    1938             : {
    1939          10 :   LOG_SCOPE ("make_node_proc_ids_parallel_consistent()", "MeshCommunication");
    1940             : 
    1941             :   // This function must be run on all processors at once
    1942          10 :   libmesh_parallel_only(mesh.comm());
    1943             : 
    1944             :   // When this function is called, each section of a parallelized mesh
    1945             :   // should be in the following state:
    1946             :   //
    1947             :   // All nodes should have the exact same physical location on every
    1948             :   // processor where they exist.
    1949             :   //
    1950             :   // Local nodes should have unique authoritative ids,
    1951             :   // and processor ids consistent with all processors which own
    1952             :   // an element touching them.
    1953             :   //
    1954             :   // Ghost nodes touching local elements should have processor ids
    1955             :   // consistent with all processors which own an element touching
    1956             :   // them.
    1957          10 :   SyncProcIds sync(mesh);
    1958             :   Parallel::sync_node_data_by_element_id
    1959       26047 :     (mesh, mesh.elements_begin(), mesh.elements_end(),
    1960        8689 :      Parallel::SyncEverything(), Parallel::SyncEverything(), sync);
    1961        8689 : }
    1962             : 
    1963             : 
    1964             : 
    1965             : // ------------------------------------------------------------
    1966       22593 : void MeshCommunication::make_new_node_proc_ids_parallel_consistent(MeshBase & mesh)
    1967             : {
    1968          76 :   LOG_SCOPE ("make_new_node_proc_ids_parallel_consistent()", "MeshCommunication");
    1969             : 
    1970             :   // This function must be run on all processors at once
    1971          38 :   libmesh_parallel_only(mesh.comm());
    1972             : 
    1973             :   // When this function is called, each section of a parallelized mesh
    1974             :   // should be in the following state:
    1975             :   //
    1976             :   // Local nodes should have unique authoritative ids,
    1977             :   // and new nodes should be unpartitioned.
    1978             :   //
    1979             :   // New ghost nodes touching local elements should be unpartitioned.
    1980             : 
    1981             :   // We may not have consistent processor ids for new nodes (because a
    1982             :   // node may be old and partitioned on one processor but new and
    1983             :   // unpartitioned on another) when we start
    1984             : #ifdef DEBUG
    1985          38 :   MeshTools::libmesh_assert_parallel_consistent_procids<Node>(mesh);
    1986             :   // MeshTools::libmesh_assert_parallel_consistent_new_node_procids(mesh);
    1987             : #endif
    1988             : 
    1989             :   // We have two kinds of new nodes.  *NEW* nodes are unpartitioned on
    1990             :   // all processors: we need to use a id-independent (i.e. dumb)
    1991             :   // heuristic to partition them.  But "new" nodes are newly created
    1992             :   // on some processors (when ghost elements are refined) yet
    1993             :   // correspond to existing nodes on other processors: we need to use
    1994             :   // the existing processor id for them.
    1995             :   //
    1996             :   // A node which is "new" on one processor will be associated with at
    1997             :   // least one ghost element, and we can just query that ghost
    1998             :   // element's owner to find out the correct processor id.
    1999             : 
    2000             :   auto node_unpartitioned =
    2001       24034 :     [](const Elem * elem, unsigned int local_node_num)
    2002       24034 :     { return elem->node_ref(local_node_num).processor_id() ==
    2003       24034 :         DofObject::invalid_processor_id; };
    2004             : 
    2005          38 :   SyncProcIds sync(mesh);
    2006             : 
    2007             :   sync_node_data_by_element_id_once
    2008       67703 :     (mesh, mesh.not_local_elements_begin(),
    2009       22631 :      mesh.not_local_elements_end(), Parallel::SyncEverything(),
    2010             :      node_unpartitioned, sync);
    2011             : 
    2012             :   // Nodes should now be unpartitioned iff they are truly new; those
    2013             :   // are the *only* nodes we will touch.
    2014             : #ifdef DEBUG
    2015          38 :   MeshTools::libmesh_assert_parallel_consistent_new_node_procids(mesh);
    2016             : #endif
    2017             : 
    2018       22631 :   NodeWasNew node_was_new(mesh);
    2019             : 
    2020             :   // Set the lowest processor id we can on truly new nodes
    2021     9522210 :   for (auto & elem : mesh.element_ptr_range())
    2022    44405618 :     for (auto & node : elem->node_ref_range())
    2023    39656051 :       if (node_was_new.was_new.count(&node))
    2024             :         {
    2025       18292 :           processor_id_type & pid = node.processor_id();
    2026    29535380 :           pid = std::min(pid, elem->processor_id());
    2027       22517 :         }
    2028             : 
    2029             :   // Then finally see if other processors have a lower option
    2030             :   Parallel::sync_node_data_by_element_id
    2031       67703 :     (mesh, mesh.elements_begin(), mesh.elements_end(),
    2032       22555 :      ElemNodesMaybeNew(), node_was_new, sync);
    2033             : 
    2034             :   // We should have consistent processor ids when we're done.
    2035             : #ifdef DEBUG
    2036          38 :   MeshTools::libmesh_assert_parallel_consistent_procids<Node>(mesh);
    2037          38 :   MeshTools::libmesh_assert_parallel_consistent_new_node_procids(mesh);
    2038             : #endif
    2039       22593 : }
    2040             : 
    2041             : 
    2042             : 
    2043             : // ------------------------------------------------------------
    2044        8609 : void MeshCommunication::make_nodes_parallel_consistent (MeshBase & mesh)
    2045             : {
    2046             :   // This function must be run on all processors at once
    2047          10 :   libmesh_parallel_only(mesh.comm());
    2048             : 
    2049             :   // When this function is called, each section of a parallelized mesh
    2050             :   // should be in the following state:
    2051             :   //
    2052             :   // Element ids and locations should be consistent on every processor
    2053             :   // where they exist.
    2054             :   //
    2055             :   // All nodes should have the exact same physical location on every
    2056             :   // processor where they exist.
    2057             :   //
    2058             :   // Local nodes should have unique authoritative ids,
    2059             :   // and processor ids consistent with all processors which own
    2060             :   // an element touching them.
    2061             :   //
    2062             :   // Ghost nodes touching local elements should have processor ids
    2063             :   // consistent with all processors which own an element touching
    2064             :   // them.
    2065             :   //
    2066             :   // Ghost nodes should have ids which are either already correct
    2067             :   // or which are in the "unpartitioned" id space.
    2068             : 
    2069             :   // First, let's sync up processor ids.  Some of these processor ids
    2070             :   // may be "wrong" from coarsening, but they're right in the sense
    2071             :   // that they'll tell us who has the authoritative dofobject ids for
    2072             :   // each node.
    2073             : 
    2074        8609 :   this->make_node_proc_ids_parallel_consistent(mesh);
    2075             : 
    2076             :   // Second, sync up dofobject ids.
    2077        8609 :   this->make_node_ids_parallel_consistent(mesh);
    2078             : 
    2079             :   // Third, sync up dofobject unique_ids if applicable.
    2080        8609 :   this->make_node_unique_ids_parallel_consistent(mesh);
    2081             : 
    2082             :   // Finally, correct the processor ids to make DofMap happy
    2083        8609 :   MeshTools::correct_node_proc_ids(mesh);
    2084        8609 : }
    2085             : 
    2086             : 
    2087             : 
    2088             : // ------------------------------------------------------------
    2089       22593 : void MeshCommunication::make_new_nodes_parallel_consistent (MeshBase & mesh)
    2090             : {
    2091             :   // This function must be run on all processors at once
    2092          38 :   libmesh_parallel_only(mesh.comm());
    2093             : 
    2094             :   // When this function is called, each section of a parallelized mesh
    2095             :   // should be in the following state:
    2096             :   //
    2097             :   // All nodes should have the exact same physical location on every
    2098             :   // processor where they exist.
    2099             :   //
    2100             :   // Local nodes should have unique authoritative ids,
    2101             :   // and new nodes should be unpartitioned.
    2102             :   //
    2103             :   // New ghost nodes touching local elements should be unpartitioned.
    2104             :   //
    2105             :   // New ghost nodes should have ids which are either already correct
    2106             :   // or which are in the "unpartitioned" id space.
    2107             :   //
    2108             :   // Non-new nodes should have correct ids and processor ids already.
    2109             : 
    2110             :   // First, let's sync up new nodes' processor ids.
    2111             : 
    2112       22593 :   this->make_new_node_proc_ids_parallel_consistent(mesh);
    2113             : 
    2114             :   // Second, sync up dofobject ids.
    2115       22593 :   this->make_node_ids_parallel_consistent(mesh);
    2116             : 
    2117             :   // Third, sync up dofobject unique_ids if applicable.
    2118       22593 :   this->make_node_unique_ids_parallel_consistent(mesh);
    2119             : 
    2120             :   // Fourth, sync up any nodal boundary conditions
    2121       22593 :   this->make_node_bcids_parallel_consistent(mesh);
    2122             : 
    2123             :   // Finally, correct the processor ids to make DofMap happy
    2124       22593 :   MeshTools::correct_node_proc_ids(mesh);
    2125       22593 : }
    2126             : 
    2127             : 
    2128             : 
    2129             : // ------------------------------------------------------------
    2130             : void
    2131      404570 : MeshCommunication::delete_remote_elements (DistributedMesh & mesh,
    2132             :                                            const std::set<Elem *> & extra_ghost_elem_ids) const
    2133             : {
    2134             :   // The mesh should know it's about to be parallelized
    2135         386 :   libmesh_assert (!mesh.is_serial());
    2136             : 
    2137         772 :   LOG_SCOPE("delete_remote_elements()", "MeshCommunication");
    2138             : 
    2139             : #ifdef DEBUG
    2140             :   // We expect maximum ids to be in sync so we can use them to size
    2141             :   // vectors
    2142         386 :   libmesh_assert(mesh.comm().verify(mesh.max_node_id()));
    2143         386 :   libmesh_assert(mesh.comm().verify(mesh.max_elem_id()));
    2144         386 :   const dof_id_type par_max_node_id = mesh.parallel_max_node_id();
    2145         386 :   const dof_id_type par_max_elem_id = mesh.parallel_max_elem_id();
    2146         386 :   libmesh_assert_equal_to (par_max_node_id, mesh.max_node_id());
    2147         386 :   libmesh_assert_equal_to (par_max_elem_id, mesh.max_elem_id());
    2148         386 :   const dof_id_type n_constraint_rows = mesh.n_constraint_rows();
    2149             : #endif
    2150             : 
    2151         772 :   connected_elem_set_type elements_to_keep;
    2152             : 
    2153             :   // Don't delete elements that we were explicitly told not to
    2154      404570 :   for (const auto & elem : extra_ghost_elem_ids)
    2155             :     {
    2156           0 :       std::vector<const Elem *> active_family;
    2157             : #ifdef LIBMESH_ENABLE_AMR
    2158           0 :       if (!elem->subactive())
    2159           0 :         elem->active_family_tree(active_family);
    2160             :       else
    2161             : #endif
    2162           0 :         active_family.push_back(elem);
    2163             : 
    2164           0 :       for (const auto & f : active_family)
    2165           0 :         elements_to_keep.insert(f);
    2166             :     }
    2167             : 
    2168             :   // See which elements we still need to keep ghosted, given that
    2169             :   // we're keeping local and unpartitioned elements.
    2170             :   query_ghosting_functors
    2171      406114 :     (mesh, mesh.processor_id(),
    2172      809526 :      mesh.active_pid_elements_begin(mesh.processor_id()),
    2173      405342 :      mesh.active_pid_elements_end(mesh.processor_id()),
    2174             :      elements_to_keep);
    2175             :   query_ghosting_functors
    2176      405728 :     (mesh, DofObject::invalid_processor_id,
    2177      809140 :      mesh.active_pid_elements_begin(DofObject::invalid_processor_id),
    2178      808754 :      mesh.active_pid_elements_end(DofObject::invalid_processor_id),
    2179             :      elements_to_keep);
    2180             : 
    2181             :   // The inactive elements we need to send should have their
    2182             :   // immediate children present.
    2183     1213324 :   connect_children(mesh, mesh.pid_elements_begin(mesh.processor_id()),
    2184      405342 :                    mesh.pid_elements_end(mesh.processor_id()),
    2185             :                    elements_to_keep);
    2186      405728 :   connect_children(mesh,
    2187      809140 :                    mesh.pid_elements_begin(DofObject::invalid_processor_id),
    2188      809140 :                    mesh.pid_elements_end(DofObject::invalid_processor_id),
    2189             :                    elements_to_keep);
    2190             : 
    2191             :   // And see which elements and nodes they depend on
    2192         772 :   connected_node_set_type connected_nodes;
    2193      404570 :   connect_element_dependencies(mesh, elements_to_keep, connected_nodes);
    2194             : 
    2195             :   // Delete all the elements we have no reason to save,
    2196             :   // starting with the most refined so that the mesh
    2197             :   // is valid at all intermediate steps
    2198      404570 :   unsigned int n_levels = MeshTools::n_levels(mesh);
    2199             : 
    2200      923889 :   for (int l = n_levels - 1; l >= 0; --l)
    2201     1057306 :     for (auto & elem : as_range(mesh.level_elements_begin(l),
    2202   100887824 :                                 mesh.level_elements_end(l)))
    2203             :       {
    2204       19148 :         libmesh_assert (elem);
    2205             :         // Make sure we don't leave any invalid pointers
    2206       55673 :         const bool keep_me = elements_to_keep.count(elem);
    2207             : 
    2208       19148 :         if (!keep_me)
    2209    35883236 :           elem->make_links_to_me_remote();
    2210             : 
    2211             :         // delete_elem doesn't currently invalidate element
    2212             :         // iterators... that had better not change
    2213       38296 :         if (!keep_me)
    2214    35883236 :           mesh.delete_elem(elem);
    2215      518359 :       }
    2216             : 
    2217             :   // Delete all the nodes we have no reason to save
    2218   167027460 :   for (auto & node : mesh.node_ptr_range())
    2219             :     {
    2220       51664 :       libmesh_assert(node);
    2221      151911 :       if (!connected_nodes.count(node))
    2222             :         {
    2223        3081 :           libmesh_assert_not_equal_to(node->processor_id(),
    2224             :                                       mesh.processor_id());
    2225    50004711 :           mesh.delete_node(node);
    2226             :         }
    2227      403798 :     }
    2228             : 
    2229             :   // If we had a point locator, it's invalid now that some of the
    2230             :   // elements it pointed to have been deleted.
    2231      404570 :   mesh.clear_point_locator();
    2232             : 
    2233             :   // We now have all remote elements and nodes deleted; our ghosting
    2234             :   // functors should be ready to delete any now-redundant cached data
    2235             :   // they use too.
    2236      942292 :   for (auto & gf : as_range(mesh.ghosting_functors_begin(), mesh.ghosting_functors_end()))
    2237      537722 :     gf->delete_remote_elements();
    2238             : 
    2239             : #ifdef DEBUG
    2240         386 :   const dof_id_type n_new_constraint_rows = mesh.n_constraint_rows();
    2241         386 :   libmesh_assert_equal_to(n_constraint_rows, n_new_constraint_rows);
    2242             : 
    2243         386 :   MeshTools::libmesh_assert_valid_refinement_tree(mesh);
    2244         386 :   MeshTools::libmesh_assert_valid_constraint_rows(mesh);
    2245             : #endif
    2246      404570 : }
    2247             : 
    2248             : } // namespace libMesh

Generated by: LCOV version 1.14