LCOV - code coverage report
Current view: top level - src/mesh - mesh_communication.C (source / functions) Hit Total Coverage
Test: libMesh/libmesh: #4476 (4beb67) with base a68cc6 Lines: 700 763 91.7 %
Date: 2026-06-03 20:22:46 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     1254569 : 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     1254569 :   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      674446 :       for (const Elem * elem : connected_elements)
     147             :         {
     148     3107538 :           for (const Node & node : elem->node_ref_range())
     149             :             {
     150             :               // Retain all elements containing constraining nodes
     151     2445264 :               if (const auto it = constraint_rows.find(&node);
     152           0 :                   it != constraint_rows.end())
     153    26143658 :                 for (auto & p : it->second)
     154             :                   {
     155    23923962 :                     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       12172 :       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        1070 :     elem_rit  = new_connected_elements.rbegin();
     188             : 
     189    30480050 :   for (; elem_rit != new_connected_elements.rend(); ++elem_rit)
     190             :     {
     191    29225481 :       const Elem * elem = *elem_rit;
     192       25220 :       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    63305664 :       for (const Elem * parent = elem->parent(); parent;
     198    34068647 :            parent = parent->parent())
     199       27368 :         if (!connected_elements.count(parent) &&
     200       13684 :             !new_connected_elements.count(parent))
     201    18382446 :           newer_connected_elements.insert (parent);
     202             : 
     203             :       auto total_family_insert =
     204    29175041 :         [&connected_elements, &new_connected_elements,
     205             :          &newer_connected_elements]
     206      380288 :         (const Elem * e)
     207             :         {
     208       25220 :           if (e->active() && e->has_children())
     209             :             {
     210           0 :               std::vector<const Elem *> subactive_family;
     211       37444 :               e->total_family_tree(subactive_family);
     212      202368 :               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       29784 :                     newer_connected_elements.insert(f);
     218             :                 }
     219             :             }
     220    29225481 :         };
     221             : 
     222    29225481 :       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    29225481 :       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       25220 :       libmesh_assert(!interior_parent || mesh);
     233             : 
     234       38304 :       if (interior_parent &&
     235       13084 :           interior_parent == mesh->query_elem_ptr(interior_parent->id()) &&
     236    29225575 :           !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       91808 :     (const Elem * elem)
     254             :     {
     255       54690 :       libmesh_assert(elem);
     256       54690 :       const Elem * parent = elem->parent();
     257       54690 :       if (parent)
     258       20106 :         libmesh_assert(connected_elements.count(parent) ||
     259             :                        new_connected_elements.count(parent) ||
     260             :                        newer_connected_elements.count(parent));
     261       54690 :     };
     262             : 
     263       29596 :   for (const auto & elem : connected_elements)
     264       28526 :     check_elem(elem);
     265       26290 :   for (const auto & elem : new_connected_elements)
     266       25220 :     check_elem(elem);
     267        2014 :   for (const auto & elem : newer_connected_elements)
     268         944 :     check_elem(elem);
     269             : #  endif // DEBUG
     270             : 
     271             : #endif // LIBMESH_ENABLE_AMR
     272     1254569 : }
     273             : 
     274             : 
     275             : 
     276     1254569 : 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    30480050 :   for (const auto & elem : new_connected_elements)
     282   313040014 :     for (auto & n : elem->node_ref_range())
     283   284040274 :       if (!connected_nodes.count(&n) &&
     284   294291697 :           !new_connected_nodes.count(&n))
     285   273523435 :         newer_connected_nodes.insert(&n);
     286     1254569 : }
     287             : 
     288             : 
     289             : } // anonymous namespace
     290             : 
     291             : 
     292             : 
     293             : namespace libMesh
     294             : {
     295             : 
     296             : 
     297     1158328 : 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     1157559 :   for (auto & gf :
     304         905 :          as_range(mesh.ghosting_functors_begin(),
     305     2730167 :                   mesh.ghosting_functors_end()))
     306             :     {
     307        2082 :       GhostingFunctor::map_type elements_to_ghost;
     308        1041 :       libmesh_assert(gf);
     309     1569893 :       (*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    18606609 :       for (auto & pr : elements_to_ghost)
     314             :         {
     315    17036716 :           const Elem * elem = pr.first;
     316        8651 :           libmesh_assert(elem != remote_elem);
     317        8651 :           libmesh_assert(mesh.elem_ptr(elem->id()) == elem);
     318    17028065 :           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    20399534 :   for (; elem_it != elem_end; ++elem_it)
     325     9635447 :     connected_elements.insert(*elem_it);
     326     1158328 : }
     327             : 
     328             : 
     329     1158328 : 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         905 :   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    24991479 :   for (const auto & elem : as_range(elem_it, elem_end))
     342             :     {
     343    11353734 :       if (elem->has_children())
     344     9539345 :         for (auto & child : elem->child_ref_range())
     345     7894502 :           if (&child != remote_elem)
     346     7637226 :             connected_elements.insert(&child);
     347     1156518 :     }
     348             : #endif // LIBMESH_ENABLE_AMR
     349     1158328 : }
     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      758572 : 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        1066 :   connected_elem_set_type new_connected_elements;
     372        1066 :   connected_node_set_type new_connected_nodes;
     373         533 :   new_connected_elements.swap(connected_elements);
     374         533 :   new_connected_nodes.swap(connected_nodes);
     375             : 
     376     2014114 :   while (!new_connected_elements.empty() ||
     377         973 :          !new_connected_nodes.empty())
     378             :     {
     379             :       auto [newer_connected_elements,
     380        1070 :             newer_connected_nodes] =
     381             :         connect_element_dependencies
     382             :           (mesh, connected_elements, connected_nodes,
     383     1256709 :            new_connected_elements, new_connected_nodes);
     384             : 
     385             :       // These have now been examined
     386        1070 :       connected_elements.merge(new_connected_elements);
     387        1070 :       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        1070 :       libmesh_assert(new_connected_elements.empty());
     392        1070 :       libmesh_assert(new_connected_nodes.empty());
     393             : 
     394             :       // These now need to be examined
     395        1070 :       new_connected_elements.swap(newer_connected_elements);
     396        1070 :       new_connected_nodes.swap(newer_connected_nodes);
     397     1252429 :     }
     398      758572 : }
     399             : 
     400             : 
     401             : std::pair<connected_elem_set_type, connected_node_set_type>
     402     1254569 : 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        1070 :   std::pair<connected_elem_set_type, connected_node_set_type> returnval;
     409        1070 :   auto & [newer_connected_elements, newer_connected_nodes] = returnval;
     410     1254569 :   connect_element_families(connected_elements, new_connected_elements,
     411             :                            newer_connected_elements, &mesh);
     412             : 
     413     1254569 :   connect_nodes(new_connected_elements, connected_nodes,
     414             :                 new_connected_nodes, newer_connected_nodes);
     415             : 
     416     1254569 :   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       66243 : 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       66243 :     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       66243 :     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    10032400 :   for (auto & elem : as_range(send_elems_begin, send_elems_end))
     496     4973033 :     if (elem->processor_id() != mesh.processor_id())
     497     3629010 :       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       66243 :   bool have_constraint_rows = !constraint_rows.empty();
     505       66243 :   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      424519 :   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      358276 :       v_t * elempp = p_elements.data();
     536      358276 :       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      358409 :           (elempp, elemend, Predicates::NotNull<v_t *>());
     547             : 
     548             :       const MeshBase::const_element_iterator elem_end =
     549             :         MeshBase::const_element_iterator
     550      716552 :           (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      716419 :       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     1074562 :       connect_children(mesh, mesh.pid_elements_begin(pid),
     561      716552 :                        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      358276 :       connect_element_dependencies(mesh, elements_to_send,
     567             :                                    connected_nodes);
     568             : 
     569      358276 :       all_nodes_to_send[pid].assign(connected_nodes.begin(),
     570             :                                     connected_nodes.end());
     571             : 
     572      358276 :       all_elems_to_send[pid].assign(elements_to_send.begin(),
     573             :                                     elements_to_send.end());
     574             : 
     575      448534 :       for (auto & [node, row] : constraint_rows)
     576             :         {
     577       29562 :           if (!connected_nodes.count(node))
     578       29562 :             continue;
     579             : 
     580           0 :           serialized_row_type serialized_row;
     581      648454 :           for (auto [elem_and_node, coef] : row)
     582      587758 :             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       60696 :             (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       66243 :   TIMPI::push_parallel_packed_range(mesh.comm(), all_nodes_to_send, &mesh,
     597             :                                     null_node_action);
     598             : 
     599       66243 :   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       66243 :   if (have_constraint_rows)
     605             :     {
     606             :       auto constraint_row_action =
     607        1740 :         [&mesh, &constraint_rows]
     608             :         (processor_id_type /* src_pid */,
     609      647866 :          const std::vector<std::pair<dof_id_type, serialized_row_type>> rows)
     610             :         {
     611       62240 :           for (auto & [node_id, serialized_row] : rows)
     612             :             {
     613           0 :               MeshBase::constraint_rows_mapped_type row;
     614      647866 :               for (auto [elem_and_node, coef] : serialized_row)
     615      587366 :                 row.emplace_back(std::make_pair(mesh.elem_ptr(elem_and_node.first),
     616           0 :                                                 elem_and_node.second),
     617           0 :                                  coef);
     618             : 
     619       60500 :               constraint_rows[mesh.node_ptr(node_id)] = row;
     620             :             }
     621        1959 :         };
     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       66243 :   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       66243 :   mesh.MeshBase::redistribute();
     651       66243 : }
     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        7015 : 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        7015 :   if (mesh.is_serial())
    1049        5851 :     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        3044 :   for (auto elem : as_range(mesh.flagged_pid_elements_begin(Elem::COARSEN, proc_id),
    1070      212399 :                             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      103920 :       const processor_id_type their_proc_id = elem->parent()->processor_id();
    1080      103920 :       if (their_proc_id != proc_id)
    1081         631 :         coarsening_elements_to_ghost[their_proc_id].push_back(elem);
    1082        1156 :     }
    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       13428 :   for (processor_id_type p=0; p != n_proc; ++p)
    1090             :     {
    1091       12264 :       if (p == proc_id)
    1092        1164 :         continue;
    1093             : 
    1094           8 :       connected_elem_set_type elements_to_send;
    1095           8 :       std::set<const Node *> nodes_to_send;
    1096             : 
    1097       11100 :       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         201 :           Elem * const * elempp = const_cast<Elem * const *>(elems.data());
    1106         201 :           Elem * const * elemend = elempp+elems.size();
    1107             :           const MeshBase::const_element_iterator elem_it =
    1108         201 :             MeshBase::const_element_iterator(elempp, elemend, Predicates::NotNull<Elem * const *>());
    1109             :           const MeshBase::const_element_iterator elem_end =
    1110         402 :             MeshBase::const_element_iterator(elemend, elemend, Predicates::NotNull<Elem * const *>());
    1111             : 
    1112         201 :           for (auto & gf : as_range(mesh.ghosting_functors_begin(),
    1113         828 :                                     mesh.ghosting_functors_end()))
    1114             :             {
    1115           0 :               GhostingFunctor::map_type elements_to_ghost;
    1116           0 :               libmesh_assert(gf);
    1117         627 :               (*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        4941 :               for (auto & pr : elements_to_ghost)
    1122             :                 {
    1123        4314 :                   const Elem * elem = pr.first;
    1124           0 :                   libmesh_assert(elem);
    1125       15059 :                   while (elem)
    1126             :                     {
    1127           0 :                       libmesh_assert(elem != remote_elem);
    1128       10745 :                       elements_to_send.insert(elem);
    1129      104948 :                       for (auto & n : elem->node_ref_range())
    1130       94203 :                         nodes_to_send.insert(&n);
    1131       10745 :                       elem = elem->parent();
    1132             :                     }
    1133             :                 }
    1134             :             }
    1135             : 
    1136         201 :           all_nodes_to_send[p].assign(nodes_to_send.begin(), nodes_to_send.end());
    1137         201 :           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        1164 :   TIMPI::push_parallel_packed_range(mesh.comm(), all_nodes_to_send, &mesh,
    1147             :                                     null_node_action);
    1148             : 
    1149        1164 :   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       14582 : void MeshCommunication::broadcast (MeshBase & mesh) const
    1167             : {
    1168             :   // Don't need to do anything if there is
    1169             :   // only one processor.
    1170       14998 :   if (mesh.n_processors() == 1)
    1171         403 :     return;
    1172             : 
    1173             :   // This function must be run on all processors at once
    1174         416 :   libmesh_parallel_only(mesh.comm());
    1175             : 
    1176         832 :   LOG_SCOPE("broadcast()", "MeshCommunication");
    1177             : 
    1178             :   // Explicitly clear the mesh on all but processor 0.
    1179       14595 :   if (mesh.processor_id() != 0)
    1180       12112 :     mesh.clear();
    1181             : 
    1182             :   // We may have set extra data only on processor 0 in a read()
    1183       14179 :   mesh.comm().broadcast(mesh._node_integer_names);
    1184       14179 :   mesh.comm().broadcast(mesh._node_integer_default_values);
    1185       14179 :   mesh.comm().broadcast(mesh._elem_integer_names);
    1186       14179 :   mesh.comm().broadcast(mesh._elem_integer_default_values);
    1187             : 
    1188             :   // We may have set mapping data only on processor 0 in a read()
    1189       14179 :   unsigned char map_type = mesh.default_mapping_type();
    1190       14179 :   unsigned char map_data = mesh.default_mapping_data();
    1191       14179 :   mesh.comm().broadcast(map_type);
    1192       14179 :   mesh.comm().broadcast(map_data);
    1193       14179 :   mesh.set_default_mapping_type(ElemMappingType(map_type));
    1194       14179 :   mesh.set_default_mapping_data(map_data);
    1195             : 
    1196             :   // Broadcast nodes
    1197       14595 :   mesh.comm().broadcast_packed_range(&mesh,
    1198       28358 :                                      mesh.nodes_begin(),
    1199       14595 :                                      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       14179 :   const unsigned int n_levels = MeshTools::paranoid_n_levels(mesh);
    1211             : 
    1212       28358 :   for (unsigned int l=0; l != n_levels; ++l)
    1213       14595 :     mesh.comm().broadcast_packed_range(&mesh,
    1214       28358 :                                        mesh.level_elements_begin(l),
    1215       28358 :                                        mesh.level_elements_end(l),
    1216             :                                        &mesh,
    1217             :                                        null_output_iterator<Elem>());
    1218             : 
    1219             :   // Make sure mesh_dimension and elem_dimensions are consistent.
    1220       14179 :   mesh.cache_elem_data();
    1221             : 
    1222             :   // Make sure mesh id counts are consistent.
    1223       14179 :   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         416 :   auto & constraint_rows = mesh.get_constraint_rows();
    1230       14179 :   bool have_constraint_rows = !constraint_rows.empty();
    1231       14179 :   mesh.comm().broadcast(have_constraint_rows);
    1232       14179 :   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       14179 :   mesh.comm().broadcast(mesh.set_subdomain_name_map());
    1279       14179 :   mesh.comm().broadcast(mesh.get_boundary_info().set_sideset_name_map());
    1280       14179 :   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       14179 :   mesh.clear_point_locator();
    1285             : 
    1286         416 :   libmesh_assert (mesh.comm().verify(mesh.n_elem()));
    1287         416 :   libmesh_assert (mesh.comm().verify(mesh.n_nodes()));
    1288             : 
    1289             : #ifdef DEBUG
    1290         416 :   MeshTools::libmesh_assert_valid_procids<Elem>(mesh);
    1291         416 :   MeshTools::libmesh_assert_valid_procids<Node>(mesh);
    1292             : #endif
    1293             : }
    1294             : #endif // LIBMESH_HAVE_MPI
    1295             : 
    1296             : 
    1297             : 
    1298             : #ifndef LIBMESH_HAVE_MPI // avoid spurious gcc warnings
    1299             : // ------------------------------------------------------------
    1300             : void MeshCommunication::gather (const processor_id_type, MeshBase &) const
    1301             : {
    1302             :   // no MPI == one processor, no need for this method...
    1303             :   return;
    1304             : }
    1305             : #else
    1306             : // ------------------------------------------------------------
    1307      110460 : void MeshCommunication::gather (const processor_id_type root_id, MeshBase & mesh) const
    1308             : {
    1309             :   // Check for quick return
    1310      110532 :   if (mesh.n_processors() == 1)
    1311        1093 :     return;
    1312             : 
    1313             :   // This function must be run on all processors at once
    1314          72 :   libmesh_parallel_only(mesh.comm());
    1315             : 
    1316         144 :   LOG_SCOPE("(all)gather()", "MeshCommunication");
    1317             : 
    1318             :   // Ensure we don't build too big a buffer at once
    1319             :   static const std::size_t approx_total_buffer_size = 1e8;
    1320             :   const std::size_t approx_each_buffer_size =
    1321      109367 :     approx_total_buffer_size / mesh.comm().size();
    1322             : 
    1323      109367 :   (root_id == DofObject::invalid_processor_id) ?
    1324             : 
    1325       95791 :     mesh.comm().allgather_packed_range (&mesh,
    1326       95791 :                                         mesh.nodes_begin(),
    1327      205096 :                                         mesh.nodes_end(),
    1328             :                                         null_output_iterator<Node>(),
    1329             :                                         approx_each_buffer_size) :
    1330             : 
    1331       13648 :     mesh.comm().gather_packed_range (root_id,
    1332             :                                      &mesh,
    1333      123005 :                                      mesh.nodes_begin(),
    1334      136633 :                                      mesh.nodes_end(),
    1335             :                                      null_output_iterator<Node>(),
    1336             :                                      approx_each_buffer_size);
    1337             : 
    1338             :   // Gather elements from coarsest to finest, so that child
    1339             :   // elements will see their parents already in place.
    1340      109367 :   const unsigned int n_levels = MeshTools::n_levels(mesh);
    1341             : 
    1342      298073 :   for (unsigned int l=0; l != n_levels; ++l)
    1343      188706 :     (root_id == DofObject::invalid_processor_id) ?
    1344             : 
    1345      168452 :       mesh.comm().allgather_packed_range (&mesh,
    1346      168452 :                                           mesh.level_elements_begin(l),
    1347      525388 :                                           mesh.level_elements_end(l),
    1348             :                                           null_output_iterator<Elem>(),
    1349             :                                           approx_each_buffer_size) :
    1350             : 
    1351       20342 :       mesh.comm().gather_packed_range (root_id,
    1352             :                                        &mesh,
    1353      209034 :                                        mesh.level_elements_begin(l),
    1354      229348 :                                        mesh.level_elements_end(l),
    1355             :                                        null_output_iterator<Elem>(),
    1356             :                                        approx_each_buffer_size);
    1357             : 
    1358             :   // If we had a point locator, it's invalid now that there are new
    1359             :   // elements it can't locate.
    1360      109367 :   mesh.clear_point_locator();
    1361             : 
    1362             :   // We may have constraint rows on IsoGeometric Analysis meshes.  We
    1363             :   // don't want to send these along with constrained nodes (like we
    1364             :   // send boundary info for those nodes) because the associated rows'
    1365             :   // elements may not exist at that point.
    1366          72 :   auto & constraint_rows = mesh.get_constraint_rows();
    1367      109367 :   bool have_constraint_rows = !constraint_rows.empty();
    1368      109367 :   mesh.comm().max(have_constraint_rows);
    1369      109367 :   if (have_constraint_rows)
    1370             :     {
    1371             :       std::map<dof_id_type,
    1372             :                std::vector<std::tuple<dof_id_type, unsigned int, Real>>>
    1373           0 :         serialized_rows;
    1374             : 
    1375         361 :       for (auto & row : constraint_rows)
    1376             :         {
    1377         238 :           const Node * node = row.first;
    1378         238 :           const dof_id_type rowid = node->id();
    1379           0 :           libmesh_assert(node == mesh.node_ptr(rowid));
    1380             : 
    1381             :           std::vector<std::tuple<dof_id_type, unsigned int, Real>>
    1382           0 :             serialized_row;
    1383         714 :           for (auto & entry : row.second)
    1384             :             serialized_row.push_back
    1385         476 :               (std::make_tuple(entry.first.first->id(),
    1386           0 :                                entry.first.second, entry.second));
    1387             : 
    1388         238 :           serialized_rows.emplace(rowid, std::move(serialized_row));
    1389             :         }
    1390             : 
    1391         123 :       if (root_id == DofObject::invalid_processor_id)
    1392         123 :         mesh.comm().set_union(serialized_rows);
    1393             :       else
    1394           0 :         mesh.comm().set_union(serialized_rows, root_id);
    1395             : 
    1396         123 :       if (root_id == DofObject::invalid_processor_id ||
    1397           0 :           root_id == mesh.processor_id())
    1398             :         {
    1399         918 :           for (auto & row : serialized_rows)
    1400             :             {
    1401         795 :               const dof_id_type rowid = row.first;
    1402         795 :               const Node * node = mesh.node_ptr(rowid);
    1403             : 
    1404             :               std::vector<std::pair<std::pair<const Elem *, unsigned int>, Real>>
    1405           0 :                 deserialized_row;
    1406        2385 :               for (auto & entry : row.second)
    1407             :                 deserialized_row.push_back
    1408        3180 :                   (std::make_pair(std::make_pair(mesh.elem_ptr(std::get<0>(entry)),
    1409           0 :                                                  std::get<1>(entry)),
    1410           0 :                                                  std::get<2>(entry)));
    1411             : 
    1412         795 :               constraint_rows.emplace(node, deserialized_row);
    1413             :             }
    1414             :         }
    1415             : #ifdef DEBUG
    1416           0 :       MeshTools::libmesh_assert_valid_constraint_rows(mesh);
    1417             : #endif
    1418             :     }
    1419             : 
    1420             : 
    1421             :   // If we are doing an allgather(), perform sanity check on the result.
    1422          72 :   if (root_id == DofObject::invalid_processor_id)
    1423             :     {
    1424          62 :       libmesh_assert (mesh.comm().verify(mesh.n_elem()));
    1425          62 :       libmesh_assert (mesh.comm().verify(mesh.n_nodes()));
    1426             :     }
    1427             : 
    1428             :   // Inform new elements of their neighbors,
    1429             :   // while resetting all remote_elem links on
    1430             :   // the ranks which did the gather.
    1431      109367 :   if (mesh.allow_find_neighbors())
    1432      196506 :     mesh.find_neighbors(root_id == DofObject::invalid_processor_id ||
    1433         144 :                         root_id == mesh.processor_id());
    1434             : 
    1435             :   // All done, but let's make sure it's done correctly
    1436             : 
    1437             : #ifdef DEBUG
    1438          72 :   MeshTools::libmesh_assert_valid_boundary_ids(mesh);
    1439             : #endif
    1440             : }
    1441             : #endif // LIBMESH_HAVE_MPI
    1442             : 
    1443             : 
    1444             : 
    1445             : // Functor for make_elems_parallel_consistent and
    1446             : // make_node_ids_parallel_consistent
    1447             : namespace {
    1448             : 
    1449             : struct SyncIds
    1450             : {
    1451             :   typedef dof_id_type datum;
    1452             :   typedef void (MeshBase::*renumber_obj)(dof_id_type, dof_id_type);
    1453             : 
    1454       22145 :   SyncIds(MeshBase & _mesh, renumber_obj _renumberer) :
    1455       22069 :     mesh(_mesh),
    1456       22145 :     renumber(_renumberer) {}
    1457             : 
    1458             :   MeshBase & mesh;
    1459             :   renumber_obj renumber;
    1460             :   // renumber_obj & renumber;
    1461             : 
    1462             :   // Find the id of each requested DofObject -
    1463             :   // Parallel::sync_* already did the work for us
    1464          34 :   void gather_data (const std::vector<dof_id_type> & ids,
    1465             :                     std::vector<datum> & ids_out) const
    1466             :   {
    1467       65902 :     ids_out = ids;
    1468       65868 :   }
    1469             : 
    1470       65902 :   void act_on_data (const std::vector<dof_id_type> & old_ids,
    1471             :                     const std::vector<datum> & new_ids) const
    1472             :   {
    1473     2716038 :     for (auto i : index_range(old_ids))
    1474     2652600 :       if (old_ids[i] != new_ids[i])
    1475     2604934 :         (mesh.*renumber)(old_ids[i], new_ids[i]);
    1476       65902 :   }
    1477             : };
    1478             : 
    1479             : 
    1480       30210 : struct SyncNodeIds
    1481             : {
    1482             :   typedef dof_id_type datum;
    1483             : 
    1484       30258 :   SyncNodeIds(MeshBase & _mesh) :
    1485       30258 :     mesh(_mesh) {}
    1486             : 
    1487             :   MeshBase & mesh;
    1488             : 
    1489             :   // We only know a Node id() is definitive if we own the Node or if
    1490             :   // we're told it's definitive.  We keep track of the latter cases by
    1491             :   // putting definitively id'd ghost nodes into this set.
    1492             :   typedef std::unordered_set<const Node *> uset_type;
    1493             :   uset_type definitive_ids;
    1494             : 
    1495             :   // We should never be told two different definitive ids for the same
    1496             :   // node, but let's check on that in debug mode.
    1497             : #ifdef DEBUG
    1498             :   typedef std::unordered_map<dof_id_type, dof_id_type> umap_type;
    1499             :   umap_type definitive_renumbering;
    1500             : #endif
    1501             : 
    1502             :   // Find the id of each requested DofObject -
    1503             :   // Parallel::sync_* already tried to do the work for us, but we can
    1504             :   // only say the result is definitive if we own the DofObject or if
    1505             :   // we were given the definitive result from another processor.
    1506      286238 :   void gather_data (const std::vector<dof_id_type> & ids,
    1507             :                     std::vector<datum> & ids_out) const
    1508             :   {
    1509         132 :     ids_out.clear();
    1510      286370 :     ids_out.resize(ids.size(), DofObject::invalid_id);
    1511             : 
    1512    59729949 :     for (auto i : index_range(ids))
    1513             :       {
    1514    59443711 :         const dof_id_type id = ids[i];
    1515    59443711 :         const Node * node = mesh.query_node_ptr(id);
    1516    59443711 :         if (node && (node->processor_id() == mesh.processor_id() ||
    1517       33924 :                      definitive_ids.count(node)))
    1518    59477351 :           ids_out[i] = id;
    1519             :       }
    1520      286238 :   }
    1521             : 
    1522      286238 :   bool act_on_data (const std::vector<dof_id_type> & old_ids,
    1523             :                     const std::vector<datum> & new_ids)
    1524             :   {
    1525         132 :     bool data_changed = false;
    1526    59729949 :     for (auto i : index_range(old_ids))
    1527             :       {
    1528    59443711 :         const dof_id_type new_id = new_ids[i];
    1529             : 
    1530    59443711 :         const dof_id_type old_id = old_ids[i];
    1531             : 
    1532    59443711 :         Node * node = mesh.query_node_ptr(old_id);
    1533             : 
    1534             :         // If we can't find the node we were asking about, another
    1535             :         // processor must have already given us the definitive id
    1536             :         // for it
    1537    59443711 :         if (!node)
    1538             :           {
    1539             :             // But let's check anyway in debug mode
    1540             : #ifdef DEBUG
    1541        5626 :             libmesh_assert
    1542             :               (definitive_renumbering.count(old_id));
    1543        5626 :             libmesh_assert_equal_to
    1544             :               (new_id, definitive_renumbering[old_id]);
    1545             : #endif
    1546    11346984 :             continue;
    1547             :           }
    1548             : 
    1549             :         // If we asked for an id but there's no definitive id ready
    1550             :         // for us yet, then we can't quit trying to sync yet.
    1551    48091101 :         if (new_id == DofObject::invalid_id)
    1552             :           {
    1553             :             // But we might have gotten a definitive id from a
    1554             :             // different request
    1555         284 :             if (!definitive_ids.count(mesh.node_ptr(old_id)))
    1556           0 :               data_changed = true;
    1557             :           }
    1558             :         else
    1559             :           {
    1560    48119115 :             if (node->processor_id() != mesh.processor_id())
    1561       46812 :               definitive_ids.insert(node);
    1562    48090817 :             if (old_id != new_id)
    1563             :               {
    1564             : #ifdef DEBUG
    1565        3234 :                 libmesh_assert
    1566             :                   (!definitive_renumbering.count(old_id));
    1567        3234 :                 definitive_renumbering[old_id] = new_id;
    1568             : #endif
    1569     4745707 :                 mesh.renumber_node(old_id, new_id);
    1570        3234 :                 data_changed = true;
    1571             :               }
    1572             :           }
    1573             :       }
    1574      286238 :     return data_changed;
    1575             :   }
    1576             : };
    1577             : 
    1578             : 
    1579             : #ifdef LIBMESH_ENABLE_AMR
    1580             : struct SyncPLevels
    1581             : {
    1582             :   typedef std::pair<unsigned char,unsigned char> datum;
    1583             : 
    1584        2560 :   SyncPLevels(MeshBase & _mesh) :
    1585        2560 :     mesh(_mesh) {}
    1586             : 
    1587             :   MeshBase & mesh;
    1588             : 
    1589             :   // Find the p_level of each requested Elem
    1590        3346 :   void gather_data (const std::vector<dof_id_type> & ids,
    1591             :                     std::vector<datum> & ids_out) const
    1592             :   {
    1593        3346 :     ids_out.reserve(ids.size());
    1594             : 
    1595       18571 :     for (const auto & id : ids)
    1596             :       {
    1597       15225 :         Elem & elem = mesh.elem_ref(id);
    1598             :         ids_out.push_back
    1599       15225 :           (std::make_pair(cast_int<unsigned char>(elem.p_level()),
    1600           0 :                           static_cast<unsigned char>(elem.p_refinement_flag())));
    1601             :       }
    1602        3346 :   }
    1603             : 
    1604        3346 :   void act_on_data (const std::vector<dof_id_type> & old_ids,
    1605             :                     const std::vector<datum> & new_p_levels) const
    1606             :   {
    1607       18571 :     for (auto i : index_range(old_ids))
    1608             :       {
    1609       15225 :         Elem & elem = mesh.elem_ref(old_ids[i]);
    1610             :         // Make sure these are consistent
    1611             :         elem.hack_p_level_and_refinement_flag
    1612       15225 :           (new_p_levels[i].first,
    1613       15225 :            static_cast<Elem::RefinementState>(new_p_levels[i].second));
    1614             :         // Make sure parents' levels are consistent
    1615       15225 :         elem.set_p_level(new_p_levels[i].first);
    1616             :       }
    1617        3346 :   }
    1618             : };
    1619             : #endif // LIBMESH_ENABLE_AMR
    1620             : 
    1621             : 
    1622             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
    1623             : template <typename DofObjSubclass>
    1624             : struct SyncUniqueIds
    1625             : {
    1626             :   typedef unique_id_type datum;
    1627             :   typedef DofObjSubclass* (MeshBase::*query_obj)(const dof_id_type);
    1628             : 
    1629       55286 :   SyncUniqueIds(MeshBase &_mesh, query_obj _querier) :
    1630       55038 :     mesh(_mesh),
    1631       55286 :     query(_querier) {}
    1632             : 
    1633             :   MeshBase & mesh;
    1634             :   query_obj query;
    1635             : 
    1636             :   // Find the id of each requested DofObject -
    1637             :   // Parallel::sync_* already did the work for us
    1638      203964 :   void gather_data (const std::vector<dof_id_type> & ids,
    1639             :                     std::vector<datum> & ids_out) const
    1640             :   {
    1641      204060 :     ids_out.reserve(ids.size());
    1642             : 
    1643     9687481 :     for (const auto & id : ids)
    1644             :       {
    1645     9483517 :         DofObjSubclass * d = (mesh.*query)(id);
    1646        6712 :         libmesh_assert(d);
    1647     9483517 :         ids_out.push_back(d->unique_id());
    1648             :       }
    1649      203964 :   }
    1650             : 
    1651      203964 :   void act_on_data (const std::vector<dof_id_type> & ids,
    1652             :                     const std::vector<datum> & unique_ids) const
    1653             :   {
    1654     9687481 :     for (auto i : index_range(ids))
    1655             :       {
    1656     9483517 :         DofObjSubclass * d = (mesh.*query)(ids[i]);
    1657        6712 :         libmesh_assert(d);
    1658     9490229 :         d->set_unique_id(unique_ids[i]);
    1659             :       }
    1660      203964 :   }
    1661             : };
    1662             : #endif // LIBMESH_ENABLE_UNIQUE_ID
    1663             : 
    1664             : template <typename DofObjSubclass>
    1665             : struct SyncBCIds
    1666             : {
    1667             :   typedef std::vector<boundary_id_type> datum;
    1668             : 
    1669       22145 :   SyncBCIds(MeshBase &_mesh) :
    1670       22145 :     mesh(_mesh) {}
    1671             : 
    1672             :   MeshBase & mesh;
    1673             : 
    1674             :   // Find the id of each requested DofObject -
    1675             :   // Parallel::sync_* already did the work for us
    1676       90569 :   void gather_data (const std::vector<dof_id_type> & ids,
    1677             :                     std::vector<datum> & ids_out) const
    1678             :   {
    1679       90569 :     ids_out.reserve(ids.size());
    1680             : 
    1681       90569 :     const BoundaryInfo & boundary_info = mesh.get_boundary_info();
    1682             : 
    1683     6122064 :     for (const auto & id : ids)
    1684             :       {
    1685     6031495 :         Node * n = mesh.query_node_ptr(id);
    1686        2981 :         libmesh_assert(n);
    1687        5962 :         std::vector<boundary_id_type> bcids;
    1688     6031495 :         boundary_info.boundary_ids(n, bcids);
    1689        2981 :         ids_out.push_back(std::move(bcids));
    1690             :       }
    1691       90569 :   }
    1692             : 
    1693       90569 :   void act_on_data (const std::vector<dof_id_type> & ids,
    1694             :                     const std::vector<datum> & bcids) const
    1695             :   {
    1696       90569 :     BoundaryInfo & boundary_info = mesh.get_boundary_info();
    1697             : 
    1698     6122064 :     for (auto i : index_range(ids))
    1699             :       {
    1700     6031495 :         Node * n = mesh.query_node_ptr(ids[i]);
    1701        2981 :         libmesh_assert(n);
    1702     6031495 :         boundary_info.add_node(n, bcids[i]);
    1703             :       }
    1704       90569 :   }
    1705             : };
    1706             : 
    1707             : }
    1708             : 
    1709             : 
    1710             : 
    1711             : // ------------------------------------------------------------
    1712       30258 : void MeshCommunication::make_node_ids_parallel_consistent (MeshBase & mesh)
    1713             : {
    1714             :   // This function must be run on all processors at once
    1715          48 :   libmesh_parallel_only(mesh.comm());
    1716             : 
    1717             :   // We need to agree on which processor owns every node, but we can't
    1718             :   // easily assert that here because we don't currently agree on which
    1719             :   // id every node has, and some of our temporary ids on unrelated
    1720             :   // nodes will "overlap".
    1721             : //#ifdef DEBUG
    1722             : //  MeshTools::libmesh_assert_parallel_consistent_procids<Node> (mesh);
    1723             : //#endif // DEBUG
    1724             : 
    1725          96 :   LOG_SCOPE ("make_node_ids_parallel_consistent()", "MeshCommunication");
    1726             : 
    1727          96 :   SyncNodeIds syncids(mesh);
    1728             :   Parallel::sync_node_data_by_element_id
    1729       90678 :     (mesh, mesh.elements_begin(), mesh.elements_end(),
    1730       30210 :      Parallel::SyncEverything(), Parallel::SyncEverything(), syncids);
    1731             : 
    1732             :   // At this point, with both ids and processor ids synced, we can
    1733             :   // finally check for topological consistency of node processor ids.
    1734             : #ifdef DEBUG
    1735          48 :   MeshTools::libmesh_assert_topology_consistent_procids<Node> (mesh);
    1736             : #endif
    1737       30258 : }
    1738             : 
    1739             : 
    1740             : 
    1741       33141 : void MeshCommunication::make_node_unique_ids_parallel_consistent (MeshBase & mesh)
    1742             : {
    1743             :   // Avoid unused variable warnings if unique ids aren't enabled.
    1744          86 :   libmesh_ignore(mesh);
    1745             : 
    1746             :   // This function must be run on all processors at once
    1747          86 :   libmesh_parallel_only(mesh.comm());
    1748             : 
    1749             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
    1750          86 :   LOG_SCOPE ("make_node_unique_ids_parallel_consistent()", "MeshCommunication");
    1751             : 
    1752          86 :   SyncUniqueIds<Node> syncuniqueids(mesh, &MeshBase::query_node_ptr);
    1753         172 :   Parallel::sync_dofobject_data_by_id(mesh.comm(),
    1754       66282 :                                       mesh.nodes_begin(),
    1755       33313 :                                       mesh.nodes_end(),
    1756             :                                       syncuniqueids);
    1757             : 
    1758             : #endif
    1759       33141 : }
    1760             : 
    1761             : 
    1762       22145 : void MeshCommunication::make_node_bcids_parallel_consistent (MeshBase & mesh)
    1763             : {
    1764             :   // Avoid unused variable warnings if unique ids aren't enabled.
    1765          38 :   libmesh_ignore(mesh);
    1766             : 
    1767             :   // This function must be run on all processors at once
    1768          38 :   libmesh_parallel_only(mesh.comm());
    1769             : 
    1770          38 :   LOG_SCOPE ("make_node_bcids_parallel_consistent()", "MeshCommunication");
    1771             : 
    1772          38 :   SyncBCIds<Node> syncbcids(mesh);
    1773          76 :   Parallel::sync_dofobject_data_by_id(mesh.comm(),
    1774       44290 :                                       mesh.nodes_begin(),
    1775       22221 :                                       mesh.nodes_end(),
    1776             :                                       syncbcids);
    1777       22145 : }
    1778             : 
    1779             : 
    1780             : 
    1781             : 
    1782             : 
    1783             : // ------------------------------------------------------------
    1784       22145 : void MeshCommunication::make_elems_parallel_consistent(MeshBase & mesh)
    1785             : {
    1786             :   // This function must be run on all processors at once
    1787          38 :   libmesh_parallel_only(mesh.comm());
    1788             : 
    1789          38 :   LOG_SCOPE ("make_elems_parallel_consistent()", "MeshCommunication");
    1790             : 
    1791          38 :   SyncIds syncids(mesh, &MeshBase::renumber_elem);
    1792             :   Parallel::sync_element_data_by_parent_id
    1793       44252 :     (mesh, mesh.active_elements_begin(),
    1794       22183 :      mesh.active_elements_end(), syncids);
    1795             : 
    1796             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
    1797          38 :   SyncUniqueIds<Elem> syncuniqueids(mesh, &MeshBase::query_elem_ptr);
    1798             :   Parallel::sync_dofobject_data_by_id
    1799       44252 :     (mesh.comm(), mesh.active_elements_begin(),
    1800       22221 :      mesh.active_elements_end(), syncuniqueids);
    1801             : #endif
    1802       22145 : }
    1803             : 
    1804             : 
    1805             : 
    1806             : // ------------------------------------------------------------
    1807             : #ifdef LIBMESH_ENABLE_AMR
    1808        2560 : void MeshCommunication::make_p_levels_parallel_consistent(MeshBase & mesh)
    1809             : {
    1810             :   // This function must be run on all processors at once
    1811           0 :   libmesh_parallel_only(mesh.comm());
    1812             : 
    1813           0 :   LOG_SCOPE ("make_p_levels_parallel_consistent()", "MeshCommunication");
    1814             : 
    1815           0 :   SyncPLevels syncplevels(mesh);
    1816             :   Parallel::sync_dofobject_data_by_id
    1817        5120 :     (mesh.comm(), mesh.elements_begin(), mesh.elements_end(),
    1818             :      syncplevels);
    1819        2560 : }
    1820             : #endif // LIBMESH_ENABLE_AMR
    1821             : 
    1822             : 
    1823             : 
    1824             : // Functors for make_node_proc_ids_parallel_consistent
    1825             : namespace {
    1826             : 
    1827             : struct SyncProcIds
    1828             : {
    1829             :   typedef processor_id_type datum;
    1830             : 
    1831       30258 :   SyncProcIds(MeshBase & _mesh) : mesh(_mesh) {}
    1832             : 
    1833             :   MeshBase & mesh;
    1834             : 
    1835             :   // ------------------------------------------------------------
    1836      236654 :   void gather_data (const std::vector<dof_id_type> & ids,
    1837             :                     std::vector<datum> & data)
    1838             :   {
    1839             :     // Find the processor id of each requested node
    1840      236654 :     data.resize(ids.size());
    1841             : 
    1842    49509857 :     for (auto i : index_range(ids))
    1843             :       {
    1844             :         // Look for this point in the mesh
    1845    49273203 :         if (ids[i] != DofObject::invalid_id)
    1846             :           {
    1847    49273203 :             Node & node = mesh.node_ref(ids[i]);
    1848             : 
    1849             :             // Return the node's correct processor id,
    1850    49273203 :             data[i] = node.processor_id();
    1851             :           }
    1852             :         else
    1853           0 :           data[i] = DofObject::invalid_processor_id;
    1854             :       }
    1855      236654 :   }
    1856             : 
    1857             :   // ------------------------------------------------------------
    1858      236654 :   bool act_on_data (const std::vector<dof_id_type> & ids,
    1859             :                     const std::vector<datum> proc_ids)
    1860             :   {
    1861          86 :     bool data_changed = false;
    1862             : 
    1863             :     // Set the ghost node processor ids we've now been informed of
    1864    49509857 :     for (auto i : index_range(ids))
    1865             :       {
    1866    49273203 :         Node & node = mesh.node_ref(ids[i]);
    1867             : 
    1868             :         // We may not have ids synched when this synchronization is done, so we
    1869             :         // *can't* use id to load-balance processor id properly; we have to use
    1870             :         // the old heuristic of choosing the smallest valid processor id.
    1871             :         //
    1872             :         // If someone tells us our node processor id is too low, then
    1873             :         // they're wrong.  If they tell us our node processor id is
    1874             :         // too high, then we're wrong.
    1875    49273203 :         if (node.processor_id() > proc_ids[i])
    1876             :           {
    1877           0 :             data_changed = true;
    1878       80126 :             node.processor_id() = proc_ids[i];
    1879             :           }
    1880             :       }
    1881             : 
    1882      236654 :     return data_changed;
    1883             :   }
    1884             : };
    1885             : 
    1886             : 
    1887             : struct ElemNodesMaybeNew
    1888             : {
    1889          38 :   ElemNodesMaybeNew() {}
    1890             : 
    1891    16740018 :   bool operator() (const Elem * elem) const
    1892             :   {
    1893             :     // If this element was just refined then it may have new nodes we
    1894             :     // need to work on
    1895             : #ifdef LIBMESH_ENABLE_AMR
    1896    16740018 :     if (elem->refinement_flag() == Elem::JUST_REFINED)
    1897        7896 :       return true;
    1898             : #endif
    1899             : 
    1900             :     // If this element has remote_elem neighbors then there may have
    1901             :     // been refinement of those neighbors that affect its nodes'
    1902             :     // processor_id()
    1903    13926636 :     for (auto neigh : elem->neighbor_ptr_range())
    1904    11589570 :       if (neigh == remote_elem)
    1905      880054 :         return true;
    1906     2337066 :     return false;
    1907             :   }
    1908             : };
    1909             : 
    1910             : 
    1911       22107 : struct NodeWasNew
    1912             : {
    1913       22145 :   NodeWasNew(const MeshBase & mesh)
    1914       22145 :   {
    1915    17142230 :     for (const auto & node : mesh.node_ptr_range())
    1916     8561335 :       if (node->processor_id() == DofObject::invalid_processor_id)
    1917       32547 :         was_new.insert(node);
    1918       22145 :   }
    1919             : 
    1920    93800260 :   bool operator() (const Elem * elem, unsigned int local_node_num) const
    1921             :   {
    1922    93800260 :     if (was_new.count(elem->node_ptr(local_node_num)))
    1923    60794062 :       return true;
    1924        9602 :     return false;
    1925             :   }
    1926             : 
    1927             :   std::unordered_set<const Node *> was_new;
    1928             : };
    1929             : 
    1930             : }
    1931             : 
    1932             : 
    1933             : 
    1934             : // ------------------------------------------------------------
    1935        8113 : void MeshCommunication::make_node_proc_ids_parallel_consistent(MeshBase & mesh)
    1936             : {
    1937          10 :   LOG_SCOPE ("make_node_proc_ids_parallel_consistent()", "MeshCommunication");
    1938             : 
    1939             :   // This function must be run on all processors at once
    1940          10 :   libmesh_parallel_only(mesh.comm());
    1941             : 
    1942             :   // When this function is called, each section of a parallelized mesh
    1943             :   // should be in the following state:
    1944             :   //
    1945             :   // All nodes should have the exact same physical location on every
    1946             :   // processor where they exist.
    1947             :   //
    1948             :   // Local nodes should have unique authoritative ids,
    1949             :   // and processor ids consistent with all processors which own
    1950             :   // an element touching them.
    1951             :   //
    1952             :   // Ghost nodes touching local elements should have processor ids
    1953             :   // consistent with all processors which own an element touching
    1954             :   // them.
    1955          10 :   SyncProcIds sync(mesh);
    1956             :   Parallel::sync_node_data_by_element_id
    1957       24319 :     (mesh, mesh.elements_begin(), mesh.elements_end(),
    1958        8113 :      Parallel::SyncEverything(), Parallel::SyncEverything(), sync);
    1959        8113 : }
    1960             : 
    1961             : 
    1962             : 
    1963             : // ------------------------------------------------------------
    1964       22145 : void MeshCommunication::make_new_node_proc_ids_parallel_consistent(MeshBase & mesh)
    1965             : {
    1966          76 :   LOG_SCOPE ("make_new_node_proc_ids_parallel_consistent()", "MeshCommunication");
    1967             : 
    1968             :   // This function must be run on all processors at once
    1969          38 :   libmesh_parallel_only(mesh.comm());
    1970             : 
    1971             :   // When this function is called, each section of a parallelized mesh
    1972             :   // should be in the following state:
    1973             :   //
    1974             :   // Local nodes should have unique authoritative ids,
    1975             :   // and new nodes should be unpartitioned.
    1976             :   //
    1977             :   // New ghost nodes touching local elements should be unpartitioned.
    1978             : 
    1979             :   // We may not have consistent processor ids for new nodes (because a
    1980             :   // node may be old and partitioned on one processor but new and
    1981             :   // unpartitioned on another) when we start
    1982             : #ifdef DEBUG
    1983          38 :   MeshTools::libmesh_assert_parallel_consistent_procids<Node>(mesh);
    1984             :   // MeshTools::libmesh_assert_parallel_consistent_new_node_procids(mesh);
    1985             : #endif
    1986             : 
    1987             :   // We have two kinds of new nodes.  *NEW* nodes are unpartitioned on
    1988             :   // all processors: we need to use a id-independent (i.e. dumb)
    1989             :   // heuristic to partition them.  But "new" nodes are newly created
    1990             :   // on some processors (when ghost elements are refined) yet
    1991             :   // correspond to existing nodes on other processors: we need to use
    1992             :   // the existing processor id for them.
    1993             :   //
    1994             :   // A node which is "new" on one processor will be associated with at
    1995             :   // least one ghost element, and we can just query that ghost
    1996             :   // element's owner to find out the correct processor id.
    1997             : 
    1998             :   auto node_unpartitioned =
    1999       24034 :     [](const Elem * elem, unsigned int local_node_num)
    2000       24034 :     { return elem->node_ref(local_node_num).processor_id() ==
    2001       24034 :         DofObject::invalid_processor_id; };
    2002             : 
    2003          38 :   SyncProcIds sync(mesh);
    2004             : 
    2005             :   sync_node_data_by_element_id_once
    2006       66359 :     (mesh, mesh.not_local_elements_begin(),
    2007       22183 :      mesh.not_local_elements_end(), Parallel::SyncEverything(),
    2008             :      node_unpartitioned, sync);
    2009             : 
    2010             :   // Nodes should now be unpartitioned iff they are truly new; those
    2011             :   // are the *only* nodes we will touch.
    2012             : #ifdef DEBUG
    2013          38 :   MeshTools::libmesh_assert_parallel_consistent_new_node_procids(mesh);
    2014             : #endif
    2015             : 
    2016       22183 :   NodeWasNew node_was_new(mesh);
    2017             : 
    2018             :   // Set the lowest processor id we can on truly new nodes
    2019     9419710 :   for (auto & elem : mesh.element_ptr_range())
    2020    43950696 :     for (auto & node : elem->node_ref_range())
    2021    39251931 :       if (node_was_new.was_new.count(&node))
    2022             :         {
    2023       18292 :           processor_id_type & pid = node.processor_id();
    2024    29155819 :           pid = std::min(pid, elem->processor_id());
    2025       22069 :         }
    2026             : 
    2027             :   // Then finally see if other processors have a lower option
    2028             :   Parallel::sync_node_data_by_element_id
    2029       66359 :     (mesh, mesh.elements_begin(), mesh.elements_end(),
    2030       22107 :      ElemNodesMaybeNew(), node_was_new, sync);
    2031             : 
    2032             :   // We should have consistent processor ids when we're done.
    2033             : #ifdef DEBUG
    2034          38 :   MeshTools::libmesh_assert_parallel_consistent_procids<Node>(mesh);
    2035          38 :   MeshTools::libmesh_assert_parallel_consistent_new_node_procids(mesh);
    2036             : #endif
    2037       22145 : }
    2038             : 
    2039             : 
    2040             : 
    2041             : // ------------------------------------------------------------
    2042        8033 : void MeshCommunication::make_nodes_parallel_consistent (MeshBase & mesh)
    2043             : {
    2044             :   // This function must be run on all processors at once
    2045          10 :   libmesh_parallel_only(mesh.comm());
    2046             : 
    2047             :   // When this function is called, each section of a parallelized mesh
    2048             :   // should be in the following state:
    2049             :   //
    2050             :   // Element ids and locations should be consistent on every processor
    2051             :   // where they exist.
    2052             :   //
    2053             :   // All nodes should have the exact same physical location on every
    2054             :   // processor where they exist.
    2055             :   //
    2056             :   // Local nodes should have unique authoritative ids,
    2057             :   // and processor ids consistent with all processors which own
    2058             :   // an element touching them.
    2059             :   //
    2060             :   // Ghost nodes touching local elements should have processor ids
    2061             :   // consistent with all processors which own an element touching
    2062             :   // them.
    2063             :   //
    2064             :   // Ghost nodes should have ids which are either already correct
    2065             :   // or which are in the "unpartitioned" id space.
    2066             : 
    2067             :   // First, let's sync up processor ids.  Some of these processor ids
    2068             :   // may be "wrong" from coarsening, but they're right in the sense
    2069             :   // that they'll tell us who has the authoritative dofobject ids for
    2070             :   // each node.
    2071             : 
    2072        8033 :   this->make_node_proc_ids_parallel_consistent(mesh);
    2073             : 
    2074             :   // Second, sync up dofobject ids.
    2075        8033 :   this->make_node_ids_parallel_consistent(mesh);
    2076             : 
    2077             :   // Third, sync up dofobject unique_ids if applicable.
    2078        8033 :   this->make_node_unique_ids_parallel_consistent(mesh);
    2079             : 
    2080             :   // Finally, correct the processor ids to make DofMap happy
    2081        8033 :   MeshTools::correct_node_proc_ids(mesh);
    2082        8033 : }
    2083             : 
    2084             : 
    2085             : 
    2086             : // ------------------------------------------------------------
    2087       22145 : void MeshCommunication::make_new_nodes_parallel_consistent (MeshBase & mesh)
    2088             : {
    2089             :   // This function must be run on all processors at once
    2090          38 :   libmesh_parallel_only(mesh.comm());
    2091             : 
    2092             :   // When this function is called, each section of a parallelized mesh
    2093             :   // should be in the following state:
    2094             :   //
    2095             :   // All nodes should have the exact same physical location on every
    2096             :   // processor where they exist.
    2097             :   //
    2098             :   // Local nodes should have unique authoritative ids,
    2099             :   // and new nodes should be unpartitioned.
    2100             :   //
    2101             :   // New ghost nodes touching local elements should be unpartitioned.
    2102             :   //
    2103             :   // New ghost nodes should have ids which are either already correct
    2104             :   // or which are in the "unpartitioned" id space.
    2105             :   //
    2106             :   // Non-new nodes should have correct ids and processor ids already.
    2107             : 
    2108             :   // First, let's sync up new nodes' processor ids.
    2109             : 
    2110       22145 :   this->make_new_node_proc_ids_parallel_consistent(mesh);
    2111             : 
    2112             :   // Second, sync up dofobject ids.
    2113       22145 :   this->make_node_ids_parallel_consistent(mesh);
    2114             : 
    2115             :   // Third, sync up dofobject unique_ids if applicable.
    2116       22145 :   this->make_node_unique_ids_parallel_consistent(mesh);
    2117             : 
    2118             :   // Fourth, sync up any nodal boundary conditions
    2119       22145 :   this->make_node_bcids_parallel_consistent(mesh);
    2120             : 
    2121             :   // Finally, correct the processor ids to make DofMap happy
    2122       22145 :   MeshTools::correct_node_proc_ids(mesh);
    2123       22145 : }
    2124             : 
    2125             : 
    2126             : 
    2127             : // ------------------------------------------------------------
    2128             : void
    2129      399980 : MeshCommunication::delete_remote_elements (DistributedMesh & mesh,
    2130             :                                            const std::set<Elem *> & extra_ghost_elem_ids) const
    2131             : {
    2132             :   // The mesh should know it's about to be parallelized
    2133         382 :   libmesh_assert (!mesh.is_serial());
    2134             : 
    2135         764 :   LOG_SCOPE("delete_remote_elements()", "MeshCommunication");
    2136             : 
    2137             : #ifdef DEBUG
    2138             :   // We expect maximum ids to be in sync so we can use them to size
    2139             :   // vectors
    2140         382 :   libmesh_assert(mesh.comm().verify(mesh.max_node_id()));
    2141         382 :   libmesh_assert(mesh.comm().verify(mesh.max_elem_id()));
    2142         382 :   const dof_id_type par_max_node_id = mesh.parallel_max_node_id();
    2143         382 :   const dof_id_type par_max_elem_id = mesh.parallel_max_elem_id();
    2144         382 :   libmesh_assert_equal_to (par_max_node_id, mesh.max_node_id());
    2145         382 :   libmesh_assert_equal_to (par_max_elem_id, mesh.max_elem_id());
    2146         382 :   const dof_id_type n_constraint_rows = mesh.n_constraint_rows();
    2147             : #endif
    2148             : 
    2149         764 :   connected_elem_set_type elements_to_keep;
    2150             : 
    2151             :   // Don't delete elements that we were explicitly told not to
    2152      399980 :   for (const auto & elem : extra_ghost_elem_ids)
    2153             :     {
    2154           0 :       std::vector<const Elem *> active_family;
    2155             : #ifdef LIBMESH_ENABLE_AMR
    2156           0 :       if (!elem->subactive())
    2157           0 :         elem->active_family_tree(active_family);
    2158             :       else
    2159             : #endif
    2160           0 :         active_family.push_back(elem);
    2161             : 
    2162           0 :       for (const auto & f : active_family)
    2163           0 :         elements_to_keep.insert(f);
    2164             :     }
    2165             : 
    2166             :   // See which elements we still need to keep ghosted, given that
    2167             :   // we're keeping local and unpartitioned elements.
    2168             :   query_ghosting_functors
    2169      401508 :     (mesh, mesh.processor_id(),
    2170      800342 :      mesh.active_pid_elements_begin(mesh.processor_id()),
    2171      400744 :      mesh.active_pid_elements_end(mesh.processor_id()),
    2172             :      elements_to_keep);
    2173             :   query_ghosting_functors
    2174      401126 :     (mesh, DofObject::invalid_processor_id,
    2175      799960 :      mesh.active_pid_elements_begin(DofObject::invalid_processor_id),
    2176      799578 :      mesh.active_pid_elements_end(DofObject::invalid_processor_id),
    2177             :      elements_to_keep);
    2178             : 
    2179             :   // The inactive elements we need to send should have their
    2180             :   // immediate children present.
    2181     1199558 :   connect_children(mesh, mesh.pid_elements_begin(mesh.processor_id()),
    2182      400744 :                    mesh.pid_elements_end(mesh.processor_id()),
    2183             :                    elements_to_keep);
    2184      401126 :   connect_children(mesh,
    2185      799960 :                    mesh.pid_elements_begin(DofObject::invalid_processor_id),
    2186      799960 :                    mesh.pid_elements_end(DofObject::invalid_processor_id),
    2187             :                    elements_to_keep);
    2188             : 
    2189             :   // And see which elements and nodes they depend on
    2190         764 :   connected_node_set_type connected_nodes;
    2191      399980 :   connect_element_dependencies(mesh, elements_to_keep, connected_nodes);
    2192             : 
    2193             :   // Delete all the elements we have no reason to save,
    2194             :   // starting with the most refined so that the mesh
    2195             :   // is valid at all intermediate steps
    2196      399980 :   unsigned int n_levels = MeshTools::n_levels(mesh);
    2197             : 
    2198      913877 :   for (int l = n_levels - 1; l >= 0; --l)
    2199     1046434 :     for (auto & elem : as_range(mesh.level_elements_begin(l),
    2200   100475114 :                                 mesh.level_elements_end(l)))
    2201             :       {
    2202       19116 :         libmesh_assert (elem);
    2203             :         // Make sure we don't leave any invalid pointers
    2204       55593 :         const bool keep_me = elements_to_keep.count(elem);
    2205             : 
    2206       19116 :         if (!keep_me)
    2207    35844140 :           elem->make_links_to_me_remote();
    2208             : 
    2209             :         // delete_elem doesn't currently invalidate element
    2210             :         // iterators... that had better not change
    2211       38232 :         if (!keep_me)
    2212    35844140 :           mesh.delete_elem(elem);
    2213      512945 :       }
    2214             : 
    2215             :   // Delete all the nodes we have no reason to save
    2216   165485436 :   for (auto & node : mesh.node_ptr_range())
    2217             :     {
    2218       51556 :       libmesh_assert(node);
    2219      151615 :       if (!connected_nodes.count(node))
    2220             :         {
    2221        3053 :           libmesh_assert_not_equal_to(node->processor_id(),
    2222             :                                       mesh.processor_id());
    2223    49936854 :           mesh.delete_node(node);
    2224             :         }
    2225      399216 :     }
    2226             : 
    2227             :   // If we had a point locator, it's invalid now that some of the
    2228             :   // elements it pointed to have been deleted.
    2229      399980 :   mesh.clear_point_locator();
    2230             : 
    2231             :   // We now have all remote elements and nodes deleted; our ghosting
    2232             :   // functors should be ready to delete any now-redundant cached data
    2233             :   // they use too.
    2234      932984 :   for (auto & gf : as_range(mesh.ghosting_functors_begin(), mesh.ghosting_functors_end()))
    2235      533004 :     gf->delete_remote_elements();
    2236             : 
    2237             : #ifdef DEBUG
    2238         382 :   const dof_id_type n_new_constraint_rows = mesh.n_constraint_rows();
    2239         382 :   libmesh_assert_equal_to(n_constraint_rows, n_new_constraint_rows);
    2240             : 
    2241         382 :   MeshTools::libmesh_assert_valid_refinement_tree(mesh);
    2242         382 :   MeshTools::libmesh_assert_valid_constraint_rows(mesh);
    2243             : #endif
    2244      399980 : }
    2245             : 
    2246             : } // namespace libMesh

Generated by: LCOV version 1.14