LCOV - code coverage report
Current view: top level - src/mesh - replicated_mesh.C (source / functions) Hit Total Coverage
Test: libMesh/libmesh: #4343 (6ea38c) with base 8c3130 Lines: 429 451 95.1 %
Date: 2026-10-13 21:47:33 Functions: 58 58 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       69922 : ReplicatedMesh::ReplicatedMesh (const Parallel::Communicator & comm_in,
      43       69922 :                                 unsigned char d) :
      44             :   UnstructuredMesh (comm_in,d),
      45       69922 :   _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       69922 :   _next_unique_id = 0;
      51             : #endif
      52             : 
      53       81834 :   const std::string default_partitioner = "metis";
      54             :   const std::string my_partitioner =
      55             :     libMesh::command_line_value("--default-partitioner",
      56      139844 :                                 default_partitioner);
      57             :   _partitioner = Partitioner::build
      58      127932 :     (Utility::string_to_enum<PartitionerType>(my_partitioner));
      59       69922 : }
      60             : 
      61             : 
      62        2395 : bool ReplicatedMesh::subclass_locally_equals(const MeshBase & other_mesh_base) const
      63             : {
      64        1038 :   const ReplicatedMesh * rep_mesh_ptr =
      65        2395 :     dynamic_cast<const ReplicatedMesh *>(&other_mesh_base);
      66        2395 :   if (!rep_mesh_ptr)
      67           0 :     return false;
      68        1038 :   const ReplicatedMesh & other_mesh = *rep_mesh_ptr;
      69             : 
      70        5828 :   if (_n_nodes != other_mesh._n_nodes ||
      71        2395 :       _n_elem != other_mesh._n_elem ||
      72             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
      73        7185 :       _next_unique_id != other_mesh._next_unique_id ||
      74             : #endif
      75        2395 :       !this->nodes_and_elements_equal(other_mesh))
      76          78 :     return false;
      77             : 
      78        1034 :   return true;
      79             : }
      80             : 
      81             : 
      82       84555 : ReplicatedMesh::~ReplicatedMesh ()
      83             : {
      84       74174 :   this->ReplicatedMesh::clear();  // Free nodes and elements
      85       84555 : }
      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        4181 : ReplicatedMesh::ReplicatedMesh (const ReplicatedMesh & other_mesh) :
      92        4181 :   ReplicatedMesh(static_cast<const MeshBase&>(other_mesh))
      93             : {
      94             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
      95        4181 :   this->_next_unique_id = other_mesh._next_unique_id;
      96             : #endif
      97        4181 : }
      98             : 
      99             : 
     100        4252 : ReplicatedMesh::ReplicatedMesh (const MeshBase & other_mesh) :
     101             :   UnstructuredMesh (other_mesh),
     102        4252 :   _n_nodes(0), _n_elem(0) // copy_* will increment this
     103             : {
     104             :   // Just copy, skipping preparation
     105        4252 :   this->copy_nodes_and_elements(other_mesh, true, 0, 0, 0, nullptr, true);
     106             : 
     107        1424 :   this->allow_find_neighbors(other_mesh.allow_find_neighbors());
     108        1424 :   this->allow_detect_interior_parents(other_mesh.allow_detect_interior_parents());
     109        1424 :   this->allow_renumbering(other_mesh.allow_renumbering());
     110        1424 :   this->allow_remote_element_removal(other_mesh.allow_remote_element_removal());
     111        1424 :   this->skip_partitioning(other_mesh.skip_partitioning());
     112             : 
     113        4252 :   this->copy_constraint_rows(other_mesh);
     114             : 
     115         724 :   auto & this_boundary_info = this->get_boundary_info();
     116         724 :   const auto & other_boundary_info = other_mesh.get_boundary_info();
     117             : 
     118        4252 :   this_boundary_info = other_boundary_info;
     119             : 
     120         724 :   this->set_subdomain_name_map() = other_mesh.get_subdomain_name_map();
     121             : 
     122        4252 :   this->_preparation = other_mesh.preparation();
     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        4252 :   if (!other_mesh.is_serial())
     127          71 :     MeshCommunication().allgather(*this);
     128        4252 : }
     129             : 
     130         156 : ReplicatedMesh & ReplicatedMesh::operator= (ReplicatedMesh && other_mesh)
     131             : {
     132          16 :   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    16014855 : const Point & ReplicatedMesh::point (const dof_id_type i) const
     168             : {
     169    16014855 :   return this->node_ref(i);
     170             : }
     171             : 
     172             : 
     173             : 
     174             : 
     175   101596618 : const Node * ReplicatedMesh::node_ptr (const dof_id_type i) const
     176             : {
     177     5262824 :   libmesh_assert_less (i, this->max_node_id());
     178     5262824 :   libmesh_assert(_nodes[i]);
     179     5262824 :   libmesh_assert_equal_to (_nodes[i]->id(), i); // This will change soon
     180             : 
     181   106821548 :   return _nodes[i];
     182             : }
     183             : 
     184             : 
     185             : 
     186             : 
     187   108134541 : Node * ReplicatedMesh::node_ptr (const dof_id_type i)
     188             : {
     189    10155925 :   libmesh_assert_less (i, this->max_node_id());
     190    10155925 :   libmesh_assert(_nodes[i]);
     191    10155925 :   libmesh_assert_equal_to (_nodes[i]->id(), i); // This will change soon
     192             : 
     193   117649116 :   return _nodes[i];
     194             : }
     195             : 
     196             : 
     197             : 
     198             : 
     199    17381450 : const Node * ReplicatedMesh::query_node_ptr (const dof_id_type i) const
     200             : {
     201    17381450 :   if (i >= this->max_node_id())
     202           0 :     return nullptr;
     203    17131445 :   libmesh_assert (_nodes[i] == nullptr ||
     204             :                   _nodes[i]->id() == i); // This will change soon
     205             : 
     206    17466632 :   return _nodes[i];
     207             : }
     208             : 
     209             : 
     210             : 
     211             : 
     212     2779108 : Node * ReplicatedMesh::query_node_ptr (const dof_id_type i)
     213             : {
     214     2779108 :   if (i >= this->max_node_id())
     215       87059 :     return nullptr;
     216      223714 :   libmesh_assert (_nodes[i] == nullptr ||
     217             :                   _nodes[i]->id() == i); // This will change soon
     218             : 
     219     2132623 :   return _nodes[i];
     220             : }
     221             : 
     222             : 
     223             : 
     224             : 
     225     3220829 : const Elem * ReplicatedMesh::elem_ptr (const dof_id_type i) const
     226             : {
     227      515737 :   libmesh_assert_less (i, this->max_elem_id());
     228      515737 :   libmesh_assert(_elements[i]);
     229      515737 :   libmesh_assert_equal_to (_elements[i]->id(), i); // This will change soon
     230             : 
     231     3640183 :   return _elements[i];
     232             : }
     233             : 
     234             : 
     235             : 
     236             : 
     237    95646427 : Elem * ReplicatedMesh::elem_ptr (const dof_id_type i)
     238             : {
     239     5269618 :   libmesh_assert_less (i, this->max_elem_id());
     240     5269618 :   libmesh_assert(_elements[i]);
     241     5269618 :   libmesh_assert_equal_to (_elements[i]->id(), i); // This will change soon
     242             : 
     243   100163421 :   return _elements[i];
     244             : }
     245             : 
     246             : 
     247             : 
     248             : 
     249    15386750 : const Elem * ReplicatedMesh::query_elem_ptr (const dof_id_type i) const
     250             : {
     251    15386750 :   if (i >= this->max_elem_id())
     252           0 :     return nullptr;
     253    15302410 :   libmesh_assert (_elements[i] == nullptr ||
     254             :                   _elements[i]->id() == i); // This will change soon
     255             : 
     256    15416334 :   return _elements[i];
     257             : }
     258             : 
     259             : 
     260             : 
     261             : 
     262     1465357 : Elem * ReplicatedMesh::query_elem_ptr (const dof_id_type i)
     263             : {
     264     1465357 :   if (i >= this->max_elem_id())
     265       44881 :     return nullptr;
     266      188348 :   libmesh_assert (_elements[i] == nullptr ||
     267             :                   _elements[i]->id() == i); // This will change soon
     268             : 
     269      809070 :   return _elements[i];
     270             : }
     271             : 
     272             : 
     273             : 
     274             : 
     275    16048389 : Elem * ReplicatedMesh::add_elem (Elem * e)
     276             : {
     277     1162578 :   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    16048389 :   if (!e->valid_id())
     285      822060 :     e->set_id (cast_int<dof_id_type>(_elements.size()));
     286             : 
     287             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
     288    16048389 :   if (!e->valid_unique_id())
     289     5219609 :     e->set_unique_id(_next_unique_id++);
     290             :   else
     291    11687381 :    _next_unique_id = std::max(_next_unique_id, e->unique_id()+1);
     292             : #endif
     293             : 
     294     2314268 :   const dof_id_type id = e->id();
     295             : 
     296    17200079 :   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      169275 :       if (e == _elements[id])
     302           0 :         return e;
     303             : 
     304             :       // Overwriting existing elements is still probably a mistake.
     305       17132 :       libmesh_assert(!_elements[id]);
     306             :     }
     307             :   else
     308             :     {
     309    15879114 :       _elements.resize(id+1, nullptr);
     310             :     }
     311             : 
     312    16048389 :   ++_n_elem;
     313    16048389 :   _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    16048389 :   this->clear_point_locator();
     318    16048389 :   this->clear_stored_ranges();
     319             : 
     320             :   // Make sure any new element is given space for any extra integers
     321             :   // we've requested
     322    16048389 :   e->add_extra_integers(_elem_integer_names.size(),
     323    16048389 :                         _elem_integer_default_values);
     324             : 
     325             :   // And set mapping type and data on any new element
     326     2314268 :   e->set_mapping_type(this->default_mapping_type());
     327     2314268 :   e->set_mapping_data(this->default_mapping_data());
     328             : 
     329    16048389 :   return e;
     330             : }
     331             : 
     332    15234442 : 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    15234442 :   return add_elem(e.release());
     338             : }
     339             : 
     340             : 
     341             : 
     342      626045 : Elem * ReplicatedMesh::insert_elem (Elem * e)
     343             : {
     344             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
     345      626045 :   if (!e->valid_unique_id())
     346       18176 :     e->set_unique_id(_next_unique_id++);
     347             :   else
     348      607869 :    _next_unique_id = std::max(_next_unique_id, e->unique_id()+1);
     349             : #endif
     350             : 
     351      260196 :   dof_id_type eid = e->id();
     352      130098 :   libmesh_assert_less (eid, _elements.size());
     353      626045 :   Elem * oldelem = _elements[eid];
     354             : 
     355      626045 :   if (oldelem)
     356             :     {
     357      130098 :       libmesh_assert_equal_to (oldelem->id(), eid);
     358      626045 :       this->delete_elem(oldelem);
     359             :     }
     360             : 
     361      626045 :   ++_n_elem;
     362      626045 :   _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      626045 :   this->clear_point_locator();
     367      626045 :   this->clear_stored_ranges();
     368             : 
     369             :   // Make sure any new element is given space for any extra integers
     370             :   // we've requested
     371      626045 :   e->add_extra_integers(_elem_integer_names.size(),
     372      626045 :                         _elem_integer_default_values);
     373             : 
     374             :   // And set mapping type and data on any new element
     375      260196 :   e->set_mapping_type(this->default_mapping_type());
     376      260196 :   e->set_mapping_data(this->default_mapping_data());
     377             : 
     378      626045 :   return e;
     379             : }
     380             : 
     381      626045 : 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      626045 :   return insert_elem(e.release());
     387             : }
     388             : 
     389             : 
     390             : 
     391     2434621 : void ReplicatedMesh::delete_elem(Elem * e)
     392             : {
     393      242305 :   libmesh_assert(e);
     394             : 
     395             :   // Initialize an iterator to eventually point to the element we want to delete
     396      242305 :   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      242305 :   libmesh_assert_less (e->id(), _elements.size());
     402             : 
     403     2676926 :   if (_elements[e->id()] == e)
     404             :     {
     405             :       // We found it!
     406     2192316 :       pos = _elements.begin();
     407      242305 :       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      242305 :   libmesh_assert (pos != _elements.end());
     420             : 
     421             :   // Remove the element from the BoundaryInfo object
     422     2434621 :   this->get_boundary_info().remove(e);
     423             : 
     424             :   // delete the element
     425     2434621 :   --_n_elem;
     426     2434621 :   delete e;
     427             : 
     428             :   // explicitly zero the pointer
     429     2434621 :   *pos = nullptr;
     430             : 
     431             :   // Some of our caches might still be valid, but we should clear the
     432             :   // ones which definitely are not.
     433     2434621 :   this->clear_point_locator();
     434     2434621 :   this->clear_stored_ranges();
     435     2434621 : }
     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    11735707 : Node * ReplicatedMesh::add_point (const Point & p,
     468             :                                   const dof_id_type id,
     469             :                                   const processor_id_type proc_id)
     470             : {
     471     1806574 :   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    11735707 :   if (id != DofObject::invalid_id)
     477     7756065 :     if (id < _nodes.size())
     478       14819 :       n = _nodes[id];
     479             :     else
     480     6825808 :       _nodes.resize(id+1);
     481             :   else
     482     4895080 :     _nodes.push_back (static_cast<Node *>(nullptr));
     483             : 
     484             :   // if the node already exists, then assign new (x,y,z) values
     485     1819244 :   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    22555976 :       n = Node::build(p, (id == DofObject::invalid_id) ?
     492     7590534 :                       cast_int<dof_id_type>(_nodes.size()-1) : id).release();
     493    11735707 :       n->processor_id() = proc_id;
     494             : 
     495    11735707 :       n->add_extra_integers(_node_integer_names.size(),
     496    11735707 :                             _node_integer_default_values);
     497             : 
     498             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
     499    11735707 :       if (!n->valid_unique_id())
     500    11735707 :         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    11735707 :       ++_n_nodes;
     506    11735707 :       if (id == DofObject::invalid_id)
     507     4895080 :         _nodes.back() = n;
     508             :       else
     509     7756065 :         _nodes[id] = n;
     510             :     }
     511             : 
     512             :   // better not pass back a nullptr.
     513     1806574 :   libmesh_assert (n);
     514             : 
     515    11735707 :   return n;
     516             : }
     517             : 
     518             : 
     519             : 
     520      945630 : Node * ReplicatedMesh::add_node (Node * n)
     521             : {
     522       96754 :   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      945630 :   if (n->valid_id())
     527             :     {
     528       96673 :       const dof_id_type id = n->id();
     529     1041891 :       if (id < _nodes.size())
     530       15076 :         libmesh_assert(!_nodes[id]);
     531             :       else
     532      748877 :         _nodes.resize(id+1); // default nullptr
     533             : 
     534     1041891 :       _nodes[id] = n;
     535             :     }
     536             :   else
     537             :     {
     538         162 :       n->set_id (cast_int<dof_id_type>(_nodes.size()));
     539         412 :       _nodes.push_back(n);
     540             :     }
     541             : 
     542      945630 :   ++_n_nodes;
     543             : 
     544             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
     545      945630 :   if (!n->valid_unique_id())
     546         420 :     n->set_unique_id(_next_unique_id++);
     547             :   else
     548     1443695 :    _next_unique_id = std::max(_next_unique_id, n->unique_id()+1);
     549             : #endif
     550             : 
     551      945630 :   n->add_extra_integers(_node_integer_names.size(),
     552      945630 :                         _node_integer_default_values);
     553             : 
     554      945630 :   return n;
     555             : }
     556             : 
     557      945630 : 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      945630 :   return add_node(n.release());
     563             : }
     564             : 
     565      250912 : void ReplicatedMesh::delete_node(Node * n)
     566             : {
     567       63787 :   libmesh_assert(n);
     568       63787 :   libmesh_assert_less (n->id(), _nodes.size());
     569             : 
     570             :   // Initialize an iterator to eventually point to the element we want
     571             :   // to delete
     572       63787 :   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      314699 :   if (_nodes[n->id()] == n)
     578             :     {
     579      187125 :       pos = _nodes.begin();
     580       63787 :       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       63787 :   libmesh_assert (pos != _nodes.end());
     591             : 
     592             :   // Delete the node from the BoundaryInfo object
     593      250912 :   this->get_boundary_info().remove(n);
     594      127574 :   _constraint_rows.erase(n);
     595             : 
     596             :   // delete the node
     597      250912 :   --_n_nodes;
     598      438037 :   delete n;
     599             : 
     600             :   // explicitly zero the pointer
     601      250912 :   *pos = nullptr;
     602      250912 : }
     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      127185 : void ReplicatedMesh::clear ()
     629             : {
     630             :   // Call parent clear function
     631      127185 :   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      127185 :   this->ReplicatedMesh::clear_elems();
     638             : 
     639    10947439 :   for (auto & node : _nodes)
     640    19944869 :     delete node;
     641             : 
     642      127185 :   _n_nodes = 0;
     643       23980 :   _nodes.clear();
     644      127185 : }
     645             : 
     646             : 
     647             : 
     648      127897 : void ReplicatedMesh::clear_elems ()
     649             : {
     650    14569024 :   for (auto & elem : _elements)
     651    14441127 :     delete elem;
     652             : 
     653      127897 :   _n_elem = 0;
     654       24186 :   _elements.clear();
     655      127897 : }
     656             : 
     657             : 
     658             : 
     659      235474 : void ReplicatedMesh::update_parallel_id_counts()
     660             : {
     661             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
     662      235474 :   _next_unique_id = this->parallel_max_unique_id();
     663             : #endif
     664             : 
     665             :   // Implicitly get max_elem_id/max_node_id by trimming the vectors
     666      470948 :   auto trim_vec = [](auto & dof_vec) {
     667      583044 :     auto last_non_null = std::find_if(dof_vec.rbegin(), dof_vec.rend(), [](DofObject * d) { return (d != nullptr); });
     668      470948 :     dof_vec.resize(last_non_null.base()-dof_vec.begin());
     669      470948 :   };
     670             : 
     671      235474 :   trim_vec(this->_nodes);
     672      235474 :   trim_vec(this->_elements);
     673             : 
     674      235474 :   _n_constraint_rows = this->count_constraint_rows();
     675             : 
     676      235474 :   this->_preparation.has_synched_id_counts = true;
     677      235474 : }
     678             : 
     679             : 
     680             : 
     681             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
     682      252872 : unique_id_type ReplicatedMesh::parallel_max_unique_id() const
     683             : {
     684             :   // This function must be run on all processors at once
     685       44352 :   parallel_object_only();
     686             : 
     687      252872 :   unique_id_type max_local = _next_unique_id;
     688      252872 :   this->comm().max(max_local);
     689      252872 :   return max_local;
     690             : }
     691             : 
     692             : 
     693             : 
     694       21166 : void ReplicatedMesh::set_next_unique_id(unique_id_type id)
     695             : {
     696       21166 :   _next_unique_id = id;
     697       21166 : }
     698             : #endif
     699             : 
     700             : 
     701             : 
     702      188379 : void ReplicatedMesh::renumber_nodes_and_elements ()
     703             : {
     704      109974 :   LOG_SCOPE("renumber_nodes_and_elem()", "Mesh");
     705             : 
     706             :   // node and element id counters
     707       36658 :   dof_id_type next_free_elem = 0;
     708       36658 :   dof_id_type next_free_node = 0;
     709             : 
     710             :   // Will hold the set of nodes that are currently connected to elements
     711       73316 :   std::unordered_set<Node *> connected_nodes;
     712             : 
     713             :   // Loop over the elements.  Note that there may
     714             :   // be nullptrs in the _elements vector from the coarsening
     715             :   // process.  Pack the elements in to a contiguous array
     716             :   // and then trim any excess.
     717             :   {
     718       36658 :     std::vector<Elem *>::iterator in        = _elements.begin();
     719       36658 :     std::vector<Elem *>::iterator out_iter  = _elements.begin();
     720       36658 :     const std::vector<Elem *>::iterator end = _elements.end();
     721             : 
     722    40557072 :     for (; in != end; ++in)
     723    40368693 :       if (*in != nullptr)
     724             :         {
     725     3122152 :           Elem * el = *in;
     726             : 
     727    38905815 :           *out_iter = *in;
     728     3122152 :           ++out_iter;
     729             : 
     730             :           // Increment the element counter
     731    38905815 :           el->set_id (next_free_elem++);
     732             : 
     733    38905815 :           if (_skip_renumber_nodes_and_elements)
     734             :             {
     735             :               // Add this elements nodes to the connected list
     736     2145255 :               for (auto & n : el->node_ref_range())
     737     1934776 :                 connected_nodes.insert(&n);
     738             :             }
     739             :           else  // We DO want node renumbering
     740             :             {
     741             :               // Loop over this element's nodes.  Number them,
     742             :               // if they have not been numbered already.  Also,
     743             :               // position them in the _nodes vector so that they
     744             :               // are packed contiguously from the beginning.
     745   240752224 :               for (auto & n : el->node_ref_range())
     746   202056888 :                 if (n.id() == next_free_node)    // don't need to process
     747    38581516 :                   next_free_node++;                      // [(src == dst) below]
     748             : 
     749   163475372 :                 else if (n.id() > next_free_node) // need to process
     750             :                   {
     751             :                     // The source and destination indices
     752             :                     // for this node
     753     1182998 :                     const dof_id_type src_idx = n.id();
     754     9125340 :                     const dof_id_type dst_idx = next_free_node++;
     755             : 
     756             :                     // ensure we want to swap a valid nodes
     757     1182998 :                     libmesh_assert(_nodes[src_idx]);
     758             : 
     759             :                     // Swap the source and destination nodes
     760     2925133 :                     std::swap(_nodes[src_idx],
     761     2925133 :                               _nodes[dst_idx] );
     762             : 
     763             :                     // Set proper indices where that makes sense
     764     9125340 :                     if (_nodes[src_idx] != nullptr)
     765     1168240 :                       _nodes[src_idx]->set_id (src_idx);
     766     1182998 :                     _nodes[dst_idx]->set_id (dst_idx);
     767             :                   }
     768             :             }
     769             :         }
     770             : 
     771             :     // Erase any additional storage. These elements have been
     772             :     // copied into nullptr voids by the procedure above, and are
     773             :     // thus repeated and unnecessary.
     774      188379 :     _elements.erase (out_iter, end);
     775             :   }
     776             : 
     777             : 
     778      188379 :   if (_skip_renumber_nodes_and_elements)
     779             :     {
     780             :       // Loop over the nodes.  Note that there may
     781             :       // be nullptrs in the _nodes vector from the coarsening
     782             :       // process.  Pack the nodes in to a contiguous array
     783             :       // and then trim any excess.
     784             : 
     785          60 :       std::vector<Node *>::iterator in        = _nodes.begin();
     786          60 :       std::vector<Node *>::iterator out_iter  = _nodes.begin();
     787          60 :       const std::vector<Node *>::iterator end = _nodes.end();
     788             : 
     789      925936 :       for (; in != end; ++in)
     790      925541 :         if (*in != nullptr)
     791             :           {
     792             :             // This is a reference so that if we change the pointer it will change in the vector
     793      209684 :             Node * & nd = *in;
     794             : 
     795             :             // If this node is still connected to an elem, put it in the list
     796      419368 :             if (connected_nodes.count(nd))
     797             :               {
     798      673877 :                 *out_iter = nd;
     799      137780 :                 ++out_iter;
     800             : 
     801             :                 // Increment the node counter
     802      673877 :                 nd->set_id (next_free_node++);
     803             :               }
     804             :             else // This node is orphaned, delete it!
     805             :               {
     806      251664 :                 this->get_boundary_info().remove (nd);
     807      143808 :                 _constraint_rows.erase(nd);
     808             : 
     809             :                 // delete the node
     810      251664 :                 --_n_nodes;
     811      431424 :                 delete nd;
     812      251664 :                 nd = nullptr;
     813             :               }
     814             :           }
     815             : 
     816             :       // Erase any additional storage.  Whatever was
     817         395 :       _nodes.erase (out_iter, end);
     818             :     }
     819             :   else // We really DO want node renumbering
     820             :     {
     821             :       // Any nodes in the vector >= _nodes[next_free_node]
     822             :       // are not connected to any elements and may be deleted
     823             :       // if desired.
     824             : 
     825             :       // Now, delete the unused nodes
     826             :       {
     827      151386 :         std::vector<Node *>::iterator nd        = _nodes.begin();
     828       36598 :         const std::vector<Node *>::iterator end = _nodes.end();
     829             : 
     830       36598 :         std::advance (nd, next_free_node);
     831             : 
     832     1724476 :         for (auto & node : as_range(nd, end))
     833             :           {
     834             :             // Mesh modification code might have already deleted some
     835             :             // nodes
     836     1536492 :             if (node == nullptr)
     837      104431 :               continue;
     838             : 
     839             :             // remove any boundary information associated with
     840             :             // this node
     841     1396559 :             this->get_boundary_info().remove (node);
     842      220100 :             _constraint_rows.erase(node);
     843             : 
     844             :             // delete the node
     845     1396559 :             --_n_nodes;
     846     2683068 :             delete node;
     847     1396559 :             node = nullptr;
     848             :           }
     849             : 
     850      187984 :         _nodes.erase (nd, end);
     851             :       }
     852             :     }
     853             : 
     854      188379 :   this->_preparation.has_removed_orphaned_nodes = true;
     855             : 
     856       36658 :   libmesh_assert_equal_to (next_free_elem, _elements.size());
     857       36658 :   libmesh_assert_equal_to (next_free_node, _nodes.size());
     858             : 
     859      188379 :   this->update_parallel_id_counts();
     860      188379 : }
     861             : 
     862             : 
     863             : 
     864        2220 : void ReplicatedMesh::fix_broken_node_and_element_numbering ()
     865             : {
     866             :   // Nodes first
     867     3180410 :   for (auto n : index_range(_nodes))
     868     3178190 :     if (this->_nodes[n] != nullptr)
     869     3178190 :       this->_nodes[n]->set_id() = cast_int<dof_id_type>(n);
     870             : 
     871             :   // Elements next
     872     3664758 :   for (auto e : index_range(_elements))
     873     3662538 :     if (this->_elements[e] != nullptr)
     874     3662538 :       this->_elements[e]->set_id() = cast_int<dof_id_type>(e);
     875        2220 : }
     876             : 
     877             : 
     878      113514 : dof_id_type ReplicatedMesh::n_active_elem () const
     879             : {
     880      207898 :   return static_cast<dof_id_type>(std::distance (this->active_elements_begin(),
     881      321412 :                                                  this->active_elements_end()));
     882             : }
     883             : 
     884             : std::vector<dof_id_type>
     885         142 : ReplicatedMesh::get_disconnected_subdomains(std::vector<subdomain_id_type> * subdomain_ids) const
     886             : {
     887             :   // find number of disconnected subdomains
     888           4 :   std::vector<dof_id_type> representative_elem_ids;
     889             : 
     890             :   // use subdomain_ids as markers for all elements to indicate if the elements
     891             :   // have been visited. Note: here subdomain ID is unrelated with element
     892             :   // subdomain_id().
     893           8 :   std::vector<subdomain_id_type> subdomains;
     894         142 :   if (!subdomain_ids)
     895           0 :     subdomain_ids = &subdomains;
     896           4 :   subdomain_ids->clear();
     897         142 :   subdomain_ids->resize(max_elem_id() + 1, Elem::invalid_subdomain_id);
     898             : 
     899             :   // counter of disconnected subdomains
     900           4 :   subdomain_id_type subdomain_counter = 0;
     901             : 
     902             :   // a stack for visiting elements, make its capacity sufficiently large to avoid
     903             :   // memory allocation and deallocation when the vector size changes
     904           8 :   std::vector<const Elem *> list;
     905         142 :   list.reserve(n_elem());
     906             : 
     907             :   // counter of visited elements
     908           4 :   dof_id_type visited = 0;
     909         142 :   dof_id_type n_active = n_active_elem();
     910           4 :   do
     911             :   {
     912        1672 :     for (const auto & elem : active_element_ptr_range())
     913         876 :       if ((*subdomain_ids)[elem->id()] == Elem::invalid_subdomain_id)
     914             :       {
     915         284 :         list.push_back(elem);
     916         284 :         (*subdomain_ids)[elem->id()] = subdomain_counter;
     917         284 :         break;
     918         268 :       }
     919             :     // we should be able to find a seed here
     920           8 :     libmesh_assert(list.size() > 0);
     921             : 
     922         284 :     dof_id_type min_id = std::numeric_limits<dof_id_type>::max();
     923        1988 :     while (list.size() > 0)
     924             :     {
     925             :       // pop up an element
     926        1704 :       const Elem * elem = list.back(); list.pop_back(); ++visited;
     927             : 
     928        3084 :       min_id = std::min(elem->id(), min_id);
     929             : 
     930        8520 :       for (auto s : elem->side_index_range())
     931             :       {
     932        6816 :         const Elem * neighbor = elem->neighbor_ptr(s);
     933        6816 :         if (neighbor != nullptr && (*subdomain_ids)[neighbor->id()] == Elem::invalid_subdomain_id)
     934             :         {
     935             :           // neighbor must be active
     936          40 :           libmesh_assert(neighbor->active());
     937        1420 :           list.push_back(neighbor);
     938        1460 :           (*subdomain_ids)[neighbor->id()] = subdomain_counter;
     939             :         }
     940             :       }
     941             :     }
     942             : 
     943         284 :     representative_elem_ids.push_back(min_id);
     944         284 :     subdomain_counter++;
     945             :   }
     946         284 :   while (visited != n_active);
     947             : 
     948         146 :   return representative_elem_ids;
     949             : }
     950             : 
     951             : std::unordered_map<dof_id_type, std::vector<std::vector<Point>>>
     952         142 : ReplicatedMesh::get_boundary_points() const
     953             : {
     954         142 :   libmesh_error_msg_if(mesh_dimension() != 2,
     955             :                        "Error: get_boundary_points only works for 2D now");
     956             : 
     957             :   // find number of disconnected subdomains
     958             :   // subdomains will hold the IDs of disconnected subdomains for all elements.
     959           8 :   std::vector<subdomain_id_type> subdomains;
     960         146 :   std::vector<dof_id_type> elem_ids = get_disconnected_subdomains(&subdomains);
     961             : 
     962           4 :   std::unordered_map<dof_id_type, std::vector<std::vector<Point>>> boundary_points;
     963             : 
     964             :   // get all boundary sides that are to be erased later during visiting
     965             :   // use a comparison functor to avoid run-time randomness due to pointers
     966             :   struct boundary_side_compare
     967             :   {
     968        1584 :     bool operator()(const std::pair<const Elem *, unsigned int> & lhs,
     969             :                     const std::pair<const Elem *, unsigned int> & rhs) const
     970             :       {
     971       42340 :         if (lhs.first->id() < rhs.first->id())
     972         328 :           return true;
     973       29298 :         else if (lhs.first->id() == rhs.first->id())
     974             :         {
     975       14668 :           if (lhs.second < rhs.second)
     976         112 :             return true;
     977             :         }
     978        1144 :         return false;
     979             :       }
     980             :   };
     981           8 :   std::set<std::pair<const Elem *, unsigned int>, boundary_side_compare> boundary_elements;
     982        3592 :   for (const auto & elem : active_element_ptr_range())
     983        8568 :     for (auto s : elem->side_index_range())
     984        7008 :       if (elem->neighbor_ptr(s) == nullptr)
     985        3542 :         boundary_elements.insert(std::pair<const Elem *, unsigned int>(elem, s));
     986             : 
     987         568 :   while (!boundary_elements.empty())
     988             :   {
     989             :     // get the first entry as the seed
     990         426 :     const Elem * eseed = boundary_elements.begin()->first;
     991         426 :     unsigned int sseed = boundary_elements.begin()->second;
     992             : 
     993             :     // get the subdomain ID that these boundary sides attached to
     994         438 :     subdomain_id_type subdomain_id = subdomains[eseed->id()];
     995             : 
     996             :     // start visiting the mesh to find all boundary nodes with the seed
     997          24 :     std::vector<Point> bpoints;
     998         426 :     const Elem * elem = eseed;
     999          12 :     unsigned int s = sseed;
    1000         438 :     std::vector<unsigned int> local_side_nodes = elem->nodes_on_side(s);
    1001             :     while (true)
    1002             :     {
    1003          96 :       std::pair<const Elem *, unsigned int> side(elem, s);
    1004          96 :       libmesh_assert(boundary_elements.count(side));
    1005          96 :       boundary_elements.erase(side);
    1006             : 
    1007             :       // push all nodes on the side except the node on the other end of the side (index 1)
    1008       11928 :       for (auto i : index_range(local_side_nodes))
    1009        8520 :         if (i != 1)
    1010        5400 :           bpoints.push_back(*static_cast<const Point *>(elem->node_ptr(local_side_nodes[i])));
    1011             : 
    1012             :       // use the last node to find next element and side
    1013        3408 :       const Node * node = elem->node_ptr(local_side_nodes[1]);
    1014          96 :       std::set<const Elem *> neighbors;
    1015        3408 :       elem->find_point_neighbors(*node, neighbors);
    1016             : 
    1017             :       // if only one neighbor is found (itself), this node is a cornor node on boundary
    1018        3408 :       if (neighbors.size() != 1)
    1019          64 :         neighbors.erase(elem);
    1020             : 
    1021             :       // find the connecting side
    1022          96 :       bool found = false;
    1023        3686 :       for (const auto & neighbor : neighbors)
    1024             :       {
    1025       10011 :         for (auto ss : neighbor->side_index_range())
    1026        9892 :           if (neighbor->neighbor_ptr(ss) == nullptr && !(elem == neighbor && s == ss))
    1027             :           {
    1028        4958 :             local_side_nodes = neighbor->nodes_on_side(ss);
    1029             :             // we expect the starting point of the side to be the same as the end of the previous side
    1030        5092 :             if (neighbor->node_ptr(local_side_nodes[0]) == node)
    1031             :             {
    1032        3408 :               elem = neighbor;
    1033          96 :               s = ss;
    1034          96 :               found = true;
    1035          96 :               break;
    1036             :             }
    1037        1588 :             else if (neighbor->node_ptr(local_side_nodes[1]) == node)
    1038             :             {
    1039           0 :               elem = neighbor;
    1040           0 :               s = ss;
    1041           0 :               found = true;
    1042             :               // flip nodes in local_side_nodes because the side is in an opposite direction
    1043           0 :               auto temp(local_side_nodes);
    1044           0 :               local_side_nodes[0] = temp[1];
    1045           0 :               local_side_nodes[1] = temp[0];
    1046           0 :               for (unsigned int i = 2; i < temp.size(); ++i)
    1047           0 :                 local_side_nodes[temp.size() + 1 - i] = temp[i];
    1048           0 :               break;
    1049             :             }
    1050             :           }
    1051         108 :         if (found)
    1052          96 :           break;
    1053             :       }
    1054             : 
    1055        3408 :       libmesh_error_msg_if(!found, "ERROR: mesh topology error on visiting boundary sides");
    1056             : 
    1057             :       // exit if we reach the starting point
    1058        3408 :       if (elem == eseed && s == sseed)
    1059          12 :         break;
    1060          84 :     }
    1061         426 :     boundary_points[elem_ids[subdomain_id]].push_back(bpoints);
    1062             :   }
    1063             : 
    1064         146 :   return boundary_points;
    1065             : }
    1066             : 
    1067             : } // namespace libMesh

Generated by: LCOV version 1.14