LCOV - code coverage report
Current view: top level - src/mesh - replicated_mesh.C (source / functions) Hit Total Coverage
Test: libMesh/libmesh: #4411 (aefcbc) with base 893689 Lines: 422 444 95.0 %
Date: 2026-07-27 16:32:15 Functions: 52 52 100.0 %
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/replicated_mesh.h"
      22             : 
      23             : #include "libmesh/boundary_info.h"
      24             : #include "libmesh/elem.h"
      25             : #include "libmesh/libmesh_logging.h"
      26             : #include "libmesh/mesh_communication.h"
      27             : #include "libmesh/parallel_implementation.h"
      28             : #include "libmesh/partitioner.h"
      29             : #include "libmesh/point.h"
      30             : #include "libmesh/string_to_enum.h"
      31             : #include "libmesh/utility.h"
      32             : 
      33             : // C++ includes
      34             : #include <unordered_map>
      35             : #include <unordered_set>
      36             : 
      37             : namespace libMesh
      38             : {
      39             : 
      40             : // ------------------------------------------------------------
      41             : // ReplicatedMesh class member functions
      42       56118 : ReplicatedMesh::ReplicatedMesh (const Parallel::Communicator & comm_in,
      43       56118 :                                 unsigned char d) :
      44             :   UnstructuredMesh (comm_in,d),
      45       56118 :   _n_nodes(0), _n_elem(0)
      46             : {
      47             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
      48             :   // In serial we just need to reset the next unique id to zero
      49             :   // here in the constructor.
      50       56118 :   _next_unique_id = 0;
      51             : #endif
      52             : 
      53       65710 :   const std::string default_partitioner = "metis";
      54             :   const std::string my_partitioner =
      55             :     libMesh::command_line_value("--default-partitioner",
      56      112236 :                                 default_partitioner);
      57             :   _partitioner = Partitioner::build
      58      102644 :     (Utility::string_to_enum<PartitionerType>(my_partitioner));
      59       56118 : }
      60             : 
      61             : 
      62       26399 : std::string_view ReplicatedMesh::subclass_first_difference_from (const MeshBase & other_mesh_base) const
      63             : {
      64       25042 :   const ReplicatedMesh * rep_mesh_ptr =
      65       26399 :     dynamic_cast<const ReplicatedMesh *>(&other_mesh_base);
      66       26399 :   if (!rep_mesh_ptr)
      67           0 :     return "ReplicatedMesh class";
      68       25042 :   const ReplicatedMesh & other_mesh = *rep_mesh_ptr;
      69             : 
      70             : #define CHECK_MEMBER(member_name) \
      71             :   if (member_name != other_mesh.member_name) \
      72             :     return #member_name;
      73             : 
      74       26399 :   CHECK_MEMBER(_n_nodes);
      75       26399 :   CHECK_MEMBER(_n_elem);
      76             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
      77       26399 :   CHECK_MEMBER(_next_unique_id);
      78             : #endif
      79       26399 :   if (!this->nodes_and_elements_equal(other_mesh))
      80          78 :     return "nodes and/or elements";
      81             : 
      82       26321 :   return "";
      83             : }
      84             : 
      85             : 
      86       94542 : ReplicatedMesh::~ReplicatedMesh ()
      87             : {
      88       72372 :   this->ReplicatedMesh::clear();  // Free nodes and elements
      89       94542 : }
      90             : 
      91             : 
      92             : // This might be specialized later, but right now it's just here to
      93             : // make sure the compiler doesn't give us a default (non-deep) copy
      94             : // constructor instead.
      95       16183 : ReplicatedMesh::ReplicatedMesh (const ReplicatedMesh & other_mesh) :
      96       16183 :   ReplicatedMesh(static_cast<const MeshBase&>(other_mesh))
      97             : {
      98             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
      99       16183 :   this->_next_unique_id = other_mesh._next_unique_id;
     100             : #endif
     101       16183 : }
     102             : 
     103             : 
     104       16254 : ReplicatedMesh::ReplicatedMesh (const MeshBase & other_mesh) :
     105             :   UnstructuredMesh (other_mesh),
     106       16254 :   _n_nodes(0), _n_elem(0) // copy_* will increment this
     107             : {
     108             :   // Just copy, skipping preparation
     109       16254 :   this->copy_nodes_and_elements(other_mesh, true, 0, 0, 0, nullptr, true);
     110             : 
     111       13426 :   this->allow_find_neighbors(other_mesh.allow_find_neighbors());
     112       13426 :   this->allow_detect_interior_parents(other_mesh.allow_detect_interior_parents());
     113       13426 :   this->allow_renumbering(other_mesh.allow_renumbering());
     114       13426 :   this->allow_remote_element_removal(other_mesh.allow_remote_element_removal());
     115       13426 :   this->skip_partitioning(other_mesh.skip_partitioning());
     116             : 
     117       16254 :   this->copy_constraint_rows(other_mesh);
     118             : 
     119       12726 :   auto & this_boundary_info = this->get_boundary_info();
     120       12726 :   const auto & other_boundary_info = other_mesh.get_boundary_info();
     121             : 
     122       16254 :   this_boundary_info = other_boundary_info;
     123             : 
     124       12726 :   this->set_subdomain_name_map() = other_mesh.get_subdomain_name_map();
     125             : 
     126       16254 :   this->_preparation = other_mesh.preparation();
     127             : 
     128             :   // If other_mesh is distributed, then we've got parts of it on each
     129             :   // processor but we're not replicated yet; fix that.
     130       16254 :   if (!other_mesh.is_serial())
     131          71 :     MeshCommunication().allgather(*this);
     132       16254 : }
     133             : 
     134         156 : ReplicatedMesh & ReplicatedMesh::operator= (ReplicatedMesh && other_mesh)
     135             : {
     136           8 :   LOG_SCOPE("operator=(&&)", "ReplicatedMesh");
     137             : 
     138             :   // Move assign as an UnstructuredMesh
     139           8 :   this->UnstructuredMesh::operator=(std::move(other_mesh));
     140             : 
     141             :   // Nodes and elements belong to ReplicatedMesh and have to be
     142             :   // moved before we can move arbitrary GhostingFunctor, Partitioner,
     143             :   // etc. subclasses.
     144         156 :   this->move_nodes_and_elements(std::move(other_mesh));
     145             : 
     146             :   // Handle those remaining moves.
     147         156 :   this->post_dofobject_moves(std::move(other_mesh));
     148             : 
     149         164 :   return *this;
     150             : }
     151             : 
     152         156 : MeshBase & ReplicatedMesh::assign(MeshBase && other_mesh)
     153             : {
     154         156 :   *this = std::move(cast_ref<ReplicatedMesh&>(other_mesh));
     155             : 
     156         156 :   return *this;
     157             : }
     158             : 
     159         156 : void ReplicatedMesh::move_nodes_and_elements(MeshBase && other_meshbase)
     160             : {
     161           8 :   ReplicatedMesh & other_mesh = cast_ref<ReplicatedMesh&>(other_meshbase);
     162             : 
     163         156 :   this->_nodes = std::move(other_mesh._nodes);
     164         156 :   this->_n_nodes = other_mesh.n_nodes();
     165             : 
     166         156 :   this->_elements = std::move(other_mesh._elements);
     167         156 :   this->_n_elem = other_mesh.n_elem();
     168         156 : }
     169             : 
     170             : 
     171    15660045 : const Point & ReplicatedMesh::point (const dof_id_type i) const
     172             : {
     173    15660045 :   return this->node_ref(i);
     174             : }
     175             : 
     176             : 
     177             : 
     178             : 
     179   101253656 : const Node * ReplicatedMesh::node_ptr (const dof_id_type i) const
     180             : {
     181     5175882 :   libmesh_assert_less (i, this->max_node_id());
     182     5175882 :   libmesh_assert(_nodes[i]);
     183     5175882 :   libmesh_assert_equal_to (_nodes[i]->id(), i); // This will change soon
     184             : 
     185   106379464 :   return _nodes[i];
     186             : }
     187             : 
     188             : 
     189             : 
     190             : 
     191   130856165 : Node * ReplicatedMesh::node_ptr (const dof_id_type i)
     192             : {
     193    22420534 :   libmesh_assert_less (i, this->max_node_id());
     194    22420534 :   libmesh_assert(_nodes[i]);
     195    22420534 :   libmesh_assert_equal_to (_nodes[i]->id(), i); // This will change soon
     196             : 
     197   142715281 :   return _nodes[i];
     198             : }
     199             : 
     200             : 
     201             : 
     202             : 
     203    34094120 : const Node * ReplicatedMesh::query_node_ptr (const dof_id_type i) const
     204             : {
     205    34094120 :   if (i >= this->max_node_id())
     206           0 :     return nullptr;
     207    33844115 :   libmesh_assert (_nodes[i] == nullptr ||
     208             :                   _nodes[i]->id() == i); // This will change soon
     209             : 
     210    34179302 :   return _nodes[i];
     211             : }
     212             : 
     213             : 
     214             : 
     215             : 
     216     4388044 : Node * ReplicatedMesh::query_node_ptr (const dof_id_type i)
     217             : {
     218     4388044 :   if (i >= this->max_node_id())
     219       86978 :     return nullptr;
     220     2036573 :   libmesh_assert (_nodes[i] == nullptr ||
     221             :                   _nodes[i]->id() == i); // This will change soon
     222             : 
     223     3783911 :   return _nodes[i];
     224             : }
     225             : 
     226             : 
     227             : 
     228             : 
     229     3239203 : const Elem * ReplicatedMesh::elem_ptr (const dof_id_type i) const
     230             : {
     231      540526 :   libmesh_assert_less (i, this->max_elem_id());
     232      540526 :   libmesh_assert(_elements[i]);
     233      540526 :   libmesh_assert_equal_to (_elements[i]->id(), i); // This will change soon
     234             : 
     235     3655522 :   return _elements[i];
     236             : }
     237             : 
     238             : 
     239             : 
     240             : 
     241    96613464 : Elem * ReplicatedMesh::elem_ptr (const dof_id_type i)
     242             : {
     243     6343989 :   libmesh_assert_less (i, this->max_elem_id());
     244     6343989 :   libmesh_assert(_elements[i]);
     245     6343989 :   libmesh_assert_equal_to (_elements[i]->id(), i); // This will change soon
     246             : 
     247   101111131 :   return _elements[i];
     248             : }
     249             : 
     250             : 
     251             : 
     252             : 
     253    26984650 : const Elem * ReplicatedMesh::query_elem_ptr (const dof_id_type i) const
     254             : {
     255    26984650 :   if (i >= this->max_elem_id())
     256           0 :     return nullptr;
     257    26900409 :   libmesh_assert (_elements[i] == nullptr ||
     258             :                   _elements[i]->id() == i); // This will change soon
     259             : 
     260    27014225 :   return _elements[i];
     261             : }
     262             : 
     263             : 
     264             : 
     265             : 
     266     2336237 : Elem * ReplicatedMesh::query_elem_ptr (const dof_id_type i)
     267             : {
     268     2336237 :   if (i >= this->max_elem_id())
     269       44850 :     return nullptr;
     270     1081198 :   libmesh_assert (_elements[i] == nullptr ||
     271             :                   _elements[i]->id() == i); // This will change soon
     272             : 
     273     1673745 :   return _elements[i];
     274             : }
     275             : 
     276             : 
     277             : 
     278             : 
     279    17187733 : Elem * ReplicatedMesh::add_elem (Elem * e)
     280             : {
     281     2462232 :   libmesh_assert(e);
     282             : 
     283             :   // We no longer merely append elements with ReplicatedMesh
     284             : 
     285             :   // If the user requests a valid id that doesn't correspond to an
     286             :   // existing element, let's give them that id, resizing the elements
     287             :   // container if necessary.
     288    17187733 :   if (!e->valid_id())
     289      819058 :     e->set_id (cast_int<dof_id_type>(_elements.size()));
     290             : 
     291             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
     292    17187733 :   if (!e->valid_unique_id())
     293     5041554 :     e->set_unique_id(_next_unique_id++);
     294             :   else
     295    12999794 :    _next_unique_id = std::max(_next_unique_id, e->unique_id()+1);
     296             : #endif
     297             : 
     298     3586944 :   const dof_id_type id = e->id();
     299             : 
     300    18312445 :   if (id < _elements.size())
     301             :     {
     302             :       // This should *almost* never happen, but we rely on it when
     303             :       // using allgather to replicate a not-yet-actually-replicated
     304             :       // ReplicatedMesh under construction in parallel.
     305      165331 :       if (e == _elements[id])
     306           0 :         return e;
     307             : 
     308             :       // Overwriting existing elements is still probably a mistake.
     309       16044 :       libmesh_assert(!_elements[id]);
     310             :     }
     311             :   else
     312             :     {
     313    17022402 :       _elements.resize(id+1, nullptr);
     314             :     }
     315             : 
     316    17187733 :   ++_n_elem;
     317    17187733 :   _elements[id] = e;
     318             : 
     319             :   // We actually added a new element.  Some of our caches might still
     320             :   // be valid, but we should clear the ones which definitely are not.
     321    17187733 :   this->clear_point_locator();
     322    17187733 :   this->clear_stored_ranges();
     323             : 
     324             :   // Make sure any new element is given space for any extra integers
     325             :   // we've requested
     326    17187733 :   e->add_extra_integers(_elem_integer_names.size(),
     327    17187733 :                         _elem_integer_default_values);
     328             : 
     329             :   // And set mapping type and data on any new element
     330     3586944 :   e->set_mapping_type(this->default_mapping_type());
     331     3586944 :   e->set_mapping_data(this->default_mapping_data());
     332             : 
     333    17187733 :   return e;
     334             : }
     335             : 
     336    16374371 : Elem * ReplicatedMesh::add_elem (std::unique_ptr<Elem> e)
     337             : {
     338             :   // The mesh now takes ownership of the Elem. Eventually the guts of
     339             :   // add_elem() will get moved to a private helper function, and
     340             :   // calling add_elem() directly will be deprecated.
     341    16374371 :   return add_elem(e.release());
     342             : }
     343             : 
     344             : 
     345             : 
     346      582121 : Elem * ReplicatedMesh::insert_elem (Elem * e)
     347             : {
     348             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
     349      582121 :   if (!e->valid_unique_id())
     350       18176 :     e->set_unique_id(_next_unique_id++);
     351             :   else
     352      563945 :    _next_unique_id = std::max(_next_unique_id, e->unique_id()+1);
     353             : #endif
     354             : 
     355      235316 :   dof_id_type eid = e->id();
     356      117658 :   libmesh_assert_less (eid, _elements.size());
     357      582121 :   Elem * oldelem = _elements[eid];
     358             : 
     359      582121 :   if (oldelem)
     360             :     {
     361      117658 :       libmesh_assert_equal_to (oldelem->id(), eid);
     362      582121 :       this->delete_elem(oldelem);
     363             :     }
     364             : 
     365      582121 :   ++_n_elem;
     366      582121 :   _elements[eid] = e;
     367             : 
     368             :   // We actually added a new element.  Some of our caches might still
     369             :   // be valid, but we should clear the ones which definitely are not.
     370      582121 :   this->clear_point_locator();
     371      582121 :   this->clear_stored_ranges();
     372             : 
     373             :   // Make sure any new element is given space for any extra integers
     374             :   // we've requested
     375      582121 :   e->add_extra_integers(_elem_integer_names.size(),
     376      582121 :                         _elem_integer_default_values);
     377             : 
     378             :   // And set mapping type and data on any new element
     379      235316 :   e->set_mapping_type(this->default_mapping_type());
     380      235316 :   e->set_mapping_data(this->default_mapping_data());
     381             : 
     382      582121 :   return e;
     383             : }
     384             : 
     385      582121 : Elem * ReplicatedMesh::insert_elem (std::unique_ptr<Elem> e)
     386             : {
     387             :   // The mesh now takes ownership of the Elem. Eventually the guts of
     388             :   // insert_elem(Elem*) will get moved to a private helper function, and
     389             :   // calling insert_elem(Elem*) directly will be deprecated.
     390      582121 :   return insert_elem(e.release());
     391             : }
     392             : 
     393             : 
     394             : 
     395     2306530 : void ReplicatedMesh::delete_elem(Elem * e)
     396             : {
     397      228957 :   libmesh_assert(e);
     398             : 
     399             :   // Initialize an iterator to eventually point to the element we want to delete
     400      228957 :   std::vector<Elem *>::iterator pos = _elements.end();
     401             : 
     402             :   // In many cases, e->id() gives us a clue as to where e
     403             :   // is located in the _elements vector.  Try that first
     404             :   // before trying the O(n_elem) search.
     405      228957 :   libmesh_assert_less (e->id(), _elements.size());
     406             : 
     407     2532845 :   if (_elements[e->id()] == e)
     408             :     {
     409             :       // We found it!
     410     2080215 :       pos = _elements.begin();
     411      228957 :       std::advance(pos, e->id());
     412             :     }
     413             : 
     414             :   else
     415             :     {
     416             :       // This search is O(n_elem)
     417           0 :       pos = std::find (_elements.begin(),
     418             :                        _elements.end(),
     419           0 :                        e);
     420             :     }
     421             : 
     422             :   // Huh? Element not in the vector?
     423      228957 :   libmesh_assert (pos != _elements.end());
     424             : 
     425             :   // Remove the element from the BoundaryInfo object
     426     2306530 :   this->get_boundary_info().remove(e);
     427             : 
     428             :   // delete the element
     429     2306530 :   --_n_elem;
     430     2306530 :   delete e;
     431             : 
     432             :   // explicitly zero the pointer
     433     2306530 :   *pos = nullptr;
     434             : 
     435             :   // Some of our caches might still be valid, but we should clear the
     436             :   // ones which definitely are not.
     437     2306530 :   this->clear_point_locator();
     438     2306530 :   this->clear_stored_ranges();
     439     2306530 : }
     440             : 
     441             : 
     442             : 
     443       21420 : void ReplicatedMesh::renumber_elem(const dof_id_type old_id,
     444             :                                    const dof_id_type new_id)
     445             : {
     446             :   // This could be a no-op
     447       21420 :   if (old_id == new_id)
     448           0 :     return;
     449             : 
     450             :   // This doesn't get used in serial yet
     451       21420 :   Elem * el = _elements[old_id];
     452        7140 :   libmesh_assert (el);
     453             : 
     454       28560 :   if (new_id >= _elements.size())
     455         288 :     _elements.resize(new_id+1, nullptr);
     456             : 
     457        7140 :   el->set_id(new_id);
     458        7140 :   libmesh_assert (!_elements[new_id]);
     459       28560 :   _elements[new_id] = el;
     460       21420 :   _elements[old_id] = nullptr;
     461             : 
     462             :   // Should we delete any caches here?  Our point locator indexes by
     463             :   // element pointer and should be fine with an id change.  Our stored
     464             :   // ranges are no longer sorted, which is *probably* fine, but let's
     465             :   // just be safe.
     466       21420 :   this->clear_stored_ranges();
     467             : }
     468             : 
     469             : 
     470             : 
     471    13774698 : Node * ReplicatedMesh::add_point (const Point & p,
     472             :                                   const dof_id_type id,
     473             :                                   const processor_id_type proc_id)
     474             : {
     475     4152081 :   Node * n = nullptr;
     476             : 
     477             :   // If the user requests a valid id, either
     478             :   // provide the existing node or resize the container
     479             :   // to fit the new node.
     480    13774698 :   if (id != DofObject::invalid_id)
     481     9875363 :     if (id < _nodes.size())
     482       14655 :       n = _nodes[id];
     483             :     else
     484     9008363 :       _nodes.resize(id+1);
     485             :   else
     486     4751680 :     _nodes.push_back (static_cast<Node *>(nullptr));
     487             : 
     488             :   // if the node already exists, then assign new (x,y,z) values
     489     4164636 :   if (n)
     490           0 :     *n = p;
     491             :   // otherwise build a new node, put it in the right spot, and return
     492             :   // a valid pointer.
     493             :   else
     494             :     {
     495    26697051 :       n = Node::build(p, (id == DofObject::invalid_id) ?
     496     9752145 :                       cast_int<dof_id_type>(_nodes.size()-1) : id).release();
     497    13774698 :       n->processor_id() = proc_id;
     498             : 
     499    13774698 :       n->add_extra_integers(_node_integer_names.size(),
     500    13774698 :                             _node_integer_default_values);
     501             : 
     502             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
     503    13774698 :       if (!n->valid_unique_id())
     504    13774698 :         n->set_unique_id(_next_unique_id++);
     505             :       else
     506           0 :        _next_unique_id = std::max(_next_unique_id, n->unique_id()+1);
     507             : #endif
     508             : 
     509    13774698 :       ++_n_nodes;
     510    13774698 :       if (id == DofObject::invalid_id)
     511     4751680 :         _nodes.back() = n;
     512             :       else
     513     9875363 :         _nodes[id] = n;
     514             :     }
     515             : 
     516             :   // better not pass back a nullptr.
     517     4152081 :   libmesh_assert (n);
     518             : 
     519    13774698 :   return n;
     520             : }
     521             : 
     522             : 
     523             : 
     524      939498 : Node * ReplicatedMesh::add_node (Node * n)
     525             : {
     526       96530 :   libmesh_assert(n);
     527             : 
     528             :   // If the user requests a valid id, either set the existing
     529             :   // container entry or resize the container to fit the new node.
     530      939498 :   if (n->valid_id())
     531             :     {
     532       96472 :       const dof_id_type id = n->id();
     533     1035639 :       if (id < _nodes.size())
     534       15076 :         libmesh_assert(!_nodes[id]);
     535             :       else
     536      742826 :         _nodes.resize(id+1); // default nullptr
     537             : 
     538     1035639 :       _nodes[id] = n;
     539             :     }
     540             :   else
     541             :     {
     542         116 :       n->set_id (cast_int<dof_id_type>(_nodes.size()));
     543         331 :       _nodes.push_back(n);
     544             :     }
     545             : 
     546      939498 :   ++_n_nodes;
     547             : 
     548             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
     549      939498 :   if (!n->valid_unique_id())
     550         331 :     n->set_unique_id(_next_unique_id++);
     551             :   else
     552     1436272 :    _next_unique_id = std::max(_next_unique_id, n->unique_id()+1);
     553             : #endif
     554             : 
     555      939498 :   n->add_extra_integers(_node_integer_names.size(),
     556      939498 :                         _node_integer_default_values);
     557             : 
     558      939498 :   return n;
     559             : }
     560             : 
     561      939498 : Node * ReplicatedMesh::add_node (std::unique_ptr<Node> n)
     562             : {
     563             :   // The mesh now takes ownership of the Node. Eventually the guts of
     564             :   // add_node() will get moved to a private helper function, and
     565             :   // calling add_node() directly will be deprecated.
     566      939498 :   return add_node(n.release());
     567             : }
     568             : 
     569      250688 : void ReplicatedMesh::delete_node(Node * n)
     570             : {
     571       63723 :   libmesh_assert(n);
     572       63723 :   libmesh_assert_less (n->id(), _nodes.size());
     573             : 
     574             :   // Initialize an iterator to eventually point to the element we want
     575             :   // to delete
     576       63723 :   std::vector<Node *>::iterator pos;
     577             : 
     578             :   // In many cases, e->id() gives us a clue as to where e
     579             :   // is located in the _elements vector.  Try that first
     580             :   // before trying the O(n_elem) search.
     581      314411 :   if (_nodes[n->id()] == n)
     582             :     {
     583      186965 :       pos = _nodes.begin();
     584       63723 :       std::advance(pos, n->id());
     585             :     }
     586             :   else
     587             :     {
     588           0 :       pos = std::find (_nodes.begin(),
     589             :                        _nodes.end(),
     590           0 :                        n);
     591             :     }
     592             : 
     593             :   // Huh? Node not in the vector?
     594       63723 :   libmesh_assert (pos != _nodes.end());
     595             : 
     596             :   // Delete the node from the BoundaryInfo object
     597      250688 :   this->get_boundary_info().remove(n);
     598      127446 :   _constraint_rows.erase(n);
     599             : 
     600             :   // delete the node
     601      250688 :   --_n_nodes;
     602      437653 :   delete n;
     603             : 
     604             :   // explicitly zero the pointer
     605      250688 :   *pos = nullptr;
     606      250688 : }
     607             : 
     608             : 
     609             : 
     610       70092 : void ReplicatedMesh::renumber_node(const dof_id_type old_id,
     611             :                                    const dof_id_type new_id)
     612             : {
     613             :   // This could be a no-op
     614       70092 :   if (old_id == new_id)
     615           0 :     return;
     616             : 
     617             :   // This doesn't get used in serial yet
     618       70092 :   Node * nd = _nodes[old_id];
     619       23364 :   libmesh_assert (nd);
     620             : 
     621       93456 :   if (new_id >= _nodes.size())
     622         288 :     _nodes.resize(new_id+1, nullptr);
     623             : 
     624       23364 :   nd->set_id(new_id);
     625       23364 :   libmesh_assert (!_nodes[new_id]);
     626       93456 :   _nodes[new_id] = nd;
     627       70092 :   _nodes[old_id] = nullptr;
     628             : }
     629             : 
     630             : 
     631             : 
     632      117566 : void ReplicatedMesh::clear ()
     633             : {
     634             :   // Call parent clear function
     635      117566 :   MeshBase::clear();
     636             : 
     637             :   // Clear our elements and nodes
     638             :   // There is no need to remove them from
     639             :   // the BoundaryInfo data structure since we
     640             :   // already cleared it.
     641      117566 :   this->ReplicatedMesh::clear_elems();
     642             : 
     643    13050747 :   for (auto & node : _nodes)
     644    21779076 :     delete node;
     645             : 
     646      117566 :   _n_nodes = 0;
     647       31557 :   _nodes.clear();
     648      117566 : }
     649             : 
     650             : 
     651             : 
     652      118264 : void ReplicatedMesh::clear_elems ()
     653             : {
     654    15703707 :   for (auto & elem : _elements)
     655    15585443 :     delete elem;
     656             : 
     657      118264 :   _n_elem = 0;
     658       31759 :   _elements.clear();
     659      118264 : }
     660             : 
     661             : 
     662             : 
     663      210422 : void ReplicatedMesh::update_parallel_id_counts()
     664             : {
     665             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
     666      210422 :   _next_unique_id = this->parallel_max_unique_id();
     667             : #endif
     668             : 
     669      210422 :   this->_preparation.has_synched_id_counts = true;
     670      210422 : }
     671             : 
     672             : 
     673             : 
     674             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
     675      238966 : unique_id_type ReplicatedMesh::parallel_max_unique_id() const
     676             : {
     677             :   // This function must be run on all processors at once
     678       59884 :   parallel_object_only();
     679             : 
     680      238966 :   unique_id_type max_local = _next_unique_id;
     681      238966 :   this->comm().max(max_local);
     682      238966 :   return max_local;
     683             : }
     684             : 
     685             : 
     686             : 
     687       32215 : void ReplicatedMesh::set_next_unique_id(unique_id_type id)
     688             : {
     689       32215 :   _next_unique_id = id;
     690       32215 : }
     691             : #endif
     692             : 
     693             : 
     694             : 
     695      163209 : void ReplicatedMesh::renumber_nodes_and_elements ()
     696             : {
     697       59640 :   LOG_SCOPE("renumber_nodes_and_elem()", "Mesh");
     698             : 
     699             :   // node and element id counters
     700       29820 :   dof_id_type next_free_elem = 0;
     701       29820 :   dof_id_type next_free_node = 0;
     702             : 
     703             :   // Will hold the set of nodes that are currently connected to elements
     704       59640 :   std::unordered_set<Node *> connected_nodes;
     705             : 
     706             :   // Loop over the elements.  Note that there may
     707             :   // be nullptrs in the _elements vector from the coarsening
     708             :   // process.  Pack the elements in to a contiguous array
     709             :   // and then trim any excess.
     710             :   {
     711       29820 :     std::vector<Elem *>::iterator in        = _elements.begin();
     712       29820 :     std::vector<Elem *>::iterator out_iter  = _elements.begin();
     713       29820 :     const std::vector<Elem *>::iterator end = _elements.end();
     714             : 
     715    40248653 :     for (; in != end; ++in)
     716    40085444 :       if (*in != nullptr)
     717             :         {
     718     3046930 :           Elem * el = *in;
     719             : 
     720    38626322 :           *out_iter = *in;
     721     3046930 :           ++out_iter;
     722             : 
     723             :           // Increment the element counter
     724    38626322 :           el->set_id (next_free_elem++);
     725             : 
     726    38626322 :           if (_skip_renumber_nodes_and_elements)
     727             :             {
     728             :               // Add this elements nodes to the connected list
     729     2145255 :               for (auto & n : el->node_ref_range())
     730     1934776 :                 connected_nodes.insert(&n);
     731             :             }
     732             :           else  // We DO want node renumbering
     733             :             {
     734             :               // Loop over this element's nodes.  Number them,
     735             :               // if they have not been numbered already.  Also,
     736             :               // position them in the _nodes vector so that they
     737             :               // are packed contiguously from the beginning.
     738   237266840 :               for (auto & n : el->node_ref_range())
     739   198850997 :                 if (n.id() == next_free_node)    // don't need to process
     740    37770676 :                   next_free_node++;                      // [(src == dst) below]
     741             : 
     742   161080321 :                 else if (n.id() > next_free_node) // need to process
     743             :                   {
     744             :                     // The source and destination indices
     745             :                     // for this node
     746     1093566 :                     const dof_id_type src_idx = n.id();
     747     8806824 :                     const dof_id_type dst_idx = next_free_node++;
     748             : 
     749             :                     // ensure we want to swap a valid nodes
     750     1093566 :                     libmesh_assert(_nodes[src_idx]);
     751             : 
     752             :                     // Swap the source and destination nodes
     753     2701347 :                     std::swap(_nodes[src_idx],
     754     2701347 :                               _nodes[dst_idx] );
     755             : 
     756             :                     // Set proper indices where that makes sense
     757     8806824 :                     if (_nodes[src_idx] != nullptr)
     758     1078820 :                       _nodes[src_idx]->set_id (src_idx);
     759     1093566 :                     _nodes[dst_idx]->set_id (dst_idx);
     760             :                   }
     761             :             }
     762             :         }
     763             : 
     764             :     // Erase any additional storage. These elements have been
     765             :     // copied into nullptr voids by the procedure above, and are
     766             :     // thus repeated and unnecessary.
     767      163209 :     _elements.erase (out_iter, end);
     768             :   }
     769             : 
     770             : 
     771      163209 :   if (_skip_renumber_nodes_and_elements)
     772             :     {
     773             :       // Loop over the nodes.  Note that there may
     774             :       // be nullptrs in the _nodes vector from the coarsening
     775             :       // process.  Pack the nodes in to a contiguous array
     776             :       // and then trim any excess.
     777             : 
     778          60 :       std::vector<Node *>::iterator in        = _nodes.begin();
     779          60 :       std::vector<Node *>::iterator out_iter  = _nodes.begin();
     780          60 :       const std::vector<Node *>::iterator end = _nodes.end();
     781             : 
     782      925936 :       for (; in != end; ++in)
     783      925541 :         if (*in != nullptr)
     784             :           {
     785             :             // This is a reference so that if we change the pointer it will change in the vector
     786      209684 :             Node * & nd = *in;
     787             : 
     788             :             // If this node is still connected to an elem, put it in the list
     789      419368 :             if (connected_nodes.count(nd))
     790             :               {
     791      673877 :                 *out_iter = nd;
     792      137780 :                 ++out_iter;
     793             : 
     794             :                 // Increment the node counter
     795      673877 :                 nd->set_id (next_free_node++);
     796             :               }
     797             :             else // This node is orphaned, delete it!
     798             :               {
     799      251664 :                 this->get_boundary_info().remove (nd);
     800      143808 :                 _constraint_rows.erase(nd);
     801             : 
     802             :                 // delete the node
     803      251664 :                 --_n_nodes;
     804      431424 :                 delete nd;
     805      251664 :                 nd = nullptr;
     806             :               }
     807             :           }
     808             : 
     809             :       // Erase any additional storage.  Whatever was
     810         395 :       _nodes.erase (out_iter, end);
     811             :     }
     812             :   else // We really DO want node renumbering
     813             :     {
     814             :       // Any nodes in the vector >= _nodes[next_free_node]
     815             :       // are not connected to any elements and may be deleted
     816             :       // if desired.
     817             : 
     818             :       // Now, delete the unused nodes
     819             :       {
     820      133054 :         std::vector<Node *>::iterator nd        = _nodes.begin();
     821       29760 :         const std::vector<Node *>::iterator end = _nodes.end();
     822             : 
     823       29760 :         std::advance (nd, next_free_node);
     824             : 
     825     1746697 :         for (auto & node : as_range(nd, end))
     826             :           {
     827             :             // Mesh modification code might have already deleted some
     828             :             // nodes
     829     1583883 :             if (node == nullptr)
     830      168342 :               continue;
     831             : 
     832             :             // remove any boundary information associated with
     833             :             // this node
     834     1350519 :             this->get_boundary_info().remove (node);
     835      195108 :             _constraint_rows.erase(node);
     836             : 
     837             :             // delete the node
     838     1350519 :             --_n_nodes;
     839     2603484 :             delete node;
     840     1350519 :             node = nullptr;
     841             :           }
     842             : 
     843      162814 :         _nodes.erase (nd, end);
     844             :       }
     845             :     }
     846             : 
     847      163209 :   this->_preparation.has_removed_orphaned_nodes = true;
     848             : 
     849       29820 :   libmesh_assert_equal_to (next_free_elem, _elements.size());
     850       29820 :   libmesh_assert_equal_to (next_free_node, _nodes.size());
     851             : 
     852      163209 :   this->update_parallel_id_counts();
     853      163209 : }
     854             : 
     855             : 
     856             : 
     857        2220 : void ReplicatedMesh::fix_broken_node_and_element_numbering ()
     858             : {
     859             :   // Nodes first
     860     3180410 :   for (auto n : index_range(_nodes))
     861     3178190 :     if (this->_nodes[n] != nullptr)
     862     3178190 :       this->_nodes[n]->set_id() = cast_int<dof_id_type>(n);
     863             : 
     864             :   // Elements next
     865     3664758 :   for (auto e : index_range(_elements))
     866     3662538 :     if (this->_elements[e] != nullptr)
     867     3662538 :       this->_elements[e]->set_id() = cast_int<dof_id_type>(e);
     868        2220 : }
     869             : 
     870             : 
     871       98371 : dof_id_type ReplicatedMesh::n_active_elem () const
     872             : {
     873      180242 :   return static_cast<dof_id_type>(std::distance (this->active_elements_begin(),
     874      278613 :                                                  this->active_elements_end()));
     875             : }
     876             : 
     877             : std::vector<dof_id_type>
     878         142 : ReplicatedMesh::get_disconnected_subdomains(std::vector<subdomain_id_type> * subdomain_ids) const
     879             : {
     880             :   // find number of disconnected subdomains
     881           4 :   std::vector<dof_id_type> representative_elem_ids;
     882             : 
     883             :   // use subdomain_ids as markers for all elements to indicate if the elements
     884             :   // have been visited. Note: here subdomain ID is unrelated with element
     885             :   // subdomain_id().
     886           8 :   std::vector<subdomain_id_type> subdomains;
     887         142 :   if (!subdomain_ids)
     888           0 :     subdomain_ids = &subdomains;
     889           4 :   subdomain_ids->clear();
     890         142 :   subdomain_ids->resize(max_elem_id() + 1, Elem::invalid_subdomain_id);
     891             : 
     892             :   // counter of disconnected subdomains
     893           4 :   subdomain_id_type subdomain_counter = 0;
     894             : 
     895             :   // a stack for visiting elements, make its capacity sufficiently large to avoid
     896             :   // memory allocation and deallocation when the vector size changes
     897           8 :   std::vector<const Elem *> list;
     898         142 :   list.reserve(n_elem());
     899             : 
     900             :   // counter of visited elements
     901           4 :   dof_id_type visited = 0;
     902         142 :   dof_id_type n_active = n_active_elem();
     903           4 :   do
     904             :   {
     905        1672 :     for (const auto & elem : active_element_ptr_range())
     906         876 :       if ((*subdomain_ids)[elem->id()] == Elem::invalid_subdomain_id)
     907             :       {
     908         284 :         list.push_back(elem);
     909         284 :         (*subdomain_ids)[elem->id()] = subdomain_counter;
     910         284 :         break;
     911         268 :       }
     912             :     // we should be able to find a seed here
     913           8 :     libmesh_assert(list.size() > 0);
     914             : 
     915         284 :     dof_id_type min_id = std::numeric_limits<dof_id_type>::max();
     916        1988 :     while (list.size() > 0)
     917             :     {
     918             :       // pop up an element
     919        1704 :       const Elem * elem = list.back(); list.pop_back(); ++visited;
     920             : 
     921        3084 :       min_id = std::min(elem->id(), min_id);
     922             : 
     923        8520 :       for (auto s : elem->side_index_range())
     924             :       {
     925        6816 :         const Elem * neighbor = elem->neighbor_ptr(s);
     926        6816 :         if (neighbor != nullptr && (*subdomain_ids)[neighbor->id()] == Elem::invalid_subdomain_id)
     927             :         {
     928             :           // neighbor must be active
     929          40 :           libmesh_assert(neighbor->active());
     930        1420 :           list.push_back(neighbor);
     931        1460 :           (*subdomain_ids)[neighbor->id()] = subdomain_counter;
     932             :         }
     933             :       }
     934             :     }
     935             : 
     936         284 :     representative_elem_ids.push_back(min_id);
     937         284 :     subdomain_counter++;
     938             :   }
     939         284 :   while (visited != n_active);
     940             : 
     941         146 :   return representative_elem_ids;
     942             : }
     943             : 
     944             : std::unordered_map<dof_id_type, std::vector<std::vector<Point>>>
     945         142 : ReplicatedMesh::get_boundary_points() const
     946             : {
     947         142 :   libmesh_error_msg_if(mesh_dimension() != 2,
     948             :                        "Error: get_boundary_points only works for 2D now");
     949             : 
     950             :   // find number of disconnected subdomains
     951             :   // subdomains will hold the IDs of disconnected subdomains for all elements.
     952           8 :   std::vector<subdomain_id_type> subdomains;
     953         146 :   std::vector<dof_id_type> elem_ids = get_disconnected_subdomains(&subdomains);
     954             : 
     955           4 :   std::unordered_map<dof_id_type, std::vector<std::vector<Point>>> boundary_points;
     956             : 
     957             :   // get all boundary sides that are to be erased later during visiting
     958             :   // use a comparison functor to avoid run-time randomness due to pointers
     959             :   struct boundary_side_compare
     960             :   {
     961        1584 :     bool operator()(const std::pair<const Elem *, unsigned int> & lhs,
     962             :                     const std::pair<const Elem *, unsigned int> & rhs) const
     963             :       {
     964       42340 :         if (lhs.first->id() < rhs.first->id())
     965         328 :           return true;
     966       29298 :         else if (lhs.first->id() == rhs.first->id())
     967             :         {
     968       14668 :           if (lhs.second < rhs.second)
     969         112 :             return true;
     970             :         }
     971        1144 :         return false;
     972             :       }
     973             :   };
     974           8 :   std::set<std::pair<const Elem *, unsigned int>, boundary_side_compare> boundary_elements;
     975        3592 :   for (const auto & elem : active_element_ptr_range())
     976        8568 :     for (auto s : elem->side_index_range())
     977        7008 :       if (elem->neighbor_ptr(s) == nullptr)
     978        3542 :         boundary_elements.insert(std::pair<const Elem *, unsigned int>(elem, s));
     979             : 
     980         568 :   while (!boundary_elements.empty())
     981             :   {
     982             :     // get the first entry as the seed
     983         426 :     const Elem * eseed = boundary_elements.begin()->first;
     984         426 :     unsigned int sseed = boundary_elements.begin()->second;
     985             : 
     986             :     // get the subdomain ID that these boundary sides attached to
     987         438 :     subdomain_id_type subdomain_id = subdomains[eseed->id()];
     988             : 
     989             :     // start visiting the mesh to find all boundary nodes with the seed
     990          24 :     std::vector<Point> bpoints;
     991         426 :     const Elem * elem = eseed;
     992          12 :     unsigned int s = sseed;
     993         438 :     std::vector<unsigned int> local_side_nodes = elem->nodes_on_side(s);
     994             :     while (true)
     995             :     {
     996          96 :       std::pair<const Elem *, unsigned int> side(elem, s);
     997          96 :       libmesh_assert(boundary_elements.count(side));
     998          96 :       boundary_elements.erase(side);
     999             : 
    1000             :       // push all nodes on the side except the node on the other end of the side (index 1)
    1001       11928 :       for (auto i : index_range(local_side_nodes))
    1002        8520 :         if (i != 1)
    1003        5400 :           bpoints.push_back(*static_cast<const Point *>(elem->node_ptr(local_side_nodes[i])));
    1004             : 
    1005             :       // use the last node to find next element and side
    1006        3408 :       const Node * node = elem->node_ptr(local_side_nodes[1]);
    1007          96 :       std::set<const Elem *> neighbors;
    1008        3408 :       elem->find_point_neighbors(*node, neighbors);
    1009             : 
    1010             :       // if only one neighbor is found (itself), this node is a cornor node on boundary
    1011        3408 :       if (neighbors.size() != 1)
    1012          64 :         neighbors.erase(elem);
    1013             : 
    1014             :       // find the connecting side
    1015          96 :       bool found = false;
    1016        3676 :       for (const auto & neighbor : neighbors)
    1017             :       {
    1018        9966 :         for (auto ss : neighbor->side_index_range())
    1019        9872 :           if (neighbor->neighbor_ptr(ss) == nullptr && !(elem == neighbor && s == ss))
    1020             :           {
    1021        4938 :             local_side_nodes = neighbor->nodes_on_side(ss);
    1022             :             // we expect the starting point of the side to be the same as the end of the previous side
    1023        5082 :             if (neighbor->node_ptr(local_side_nodes[0]) == node)
    1024             :             {
    1025        3408 :               elem = neighbor;
    1026          96 :               s = ss;
    1027          96 :               found = true;
    1028          96 :               break;
    1029             :             }
    1030        1578 :             else if (neighbor->node_ptr(local_side_nodes[1]) == node)
    1031             :             {
    1032           0 :               elem = neighbor;
    1033           0 :               s = ss;
    1034           0 :               found = true;
    1035             :               // flip nodes in local_side_nodes because the side is in an opposite direction
    1036           0 :               auto temp(local_side_nodes);
    1037           0 :               local_side_nodes[0] = temp[1];
    1038           0 :               local_side_nodes[1] = temp[0];
    1039           0 :               for (unsigned int i = 2; i < temp.size(); ++i)
    1040           0 :                 local_side_nodes[temp.size() + 1 - i] = temp[i];
    1041           0 :               break;
    1042             :             }
    1043             :           }
    1044         101 :         if (found)
    1045          96 :           break;
    1046             :       }
    1047             : 
    1048        3408 :       libmesh_error_msg_if(!found, "ERROR: mesh topology error on visiting boundary sides");
    1049             : 
    1050             :       // exit if we reach the starting point
    1051        3408 :       if (elem == eseed && s == sseed)
    1052          12 :         break;
    1053          84 :     }
    1054         426 :     boundary_points[elem_ids[subdomain_id]].push_back(bpoints);
    1055             :   }
    1056             : 
    1057         146 :   return boundary_points;
    1058             : }
    1059             : 
    1060             : } // namespace libMesh

Generated by: LCOV version 1.14