LCOV - code coverage report
Current view: top level - src/mesh - replicated_mesh.C (source / functions) Hit Total Coverage
Test: libMesh/libmesh: #4229 (6a9aeb) with base 727f46 Lines: 392 453 86.5 %
Date: 2025-08-19 19:27:09 Functions: 48 54 88.9 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // The libMesh Finite Element Library.
       2             : // Copyright (C) 2002-2025 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       48994 : ReplicatedMesh::ReplicatedMesh (const Parallel::Communicator & comm_in,
      43       48994 :                                 unsigned char d) :
      44             :   UnstructuredMesh (comm_in,d),
      45       48994 :   _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       48994 :   _next_unique_id = 0;
      51             : #endif
      52             : 
      53       57588 :   const std::string default_partitioner = "metis";
      54             :   const std::string my_partitioner =
      55             :     libMesh::command_line_value("--default-partitioner",
      56       97988 :                                 default_partitioner);
      57             :   _partitioner = Partitioner::build
      58       89394 :     (Utility::string_to_enum<PartitionerType>(my_partitioner));
      59       48994 : }
      60             : 
      61             : 
      62        1414 : bool ReplicatedMesh::subclass_locally_equals(const MeshBase & other_mesh_base) const
      63             : {
      64         770 :   const ReplicatedMesh * rep_mesh_ptr =
      65        1414 :     dynamic_cast<const ReplicatedMesh *>(&other_mesh_base);
      66        1414 :   if (!rep_mesh_ptr)
      67           0 :     return false;
      68         770 :   const ReplicatedMesh & other_mesh = *rep_mesh_ptr;
      69             : 
      70        3598 :   if (_n_nodes != other_mesh._n_nodes ||
      71        1414 :       _n_elem != other_mesh._n_elem ||
      72             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
      73        4242 :       _next_unique_id != other_mesh._next_unique_id ||
      74             : #endif
      75        1414 :       !this->nodes_and_elements_equal(other_mesh))
      76          78 :     return false;
      77             : 
      78         766 :   return true;
      79             : }
      80             : 
      81             : 
      82       62334 : ReplicatedMesh::~ReplicatedMesh ()
      83             : {
      84       52777 :   this->ReplicatedMesh::clear();  // Free nodes and elements
      85       62334 : }
      86             : 
      87             : 
      88             : // This might be specialized later, but right now it's just here to
      89             : // make sure the compiler doesn't give us a default (non-deep) copy
      90             : // constructor instead.
      91        3712 : ReplicatedMesh::ReplicatedMesh (const ReplicatedMesh & other_mesh) :
      92        3712 :   ReplicatedMesh(static_cast<const MeshBase&>(other_mesh))
      93             : {
      94             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
      95        3712 :   this->_next_unique_id = other_mesh._next_unique_id;
      96             : #endif
      97        3712 : }
      98             : 
      99             : 
     100        3783 : ReplicatedMesh::ReplicatedMesh (const MeshBase & other_mesh) :
     101             :   UnstructuredMesh (other_mesh),
     102        3783 :   _n_nodes(0), _n_elem(0) // copy_* will increment this
     103             : {
     104        3783 :   this->copy_nodes_and_elements(other_mesh, true);
     105             : 
     106        1372 :   this->allow_find_neighbors(other_mesh.allow_find_neighbors());
     107        1372 :   this->allow_renumbering(other_mesh.allow_renumbering());
     108        1372 :   this->allow_remote_element_removal(other_mesh.allow_remote_element_removal());
     109        1372 :   this->skip_partitioning(other_mesh.skip_partitioning());
     110             : 
     111             :   // The prepare_for_use() in copy_nodes_and_elements() is going to be
     112             :   // tricky to remove without breaking backwards compatibility, but it
     113             :   // updates some things we want to just copy.
     114        3783 :   this->copy_cached_data(other_mesh);
     115             : 
     116        3783 :   this->copy_constraint_rows(other_mesh);
     117             : 
     118        3783 :   this->_is_prepared = other_mesh.is_prepared();
     119             : 
     120         694 :   auto & this_boundary_info = this->get_boundary_info();
     121         694 :   const auto & other_boundary_info = other_mesh.get_boundary_info();
     122             : 
     123        3783 :   this_boundary_info = other_boundary_info;
     124             : 
     125         694 :   this->set_subdomain_name_map() = other_mesh.get_subdomain_name_map();
     126             : 
     127             :   // If other_mesh is distributed, then we've got parts of it on each
     128             :   // processor but we're not replicated yet; fix that.
     129        3783 :   if (!other_mesh.is_serial())
     130          71 :     MeshCommunication().allgather(*this);
     131        3783 : }
     132             : 
     133         156 : ReplicatedMesh & ReplicatedMesh::operator= (ReplicatedMesh && other_mesh)
     134             : {
     135           8 :   LOG_SCOPE("operator=(&&)", "ReplicatedMesh");
     136             : 
     137             :   // Move assign as an UnstructuredMesh
     138           8 :   this->UnstructuredMesh::operator=(std::move(other_mesh));
     139             : 
     140             :   // Nodes and elements belong to ReplicatedMesh and have to be
     141             :   // moved before we can move arbitrary GhostingFunctor, Partitioner,
     142             :   // etc. subclasses.
     143         156 :   this->move_nodes_and_elements(std::move(other_mesh));
     144             : 
     145             :   // Handle those remaining moves.
     146         156 :   this->post_dofobject_moves(std::move(other_mesh));
     147             : 
     148         164 :   return *this;
     149             : }
     150             : 
     151         156 : MeshBase & ReplicatedMesh::assign(MeshBase && other_mesh)
     152             : {
     153         156 :   *this = std::move(cast_ref<ReplicatedMesh&>(other_mesh));
     154             : 
     155         156 :   return *this;
     156             : }
     157             : 
     158         156 : void ReplicatedMesh::move_nodes_and_elements(MeshBase && other_meshbase)
     159             : {
     160           8 :   ReplicatedMesh & other_mesh = cast_ref<ReplicatedMesh&>(other_meshbase);
     161             : 
     162         156 :   this->_nodes = std::move(other_mesh._nodes);
     163         156 :   this->_n_nodes = other_mesh.n_nodes();
     164             : 
     165         156 :   this->_elements = std::move(other_mesh._elements);
     166         156 :   this->_n_elem = other_mesh.n_elem();
     167         156 : }
     168             : 
     169             : 
     170    15323614 : const Point & ReplicatedMesh::point (const dof_id_type i) const
     171             : {
     172    15323614 :   return this->node_ref(i);
     173             : }
     174             : 
     175             : 
     176             : 
     177             : 
     178   100853687 : const Node * ReplicatedMesh::node_ptr (const dof_id_type i) const
     179             : {
     180     5035399 :   libmesh_assert_less (i, this->max_node_id());
     181     5035399 :   libmesh_assert(_nodes[i]);
     182     5035399 :   libmesh_assert_equal_to (_nodes[i]->id(), i); // This will change soon
     183             : 
     184   105851186 :   return _nodes[i];
     185             : }
     186             : 
     187             : 
     188             : 
     189             : 
     190   102814018 : Node * ReplicatedMesh::node_ptr (const dof_id_type i)
     191             : {
     192    12422848 :   libmesh_assert_less (i, this->max_node_id());
     193    12422848 :   libmesh_assert(_nodes[i]);
     194    12422848 :   libmesh_assert_equal_to (_nodes[i]->id(), i); // This will change soon
     195             : 
     196   114640131 :   return _nodes[i];
     197             : }
     198             : 
     199             : 
     200             : 
     201             : 
     202    15892260 : const Node * ReplicatedMesh::query_node_ptr (const dof_id_type i) const
     203             : {
     204    15892260 :   if (i >= this->max_node_id())
     205           2 :     return nullptr;
     206    15765053 :   libmesh_assert (_nodes[i] == nullptr ||
     207             :                   _nodes[i]->id() == i); // This will change soon
     208             : 
     209    15930368 :   return _nodes[i];
     210             : }
     211             : 
     212             : 
     213             : 
     214             : 
     215     1565962 : Node * ReplicatedMesh::query_node_ptr (const dof_id_type i)
     216             : {
     217     1565962 :   if (i >= this->max_node_id())
     218       59038 :     return nullptr;
     219      100713 :   libmesh_assert (_nodes[i] == nullptr ||
     220             :                   _nodes[i]->id() == i); // This will change soon
     221             : 
     222      981341 :   return _nodes[i];
     223             : }
     224             : 
     225             : 
     226             : 
     227             : 
     228     2305519 : const Elem * ReplicatedMesh::elem_ptr (const dof_id_type i) const
     229             : {
     230      497460 :   libmesh_assert_less (i, this->max_elem_id());
     231      497460 :   libmesh_assert(_elements[i]);
     232      497460 :   libmesh_assert_equal_to (_elements[i]->id(), i); // This will change soon
     233             : 
     234     2703868 :   return _elements[i];
     235             : }
     236             : 
     237             : 
     238             : 
     239             : 
     240    77624096 : Elem * ReplicatedMesh::elem_ptr (const dof_id_type i)
     241             : {
     242     4853499 :   libmesh_assert_less (i, this->max_elem_id());
     243     4853499 :   libmesh_assert(_elements[i]);
     244     4853499 :   libmesh_assert_equal_to (_elements[i]->id(), i); // This will change soon
     245             : 
     246    81845915 :   return _elements[i];
     247             : }
     248             : 
     249             : 
     250             : 
     251             : 
     252    15515357 : const Elem * ReplicatedMesh::query_elem_ptr (const dof_id_type i) const
     253             : {
     254    15515357 :   if (i >= this->max_elem_id())
     255           4 :     return nullptr;
     256    15470536 :   libmesh_assert (_elements[i] == nullptr ||
     257             :                   _elements[i]->id() == i); // This will change soon
     258             : 
     259    15529816 :   return _elements[i];
     260             : }
     261             : 
     262             : 
     263             : 
     264             : 
     265     1414850 : Elem * ReplicatedMesh::query_elem_ptr (const dof_id_type i)
     266             : {
     267     1414850 :   if (i >= this->max_elem_id())
     268       42891 :     return nullptr;
     269      188466 :   libmesh_assert (_elements[i] == nullptr ||
     270             :                   _elements[i]->id() == i); // This will change soon
     271             : 
     272      765367 :   return _elements[i];
     273             : }
     274             : 
     275             : 
     276             : 
     277             : 
     278    15273193 : Elem * ReplicatedMesh::add_elem (Elem * e)
     279             : {
     280     1114768 :   libmesh_assert(e);
     281             : 
     282             :   // We no longer merely append elements with ReplicatedMesh
     283             : 
     284             :   // If the user requests a valid id that doesn't correspond to an
     285             :   // existing element, let's give them that id, resizing the elements
     286             :   // container if necessary.
     287    15273193 :   if (!e->valid_id())
     288      793044 :     e->set_id (cast_int<dof_id_type>(_elements.size()));
     289             : 
     290             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
     291    15273193 :   if (!e->valid_unique_id())
     292     4581042 :     e->set_unique_id(_next_unique_id++);
     293             :   else
     294    11525956 :    _next_unique_id = std::max(_next_unique_id, e->unique_id()+1);
     295             : #endif
     296             : 
     297     2218716 :   const dof_id_type id = e->id();
     298             : 
     299    16377141 :   if (id < _elements.size())
     300             :     {
     301             :       // This should *almost* never happen, but we rely on it when
     302             :       // using allgather to replicate a not-yet-actually-replicated
     303             :       // ReplicatedMesh under construction in parallel.
     304      144798 :       if (e == _elements[id])
     305           0 :         return e;
     306             : 
     307             :       // Overwriting existing elements is still probably a mistake.
     308       12996 :       libmesh_assert(!_elements[id]);
     309             :     }
     310             :   else
     311             :     {
     312    15128395 :       _elements.resize(id+1, nullptr);
     313             :     }
     314             : 
     315    15273193 :   ++_n_elem;
     316    15273193 :   _elements[id] = e;
     317             : 
     318             :   // Make sure any new element is given space for any extra integers
     319             :   // we've requested
     320    15273193 :   e->add_extra_integers(_elem_integer_names.size(),
     321    15273193 :                         _elem_integer_default_values);
     322             : 
     323             :   // And set mapping type and data on any new element
     324     2218716 :   e->set_mapping_type(this->default_mapping_type());
     325     2218716 :   e->set_mapping_data(this->default_mapping_data());
     326             : 
     327    15273193 :   return e;
     328             : }
     329             : 
     330    14465708 : Elem * ReplicatedMesh::add_elem (std::unique_ptr<Elem> e)
     331             : {
     332             :   // The mesh now takes ownership of the Elem. Eventually the guts of
     333             :   // add_elem() will get moved to a private helper function, and
     334             :   // calling add_elem() directly will be deprecated.
     335    14465708 :   return add_elem(e.release());
     336             : }
     337             : 
     338             : 
     339             : 
     340      554231 : Elem * ReplicatedMesh::insert_elem (Elem * e)
     341             : {
     342             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
     343      554231 :   if (!e->valid_unique_id())
     344       18176 :     e->set_unique_id(_next_unique_id++);
     345             :   else
     346      536055 :    _next_unique_id = std::max(_next_unique_id, e->unique_id()+1);
     347             : #endif
     348             : 
     349      239108 :   dof_id_type eid = e->id();
     350      119554 :   libmesh_assert_less (eid, _elements.size());
     351      554231 :   Elem * oldelem = _elements[eid];
     352             : 
     353      554231 :   if (oldelem)
     354             :     {
     355      119554 :       libmesh_assert_equal_to (oldelem->id(), eid);
     356      554231 :       this->delete_elem(oldelem);
     357             :     }
     358             : 
     359      554231 :   ++_n_elem;
     360      554231 :   _elements[eid] = e;
     361             : 
     362             :   // Make sure any new element is given space for any extra integers
     363             :   // we've requested
     364      554231 :   e->add_extra_integers(_elem_integer_names.size(),
     365      554231 :                         _elem_integer_default_values);
     366             : 
     367             :   // And set mapping type and data on any new element
     368      239108 :   e->set_mapping_type(this->default_mapping_type());
     369      239108 :   e->set_mapping_data(this->default_mapping_data());
     370             : 
     371      554231 :   return e;
     372             : }
     373             : 
     374      554231 : Elem * ReplicatedMesh::insert_elem (std::unique_ptr<Elem> e)
     375             : {
     376             :   // The mesh now takes ownership of the Elem. Eventually the guts of
     377             :   // insert_elem(Elem*) will get moved to a private helper function, and
     378             :   // calling insert_elem(Elem*) directly will be deprecated.
     379      554231 :   return insert_elem(e.release());
     380             : }
     381             : 
     382             : 
     383             : 
     384     2007902 : void ReplicatedMesh::delete_elem(Elem * e)
     385             : {
     386      217195 :   libmesh_assert(e);
     387             : 
     388             :   // Initialize an iterator to eventually point to the element we want to delete
     389      217195 :   std::vector<Elem *>::iterator pos = _elements.end();
     390             : 
     391             :   // In many cases, e->id() gives us a clue as to where e
     392             :   // is located in the _elements vector.  Try that first
     393             :   // before trying the O(n_elem) search.
     394      217195 :   libmesh_assert_less (e->id(), _elements.size());
     395             : 
     396     2225097 :   if (_elements[e->id()] == e)
     397             :     {
     398             :       // We found it!
     399     1790707 :       pos = _elements.begin();
     400      217195 :       std::advance(pos, e->id());
     401             :     }
     402             : 
     403             :   else
     404             :     {
     405             :       // This search is O(n_elem)
     406           0 :       pos = std::find (_elements.begin(),
     407             :                        _elements.end(),
     408           0 :                        e);
     409             :     }
     410             : 
     411             :   // Huh? Element not in the vector?
     412      217195 :   libmesh_assert (pos != _elements.end());
     413             : 
     414             :   // Remove the element from the BoundaryInfo object
     415     2007902 :   this->get_boundary_info().remove(e);
     416             : 
     417             :   // delete the element
     418     2007902 :   --_n_elem;
     419     2007902 :   delete e;
     420             : 
     421             :   // explicitly zero the pointer
     422     2007902 :   *pos = nullptr;
     423     2007902 : }
     424             : 
     425             : 
     426             : 
     427           0 : void ReplicatedMesh::renumber_elem(const dof_id_type old_id,
     428             :                                    const dof_id_type new_id)
     429             : {
     430             :   // This could be a no-op
     431           0 :   if (old_id == new_id)
     432           0 :     return;
     433             : 
     434             :   // This doesn't get used in serial yet
     435           0 :   Elem * el = _elements[old_id];
     436           0 :   libmesh_assert (el);
     437             : 
     438           0 :   if (new_id >= _elements.size())
     439           0 :     _elements.resize(new_id+1, nullptr);
     440             : 
     441           0 :   el->set_id(new_id);
     442           0 :   libmesh_assert (!_elements[new_id]);
     443           0 :   _elements[new_id] = el;
     444           0 :   _elements[old_id] = nullptr;
     445             : }
     446             : 
     447             : 
     448             : 
     449    10843485 : Node * ReplicatedMesh::add_point (const Point & p,
     450             :                                   const dof_id_type id,
     451             :                                   const processor_id_type proc_id)
     452             : {
     453     1751405 :   Node * n = nullptr;
     454             : 
     455             :   // If the user requests a valid id, either
     456             :   // provide the existing node or resize the container
     457             :   // to fit the new node.
     458    10843485 :   if (id != DofObject::invalid_id)
     459     7674858 :     if (id < _nodes.size())
     460       10309 :       n = _nodes[id];
     461             :     else
     462     6747872 :       _nodes.resize(id+1);
     463             :   else
     464     4085304 :     _nodes.push_back (static_cast<Node *>(nullptr));
     465             : 
     466             :   // if the node already exists, then assign new (x,y,z) values
     467     1760864 :   if (n)
     468           0 :     *n = p;
     469             :   // otherwise build a new node, put it in the right spot, and return
     470             :   // a valid pointer.
     471             :   else
     472             :     {
     473    20770289 :       n = Node::build(p, (id == DofObject::invalid_id) ?
     474     6669297 :                       cast_int<dof_id_type>(_nodes.size()-1) : id).release();
     475    10843485 :       n->processor_id() = proc_id;
     476             : 
     477    10843485 :       n->add_extra_integers(_node_integer_names.size(),
     478    10843485 :                             _node_integer_default_values);
     479             : 
     480             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
     481    10843485 :       if (!n->valid_unique_id())
     482    10843485 :         n->set_unique_id(_next_unique_id++);
     483             :       else
     484           0 :        _next_unique_id = std::max(_next_unique_id, n->unique_id()+1);
     485             : #endif
     486             : 
     487    10843485 :       ++_n_nodes;
     488    10843485 :       if (id == DofObject::invalid_id)
     489     4085304 :         _nodes.back() = n;
     490             :       else
     491     7674858 :         _nodes[id] = n;
     492             :     }
     493             : 
     494             :   // better not pass back a nullptr.
     495     1751405 :   libmesh_assert (n);
     496             : 
     497    10843485 :   return n;
     498             : }
     499             : 
     500             : 
     501             : 
     502      697761 : Node * ReplicatedMesh::add_node (Node * n)
     503             : {
     504       62046 :   libmesh_assert(n);
     505             : 
     506             :   // If the user requests a valid id, either set the existing
     507             :   // container entry or resize the container to fit the new node.
     508      697761 :   if (n->valid_id())
     509             :     {
     510       62046 :       const dof_id_type id = n->id();
     511      759807 :       if (id < _nodes.size())
     512        6710 :         libmesh_assert(!_nodes[id]);
     513             :       else
     514      625722 :         _nodes.resize(id+1); // default nullptr
     515             : 
     516      759807 :       _nodes[id] = n;
     517             :     }
     518             :   else
     519             :     {
     520           0 :       n->set_id (cast_int<dof_id_type>(_nodes.size()));
     521           0 :       _nodes.push_back(n);
     522             :     }
     523             : 
     524      697761 :   ++_n_nodes;
     525             : 
     526             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
     527      697761 :   if (!n->valid_unique_id())
     528           0 :     n->set_unique_id(_next_unique_id++);
     529             :   else
     530     1158512 :    _next_unique_id = std::max(_next_unique_id, n->unique_id()+1);
     531             : #endif
     532             : 
     533      697761 :   n->add_extra_integers(_node_integer_names.size(),
     534      697761 :                         _node_integer_default_values);
     535             : 
     536      697761 :   return n;
     537             : }
     538             : 
     539      697761 : Node * ReplicatedMesh::add_node (std::unique_ptr<Node> n)
     540             : {
     541             :   // The mesh now takes ownership of the Node. Eventually the guts of
     542             :   // add_node() will get moved to a private helper function, and
     543             :   // calling add_node() directly will be deprecated.
     544      697761 :   return add_node(n.release());
     545             : }
     546             : 
     547             : #ifdef LIBMESH_ENABLE_DEPRECATED
     548             : 
     549           0 : Node * ReplicatedMesh::insert_node(Node * n)
     550             : {
     551             :   libmesh_deprecated();
     552           0 :   libmesh_error_msg_if(!n, "Error, attempting to insert nullptr node.");
     553           0 :   libmesh_error_msg_if(n->id() == DofObject::invalid_id, "Error, cannot insert node with invalid id.");
     554             : 
     555           0 :   if (n->id() < _nodes.size())
     556             :     {
     557             :       // Trying to add an existing node is a no-op.  This lets us use
     558             :       // a straightforward MeshCommunication::allgather() to fix a
     559             :       // not-actually-replicated-yet ReplicatedMesh, as occurs when
     560             :       // reading Nemesis files.
     561           0 :       if (n->valid_id() && _nodes[n->id()] == n)
     562           0 :         return n;
     563             : 
     564             :       // Don't allow anything else to replace an existing Node.
     565           0 :       libmesh_error_msg_if(_nodes[ n->id() ] != nullptr,
     566             :                            "Error, cannot insert new node on top of existing node.");
     567             :     }
     568             :   else
     569             :     {
     570             :       // Allocate just enough space to store the new node.  This will
     571             :       // cause highly non-ideal memory allocation behavior if called
     572             :       // repeatedly...
     573           0 :       _nodes.resize(n->id() + 1);
     574             :     }
     575             : 
     576             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
     577           0 :   if (!n->valid_unique_id())
     578           0 :     n->set_unique_id(_next_unique_id++);
     579             :   else
     580           0 :    _next_unique_id = std::max(_next_unique_id, n->unique_id()+1);
     581             : #endif
     582             : 
     583           0 :   n->add_extra_integers(_node_integer_names.size(),
     584           0 :                         _node_integer_default_values);
     585             : 
     586             :   // We have enough space and this spot isn't already occupied by
     587             :   // another node, so go ahead and add it.
     588           0 :   ++_n_nodes;
     589           0 :   _nodes[ n->id() ] = n;
     590             : 
     591             :   // If we made it this far, we just inserted the node the user handed
     592             :   // us, so we can give it right back.
     593           0 :   return n;
     594             : }
     595             : 
     596           0 : Node * ReplicatedMesh::insert_node(std::unique_ptr<Node> n)
     597             : {
     598             :   libmesh_deprecated();
     599             :   // The mesh now takes ownership of the Node. Eventually the guts of
     600             :   // insert_node(Node*) will get moved to a private helper function, and
     601             :   // calling insert_node(Node*) directly will be deprecated.
     602           0 :   return insert_node(n.release());
     603             : }
     604             : 
     605             : #endif
     606             : 
     607      250701 : void ReplicatedMesh::delete_node(Node * n)
     608             : {
     609       63997 :   libmesh_assert(n);
     610       63997 :   libmesh_assert_less (n->id(), _nodes.size());
     611             : 
     612             :   // Initialize an iterator to eventually point to the element we want
     613             :   // to delete
     614       63997 :   std::vector<Node *>::iterator pos;
     615             : 
     616             :   // In many cases, e->id() gives us a clue as to where e
     617             :   // is located in the _elements vector.  Try that first
     618             :   // before trying the O(n_elem) search.
     619      314698 :   if (_nodes[n->id()] == n)
     620             :     {
     621      186704 :       pos = _nodes.begin();
     622       63997 :       std::advance(pos, n->id());
     623             :     }
     624             :   else
     625             :     {
     626           0 :       pos = std::find (_nodes.begin(),
     627             :                        _nodes.end(),
     628           0 :                        n);
     629             :     }
     630             : 
     631             :   // Huh? Node not in the vector?
     632       63997 :   libmesh_assert (pos != _nodes.end());
     633             : 
     634             :   // Delete the node from the BoundaryInfo object
     635      250701 :   this->get_boundary_info().remove(n);
     636      127994 :   _constraint_rows.erase(n);
     637             : 
     638             :   // delete the node
     639      250701 :   --_n_nodes;
     640      437405 :   delete n;
     641             : 
     642             :   // explicitly zero the pointer
     643      250701 :   *pos = nullptr;
     644      250701 : }
     645             : 
     646             : 
     647             : 
     648           0 : void ReplicatedMesh::renumber_node(const dof_id_type old_id,
     649             :                                    const dof_id_type new_id)
     650             : {
     651             :   // This could be a no-op
     652           0 :   if (old_id == new_id)
     653           0 :     return;
     654             : 
     655             :   // This doesn't get used in serial yet
     656           0 :   Node * nd = _nodes[old_id];
     657           0 :   libmesh_assert (nd);
     658             : 
     659           0 :   if (new_id >= _nodes.size())
     660           0 :     _nodes.resize(new_id+1, nullptr);
     661             : 
     662           0 :   nd->set_id(new_id);
     663           0 :   libmesh_assert (!_nodes[new_id]);
     664           0 :   _nodes[new_id] = nd;
     665           0 :   _nodes[old_id] = nullptr;
     666             : }
     667             : 
     668             : 
     669             : 
     670       94746 : void ReplicatedMesh::clear ()
     671             : {
     672             :   // Call parent clear function
     673       94746 :   MeshBase::clear();
     674             : 
     675             :   // Clear our elements and nodes
     676             :   // There is no need to remove them from
     677             :   // the BoundaryInfo data structure since we
     678             :   // already cleared it.
     679       94746 :   this->ReplicatedMesh::clear_elems();
     680             : 
     681    10330200 :   for (auto & node : _nodes)
     682    18835884 :     delete node;
     683             : 
     684       94746 :   _n_nodes = 0;
     685       18024 :   _nodes.clear();
     686       94746 : }
     687             : 
     688             : 
     689             : 
     690       95398 : void ReplicatedMesh::clear_elems ()
     691             : {
     692    13994839 :   for (auto & elem : _elements)
     693    13899441 :     delete elem;
     694             : 
     695       95398 :   _n_elem = 0;
     696       18212 :   _elements.clear();
     697       95398 : }
     698             : 
     699             : 
     700             : 
     701      153816 : void ReplicatedMesh::update_parallel_id_counts()
     702             : {
     703             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
     704      153816 :   _next_unique_id = this->parallel_max_unique_id();
     705             : #endif
     706      153816 : }
     707             : 
     708             : 
     709             : 
     710             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
     711      168048 : unique_id_type ReplicatedMesh::parallel_max_unique_id() const
     712             : {
     713             :   // This function must be run on all processors at once
     714       27622 :   parallel_object_only();
     715             : 
     716      168048 :   unique_id_type max_local = _next_unique_id;
     717      168048 :   this->comm().max(max_local);
     718      168048 :   return max_local;
     719             : }
     720             : 
     721             : 
     722             : 
     723       10376 : void ReplicatedMesh::set_next_unique_id(unique_id_type id)
     724             : {
     725       10376 :   _next_unique_id = id;
     726       10376 : }
     727             : #endif
     728             : 
     729             : 
     730             : 
     731      124263 : void ReplicatedMesh::renumber_nodes_and_elements ()
     732             : {
     733       44448 :   LOG_SCOPE("renumber_nodes_and_elem()", "Mesh");
     734             : 
     735             :   // node and element id counters
     736       22224 :   dof_id_type next_free_elem = 0;
     737       22224 :   dof_id_type next_free_node = 0;
     738             : 
     739             :   // Will hold the set of nodes that are currently connected to elements
     740       44448 :   std::unordered_set<Node *> connected_nodes;
     741             : 
     742             :   // Loop over the elements.  Note that there may
     743             :   // be nullptrs in the _elements vector from the coarsening
     744             :   // process.  Pack the elements in to a contiguous array
     745             :   // and then trim any excess.
     746             :   {
     747       22224 :     std::vector<Elem *>::iterator in        = _elements.begin();
     748       22224 :     std::vector<Elem *>::iterator out_iter  = _elements.begin();
     749       22224 :     const std::vector<Elem *>::iterator end = _elements.end();
     750             : 
     751    34595300 :     for (; in != end; ++in)
     752    34471037 :       if (*in != nullptr)
     753             :         {
     754     2875984 :           Elem * el = *in;
     755             : 
     756    33188219 :           *out_iter = *in;
     757     2875984 :           ++out_iter;
     758             : 
     759             :           // Increment the element counter
     760    33188219 :           el->set_id (next_free_elem++);
     761             : 
     762    33188219 :           if (_skip_renumber_nodes_and_elements)
     763             :             {
     764             :               // Add this elements nodes to the connected list
     765     2051315 :               for (auto & n : el->node_ref_range())
     766     1846096 :                 connected_nodes.insert(&n);
     767             :             }
     768             :           else  // We DO want node renumbering
     769             :             {
     770             :               // Loop over this element's nodes.  Number them,
     771             :               // if they have not been numbered already.  Also,
     772             :               // position them in the _nodes vector so that they
     773             :               // are packed contiguously from the beginning.
     774   191792174 :               for (auto & n : el->node_ref_range())
     775   158809174 :                 if (n.id() == next_free_node)    // don't need to process
     776    25867116 :                   next_free_node++;                      // [(src == dst) below]
     777             : 
     778   132942058 :                 else if (n.id() > next_free_node) // need to process
     779             :                   {
     780             :                     // The source and destination indices
     781             :                     // for this node
     782     1061994 :                     const dof_id_type src_idx = n.id();
     783     7304460 :                     const dof_id_type dst_idx = next_free_node++;
     784             : 
     785             :                     // ensure we want to swap a valid nodes
     786     1061994 :                     libmesh_assert(_nodes[src_idx]);
     787             : 
     788             :                     // Swap the source and destination nodes
     789     2644164 :                     std::swap(_nodes[src_idx],
     790     2644164 :                               _nodes[dst_idx] );
     791             : 
     792             :                     // Set proper indices where that makes sense
     793     7304460 :                     if (_nodes[src_idx] != nullptr)
     794     1048668 :                       _nodes[src_idx]->set_id (src_idx);
     795     1061994 :                     _nodes[dst_idx]->set_id (dst_idx);
     796             :                   }
     797             :             }
     798             :         }
     799             : 
     800             :     // Erase any additional storage. These elements have been
     801             :     // copied into nullptr voids by the procedure above, and are
     802             :     // thus repeated and unnecessary.
     803      124263 :     _elements.erase (out_iter, end);
     804             :   }
     805             : 
     806             : 
     807      124263 :   if (_skip_renumber_nodes_and_elements)
     808             :     {
     809             :       // Loop over the nodes.  Note that there may
     810             :       // be nullptrs in the _nodes vector from the coarsening
     811             :       // process.  Pack the nodes in to a contiguous array
     812             :       // and then trim any excess.
     813             : 
     814          56 :       std::vector<Node *>::iterator in        = _nodes.begin();
     815          56 :       std::vector<Node *>::iterator out_iter  = _nodes.begin();
     816          56 :       const std::vector<Node *>::iterator end = _nodes.end();
     817             : 
     818      901831 :       for (; in != end; ++in)
     819      901446 :         if (*in != nullptr)
     820             :           {
     821             :             // This is a reference so that if we change the pointer it will change in the vector
     822      200046 :             Node * & nd = *in;
     823             : 
     824             :             // If this node is still connected to an elem, put it in the list
     825      400092 :             if (connected_nodes.count(nd))
     826             :               {
     827      649782 :                 *out_iter = nd;
     828      128142 :                 ++out_iter;
     829             : 
     830             :                 // Increment the node counter
     831      649782 :                 nd->set_id (next_free_node++);
     832             :               }
     833             :             else // This node is orphaned, delete it!
     834             :               {
     835      251664 :                 this->get_boundary_info().remove (nd);
     836      143808 :                 _constraint_rows.erase(nd);
     837             : 
     838             :                 // delete the node
     839      251664 :                 --_n_nodes;
     840      431424 :                 delete nd;
     841      251664 :                 nd = nullptr;
     842             :               }
     843             :           }
     844             : 
     845             :       // Erase any additional storage.  Whatever was
     846         385 :       _nodes.erase (out_iter, end);
     847             :     }
     848             :   else // We really DO want node renumbering
     849             :     {
     850             :       // Any nodes in the vector >= _nodes[next_free_node]
     851             :       // are not connected to any elements and may be deleted
     852             :       // if desired.
     853             : 
     854             :       // Now, delete the unused nodes
     855             :       {
     856      101710 :         std::vector<Node *>::iterator nd        = _nodes.begin();
     857       22168 :         const std::vector<Node *>::iterator end = _nodes.end();
     858             : 
     859       22168 :         std::advance (nd, next_free_node);
     860             : 
     861     1193307 :         for (auto & node : as_range(nd, end))
     862             :           {
     863             :             // Mesh modification code might have already deleted some
     864             :             // nodes
     865     1069429 :             if (node == nullptr)
     866      164880 :               continue;
     867             : 
     868             :             // remove any boundary information associated with
     869             :             // this node
     870      840651 :             this->get_boundary_info().remove (node);
     871      159500 :             _constraint_rows.erase(node);
     872             : 
     873             :             // delete the node
     874      840651 :             --_n_nodes;
     875     1601552 :             delete node;
     876      840651 :             node = nullptr;
     877             :           }
     878             : 
     879      123878 :         _nodes.erase (nd, end);
     880             :       }
     881             :     }
     882             : 
     883       22224 :   libmesh_assert_equal_to (next_free_elem, _elements.size());
     884       22224 :   libmesh_assert_equal_to (next_free_node, _nodes.size());
     885             : 
     886      124263 :   this->update_parallel_id_counts();
     887      124263 : }
     888             : 
     889             : 
     890             : 
     891        2080 : void ReplicatedMesh::fix_broken_node_and_element_numbering ()
     892             : {
     893             :   // Nodes first
     894     2948210 :   for (auto n : index_range(_nodes))
     895     2946130 :     if (this->_nodes[n] != nullptr)
     896     2946130 :       this->_nodes[n]->set_id() = cast_int<dof_id_type>(n);
     897             : 
     898             :   // Elements next
     899     3585538 :   for (auto e : index_range(_elements))
     900     3583458 :     if (this->_elements[e] != nullptr)
     901     3583458 :       this->_elements[e]->set_id() = cast_int<dof_id_type>(e);
     902        2080 : }
     903             : 
     904             : 
     905       86474 : dof_id_type ReplicatedMesh::n_active_elem () const
     906             : {
     907      157732 :   return static_cast<dof_id_type>(std::distance (this->active_elements_begin(),
     908      244206 :                                                  this->active_elements_end()));
     909             : }
     910             : 
     911             : std::vector<dof_id_type>
     912         142 : ReplicatedMesh::get_disconnected_subdomains(std::vector<subdomain_id_type> * subdomain_ids) const
     913             : {
     914             :   // find number of disconnected subdomains
     915           4 :   std::vector<dof_id_type> representative_elem_ids;
     916             : 
     917             :   // use subdomain_ids as markers for all elements to indicate if the elements
     918             :   // have been visited. Note: here subdomain ID is unrelated with element
     919             :   // subdomain_id().
     920           8 :   std::vector<subdomain_id_type> subdomains;
     921         142 :   if (!subdomain_ids)
     922           0 :     subdomain_ids = &subdomains;
     923           4 :   subdomain_ids->clear();
     924         142 :   subdomain_ids->resize(max_elem_id() + 1, Elem::invalid_subdomain_id);
     925             : 
     926             :   // counter of disconnected subdomains
     927           4 :   subdomain_id_type subdomain_counter = 0;
     928             : 
     929             :   // a stack for visiting elements, make its capacity sufficiently large to avoid
     930             :   // memory allocation and deallocation when the vector size changes
     931           8 :   std::vector<const Elem *> list;
     932         142 :   list.reserve(n_elem());
     933             : 
     934             :   // counter of visited elements
     935           4 :   dof_id_type visited = 0;
     936         142 :   dof_id_type n_active = n_active_elem();
     937           4 :   do
     938             :   {
     939        1672 :     for (const auto & elem : active_element_ptr_range())
     940         876 :       if ((*subdomain_ids)[elem->id()] == Elem::invalid_subdomain_id)
     941             :       {
     942         284 :         list.push_back(elem);
     943         284 :         (*subdomain_ids)[elem->id()] = subdomain_counter;
     944         284 :         break;
     945         268 :       }
     946             :     // we should be able to find a seed here
     947           8 :     libmesh_assert(list.size() > 0);
     948             : 
     949         284 :     dof_id_type min_id = std::numeric_limits<dof_id_type>::max();
     950        1988 :     while (list.size() > 0)
     951             :     {
     952             :       // pop up an element
     953        1704 :       const Elem * elem = list.back(); list.pop_back(); ++visited;
     954             : 
     955        3084 :       min_id = std::min(elem->id(), min_id);
     956             : 
     957        8520 :       for (auto s : elem->side_index_range())
     958             :       {
     959        6816 :         const Elem * neighbor = elem->neighbor_ptr(s);
     960        6816 :         if (neighbor != nullptr && (*subdomain_ids)[neighbor->id()] == Elem::invalid_subdomain_id)
     961             :         {
     962             :           // neighbor must be active
     963          40 :           libmesh_assert(neighbor->active());
     964        1420 :           list.push_back(neighbor);
     965        1460 :           (*subdomain_ids)[neighbor->id()] = subdomain_counter;
     966             :         }
     967             :       }
     968             :     }
     969             : 
     970         284 :     representative_elem_ids.push_back(min_id);
     971         284 :     subdomain_counter++;
     972             :   }
     973         284 :   while (visited != n_active);
     974             : 
     975         146 :   return representative_elem_ids;
     976             : }
     977             : 
     978             : std::unordered_map<dof_id_type, std::vector<std::vector<Point>>>
     979         142 : ReplicatedMesh::get_boundary_points() const
     980             : {
     981         142 :   libmesh_error_msg_if(mesh_dimension() != 2,
     982             :                        "Error: get_boundary_points only works for 2D now");
     983             : 
     984             :   // find number of disconnected subdomains
     985             :   // subdomains will hold the IDs of disconnected subdomains for all elements.
     986           8 :   std::vector<subdomain_id_type> subdomains;
     987         146 :   std::vector<dof_id_type> elem_ids = get_disconnected_subdomains(&subdomains);
     988             : 
     989           4 :   std::unordered_map<dof_id_type, std::vector<std::vector<Point>>> boundary_points;
     990             : 
     991             :   // get all boundary sides that are to be erased later during visiting
     992             :   // use a comparison functor to avoid run-time randomness due to pointers
     993             :   struct boundary_side_compare
     994             :   {
     995        1584 :     bool operator()(const std::pair<const Elem *, unsigned int> & lhs,
     996             :                     const std::pair<const Elem *, unsigned int> & rhs) const
     997             :       {
     998       42340 :         if (lhs.first->id() < rhs.first->id())
     999         328 :           return true;
    1000       29298 :         else if (lhs.first->id() == rhs.first->id())
    1001             :         {
    1002       14668 :           if (lhs.second < rhs.second)
    1003         112 :             return true;
    1004             :         }
    1005        1144 :         return false;
    1006             :       }
    1007             :   };
    1008           8 :   std::set<std::pair<const Elem *, unsigned int>, boundary_side_compare> boundary_elements;
    1009        3592 :   for (const auto & elem : active_element_ptr_range())
    1010        8568 :     for (auto s : elem->side_index_range())
    1011        7008 :       if (elem->neighbor_ptr(s) == nullptr)
    1012        3542 :         boundary_elements.insert(std::pair<const Elem *, unsigned int>(elem, s));
    1013             : 
    1014         568 :   while (!boundary_elements.empty())
    1015             :   {
    1016             :     // get the first entry as the seed
    1017         426 :     const Elem * eseed = boundary_elements.begin()->first;
    1018         426 :     unsigned int sseed = boundary_elements.begin()->second;
    1019             : 
    1020             :     // get the subdomain ID that these boundary sides attached to
    1021         438 :     subdomain_id_type subdomain_id = subdomains[eseed->id()];
    1022             : 
    1023             :     // start visiting the mesh to find all boundary nodes with the seed
    1024          24 :     std::vector<Point> bpoints;
    1025         426 :     const Elem * elem = eseed;
    1026          12 :     unsigned int s = sseed;
    1027         438 :     std::vector<unsigned int> local_side_nodes = elem->nodes_on_side(s);
    1028             :     while (true)
    1029             :     {
    1030          96 :       std::pair<const Elem *, unsigned int> side(elem, s);
    1031          96 :       libmesh_assert(boundary_elements.count(side));
    1032          96 :       boundary_elements.erase(side);
    1033             : 
    1034             :       // push all nodes on the side except the node on the other end of the side (index 1)
    1035       11928 :       for (auto i : index_range(local_side_nodes))
    1036        8520 :         if (i != 1)
    1037        5400 :           bpoints.push_back(*static_cast<const Point *>(elem->node_ptr(local_side_nodes[i])));
    1038             : 
    1039             :       // use the last node to find next element and side
    1040        3408 :       const Node * node = elem->node_ptr(local_side_nodes[1]);
    1041          96 :       std::set<const Elem *> neighbors;
    1042        3408 :       elem->find_point_neighbors(*node, neighbors);
    1043             : 
    1044             :       // if only one neighbor is found (itself), this node is a cornor node on boundary
    1045        3408 :       if (neighbors.size() != 1)
    1046          64 :         neighbors.erase(elem);
    1047             : 
    1048             :       // find the connecting side
    1049          96 :       bool found = false;
    1050        3687 :       for (const auto & neighbor : neighbors)
    1051             :       {
    1052       10019 :         for (auto ss : neighbor->side_index_range())
    1053        9908 :           if (neighbor->neighbor_ptr(ss) == nullptr && !(elem == neighbor && s == ss))
    1054             :           {
    1055        4960 :             local_side_nodes = neighbor->nodes_on_side(ss);
    1056             :             // we expect the starting point of the side to be the same as the end of the previous side
    1057        5100 :             if (neighbor->node_ptr(local_side_nodes[0]) == node)
    1058             :             {
    1059        3408 :               elem = neighbor;
    1060          96 :               s = ss;
    1061          96 :               found = true;
    1062          96 :               break;
    1063             :             }
    1064        1596 :             else if (neighbor->node_ptr(local_side_nodes[1]) == node)
    1065             :             {
    1066           0 :               elem = neighbor;
    1067           0 :               s = ss;
    1068           0 :               found = true;
    1069             :               // flip nodes in local_side_nodes because the side is in an opposite direction
    1070           0 :               auto temp(local_side_nodes);
    1071           0 :               local_side_nodes[0] = temp[1];
    1072           0 :               local_side_nodes[1] = temp[0];
    1073           0 :               for (unsigned int i = 2; i < temp.size(); ++i)
    1074           0 :                 local_side_nodes[temp.size() + 1 - i] = temp[i];
    1075           0 :               break;
    1076             :             }
    1077             :           }
    1078         105 :         if (found)
    1079          96 :           break;
    1080             :       }
    1081             : 
    1082        3408 :       libmesh_error_msg_if(!found, "ERROR: mesh topology error on visiting boundary sides");
    1083             : 
    1084             :       // exit if we reach the starting point
    1085        3408 :       if (elem == eseed && s == sseed)
    1086          12 :         break;
    1087          84 :     }
    1088         426 :     boundary_points[elem_ids[subdomain_id]].push_back(bpoints);
    1089             :   }
    1090             : 
    1091         146 :   return boundary_points;
    1092             : }
    1093             : 
    1094             : } // namespace libMesh

Generated by: LCOV version 1.14