LCOV - code coverage report
Current view: top level - src/mesh - distributed_mesh.C (source / functions) Hit Total Coverage
Test: libMesh/libmesh: #4533 (621b1e) with base 036428 Lines: 756 806 93.8 %
Date: 2026-08-28 14:39:54 Functions: 91 96 94.8 %
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/distributed_mesh.h"
      22             : 
      23             : // libMesh includes
      24             : #include "libmesh/boundary_info.h"
      25             : #include "libmesh/elem.h"
      26             : #include "libmesh/libmesh_logging.h"
      27             : #include "libmesh/mesh_communication.h"
      28             : #include "libmesh/mesh_tools.h"
      29             : #include "libmesh/partitioner.h"
      30             : #include "libmesh/string_to_enum.h"
      31             : 
      32             : // TIMPI includes
      33             : #include "timpi/parallel_implementation.h"
      34             : #include "timpi/parallel_sync.h"
      35             : 
      36             : 
      37             : namespace libMesh
      38             : {
      39             : 
      40             : // ------------------------------------------------------------
      41             : // DistributedMesh class member functions
      42      278256 : DistributedMesh::DistributedMesh (const Parallel::Communicator & comm_in,
      43      278256 :                                   unsigned char d) :
      44      277760 :   UnstructuredMesh (comm_in,d), _is_serial(true),
      45      277760 :   _is_serial_on_proc_0(true),
      46      277760 :   _deleted_coarse_elements(false),
      47      277760 :   _n_nodes(0), _n_elem(0), _max_node_id(0), _max_elem_id(0),
      48      278504 :   _next_free_local_node_id(this->processor_id()),
      49      278256 :   _next_free_local_elem_id(this->processor_id()),
      50      278256 :   _next_free_unpartitioned_node_id(this->n_processors()),
      51      278256 :   _next_free_unpartitioned_elem_id(this->n_processors())
      52             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
      53      278256 :   , _next_unpartitioned_unique_id(this->n_processors())
      54             : #endif
      55             : {
      56             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
      57      278256 :   _next_unique_id = this->processor_id();
      58             : #endif
      59             : 
      60      278504 :   const std::string default_partitioner = "parmetis";
      61             :   const std::string my_partitioner =
      62             :     libMesh::command_line_value("--default-partitioner",
      63      556512 :                                 default_partitioner);
      64             :   _partitioner = Partitioner::build
      65      556264 :     (Utility::string_to_enum<PartitionerType>(my_partitioner));
      66      278256 : }
      67             : 
      68         270 : DistributedMesh & DistributedMesh::operator= (DistributedMesh && other_mesh)
      69             : {
      70           4 :   LOG_SCOPE("operator=(&&)", "DistributedMesh");
      71             : 
      72             :   // Move assign as an UnstructuredMesh.
      73           4 :   this->UnstructuredMesh::operator=(std::move(other_mesh));
      74             : 
      75             :   // Nodes and elements belong to DistributedMesh and have to be
      76             :   // moved before we can move arbitrary GhostingFunctor, Partitioner,
      77             :   // etc. subclasses.
      78         270 :   this->move_nodes_and_elements(std::move(other_mesh));
      79             : 
      80             :   // But move_nodes_and_elems misses (or guesses about) some of our
      81             :   // subclass values, and we want more precision than a guess.
      82         270 :   _deleted_coarse_elements = other_mesh._deleted_coarse_elements;
      83           4 :   _extra_ghost_elems = std::move(other_mesh._extra_ghost_elems);
      84             : 
      85             :   // Handle remaining MeshBase moves.
      86         270 :   this->post_dofobject_moves(std::move(other_mesh));
      87             : 
      88         274 :   return *this;
      89             : }
      90             : 
      91         270 : MeshBase & DistributedMesh::assign(MeshBase && other_mesh)
      92             : {
      93         270 :   *this = std::move(cast_ref<DistributedMesh&>(other_mesh));
      94             : 
      95         270 :   return *this;
      96             : }
      97             : 
      98       12346 : bool DistributedMesh::subclass_locally_equals(const MeshBase & other_mesh_base) const
      99             : {
     100          28 :   const DistributedMesh * dist_mesh_ptr =
     101       12346 :     dynamic_cast<const DistributedMesh *>(&other_mesh_base);
     102       12346 :   if (!dist_mesh_ptr)
     103           0 :     return false;
     104          28 :   const DistributedMesh & other_mesh = *dist_mesh_ptr;
     105             : 
     106          84 :   if (_is_serial != other_mesh._is_serial ||
     107       12328 :       _is_serial_on_proc_0 != other_mesh._is_serial_on_proc_0 ||
     108       12346 :       _deleted_coarse_elements != other_mesh._deleted_coarse_elements ||
     109       12328 :       _n_nodes != other_mesh._n_nodes ||
     110       12346 :       _n_elem != other_mesh._n_elem ||
     111       12346 :       _max_node_id != other_mesh._max_node_id ||
     112       37038 :       _max_elem_id != other_mesh._max_elem_id ||
     113             :       // We expect these things to change in a prepare_for_use();
     114             :       // they're conceptually "mutable"...
     115             : /*
     116             :       _next_free_local_node_id != other_mesh._next_free_local_node_id ||
     117             :       _next_free_local_elem_id != other_mesh._next_free_local_elem_id ||
     118             :       _next_free_unpartitioned_node_id != other_mesh._next_free_unpartitioned_node_id ||
     119             :       _next_free_unpartitioned_elem_id != other_mesh._next_free_unpartitioned_elem_id ||
     120             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
     121             :       _next_unpartitioned_unique_id != other_mesh._next_unpartitioned_unique_id ||
     122             : #endif
     123             : */
     124       12346 :       !this->nodes_and_elements_equal(other_mesh))
     125          63 :     return false;
     126             : 
     127       12309 :   if (_extra_ghost_elems.size() !=
     128          26 :       other_mesh._extra_ghost_elems.size())
     129           0 :     return false;
     130       12283 :   for (auto & elem : _extra_ghost_elems)
     131             :     {
     132           0 :       libmesh_assert(this->query_elem_ptr(elem->id()) == elem);
     133           0 :       const Elem * other_elem = other_mesh.query_elem_ptr(elem->id());
     134           0 :       if (!other_elem ||
     135           0 :           !other_mesh._extra_ghost_elems.count(const_cast<Elem *>(other_elem)))
     136           0 :         return false;
     137             :     }
     138             : 
     139          26 :   return true;
     140             : }
     141             : 
     142      320366 : DistributedMesh::~DistributedMesh ()
     143             : {
     144      298475 :   this->DistributedMesh::clear();  // Free nodes and elements
     145      320366 : }
     146             : 
     147             : 
     148             : // This might be specialized later, but right now it's just here to
     149             : // make sure the compiler doesn't give us a default (non-deep) copy
     150             : // constructor instead.
     151       17734 : DistributedMesh::DistributedMesh (const DistributedMesh & other_mesh) :
     152       17734 :   DistributedMesh(static_cast<const MeshBase &>(other_mesh))
     153             : {
     154       17734 :   _deleted_coarse_elements = other_mesh._deleted_coarse_elements;
     155             : 
     156             :   // Need to copy extra_ghost_elems
     157       17734 :   for (auto & elem : other_mesh._extra_ghost_elems)
     158           0 :     _extra_ghost_elems.insert(this->elem_ptr(elem->id()));
     159       17734 : }
     160             : 
     161             : 
     162             : 
     163       20219 : DistributedMesh::DistributedMesh (const MeshBase & other_mesh) :
     164       20219 :   UnstructuredMesh (other_mesh), _is_serial(other_mesh.is_serial()),
     165       20309 :   _is_serial_on_proc_0(other_mesh.is_serial_on_zero()),
     166       20039 :   _deleted_coarse_elements(true), // better safe than sorry...
     167       20039 :   _n_nodes(0), _n_elem(0), _max_node_id(0), _max_elem_id(0), // recomputed below
     168       20309 :   _next_free_local_node_id(this->processor_id()),
     169       20219 :   _next_free_local_elem_id(this->processor_id()),
     170       20219 :   _next_free_unpartitioned_node_id(this->n_processors()),
     171       40348 :   _next_free_unpartitioned_elem_id(this->n_processors())
     172             : {
     173             :   // Just copy, skipping preparation
     174       20219 :   this->copy_nodes_and_elements(other_mesh, true, 0, 0, 0, nullptr, true);
     175             : 
     176         180 :   this->allow_find_neighbors(other_mesh.allow_find_neighbors());
     177         180 :   this->allow_detect_interior_parents(other_mesh.allow_detect_interior_parents());
     178         180 :   this->allow_renumbering(other_mesh.allow_renumbering());
     179         180 :   this->allow_remote_element_removal(other_mesh.allow_remote_element_removal());
     180         180 :   this->skip_partitioning(other_mesh.skip_partitioning());
     181             : 
     182       20219 :   this->copy_constraint_rows(other_mesh);
     183             : 
     184          90 :   auto & this_boundary_info = this->get_boundary_info();
     185          90 :   const auto & other_boundary_info = other_mesh.get_boundary_info();
     186             : 
     187       20219 :   this_boundary_info = other_boundary_info;
     188             : 
     189          90 :   this->set_subdomain_name_map() = other_mesh.get_subdomain_name_map();
     190             : 
     191             :   // add_node()/add_elem() only increment _n_nodes/_n_elem for
     192             :   // nodes/elements they consider locally owned (or unpartitioned), so after
     193             :   // copying only the objects visible to this processor, those counts
     194             :   // reflect an incomplete local view rather than other_mesh's totals,
     195             :   // and need to be copied afresh.
     196       20219 :   _n_nodes = other_mesh.n_nodes();
     197       20219 :   _n_elem = other_mesh.n_elem();
     198       20219 :   _max_node_id = other_mesh.max_node_id();
     199       20219 :   _max_elem_id = other_mesh.max_elem_id();
     200             : 
     201             :   // If other_mesh is actually a DistributedMesh, we can just copy its raw
     202             :   // counters directly, mirroring other_mesh's own bookkeeping exactly
     203       20219 :   if (const DistributedMesh * other_dist_mesh = dynamic_cast<const DistributedMesh *>(&other_mesh))
     204             :     {
     205       19782 :       _next_free_local_node_id = other_dist_mesh->_next_free_local_node_id;
     206       19782 :       _next_free_local_elem_id = other_dist_mesh->_next_free_local_elem_id;
     207       19782 :       _next_free_unpartitioned_node_id = other_dist_mesh->_next_free_unpartitioned_node_id;
     208       19782 :       _next_free_unpartitioned_elem_id = other_dist_mesh->_next_free_unpartitioned_elem_id;
     209             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
     210       19782 :       _next_unique_id = other_dist_mesh->_next_unique_id;
     211       19782 :       _next_unpartitioned_unique_id = other_dist_mesh->_next_unpartitioned_unique_id;
     212             : #endif
     213             :     }
     214             :   else
     215             :     {
     216             :       // For any other MeshBase subclass (e.g. ReplicatedMesh) we have no
     217             :       // raw counterpart fields to copy, so derive the free-id-range
     218             :       // counters from _max_elem_id/_max_node_id the same way
     219             :       // update_parallel_id_counts() does via the set_next_ids() method. For
     220             :       // the unique id counters we copy other_mesh's own local next_unique_id()
     221             :       // and derive the next available unique ids
     222             :       // (partitioned and unpartitioned) via set_next_unique_ids().
     223         437 :       this->set_next_ids();
     224             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
     225          70 :       libmesh_assert(other_mesh.comm().verify(other_mesh.next_unique_id()));
     226         437 :       this->set_next_unique_ids(other_mesh.next_unique_id());
     227             : #endif
     228             :     }
     229             : 
     230             :   // Copy other_mesh's actual preparation state, including whatever it
     231             :   // reports for has_synched_id_counts: the counts above are a faithful copy
     232             :   // of other_mesh's own (possibly not-yet-synced) counts, not a freshly
     233             :   // verified computation, so our synced-ness should match other_mesh's.
     234       20219 :   this->_preparation = other_mesh.preparation();
     235       20219 : }
     236             : 
     237         270 : void DistributedMesh::move_nodes_and_elements(MeshBase && other_meshbase)
     238             : {
     239           4 :   DistributedMesh & other_mesh = cast_ref<DistributedMesh&>(other_meshbase);
     240             : 
     241           4 :   this->_nodes = std::move(other_mesh._nodes);
     242         270 :   this->_n_nodes = other_mesh.n_nodes();
     243             : 
     244           4 :   this->_elements = std::move(other_mesh._elements);
     245         270 :   this->_n_elem = other_mesh.n_elem();
     246             : 
     247         270 :   _is_serial = other_mesh.is_serial();
     248         270 :   _is_serial_on_proc_0 = other_mesh.is_serial_on_zero();
     249         270 :   _deleted_coarse_elements = true; // Better safe than sorry
     250             : 
     251         270 :   _max_node_id = other_mesh.max_node_id();
     252         270 :   _max_elem_id = other_mesh.max_elem_id();
     253             : 
     254         270 :   _next_free_local_node_id = other_mesh._next_free_local_node_id;
     255         270 :   _next_free_local_elem_id = other_mesh._next_free_local_elem_id;
     256         270 :   _next_free_unpartitioned_node_id = other_mesh._next_free_unpartitioned_node_id;
     257         270 :   _next_free_unpartitioned_elem_id = other_mesh._next_free_unpartitioned_elem_id;
     258             : 
     259             :   #ifdef LIBMESH_ENABLE_UNIQUE_ID
     260         270 :   _next_unpartitioned_unique_id = other_mesh._next_unpartitioned_unique_id;
     261             :   #endif
     262         270 : }
     263             : 
     264     1916919 : void DistributedMesh::set_next_ids()
     265             : {
     266     1916919 :   _next_free_unpartitioned_elem_id =
     267     1918683 :     ((_max_elem_id-1) / (this->n_processors() + 1) + 1) *
     268     1916919 :     (this->n_processors() + 1) + this->n_processors();
     269     1916919 :   _next_free_local_elem_id =
     270     1916919 :     ((_max_elem_id + this->n_processors() - 1) / (this->n_processors() + 1) + 1) *
     271     1916919 :     (this->n_processors() + 1) + this->processor_id();
     272             : 
     273     1916919 :   _next_free_unpartitioned_node_id =
     274     1918683 :     ((_max_node_id-1) / (this->n_processors() + 1) + 1) *
     275     1916919 :     (this->n_processors() + 1) + this->n_processors();
     276     1916919 :   _next_free_local_node_id =
     277     1916919 :     ((_max_node_id + this->n_processors() - 1) / (this->n_processors() + 1) + 1) *
     278     1916919 :     (this->n_processors() + 1) + this->processor_id();
     279     1916919 : }
     280             : 
     281             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
     282     1916919 : void DistributedMesh::set_next_unique_ids(unique_id_type parallel_max_unique_id)
     283             : {
     284             :   // Unique ids are laid out in repeating groups of (n_processors()+1)
     285             :   // consecutive integers ("alignment" here means a value's position, i.e.
     286             :   // its residue mod (n_processors()+1), within one of these groups). In
     287             :   // every group, the first n_processors() slots (residues 0..n_processors()-1)
     288             :   // are each permanently earmarked for one processor's locally-owned
     289             :   // objects, and the last slot (residue n_processors()) is permanently
     290             :   // earmarked for unpartitioned objects.
     291             :   //
     292             :   // parallel_max_unique_id carries no guarantee of landing on any
     293             :   // particular residue, so rather than simply offsetting it by
     294             :   // processor_id()/n_processors(), we have to explicitly round up to the
     295             :   // start of the next full, entirely-unused group before adding this
     296             :   // processor's (or the unpartitioned pool's) fixed offset into that group.
     297             :   //
     298             :   // (parallel_max_unique_id - 1) / (n_processors()+1) + 1 is the standard
     299             :   // integer idiom for ceil(parallel_max_unique_id / (n_processors()+1)):
     300             :   // the number of complete groups needed to reach at least past the
     301             :   // current max id. Multiplying back by (n_processors()+1) gives the first
     302             :   // id of the next group that is guaranteed to be entirely unused; adding
     303             :   // n_processors(), the unpartitioned pool's fixed offset within a group,
     304             :   // lands on that pool's reserved slot in that group.
     305     1916919 :   _next_unpartitioned_unique_id =
     306     1918683 :       ((parallel_max_unique_id - 1) / (this->n_processors() + 1) + 1) *
     307     1916919 :           (this->n_processors() + 1) +
     308     1916919 :       this->n_processors();
     309             : 
     310             :   // Same idiom, but shifted by (n_processors()-1) before dividing so that
     311             :   // the rounding accounts for processor_id() possibly being less than the
     312             :   // residue the raw max id already occupies within its group; this can
     313             :   // land this processor's slot in the same group as the unpartitioned
     314             :   // pool's above, or push it into the following group, depending on where
     315             :   // the max id and this processor's offset happen to fall.
     316     1916919 :   _next_unique_id =
     317     1916919 :       ((parallel_max_unique_id + this->n_processors() - 1) / (this->n_processors() + 1) + 1) *
     318     1916919 :           (this->n_processors() + 1) +
     319     1916919 :       this->processor_id();
     320     1916919 : }
     321             : #endif
     322             : 
     323             : // We use cached values for these so they can be called
     324             : // from one processor without bothering the rest, but
     325             : // we may need to update those caches before doing a full
     326             : // renumbering
     327     1916482 : void DistributedMesh::update_parallel_id_counts()
     328             : {
     329             :   // This function must be run on all processors at once
     330        1694 :   parallel_object_only();
     331             : 
     332     1916482 :   _n_elem  = this->parallel_n_elem();
     333     1916482 :   _n_nodes = this->parallel_n_nodes();
     334     1916482 :   _max_node_id = this->parallel_max_node_id();
     335     1916482 :   _max_elem_id = this->parallel_max_elem_id();
     336             : 
     337     1916482 :   this->set_next_ids();
     338             : 
     339             :   // set_next_unique_ids() needs the true parallel max unique id (not just
     340             :   // this processor's possibly-stale cached _next_unique_id) since the whole
     341             :   // point of this function is to recompute counters that may have drifted
     342             :   // out of sync.
     343             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
     344     1916482 :   this->set_next_unique_ids(this->parallel_max_unique_id());
     345             : #endif
     346             : 
     347     1916482 :   this->_preparation.has_synched_id_counts = true;
     348     1916482 : }
     349             : 
     350             : 
     351             : // Or in debug mode we may want to test the uncached values without
     352             : // changing the cache
     353     1924207 : dof_id_type DistributedMesh::parallel_n_elem() const
     354             : {
     355             :   // This function must be run on all processors at once
     356        2542 :   parallel_object_only();
     357             : 
     358     1924207 :   dof_id_type n_local = this->n_local_elem();
     359     1924207 :   this->comm().sum(n_local);
     360     1924207 :   n_local += this->n_unpartitioned_elem();
     361     1924207 :   return n_local;
     362             : }
     363             : 
     364             : 
     365             : 
     366     1923478 : dof_id_type DistributedMesh::parallel_max_elem_id() const
     367             : {
     368             :   // This function must be run on all processors at once
     369        8690 :   parallel_object_only();
     370             : 
     371     1923478 :   dof_id_type max_local = 0;
     372             : 
     373             :   dofobject_container<Elem>::const_reverse_veclike_iterator
     374        8690 :     rit = _elements.rbegin();
     375             : 
     376             :   const dofobject_container<Elem>::const_reverse_veclike_iterator
     377        8690 :     rend = _elements.rend();
     378             : 
     379             :   // Look for the maximum element id.  Search backwards through
     380             :   // elements so we can break out early.  Beware of nullptr entries that
     381             :   // haven't yet been cleared from _elements.
     382    10556256 :   for (; rit != rend; ++rit)
     383             :     {
     384    10035125 :       const DofObject *d = *rit;
     385       19001 :       if (d)
     386             :         {
     387        8475 :           libmesh_assert(_elements[d->id()] == d);
     388     1402347 :           max_local = d->id() + 1;
     389     1402347 :           break;
     390             :         }
     391             :     }
     392             : 
     393     1923478 :   this->comm().max(max_local);
     394     1923478 :   return max_local;
     395             : }
     396             : 
     397             : 
     398             : 
     399             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
     400     1999910 : unique_id_type DistributedMesh::parallel_max_unique_id() const
     401             : {
     402             :   // This function must be run on all processors at once
     403        1796 :   parallel_object_only();
     404             : 
     405     3999820 :   unique_id_type max_local = std::max(_next_unique_id,
     406     2290298 :                                       _next_unpartitioned_unique_id);
     407     1999910 :   this->comm().max(max_local);
     408     1999910 :   return max_local;
     409             : }
     410             : 
     411             : 
     412             : 
     413       78327 : void DistributedMesh::set_next_unique_id(unique_id_type id)
     414             : {
     415         144 :   _next_unique_id = id;
     416       78327 :   _next_unpartitioned_unique_id =
     417       78471 :     ((_next_unique_id-1) / (this->n_processors() + 1) + 1) *
     418       78327 :     (this->n_processors() + 1) + this->n_processors();
     419       78327 :   _next_unique_id =
     420       78327 :     ((_next_unique_id + this->n_processors() - 1) / (this->n_processors() + 1) + 1) *
     421       78327 :     (this->n_processors() + 1) + this->processor_id();
     422       78327 : }
     423             : #endif
     424             : 
     425             : 
     426             : 
     427     1924655 : dof_id_type DistributedMesh::parallel_n_nodes() const
     428             : {
     429             :   // This function must be run on all processors at once
     430        2542 :   parallel_object_only();
     431             : 
     432     1924655 :   dof_id_type n_local = this->n_local_nodes();
     433     1924655 :   this->comm().sum(n_local);
     434     1924655 :   n_local += this->n_unpartitioned_nodes();
     435     1924655 :   return n_local;
     436             : }
     437             : 
     438             : 
     439             : 
     440     1921062 : dof_id_type DistributedMesh::parallel_max_node_id() const
     441             : {
     442             :   // This function must be run on all processors at once
     443        6274 :   parallel_object_only();
     444             : 
     445     1921062 :   dof_id_type max_local = 0;
     446             : 
     447             :   dofobject_container<Node>::const_reverse_veclike_iterator
     448        6274 :     rit = _nodes.rbegin();
     449             : 
     450             :   const dofobject_container<Node>::const_reverse_veclike_iterator
     451        6274 :     rend = _nodes.rend();
     452             : 
     453             :   // Look for the maximum node id.  Search backwards through
     454             :   // nodes so we can break out early.  Beware of nullptr entries that
     455             :   // haven't yet been cleared from _nodes
     456    38134626 :   for (; rit != rend; ++rit)
     457             :     {
     458    37613565 :       const DofObject *d = *rit;
     459       63385 :       if (d)
     460             :         {
     461        6129 :           libmesh_assert(_nodes[d->id()] == d);
     462     1400001 :           max_local = d->id() + 1;
     463     1400001 :           break;
     464             :         }
     465             :     }
     466             : 
     467     1921062 :   this->comm().max(max_local);
     468     1921062 :   return max_local;
     469             : }
     470             : 
     471             : 
     472             : 
     473    42416396 : const Point & DistributedMesh::point (const dof_id_type i) const
     474             : {
     475    42416396 :   return this->node_ref(i);
     476             : }
     477             : 
     478             : 
     479             : 
     480    43521785 : const Node * DistributedMesh::node_ptr (const dof_id_type i) const
     481             : {
     482      136653 :   libmesh_assert(_nodes[i]);
     483      136653 :   libmesh_assert_equal_to (_nodes[i]->id(), i);
     484             : 
     485    43521785 :   return _nodes[i];
     486             : }
     487             : 
     488             : 
     489             : 
     490             : 
     491   643652387 : Node * DistributedMesh::node_ptr (const dof_id_type i)
     492             : {
     493      489296 :   libmesh_assert(_nodes[i]);
     494      489296 :   libmesh_assert_equal_to (_nodes[i]->id(), i);
     495             : 
     496   643652387 :   return _nodes[i];
     497             : }
     498             : 
     499             : 
     500             : 
     501             : 
     502     3109134 : const Node * DistributedMesh::query_node_ptr (const dof_id_type i) const
     503             : {
     504     3109134 :   if (const auto it = _nodes.find(i);
     505      657411 :       it != _nodes.end())
     506             :     {
     507     2820622 :       const Node * n = *it;
     508      368899 :       libmesh_assert (!n || n->id() == i);
     509      368899 :       return n;
     510             :     }
     511             : 
     512      288512 :   return nullptr;
     513             : }
     514             : 
     515             : 
     516             : 
     517             : 
     518   367387736 : Node * DistributedMesh::query_node_ptr (const dof_id_type i)
     519             : {
     520   367387736 :   if (auto it = _nodes.find(i);
     521      159367 :       it != _nodes.end())
     522             :     {
     523   284598818 :       Node * n = *it;
     524      111970 :       libmesh_assert (!n || n->id() == i);
     525      111970 :       return n;
     526             :     }
     527             : 
     528       47397 :   return nullptr;
     529             : }
     530             : 
     531             : 
     532             : 
     533             : 
     534     3050216 : const Elem * DistributedMesh::elem_ptr (const dof_id_type i) const
     535             : {
     536       10087 :   libmesh_assert(_elements[i]);
     537       10087 :   libmesh_assert_equal_to (_elements[i]->id(), i);
     538             : 
     539     3050216 :   return _elements[i];
     540             : }
     541             : 
     542             : 
     543             : 
     544             : 
     545   286911794 : Elem * DistributedMesh::elem_ptr (const dof_id_type i)
     546             : {
     547      167221 :   libmesh_assert(_elements[i]);
     548      167221 :   libmesh_assert_equal_to (_elements[i]->id(), i);
     549             : 
     550   286911794 :   return _elements[i];
     551             : }
     552             : 
     553             : 
     554             : 
     555             : 
     556     1457373 : const Elem * DistributedMesh::query_elem_ptr (const dof_id_type i) const
     557             : {
     558     1457373 :   if (const auto it = _elements.find(i);
     559      618403 :       it != _elements.end())
     560             :     {
     561     1099794 :       const Elem * e = *it;
     562      269739 :       libmesh_assert (!e || e->id() == i);
     563      269739 :       return e;
     564             :     }
     565             : 
     566      348664 :   return nullptr;
     567             : }
     568             : 
     569             : 
     570             : 
     571             : 
     572   603663700 : Elem * DistributedMesh::query_elem_ptr (const dof_id_type i)
     573             : {
     574   603663700 :   if (auto it = _elements.find(i);
     575      194370 :       it != _elements.end())
     576             :     {
     577   518160090 :       Elem * e = *it;
     578      190690 :       libmesh_assert (!e || e->id() == i);
     579      190690 :       return e;
     580             :     }
     581             : 
     582        3680 :   return nullptr;
     583             : }
     584             : 
     585             : 
     586             : 
     587             : 
     588    44050320 : Elem * DistributedMesh::add_elem (Elem * e)
     589             : {
     590             :   // Don't try to add nullptrs!
     591       18945 :   libmesh_assert(e);
     592             : 
     593             :   // Trying to add an existing element is a no-op
     594    44050320 :   if (e->valid_id() && _elements[e->id()] == e)
     595           0 :     return e;
     596             : 
     597    44050320 :   const processor_id_type elem_procid = e->processor_id();
     598             : 
     599    44050320 :   if (!e->valid_id())
     600             :     {
     601             :       // We should only be creating new ids past the end of the range
     602             :       // of existing ids
     603        3568 :       libmesh_assert_greater_equal(_next_free_unpartitioned_elem_id,
     604             :                                    _max_elem_id);
     605        3568 :       libmesh_assert_greater_equal(_next_free_local_elem_id, _max_elem_id);
     606             : 
     607             :       // Use the unpartitioned ids for unpartitioned elems, and
     608             :       // temporarily for ghost elems
     609     3860185 :       dof_id_type * next_id = &_next_free_unpartitioned_elem_id;
     610     3863753 :       if (elem_procid == this->processor_id())
     611     1133684 :         next_id = &_next_free_local_elem_id;
     612     3860185 :       e->set_id (*next_id);
     613             :     }
     614             : 
     615             :   {
     616             :     // Advance next_ids up high enough that each is pointing to an
     617             :     // unused id and any subsequent increments will still point us
     618             :     // to unused ids
     619    88100640 :     _max_elem_id = std::max(_max_elem_id,
     620    44050320 :                             static_cast<dof_id_type>(e->id()+1));
     621             : 
     622    44050320 :     if (_next_free_unpartitioned_elem_id < _max_elem_id)
     623     5167248 :       _next_free_unpartitioned_elem_id =
     624     5167248 :         ((_max_elem_id-1) / (this->n_processors() + 1) + 1) *
     625     5167248 :         (this->n_processors() + 1) + this->n_processors();
     626    44050320 :     if (_next_free_local_elem_id < _max_elem_id)
     627     3463752 :       _next_free_local_elem_id =
     628     3470005 :         ((_max_elem_id + this->n_processors() - 1) / (this->n_processors() + 1) + 1) *
     629     3463752 :         (this->n_processors() + 1) + this->processor_id();
     630             : 
     631             : #ifndef NDEBUG
     632             :     // We need a const dofobject_container so we don't inadvertently create
     633             :     // nullptr entries when testing for non-nullptr ones
     634       18945 :     const dofobject_container<Elem> & const_elements = _elements;
     635             : #endif
     636       18945 :     libmesh_assert(!const_elements[_next_free_unpartitioned_elem_id]);
     637       18945 :     libmesh_assert(!const_elements[_next_free_local_elem_id]);
     638             :   }
     639             : 
     640             :   // Don't try to overwrite existing elems
     641       18945 :   libmesh_assert (!_elements[e->id()]);
     642             : 
     643    44050320 :   _elements[e->id()] = e;
     644             : 
     645             :   // We actually added a new element.  Some of our caches might still
     646             :   // be valid, but we should clear the ones which definitely are not.
     647    44050320 :   this->clear_point_locator();
     648    44050320 :   this->clear_stored_ranges();
     649             : 
     650             :   // Try to make the cached elem data more accurate
     651    44069265 :   if (elem_procid == this->processor_id() ||
     652             :       elem_procid == DofObject::invalid_processor_id)
     653    12914092 :     _n_elem++;
     654             : 
     655             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
     656    44050320 :   if (!e->valid_unique_id())
     657             :     {
     658    13510369 :       if (processor_id() == e->processor_id())
     659             :         {
     660     1133684 :           e->set_unique_id(_next_unique_id);
     661     1133684 :           _next_unique_id += this->n_processors() + 1;
     662             :         }
     663             :       else
     664             :         {
     665    12376685 :           e->set_unique_id(_next_unpartitioned_unique_id);
     666    12376685 :           _next_unpartitioned_unique_id += this->n_processors() + 1;
     667             :         }
     668             :     }
     669             :   else
     670             :     {
     671    30564328 :       _next_unique_id = std::max(_next_unique_id, e->unique_id()+1);
     672    30539951 :       _next_unique_id =
     673    30539951 :         ((_next_unique_id + this->n_processors() - 1) / (this->n_processors() + 1) + 1) *
     674    30539951 :         (this->n_processors() + 1) + this->processor_id();
     675             :     }
     676             : #endif
     677             : 
     678             :   // Unpartitioned elems should be added on every processor
     679             :   // And shouldn't be added in the same batch as ghost elems
     680             :   // But we might be just adding on processor 0 to
     681             :   // broadcast later
     682             :   // #ifdef DEBUG
     683             :   //   if (elem_procid == DofObject::invalid_processor_id)
     684             :   //     {
     685             :   //       dof_id_type elem_id = e->id();
     686             :   //       this->comm().max(elem_id);
     687             :   //       libmesh_assert_equal_to (elem_id, e->id());
     688             :   //     }
     689             :   // #endif
     690             : 
     691             :   // Make sure any new element is given space for any extra integers
     692             :   // we've requested
     693    44050320 :   e->add_extra_integers(_elem_integer_names.size(),
     694    44050320 :                         _elem_integer_default_values);
     695             : 
     696             :   // And set mapping type and data on any new element
     697       37890 :   e->set_mapping_type(this->default_mapping_type());
     698       37890 :   e->set_mapping_data(this->default_mapping_data());
     699             : 
     700    44050320 :   return e;
     701             : }
     702             : 
     703             : 
     704             : 
     705    14746574 : Elem * DistributedMesh::add_elem (std::unique_ptr<Elem> e)
     706             : {
     707             :   // The mesh now takes ownership of the Elem. Eventually the guts of
     708             :   // add_elem() will get moved to a private helper function, and
     709             :   // calling add_elem() directly will be deprecated.
     710    14746574 :   return add_elem(e.release());
     711             : }
     712             : 
     713             : 
     714             : 
     715     3351724 : Elem * DistributedMesh::insert_elem (Elem * e)
     716             : {
     717     3351724 :   if (_elements[e->id()])
     718     3351724 :     this->delete_elem(_elements[e->id()]);
     719             : 
     720             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
     721     3351724 :   if (!e->valid_unique_id())
     722             :     {
     723           0 :       if (processor_id() == e->processor_id())
     724             :         {
     725           0 :           e->set_unique_id(_next_unique_id);
     726           0 :           _next_unique_id += this->n_processors() + 1;
     727             :         }
     728             :       else
     729             :         {
     730           0 :           e->set_unique_id(_next_unpartitioned_unique_id);
     731           0 :           _next_unpartitioned_unique_id += this->n_processors() + 1;
     732             :         }
     733             :     }
     734             :   else
     735             :     {
     736     3351724 :       _next_unique_id = std::max(_next_unique_id, e->unique_id()+1);
     737     3351724 :       _next_unique_id =
     738     3355420 :         ((_next_unique_id + this->n_processors() - 1) / (this->n_processors() + 1) + 1) *
     739     3351724 :         (this->n_processors() + 1) + this->processor_id();
     740             :     }
     741             : #endif
     742             : 
     743             :   // Try to make the cached elem data more accurate
     744     3351724 :   processor_id_type elem_procid = e->processor_id();
     745     3355420 :   if (elem_procid == this->processor_id() ||
     746             :       elem_procid == DofObject::invalid_processor_id)
     747     3220856 :     _n_elem++;
     748             : 
     749     3351724 :   _elements[e->id()] = e;
     750             : 
     751             :   // We actually added a new element.  Some of our caches might still
     752             :   // be valid, but we should clear the ones which definitely are not.
     753     3351724 :   this->clear_point_locator();
     754     3351724 :   this->clear_stored_ranges();
     755             : 
     756             :   // Make sure any new element is given space for any extra integers
     757             :   // we've requested
     758     3351724 :   e->add_extra_integers(_elem_integer_names.size(),
     759     3351724 :                         _elem_integer_default_values);
     760             : 
     761             :   // And set mapping type and data on any new element
     762        7392 :   e->set_mapping_type(this->default_mapping_type());
     763        7392 :   e->set_mapping_data(this->default_mapping_data());
     764             : 
     765     3351724 :   return e;
     766             : }
     767             : 
     768     3351724 : Elem * DistributedMesh::insert_elem (std::unique_ptr<Elem> e)
     769             : {
     770             :   // The mesh now takes ownership of the Elem. Eventually the guts of
     771             :   // insert_elem(Elem*) will get moved to a private helper function, and
     772             :   // calling insert_elem(Elem*) directly will be deprecated.
     773     3351724 :   return insert_elem(e.release());
     774             : }
     775             : 
     776             : 
     777    40097977 : void DistributedMesh::delete_elem(Elem * e)
     778             : {
     779        7610 :   libmesh_assert (e);
     780             : 
     781             :   // Try to make the cached elem data more accurate
     782    40097977 :   _n_elem--;
     783             : 
     784             :   // Was this a coarse element, not just a coarsening where we still
     785             :   // have some ancestor structure?  Was it a *local* element, that we
     786             :   // might have been depending on as an owner of local nodes?  We'll
     787             :   // have to be more careful with our nodes in contract() later; no
     788             :   // telling if we just locally orphaned a node that should be
     789             :   // globally retained.
     790    40107407 :   if (e->processor_id() == this->processor_id() &&
     791        3640 :       !e->parent())
     792       80793 :     _deleted_coarse_elements = true;
     793             : 
     794             :   // Delete the element from the BoundaryInfo object
     795    40097977 :   this->get_boundary_info().remove(e);
     796             : 
     797             :   // But not yet from the container; we might invalidate
     798             :   // an iterator that way!
     799             : 
     800             :   //_elements.erase(e->id());
     801             : 
     802             :   // Instead, we set it to nullptr for now
     803             : 
     804    40097977 :   _elements[e->id()] = nullptr;
     805             : 
     806             :   // delete the element
     807    40097977 :   delete e;
     808             : 
     809             :   // Some of our caches might still be valid, but we should clear the
     810             :   // ones which definitely are not.
     811    40097977 :   this->clear_point_locator();
     812    40097977 :   this->clear_stored_ranges();
     813    40097977 : }
     814             : 
     815             : 
     816             : 
     817     3208100 : void DistributedMesh::renumber_elem(const dof_id_type old_id,
     818             :                                     const dof_id_type new_id)
     819             : {
     820             :   // This could be a no-op
     821     3208100 :   if (old_id == new_id)
     822           0 :     return;
     823             : 
     824     3208100 :   Elem * el = _elements[old_id];
     825        1160 :   libmesh_assert (el);
     826        1160 :   libmesh_assert_equal_to (el->id(), old_id);
     827             : 
     828     3208100 :   el->set_id(new_id);
     829        1160 :   libmesh_assert (!_elements[new_id]);
     830     3208100 :   _elements[new_id] = el;
     831     3208100 :   _elements.erase(old_id);
     832             : 
     833             :   // Should we delete any caches here?  Our point locator indexes by
     834             :   // element pointer and should be fine with an id change.  Our stored
     835             :   // ranges are no longer sorted, which is *probably* fine, but let's
     836             :   // just be safe.
     837     3208100 :   this->clear_stored_ranges();
     838             : }
     839             : 
     840             : 
     841             : 
     842    40955093 : Node * DistributedMesh::add_point (const Point & p,
     843             :                                    const dof_id_type id,
     844             :                                    const processor_id_type proc_id)
     845             : {
     846    40955093 :   Node * old_n = this->query_node_ptr(id);
     847             : 
     848    40955093 :   if (old_n)
     849             :     {
     850           0 :       *old_n = p;
     851           0 :       old_n->processor_id() = proc_id;
     852             : 
     853           0 :       return old_n;
     854             :     }
     855             : 
     856    40915194 :   Node * n = Node::build(p, id).release();
     857    40955093 :   n->processor_id() = proc_id;
     858             : 
     859    40955093 :   return DistributedMesh::add_node(n);
     860             : }
     861             : 
     862             : 
     863        4130 : void DistributedMesh::own_node (Node & n)
     864             : {
     865             :   // This had better be a node in our mesh
     866           0 :   libmesh_assert(_nodes[n.id()] == &n);
     867             : 
     868        4130 :   _nodes[n.id()] = nullptr;
     869        4130 :   _n_nodes--;
     870             : 
     871           0 :   n.set_id(DofObject::invalid_id);
     872        4130 :   n.processor_id() = this->processor_id();
     873             : 
     874        4130 :   this->add_node(&n);
     875        4130 : }
     876             : 
     877             : 
     878    71733001 : Node * DistributedMesh::add_node (Node * n)
     879             : {
     880             :   // Don't try to add nullptrs!
     881       41611 :   libmesh_assert(n);
     882             : 
     883             :   // Trying to add an existing node is a no-op
     884    71733001 :   if (n->valid_id() && _nodes[n->id()] == n)
     885           0 :     return n;
     886             : 
     887    71733001 :   const processor_id_type node_procid = n->processor_id();
     888             : 
     889    71733001 :   if (!n->valid_id())
     890             :     {
     891             :       // We should only be creating new ids past the end of the range
     892             :       // of existing ids
     893       17829 :       libmesh_assert_greater_equal(_next_free_unpartitioned_node_id,
     894             :                                    _max_node_id);
     895       17829 :       libmesh_assert_greater_equal(_next_free_local_node_id, _max_node_id);
     896             : 
     897             :       // Use the unpartitioned ids for unpartitioned nodes,
     898             :       // and temporarily for ghost nodes
     899    17191263 :       dof_id_type * next_id = &_next_free_unpartitioned_node_id;
     900    17209092 :       if (node_procid == this->processor_id())
     901     2128730 :         next_id = &_next_free_local_node_id;
     902    17191263 :       n->set_id (*next_id);
     903             :     }
     904             : 
     905             :   {
     906             :     // Advance next_ids up high enough that each is pointing to an
     907             :     // unused id and any subsequent increments will still point us
     908             :     // to unused ids
     909   143466002 :     _max_node_id = std::max(_max_node_id,
     910    71733001 :                             static_cast<dof_id_type>(n->id()+1));
     911             : 
     912    71733001 :     if (_next_free_unpartitioned_node_id < _max_node_id)
     913    20115915 :       _next_free_unpartitioned_node_id =
     914    20115915 :         ((_max_node_id-1) / (this->n_processors() + 1) + 1) *
     915    20115915 :         (this->n_processors() + 1) + this->n_processors();
     916    71733001 :     if (_next_free_local_node_id < _max_node_id)
     917    11727360 :       _next_free_local_node_id =
     918    11745528 :         ((_max_node_id + this->n_processors() - 1) / (this->n_processors() + 1) + 1) *
     919    11727360 :         (this->n_processors() + 1) + this->processor_id();
     920             : 
     921             : #ifndef NDEBUG
     922             :     // We need a const dofobject_container so we don't inadvertently create
     923             :     // nullptr entries when testing for non-nullptr ones
     924       41611 :     const dofobject_container<Node> & const_nodes = _nodes;
     925             : #endif
     926       41611 :     libmesh_assert(!const_nodes[_next_free_unpartitioned_node_id]);
     927       41611 :     libmesh_assert(!const_nodes[_next_free_local_node_id]);
     928             :   }
     929             : 
     930             :   // Don't try to overwrite existing nodes
     931       41611 :   libmesh_assert (!_nodes[n->id()]);
     932             : 
     933    71733001 :   _nodes[n->id()] = n;
     934             : 
     935             :   // Try to make the cached node data more accurate
     936    71774612 :   if (node_procid == this->processor_id() ||
     937             :       node_procid == DofObject::invalid_processor_id)
     938    38540731 :     _n_nodes++;
     939             : 
     940             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
     941    71733001 :   if (!n->valid_unique_id())
     942             :     {
     943    40956973 :       if (processor_id() == n->processor_id())
     944             :         {
     945     2545412 :           n->set_unique_id(_next_unique_id);
     946     2545412 :           _next_unique_id += this->n_processors() + 1;
     947             :         }
     948             :       else
     949             :         {
     950    38411561 :           n->set_unique_id(_next_unpartitioned_unique_id);
     951    38411561 :           _next_unpartitioned_unique_id += this->n_processors() + 1;
     952             :         }
     953             :     }
     954             :   else
     955             :     {
     956    30906548 :       _next_unique_id = std::max(_next_unique_id, n->unique_id()+1);
     957    30776028 :       _next_unique_id =
     958    30776028 :         ((_next_unique_id + this->n_processors() - 1) / (this->n_processors() + 1) + 1) *
     959    30776028 :         (this->n_processors() + 1) + this->processor_id();
     960             :     }
     961             : #endif
     962             : 
     963    71733001 :   n->add_extra_integers(_node_integer_names.size(),
     964    71733001 :                         _node_integer_default_values);
     965             : 
     966             :   // Unpartitioned nodes should be added on every processor
     967             :   // And shouldn't be added in the same batch as ghost nodes
     968             :   // But we might be just adding on processor 0 to
     969             :   // broadcast later
     970             :   // #ifdef DEBUG
     971             :   //   if (node_procid == DofObject::invalid_processor_id)
     972             :   //     {
     973             :   //       dof_id_type node_id = n->id();
     974             :   //       this->comm().max(node_id);
     975             :   //       libmesh_assert_equal_to (node_id, n->id());
     976             :   //     }
     977             :   // #endif
     978             : 
     979    71733001 :   return n;
     980             : }
     981             : 
     982    30773778 : Node * DistributedMesh::add_node (std::unique_ptr<Node> n)
     983             : {
     984             :   // The mesh now takes ownership of the Node. Eventually the guts of
     985             :   // add_node() will get moved to a private helper function, and
     986             :   // calling add_node() directly will be deprecated.
     987    30773778 :   return add_node(n.release());
     988             : }
     989             : 
     990    50495302 : void DistributedMesh::delete_node(Node * n)
     991             : {
     992        4497 :   libmesh_assert(n);
     993        4497 :   libmesh_assert(_nodes[n->id()]);
     994             : 
     995             :   // Try to make the cached elem data more accurate
     996    50495302 :   _n_nodes--;
     997             : 
     998             :   // Delete the node from the BoundaryInfo object
     999    50495302 :   this->get_boundary_info().remove(n);
    1000        8994 :   _constraint_rows.erase(n);
    1001             : 
    1002             :   // But not yet from the container; we might invalidate
    1003             :   // an iterator that way!
    1004             : 
    1005             :   //_nodes.erase(n->id());
    1006             : 
    1007             :   // Instead, we set it to nullptr for now
    1008             : 
    1009    50495302 :   _nodes[n->id()] = nullptr;
    1010             : 
    1011             :   // delete the node
    1012    50495302 :   delete n;
    1013    50495302 : }
    1014             : 
    1015             : 
    1016             : 
    1017     6899073 : void DistributedMesh::renumber_node(const dof_id_type old_id,
    1018             :                                     const dof_id_type new_id)
    1019             : {
    1020             :   // This could be a no-op
    1021     6899073 :   if (old_id == new_id)
    1022           0 :     return;
    1023             : 
    1024     6898512 :   Node * nd = _nodes[old_id];
    1025        3234 :   libmesh_assert (nd);
    1026        3234 :   libmesh_assert_equal_to (nd->id(), old_id);
    1027             : 
    1028             :   // If we have nodes shipped to this processor for NodeConstraints
    1029             :   // use, then those nodes will exist in _nodes, but may not be
    1030             :   // locatable via a TopologyMap due to the insufficiency of elements
    1031             :   // connecting to them.  If local refinement then wants to create a
    1032             :   // *new* node in the same location, it will initially get a temporary
    1033             :   // id, and then make_node_ids_parallel_consistent() will try to move
    1034             :   // it to the canonical id.  We need to account for this case to
    1035             :   // avoid false positives and memory leaks.
    1036             : #ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS
    1037        6468 :   if (_nodes[new_id])
    1038             :     {
    1039           0 :       libmesh_assert_equal_to (*(Point *)_nodes[new_id],
    1040             :                                *(Point *)_nodes[old_id]);
    1041           0 :       _nodes.erase(new_id);
    1042             :     }
    1043             : #else
    1044             :   // If we aren't shipping nodes for NodeConstraints, there should be
    1045             :   // no reason for renumbering one node onto another.
    1046             :   libmesh_assert (!_nodes[new_id]);
    1047             : #endif
    1048     6898512 :   _nodes[new_id] = nd;
    1049     6898512 :   nd->set_id(new_id);
    1050             : 
    1051     6898512 :   _nodes.erase(old_id);
    1052             : }
    1053             : 
    1054             : 
    1055             : 
    1056      556952 : void DistributedMesh::clear ()
    1057             : {
    1058             :   // Call parent clear function
    1059      556952 :   MeshBase::clear();
    1060             : 
    1061             :   // Clear our elements and nodes
    1062             :   // There is no need to remove them from
    1063             :   // the BoundaryInfo data structure since we
    1064             :   // already cleared it.
    1065      556952 :   this->DistributedMesh::clear_elems();
    1066             : 
    1067    22594334 :   for (auto & node : _nodes)
    1068    40907060 :     delete node;
    1069             : 
    1070         578 :   _nodes.clear();
    1071             : 
    1072             :   // We're no longer distributed if we were before
    1073      556952 :   _is_serial = true;
    1074      556952 :   _is_serial_on_proc_0 = true;
    1075             : 
    1076             :   // We deleted a ton of coarse elements, but their nodes got deleted too so
    1077             :   // all is copacetic.
    1078      556952 :   _deleted_coarse_elements = false;
    1079             : 
    1080             :   // Correct our caches
    1081      556952 :   _n_nodes = 0;
    1082      556952 :   _max_node_id = 0;
    1083      557530 :   _next_free_local_node_id = this->processor_id();
    1084      556952 :   _next_free_unpartitioned_node_id = this->n_processors();
    1085      556952 : }
    1086             : 
    1087             : 
    1088             : 
    1089      563352 : void DistributedMesh::clear_elems ()
    1090             : {
    1091     9213447 :   for (auto & elem : _elements)
    1092     8650095 :     delete elem;
    1093             : 
    1094         578 :   _elements.clear();
    1095             : 
    1096             :   // Correct our caches
    1097      563352 :   _n_elem = 0;
    1098      563352 :   _max_elem_id = 0;
    1099      563930 :   _next_free_local_elem_id = this->processor_id();
    1100      563352 :   _next_free_unpartitioned_elem_id = this->n_processors();
    1101      563352 : }
    1102             : 
    1103             : 
    1104             : 
    1105      560012 : void DistributedMesh::redistribute ()
    1106             : {
    1107             :   // If this is a truly parallel mesh, go through the redistribution/gather/delete remote steps
    1108      560012 :   if (!this->is_serial())
    1109             :     {
    1110             :       // Construct a MeshCommunication object to actually redistribute the nodes
    1111             :       // and elements according to the partitioner, and then to re-gather the neighbors.
    1112             :       MeshCommunication mc;
    1113       68322 :       mc.redistribute(*this);
    1114             : 
    1115       68322 :       this->update_parallel_id_counts();
    1116             : 
    1117             :       // We ought to still have valid neighbor links; we communicate
    1118             :       // them for newly-redistributed elements
    1119             :       // this->find_neighbors();
    1120             : 
    1121             :       // Is this necessary?  If we are called from prepare_for_use(), this will be called
    1122             :       // anyway... but users can always call partition directly, in which case we do need
    1123             :       // to call delete_remote_elements()...
    1124             :       //
    1125             :       // Regardless of whether it's necessary, it isn't safe.  We
    1126             :       // haven't communicated new node processor_ids yet, and we can't
    1127             :       // delete nodes until we do.
    1128             :       // this->delete_remote_elements();
    1129             :     }
    1130             :   else
    1131             :     // The base class can handle non-distributed things, like
    1132             :     // notifying any GhostingFunctors of changes
    1133      491690 :     MeshBase::redistribute();
    1134      560012 : }
    1135             : 
    1136             : 
    1137             : 
    1138      481565 : void DistributedMesh::update_post_partitioning ()
    1139             : {
    1140             :   // this->recalculate_n_partitions();
    1141             : 
    1142             :   // Let's do the base class cache clearing first, just in case our
    1143             :   // later computations are ever changed to make use of a local
    1144             :   // elements range cache
    1145      481565 :   this->MeshBase::update_post_partitioning();
    1146             : 
    1147             :   // Partitioning changes our numbers of unpartitioned objects
    1148      481565 :   this->update_parallel_id_counts();
    1149      481565 : }
    1150             : 
    1151             : 
    1152             : 
    1153             : template <typename T>
    1154        3356 : void DistributedMesh::libmesh_assert_valid_parallel_object_ids(const dofobject_container<T> & objects) const
    1155             : {
    1156             :   // This function must be run on all processors at once
    1157        3356 :   parallel_object_only();
    1158             : 
    1159        3356 :   const dof_id_type pmax_node_id = this->parallel_max_node_id();
    1160        3356 :   const dof_id_type pmax_elem_id = this->parallel_max_elem_id();
    1161        3356 :   const dof_id_type pmax_id = std::max(pmax_node_id, pmax_elem_id);
    1162             : 
    1163      894268 :   for (dof_id_type i=0; i != pmax_id; ++i)
    1164             :     {
    1165      890912 :       T * obj = objects[i]; // Returns nullptr if there's no map entry
    1166             : 
    1167             :       // Local lookups by id should return the requested object
    1168      890912 :       libmesh_assert(!obj || obj->id() == i);
    1169             : 
    1170             :       // All processors with an object should agree on id
    1171             : #ifndef NDEBUG
    1172      890912 :       const dof_id_type dofid = obj && obj->valid_id() ?
    1173             :         obj->id() : DofObject::invalid_id;
    1174      890912 :       libmesh_assert(this->comm().semiverify(obj ? &dofid : nullptr));
    1175             : #endif
    1176             : 
    1177             :       // All processors with an object should agree on processor id
    1178      890912 :       const dof_id_type procid = obj && obj->valid_processor_id() ?
    1179             :         obj->processor_id() : DofObject::invalid_processor_id;
    1180      890912 :       libmesh_assert(this->comm().semiverify(obj ? &procid : nullptr));
    1181             : 
    1182      890912 :       dof_id_type min_procid = procid;
    1183      890912 :       this->comm().min(min_procid);
    1184             : 
    1185             :       // Either:
    1186             :       // 1.) I own this elem (min_procid == this->processor_id()) *and* I have a valid pointer to it (obj != nullptr)
    1187             :       // or
    1188             :       // 2.) I don't own this elem (min_procid != this->processor_id()).  (In this case I may or may not have a valid pointer to it.)
    1189             : 
    1190             :       // Original assert logic
    1191             :       // libmesh_assert (min_procid != this->processor_id() || obj);
    1192             : 
    1193             :       // More human-understandable logic...
    1194      890912 :       libmesh_assert (
    1195             :                       ((min_procid == this->processor_id()) && obj)
    1196             :                       ||
    1197             :                       (min_procid != this->processor_id())
    1198             :                       );
    1199             : 
    1200             : #if defined(LIBMESH_ENABLE_UNIQUE_ID) && !defined(NDEBUG)
    1201             :       // All processors with an object should agree on unique id
    1202      890912 :       const unique_id_type uniqueid = obj ? obj->unique_id() : 0;
    1203      890912 :       libmesh_assert(this->comm().semiverify(obj ? &uniqueid : nullptr));
    1204             : #endif
    1205             :     }
    1206        3356 : }
    1207             : 
    1208             : 
    1209             : 
    1210        1678 : void DistributedMesh::libmesh_assert_valid_parallel_ids () const
    1211             : {
    1212        1678 :   this->libmesh_assert_valid_parallel_object_ids (this->_elements);
    1213        1678 :   this->libmesh_assert_valid_parallel_object_ids (this->_nodes);
    1214        1678 : }
    1215             : 
    1216             : 
    1217             : 
    1218         402 : void DistributedMesh::libmesh_assert_valid_parallel_p_levels () const
    1219             : {
    1220             : #ifndef NDEBUG
    1221             :   // This function must be run on all processors at once
    1222         402 :   parallel_object_only();
    1223             : 
    1224         402 :   dof_id_type pmax_elem_id = this->parallel_max_elem_id();
    1225             : 
    1226       21958 :   for (dof_id_type i=0; i != pmax_elem_id; ++i)
    1227             :     {
    1228       21556 :       Elem * el = _elements[i]; // Returns nullptr if there's no map entry
    1229             : 
    1230       21556 :       unsigned int p_level = el ?  (el->p_level()) : libMesh::invalid_uint;
    1231             : 
    1232             :       // All processors with an active element should agree on p level
    1233       21556 :       libmesh_assert(this->comm().semiverify((el && el->active()) ? &p_level : nullptr));
    1234             :     }
    1235             : #endif
    1236         402 : }
    1237             : 
    1238             : 
    1239             : 
    1240             : 
    1241        1626 : void DistributedMesh::libmesh_assert_valid_parallel_flags () const
    1242             : {
    1243             : #if defined(LIBMESH_ENABLE_AMR) && !defined(NDEBUG)
    1244             :   // This function must be run on all processors at once
    1245        1626 :   parallel_object_only();
    1246             : 
    1247        1626 :   dof_id_type pmax_elem_id = this->parallel_max_elem_id();
    1248             : 
    1249      144668 :   for (dof_id_type i=0; i != pmax_elem_id; ++i)
    1250             :     {
    1251      143042 :       Elem * el = _elements[i]; // Returns nullptr if there's no map entry
    1252             : 
    1253      143042 :       unsigned int refinement_flag   = el ?
    1254       65709 :         static_cast<unsigned int> (el->refinement_flag()) : libMesh::invalid_uint;
    1255      143042 :       unsigned int p_refinement_flag = el ?
    1256       65709 :         static_cast<unsigned int> (el->p_refinement_flag()) : libMesh::invalid_uint;
    1257             : 
    1258      143042 :       libmesh_assert(this->comm().semiverify(el ? &refinement_flag : nullptr));
    1259             : 
    1260             :       // p refinement flags aren't always kept correct on inactive
    1261             :       // ghost elements
    1262      143042 :       libmesh_assert(this->comm().semiverify((el && el->active()) ? &p_refinement_flag : nullptr));
    1263             :     }
    1264             : #endif // LIBMESH_ENABLE_AMR
    1265        1626 : }
    1266             : 
    1267             : 
    1268             : 
    1269             : template <typename T>
    1270             : dof_id_type
    1271     1717566 : DistributedMesh::renumber_dof_objects(dofobject_container<T> & objects)
    1272             : {
    1273             :   // This function must be run on all processors at once
    1274         800 :   parallel_object_only();
    1275             : 
    1276             :   typedef typename dofobject_container<T>::veclike_iterator object_iterator;
    1277             : 
    1278             :   // In parallel we may not know what objects other processors have.
    1279             :   // Start by figuring out how many
    1280         800 :   dof_id_type unpartitioned_objects = 0;
    1281             : 
    1282             :   std::unordered_map<processor_id_type, dof_id_type>
    1283        1600 :     ghost_objects_from_proc;
    1284             : 
    1285     1717566 :   object_iterator it  = objects.begin();
    1286         800 :   object_iterator end = objects.end();
    1287             : 
    1288   109777364 :   while (it != end)
    1289             :     {
    1290   108059798 :       T * obj = *it;
    1291             : 
    1292             :       // Remove any nullptr container entries while we're here.
    1293   108059798 :       if (!obj)
    1294     1417935 :         it = objects.erase(it);
    1295             :       else
    1296             :         {
    1297   106641863 :           processor_id_type obj_procid = obj->processor_id();
    1298   106641863 :           if (obj_procid == DofObject::invalid_processor_id)
    1299    42414931 :             unpartitioned_objects++;
    1300             :           else
    1301    64226932 :             ghost_objects_from_proc[obj_procid]++;
    1302             : 
    1303             :           // Finally, increment the iterator
    1304       56414 :           ++it;
    1305             :         }
    1306             :     }
    1307             : 
    1308     1719166 :   std::vector<dof_id_type> objects_on_proc(this->n_processors(), 0);
    1309     1718366 :   auto this_it = ghost_objects_from_proc.find(this->processor_id());
    1310         800 :   this->comm().allgather
    1311     1718057 :     ((this_it == ghost_objects_from_proc.end()) ?
    1312         491 :      dof_id_type(0) : this_it->second, objects_on_proc);
    1313             : 
    1314             : #ifndef NDEBUG
    1315         800 :   libmesh_assert(this->comm().verify(unpartitioned_objects));
    1316        2400 :   for (processor_id_type p=0, np=this->n_processors(); p != np; ++p)
    1317        1600 :     if (ghost_objects_from_proc.count(p))
    1318         951 :       libmesh_assert_less_equal (ghost_objects_from_proc[p], objects_on_proc[p]);
    1319             :     else
    1320         649 :       libmesh_assert_less_equal (0, objects_on_proc[p]);
    1321             : #endif
    1322             : 
    1323             :   // We'll renumber objects in blocks by processor id
    1324     1719166 :   std::vector<dof_id_type> first_object_on_proc(this->n_processors());
    1325    18225342 :   for (processor_id_type i=1, np=this->n_processors(); i != np; ++i)
    1326    16510976 :     first_object_on_proc[i] = first_object_on_proc[i-1] +
    1327         800 :       objects_on_proc[i-1];
    1328     1718366 :   dof_id_type next_id = first_object_on_proc[this->processor_id()];
    1329     1717566 :   dof_id_type first_free_id =
    1330     1719166 :     first_object_on_proc[this->n_processors()-1] +
    1331         800 :     objects_on_proc[this->n_processors()-1] +
    1332             :     unpartitioned_objects;
    1333             : 
    1334             :   // First set new local object ids and build request sets
    1335             :   // for non-local object ids
    1336             : 
    1337             :   // Request sets to send to each processor
    1338             :   std::map<processor_id_type, std::vector<dof_id_type>>
    1339         800 :     requested_ids;
    1340             : 
    1341             :   // We know how many objects live on each processor, so reserve() space for
    1342             :   // each.
    1343         800 :   auto ghost_end = ghost_objects_from_proc.end();
    1344    19942908 :   for (auto p : make_range(this->n_processors()))
    1345    18226942 :     if (p != this->processor_id())
    1346             :       {
    1347    16508576 :         if (const auto p_it = ghost_objects_from_proc.find(p);
    1348         800 :             p_it != ghost_end)
    1349     3322991 :           requested_ids[p].reserve(p_it->second);
    1350             :       }
    1351             : 
    1352         800 :   end = objects.end();
    1353   108359429 :   for (it = objects.begin(); it != end; ++it)
    1354             :     {
    1355   106641863 :       T * obj = *it;
    1356   106641863 :       if (!obj)
    1357           0 :         continue;
    1358   106698277 :       if (obj->processor_id() == this->processor_id())
    1359    19773492 :         obj->set_id(next_id++);
    1360    86868371 :       else if (obj->processor_id() != DofObject::invalid_processor_id)
    1361    44453440 :         requested_ids[obj->processor_id()].push_back(obj->id());
    1362             :     }
    1363             : 
    1364             :   // Next set ghost object ids from other processors
    1365             : 
    1366     1734737 :   auto gather_functor =
    1367    47743009 :     [
    1368             : #ifndef NDEBUG
    1369             :      this,
    1370             :      &first_object_on_proc,
    1371             :      &objects_on_proc,
    1372             : #endif
    1373             :      &objects]
    1374             :     (processor_id_type, const std::vector<dof_id_type> & ids,
    1375         920 :      std::vector<dof_id_type> & new_ids)
    1376             :     {
    1377         920 :       std::size_t ids_size = ids.size();
    1378     3322991 :       new_ids.resize(ids_size);
    1379             : 
    1380    47776431 :       for (std::size_t i=0; i != ids_size; ++i)
    1381             :         {
    1382    44453440 :           T * obj = objects[ids[i]];
    1383       16251 :           libmesh_assert(obj);
    1384       16251 :           libmesh_assert_equal_to (obj->processor_id(), this->processor_id());
    1385    44469691 :           new_ids[i] = obj->id();
    1386             : 
    1387       16251 :           libmesh_assert_greater_equal (new_ids[i],
    1388             :                                         first_object_on_proc[this->processor_id()]);
    1389       16251 :           libmesh_assert_less (new_ids[i],
    1390             :                                first_object_on_proc[this->processor_id()] +
    1391             :                                objects_on_proc[this->processor_id()]);
    1392             :         }
    1393             :     };
    1394             : 
    1395     1734737 :   auto action_functor =
    1396    47743009 :     [
    1397             : #ifndef NDEBUG
    1398             :      &first_object_on_proc,
    1399             :      &objects_on_proc,
    1400             : #endif
    1401             :      &objects]
    1402             :     (processor_id_type libmesh_dbg_var(pid),
    1403             :      const std::vector<dof_id_type> & ids,
    1404         920 :      const std::vector<dof_id_type> & data)
    1405             :     {
    1406             :       // Copy the id changes we've now been informed of
    1407    47776431 :       for (auto i : index_range(ids))
    1408             :         {
    1409    44453440 :           T * obj = objects[ids[i]];
    1410       16251 :           libmesh_assert (obj);
    1411       16251 :           libmesh_assert_equal_to (obj->processor_id(), pid);
    1412       16251 :           libmesh_assert_greater_equal (data[i],
    1413             :                                         first_object_on_proc[pid]);
    1414       16251 :           libmesh_assert_less (data[i],
    1415             :                                first_object_on_proc[pid] +
    1416             :                                objects_on_proc[pid]);
    1417    44469691 :           obj->set_id(data[i]);
    1418             :         }
    1419             :     };
    1420             : 
    1421         800 :   const dof_id_type * ex = nullptr;
    1422             :   Parallel::pull_parallel_vector_data
    1423     1717566 :     (this->comm(), requested_ids, gather_functor, action_functor, ex);
    1424             : 
    1425             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
    1426     1734737 :   auto unique_gather_functor =
    1427    47743009 :     [
    1428             : #ifndef NDEBUG
    1429             :      this,
    1430             : #endif
    1431             :      &objects]
    1432             :     (processor_id_type, const std::vector<dof_id_type> & ids,
    1433         920 :      std::vector<unique_id_type> & data)
    1434             :     {
    1435         920 :       std::size_t ids_size = ids.size();
    1436     3322991 :       data.resize(ids_size);
    1437             : 
    1438    47776431 :       for (std::size_t i=0; i != ids_size; ++i)
    1439             :         {
    1440    44453440 :           T * obj = objects[ids[i]];
    1441       16251 :           libmesh_assert(obj);
    1442       16251 :           libmesh_assert_equal_to (obj->processor_id(), this->processor_id());
    1443    88906880 :           data[i] = obj->valid_unique_id() ? obj->unique_id() : DofObject::invalid_unique_id;
    1444             :         }
    1445             :     };
    1446             : 
    1447     1734737 :   auto unique_action_functor =
    1448    47743009 :     [&objects]
    1449             :     (processor_id_type libmesh_dbg_var(pid),
    1450             :      const std::vector<dof_id_type> & ids,
    1451         920 :      const std::vector<unique_id_type> & data)
    1452             :     {
    1453    47776431 :       for (auto i : index_range(ids))
    1454             :         {
    1455    44453440 :           T * obj = objects[ids[i]];
    1456       16251 :           libmesh_assert (obj);
    1457       16251 :           libmesh_assert_equal_to (obj->processor_id(), pid);
    1458    44453440 :           if (!obj->valid_unique_id() && data[i] != DofObject::invalid_unique_id)
    1459           0 :             obj->set_unique_id(data[i]);
    1460             :         }
    1461             :     };
    1462             : 
    1463         800 :   const unique_id_type * unique_ex = nullptr;
    1464             :   Parallel::pull_parallel_vector_data
    1465     1717566 :     (this->comm(), requested_ids, unique_gather_functor,
    1466             :      unique_action_functor, unique_ex);
    1467             : #endif
    1468             : 
    1469             :   // Next set unpartitioned object ids
    1470         800 :   next_id = 0;
    1471    19942908 :   for (auto i : make_range(this->n_processors()))
    1472    18226942 :     next_id += objects_on_proc[i];
    1473   108359429 :   for (it = objects.begin(); it != end; ++it)
    1474             :     {
    1475   106641863 :       T * obj = *it;
    1476   106641863 :       if (!obj)
    1477           0 :         continue;
    1478   106641863 :       if (obj->processor_id() == DofObject::invalid_processor_id)
    1479    42414931 :         obj->set_id(next_id++);
    1480             :     }
    1481             : 
    1482             :   // Finally shuffle around objects so that container indices
    1483             :   // match ids
    1484     1717566 :   it = objects.begin();
    1485         800 :   end = objects.end();
    1486   114830935 :   while (it != end)
    1487             :     {
    1488   113113369 :       T * obj = *it;
    1489   113113369 :       if (obj) // don't try shuffling already-nullptr entries
    1490             :         {
    1491   113113369 :           T * next = objects[obj->id()];
    1492             :           // If we have to move this object
    1493   113113369 :           if (next != obj)
    1494             :             {
    1495             :               // nullptr out its original position for now
    1496             :               // (our shuffling may put another object there shortly)
    1497    39560477 :               *it = nullptr;
    1498             : 
    1499             :               // There may already be another object with this id that
    1500             :               // needs to be moved itself
    1501    51028603 :               while (next)
    1502             :                 {
    1503             :                   // We shouldn't be trying to give two objects the
    1504             :                   // same id
    1505        9329 :                   libmesh_assert_not_equal_to (next->id(), obj->id());
    1506    11468126 :                   objects[obj->id()] = obj;
    1507        9329 :                   obj = next;
    1508    11468126 :                   next = objects[obj->id()];
    1509             :                 }
    1510    39560477 :               objects[obj->id()] = obj;
    1511             :             }
    1512             :         }
    1513             : 
    1514             :       // Remove any container entries that were left as nullptr.
    1515      115296 :       if (!obj)
    1516           0 :         it = objects.erase(it);
    1517             :       else
    1518       57648 :         ++it;
    1519             :     }
    1520             : 
    1521     1718366 :   return first_free_id;
    1522             : }
    1523             : 
    1524             : 
    1525      860453 : void DistributedMesh::renumber_nodes_and_elements ()
    1526             : {
    1527         402 :   parallel_object_only();
    1528             : 
    1529             : #ifdef DEBUG
    1530             :   // Make sure our ids and flags are consistent
    1531         402 :   this->libmesh_assert_valid_parallel_ids();
    1532         402 :   this->libmesh_assert_valid_parallel_flags();
    1533         402 :   this->libmesh_assert_valid_parallel_p_levels();
    1534             : #endif
    1535             : 
    1536         402 :   LOG_SCOPE("renumber_nodes_and_elements()", "DistributedMesh");
    1537             : 
    1538             :   // Nodes not connected to any elements, and nullptr node entries
    1539             :   // in our container, should be deleted.  But wait!  If we've deleted coarse
    1540             :   // local elements on some processor, other processors might have ghosted
    1541             :   // nodes from it that are now no longer connected to any elements on it, but
    1542             :   // that are connected to their own semilocal elements.  We'll have to
    1543             :   // communicate to ascertain if that's the case.
    1544      860453 :   this->comm().max(_deleted_coarse_elements);
    1545             : 
    1546             :   // What used nodes do we see on our proc?
    1547         402 :   std::set<dof_id_type> used_nodes;
    1548             : 
    1549             :   // What used node info should we send from our proc?  Could we take ownership
    1550             :   // of each node if we needed to?
    1551             :   std::map<processor_id_type, std::map<dof_id_type, bool>>
    1552         402 :     used_nodes_on_proc;
    1553             : 
    1554             :   // flag the nodes we need
    1555    56897540 :   for (auto & elem : this->element_ptr_range())
    1556   296435061 :     for (const Node & node : elem->node_ref_range())
    1557             :       {
    1558   268817129 :         const dof_id_type n = node.id();
    1559   268672759 :         used_nodes.insert(n);
    1560   268817129 :         if (_deleted_coarse_elements)
    1561             :           {
    1562     3145701 :             const processor_id_type p = node.processor_id();
    1563     3145985 :             if (p != this->processor_id())
    1564             :               {
    1565     2257624 :                 auto & used_nodes_on_p = used_nodes_on_proc[p];
    1566     2257766 :                 if (elem->processor_id() == this->processor_id())
    1567      216210 :                   used_nodes_on_p[n] = true;
    1568             :                 else
    1569         105 :                   if (!used_nodes_on_p.count(n))
    1570      525626 :                     used_nodes_on_p[n] = false;
    1571             :               }
    1572             :           }
    1573      859649 :       }
    1574             : 
    1575      860453 :   if (_deleted_coarse_elements)
    1576             :     {
    1577             :       // "unsigned char" == "bool, but MPI::BOOL is iffy to use"
    1578             :       typedef unsigned char boolish;
    1579             :       std::map<processor_id_type, std::vector<std::pair<dof_id_type, boolish>>>
    1580          28 :         used_nodes_on_proc_vecs;
    1581       73209 :       for (auto & [pid, nodemap] : used_nodes_on_proc)
    1582       56827 :         used_nodes_on_proc_vecs[pid].assign(nodemap.begin(), nodemap.end());
    1583             : 
    1584          28 :       std::map<dof_id_type,processor_id_type> repartitioned_node_pids;
    1585             :       std::map<processor_id_type, std::set<dof_id_type>>
    1586          28 :         repartitioned_node_sets_to_push;
    1587             : 
    1588             :       auto ids_action_functor =
    1589       56801 :         [&used_nodes, &repartitioned_node_pids,
    1590             :          &repartitioned_node_sets_to_push]
    1591             :         (processor_id_type pid,
    1592         112 :          const std::vector<std::pair<dof_id_type, boolish>> & ids_and_bools)
    1593             :         {
    1594      592596 :           for (auto [n, sender_could_become_owner] : ids_and_bools)
    1595             :             {
    1596             :               // If we don't see a use for our own node, but someone
    1597             :               // else does, better figure out who should own it next.
    1598          97 :               if (!used_nodes.count(n))
    1599             :                 {
    1600           2 :                   if (auto it = repartitioned_node_pids.find(n);
    1601           2 :                       sender_could_become_owner)
    1602             :                     {
    1603           1 :                       if (it != repartitioned_node_pids.end() &&
    1604           1 :                           pid < it->second)
    1605           1 :                         it->second = pid;
    1606             :                       else
    1607           0 :                         repartitioned_node_pids[n] = pid;
    1608             :                     }
    1609             :                   else
    1610           1 :                     if (it == repartitioned_node_pids.end())
    1611           1 :                       repartitioned_node_pids[n] =
    1612             :                         DofObject::invalid_processor_id;
    1613             : 
    1614           2 :                   repartitioned_node_sets_to_push[pid].insert(n);
    1615             :                 }
    1616             :             }
    1617       16394 :         };
    1618             : 
    1619             :       // We need two pushes instead of a pull here because we need to
    1620             :       // know *all* the queries for a particular node before we can
    1621             :       // respond to *any* of them.
    1622             :       Parallel::push_parallel_vector_data
    1623       16382 :       (this->comm(), used_nodes_on_proc_vecs, ids_action_functor);
    1624             : 
    1625             :       // Repartition (what used to be) our own nodes first
    1626       16383 :       for (auto & [n, p] : repartitioned_node_pids)
    1627             :         {
    1628           1 :           Node & node = this->node_ref(n);
    1629           0 :           libmesh_assert_equal_to(node.processor_id(), this->processor_id());
    1630           0 :           libmesh_assert_not_equal_to_msg(p, DofObject::invalid_processor_id, "Node " << n << " is lost?");
    1631           1 :           node.processor_id() = p;
    1632             :         }
    1633             : 
    1634             :       // Then push to repartition others' ghosted copies.
    1635             : 
    1636             :       std::map<processor_id_type, std::vector<std::pair<dof_id_type,processor_id_type>>>
    1637          28 :         repartitioned_node_vecs;
    1638             : 
    1639       16384 :       for (auto & [p, nodeset] : repartitioned_node_sets_to_push)
    1640             :         {
    1641           2 :           auto & rn_vec = repartitioned_node_vecs[p];
    1642           4 :           for (auto n : nodeset)
    1643           2 :             rn_vec.emplace_back(n, repartitioned_node_pids[n]);
    1644             :         }
    1645             : 
    1646             :       auto repartition_node_functor =
    1647           2 :         [this]
    1648             :         (processor_id_type libmesh_dbg_var(pid),
    1649           2 :          const std::vector<std::pair<dof_id_type, processor_id_type>> & ids_and_pids)
    1650             :         {
    1651           4 :           for (auto [n, p] : ids_and_pids)
    1652             :             {
    1653           0 :               libmesh_assert_not_equal_to(p, DofObject::invalid_processor_id);
    1654           2 :               Node & node = this->node_ref(n);
    1655           0 :               libmesh_assert_equal_to(node.processor_id(), pid);
    1656           2 :               node.processor_id() = p;
    1657             :             }
    1658       16354 :         };
    1659             : 
    1660             :       Parallel::push_parallel_vector_data
    1661       16382 :       (this->comm(), repartitioned_node_vecs, repartition_node_functor);
    1662             :     }
    1663             : 
    1664      860453 :   _deleted_coarse_elements = false;
    1665             : 
    1666             :   // Nodes not connected to any local elements, and nullptr node entries
    1667             :   // in our container, are deleted
    1668             :   {
    1669      860453 :     node_iterator_imp  it = _nodes.begin();
    1670         402 :     node_iterator_imp end = _nodes.end();
    1671             : 
    1672    86718050 :     while (it != end)
    1673             :       {
    1674    85857597 :         Node * nd = *it;
    1675    85857597 :         if (!nd)
    1676     3471824 :           it = _nodes.erase(it);
    1677    82385773 :         else if (!used_nodes.count(nd->id()))
    1678             :           {
    1679             :             // remove any boundary information associated with
    1680             :             // this node
    1681     2328191 :             this->get_boundary_info().remove (nd);
    1682        2828 :             _constraint_rows.erase(nd);
    1683             : 
    1684             :             // delete the node
    1685     2328191 :             delete nd;
    1686             : 
    1687     2328191 :             it = _nodes.erase(it);
    1688             :           }
    1689             :         else
    1690       45269 :           ++it;
    1691             :       }
    1692             :   }
    1693             : 
    1694      860453 :   this->_preparation.has_removed_orphaned_nodes = true;
    1695             : 
    1696      860453 :   if (_skip_renumber_nodes_and_elements)
    1697             :     {
    1698        1670 :       this->update_parallel_id_counts();
    1699           2 :       return;
    1700             :     }
    1701             : 
    1702             :   // Finally renumber all the elements
    1703      858783 :   _n_elem = this->renumber_dof_objects (this->_elements);
    1704             : 
    1705             :   // and all the remaining nodes
    1706      858783 :   _n_nodes = this->renumber_dof_objects (this->_nodes);
    1707             : 
    1708             :   // And figure out what IDs we should use when adding new nodes and
    1709             :   // new elements
    1710      858783 :   this->update_parallel_id_counts();
    1711             : 
    1712             :   // Make sure our caches are up to date and our
    1713             :   // DofObjects are well packed
    1714             : #ifdef DEBUG
    1715         400 :   libmesh_assert_equal_to (this->n_nodes(), this->parallel_n_nodes());
    1716         400 :   libmesh_assert_equal_to (this->n_elem(), this->parallel_n_elem());
    1717         400 :   const dof_id_type pmax_node_id = this->parallel_max_node_id();
    1718         400 :   const dof_id_type pmax_elem_id = this->parallel_max_elem_id();
    1719         400 :   libmesh_assert_equal_to (this->max_node_id(), pmax_node_id);
    1720         400 :   libmesh_assert_equal_to (this->max_elem_id(), pmax_elem_id);
    1721         400 :   libmesh_assert_equal_to (this->n_nodes(), this->max_node_id());
    1722         400 :   libmesh_assert_equal_to (this->n_elem(), this->max_elem_id());
    1723             : 
    1724             :   // Make sure our ids and flags are consistent
    1725         400 :   this->libmesh_assert_valid_parallel_ids();
    1726         400 :   this->libmesh_assert_valid_parallel_flags();
    1727             : 
    1728             :   // And make sure we've made our numbering monotonic
    1729         400 :   MeshTools::libmesh_assert_valid_elem_ids(*this);
    1730             : #endif
    1731             : }
    1732             : 
    1733             : 
    1734             : 
    1735       17410 : void DistributedMesh::fix_broken_node_and_element_numbering ()
    1736             : {
    1737             :   // We can't use range-for here because we need access to the special
    1738             :   // iterators' methods, not just to their dereferenced values.
    1739             : 
    1740             :   // Nodes first
    1741           0 :   for (auto pr = this->_nodes.begin(),
    1742     5444770 :            end = this->_nodes.end(); pr != end; ++pr)
    1743             :     {
    1744     5427360 :       Node * n = *pr;
    1745     5427360 :       if (n != nullptr)
    1746             :         {
    1747           0 :           const dof_id_type id = pr.index();
    1748     5204550 :           n->set_id() = id;
    1749           0 :           libmesh_assert_equal_to(this->node_ptr(id), n);
    1750             :         }
    1751             :     }
    1752             : 
    1753             :   // Elements next
    1754           0 :   for (auto pr = this->_elements.begin(),
    1755     5671231 :            end = this->_elements.end(); pr != end; ++pr)
    1756             :     {
    1757     5653821 :       Elem * e = *pr;
    1758     5653821 :       if (e != nullptr)
    1759             :         {
    1760           0 :           const dof_id_type id = pr.index();
    1761     5590229 :           e->set_id() = id;
    1762           0 :           libmesh_assert_equal_to(this->elem_ptr(id), e);
    1763             :         }
    1764             :     }
    1765       17410 : }
    1766             : 
    1767             : 
    1768             : 
    1769      638691 : dof_id_type DistributedMesh::n_active_elem () const
    1770             : {
    1771         550 :   parallel_object_only();
    1772             : 
    1773             :   // Get local active elements first
    1774             :   dof_id_type active_elements =
    1775     1276832 :     static_cast<dof_id_type>(std::distance (this->active_local_elements_begin(),
    1776     1914973 :                                             this->active_local_elements_end()));
    1777      638691 :   this->comm().sum(active_elements);
    1778             : 
    1779             :   // Then add unpartitioned active elements, which should exist on
    1780             :   // every processor
    1781      638691 :   active_elements +=
    1782      638691 :     static_cast<dof_id_type>(std::distance
    1783     1276832 :                              (this->active_pid_elements_begin(DofObject::invalid_processor_id),
    1784      639241 :                               this->active_pid_elements_end(DofObject::invalid_processor_id)));
    1785      638691 :   return active_elements;
    1786             : }
    1787             : 
    1788             : 
    1789             : 
    1790      404641 : void DistributedMesh::delete_remote_elements()
    1791             : {
    1792             : #ifdef DEBUG
    1793             :   // Make sure our neighbor links are all fine
    1794         388 :   MeshTools::libmesh_assert_valid_neighbors(*this);
    1795             : 
    1796             :   // And our child/parent links, and our flags
    1797         388 :   MeshTools::libmesh_assert_valid_refinement_tree(*this);
    1798             : 
    1799             :   // Make sure our ids and flags are consistent
    1800         388 :   this->libmesh_assert_valid_parallel_ids();
    1801         388 :   this->libmesh_assert_valid_parallel_flags();
    1802             : 
    1803         388 :   libmesh_assert_equal_to (this->n_nodes(), this->parallel_n_nodes());
    1804         388 :   libmesh_assert_equal_to (this->n_elem(), this->parallel_n_elem());
    1805         388 :   const dof_id_type pmax_node_id = this->parallel_max_node_id();
    1806         388 :   const dof_id_type pmax_elem_id = this->parallel_max_elem_id();
    1807         388 :   libmesh_assert_equal_to (this->max_node_id(), pmax_node_id);
    1808         388 :   libmesh_assert_equal_to (this->max_elem_id(), pmax_elem_id);
    1809             : #endif
    1810             : 
    1811      404641 :   _is_serial = false;
    1812      404641 :   _is_serial_on_proc_0 = false;
    1813             : 
    1814      404641 :   MeshCommunication().delete_remote_elements(*this, _extra_ghost_elems);
    1815             : 
    1816         388 :   libmesh_assert_equal_to (this->max_elem_id(), this->parallel_max_elem_id());
    1817             : 
    1818             :   // Now make sure the containers actually shrink - strip
    1819             :   // any newly-created nullptr voids out of the element array
    1820      404641 :   dofobject_container<Elem>::veclike_iterator e_it        = _elements.begin();
    1821         388 :   const dofobject_container<Elem>::veclike_iterator e_end = _elements.end();
    1822    53430172 :   while (e_it != e_end)
    1823    53025531 :     if (!*e_it)
    1824    39493540 :       e_it = _elements.erase(e_it);
    1825             :     else
    1826       17389 :       ++e_it;
    1827             : 
    1828      404641 :   dofobject_container<Node>::veclike_iterator n_it        = _nodes.begin();
    1829         388 :   const dofobject_container<Node>::veclike_iterator n_end = _nodes.end();
    1830    99941974 :   while (n_it != n_end)
    1831    99537333 :     if (!*n_it)
    1832    66380838 :       n_it = _nodes.erase(n_it);
    1833             :     else
    1834       48597 :       ++n_it;
    1835             : 
    1836             :   // We may have deleted no-longer-connected nodes or coarsened-away
    1837             :   // elements; let's update our caches.
    1838      404641 :   this->update_parallel_id_counts();
    1839             : 
    1840             :   // We may have deleted nodes or elements that were the only local
    1841             :   // representatives of some particular boundary id(s); let's update
    1842             :   // those caches.
    1843      404641 :   this->get_boundary_info().regenerate_id_sets();
    1844             : 
    1845             : #ifdef DEBUG
    1846             :   // We might not have well-packed objects if the user didn't allow us
    1847             :   // to renumber
    1848             :   // libmesh_assert_equal_to (this->n_nodes(), this->max_node_id());
    1849             :   // libmesh_assert_equal_to (this->n_elem(), this->max_elem_id());
    1850             : 
    1851             :   // Make sure our neighbor links are all fine
    1852         388 :   MeshTools::libmesh_assert_valid_neighbors(*this);
    1853             : 
    1854             :   // And our child/parent links, and our flags
    1855         388 :   MeshTools::libmesh_assert_valid_refinement_tree(*this);
    1856             : 
    1857             :   // Make sure our ids and flags are consistent
    1858         388 :   this->libmesh_assert_valid_parallel_ids();
    1859         388 :   this->libmesh_assert_valid_parallel_flags();
    1860             : #endif
    1861             : 
    1862      404641 :   this->_preparation.has_removed_remote_elements = true;
    1863      404641 : }
    1864             : 
    1865             : 
    1866           0 : void DistributedMesh::add_extra_ghost_elem(Elem * e)
    1867             : {
    1868             :   // First add the elem like normal
    1869           0 :   add_elem(e);
    1870             : 
    1871             :   // Now add it to the set that won't be deleted when we call
    1872             :   // delete_remote_elements()
    1873           0 :   _extra_ghost_elems.insert(e);
    1874           0 : }
    1875             : 
    1876             : void
    1877           0 : DistributedMesh::clear_extra_ghost_elems(const std::set<Elem *> & extra_ghost_elems)
    1878             : {
    1879           0 :   std::set<Elem *> tmp;
    1880           0 :   std::set_difference(_extra_ghost_elems.begin(), _extra_ghost_elems.end(),
    1881             :                       extra_ghost_elems.begin(), extra_ghost_elems.end(),
    1882           0 :                       std::inserter(tmp, tmp.begin()));
    1883           0 :   _extra_ghost_elems = tmp;
    1884           0 : }
    1885             : 
    1886       97139 : void DistributedMesh::allgather()
    1887             : {
    1888       97139 :   if (_is_serial)
    1889           0 :     return;
    1890       97137 :   MeshCommunication().allgather(*this);
    1891       97137 :   _is_serial = true;
    1892       97137 :   _is_serial_on_proc_0 = true;
    1893             : 
    1894             :   // Make sure our caches are up to date and our
    1895             :   // DofObjects are well packed
    1896             : #ifdef DEBUG
    1897          48 :   libmesh_assert_equal_to (this->n_nodes(), this->parallel_n_nodes());
    1898          48 :   libmesh_assert_equal_to (this->n_elem(), this->parallel_n_elem());
    1899          48 :   const dof_id_type pmax_node_id = this->parallel_max_node_id();
    1900          48 :   const dof_id_type pmax_elem_id = this->parallel_max_elem_id();
    1901          48 :   libmesh_assert_equal_to (this->max_node_id(), pmax_node_id);
    1902          48 :   libmesh_assert_equal_to (this->max_elem_id(), pmax_elem_id);
    1903             : 
    1904             :   // If we've disabled renumbering we can't be sure we're contiguous
    1905             :   // libmesh_assert_equal_to (this->n_nodes(), this->max_node_id());
    1906             :   // libmesh_assert_equal_to (this->n_elem(), this->max_elem_id());
    1907             : 
    1908             :   // Make sure our neighbor links are all fine
    1909          48 :   MeshTools::libmesh_assert_valid_neighbors(*this);
    1910             : 
    1911             :   // Make sure our ids and flags are consistent
    1912          48 :   this->libmesh_assert_valid_parallel_ids();
    1913          48 :   this->libmesh_assert_valid_parallel_flags();
    1914             : #endif
    1915             : }
    1916             : 
    1917       18352 : void DistributedMesh::gather_to_zero()
    1918             : {
    1919       18352 :   if (_is_serial_on_proc_0)
    1920           4 :     return;
    1921             : 
    1922       14114 :   _is_serial_on_proc_0 = true;
    1923       14114 :   MeshCommunication().gather(0, *this);
    1924             : }
    1925             : 
    1926             : 
    1927             : } // namespace libMesh

Generated by: LCOV version 1.14