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

Generated by: LCOV version 1.14