libMesh
distributed_mesh.C
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2026 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3 
4 // This library is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU Lesser General Public
6 // License as published by the Free Software Foundation; either
7 // version 2.1 of the License, or (at your option) any later version.
8 
9 // This library is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // Lesser General Public License for more details.
13 
14 // You should have received a copy of the GNU Lesser General Public
15 // License along with this library; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 
18 
19 
20 // Local includes
21 #include "libmesh/distributed_mesh.h"
22 
23 // libMesh includes
24 #include "libmesh/boundary_info.h"
25 #include "libmesh/elem.h"
26 #include "libmesh/libmesh_logging.h"
27 #include "libmesh/mesh_communication.h"
28 #include "libmesh/mesh_tools.h"
29 #include "libmesh/partitioner.h"
30 #include "libmesh/string_to_enum.h"
31 
32 // TIMPI includes
34 #include "timpi/parallel_sync.h"
35 
36 
37 namespace libMesh
38 {
39 
40 // ------------------------------------------------------------
41 // DistributedMesh class member functions
43  unsigned char d) :
44  UnstructuredMesh (comm_in,d), _is_serial(true),
45  _is_serial_on_proc_0(true),
46  _deleted_coarse_elements(false),
47  _n_nodes(0), _n_elem(0), _max_node_id(0), _max_elem_id(0),
48  _next_free_local_node_id(this->processor_id()),
49  _next_free_local_elem_id(this->processor_id()),
50  _next_free_unpartitioned_node_id(this->n_processors()),
51  _next_free_unpartitioned_elem_id(this->n_processors())
52 #ifdef LIBMESH_ENABLE_UNIQUE_ID
53  , _next_unpartitioned_unique_id(this->n_processors())
54 #endif
55 {
56 #ifdef LIBMESH_ENABLE_UNIQUE_ID
57  _next_unique_id = this->processor_id();
58 #endif
59 
60  const std::string default_partitioner = "parmetis";
61  const std::string my_partitioner =
62  libMesh::command_line_value("--default-partitioner",
63  default_partitioner);
65  (Utility::string_to_enum<PartitionerType>(my_partitioner));
66 }
67 
69 {
70  LOG_SCOPE("operator=(&&)", "DistributedMesh");
71 
72  // Move assign as an UnstructuredMesh.
73  this->UnstructuredMesh::operator=(std::move(other_mesh));
74 
75  // Nodes and elements belong to DistributedMesh and have to be
76  // moved before we can move arbitrary GhostingFunctor, Partitioner,
77  // etc. subclasses.
78  this->move_nodes_and_elements(std::move(other_mesh));
79 
80  // But move_nodes_and_elems misses (or guesses about) some of our
81  // subclass values, and we want more precision than a guess.
82  _deleted_coarse_elements = other_mesh._deleted_coarse_elements;
83  _extra_ghost_elems = std::move(other_mesh._extra_ghost_elems);
84 
85  // Handle remaining MeshBase moves.
86  this->post_dofobject_moves(std::move(other_mesh));
87 
88  return *this;
89 }
90 
92 {
93  *this = std::move(cast_ref<DistributedMesh&>(other_mesh));
94 
95  return *this;
96 }
97 
98 bool DistributedMesh::subclass_locally_equals(const MeshBase & other_mesh_base) const
99 {
100  const DistributedMesh * dist_mesh_ptr =
101  dynamic_cast<const DistributedMesh *>(&other_mesh_base);
102  if (!dist_mesh_ptr)
103  return false;
104  const DistributedMesh & other_mesh = *dist_mesh_ptr;
105 
106  if (_is_serial != other_mesh._is_serial ||
109  _n_nodes != other_mesh._n_nodes ||
110  _n_elem != other_mesh._n_elem ||
111  _max_node_id != other_mesh._max_node_id ||
112  _max_elem_id != other_mesh._max_elem_id ||
113  // We expect these things to change in a prepare_for_use();
114  // they're conceptually "mutable"...
115 /*
116  _next_free_local_node_id != other_mesh._next_free_local_node_id ||
117  _next_free_local_elem_id != other_mesh._next_free_local_elem_id ||
118  _next_free_unpartitioned_node_id != other_mesh._next_free_unpartitioned_node_id ||
119  _next_free_unpartitioned_elem_id != other_mesh._next_free_unpartitioned_elem_id ||
120 #ifdef LIBMESH_ENABLE_UNIQUE_ID
121  _next_unpartitioned_unique_id != other_mesh._next_unpartitioned_unique_id ||
122 #endif
123 */
124  !this->nodes_and_elements_equal(other_mesh))
125  return false;
126 
127  if (_extra_ghost_elems.size() !=
128  other_mesh._extra_ghost_elems.size())
129  return false;
130  for (auto & elem : _extra_ghost_elems)
131  {
132  libmesh_assert(this->query_elem_ptr(elem->id()) == elem);
133  const Elem * other_elem = other_mesh.query_elem_ptr(elem->id());
134  if (!other_elem ||
135  !other_mesh._extra_ghost_elems.count(const_cast<Elem *>(other_elem)))
136  return false;
137  }
138 
139  return true;
140 }
141 
143 {
144  this->DistributedMesh::clear(); // Free nodes and elements
145 }
146 
147 
148 // This might be specialized later, but right now it's just here to
149 // make sure the compiler doesn't give us a default (non-deep) copy
150 // constructor instead.
152  DistributedMesh(static_cast<const MeshBase &>(other_mesh))
153 {
154  _is_serial = other_mesh._is_serial;
157 
158  _n_nodes = other_mesh.n_nodes();
159  _n_elem = other_mesh.n_elem();
160  _max_node_id = other_mesh.max_node_id();
161  _max_elem_id = other_mesh.max_elem_id();
163  other_mesh._next_free_local_node_id;
165  other_mesh._next_free_local_elem_id;
170 #ifdef LIBMESH_ENABLE_UNIQUE_ID
172  other_mesh._next_unique_id;
175 #endif
176 
177  // Need to copy extra_ghost_elems
178  for (auto & elem : other_mesh._extra_ghost_elems)
179  _extra_ghost_elems.insert(this->elem_ptr(elem->id()));
180 }
181 
182 
183 
185  UnstructuredMesh (other_mesh), _is_serial(other_mesh.is_serial()),
186  _is_serial_on_proc_0(other_mesh.is_serial()),
187  _deleted_coarse_elements(true), // better safe than sorry...
188  _n_nodes(0), _n_elem(0), _max_node_id(0), _max_elem_id(0),
189  _next_free_local_node_id(this->processor_id()),
190  _next_free_local_elem_id(this->processor_id()),
191  _next_free_unpartitioned_node_id(this->n_processors()),
192  _next_free_unpartitioned_elem_id(this->n_processors())
193 {
194  // Just copy, skipping preparation
195  this->copy_nodes_and_elements(other_mesh, true, 0, 0, 0, nullptr, true);
196 
197  this->allow_find_neighbors(other_mesh.allow_find_neighbors());
199  this->allow_renumbering(other_mesh.allow_renumbering());
201  this->skip_partitioning(other_mesh.skip_partitioning());
202 
203  this->copy_constraint_rows(other_mesh);
204 
205  this->_preparation = other_mesh.preparation();
206 
207  auto & this_boundary_info = this->get_boundary_info();
208  const auto & other_boundary_info = other_mesh.get_boundary_info();
209 
210  this_boundary_info = other_boundary_info;
211 
212  this->set_subdomain_name_map() = other_mesh.get_subdomain_name_map();
213 
214 #ifdef LIBMESH_ENABLE_UNIQUE_ID
215  _next_unique_id = other_mesh.parallel_max_unique_id() +
216  this->processor_id();
218  (this->n_processors() - this->processor_id());
219 #endif
221 }
222 
224 {
225  DistributedMesh & other_mesh = cast_ref<DistributedMesh&>(other_meshbase);
226 
227  this->_nodes = std::move(other_mesh._nodes);
228  this->_n_nodes = other_mesh.n_nodes();
229 
230  this->_elements = std::move(other_mesh._elements);
231  this->_n_elem = other_mesh.n_elem();
232 
233  _is_serial = other_mesh.is_serial();
235  _deleted_coarse_elements = true; // Better safe than sorry
236 
237  _max_node_id = other_mesh.max_node_id();
238  _max_elem_id = other_mesh.max_elem_id();
239 
244 
245  #ifdef LIBMESH_ENABLE_UNIQUE_ID
247  #endif
248 }
249 
250 // We use cached values for these so they can be called
251 // from one processor without bothering the rest, but
252 // we may need to update those caches before doing a full
253 // renumbering
255 {
256  // This function must be run on all processors at once
257  parallel_object_only();
258 
259  _n_elem = this->parallel_n_elem();
260  _n_nodes = this->parallel_n_nodes();
263 
266  ((_max_elem_id-1) / (this->n_processors() + 1) + 1) *
267  (this->n_processors() + 1) + this->n_processors();
270  ((_max_elem_id + this->n_processors() - 1) / (this->n_processors() + 1) + 1) *
271  (this->n_processors() + 1) + this->processor_id();
272 
275  ((_max_node_id-1) / (this->n_processors() + 1) + 1) *
276  (this->n_processors() + 1) + this->n_processors();
279  ((_max_node_id + this->n_processors() - 1) / (this->n_processors() + 1) + 1) *
280  (this->n_processors() + 1) + this->processor_id();
281 
282 #ifdef LIBMESH_ENABLE_UNIQUE_ID
285  ((_next_unique_id-1) / (this->n_processors() + 1) + 1) *
286  (this->n_processors() + 1) + this->n_processors();
288  ((_next_unique_id + this->n_processors() - 1) / (this->n_processors() + 1) + 1) *
289  (this->n_processors() + 1) + this->processor_id();
290 #endif
291 
292  this->_preparation.has_synched_id_counts = true;
293 }
294 
295 
296 // Or in debug mode we may want to test the uncached values without
297 // changing the cache
299 {
300  // This function must be run on all processors at once
301  parallel_object_only();
302 
303  dof_id_type n_local = this->n_local_elem();
304  this->comm().sum(n_local);
305  n_local += this->n_unpartitioned_elem();
306  return n_local;
307 }
308 
309 
310 
312 {
313  // This function must be run on all processors at once
314  parallel_object_only();
315 
316  dof_id_type max_local = 0;
317 
319  rit = _elements.rbegin();
320 
322  rend = _elements.rend();
323 
324  // Look for the maximum element id. Search backwards through
325  // elements so we can break out early. Beware of nullptr entries that
326  // haven't yet been cleared from _elements.
327  for (; rit != rend; ++rit)
328  {
329  const DofObject *d = *rit;
330  if (d)
331  {
332  libmesh_assert(_elements[d->id()] == d);
333  max_local = d->id() + 1;
334  break;
335  }
336  }
337 
338  this->comm().max(max_local);
339  return max_local;
340 }
341 
342 
343 
344 #ifdef LIBMESH_ENABLE_UNIQUE_ID
346 {
347  // This function must be run on all processors at once
348  parallel_object_only();
349 
350  unique_id_type max_local = std::max(_next_unique_id,
352  this->comm().max(max_local);
353  return max_local;
354 }
355 
356 
357 
359 {
360  _next_unique_id = id;
362  ((_next_unique_id-1) / (this->n_processors() + 1) + 1) *
363  (this->n_processors() + 1) + this->n_processors();
365  ((_next_unique_id + this->n_processors() - 1) / (this->n_processors() + 1) + 1) *
366  (this->n_processors() + 1) + this->processor_id();
367 }
368 #endif
369 
370 
371 
373 {
374  // This function must be run on all processors at once
375  parallel_object_only();
376 
377  dof_id_type n_local = this->n_local_nodes();
378  this->comm().sum(n_local);
379  n_local += this->n_unpartitioned_nodes();
380  return n_local;
381 }
382 
383 
384 
386 {
387  // This function must be run on all processors at once
388  parallel_object_only();
389 
390  dof_id_type max_local = 0;
391 
393  rit = _nodes.rbegin();
394 
396  rend = _nodes.rend();
397 
398  // Look for the maximum node id. Search backwards through
399  // nodes so we can break out early. Beware of nullptr entries that
400  // haven't yet been cleared from _nodes
401  for (; rit != rend; ++rit)
402  {
403  const DofObject *d = *rit;
404  if (d)
405  {
406  libmesh_assert(_nodes[d->id()] == d);
407  max_local = d->id() + 1;
408  break;
409  }
410  }
411 
412  this->comm().max(max_local);
413  return max_local;
414 }
415 
416 
417 
418 const Point & DistributedMesh::point (const dof_id_type i) const
419 {
420  return this->node_ref(i);
421 }
422 
423 
424 
426 {
428  libmesh_assert_equal_to (_nodes[i]->id(), i);
429 
430  return _nodes[i];
431 }
432 
433 
434 
435 
437 {
439  libmesh_assert_equal_to (_nodes[i]->id(), i);
440 
441  return _nodes[i];
442 }
443 
444 
445 
446 
448 {
449  if (const auto it = _nodes.find(i);
450  it != _nodes.end())
451  {
452  const Node * n = *it;
453  libmesh_assert (!n || n->id() == i);
454  return n;
455  }
456 
457  return nullptr;
458 }
459 
460 
461 
462 
464 {
465  if (auto it = _nodes.find(i);
466  it != _nodes.end())
467  {
468  Node * n = *it;
469  libmesh_assert (!n || n->id() == i);
470  return n;
471  }
472 
473  return nullptr;
474 }
475 
476 
477 
478 
480 {
482  libmesh_assert_equal_to (_elements[i]->id(), i);
483 
484  return _elements[i];
485 }
486 
487 
488 
489 
491 {
493  libmesh_assert_equal_to (_elements[i]->id(), i);
494 
495  return _elements[i];
496 }
497 
498 
499 
500 
502 {
503  if (const auto it = _elements.find(i);
504  it != _elements.end())
505  {
506  const Elem * e = *it;
507  libmesh_assert (!e || e->id() == i);
508  return e;
509  }
510 
511  return nullptr;
512 }
513 
514 
515 
516 
518 {
519  if (auto it = _elements.find(i);
520  it != _elements.end())
521  {
522  Elem * e = *it;
523  libmesh_assert (!e || e->id() == i);
524  return e;
525  }
526 
527  return nullptr;
528 }
529 
530 
531 
532 
534 {
535  // Don't try to add nullptrs!
536  libmesh_assert(e);
537 
538  // Trying to add an existing element is a no-op
539  if (e->valid_id() && _elements[e->id()] == e)
540  return e;
541 
542  const processor_id_type elem_procid = e->processor_id();
543 
544  if (!e->valid_id())
545  {
546  // We should only be creating new ids past the end of the range
547  // of existing ids
548  libmesh_assert_greater_equal(_next_free_unpartitioned_elem_id,
549  _max_elem_id);
550  libmesh_assert_greater_equal(_next_free_local_elem_id, _max_elem_id);
551 
552  // Use the unpartitioned ids for unpartitioned elems, and
553  // temporarily for ghost elems
555  if (elem_procid == this->processor_id())
556  next_id = &_next_free_local_elem_id;
557  e->set_id (*next_id);
558  }
559 
560  {
561  // Advance next_ids up high enough that each is pointing to an
562  // unused id and any subsequent increments will still point us
563  // to unused ids
564  _max_elem_id = std::max(_max_elem_id,
565  static_cast<dof_id_type>(e->id()+1));
566 
569  ((_max_elem_id-1) / (this->n_processors() + 1) + 1) *
570  (this->n_processors() + 1) + this->n_processors();
573  ((_max_elem_id + this->n_processors() - 1) / (this->n_processors() + 1) + 1) *
574  (this->n_processors() + 1) + this->processor_id();
575 
576 #ifndef NDEBUG
577  // We need a const dofobject_container so we don't inadvertently create
578  // nullptr entries when testing for non-nullptr ones
579  const dofobject_container<Elem> & const_elements = _elements;
580 #endif
582  libmesh_assert(!const_elements[_next_free_local_elem_id]);
583  }
584 
585  // Don't try to overwrite existing elems
586  libmesh_assert (!_elements[e->id()]);
587 
588  _elements[e->id()] = e;
589 
590  // We actually added a new element. Some of our caches might still
591  // be valid, but we should clear the ones which definitely are not.
592  this->clear_point_locator();
593  this->clear_stored_ranges();
594 
595  // Try to make the cached elem data more accurate
596  if (elem_procid == this->processor_id() ||
597  elem_procid == DofObject::invalid_processor_id)
598  _n_elem++;
599 
600 #ifdef LIBMESH_ENABLE_UNIQUE_ID
601  if (!e->valid_unique_id())
602  {
603  if (processor_id() == e->processor_id())
604  {
606  _next_unique_id += this->n_processors() + 1;
607  }
608  else
609  {
612  }
613  }
614  else
615  {
616  _next_unique_id = std::max(_next_unique_id, e->unique_id()+1);
618  ((_next_unique_id + this->n_processors() - 1) / (this->n_processors() + 1) + 1) *
619  (this->n_processors() + 1) + this->processor_id();
620  }
621 #endif
622 
623  // Unpartitioned elems should be added on every processor
624  // And shouldn't be added in the same batch as ghost elems
625  // But we might be just adding on processor 0 to
626  // broadcast later
627  // #ifdef DEBUG
628  // if (elem_procid == DofObject::invalid_processor_id)
629  // {
630  // dof_id_type elem_id = e->id();
631  // this->comm().max(elem_id);
632  // libmesh_assert_equal_to (elem_id, e->id());
633  // }
634  // #endif
635 
636  // Make sure any new element is given space for any extra integers
637  // we've requested
640 
641  // And set mapping type and data on any new element
644 
645  return e;
646 }
647 
648 
649 
650 Elem * DistributedMesh::add_elem (std::unique_ptr<Elem> e)
651 {
652  // The mesh now takes ownership of the Elem. Eventually the guts of
653  // add_elem() will get moved to a private helper function, and
654  // calling add_elem() directly will be deprecated.
655  return add_elem(e.release());
656 }
657 
658 
659 
661 {
662  if (_elements[e->id()])
663  this->delete_elem(_elements[e->id()]);
664 
665 #ifdef LIBMESH_ENABLE_UNIQUE_ID
666  if (!e->valid_unique_id())
667  {
668  if (processor_id() == e->processor_id())
669  {
671  _next_unique_id += this->n_processors() + 1;
672  }
673  else
674  {
677  }
678  }
679  else
680  {
681  _next_unique_id = std::max(_next_unique_id, e->unique_id()+1);
683  ((_next_unique_id + this->n_processors() - 1) / (this->n_processors() + 1) + 1) *
684  (this->n_processors() + 1) + this->processor_id();
685  }
686 #endif
687 
688  // Try to make the cached elem data more accurate
689  processor_id_type elem_procid = e->processor_id();
690  if (elem_procid == this->processor_id() ||
691  elem_procid == DofObject::invalid_processor_id)
692  _n_elem++;
693 
694  _elements[e->id()] = e;
695 
696  // We actually added a new element. Some of our caches might still
697  // be valid, but we should clear the ones which definitely are not.
698  this->clear_point_locator();
699  this->clear_stored_ranges();
700 
701  // Make sure any new element is given space for any extra integers
702  // we've requested
705 
706  // And set mapping type and data on any new element
709 
710  return e;
711 }
712 
713 Elem * DistributedMesh::insert_elem (std::unique_ptr<Elem> e)
714 {
715  // The mesh now takes ownership of the Elem. Eventually the guts of
716  // insert_elem(Elem*) will get moved to a private helper function, and
717  // calling insert_elem(Elem*) directly will be deprecated.
718  return insert_elem(e.release());
719 }
720 
721 
723 {
724  libmesh_assert (e);
725 
726  // Try to make the cached elem data more accurate
727  _n_elem--;
728 
729  // Was this a coarse element, not just a coarsening where we still
730  // have some ancestor structure? Was it a *local* element, that we
731  // might have been depending on as an owner of local nodes? We'll
732  // have to be more careful with our nodes in contract() later; no
733  // telling if we just locally orphaned a node that should be
734  // globally retained.
735  if (e->processor_id() == this->processor_id() &&
736  !e->parent())
738 
739  // Delete the element from the BoundaryInfo object
740  this->get_boundary_info().remove(e);
741 
742  // But not yet from the container; we might invalidate
743  // an iterator that way!
744 
745  //_elements.erase(e->id());
746 
747  // Instead, we set it to nullptr for now
748 
749  _elements[e->id()] = nullptr;
750 
751  // delete the element
752  delete e;
753 
754  // Some of our caches might still be valid, but we should clear the
755  // ones which definitely are not.
756  this->clear_point_locator();
757  this->clear_stored_ranges();
758 }
759 
760 
761 
763  const dof_id_type new_id)
764 {
765  // This could be a no-op
766  if (old_id == new_id)
767  return;
768 
769  Elem * el = _elements[old_id];
770  libmesh_assert (el);
771  libmesh_assert_equal_to (el->id(), old_id);
772 
773  el->set_id(new_id);
774  libmesh_assert (!_elements[new_id]);
775  _elements[new_id] = el;
776  _elements.erase(old_id);
777 
778  // Should we delete any caches here? Our point locator indexes by
779  // element pointer and should be fine with an id change. Our stored
780  // ranges are no longer sorted, which is *probably* fine, but let's
781  // just be safe.
782  this->clear_stored_ranges();
783 }
784 
785 
786 
788  const dof_id_type id,
789  const processor_id_type proc_id)
790 {
791  Node * old_n = this->query_node_ptr(id);
792 
793  if (old_n)
794  {
795  *old_n = p;
796  old_n->processor_id() = proc_id;
797 
798  return old_n;
799  }
800 
801  Node * n = Node::build(p, id).release();
802  n->processor_id() = proc_id;
803 
804  return DistributedMesh::add_node(n);
805 }
806 
807 
809 {
810  // This had better be a node in our mesh
811  libmesh_assert(_nodes[n.id()] == &n);
812 
813  _nodes[n.id()] = nullptr;
814  _n_nodes--;
815 
817  n.processor_id() = this->processor_id();
818 
819  this->add_node(&n);
820 }
821 
822 
824 {
825  // Don't try to add nullptrs!
826  libmesh_assert(n);
827 
828  // Trying to add an existing node is a no-op
829  if (n->valid_id() && _nodes[n->id()] == n)
830  return n;
831 
832  const processor_id_type node_procid = n->processor_id();
833 
834  if (!n->valid_id())
835  {
836  // We should only be creating new ids past the end of the range
837  // of existing ids
838  libmesh_assert_greater_equal(_next_free_unpartitioned_node_id,
839  _max_node_id);
840  libmesh_assert_greater_equal(_next_free_local_node_id, _max_node_id);
841 
842  // Use the unpartitioned ids for unpartitioned nodes,
843  // and temporarily for ghost nodes
845  if (node_procid == this->processor_id())
846  next_id = &_next_free_local_node_id;
847  n->set_id (*next_id);
848  }
849 
850  {
851  // Advance next_ids up high enough that each is pointing to an
852  // unused id and any subsequent increments will still point us
853  // to unused ids
854  _max_node_id = std::max(_max_node_id,
855  static_cast<dof_id_type>(n->id()+1));
856 
859  ((_max_node_id-1) / (this->n_processors() + 1) + 1) *
860  (this->n_processors() + 1) + this->n_processors();
863  ((_max_node_id + this->n_processors() - 1) / (this->n_processors() + 1) + 1) *
864  (this->n_processors() + 1) + this->processor_id();
865 
866 #ifndef NDEBUG
867  // We need a const dofobject_container so we don't inadvertently create
868  // nullptr entries when testing for non-nullptr ones
869  const dofobject_container<Node> & const_nodes = _nodes;
870 #endif
873  }
874 
875  // Don't try to overwrite existing nodes
876  libmesh_assert (!_nodes[n->id()]);
877 
878  _nodes[n->id()] = n;
879 
880  // Try to make the cached node data more accurate
881  if (node_procid == this->processor_id() ||
882  node_procid == DofObject::invalid_processor_id)
883  _n_nodes++;
884 
885 #ifdef LIBMESH_ENABLE_UNIQUE_ID
886  if (!n->valid_unique_id())
887  {
888  if (processor_id() == n->processor_id())
889  {
891  _next_unique_id += this->n_processors() + 1;
892  }
893  else
894  {
897  }
898  }
899  else
900  {
901  _next_unique_id = std::max(_next_unique_id, n->unique_id()+1);
903  ((_next_unique_id + this->n_processors() - 1) / (this->n_processors() + 1) + 1) *
904  (this->n_processors() + 1) + this->processor_id();
905  }
906 #endif
907 
910 
911  // Unpartitioned nodes should be added on every processor
912  // And shouldn't be added in the same batch as ghost nodes
913  // But we might be just adding on processor 0 to
914  // broadcast later
915  // #ifdef DEBUG
916  // if (node_procid == DofObject::invalid_processor_id)
917  // {
918  // dof_id_type node_id = n->id();
919  // this->comm().max(node_id);
920  // libmesh_assert_equal_to (node_id, n->id());
921  // }
922  // #endif
923 
924  return n;
925 }
926 
927 Node * DistributedMesh::add_node (std::unique_ptr<Node> n)
928 {
929  // The mesh now takes ownership of the Node. Eventually the guts of
930  // add_node() will get moved to a private helper function, and
931  // calling add_node() directly will be deprecated.
932  return add_node(n.release());
933 }
934 
936 {
937  libmesh_assert(n);
938  libmesh_assert(_nodes[n->id()]);
939 
940  // Try to make the cached elem data more accurate
941  _n_nodes--;
942 
943  // Delete the node from the BoundaryInfo object
944  this->get_boundary_info().remove(n);
945  _constraint_rows.erase(n);
946 
947  // But not yet from the container; we might invalidate
948  // an iterator that way!
949 
950  //_nodes.erase(n->id());
951 
952  // Instead, we set it to nullptr for now
953 
954  _nodes[n->id()] = nullptr;
955 
956  // delete the node
957  delete n;
958 }
959 
960 
961 
963  const dof_id_type new_id)
964 {
965  // This could be a no-op
966  if (old_id == new_id)
967  return;
968 
969  Node * nd = _nodes[old_id];
970  libmesh_assert (nd);
971  libmesh_assert_equal_to (nd->id(), old_id);
972 
973  // If we have nodes shipped to this processor for NodeConstraints
974  // use, then those nodes will exist in _nodes, but may not be
975  // locatable via a TopologyMap due to the insufficiency of elements
976  // connecting to them. If local refinement then wants to create a
977  // *new* node in the same location, it will initially get a temporary
978  // id, and then make_node_ids_parallel_consistent() will try to move
979  // it to the canonical id. We need to account for this case to
980  // avoid false positives and memory leaks.
981 #ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS
982  if (_nodes[new_id])
983  {
984  libmesh_assert_equal_to (*(Point *)_nodes[new_id],
985  *(Point *)_nodes[old_id]);
986  _nodes.erase(new_id);
987  }
988 #else
989  // If we aren't shipping nodes for NodeConstraints, there should be
990  // no reason for renumbering one node onto another.
991  libmesh_assert (!_nodes[new_id]);
992 #endif
993  _nodes[new_id] = nd;
994  nd->set_id(new_id);
995 
996  _nodes.erase(old_id);
997 }
998 
999 
1000 
1002 {
1003  // Call parent clear function
1004  MeshBase::clear();
1005 
1006  // Clear our elements and nodes
1007  // There is no need to remove them from
1008  // the BoundaryInfo data structure since we
1009  // already cleared it.
1011 
1012  for (auto & node : _nodes)
1013  delete node;
1014 
1015  _nodes.clear();
1016 
1017  // We're no longer distributed if we were before
1018  _is_serial = true;
1019  _is_serial_on_proc_0 = true;
1020 
1021  // We deleted a ton of coarse elements, but their nodes got deleted too so
1022  // all is copacetic.
1023  _deleted_coarse_elements = false;
1024 
1025  // Correct our caches
1026  _n_nodes = 0;
1027  _max_node_id = 0;
1030 }
1031 
1032 
1033 
1035 {
1036  for (auto & elem : _elements)
1037  delete elem;
1038 
1039  _elements.clear();
1040 
1041  // Correct our caches
1042  _n_elem = 0;
1043  _max_elem_id = 0;
1046 }
1047 
1048 
1049 
1051 {
1052  // If this is a truly parallel mesh, go through the redistribution/gather/delete remote steps
1053  if (!this->is_serial())
1054  {
1055  // Construct a MeshCommunication object to actually redistribute the nodes
1056  // and elements according to the partitioner, and then to re-gather the neighbors.
1057  MeshCommunication mc;
1058  mc.redistribute(*this);
1059 
1060  this->update_parallel_id_counts();
1061 
1062  // We ought to still have valid neighbor links; we communicate
1063  // them for newly-redistributed elements
1064  // this->find_neighbors();
1065 
1066  // Is this necessary? If we are called from prepare_for_use(), this will be called
1067  // anyway... but users can always call partition directly, in which case we do need
1068  // to call delete_remote_elements()...
1069  //
1070  // Regardless of whether it's necessary, it isn't safe. We
1071  // haven't communicated new node processor_ids yet, and we can't
1072  // delete nodes until we do.
1073  // this->delete_remote_elements();
1074  }
1075  else
1076  // The base class can handle non-distributed things, like
1077  // notifying any GhostingFunctors of changes
1079 }
1080 
1081 
1082 
1084 {
1085  // this->recalculate_n_partitions();
1086 
1087  // Let's do the base class cache clearing first, just in case our
1088  // later computations are ever changed to make use of a local
1089  // elements range cache
1091 
1092  // Partitioning changes our numbers of unpartitioned objects
1093  this->update_parallel_id_counts();
1094 }
1095 
1096 
1097 
1098 template <typename T>
1100 {
1101  // This function must be run on all processors at once
1102  parallel_object_only();
1103 
1104  const dof_id_type pmax_node_id = this->parallel_max_node_id();
1105  const dof_id_type pmax_elem_id = this->parallel_max_elem_id();
1106  const dof_id_type pmax_id = std::max(pmax_node_id, pmax_elem_id);
1107 
1108  for (dof_id_type i=0; i != pmax_id; ++i)
1109  {
1110  T * obj = objects[i]; // Returns nullptr if there's no map entry
1111 
1112  // Local lookups by id should return the requested object
1113  libmesh_assert(!obj || obj->id() == i);
1114 
1115  // All processors with an object should agree on id
1116 #ifndef NDEBUG
1117  const dof_id_type dofid = obj && obj->valid_id() ?
1118  obj->id() : DofObject::invalid_id;
1119  libmesh_assert(this->comm().semiverify(obj ? &dofid : nullptr));
1120 #endif
1121 
1122  // All processors with an object should agree on processor id
1123  const dof_id_type procid = obj && obj->valid_processor_id() ?
1124  obj->processor_id() : DofObject::invalid_processor_id;
1125  libmesh_assert(this->comm().semiverify(obj ? &procid : nullptr));
1126 
1127  dof_id_type min_procid = procid;
1128  this->comm().min(min_procid);
1129 
1130  // Either:
1131  // 1.) I own this elem (min_procid == this->processor_id()) *and* I have a valid pointer to it (obj != nullptr)
1132  // or
1133  // 2.) I don't own this elem (min_procid != this->processor_id()). (In this case I may or may not have a valid pointer to it.)
1134 
1135  // Original assert logic
1136  // libmesh_assert (min_procid != this->processor_id() || obj);
1137 
1138  // More human-understandable logic...
1139  libmesh_assert (
1140  ((min_procid == this->processor_id()) && obj)
1141  ||
1142  (min_procid != this->processor_id())
1143  );
1144 
1145 #if defined(LIBMESH_ENABLE_UNIQUE_ID) && !defined(NDEBUG)
1146  // All processors with an object should agree on unique id
1147  const unique_id_type uniqueid = obj ? obj->unique_id() : 0;
1148  libmesh_assert(this->comm().semiverify(obj ? &uniqueid : nullptr));
1149 #endif
1150  }
1151 }
1152 
1153 
1154 
1156 {
1158  this->libmesh_assert_valid_parallel_object_ids (this->_nodes);
1159 }
1160 
1161 
1162 
1164 {
1165 #ifndef NDEBUG
1166  // This function must be run on all processors at once
1167  parallel_object_only();
1168 
1169  dof_id_type pmax_elem_id = this->parallel_max_elem_id();
1170 
1171  for (dof_id_type i=0; i != pmax_elem_id; ++i)
1172  {
1173  Elem * el = _elements[i]; // Returns nullptr if there's no map entry
1174 
1175  unsigned int p_level = el ? (el->p_level()) : libMesh::invalid_uint;
1176 
1177  // All processors with an active element should agree on p level
1178  libmesh_assert(this->comm().semiverify((el && el->active()) ? &p_level : nullptr));
1179  }
1180 #endif
1181 }
1182 
1183 
1184 
1185 
1187 {
1188 #if defined(LIBMESH_ENABLE_AMR) && !defined(NDEBUG)
1189  // This function must be run on all processors at once
1190  parallel_object_only();
1191 
1192  dof_id_type pmax_elem_id = this->parallel_max_elem_id();
1193 
1194  for (dof_id_type i=0; i != pmax_elem_id; ++i)
1195  {
1196  Elem * el = _elements[i]; // Returns nullptr if there's no map entry
1197 
1198  unsigned int refinement_flag = el ?
1199  static_cast<unsigned int> (el->refinement_flag()) : libMesh::invalid_uint;
1200  unsigned int p_refinement_flag = el ?
1201  static_cast<unsigned int> (el->p_refinement_flag()) : libMesh::invalid_uint;
1202 
1203  libmesh_assert(this->comm().semiverify(el ? &refinement_flag : nullptr));
1204 
1205  // p refinement flags aren't always kept correct on inactive
1206  // ghost elements
1207  libmesh_assert(this->comm().semiverify((el && el->active()) ? &p_refinement_flag : nullptr));
1208  }
1209 #endif // LIBMESH_ENABLE_AMR
1210 }
1211 
1212 
1213 
1214 template <typename T>
1217 {
1218  // This function must be run on all processors at once
1219  parallel_object_only();
1220 
1221  typedef typename dofobject_container<T>::veclike_iterator object_iterator;
1222 
1223  // In parallel we may not know what objects other processors have.
1224  // Start by figuring out how many
1225  dof_id_type unpartitioned_objects = 0;
1226 
1227  std::unordered_map<processor_id_type, dof_id_type>
1228  ghost_objects_from_proc;
1229 
1230  object_iterator it = objects.begin();
1231  object_iterator end = objects.end();
1232 
1233  while (it != end)
1234  {
1235  T * obj = *it;
1236 
1237  // Remove any nullptr container entries while we're here.
1238  if (!obj)
1239  it = objects.erase(it);
1240  else
1241  {
1242  processor_id_type obj_procid = obj->processor_id();
1243  if (obj_procid == DofObject::invalid_processor_id)
1244  unpartitioned_objects++;
1245  else
1246  ghost_objects_from_proc[obj_procid]++;
1247 
1248  // Finally, increment the iterator
1249  ++it;
1250  }
1251  }
1252 
1253  std::vector<dof_id_type> objects_on_proc(this->n_processors(), 0);
1254  auto this_it = ghost_objects_from_proc.find(this->processor_id());
1255  this->comm().allgather
1256  ((this_it == ghost_objects_from_proc.end()) ?
1257  dof_id_type(0) : this_it->second, objects_on_proc);
1258 
1259 #ifndef NDEBUG
1260  libmesh_assert(this->comm().verify(unpartitioned_objects));
1261  for (processor_id_type p=0, np=this->n_processors(); p != np; ++p)
1262  if (ghost_objects_from_proc.count(p))
1263  libmesh_assert_less_equal (ghost_objects_from_proc[p], objects_on_proc[p]);
1264  else
1265  libmesh_assert_less_equal (0, objects_on_proc[p]);
1266 #endif
1267 
1268  // We'll renumber objects in blocks by processor id
1269  std::vector<dof_id_type> first_object_on_proc(this->n_processors());
1270  for (processor_id_type i=1, np=this->n_processors(); i != np; ++i)
1271  first_object_on_proc[i] = first_object_on_proc[i-1] +
1272  objects_on_proc[i-1];
1273  dof_id_type next_id = first_object_on_proc[this->processor_id()];
1274  dof_id_type first_free_id =
1275  first_object_on_proc[this->n_processors()-1] +
1276  objects_on_proc[this->n_processors()-1] +
1277  unpartitioned_objects;
1278 
1279  // First set new local object ids and build request sets
1280  // for non-local object ids
1281 
1282  // Request sets to send to each processor
1283  std::map<processor_id_type, std::vector<dof_id_type>>
1284  requested_ids;
1285 
1286  // We know how many objects live on each processor, so reserve() space for
1287  // each.
1288  auto ghost_end = ghost_objects_from_proc.end();
1289  for (auto p : make_range(this->n_processors()))
1290  if (p != this->processor_id())
1291  {
1292  if (const auto p_it = ghost_objects_from_proc.find(p);
1293  p_it != ghost_end)
1294  requested_ids[p].reserve(p_it->second);
1295  }
1296 
1297  end = objects.end();
1298  for (it = objects.begin(); it != end; ++it)
1299  {
1300  T * obj = *it;
1301  if (!obj)
1302  continue;
1303  if (obj->processor_id() == this->processor_id())
1304  obj->set_id(next_id++);
1305  else if (obj->processor_id() != DofObject::invalid_processor_id)
1306  requested_ids[obj->processor_id()].push_back(obj->id());
1307  }
1308 
1309  // Next set ghost object ids from other processors
1310 
1311  auto gather_functor =
1312  [
1313 #ifndef NDEBUG
1314  this,
1315  &first_object_on_proc,
1316  &objects_on_proc,
1317 #endif
1318  &objects]
1319  (processor_id_type, const std::vector<dof_id_type> & ids,
1320  std::vector<dof_id_type> & new_ids)
1321  {
1322  std::size_t ids_size = ids.size();
1323  new_ids.resize(ids_size);
1324 
1325  for (std::size_t i=0; i != ids_size; ++i)
1326  {
1327  T * obj = objects[ids[i]];
1328  libmesh_assert(obj);
1329  libmesh_assert_equal_to (obj->processor_id(), this->processor_id());
1330  new_ids[i] = obj->id();
1331 
1332  libmesh_assert_greater_equal (new_ids[i],
1333  first_object_on_proc[this->processor_id()]);
1334  libmesh_assert_less (new_ids[i],
1335  first_object_on_proc[this->processor_id()] +
1336  objects_on_proc[this->processor_id()]);
1337  }
1338  };
1339 
1340  auto action_functor =
1341  [
1342 #ifndef NDEBUG
1343  &first_object_on_proc,
1344  &objects_on_proc,
1345 #endif
1346  &objects]
1347  (processor_id_type libmesh_dbg_var(pid),
1348  const std::vector<dof_id_type> & ids,
1349  const std::vector<dof_id_type> & data)
1350  {
1351  // Copy the id changes we've now been informed of
1352  for (auto i : index_range(ids))
1353  {
1354  T * obj = objects[ids[i]];
1355  libmesh_assert (obj);
1356  libmesh_assert_equal_to (obj->processor_id(), pid);
1357  libmesh_assert_greater_equal (data[i],
1358  first_object_on_proc[pid]);
1359  libmesh_assert_less (data[i],
1360  first_object_on_proc[pid] +
1361  objects_on_proc[pid]);
1362  obj->set_id(data[i]);
1363  }
1364  };
1365 
1366  const dof_id_type * ex = nullptr;
1367  Parallel::pull_parallel_vector_data
1368  (this->comm(), requested_ids, gather_functor, action_functor, ex);
1369 
1370 #ifdef LIBMESH_ENABLE_UNIQUE_ID
1371  auto unique_gather_functor =
1372  [
1373 #ifndef NDEBUG
1374  this,
1375 #endif
1376  &objects]
1377  (processor_id_type, const std::vector<dof_id_type> & ids,
1378  std::vector<unique_id_type> & data)
1379  {
1380  std::size_t ids_size = ids.size();
1381  data.resize(ids_size);
1382 
1383  for (std::size_t i=0; i != ids_size; ++i)
1384  {
1385  T * obj = objects[ids[i]];
1386  libmesh_assert(obj);
1387  libmesh_assert_equal_to (obj->processor_id(), this->processor_id());
1388  data[i] = obj->valid_unique_id() ? obj->unique_id() : DofObject::invalid_unique_id;
1389  }
1390  };
1391 
1392  auto unique_action_functor =
1393  [&objects]
1394  (processor_id_type libmesh_dbg_var(pid),
1395  const std::vector<dof_id_type> & ids,
1396  const std::vector<unique_id_type> & data)
1397  {
1398  for (auto i : index_range(ids))
1399  {
1400  T * obj = objects[ids[i]];
1401  libmesh_assert (obj);
1402  libmesh_assert_equal_to (obj->processor_id(), pid);
1403  if (!obj->valid_unique_id() && data[i] != DofObject::invalid_unique_id)
1404  obj->set_unique_id(data[i]);
1405  }
1406  };
1407 
1408  const unique_id_type * unique_ex = nullptr;
1409  Parallel::pull_parallel_vector_data
1410  (this->comm(), requested_ids, unique_gather_functor,
1411  unique_action_functor, unique_ex);
1412 #endif
1413 
1414  // Next set unpartitioned object ids
1415  next_id = 0;
1416  for (auto i : make_range(this->n_processors()))
1417  next_id += objects_on_proc[i];
1418  for (it = objects.begin(); it != end; ++it)
1419  {
1420  T * obj = *it;
1421  if (!obj)
1422  continue;
1423  if (obj->processor_id() == DofObject::invalid_processor_id)
1424  obj->set_id(next_id++);
1425  }
1426 
1427  // Finally shuffle around objects so that container indices
1428  // match ids
1429  it = objects.begin();
1430  end = objects.end();
1431  while (it != end)
1432  {
1433  T * obj = *it;
1434  if (obj) // don't try shuffling already-nullptr entries
1435  {
1436  T * next = objects[obj->id()];
1437  // If we have to move this object
1438  if (next != obj)
1439  {
1440  // nullptr out its original position for now
1441  // (our shuffling may put another object there shortly)
1442  *it = nullptr;
1443 
1444  // There may already be another object with this id that
1445  // needs to be moved itself
1446  while (next)
1447  {
1448  // We shouldn't be trying to give two objects the
1449  // same id
1450  libmesh_assert_not_equal_to (next->id(), obj->id());
1451  objects[obj->id()] = obj;
1452  obj = next;
1453  next = objects[obj->id()];
1454  }
1455  objects[obj->id()] = obj;
1456  }
1457  }
1458 
1459  // Remove any container entries that were left as nullptr.
1460  if (!obj)
1461  it = objects.erase(it);
1462  else
1463  ++it;
1464  }
1465 
1466  return first_free_id;
1467 }
1468 
1469 
1471 {
1472  parallel_object_only();
1473 
1474 #ifdef DEBUG
1475  // Make sure our ids and flags are consistent
1479 #endif
1480 
1481  LOG_SCOPE("renumber_nodes_and_elements()", "DistributedMesh");
1482 
1483  // Nodes not connected to any elements, and nullptr node entries
1484  // in our container, should be deleted. But wait! If we've deleted coarse
1485  // local elements on some processor, other processors might have ghosted
1486  // nodes from it that are now no longer connected to any elements on it, but
1487  // that are connected to their own semilocal elements. We'll have to
1488  // communicate to ascertain if that's the case.
1490 
1491  // What used nodes do we see on our proc?
1492  std::set<dof_id_type> used_nodes;
1493 
1494  // What used node info should we send from our proc? Could we take ownership
1495  // of each node if we needed to?
1496  std::map<processor_id_type, std::map<dof_id_type, bool>>
1497  used_nodes_on_proc;
1498 
1499  // flag the nodes we need
1500  for (auto & elem : this->element_ptr_range())
1501  for (const Node & node : elem->node_ref_range())
1502  {
1503  const dof_id_type n = node.id();
1504  used_nodes.insert(n);
1506  {
1507  const processor_id_type p = node.processor_id();
1508  if (p != this->processor_id())
1509  {
1510  auto & used_nodes_on_p = used_nodes_on_proc[p];
1511  if (elem->processor_id() == this->processor_id())
1512  used_nodes_on_p[n] = true;
1513  else
1514  if (!used_nodes_on_p.count(n))
1515  used_nodes_on_p[n] = false;
1516  }
1517  }
1518  }
1519 
1521  {
1522  // "unsigned char" == "bool, but MPI::BOOL is iffy to use"
1523  typedef unsigned char boolish;
1524  std::map<processor_id_type, std::vector<std::pair<dof_id_type, boolish>>>
1525  used_nodes_on_proc_vecs;
1526  for (auto & [pid, nodemap] : used_nodes_on_proc)
1527  used_nodes_on_proc_vecs[pid].assign(nodemap.begin(), nodemap.end());
1528 
1529  std::map<dof_id_type,processor_id_type> repartitioned_node_pids;
1530  std::map<processor_id_type, std::set<dof_id_type>>
1531  repartitioned_node_sets_to_push;
1532 
1533  auto ids_action_functor =
1534  [&used_nodes, &repartitioned_node_pids,
1535  &repartitioned_node_sets_to_push]
1537  const std::vector<std::pair<dof_id_type, boolish>> & ids_and_bools)
1538  {
1539  for (auto [n, sender_could_become_owner] : ids_and_bools)
1540  {
1541  // If we don't see a use for our own node, but someone
1542  // else does, better figure out who should own it next.
1543  if (!used_nodes.count(n))
1544  {
1545  if (auto it = repartitioned_node_pids.find(n);
1546  sender_could_become_owner)
1547  {
1548  if (it != repartitioned_node_pids.end() &&
1549  pid < it->second)
1550  it->second = pid;
1551  else
1552  repartitioned_node_pids[n] = pid;
1553  }
1554  else
1555  if (it == repartitioned_node_pids.end())
1556  repartitioned_node_pids[n] =
1558 
1559  repartitioned_node_sets_to_push[pid].insert(n);
1560  }
1561  }
1562  };
1563 
1564  // We need two pushes instead of a pull here because we need to
1565  // know *all* the queries for a particular node before we can
1566  // respond to *any* of them.
1567  Parallel::push_parallel_vector_data
1568  (this->comm(), used_nodes_on_proc_vecs, ids_action_functor);
1569 
1570  // Repartition (what used to be) our own nodes first
1571  for (auto & [n, p] : repartitioned_node_pids)
1572  {
1573  Node & node = this->node_ref(n);
1574  libmesh_assert_equal_to(node.processor_id(), this->processor_id());
1575  libmesh_assert_not_equal_to_msg(p, DofObject::invalid_processor_id, "Node " << n << " is lost?");
1576  node.processor_id() = p;
1577  }
1578 
1579  // Then push to repartition others' ghosted copies.
1580 
1581  std::map<processor_id_type, std::vector<std::pair<dof_id_type,processor_id_type>>>
1582  repartitioned_node_vecs;
1583 
1584  for (auto & [p, nodeset] : repartitioned_node_sets_to_push)
1585  {
1586  auto & rn_vec = repartitioned_node_vecs[p];
1587  for (auto n : nodeset)
1588  rn_vec.emplace_back(n, repartitioned_node_pids[n]);
1589  }
1590 
1591  auto repartition_node_functor =
1592  [this]
1593  (processor_id_type libmesh_dbg_var(pid),
1594  const std::vector<std::pair<dof_id_type, processor_id_type>> & ids_and_pids)
1595  {
1596  for (auto [n, p] : ids_and_pids)
1597  {
1598  libmesh_assert_not_equal_to(p, DofObject::invalid_processor_id);
1599  Node & node = this->node_ref(n);
1600  libmesh_assert_equal_to(node.processor_id(), pid);
1601  node.processor_id() = p;
1602  }
1603  };
1604 
1605  Parallel::push_parallel_vector_data
1606  (this->comm(), repartitioned_node_vecs, repartition_node_functor);
1607  }
1608 
1609  _deleted_coarse_elements = false;
1610 
1611  // Nodes not connected to any local elements, and nullptr node entries
1612  // in our container, are deleted
1613  {
1614  node_iterator_imp it = _nodes.begin();
1615  node_iterator_imp end = _nodes.end();
1616 
1617  while (it != end)
1618  {
1619  Node * nd = *it;
1620  if (!nd)
1621  it = _nodes.erase(it);
1622  else if (!used_nodes.count(nd->id()))
1623  {
1624  // remove any boundary information associated with
1625  // this node
1626  this->get_boundary_info().remove (nd);
1627  _constraint_rows.erase(nd);
1628 
1629  // delete the node
1630  delete nd;
1631 
1632  it = _nodes.erase(it);
1633  }
1634  else
1635  ++it;
1636  }
1637  }
1638 
1640 
1642  {
1643  this->update_parallel_id_counts();
1644  return;
1645  }
1646 
1647  // Finally renumber all the elements
1648  _n_elem = this->renumber_dof_objects (this->_elements);
1649 
1650  // and all the remaining nodes
1651  _n_nodes = this->renumber_dof_objects (this->_nodes);
1652 
1653  // And figure out what IDs we should use when adding new nodes and
1654  // new elements
1655  this->update_parallel_id_counts();
1656 
1657  // Make sure our caches are up to date and our
1658  // DofObjects are well packed
1659 #ifdef DEBUG
1660  libmesh_assert_equal_to (this->n_nodes(), this->parallel_n_nodes());
1661  libmesh_assert_equal_to (this->n_elem(), this->parallel_n_elem());
1662  const dof_id_type pmax_node_id = this->parallel_max_node_id();
1663  const dof_id_type pmax_elem_id = this->parallel_max_elem_id();
1664  libmesh_assert_equal_to (this->max_node_id(), pmax_node_id);
1665  libmesh_assert_equal_to (this->max_elem_id(), pmax_elem_id);
1666  libmesh_assert_equal_to (this->n_nodes(), this->max_node_id());
1667  libmesh_assert_equal_to (this->n_elem(), this->max_elem_id());
1668 
1669  // Make sure our ids and flags are consistent
1672 
1673  // And make sure we've made our numbering monotonic
1675 #endif
1676 }
1677 
1678 
1679 
1681 {
1682  // We can't use range-for here because we need access to the special
1683  // iterators' methods, not just to their dereferenced values.
1684 
1685  // Nodes first
1686  for (auto pr = this->_nodes.begin(),
1687  end = this->_nodes.end(); pr != end; ++pr)
1688  {
1689  Node * n = *pr;
1690  if (n != nullptr)
1691  {
1692  const dof_id_type id = pr.index();
1693  n->set_id() = id;
1694  libmesh_assert_equal_to(this->node_ptr(id), n);
1695  }
1696  }
1697 
1698  // Elements next
1699  for (auto pr = this->_elements.begin(),
1700  end = this->_elements.end(); pr != end; ++pr)
1701  {
1702  Elem * e = *pr;
1703  if (e != nullptr)
1704  {
1705  const dof_id_type id = pr.index();
1706  e->set_id() = id;
1707  libmesh_assert_equal_to(this->elem_ptr(id), e);
1708  }
1709  }
1710 }
1711 
1712 
1713 
1715 {
1716  parallel_object_only();
1717 
1718  // Get local active elements first
1719  dof_id_type active_elements =
1720  static_cast<dof_id_type>(std::distance (this->active_local_elements_begin(),
1721  this->active_local_elements_end()));
1722  this->comm().sum(active_elements);
1723 
1724  // Then add unpartitioned active elements, which should exist on
1725  // every processor
1726  active_elements +=
1727  static_cast<dof_id_type>(std::distance
1728  (this->active_pid_elements_begin(DofObject::invalid_processor_id),
1729  this->active_pid_elements_end(DofObject::invalid_processor_id)));
1730  return active_elements;
1731 }
1732 
1733 
1734 
1736 {
1737 #ifdef DEBUG
1738  // Make sure our neighbor links are all fine
1740 
1741  // And our child/parent links, and our flags
1743 
1744  // Make sure our ids and flags are consistent
1747 
1748  libmesh_assert_equal_to (this->n_nodes(), this->parallel_n_nodes());
1749  libmesh_assert_equal_to (this->n_elem(), this->parallel_n_elem());
1750  const dof_id_type pmax_node_id = this->parallel_max_node_id();
1751  const dof_id_type pmax_elem_id = this->parallel_max_elem_id();
1752  libmesh_assert_equal_to (this->max_node_id(), pmax_node_id);
1753  libmesh_assert_equal_to (this->max_elem_id(), pmax_elem_id);
1754 #endif
1755 
1756  _is_serial = false;
1757  _is_serial_on_proc_0 = false;
1758 
1759  MeshCommunication().delete_remote_elements(*this, _extra_ghost_elems);
1760 
1761  libmesh_assert_equal_to (this->max_elem_id(), this->parallel_max_elem_id());
1762 
1763  // Now make sure the containers actually shrink - strip
1764  // any newly-created nullptr voids out of the element array
1767  while (e_it != e_end)
1768  if (!*e_it)
1769  e_it = _elements.erase(e_it);
1770  else
1771  ++e_it;
1772 
1775  while (n_it != n_end)
1776  if (!*n_it)
1777  n_it = _nodes.erase(n_it);
1778  else
1779  ++n_it;
1780 
1781  // We may have deleted no-longer-connected nodes or coarsened-away
1782  // elements; let's update our caches.
1783  this->update_parallel_id_counts();
1784 
1785  // We may have deleted nodes or elements that were the only local
1786  // representatives of some particular boundary id(s); let's update
1787  // those caches.
1789 
1790 #ifdef DEBUG
1791  // We might not have well-packed objects if the user didn't allow us
1792  // to renumber
1793  // libmesh_assert_equal_to (this->n_nodes(), this->max_node_id());
1794  // libmesh_assert_equal_to (this->n_elem(), this->max_elem_id());
1795 
1796  // Make sure our neighbor links are all fine
1798 
1799  // And our child/parent links, and our flags
1801 
1802  // Make sure our ids and flags are consistent
1805 #endif
1806 
1808 }
1809 
1810 
1812 {
1813  // First add the elem like normal
1814  add_elem(e);
1815 
1816  // Now add it to the set that won't be deleted when we call
1817  // delete_remote_elements()
1818  _extra_ghost_elems.insert(e);
1819 }
1820 
1821 void
1822 DistributedMesh::clear_extra_ghost_elems(const std::set<Elem *> & extra_ghost_elems)
1823 {
1824  std::set<Elem *> tmp;
1825  std::set_difference(_extra_ghost_elems.begin(), _extra_ghost_elems.end(),
1826  extra_ghost_elems.begin(), extra_ghost_elems.end(),
1827  std::inserter(tmp, tmp.begin()));
1828  _extra_ghost_elems = tmp;
1829 }
1830 
1832 {
1833  if (_is_serial)
1834  return;
1835  MeshCommunication().allgather(*this);
1836  _is_serial = true;
1837  _is_serial_on_proc_0 = true;
1838 
1839  // Make sure our caches are up to date and our
1840  // DofObjects are well packed
1841 #ifdef DEBUG
1842  libmesh_assert_equal_to (this->n_nodes(), this->parallel_n_nodes());
1843  libmesh_assert_equal_to (this->n_elem(), this->parallel_n_elem());
1844  const dof_id_type pmax_node_id = this->parallel_max_node_id();
1845  const dof_id_type pmax_elem_id = this->parallel_max_elem_id();
1846  libmesh_assert_equal_to (this->max_node_id(), pmax_node_id);
1847  libmesh_assert_equal_to (this->max_elem_id(), pmax_elem_id);
1848 
1849  // If we've disabled renumbering we can't be sure we're contiguous
1850  // libmesh_assert_equal_to (this->n_nodes(), this->max_node_id());
1851  // libmesh_assert_equal_to (this->n_elem(), this->max_elem_id());
1852 
1853  // Make sure our neighbor links are all fine
1855 
1856  // Make sure our ids and flags are consistent
1859 #endif
1860 }
1861 
1863 {
1865  return;
1866 
1867  _is_serial_on_proc_0 = true;
1868  MeshCommunication().gather(0, *this);
1869 }
1870 
1871 
1872 } // namespace libMesh
UnstructuredMesh & operator=(const UnstructuredMesh &)=delete
Copy assignment is not allowed.
This mapvector templated class is intended to provide the performance characteristics of a std::map w...
Definition: mapvector.h:42
virtual void update_post_partitioning()
Recalculate any cached data (or invalidate any caches that are computed on the fly) after elements an...
Definition: mesh_base.C:1173
RefinementState refinement_flag() const
Definition: elem.h:3224
virtual Node * add_point(const Point &p, const dof_id_type id=DofObject::invalid_id, const processor_id_type proc_id=DofObject::invalid_processor_id) override final
functions for adding /deleting nodes elements.
virtual void update_parallel_id_counts() override
Updates parallel caches so that methods like n_elem() accurately reflect changes on other processors...
void allgather(const T &send_data, std::vector< T, A > &recv_data) const
virtual dof_id_type parallel_n_nodes() const override
const Elem * parent() const
Definition: elem.h:3044
bool _skip_renumber_nodes_and_elements
If this is true then renumbering will be kept to a minimum.
Definition: mesh_base.h:2237
virtual Elem * add_elem(Elem *e) override final
Add elem e to the end of the element array.
static constexpr processor_id_type invalid_processor_id
An invalid processor_id to distinguish DoFs that have not been assigned to a processor.
Definition: dof_object.h:484
A Node is like a Point, but with more information.
Definition: node.h:52
virtual unique_id_type parallel_max_unique_id() const =0
dof_id_type n_unpartitioned_nodes() const
Definition: mesh_base.h:587
const unsigned int invalid_uint
A number which is used quite often to represent an invalid or uninitialized value for an unsigned int...
Definition: libmesh.h:303
std::vector< std::string > _elem_integer_names
The array of names for integer data associated with each element in the mesh.
Definition: mesh_base.h:2338
virtual void libmesh_assert_valid_parallel_ids() const override
Verify id and processor_id consistency of our elements and nodes containers.
virtual void fix_broken_node_and_element_numbering() override
There is no reason for a user to ever call this function.
static constexpr unique_id_type invalid_unique_id
An invalid unique_id to distinguish an uninitialized DofObject.
Definition: dof_object.h:478
void set_mapping_type(const ElemMappingType type)
Sets the value of the mapping type for the element.
Definition: elem.h:3142
void allow_renumbering(bool allow)
If false is passed in then this mesh will no longer be renumbered when being prepared for use...
Definition: mesh_base.h:1345
virtual void renumber_elem(dof_id_type old_id, dof_id_type new_id) override final
Changes the id of element old_id, both by changing elem(old_id)->id() and by moving elem(old_id) in t...
void skip_partitioning(bool skip)
If true is passed in then nothing on this mesh will be (re)partitioned.
Definition: mesh_base.h:1419
bool _is_serial_on_proc_0
A boolean remembering whether we&#39;re serialized to proc 0 or not.
dof_id_type _n_nodes
Cached data from the last renumber_nodes_and_elements call.
bool allow_detect_interior_parents() const
Definition: mesh_base.h:1360
virtual void clear() override
Clear all internal data.
virtual void renumber_nodes_and_elements() override
Remove nullptr elements from arrays.
RefinementState p_refinement_flag() const
Definition: elem.h:3240
void libmesh_assert_valid_refinement_tree(const MeshBase &mesh)
A function for verifying that elements on this processor have valid descendants and consistent active...
Definition: mesh_tools.C:1627
virtual dof_id_type n_nodes() const override final
dof_id_type _next_free_local_node_id
Guaranteed globally unused IDs for use when adding new nodes or elements.
void remove(const Node *node)
Removes the boundary conditions associated with node node, if any exist.
void sum(T &r) const
virtual void allgather() override
Gathers all elements and nodes of the mesh onto every processor.
This is the base class from which all geometric element types are derived.
Definition: elem.h:94
dof_id_type n_local_nodes() const
Definition: mesh_base.h:581
constraint_rows_type _constraint_rows
Definition: mesh_base.h:2409
unique_id_type unique_id() const
Definition: dof_object.h:835
void copy_constraint_rows(const MeshBase &other_mesh)
Copy the constraints from the other mesh to this mesh.
Definition: mesh_base.C:2450
const Parallel::Communicator & comm() const
bool _is_serial
A boolean remembering whether we&#39;re serialized or not.
unsigned int p_level() const
Definition: elem.h:3122
void libmesh_assert_valid_parallel_flags() const
Verify refinement_flag and p_refinement_flag consistency of our elements containers.
The libMesh namespace provides an interface to certain functionality in the library.
virtual void delete_elem(Elem *e) override final
Removes element e from the mesh.
void allow_detect_interior_parents(bool allow)
If false is passed then this mesh will no longer work to detect interior parents when being prepared ...
Definition: mesh_base.h:1359
const BoundaryInfo & get_boundary_info() const
The information about boundary ids on the mesh.
Definition: mesh_base.h:170
virtual void add_extra_ghost_elem(Elem *e)
Inserts the element and adds it to a list of elements that should not get deleted or have their desce...
dof_id_type n_unpartitioned_elem() const
Definition: mesh_base.h:693
std::vector< std::string > _node_integer_names
The array of names for integer data associated with each node in the mesh.
Definition: mesh_base.h:2350
virtual Node * add_node(Node *n) override final
Add Node n to the end of the vertex array.
Real distance(const Point &p)
Preparation preparation() const
Definition: mesh_base.h:213
virtual const Point & point(const dof_id_type i) const override final
void clear_stored_ranges()
Clears stored ranges, to indicate that the mesh has changed and they should be regenerated when next ...
Definition: mesh_base.C:1943
virtual unique_id_type parallel_max_unique_id() const override
dof_id_type n_local_elem() const
Definition: mesh_base.h:687
virtual void delete_remote_elements() override
Deletes all nonlocal elements of the mesh except for "ghosts" which touch a local element...
void libmesh_assert_valid_parallel_object_ids(const dofobject_container< T > &) const
Verify id, processor_id, and if applicable unique_id consistency of a parallel objects container...
uint8_t processor_id_type
Definition: id_types.h:104
This is the MeshBase class.
Definition: mesh_base.h:80
void libmesh_assert_valid_parallel_p_levels() const
Verify p_level consistency of our elements containers.
dof_id_type & set_id()
Definition: dof_object.h:827
ElemMappingType default_mapping_type() const
Returns the default master space to physical space mapping basis functions to be used on newly added ...
Definition: mesh_base.h:931
unique_id_type _next_unique_id
The next available unique id for assigning ids to DOF objects.
Definition: mesh_base.h:2212
virtual void clear() override
Free all new memory associated with the object, but restore its original state, with the mesh pointer...
Definition: dof_map.C:871
processor_id_type pid unsigned int level std::set< subdomain_id_type > ss const DofMap &dof_map LIBMESH_COMMA unsigned int dof_map LIBMESH_COMMA var_num unsigned char rflag processor_id_type pid const DofMap &dof_map LIBMESH_COMMA unsigned int dof_map LIBMESH_COMMA var_num DECLARE_NODE_ITERATORS(multi_evaluable_, std::vector< const DofMap * > dof_maps, dof_maps) protected dofobject_container< Node > _nodes
Move node and elements from a DistributedMesh.
void allow_remote_element_removal(bool allow)
If false is passed in then this mesh will no longer have remote elements deleted when being prepared ...
Definition: mesh_base.h:1368
processor_id_type n_processors() const
virtual const Elem * elem_ptr(const dof_id_type i) const override final
friend class MeshCommunication
Make the MeshCommunication class a friend so that it can directly broadcast *_integer_names.
Definition: mesh_base.h:2439
virtual dof_id_type parallel_n_elem() const override
T command_line_value(const std::string &, T)
Definition: libmesh.C:971
This is the MeshCommunication class.
static std::unique_ptr< Partitioner > build(const PartitionerType solver_package)
Builds a Partitioner of the type specified by partitioner_type.
Definition: partitioner.C:159
dof_id_type id() const
Definition: dof_object.h:819
void min(const T &r, T &o, Request &req) const
const std::map< subdomain_id_type, std::string > & get_subdomain_name_map() const
Definition: mesh_base.h:1896
static constexpr dof_id_type invalid_id
An invalid id to distinguish an uninitialized DofObject.
Definition: dof_object.h:473
virtual void move_nodes_and_elements(MeshBase &&other_mesh)=0
Move node and elements from other_mesh to this mesh.
std::set< Elem * > _extra_ghost_elems
These are extra ghost elements that we want to make sure not to delete when we call delete_remote_ele...
The UnstructuredMesh class is derived from the MeshBase class.
unsigned char default_mapping_data() const
Returns any default data value used by the master space to physical space mapping.
Definition: mesh_base.h:949
void erase(index_t i)
Definition: mapvector.h:183
virtual bool is_serial_on_zero() const override final
std::unique_ptr< Partitioner > _partitioner
A partitioner to use at each prepare_for_use().
Definition: mesh_base.h:2206
void set_mapping_data(const unsigned char data)
Sets the value of the mapping data for the element.
Definition: elem.h:3158
void clear_point_locator()
Releases the current PointLocator object.
Definition: mesh_base.C:1859
virtual void set_next_unique_id(unique_id_type id) override
Sets the next available unique id to be used.
virtual void clear_elems() override
Clear internal Elem data.
bool allow_find_neighbors() const
Definition: mesh_base.h:1353
libmesh_assert(ctx)
virtual void own_node(Node &n) override final
Takes ownership of node n on this partition of a distributed mesh, by setting n.processor_id() to thi...
virtual void clear_extra_ghost_elems()
Clears extra ghost elements.
const std::set< Elem * > & extra_ghost_elems() const
Const accessor to the ghosted elements.
bool valid_unique_id() const
Definition: dof_object.h:869
virtual const Node * query_node_ptr(const dof_id_type i) const override final
void allow_find_neighbors(bool allow)
If false is passed then this mesh will no longer work to find element neighbors when being prepared f...
Definition: mesh_base.h:1352
virtual bool subclass_locally_equals(const MeshBase &other_mesh) const override
Shim to allow operator == (&) to behave like a virtual function without having to be one...
dof_id_type parallel_max_node_id() const
veclike_iterator end()
Definition: mapvector.h:203
std::map< subdomain_id_type, std::string > & set_subdomain_name_map()
Definition: mesh_base.h:1894
bool allow_remote_element_removal() const
Definition: mesh_base.h:1369
The DistributedMesh class is derived from the MeshBase class, and is intended to provide identical fu...
void regenerate_id_sets()
Clears and regenerates the cached sets of ids.
virtual void clear()
Deletes all the element and node data that is currently stored.
Definition: mesh_base.C:1029
dof_id_type _next_free_unpartitioned_node_id
dofobject_container< Elem > _elements
The elements in the mesh.
virtual void delete_node(Node *n) override final
Removes the Node n from the mesh.
bool skip_partitioning() const
Definition: mesh_base.h:1421
virtual void renumber_node(dof_id_type old_id, dof_id_type new_id) override final
Changes the id of node old_id, both by changing node(old_id)->id() and by moving node(old_id) in the ...
std::vector< dof_id_type > _node_integer_default_values
The array of default initialization values for integer data associated with each node in the mesh...
Definition: mesh_base.h:2356
static std::unique_ptr< Node > build(const Node &n)
Definition: node.h:315
Preparation _preparation
Flags indicating in what ways this mesh has been prepared.
Definition: mesh_base.h:2162
static const unsigned int next[3]
A lookup table for the increment modulo 3 operation, for iterating through the three nodes per elemen...
virtual void redistribute() override
Redistribute elements between processors.
std::vector< dof_id_type > _elem_integer_default_values
The array of default initialization values for integer data associated with each element in the mesh...
Definition: mesh_base.h:2344
DistributedMesh & operator=(const DistributedMesh &)=delete
Copy assignment is not allowed.
void set_unique_id(unique_id_type new_id)
Sets the unique_id for this DofObject.
Definition: dof_object.h:848
virtual dof_id_type n_active_elem() const override final
dof_id_type _next_free_unpartitioned_elem_id
bool valid_id() const
Definition: dof_object.h:861
void max(const T &r, T &o, Request &req) const
DistributedMesh(const Parallel::Communicator &comm_in, unsigned char dim=1)
Constructor.
veclike_iterator begin()
Definition: mapvector.h:193
void post_dofobject_moves(MeshBase &&other_mesh)
Moves any superclass data (e.g.
Definition: mesh_base.C:2356
virtual void gather_to_zero() override
Gathers all elements and nodes of the mesh onto processor zero.
virtual Elem * insert_elem(Elem *e) override final
Insert elem e to the element array, preserving its id and replacing/deleting any existing element wit...
virtual dof_id_type max_node_id() const override final
IntRange< T > make_range(T beg, T end)
The 2-parameter make_range() helper function returns an IntRange<T> when both input parameters are of...
Definition: int_range.h:176
The DofObject defines an abstract base class for objects that have degrees of freedom associated with...
Definition: dof_object.h:54
void add_extra_integers(const unsigned int n_integers)
Assigns a set of extra integers to this DofObject.
Definition: dof_object.C:482
virtual void copy_nodes_and_elements(const MeshBase &other_mesh, const bool skip_find_neighbors=false, dof_id_type element_id_offset=0, dof_id_type node_id_offset=0, unique_id_type unique_id_offset=0, std::unordered_map< subdomain_id_type, subdomain_id_type > *id_remapping=nullptr, const bool skip_preparation=false)
Deep copy of nodes and elements from another mesh object (used by subclass copy constructors and by m...
virtual const Node & node_ref(const dof_id_type i) const
Definition: mesh_base.h:735
virtual void update_post_partitioning() override
Recalculate cached data after elements and nodes have been repartitioned.
bool allow_renumbering() const
Definition: mesh_base.h:1346
unique_id_type _next_unpartitioned_unique_id
The next available unique id for assigning ids to unpartitioned DOF objects.
virtual MeshBase & assign(MeshBase &&other_mesh) override
Shim to call the move assignment operator for this class.
virtual dof_id_type n_elem() const override final
void libmesh_assert_valid_neighbors(const MeshBase &mesh, bool assert_valid_remote_elems=true)
A function for verifying that neighbor connectivity is correct (each element is a neighbor of or desc...
Definition: mesh_tools.C:2320
virtual ~DistributedMesh()
Destructor.
processor_id_type processor_id() const
virtual bool is_serial() const override final
virtual dof_id_type max_elem_id() const override final
bool active() const
Definition: elem.h:2955
dof_id_type _next_free_local_elem_id
virtual void redistribute()
Redistribute elements between processors.
Definition: mesh_base.C:1161
processor_id_type processor_id() const
Definition: dof_object.h:881
bool _deleted_coarse_elements
A boolean remembering whether we&#39;ve recently deleted top-level elements or not.
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:39
dof_id_type renumber_dof_objects(dofobject_container< T > &)
Renumber a parallel objects container.
uint8_t unique_id_type
Definition: id_types.h:86
void redistribute(DistributedMesh &mesh, bool newly_coarsened_only=false) const
This method takes a parallel distributed mesh and redistributes the elements.
auto index_range(const T &sizable)
Helper function that returns an IntRange<std::size_t> representing all the indices of the passed-in v...
Definition: int_range.h:153
dof_id_type parallel_max_elem_id() const
uint8_t dof_id_type
Definition: id_types.h:67
void libmesh_assert_valid_elem_ids(const MeshBase &mesh)
A function for verifying that ids and processor assignment of elements are correctly sorted (monotone...
Definition: mesh_tools.C:1398
virtual const Node * node_ptr(const dof_id_type i) const override final
virtual const Elem * query_elem_ptr(const dof_id_type i) const override final