LCOV - code coverage report
Current view: top level - src/mesh - distributed_mesh.C (source / functions) Hit Total Coverage
Test: libMesh/libmesh: #4475 (55045b) with base a68cc6 Lines: 760 812 93.6 %
Date: 2026-06-03 14:29:06 Functions: 89 94 94.7 %
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      276635 : DistributedMesh::DistributedMesh (const Parallel::Communicator & comm_in,
      43      276635 :                                   unsigned char d) :
      44      276151 :   UnstructuredMesh (comm_in,d), _is_serial(true),
      45      276151 :   _is_serial_on_proc_0(true),
      46      276151 :   _deleted_coarse_elements(false),
      47      276151 :   _n_nodes(0), _n_elem(0), _max_node_id(0), _max_elem_id(0),
      48      276877 :   _next_free_local_node_id(this->processor_id()),
      49      276635 :   _next_free_local_elem_id(this->processor_id()),
      50      276635 :   _next_free_unpartitioned_node_id(this->n_processors()),
      51      276635 :   _next_free_unpartitioned_elem_id(this->n_processors())
      52             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
      53      276635 :   , _next_unpartitioned_unique_id(this->n_processors())
      54             : #endif
      55             : {
      56             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
      57      276635 :   _next_unique_id = this->processor_id();
      58             : #endif
      59             : 
      60      276877 :   const std::string default_partitioner = "parmetis";
      61             :   const std::string my_partitioner =
      62             :     libMesh::command_line_value("--default-partitioner",
      63      553270 :                                 default_partitioner);
      64             :   _partitioner = Partitioner::build
      65      553028 :     (Utility::string_to_enum<PartitionerType>(my_partitioner));
      66      276635 : }
      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      318532 : DistributedMesh::~DistributedMesh ()
     143             : {
     144      296783 :   this->DistributedMesh::clear();  // Free nodes and elements
     145      318532 : }
     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       17663 : DistributedMesh::DistributedMesh (const DistributedMesh & other_mesh) :
     152       17663 :   DistributedMesh(static_cast<const MeshBase &>(other_mesh))
     153             : {
     154       17663 :   _is_serial = other_mesh._is_serial;
     155       17663 :   _is_serial_on_proc_0 = other_mesh._is_serial_on_proc_0;
     156       17663 :   _deleted_coarse_elements = other_mesh._deleted_coarse_elements;
     157             : 
     158       17663 :   _n_nodes = other_mesh.n_nodes();
     159       17663 :   _n_elem  = other_mesh.n_elem();
     160       17663 :   _max_node_id = other_mesh.max_node_id();
     161       17663 :   _max_elem_id = other_mesh.max_elem_id();
     162       17663 :   _next_free_local_node_id =
     163       17663 :     other_mesh._next_free_local_node_id;
     164       17663 :   _next_free_local_elem_id =
     165       17663 :     other_mesh._next_free_local_elem_id;
     166       17663 :   _next_free_unpartitioned_node_id =
     167       17663 :     other_mesh._next_free_unpartitioned_node_id;
     168       17663 :   _next_free_unpartitioned_elem_id =
     169       17663 :     other_mesh._next_free_unpartitioned_elem_id;
     170             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
     171       17663 :   _next_unique_id =
     172       17663 :     other_mesh._next_unique_id;
     173       17663 :   _next_unpartitioned_unique_id =
     174       17663 :     other_mesh._next_unpartitioned_unique_id;
     175             : #endif
     176             : 
     177             :   // Need to copy extra_ghost_elems
     178       17663 :   for (auto & elem : other_mesh._extra_ghost_elems)
     179           0 :     _extra_ghost_elems.insert(this->elem_ptr(elem->id()));
     180       17663 : }
     181             : 
     182             : 
     183             : 
     184       20148 : DistributedMesh::DistributedMesh (const MeshBase & other_mesh) :
     185       20148 :   UnstructuredMesh (other_mesh), _is_serial(other_mesh.is_serial()),
     186       20236 :   _is_serial_on_proc_0(other_mesh.is_serial()),
     187       19972 :   _deleted_coarse_elements(true), // better safe than sorry...
     188       19972 :   _n_nodes(0), _n_elem(0), _max_node_id(0), _max_elem_id(0),
     189       20236 :   _next_free_local_node_id(this->processor_id()),
     190       20148 :   _next_free_local_elem_id(this->processor_id()),
     191       20148 :   _next_free_unpartitioned_node_id(this->n_processors()),
     192       40208 :   _next_free_unpartitioned_elem_id(this->n_processors())
     193             : {
     194             :   // Just copy, skipping preparation
     195       20148 :   this->copy_nodes_and_elements(other_mesh, true, 0, 0, 0, nullptr, true);
     196             : 
     197         176 :   this->allow_find_neighbors(other_mesh.allow_find_neighbors());
     198         176 :   this->allow_detect_interior_parents(other_mesh.allow_detect_interior_parents());
     199         176 :   this->allow_renumbering(other_mesh.allow_renumbering());
     200         176 :   this->allow_remote_element_removal(other_mesh.allow_remote_element_removal());
     201         176 :   this->skip_partitioning(other_mesh.skip_partitioning());
     202             : 
     203       20148 :   this->copy_constraint_rows(other_mesh);
     204             : 
     205       20148 :   this->_preparation = other_mesh.preparation();
     206             : 
     207          88 :   auto & this_boundary_info = this->get_boundary_info();
     208          88 :   const auto & other_boundary_info = other_mesh.get_boundary_info();
     209             : 
     210       20148 :   this_boundary_info = other_boundary_info;
     211             : 
     212          88 :   this->set_subdomain_name_map() = other_mesh.get_subdomain_name_map();
     213             : 
     214             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
     215       20148 :   _next_unique_id = other_mesh.parallel_max_unique_id() +
     216       20236 :                     this->processor_id();
     217       20236 :   _next_unpartitioned_unique_id = _next_unique_id +
     218       20148 :     (this->n_processors() - this->processor_id());
     219             : #endif
     220       20148 :   this->update_parallel_id_counts();
     221       20148 : }
     222             : 
     223         270 : void DistributedMesh::move_nodes_and_elements(MeshBase && other_meshbase)
     224             : {
     225           4 :   DistributedMesh & other_mesh = cast_ref<DistributedMesh&>(other_meshbase);
     226             : 
     227           4 :   this->_nodes = std::move(other_mesh._nodes);
     228         270 :   this->_n_nodes = other_mesh.n_nodes();
     229             : 
     230           4 :   this->_elements = std::move(other_mesh._elements);
     231         270 :   this->_n_elem = other_mesh.n_elem();
     232             : 
     233         270 :   _is_serial = other_mesh.is_serial();
     234         270 :   _is_serial_on_proc_0 = other_mesh.is_serial_on_zero();
     235         270 :   _deleted_coarse_elements = true; // Better safe than sorry
     236             : 
     237         270 :   _max_node_id = other_mesh.max_node_id();
     238         270 :   _max_elem_id = other_mesh.max_elem_id();
     239             : 
     240         270 :   _next_free_local_node_id = other_mesh._next_free_local_node_id;
     241         270 :   _next_free_local_elem_id = other_mesh._next_free_local_elem_id;
     242         270 :   _next_free_unpartitioned_node_id = other_mesh._next_free_unpartitioned_node_id;
     243         270 :   _next_free_unpartitioned_elem_id = other_mesh._next_free_unpartitioned_elem_id;
     244             : 
     245             :   #ifdef LIBMESH_ENABLE_UNIQUE_ID
     246         270 :   _next_unpartitioned_unique_id = other_mesh._next_unpartitioned_unique_id;
     247             :   #endif
     248         270 : }
     249             : 
     250             : // We use cached values for these so they can be called
     251             : // from one processor without bothering the rest, but
     252             : // we may need to update those caches before doing a full
     253             : // renumbering
     254     1709473 : void DistributedMesh::update_parallel_id_counts()
     255             : {
     256             :   // This function must be run on all processors at once
     257        1722 :   parallel_object_only();
     258             : 
     259     1709473 :   _n_elem  = this->parallel_n_elem();
     260     1709473 :   _n_nodes = this->parallel_n_nodes();
     261     1709473 :   _max_node_id = this->parallel_max_node_id();
     262     1709473 :   _max_elem_id = this->parallel_max_elem_id();
     263             : 
     264     1709473 :   if (_next_free_unpartitioned_elem_id < _max_elem_id)
     265       21546 :     _next_free_unpartitioned_elem_id =
     266       21546 :       ((_max_elem_id-1) / (this->n_processors() + 1) + 1) *
     267       21546 :       (this->n_processors() + 1) + this->n_processors();
     268     1709473 :   if (_next_free_local_elem_id < _max_elem_id)
     269       21054 :     _next_free_local_elem_id =
     270       21076 :       ((_max_elem_id + this->n_processors() - 1) / (this->n_processors() + 1) + 1) *
     271       21054 :       (this->n_processors() + 1) + this->processor_id();
     272             : 
     273     1709473 :   if (_next_free_unpartitioned_node_id < _max_node_id)
     274       28243 :     _next_free_unpartitioned_node_id =
     275       28243 :       ((_max_node_id-1) / (this->n_processors() + 1) + 1) *
     276       28243 :       (this->n_processors() + 1) + this->n_processors();
     277     1709473 :   if (_next_free_local_node_id < _max_node_id)
     278       28885 :     _next_free_local_node_id =
     279       28910 :       ((_max_node_id + this->n_processors() - 1) / (this->n_processors() + 1) + 1) *
     280       28885 :       (this->n_processors() + 1) + this->processor_id();
     281             : 
     282             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
     283     1709473 :   _next_unique_id = this->parallel_max_unique_id();
     284     1709473 :   _next_unpartitioned_unique_id =
     285     1711195 :     ((_next_unique_id-1) / (this->n_processors() + 1) + 1) *
     286     1709473 :     (this->n_processors() + 1) + this->n_processors();
     287     1709473 :   _next_unique_id =
     288     1709473 :     ((_next_unique_id + this->n_processors() - 1) / (this->n_processors() + 1) + 1) *
     289     1709473 :     (this->n_processors() + 1) + this->processor_id();
     290             : #endif
     291             : 
     292     1709473 :   this->_preparation.has_synched_id_counts = true;
     293     1709473 : }
     294             : 
     295             : 
     296             : // Or in debug mode we may want to test the uncached values without
     297             : // changing the cache
     298     1717184 : dof_id_type DistributedMesh::parallel_n_elem() const
     299             : {
     300             :   // This function must be run on all processors at once
     301        2556 :   parallel_object_only();
     302             : 
     303     1717184 :   dof_id_type n_local = this->n_local_elem();
     304     1717184 :   this->comm().sum(n_local);
     305     1717184 :   n_local += this->n_unpartitioned_elem();
     306     1717184 :   return n_local;
     307             : }
     308             : 
     309             : 
     310             : 
     311     1716351 : dof_id_type DistributedMesh::parallel_max_elem_id() const
     312             : {
     313             :   // This function must be run on all processors at once
     314        8600 :   parallel_object_only();
     315             : 
     316     1716351 :   dof_id_type max_local = 0;
     317             : 
     318             :   dofobject_container<Elem>::const_reverse_veclike_iterator
     319        8600 :     rit = _elements.rbegin();
     320             : 
     321             :   const dofobject_container<Elem>::const_reverse_veclike_iterator
     322        8600 :     rend = _elements.rend();
     323             : 
     324             :   // Look for the maximum element id.  Search backwards through
     325             :   // elements so we can break out early.  Beware of nullptr entries that
     326             :   // haven't yet been cleared from _elements.
     327    11135240 :   for (; rit != rend; ++rit)
     328             :     {
     329    10732337 :       const DofObject *d = *rit;
     330       18877 :       if (d)
     331             :         {
     332        8385 :           libmesh_assert(_elements[d->id()] == d);
     333     1313448 :           max_local = d->id() + 1;
     334     1313448 :           break;
     335             :         }
     336             :     }
     337             : 
     338     1716351 :   this->comm().max(max_local);
     339     1716351 :   return max_local;
     340             : }
     341             : 
     342             : 
     343             : 
     344             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
     345     1811325 : unique_id_type DistributedMesh::parallel_max_unique_id() const
     346             : {
     347             :   // This function must be run on all processors at once
     348        1840 :   parallel_object_only();
     349             : 
     350     3622650 :   unique_id_type max_local = std::max(_next_unique_id,
     351     2119723 :                                       _next_unpartitioned_unique_id);
     352     1811325 :   this->comm().max(max_local);
     353     1811325 :   return max_local;
     354             : }
     355             : 
     356             : 
     357             : 
     358       77744 : void DistributedMesh::set_next_unique_id(unique_id_type id)
     359             : {
     360         142 :   _next_unique_id = id;
     361       77744 :   _next_unpartitioned_unique_id =
     362       77886 :     ((_next_unique_id-1) / (this->n_processors() + 1) + 1) *
     363       77744 :     (this->n_processors() + 1) + this->n_processors();
     364       77744 :   _next_unique_id =
     365       77744 :     ((_next_unique_id + this->n_processors() - 1) / (this->n_processors() + 1) + 1) *
     366       77744 :     (this->n_processors() + 1) + this->processor_id();
     367       77744 : }
     368             : #endif
     369             : 
     370             : 
     371             : 
     372     1717632 : dof_id_type DistributedMesh::parallel_n_nodes() const
     373             : {
     374             :   // This function must be run on all processors at once
     375        2556 :   parallel_object_only();
     376             : 
     377     1717632 :   dof_id_type n_local = this->n_local_nodes();
     378     1717632 :   this->comm().sum(n_local);
     379     1717632 :   n_local += this->n_unpartitioned_nodes();
     380     1717632 :   return n_local;
     381             : }
     382             : 
     383             : 
     384             : 
     385     1713977 : dof_id_type DistributedMesh::parallel_max_node_id() const
     386             : {
     387             :   // This function must be run on all processors at once
     388        6226 :   parallel_object_only();
     389             : 
     390     1713977 :   dof_id_type max_local = 0;
     391             : 
     392             :   dofobject_container<Node>::const_reverse_veclike_iterator
     393        6226 :     rit = _nodes.rbegin();
     394             : 
     395             :   const dofobject_container<Node>::const_reverse_veclike_iterator
     396        6226 :     rend = _nodes.rend();
     397             : 
     398             :   // Look for the maximum node id.  Search backwards through
     399             :   // nodes so we can break out early.  Beware of nullptr entries that
     400             :   // haven't yet been cleared from _nodes
     401    39401767 :   for (; rit != rend; ++rit)
     402             :     {
     403    38998934 :       const DofObject *d = *rit;
     404       63161 :       if (d)
     405             :         {
     406        6081 :           libmesh_assert(_nodes[d->id()] == d);
     407     1311144 :           max_local = d->id() + 1;
     408     1311144 :           break;
     409             :         }
     410             :     }
     411             : 
     412     1713977 :   this->comm().max(max_local);
     413     1713977 :   return max_local;
     414             : }
     415             : 
     416             : 
     417             : 
     418    42431212 : const Point & DistributedMesh::point (const dof_id_type i) const
     419             : {
     420    42431212 :   return this->node_ref(i);
     421             : }
     422             : 
     423             : 
     424             : 
     425    43536601 : const Node * DistributedMesh::node_ptr (const dof_id_type i) const
     426             : {
     427      136653 :   libmesh_assert(_nodes[i]);
     428      136653 :   libmesh_assert_equal_to (_nodes[i]->id(), i);
     429             : 
     430    43536601 :   return _nodes[i];
     431             : }
     432             : 
     433             : 
     434             : 
     435             : 
     436   734214004 : Node * DistributedMesh::node_ptr (const dof_id_type i)
     437             : {
     438      541258 :   libmesh_assert(_nodes[i]);
     439      541258 :   libmesh_assert_equal_to (_nodes[i]->id(), i);
     440             : 
     441   734214004 :   return _nodes[i];
     442             : }
     443             : 
     444             : 
     445             : 
     446             : 
     447     3114230 : const Node * DistributedMesh::query_node_ptr (const dof_id_type i) const
     448             : {
     449     3114230 :   if (const auto it = _nodes.find(i);
     450      662507 :       it != _nodes.end())
     451             :     {
     452     2820162 :       const Node * n = *it;
     453      368439 :       libmesh_assert (!n || n->id() == i);
     454      368439 :       return n;
     455             :     }
     456             : 
     457      294068 :   return nullptr;
     458             : }
     459             : 
     460             : 
     461             : 
     462             : 
     463   367281329 : Node * DistributedMesh::query_node_ptr (const dof_id_type i)
     464             : {
     465   367281329 :   if (auto it = _nodes.find(i);
     466      159224 :       it != _nodes.end())
     467             :     {
     468   284558487 :       Node * n = *it;
     469      111971 :       libmesh_assert (!n || n->id() == i);
     470      111971 :       return n;
     471             :     }
     472             : 
     473       47253 :   return nullptr;
     474             : }
     475             : 
     476             : 
     477             : 
     478             : 
     479     3049564 : const Elem * DistributedMesh::elem_ptr (const dof_id_type i) const
     480             : {
     481       10062 :   libmesh_assert(_elements[i]);
     482       10062 :   libmesh_assert_equal_to (_elements[i]->id(), i);
     483             : 
     484     3049564 :   return _elements[i];
     485             : }
     486             : 
     487             : 
     488             : 
     489             : 
     490   286875120 : Elem * DistributedMesh::elem_ptr (const dof_id_type i)
     491             : {
     492      167219 :   libmesh_assert(_elements[i]);
     493      167219 :   libmesh_assert_equal_to (_elements[i]->id(), i);
     494             : 
     495   286875120 :   return _elements[i];
     496             : }
     497             : 
     498             : 
     499             : 
     500             : 
     501     1474667 : const Elem * DistributedMesh::query_elem_ptr (const dof_id_type i) const
     502             : {
     503     1474667 :   if (const auto it = _elements.find(i);
     504      636453 :       it != _elements.end())
     505             :     {
     506     1098550 :       const Elem * e = *it;
     507      269217 :       libmesh_assert (!e || e->id() == i);
     508      269217 :       return e;
     509             :     }
     510             : 
     511      367236 :   return nullptr;
     512             : }
     513             : 
     514             : 
     515             : 
     516             : 
     517   603557308 : Elem * DistributedMesh::query_elem_ptr (const dof_id_type i)
     518             : {
     519   603557308 :   if (auto it = _elements.find(i);
     520      194370 :       it != _elements.end())
     521             :     {
     522   518040619 :       Elem * e = *it;
     523      190691 :       libmesh_assert (!e || e->id() == i);
     524      190691 :       return e;
     525             :     }
     526             : 
     527        3679 :   return nullptr;
     528             : }
     529             : 
     530             : 
     531             : 
     532             : 
     533    44036151 : Elem * DistributedMesh::add_elem (Elem * e)
     534             : {
     535             :   // Don't try to add nullptrs!
     536       18881 :   libmesh_assert(e);
     537             : 
     538             :   // Trying to add an existing element is a no-op
     539    44036151 :   if (e->valid_id() && _elements[e->id()] == e)
     540           0 :     return e;
     541             : 
     542    44036151 :   const processor_id_type elem_procid = e->processor_id();
     543             : 
     544    44036151 :   if (!e->valid_id())
     545             :     {
     546             :       // We should only be creating new ids past the end of the range
     547             :       // of existing ids
     548        3568 :       libmesh_assert_greater_equal(_next_free_unpartitioned_elem_id,
     549             :                                    _max_elem_id);
     550        3568 :       libmesh_assert_greater_equal(_next_free_local_elem_id, _max_elem_id);
     551             : 
     552             :       // Use the unpartitioned ids for unpartitioned elems, and
     553             :       // temporarily for ghost elems
     554     3857269 :       dof_id_type * next_id = &_next_free_unpartitioned_elem_id;
     555     3860837 :       if (elem_procid == this->processor_id())
     556     1133564 :         next_id = &_next_free_local_elem_id;
     557     3857269 :       e->set_id (*next_id);
     558             :     }
     559             : 
     560             :   {
     561             :     // Advance next_ids up high enough that each is pointing to an
     562             :     // unused id and any subsequent increments will still point us
     563             :     // to unused ids
     564    88072302 :     _max_elem_id = std::max(_max_elem_id,
     565    44036151 :                             static_cast<dof_id_type>(e->id()+1));
     566             : 
     567    44036151 :     if (_next_free_unpartitioned_elem_id < _max_elem_id)
     568     5138781 :       _next_free_unpartitioned_elem_id =
     569     5138781 :         ((_max_elem_id-1) / (this->n_processors() + 1) + 1) *
     570     5138781 :         (this->n_processors() + 1) + this->n_processors();
     571    44036151 :     if (_next_free_local_elem_id < _max_elem_id)
     572     3445697 :       _next_free_local_elem_id =
     573     3451937 :         ((_max_elem_id + this->n_processors() - 1) / (this->n_processors() + 1) + 1) *
     574     3445697 :         (this->n_processors() + 1) + this->processor_id();
     575             : 
     576             : #ifndef NDEBUG
     577             :     // We need a const dofobject_container so we don't inadvertently create
     578             :     // nullptr entries when testing for non-nullptr ones
     579       18881 :     const dofobject_container<Elem> & const_elements = _elements;
     580             : #endif
     581       18881 :     libmesh_assert(!const_elements[_next_free_unpartitioned_elem_id]);
     582       18881 :     libmesh_assert(!const_elements[_next_free_local_elem_id]);
     583             :   }
     584             : 
     585             :   // Don't try to overwrite existing elems
     586       18881 :   libmesh_assert (!_elements[e->id()]);
     587             : 
     588    44036151 :   _elements[e->id()] = e;
     589             : 
     590             :   // We actually added a new element.  Some of our caches might still
     591             :   // be valid, but we should clear the ones which definitely are not.
     592    44036151 :   this->clear_point_locator();
     593    44036151 :   this->clear_stored_ranges();
     594             : 
     595             :   // Try to make the cached elem data more accurate
     596    44055032 :   if (elem_procid == this->processor_id() ||
     597             :       elem_procid == DofObject::invalid_processor_id)
     598    12902933 :     _n_elem++;
     599             : 
     600             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
     601    44036151 :   if (!e->valid_unique_id())
     602             :     {
     603    13500311 :       if (processor_id() == e->processor_id())
     604             :         {
     605     1133564 :           e->set_unique_id(_next_unique_id);
     606     1133564 :           _next_unique_id += this->n_processors() + 1;
     607             :         }
     608             :       else
     609             :         {
     610    12366747 :           e->set_unique_id(_next_unpartitioned_unique_id);
     611    12366747 :           _next_unpartitioned_unique_id += this->n_processors() + 1;
     612             :         }
     613             :     }
     614             :   else
     615             :     {
     616    30560078 :       _next_unique_id = std::max(_next_unique_id, e->unique_id()+1);
     617    30535840 :       _next_unique_id =
     618    30535840 :         ((_next_unique_id + this->n_processors() - 1) / (this->n_processors() + 1) + 1) *
     619    30535840 :         (this->n_processors() + 1) + this->processor_id();
     620             :     }
     621             : #endif
     622             : 
     623             :   // Unpartitioned elems should be added on every processor
     624             :   // And shouldn't be added in the same batch as ghost elems
     625             :   // But we might be just adding on processor 0 to
     626             :   // broadcast later
     627             :   // #ifdef DEBUG
     628             :   //   if (elem_procid == DofObject::invalid_processor_id)
     629             :   //     {
     630             :   //       dof_id_type elem_id = e->id();
     631             :   //       this->comm().max(elem_id);
     632             :   //       libmesh_assert_equal_to (elem_id, e->id());
     633             :   //     }
     634             :   // #endif
     635             : 
     636             :   // Make sure any new element is given space for any extra integers
     637             :   // we've requested
     638    44036151 :   e->add_extra_integers(_elem_integer_names.size(),
     639    44036151 :                         _elem_integer_default_values);
     640             : 
     641             :   // And set mapping type and data on any new element
     642       37762 :   e->set_mapping_type(this->default_mapping_type());
     643       37762 :   e->set_mapping_data(this->default_mapping_data());
     644             : 
     645    44036151 :   return e;
     646             : }
     647             : 
     648             : 
     649             : 
     650    14735595 : Elem * DistributedMesh::add_elem (std::unique_ptr<Elem> e)
     651             : {
     652             :   // The mesh now takes ownership of the Elem. Eventually the guts of
     653             :   // add_elem() will get moved to a private helper function, and
     654             :   // calling add_elem() directly will be deprecated.
     655    14735595 :   return add_elem(e.release());
     656             : }
     657             : 
     658             : 
     659             : 
     660     3348460 : Elem * DistributedMesh::insert_elem (Elem * e)
     661             : {
     662     3348460 :   if (_elements[e->id()])
     663     3348460 :     this->delete_elem(_elements[e->id()]);
     664             : 
     665             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
     666     3348460 :   if (!e->valid_unique_id())
     667             :     {
     668           0 :       if (processor_id() == e->processor_id())
     669             :         {
     670           0 :           e->set_unique_id(_next_unique_id);
     671           0 :           _next_unique_id += this->n_processors() + 1;
     672             :         }
     673             :       else
     674             :         {
     675           0 :           e->set_unique_id(_next_unpartitioned_unique_id);
     676           0 :           _next_unpartitioned_unique_id += this->n_processors() + 1;
     677             :         }
     678             :     }
     679             :   else
     680             :     {
     681     3373838 :       _next_unique_id = std::max(_next_unique_id, e->unique_id()+1);
     682     3348460 :       _next_unique_id =
     683     3352156 :         ((_next_unique_id + this->n_processors() - 1) / (this->n_processors() + 1) + 1) *
     684     3348460 :         (this->n_processors() + 1) + this->processor_id();
     685             :     }
     686             : #endif
     687             : 
     688             :   // Try to make the cached elem data more accurate
     689     3348460 :   processor_id_type elem_procid = e->processor_id();
     690     3352156 :   if (elem_procid == this->processor_id() ||
     691             :       elem_procid == DofObject::invalid_processor_id)
     692     3219384 :     _n_elem++;
     693             : 
     694     3348460 :   _elements[e->id()] = e;
     695             : 
     696             :   // We actually added a new element.  Some of our caches might still
     697             :   // be valid, but we should clear the ones which definitely are not.
     698     3348460 :   this->clear_point_locator();
     699     3348460 :   this->clear_stored_ranges();
     700             : 
     701             :   // Make sure any new element is given space for any extra integers
     702             :   // we've requested
     703     3348460 :   e->add_extra_integers(_elem_integer_names.size(),
     704     3348460 :                         _elem_integer_default_values);
     705             : 
     706             :   // And set mapping type and data on any new element
     707        7392 :   e->set_mapping_type(this->default_mapping_type());
     708        7392 :   e->set_mapping_data(this->default_mapping_data());
     709             : 
     710     3348460 :   return e;
     711             : }
     712             : 
     713     3348460 : Elem * DistributedMesh::insert_elem (std::unique_ptr<Elem> e)
     714             : {
     715             :   // The mesh now takes ownership of the Elem. Eventually the guts of
     716             :   // insert_elem(Elem*) will get moved to a private helper function, and
     717             :   // calling insert_elem(Elem*) directly will be deprecated.
     718     3348460 :   return insert_elem(e.release());
     719             : }
     720             : 
     721             : 
     722    40088130 : void DistributedMesh::delete_elem(Elem * e)
     723             : {
     724        7586 :   libmesh_assert (e);
     725             : 
     726             :   // Try to make the cached elem data more accurate
     727    40088130 :   _n_elem--;
     728             : 
     729             :   // Was this a coarse element, not just a coarsening where we still
     730             :   // have some ancestor structure?  Was it a *local* element, that we
     731             :   // might have been depending on as an owner of local nodes?  We'll
     732             :   // have to be more careful with our nodes in contract() later; no
     733             :   // telling if we just locally orphaned a node that should be
     734             :   // globally retained.
     735    40097536 :   if (e->processor_id() == this->processor_id() &&
     736        3640 :       !e->parent())
     737       80473 :     _deleted_coarse_elements = true;
     738             : 
     739             :   // Delete the element from the BoundaryInfo object
     740    40088130 :   this->get_boundary_info().remove(e);
     741             : 
     742             :   // But not yet from the container; we might invalidate
     743             :   // an iterator that way!
     744             : 
     745             :   //_elements.erase(e->id());
     746             : 
     747             :   // Instead, we set it to nullptr for now
     748             : 
     749    40088130 :   _elements[e->id()] = nullptr;
     750             : 
     751             :   // delete the element
     752    40088130 :   delete e;
     753             : 
     754             :   // Some of our caches might still be valid, but we should clear the
     755             :   // ones which definitely are not.
     756    40088130 :   this->clear_point_locator();
     757    40088130 :   this->clear_stored_ranges();
     758    40088130 : }
     759             : 
     760             : 
     761             : 
     762     3207800 : void DistributedMesh::renumber_elem(const dof_id_type old_id,
     763             :                                     const dof_id_type new_id)
     764             : {
     765             :   // This could be a no-op
     766     3207800 :   if (old_id == new_id)
     767           0 :     return;
     768             : 
     769     3207800 :   Elem * el = _elements[old_id];
     770        1160 :   libmesh_assert (el);
     771        1160 :   libmesh_assert_equal_to (el->id(), old_id);
     772             : 
     773     3207800 :   el->set_id(new_id);
     774        1160 :   libmesh_assert (!_elements[new_id]);
     775     3207800 :   _elements[new_id] = el;
     776     3207800 :   _elements.erase(old_id);
     777             : 
     778             :   // Should we delete any caches here?  Our point locator indexes by
     779             :   // element pointer and should be fine with an id change.  Our stored
     780             :   // ranges are no longer sorted, which is *probably* fine, but let's
     781             :   // just be safe.
     782     3207800 :   this->clear_stored_ranges();
     783             : }
     784             : 
     785             : 
     786             : 
     787    40929334 : Node * DistributedMesh::add_point (const Point & p,
     788             :                                    const dof_id_type id,
     789             :                                    const processor_id_type proc_id)
     790             : {
     791    40929334 :   Node * old_n = this->query_node_ptr(id);
     792             : 
     793    40929334 :   if (old_n)
     794             :     {
     795           0 :       *old_n = p;
     796           0 :       old_n->processor_id() = proc_id;
     797             : 
     798           0 :       return old_n;
     799             :     }
     800             : 
     801    40889579 :   Node * n = Node::build(p, id).release();
     802    40929334 :   n->processor_id() = proc_id;
     803             : 
     804    40929334 :   return DistributedMesh::add_node(n);
     805             : }
     806             : 
     807             : 
     808        4130 : void DistributedMesh::own_node (Node & n)
     809             : {
     810             :   // This had better be a node in our mesh
     811           0 :   libmesh_assert(_nodes[n.id()] == &n);
     812             : 
     813        4130 :   _nodes[n.id()] = nullptr;
     814        4130 :   _n_nodes--;
     815             : 
     816           0 :   n.set_id(DofObject::invalid_id);
     817        4130 :   n.processor_id() = this->processor_id();
     818             : 
     819        4130 :   this->add_node(&n);
     820        4130 : }
     821             : 
     822             : 
     823    71701873 : Node * DistributedMesh::add_node (Node * n)
     824             : {
     825             :   // Don't try to add nullptrs!
     826       41467 :   libmesh_assert(n);
     827             : 
     828             :   // Trying to add an existing node is a no-op
     829    71701873 :   if (n->valid_id() && _nodes[n->id()] == n)
     830           0 :     return n;
     831             : 
     832    71701873 :   const processor_id_type node_procid = n->processor_id();
     833             : 
     834    71701873 :   if (!n->valid_id())
     835             :     {
     836             :       // We should only be creating new ids past the end of the range
     837             :       // of existing ids
     838       17829 :       libmesh_assert_greater_equal(_next_free_unpartitioned_node_id,
     839             :                                    _max_node_id);
     840       17829 :       libmesh_assert_greater_equal(_next_free_local_node_id, _max_node_id);
     841             : 
     842             :       // Use the unpartitioned ids for unpartitioned nodes,
     843             :       // and temporarily for ghost nodes
     844    17183188 :       dof_id_type * next_id = &_next_free_unpartitioned_node_id;
     845    17201017 :       if (node_procid == this->processor_id())
     846     2128337 :         next_id = &_next_free_local_node_id;
     847    17183188 :       n->set_id (*next_id);
     848             :     }
     849             : 
     850             :   {
     851             :     // Advance next_ids up high enough that each is pointing to an
     852             :     // unused id and any subsequent increments will still point us
     853             :     // to unused ids
     854   143403746 :     _max_node_id = std::max(_max_node_id,
     855    71701873 :                             static_cast<dof_id_type>(n->id()+1));
     856             : 
     857    71701873 :     if (_next_free_unpartitioned_node_id < _max_node_id)
     858    20102498 :       _next_free_unpartitioned_node_id =
     859    20102498 :         ((_max_node_id-1) / (this->n_processors() + 1) + 1) *
     860    20102498 :         (this->n_processors() + 1) + this->n_processors();
     861    71701873 :     if (_next_free_local_node_id < _max_node_id)
     862    11711351 :       _next_free_local_node_id =
     863    11729147 :         ((_max_node_id + this->n_processors() - 1) / (this->n_processors() + 1) + 1) *
     864    11711351 :         (this->n_processors() + 1) + this->processor_id();
     865             : 
     866             : #ifndef NDEBUG
     867             :     // We need a const dofobject_container so we don't inadvertently create
     868             :     // nullptr entries when testing for non-nullptr ones
     869       41467 :     const dofobject_container<Node> & const_nodes = _nodes;
     870             : #endif
     871       41467 :     libmesh_assert(!const_nodes[_next_free_unpartitioned_node_id]);
     872       41467 :     libmesh_assert(!const_nodes[_next_free_local_node_id]);
     873             :   }
     874             : 
     875             :   // Don't try to overwrite existing nodes
     876       41467 :   libmesh_assert (!_nodes[n->id()]);
     877             : 
     878    71701873 :   _nodes[n->id()] = n;
     879             : 
     880             :   // Try to make the cached node data more accurate
     881    71743340 :   if (node_procid == this->processor_id() ||
     882             :       node_procid == DofObject::invalid_processor_id)
     883    38515799 :     _n_nodes++;
     884             : 
     885             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
     886    71701873 :   if (!n->valid_unique_id())
     887             :     {
     888    40931062 :       if (processor_id() == n->processor_id())
     889             :         {
     890     2544599 :           n->set_unique_id(_next_unique_id);
     891     2544599 :           _next_unique_id += this->n_processors() + 1;
     892             :         }
     893             :       else
     894             :         {
     895    38386463 :           n->set_unique_id(_next_unpartitioned_unique_id);
     896    38386463 :           _next_unpartitioned_unique_id += this->n_processors() + 1;
     897             :         }
     898             :     }
     899             :   else
     900             :     {
     901    30901256 :       _next_unique_id = std::max(_next_unique_id, n->unique_id()+1);
     902    30770811 :       _next_unique_id =
     903    30770811 :         ((_next_unique_id + this->n_processors() - 1) / (this->n_processors() + 1) + 1) *
     904    30770811 :         (this->n_processors() + 1) + this->processor_id();
     905             :     }
     906             : #endif
     907             : 
     908    71701873 :   n->add_extra_integers(_node_integer_names.size(),
     909    71701873 :                         _node_integer_default_values);
     910             : 
     911             :   // Unpartitioned nodes should be added on every processor
     912             :   // And shouldn't be added in the same batch as ghost nodes
     913             :   // But we might be just adding on processor 0 to
     914             :   // broadcast later
     915             :   // #ifdef DEBUG
     916             :   //   if (node_procid == DofObject::invalid_processor_id)
     917             :   //     {
     918             :   //       dof_id_type node_id = n->id();
     919             :   //       this->comm().max(node_id);
     920             :   //       libmesh_assert_equal_to (node_id, n->id());
     921             :   //     }
     922             :   // #endif
     923             : 
     924    71701873 :   return n;
     925             : }
     926             : 
     927    30768409 : Node * DistributedMesh::add_node (std::unique_ptr<Node> n)
     928             : {
     929             :   // The mesh now takes ownership of the Node. Eventually the guts of
     930             :   // add_node() will get moved to a private helper function, and
     931             :   // calling add_node() directly will be deprecated.
     932    30768409 :   return add_node(n.release());
     933             : }
     934             : 
     935    50479443 : void DistributedMesh::delete_node(Node * n)
     936             : {
     937        4461 :   libmesh_assert(n);
     938        4461 :   libmesh_assert(_nodes[n->id()]);
     939             : 
     940             :   // Try to make the cached elem data more accurate
     941    50479443 :   _n_nodes--;
     942             : 
     943             :   // Delete the node from the BoundaryInfo object
     944    50479443 :   this->get_boundary_info().remove(n);
     945        8922 :   _constraint_rows.erase(n);
     946             : 
     947             :   // But not yet from the container; we might invalidate
     948             :   // an iterator that way!
     949             : 
     950             :   //_nodes.erase(n->id());
     951             : 
     952             :   // Instead, we set it to nullptr for now
     953             : 
     954    50479443 :   _nodes[n->id()] = nullptr;
     955             : 
     956             :   // delete the node
     957    50479443 :   delete n;
     958    50479443 : }
     959             : 
     960             : 
     961             : 
     962     6897011 : void DistributedMesh::renumber_node(const dof_id_type old_id,
     963             :                                     const dof_id_type new_id)
     964             : {
     965             :   // This could be a no-op
     966     6897011 :   if (old_id == new_id)
     967           0 :     return;
     968             : 
     969     6896419 :   Node * nd = _nodes[old_id];
     970        3234 :   libmesh_assert (nd);
     971        3234 :   libmesh_assert_equal_to (nd->id(), old_id);
     972             : 
     973             :   // If we have nodes shipped to this processor for NodeConstraints
     974             :   // use, then those nodes will exist in _nodes, but may not be
     975             :   // locatable via a TopologyMap due to the insufficiency of elements
     976             :   // connecting to them.  If local refinement then wants to create a
     977             :   // *new* node in the same location, it will initially get a temporary
     978             :   // id, and then make_node_ids_parallel_consistent() will try to move
     979             :   // it to the canonical id.  We need to account for this case to
     980             :   // avoid false positives and memory leaks.
     981             : #ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS
     982        6468 :   if (_nodes[new_id])
     983             :     {
     984           0 :       libmesh_assert_equal_to (*(Point *)_nodes[new_id],
     985             :                                *(Point *)_nodes[old_id]);
     986           0 :       _nodes.erase(new_id);
     987             :     }
     988             : #else
     989             :   // If we aren't shipping nodes for NodeConstraints, there should be
     990             :   // no reason for renumbering one node onto another.
     991             :   libmesh_assert (!_nodes[new_id]);
     992             : #endif
     993     6896419 :   _nodes[new_id] = nd;
     994     6896419 :   nd->set_id(new_id);
     995             : 
     996     6896419 :   _nodes.erase(old_id);
     997             : }
     998             : 
     999             : 
    1000             : 
    1001      554311 : void DistributedMesh::clear ()
    1002             : {
    1003             :   // Call parent clear function
    1004      554311 :   MeshBase::clear();
    1005             : 
    1006             :   // Clear our elements and nodes
    1007             :   // There is no need to remove them from
    1008             :   // the BoundaryInfo data structure since we
    1009             :   // already cleared it.
    1010      554311 :   this->DistributedMesh::clear_elems();
    1011             : 
    1012    23248916 :   for (auto & node : _nodes)
    1013    41549634 :     delete node;
    1014             : 
    1015         564 :   _nodes.clear();
    1016             : 
    1017             :   // We're no longer distributed if we were before
    1018      554311 :   _is_serial = true;
    1019      554311 :   _is_serial_on_proc_0 = true;
    1020             : 
    1021             :   // We deleted a ton of coarse elements, but their nodes got deleted too so
    1022             :   // all is copacetic.
    1023      554311 :   _deleted_coarse_elements = false;
    1024             : 
    1025             :   // Correct our caches
    1026      554311 :   _n_nodes = 0;
    1027      554311 :   _max_node_id = 0;
    1028      554875 :   _next_free_local_node_id = this->processor_id();
    1029      554311 :   _next_free_unpartitioned_node_id = this->n_processors();
    1030      554311 : }
    1031             : 
    1032             : 
    1033             : 
    1034      560327 : void DistributedMesh::clear_elems ()
    1035             : {
    1036     9340987 :   for (auto & elem : _elements)
    1037     8780660 :     delete elem;
    1038             : 
    1039         564 :   _elements.clear();
    1040             : 
    1041             :   // Correct our caches
    1042      560327 :   _n_elem = 0;
    1043      560327 :   _max_elem_id = 0;
    1044      560891 :   _next_free_local_elem_id = this->processor_id();
    1045      560327 :   _next_free_unpartitioned_elem_id = this->n_processors();
    1046      560327 : }
    1047             : 
    1048             : 
    1049             : 
    1050      553573 : void DistributedMesh::redistribute ()
    1051             : {
    1052             :   // If this is a truly parallel mesh, go through the redistribution/gather/delete remote steps
    1053      553573 :   if (!this->is_serial())
    1054             :     {
    1055             :       // Construct a MeshCommunication object to actually redistribute the nodes
    1056             :       // and elements according to the partitioner, and then to re-gather the neighbors.
    1057             :       MeshCommunication mc;
    1058       68133 :       mc.redistribute(*this);
    1059             : 
    1060       68133 :       this->update_parallel_id_counts();
    1061             : 
    1062             :       // We ought to still have valid neighbor links; we communicate
    1063             :       // them for newly-redistributed elements
    1064             :       // this->find_neighbors();
    1065             : 
    1066             :       // Is this necessary?  If we are called from prepare_for_use(), this will be called
    1067             :       // anyway... but users can always call partition directly, in which case we do need
    1068             :       // to call delete_remote_elements()...
    1069             :       //
    1070             :       // Regardless of whether it's necessary, it isn't safe.  We
    1071             :       // haven't communicated new node processor_ids yet, and we can't
    1072             :       // delete nodes until we do.
    1073             :       // this->delete_remote_elements();
    1074             :     }
    1075             :   else
    1076             :     // The base class can handle non-distributed things, like
    1077             :     // notifying any GhostingFunctors of changes
    1078      485440 :     MeshBase::redistribute();
    1079      553573 : }
    1080             : 
    1081             : 
    1082             : 
    1083      475630 : void DistributedMesh::update_post_partitioning ()
    1084             : {
    1085             :   // this->recalculate_n_partitions();
    1086             : 
    1087             :   // Let's do the base class cache clearing first, just in case our
    1088             :   // later computations are ever changed to make use of a local
    1089             :   // elements range cache
    1090      475630 :   this->MeshBase::update_post_partitioning();
    1091             : 
    1092             :   // Partitioning changes our numbers of unpartitioned objects
    1093      475630 :   this->update_parallel_id_counts();
    1094      475630 : }
    1095             : 
    1096             : 
    1097             : 
    1098             : template <typename T>
    1099        3300 : void DistributedMesh::libmesh_assert_valid_parallel_object_ids(const dofobject_container<T> & objects) const
    1100             : {
    1101             :   // This function must be run on all processors at once
    1102        3300 :   parallel_object_only();
    1103             : 
    1104        3300 :   const dof_id_type pmax_node_id = this->parallel_max_node_id();
    1105        3300 :   const dof_id_type pmax_elem_id = this->parallel_max_elem_id();
    1106        3300 :   const dof_id_type pmax_id = std::max(pmax_node_id, pmax_elem_id);
    1107             : 
    1108      906732 :   for (dof_id_type i=0; i != pmax_id; ++i)
    1109             :     {
    1110      903432 :       T * obj = objects[i]; // Returns nullptr if there's no map entry
    1111             : 
    1112             :       // Local lookups by id should return the requested object
    1113      903432 :       libmesh_assert(!obj || obj->id() == i);
    1114             : 
    1115             :       // All processors with an object should agree on id
    1116             : #ifndef NDEBUG
    1117      903432 :       const dof_id_type dofid = obj && obj->valid_id() ?
    1118             :         obj->id() : DofObject::invalid_id;
    1119      903432 :       libmesh_assert(this->comm().semiverify(obj ? &dofid : nullptr));
    1120             : #endif
    1121             : 
    1122             :       // All processors with an object should agree on processor id
    1123      903432 :       const dof_id_type procid = obj && obj->valid_processor_id() ?
    1124             :         obj->processor_id() : DofObject::invalid_processor_id;
    1125      903432 :       libmesh_assert(this->comm().semiverify(obj ? &procid : nullptr));
    1126             : 
    1127      903432 :       dof_id_type min_procid = procid;
    1128      903432 :       this->comm().min(min_procid);
    1129             : 
    1130             :       // Either:
    1131             :       // 1.) I own this elem (min_procid == this->processor_id()) *and* I have a valid pointer to it (obj != nullptr)
    1132             :       // or
    1133             :       // 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.)
    1134             : 
    1135             :       // Original assert logic
    1136             :       // libmesh_assert (min_procid != this->processor_id() || obj);
    1137             : 
    1138             :       // More human-understandable logic...
    1139      903432 :       libmesh_assert (
    1140             :                       ((min_procid == this->processor_id()) && obj)
    1141             :                       ||
    1142             :                       (min_procid != this->processor_id())
    1143             :                       );
    1144             : 
    1145             : #if defined(LIBMESH_ENABLE_UNIQUE_ID) && !defined(NDEBUG)
    1146             :       // All processors with an object should agree on unique id
    1147      903432 :       const unique_id_type uniqueid = obj ? obj->unique_id() : 0;
    1148      903432 :       libmesh_assert(this->comm().semiverify(obj ? &uniqueid : nullptr));
    1149             : #endif
    1150             :     }
    1151        3300 : }
    1152             : 
    1153             : 
    1154             : 
    1155        1650 : void DistributedMesh::libmesh_assert_valid_parallel_ids () const
    1156             : {
    1157        1650 :   this->libmesh_assert_valid_parallel_object_ids (this->_elements);
    1158        1650 :   this->libmesh_assert_valid_parallel_object_ids (this->_nodes);
    1159        1650 : }
    1160             : 
    1161             : 
    1162             : 
    1163         394 : void DistributedMesh::libmesh_assert_valid_parallel_p_levels () const
    1164             : {
    1165             : #ifndef NDEBUG
    1166             :   // This function must be run on all processors at once
    1167         394 :   parallel_object_only();
    1168             : 
    1169         394 :   dof_id_type pmax_elem_id = this->parallel_max_elem_id();
    1170             : 
    1171       21872 :   for (dof_id_type i=0; i != pmax_elem_id; ++i)
    1172             :     {
    1173       21478 :       Elem * el = _elements[i]; // Returns nullptr if there's no map entry
    1174             : 
    1175       21478 :       unsigned int p_level = el ?  (el->p_level()) : libMesh::invalid_uint;
    1176             : 
    1177             :       // All processors with an active element should agree on p level
    1178       21478 :       libmesh_assert(this->comm().semiverify((el && el->active()) ? &p_level : nullptr));
    1179             :     }
    1180             : #endif
    1181         394 : }
    1182             : 
    1183             : 
    1184             : 
    1185             : 
    1186        1598 : void DistributedMesh::libmesh_assert_valid_parallel_flags () const
    1187             : {
    1188             : #if defined(LIBMESH_ENABLE_AMR) && !defined(NDEBUG)
    1189             :   // This function must be run on all processors at once
    1190        1598 :   parallel_object_only();
    1191             : 
    1192        1598 :   dof_id_type pmax_elem_id = this->parallel_max_elem_id();
    1193             : 
    1194      148394 :   for (dof_id_type i=0; i != pmax_elem_id; ++i)
    1195             :     {
    1196      146796 :       Elem * el = _elements[i]; // Returns nullptr if there's no map entry
    1197             : 
    1198      146796 :       unsigned int refinement_flag   = el ?
    1199       65517 :         static_cast<unsigned int> (el->refinement_flag()) : libMesh::invalid_uint;
    1200      146796 :       unsigned int p_refinement_flag = el ?
    1201       65517 :         static_cast<unsigned int> (el->p_refinement_flag()) : libMesh::invalid_uint;
    1202             : 
    1203      146796 :       libmesh_assert(this->comm().semiverify(el ? &refinement_flag : nullptr));
    1204             : 
    1205             :       // p refinement flags aren't always kept correct on inactive
    1206             :       // ghost elements
    1207      146796 :       libmesh_assert(this->comm().semiverify((el && el->active()) ? &p_refinement_flag : nullptr));
    1208             :     }
    1209             : #endif // LIBMESH_ENABLE_AMR
    1210        1598 : }
    1211             : 
    1212             : 
    1213             : 
    1214             : template <typename T>
    1215             : dof_id_type
    1216     1353094 : DistributedMesh::renumber_dof_objects(dofobject_container<T> & objects)
    1217             : {
    1218             :   // This function must be run on all processors at once
    1219         784 :   parallel_object_only();
    1220             : 
    1221             :   typedef typename dofobject_container<T>::veclike_iterator object_iterator;
    1222             : 
    1223             :   // In parallel we may not know what objects other processors have.
    1224             :   // Start by figuring out how many
    1225         784 :   dof_id_type unpartitioned_objects = 0;
    1226             : 
    1227             :   std::unordered_map<processor_id_type, dof_id_type>
    1228        1568 :     ghost_objects_from_proc;
    1229             : 
    1230     1353094 :   object_iterator it  = objects.begin();
    1231         784 :   object_iterator end = objects.end();
    1232             : 
    1233   103993340 :   while (it != end)
    1234             :     {
    1235   102640246 :       T * obj = *it;
    1236             : 
    1237             :       // Remove any nullptr container entries while we're here.
    1238   102640246 :       if (!obj)
    1239     1288570 :         it = objects.erase(it);
    1240             :       else
    1241             :         {
    1242   101351676 :           processor_id_type obj_procid = obj->processor_id();
    1243   101351676 :           if (obj_procid == DofObject::invalid_processor_id)
    1244    42383115 :             unpartitioned_objects++;
    1245             :           else
    1246    58968561 :             ghost_objects_from_proc[obj_procid]++;
    1247             : 
    1248             :           // Finally, increment the iterator
    1249       56228 :           ++it;
    1250             :         }
    1251             :     }
    1252             : 
    1253     1354662 :   std::vector<dof_id_type> objects_on_proc(this->n_processors(), 0);
    1254     1353878 :   auto this_it = ghost_objects_from_proc.find(this->processor_id());
    1255         784 :   this->comm().allgather
    1256     1353577 :     ((this_it == ghost_objects_from_proc.end()) ?
    1257         483 :      dof_id_type(0) : this_it->second, objects_on_proc);
    1258             : 
    1259             : #ifndef NDEBUG
    1260         784 :   libmesh_assert(this->comm().verify(unpartitioned_objects));
    1261        2352 :   for (processor_id_type p=0, np=this->n_processors(); p != np; ++p)
    1262        1568 :     if (ghost_objects_from_proc.count(p))
    1263         938 :       libmesh_assert_less_equal (ghost_objects_from_proc[p], objects_on_proc[p]);
    1264             :     else
    1265         630 :       libmesh_assert_less_equal (0, objects_on_proc[p]);
    1266             : #endif
    1267             : 
    1268             :   // We'll renumber objects in blocks by processor id
    1269     1354662 :   std::vector<dof_id_type> first_object_on_proc(this->n_processors());
    1270    14353318 :   for (processor_id_type i=1, np=this->n_processors(); i != np; ++i)
    1271    13003360 :     first_object_on_proc[i] = first_object_on_proc[i-1] +
    1272         784 :       objects_on_proc[i-1];
    1273     1353878 :   dof_id_type next_id = first_object_on_proc[this->processor_id()];
    1274     1353094 :   dof_id_type first_free_id =
    1275     1354662 :     first_object_on_proc[this->n_processors()-1] +
    1276         784 :     objects_on_proc[this->n_processors()-1] +
    1277             :     unpartitioned_objects;
    1278             : 
    1279             :   // First set new local object ids and build request sets
    1280             :   // for non-local object ids
    1281             : 
    1282             :   // Request sets to send to each processor
    1283             :   std::map<processor_id_type, std::vector<dof_id_type>>
    1284         784 :     requested_ids;
    1285             : 
    1286             :   // We know how many objects live on each processor, so reserve() space for
    1287             :   // each.
    1288         784 :   auto ghost_end = ghost_objects_from_proc.end();
    1289    15706412 :   for (auto p : make_range(this->n_processors()))
    1290    14354886 :     if (p != this->processor_id())
    1291             :       {
    1292    13001008 :         if (const auto p_it = ghost_objects_from_proc.find(p);
    1293         784 :             p_it != ghost_end)
    1294     2815126 :           requested_ids[p].reserve(p_it->second);
    1295             :       }
    1296             : 
    1297         784 :   end = objects.end();
    1298   102704770 :   for (it = objects.begin(); it != end; ++it)
    1299             :     {
    1300   101351676 :       T * obj = *it;
    1301   101351676 :       if (!obj)
    1302           0 :         continue;
    1303   101407904 :       if (obj->processor_id() == this->processor_id())
    1304    18233770 :         obj->set_id(next_id++);
    1305    83117906 :       else if (obj->processor_id() != DofObject::invalid_processor_id)
    1306    40734791 :         requested_ids[obj->processor_id()].push_back(obj->id());
    1307             :     }
    1308             : 
    1309             :   // Next set ghost object ids from other processors
    1310             : 
    1311     1370237 :   auto gather_functor =
    1312    43516541 :     [
    1313             : #ifndef NDEBUG
    1314             :      this,
    1315             :      &first_object_on_proc,
    1316             :      &objects_on_proc,
    1317             : #endif
    1318             :      &objects]
    1319             :     (processor_id_type, const std::vector<dof_id_type> & ids,
    1320         910 :      std::vector<dof_id_type> & new_ids)
    1321             :     {
    1322         910 :       std::size_t ids_size = ids.size();
    1323     2815126 :       new_ids.resize(ids_size);
    1324             : 
    1325    43549917 :       for (std::size_t i=0; i != ids_size; ++i)
    1326             :         {
    1327    40734791 :           T * obj = objects[ids[i]];
    1328       16233 :           libmesh_assert(obj);
    1329       16233 :           libmesh_assert_equal_to (obj->processor_id(), this->processor_id());
    1330    40751024 :           new_ids[i] = obj->id();
    1331             : 
    1332       16233 :           libmesh_assert_greater_equal (new_ids[i],
    1333             :                                         first_object_on_proc[this->processor_id()]);
    1334       16233 :           libmesh_assert_less (new_ids[i],
    1335             :                                first_object_on_proc[this->processor_id()] +
    1336             :                                objects_on_proc[this->processor_id()]);
    1337             :         }
    1338             :     };
    1339             : 
    1340     1370237 :   auto action_functor =
    1341    43516541 :     [
    1342             : #ifndef NDEBUG
    1343             :      &first_object_on_proc,
    1344             :      &objects_on_proc,
    1345             : #endif
    1346             :      &objects]
    1347             :     (processor_id_type libmesh_dbg_var(pid),
    1348             :      const std::vector<dof_id_type> & ids,
    1349         910 :      const std::vector<dof_id_type> & data)
    1350             :     {
    1351             :       // Copy the id changes we've now been informed of
    1352    43549917 :       for (auto i : index_range(ids))
    1353             :         {
    1354    40734791 :           T * obj = objects[ids[i]];
    1355       16233 :           libmesh_assert (obj);
    1356       16233 :           libmesh_assert_equal_to (obj->processor_id(), pid);
    1357       16233 :           libmesh_assert_greater_equal (data[i],
    1358             :                                         first_object_on_proc[pid]);
    1359       16233 :           libmesh_assert_less (data[i],
    1360             :                                first_object_on_proc[pid] +
    1361             :                                objects_on_proc[pid]);
    1362    40751024 :           obj->set_id(data[i]);
    1363             :         }
    1364             :     };
    1365             : 
    1366         784 :   const dof_id_type * ex = nullptr;
    1367             :   Parallel::pull_parallel_vector_data
    1368     1353094 :     (this->comm(), requested_ids, gather_functor, action_functor, ex);
    1369             : 
    1370             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
    1371     1370237 :   auto unique_gather_functor =
    1372    43516541 :     [
    1373             : #ifndef NDEBUG
    1374             :      this,
    1375             : #endif
    1376             :      &objects]
    1377             :     (processor_id_type, const std::vector<dof_id_type> & ids,
    1378         910 :      std::vector<unique_id_type> & data)
    1379             :     {
    1380         910 :       std::size_t ids_size = ids.size();
    1381     2815126 :       data.resize(ids_size);
    1382             : 
    1383    43549917 :       for (std::size_t i=0; i != ids_size; ++i)
    1384             :         {
    1385    40734791 :           T * obj = objects[ids[i]];
    1386       16233 :           libmesh_assert(obj);
    1387       16233 :           libmesh_assert_equal_to (obj->processor_id(), this->processor_id());
    1388    81469582 :           data[i] = obj->valid_unique_id() ? obj->unique_id() : DofObject::invalid_unique_id;
    1389             :         }
    1390             :     };
    1391             : 
    1392     1370237 :   auto unique_action_functor =
    1393    43516541 :     [&objects]
    1394             :     (processor_id_type libmesh_dbg_var(pid),
    1395             :      const std::vector<dof_id_type> & ids,
    1396         910 :      const std::vector<unique_id_type> & data)
    1397             :     {
    1398    43549917 :       for (auto i : index_range(ids))
    1399             :         {
    1400    40734791 :           T * obj = objects[ids[i]];
    1401       16233 :           libmesh_assert (obj);
    1402       16233 :           libmesh_assert_equal_to (obj->processor_id(), pid);
    1403    40734791 :           if (!obj->valid_unique_id() && data[i] != DofObject::invalid_unique_id)
    1404           0 :             obj->set_unique_id(data[i]);
    1405             :         }
    1406             :     };
    1407             : 
    1408         784 :   const unique_id_type * unique_ex = nullptr;
    1409             :   Parallel::pull_parallel_vector_data
    1410     1353094 :     (this->comm(), requested_ids, unique_gather_functor,
    1411             :      unique_action_functor, unique_ex);
    1412             : #endif
    1413             : 
    1414             :   // Next set unpartitioned object ids
    1415         784 :   next_id = 0;
    1416    15706412 :   for (auto i : make_range(this->n_processors()))
    1417    14354886 :     next_id += objects_on_proc[i];
    1418   102704770 :   for (it = objects.begin(); it != end; ++it)
    1419             :     {
    1420   101351676 :       T * obj = *it;
    1421   101351676 :       if (!obj)
    1422           0 :         continue;
    1423   101351676 :       if (obj->processor_id() == DofObject::invalid_processor_id)
    1424    42383115 :         obj->set_id(next_id++);
    1425             :     }
    1426             : 
    1427             :   // Finally shuffle around objects so that container indices
    1428             :   // match ids
    1429     1353094 :   it = objects.begin();
    1430         784 :   end = objects.end();
    1431   108944249 :   while (it != end)
    1432             :     {
    1433   107591155 :       T * obj = *it;
    1434   107591155 :       if (obj) // don't try shuffling already-nullptr entries
    1435             :         {
    1436   107591155 :           T * next = objects[obj->id()];
    1437             :           // If we have to move this object
    1438   107591155 :           if (next != obj)
    1439             :             {
    1440             :               // nullptr out its original position for now
    1441             :               // (our shuffling may put another object there shortly)
    1442    39667916 :               *it = nullptr;
    1443             : 
    1444             :               // There may already be another object with this id that
    1445             :               // needs to be moved itself
    1446    50995593 :               while (next)
    1447             :                 {
    1448             :                   // We shouldn't be trying to give two objects the
    1449             :                   // same id
    1450        9326 :                   libmesh_assert_not_equal_to (next->id(), obj->id());
    1451    11327677 :                   objects[obj->id()] = obj;
    1452        9326 :                   obj = next;
    1453    11327677 :                   next = objects[obj->id()];
    1454             :                 }
    1455    39667916 :               objects[obj->id()] = obj;
    1456             :             }
    1457             :         }
    1458             : 
    1459             :       // Remove any container entries that were left as nullptr.
    1460      114904 :       if (!obj)
    1461           0 :         it = objects.erase(it);
    1462             :       else
    1463       57452 :         ++it;
    1464             :     }
    1465             : 
    1466     1353878 :   return first_free_id;
    1467             : }
    1468             : 
    1469             : 
    1470      678217 : void DistributedMesh::renumber_nodes_and_elements ()
    1471             : {
    1472         394 :   parallel_object_only();
    1473             : 
    1474             : #ifdef DEBUG
    1475             :   // Make sure our ids and flags are consistent
    1476         394 :   this->libmesh_assert_valid_parallel_ids();
    1477         394 :   this->libmesh_assert_valid_parallel_flags();
    1478         394 :   this->libmesh_assert_valid_parallel_p_levels();
    1479             : #endif
    1480             : 
    1481         394 :   LOG_SCOPE("renumber_nodes_and_elements()", "DistributedMesh");
    1482             : 
    1483             :   // Nodes not connected to any elements, and nullptr node entries
    1484             :   // in our container, should be deleted.  But wait!  If we've deleted coarse
    1485             :   // local elements on some processor, other processors might have ghosted
    1486             :   // nodes from it that are now no longer connected to any elements on it, but
    1487             :   // that are connected to their own semilocal elements.  We'll have to
    1488             :   // communicate to ascertain if that's the case.
    1489      678217 :   this->comm().max(_deleted_coarse_elements);
    1490             : 
    1491             :   // What used nodes do we see on our proc?
    1492         394 :   std::set<dof_id_type> used_nodes;
    1493             : 
    1494             :   // What used node info should we send from our proc?  Could we take ownership
    1495             :   // of each node if we needed to?
    1496             :   std::map<processor_id_type, std::map<dof_id_type, bool>>
    1497         394 :     used_nodes_on_proc;
    1498             : 
    1499             :   // flag the nodes we need
    1500    54558016 :   for (auto & elem : this->element_ptr_range())
    1501   283841613 :     for (const Node & node : elem->node_ref_range())
    1502             :       {
    1503   257211323 :         const dof_id_type n = node.id();
    1504   257067209 :         used_nodes.insert(n);
    1505   257211323 :         if (_deleted_coarse_elements)
    1506             :           {
    1507     3123685 :             const processor_id_type p = node.processor_id();
    1508     3123969 :             if (p != this->processor_id())
    1509             :               {
    1510     2237336 :                 auto & used_nodes_on_p = used_nodes_on_proc[p];
    1511     2237478 :                 if (elem->processor_id() == this->processor_id())
    1512      215584 :                   used_nodes_on_p[n] = true;
    1513             :                 else
    1514         105 :                   if (!used_nodes_on_p.count(n))
    1515      516282 :                     used_nodes_on_p[n] = false;
    1516             :               }
    1517             :           }
    1518      677429 :       }
    1519             : 
    1520      678217 :   if (_deleted_coarse_elements)
    1521             :     {
    1522             :       // "unsigned char" == "bool, but MPI::BOOL is iffy to use"
    1523             :       typedef unsigned char boolish;
    1524             :       std::map<processor_id_type, std::vector<std::pair<dof_id_type, boolish>>>
    1525          28 :         used_nodes_on_proc_vecs;
    1526       70355 :       for (auto & [pid, nodemap] : used_nodes_on_proc)
    1527       54485 :         used_nodes_on_proc_vecs[pid].assign(nodemap.begin(), nodemap.end());
    1528             : 
    1529          28 :       std::map<dof_id_type,processor_id_type> repartitioned_node_pids;
    1530             :       std::map<processor_id_type, std::set<dof_id_type>>
    1531          28 :         repartitioned_node_sets_to_push;
    1532             : 
    1533             :       auto ids_action_functor =
    1534       54459 :         [&used_nodes, &repartitioned_node_pids,
    1535             :          &repartitioned_node_sets_to_push]
    1536             :         (processor_id_type pid,
    1537         112 :          const std::vector<std::pair<dof_id_type, boolish>> & ids_and_bools)
    1538             :         {
    1539      580910 :           for (auto [n, sender_could_become_owner] : ids_and_bools)
    1540             :             {
    1541             :               // If we don't see a use for our own node, but someone
    1542             :               // else does, better figure out who should own it next.
    1543          97 :               if (!used_nodes.count(n))
    1544             :                 {
    1545           2 :                   if (auto it = repartitioned_node_pids.find(n);
    1546           2 :                       sender_could_become_owner)
    1547             :                     {
    1548           1 :                       if (it != repartitioned_node_pids.end() &&
    1549           0 :                           pid < it->second)
    1550           0 :                         it->second = pid;
    1551             :                       else
    1552           1 :                         repartitioned_node_pids[n] = pid;
    1553             :                     }
    1554             :                   else
    1555           1 :                     if (it == repartitioned_node_pids.end())
    1556           0 :                       repartitioned_node_pids[n] =
    1557             :                         DofObject::invalid_processor_id;
    1558             : 
    1559           2 :                   repartitioned_node_sets_to_push[pid].insert(n);
    1560             :                 }
    1561             :             }
    1562       15882 :         };
    1563             : 
    1564             :       // We need two pushes instead of a pull here because we need to
    1565             :       // know *all* the queries for a particular node before we can
    1566             :       // respond to *any* of them.
    1567             :       Parallel::push_parallel_vector_data
    1568       15870 :       (this->comm(), used_nodes_on_proc_vecs, ids_action_functor);
    1569             : 
    1570             :       // Repartition (what used to be) our own nodes first
    1571       15871 :       for (auto & [n, p] : repartitioned_node_pids)
    1572             :         {
    1573           1 :           Node & node = this->node_ref(n);
    1574           0 :           libmesh_assert_equal_to(node.processor_id(), this->processor_id());
    1575           0 :           libmesh_assert_not_equal_to_msg(p, DofObject::invalid_processor_id, "Node " << n << " is lost?");
    1576           1 :           node.processor_id() = p;
    1577             :         }
    1578             : 
    1579             :       // Then push to repartition others' ghosted copies.
    1580             : 
    1581             :       std::map<processor_id_type, std::vector<std::pair<dof_id_type,processor_id_type>>>
    1582          28 :         repartitioned_node_vecs;
    1583             : 
    1584       15872 :       for (auto & [p, nodeset] : repartitioned_node_sets_to_push)
    1585             :         {
    1586           2 :           auto & rn_vec = repartitioned_node_vecs[p];
    1587           4 :           for (auto n : nodeset)
    1588           2 :             rn_vec.emplace_back(n, repartitioned_node_pids[n]);
    1589             :         }
    1590             : 
    1591             :       auto repartition_node_functor =
    1592           2 :         [this]
    1593             :         (processor_id_type libmesh_dbg_var(pid),
    1594           2 :          const std::vector<std::pair<dof_id_type, processor_id_type>> & ids_and_pids)
    1595             :         {
    1596           4 :           for (auto [n, p] : ids_and_pids)
    1597             :             {
    1598           0 :               libmesh_assert_not_equal_to(p, DofObject::invalid_processor_id);
    1599           2 :               Node & node = this->node_ref(n);
    1600           0 :               libmesh_assert_equal_to(node.processor_id(), pid);
    1601           2 :               node.processor_id() = p;
    1602             :             }
    1603       15842 :         };
    1604             : 
    1605             :       Parallel::push_parallel_vector_data
    1606       15870 :       (this->comm(), repartitioned_node_vecs, repartition_node_functor);
    1607             :     }
    1608             : 
    1609      678217 :   _deleted_coarse_elements = false;
    1610             : 
    1611             :   // Nodes not connected to any local elements, and nullptr node entries
    1612             :   // in our container, are deleted
    1613             :   {
    1614      678217 :     node_iterator_imp  it = _nodes.begin();
    1615         394 :     node_iterator_imp end = _nodes.end();
    1616             : 
    1617    81504562 :     while (it != end)
    1618             :       {
    1619    80826345 :         Node * nd = *it;
    1620    80826345 :         if (!nd)
    1621     2743685 :           it = _nodes.erase(it);
    1622    78082660 :         else if (!used_nodes.count(nd->id()))
    1623             :           {
    1624             :             // remove any boundary information associated with
    1625             :             // this node
    1626     2327679 :             this->get_boundary_info().remove (nd);
    1627        2828 :             _constraint_rows.erase(nd);
    1628             : 
    1629             :             // delete the node
    1630     2327679 :             delete nd;
    1631             : 
    1632     2327679 :             it = _nodes.erase(it);
    1633             :           }
    1634             :         else
    1635       45139 :           ++it;
    1636             :       }
    1637             :   }
    1638             : 
    1639      678217 :   this->_preparation.has_removed_orphaned_nodes = true;
    1640             : 
    1641      678217 :   if (_skip_renumber_nodes_and_elements)
    1642             :     {
    1643        1670 :       this->update_parallel_id_counts();
    1644           2 :       return;
    1645             :     }
    1646             : 
    1647             :   // Finally renumber all the elements
    1648      676547 :   _n_elem = this->renumber_dof_objects (this->_elements);
    1649             : 
    1650             :   // and all the remaining nodes
    1651      676547 :   _n_nodes = this->renumber_dof_objects (this->_nodes);
    1652             : 
    1653             :   // And figure out what IDs we should use when adding new nodes and
    1654             :   // new elements
    1655      676547 :   this->update_parallel_id_counts();
    1656             : 
    1657             :   // Make sure our caches are up to date and our
    1658             :   // DofObjects are well packed
    1659             : #ifdef DEBUG
    1660         392 :   libmesh_assert_equal_to (this->n_nodes(), this->parallel_n_nodes());
    1661         392 :   libmesh_assert_equal_to (this->n_elem(), this->parallel_n_elem());
    1662         392 :   const dof_id_type pmax_node_id = this->parallel_max_node_id();
    1663         392 :   const dof_id_type pmax_elem_id = this->parallel_max_elem_id();
    1664         392 :   libmesh_assert_equal_to (this->max_node_id(), pmax_node_id);
    1665         392 :   libmesh_assert_equal_to (this->max_elem_id(), pmax_elem_id);
    1666         392 :   libmesh_assert_equal_to (this->n_nodes(), this->max_node_id());
    1667         392 :   libmesh_assert_equal_to (this->n_elem(), this->max_elem_id());
    1668             : 
    1669             :   // Make sure our ids and flags are consistent
    1670         392 :   this->libmesh_assert_valid_parallel_ids();
    1671         392 :   this->libmesh_assert_valid_parallel_flags();
    1672             : 
    1673             :   // And make sure we've made our numbering monotonic
    1674         392 :   MeshTools::libmesh_assert_valid_elem_ids(*this);
    1675             : #endif
    1676             : }
    1677             : 
    1678             : 
    1679             : 
    1680       17410 : void DistributedMesh::fix_broken_node_and_element_numbering ()
    1681             : {
    1682             :   // We can't use range-for here because we need access to the special
    1683             :   // iterators' methods, not just to their dereferenced values.
    1684             : 
    1685             :   // Nodes first
    1686           0 :   for (auto pr = this->_nodes.begin(),
    1687     5444770 :            end = this->_nodes.end(); pr != end; ++pr)
    1688             :     {
    1689     5427360 :       Node * n = *pr;
    1690     5427360 :       if (n != nullptr)
    1691             :         {
    1692           0 :           const dof_id_type id = pr.index();
    1693     5204550 :           n->set_id() = id;
    1694           0 :           libmesh_assert_equal_to(this->node_ptr(id), n);
    1695             :         }
    1696             :     }
    1697             : 
    1698             :   // Elements next
    1699           0 :   for (auto pr = this->_elements.begin(),
    1700     5671231 :            end = this->_elements.end(); pr != end; ++pr)
    1701             :     {
    1702     5653821 :       Elem * e = *pr;
    1703     5653821 :       if (e != nullptr)
    1704             :         {
    1705           0 :           const dof_id_type id = pr.index();
    1706     5590229 :           e->set_id() = id;
    1707           0 :           libmesh_assert_equal_to(this->elem_ptr(id), e);
    1708             :         }
    1709             :     }
    1710       17410 : }
    1711             : 
    1712             : 
    1713             : 
    1714      631970 : dof_id_type DistributedMesh::n_active_elem () const
    1715             : {
    1716         540 :   parallel_object_only();
    1717             : 
    1718             :   // Get local active elements first
    1719             :   dof_id_type active_elements =
    1720     1263400 :     static_cast<dof_id_type>(std::distance (this->active_local_elements_begin(),
    1721     1894830 :                                             this->active_local_elements_end()));
    1722      631970 :   this->comm().sum(active_elements);
    1723             : 
    1724             :   // Then add unpartitioned active elements, which should exist on
    1725             :   // every processor
    1726      631970 :   active_elements +=
    1727      631970 :     static_cast<dof_id_type>(std::distance
    1728     1263400 :                              (this->active_pid_elements_begin(DofObject::invalid_processor_id),
    1729      632510 :                               this->active_pid_elements_end(DofObject::invalid_processor_id)));
    1730      631970 :   return active_elements;
    1731             : }
    1732             : 
    1733             : 
    1734             : 
    1735      403244 : void DistributedMesh::delete_remote_elements()
    1736             : {
    1737             : #ifdef DEBUG
    1738             :   // Make sure our neighbor links are all fine
    1739         382 :   MeshTools::libmesh_assert_valid_neighbors(*this);
    1740             : 
    1741             :   // And our child/parent links, and our flags
    1742         382 :   MeshTools::libmesh_assert_valid_refinement_tree(*this);
    1743             : 
    1744             :   // Make sure our ids and flags are consistent
    1745         382 :   this->libmesh_assert_valid_parallel_ids();
    1746         382 :   this->libmesh_assert_valid_parallel_flags();
    1747             : 
    1748         382 :   libmesh_assert_equal_to (this->n_nodes(), this->parallel_n_nodes());
    1749         382 :   libmesh_assert_equal_to (this->n_elem(), this->parallel_n_elem());
    1750         382 :   const dof_id_type pmax_node_id = this->parallel_max_node_id();
    1751         382 :   const dof_id_type pmax_elem_id = this->parallel_max_elem_id();
    1752         382 :   libmesh_assert_equal_to (this->max_node_id(), pmax_node_id);
    1753         382 :   libmesh_assert_equal_to (this->max_elem_id(), pmax_elem_id);
    1754             : #endif
    1755             : 
    1756      403244 :   _is_serial = false;
    1757      403244 :   _is_serial_on_proc_0 = false;
    1758             : 
    1759      403244 :   MeshCommunication().delete_remote_elements(*this, _extra_ghost_elems);
    1760             : 
    1761         382 :   libmesh_assert_equal_to (this->max_elem_id(), this->parallel_max_elem_id());
    1762             : 
    1763             :   // Now make sure the containers actually shrink - strip
    1764             :   // any newly-created nullptr voids out of the element array
    1765      403244 :   dofobject_container<Elem>::veclike_iterator e_it        = _elements.begin();
    1766         382 :   const dofobject_container<Elem>::veclike_iterator e_end = _elements.end();
    1767    53520534 :   while (e_it != e_end)
    1768    53117290 :     if (!*e_it)
    1769    39588284 :       e_it = _elements.erase(e_it);
    1770             :     else
    1771       17361 :       ++e_it;
    1772             : 
    1773      403244 :   dofobject_container<Node>::veclike_iterator n_it        = _nodes.begin();
    1774         382 :   const dofobject_container<Node>::veclike_iterator n_end = _nodes.end();
    1775   100184839 :   while (n_it != n_end)
    1776    99781595 :     if (!*n_it)
    1777    66632226 :       n_it = _nodes.erase(n_it);
    1778             :     else
    1779       48503 :       ++n_it;
    1780             : 
    1781             :   // We may have deleted no-longer-connected nodes or coarsened-away
    1782             :   // elements; let's update our caches.
    1783      403244 :   this->update_parallel_id_counts();
    1784             : 
    1785             :   // We may have deleted nodes or elements that were the only local
    1786             :   // representatives of some particular boundary id(s); let's update
    1787             :   // those caches.
    1788      403244 :   this->get_boundary_info().regenerate_id_sets();
    1789             : 
    1790             : #ifdef DEBUG
    1791             :   // We might not have well-packed objects if the user didn't allow us
    1792             :   // to renumber
    1793             :   // libmesh_assert_equal_to (this->n_nodes(), this->max_node_id());
    1794             :   // libmesh_assert_equal_to (this->n_elem(), this->max_elem_id());
    1795             : 
    1796             :   // Make sure our neighbor links are all fine
    1797         382 :   MeshTools::libmesh_assert_valid_neighbors(*this);
    1798             : 
    1799             :   // And our child/parent links, and our flags
    1800         382 :   MeshTools::libmesh_assert_valid_refinement_tree(*this);
    1801             : 
    1802             :   // Make sure our ids and flags are consistent
    1803         382 :   this->libmesh_assert_valid_parallel_ids();
    1804         382 :   this->libmesh_assert_valid_parallel_flags();
    1805             : #endif
    1806             : 
    1807      403244 :   this->_preparation.has_removed_remote_elements = true;
    1808      403244 : }
    1809             : 
    1810             : 
    1811           0 : void DistributedMesh::add_extra_ghost_elem(Elem * e)
    1812             : {
    1813             :   // First add the elem like normal
    1814           0 :   add_elem(e);
    1815             : 
    1816             :   // Now add it to the set that won't be deleted when we call
    1817             :   // delete_remote_elements()
    1818           0 :   _extra_ghost_elems.insert(e);
    1819           0 : }
    1820             : 
    1821             : void
    1822           0 : DistributedMesh::clear_extra_ghost_elems(const std::set<Elem *> & extra_ghost_elems)
    1823             : {
    1824           0 :   std::set<Elem *> tmp;
    1825           0 :   std::set_difference(_extra_ghost_elems.begin(), _extra_ghost_elems.end(),
    1826             :                       extra_ghost_elems.begin(), extra_ghost_elems.end(),
    1827           0 :                       std::inserter(tmp, tmp.begin()));
    1828           0 :   _extra_ghost_elems = tmp;
    1829           0 : }
    1830             : 
    1831       96828 : void DistributedMesh::allgather()
    1832             : {
    1833       96828 :   if (_is_serial)
    1834           0 :     return;
    1835       96826 :   MeshCommunication().allgather(*this);
    1836       96826 :   _is_serial = true;
    1837       96826 :   _is_serial_on_proc_0 = true;
    1838             : 
    1839             :   // Make sure our caches are up to date and our
    1840             :   // DofObjects are well packed
    1841             : #ifdef DEBUG
    1842          48 :   libmesh_assert_equal_to (this->n_nodes(), this->parallel_n_nodes());
    1843          48 :   libmesh_assert_equal_to (this->n_elem(), this->parallel_n_elem());
    1844          48 :   const dof_id_type pmax_node_id = this->parallel_max_node_id();
    1845          48 :   const dof_id_type pmax_elem_id = this->parallel_max_elem_id();
    1846          48 :   libmesh_assert_equal_to (this->max_node_id(), pmax_node_id);
    1847          48 :   libmesh_assert_equal_to (this->max_elem_id(), pmax_elem_id);
    1848             : 
    1849             :   // If we've disabled renumbering we can't be sure we're contiguous
    1850             :   // libmesh_assert_equal_to (this->n_nodes(), this->max_node_id());
    1851             :   // libmesh_assert_equal_to (this->n_elem(), this->max_elem_id());
    1852             : 
    1853             :   // Make sure our neighbor links are all fine
    1854          48 :   MeshTools::libmesh_assert_valid_neighbors(*this);
    1855             : 
    1856             :   // Make sure our ids and flags are consistent
    1857          48 :   this->libmesh_assert_valid_parallel_ids();
    1858          48 :   this->libmesh_assert_valid_parallel_flags();
    1859             : #endif
    1860             : }
    1861             : 
    1862       18096 : void DistributedMesh::gather_to_zero()
    1863             : {
    1864       18096 :   if (_is_serial_on_proc_0)
    1865           4 :     return;
    1866             : 
    1867       13858 :   _is_serial_on_proc_0 = true;
    1868       13858 :   MeshCommunication().gather(0, *this);
    1869             : }
    1870             : 
    1871             : 
    1872             : } // namespace libMesh

Generated by: LCOV version 1.14