libMesh
mesh_tools.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/elem.h"
22 #include "libmesh/elem_range.h"
23 #include "libmesh/libmesh_logging.h"
24 #include "libmesh/mesh_base.h"
25 #include "libmesh/mesh_communication.h"
26 #include "libmesh/mesh_serializer.h"
27 #include "libmesh/mesh_tools.h"
28 #include "libmesh/node_range.h"
29 #include "libmesh/parallel.h"
30 #include "libmesh/parallel_algebra.h"
31 #include "libmesh/parallel_ghost_sync.h"
32 #include "libmesh/sphere.h"
33 #include "libmesh/threads.h"
34 #include "libmesh/enum_to_string.h"
35 #include "libmesh/enum_elem_type.h"
36 #include "libmesh/int_range.h"
37 #include "libmesh/utility.h"
38 #include "libmesh/boundary_info.h"
39 
40 #ifndef NDEBUG
41 # include "libmesh/remote_elem.h"
42 #endif
43 
44 // C++ includes
45 #include <limits>
46 #include <numeric> // for std::accumulate
47 #include <set>
48 #include <unordered_map>
49 #include <unordered_set>
50 
51 
52 
53 // ------------------------------------------------------------
54 // anonymous namespace for helper classes
55 namespace {
56 
57 using namespace libMesh;
58 
66 class SumElemWeight
67 {
68 public:
69  SumElemWeight () :
70  _weight(0)
71  {}
72 
73  SumElemWeight (SumElemWeight &, Threads::split) :
74  _weight(0)
75  {}
76 
77  void operator()(const ConstElemRange & range)
78  {
79  for (const auto & elem : range)
80  _weight += elem->n_nodes();
81  }
82 
83  dof_id_type weight() const
84  { return _weight; }
85 
86  // If we don't have threads we never need a join, and icpc yells a
87  // warning if it sees an anonymous function that's never used
88 #if LIBMESH_USING_THREADS
89  void join (const SumElemWeight & other)
90  { _weight += other.weight(); }
91 #endif
92 
93 private:
94  dof_id_type _weight;
95 };
96 
97 
104 class FindBBox
105 {
106 public:
107  FindBBox () : _bbox()
108  {}
109 
110  FindBBox (FindBBox & other, Threads::split) :
111  _bbox(other._bbox)
112  {}
113 
114  void operator()(const ConstNodeRange & range)
115  {
116  for (const auto & node : range)
117  {
118  libmesh_assert(node);
119  _bbox.union_with(*node);
120  }
121  }
122 
123  void operator()(const ConstElemRange & range)
124  {
125  for (const auto & elem : range)
126  {
127  libmesh_assert(elem);
128  _bbox.union_with(elem->loose_bounding_box());
129  }
130  }
131 
132  Point & min() { return _bbox.min(); }
133 
134  Point & max() { return _bbox.max(); }
135 
136  // If we don't have threads we never need a join, and icpc yells a
137  // warning if it sees an anonymous function that's never used
138 #if LIBMESH_USING_THREADS
139  void join (const FindBBox & other)
140  {
141  _bbox.union_with(other._bbox);
142  }
143 #endif
144 
145  libMesh::BoundingBox & bbox ()
146  {
147  return _bbox;
148  }
149 
150 private:
151  BoundingBox _bbox;
152 };
153 
154 #ifdef DEBUG
155 void assert_semiverify_dofobj(const Parallel::Communicator & communicator,
156  const DofObject * d,
157  unsigned int sysnum = libMesh::invalid_uint)
158 {
159  if (d)
160  {
161  const unsigned int n_sys = d->n_systems();
162 
163  std::vector<unsigned int> n_vars (n_sys, 0);
164  for (unsigned int s = 0; s != n_sys; ++s)
165  if (sysnum == s ||
166  sysnum == libMesh::invalid_uint)
167  n_vars[s] = d->n_vars(s);
168 
169  const unsigned int tot_n_vars =
170  std::accumulate(n_vars.begin(), n_vars.end(), 0);
171 
172  std::vector<unsigned int> n_comp (tot_n_vars, 0);
173  std::vector<dof_id_type> first_dof (tot_n_vars, 0);
174 
175  for (unsigned int s = 0, i=0; s != n_sys; ++s)
176  {
177  if (sysnum != s &&
178  sysnum != libMesh::invalid_uint)
179  continue;
180 
181  for (unsigned int v = 0; v != n_vars[s]; ++v, ++i)
182  {
183  n_comp[i] = d->n_comp(s,v);
184  first_dof[i] = n_comp[i] ? d->dof_number(s,v,0) : DofObject::invalid_id;
185  }
186  }
187 
188  libmesh_assert(communicator.semiverify(&n_sys));
189  libmesh_assert(communicator.semiverify(&n_vars));
190  libmesh_assert(communicator.semiverify(&n_comp));
191  libmesh_assert(communicator.semiverify(&first_dof));
192  }
193  else
194  {
195  const unsigned int * p_ui = nullptr;
196  const std::vector<unsigned int> * p_vui = nullptr;
197  const std::vector<dof_id_type> * p_vdid = nullptr;
198 
199  libmesh_assert(communicator.semiverify(p_ui));
200  libmesh_assert(communicator.semiverify(p_vui));
201  libmesh_assert(communicator.semiverify(p_vui));
202  libmesh_assert(communicator.semiverify(p_vdid));
203  }
204 }
205 
206 
207 
208 #ifdef LIBMESH_ENABLE_UNIQUE_ID
209 void assert_dofobj_unique_id(const Parallel::Communicator & comm,
210  const DofObject * d,
211  const std::unordered_set<unique_id_type> & unique_ids)
212 {
213  // Duplicating some semiverify code here so we can reuse
214  // tempmin,tempmax afterward
215 
216  unique_id_type tempmin, tempmax;
217  if (d)
218  {
219  tempmin = tempmax = d->unique_id();
220  }
221  else
222  {
225  }
226  comm.min(tempmin);
227  comm.max(tempmax);
228  bool invalid = d && ((d->unique_id() != tempmin) ||
229  (d->unique_id() != tempmax));
230  comm.max(invalid);
231 
232  // First verify that everything is in sync
233  libmesh_assert(!invalid);
234 
235  // Then verify that any remote id doesn't duplicate a local one.
236  if (!d && tempmin == tempmax)
237  libmesh_assert(!unique_ids.count(tempmin));
238 }
239 #endif // LIBMESH_ENABLE_UNIQUE_ID
240 #endif // DEBUG
241 
242 void find_nodal_neighbors_helper(const dof_id_type global_id,
243  const std::vector<const Elem *> & node_to_elem_vec,
244  std::vector<const Node *> & neighbors)
245 {
246  // We'll construct a std::set<const Node *> for more efficient
247  // searching while finding the nodal neighbors, and return it to the
248  // user in a std::vector.
249  std::set<const Node *> neighbor_set;
250 
251  // Look through the elements that contain this node
252  // find the local node id... then find the side that
253  // node lives on in the element
254  // next, look for the _other_ node on that side
255  // That other node is a "nodal_neighbor"... save it
256  for (const auto & elem : node_to_elem_vec)
257  {
258  // We only care about active elements...
259  if (elem->active())
260  {
261  // Which local node number is global_id?
262  unsigned local_node_number = elem->local_node(global_id);
263 
264  // Make sure it was found
265  libmesh_assert_not_equal_to(local_node_number, libMesh::invalid_uint);
266 
267  const unsigned short n_edges = elem->n_edges();
268 
269  // If this element has no edges, the edge-based algorithm below doesn't make sense.
270  if (!n_edges)
271  {
272  switch (elem->type())
273  {
274  case EDGE2:
275  {
276  switch (local_node_number)
277  {
278  case 0:
279  // The other node is a nodal neighbor
280  neighbor_set.insert(elem->node_ptr(1));
281  break;
282 
283  case 1:
284  // The other node is a nodal neighbor
285  neighbor_set.insert(elem->node_ptr(0));
286  break;
287 
288  default:
289  libmesh_error_msg("Invalid local node number: " << local_node_number << " found." << std::endl);
290  }
291  break;
292  }
293 
294  case EDGE3:
295  {
296  switch (local_node_number)
297  {
298  // The outside nodes have node 2 as a neighbor
299  case 0:
300  case 1:
301  neighbor_set.insert(elem->node_ptr(2));
302  break;
303 
304  // The middle node has the outer nodes as neighbors
305  case 2:
306  neighbor_set.insert(elem->node_ptr(0));
307  neighbor_set.insert(elem->node_ptr(1));
308  break;
309 
310  default:
311  libmesh_error_msg("Invalid local node number: " << local_node_number << " found." << std::endl);
312  }
313  break;
314  }
315 
316  case EDGE4:
317  {
318  switch (local_node_number)
319  {
320  case 0:
321  // The left-middle node is a nodal neighbor
322  neighbor_set.insert(elem->node_ptr(2));
323  break;
324 
325  case 1:
326  // The right-middle node is a nodal neighbor
327  neighbor_set.insert(elem->node_ptr(3));
328  break;
329 
330  // The left-middle node
331  case 2:
332  neighbor_set.insert(elem->node_ptr(0));
333  neighbor_set.insert(elem->node_ptr(3));
334  break;
335 
336  // The right-middle node
337  case 3:
338  neighbor_set.insert(elem->node_ptr(1));
339  neighbor_set.insert(elem->node_ptr(2));
340  break;
341 
342  default:
343  libmesh_error_msg("Invalid local node number: " << local_node_number << " found." << std::endl);
344  }
345  break;
346  }
347 
348  default:
349  libmesh_error_msg("Unrecognized ElemType: " << Utility::enum_to_string(elem->type()) << std::endl);
350  }
351  }
352 
353  const auto elem_order = Elem::type_to_default_order_map[elem->type()];
354 
355  // Index of the current edge
356  unsigned current_edge = 0;
357 
358  const unsigned short n_nodes = elem->n_nodes();
359 
360  while (current_edge < n_edges)
361  {
362  // Find the edge the node is on
363  bool found_edge = false;
364  for (; current_edge<n_edges; ++current_edge)
365  if (elem->is_node_on_edge(local_node_number, current_edge))
366  {
367  found_edge = true;
368  break;
369  }
370 
371  // Did we find one?
372  if (found_edge)
373  {
374  const Node * node_to_save = nullptr;
375 
376  // Find another node in this element on this edge
377  for (unsigned other_node_this_edge = 0; other_node_this_edge != n_nodes; other_node_this_edge++)
378  {
379  const bool both_vertices = elem->is_vertex(local_node_number) &&
380  elem->is_vertex(other_node_this_edge);
381  if ( elem->is_node_on_edge(other_node_this_edge, current_edge) && // On the current edge
382  elem->node_id(other_node_this_edge) != global_id && // But not the original node
383  // vertex nodes on the same edge of higher order elements are not nodal neighbors
384  (elem_order == 1 || !both_vertices))
385  {
386  // We've found a nodal neighbor! Save a pointer to it..
387  node_to_save = elem->node_ptr(other_node_this_edge);
388 
389  // Make sure we found something
390  libmesh_assert(node_to_save != nullptr);
391 
392  neighbor_set.insert(node_to_save);
393  }
394  }
395  }
396 
397  // Keep looking for edges, node may be on more than one edge
398  current_edge++;
399  }
400  } // if (elem->active())
401  } // for
402 
403  // Assign the entries from the set to the vector. Note: this
404  // replaces any existing contents in neighbors and modifies its size
405  // accordingly.
406  neighbors.assign(neighbor_set.begin(), neighbor_set.end());
407 }
408 
409 }
410 
411 
412 namespace libMesh
413 {
414 
415 // ------------------------------------------------------------
416 // MeshTools functions
417 
418 namespace MeshTools
419 {
420 
422 {
423  if (!mesh.is_serial())
424  {
425  libmesh_parallel_only(mesh.comm());
427  mesh.comm().sum(weight);
428  dof_id_type unpartitioned_weight =
430  return weight + unpartitioned_weight;
431  }
432 
433  SumElemWeight sew;
434 
435  Threads::parallel_reduce (ConstElemRange (mesh.elements_begin(),
436  mesh.elements_end()),
437  sew);
438  return sew.weight();
439 
440 }
441 
442 
443 
445 {
446  SumElemWeight sew;
447 
448  Threads::parallel_reduce (ConstElemRange (mesh.pid_elements_begin(pid),
449  mesh.pid_elements_end(pid)),
450  sew);
451  return sew.weight();
452 }
453 
454 
455 
457  std::vector<std::vector<dof_id_type>> & nodes_to_elem_map)
458 {
459  // A vector indexed over all nodes is too inefficient to use for a
460  // distributed mesh. Use the unordered_map API instead.
461  if (!mesh.is_serial())
462  libmesh_deprecated();
463 
464  nodes_to_elem_map.resize (mesh.max_node_id());
465 
466  for (const auto & elem : mesh.element_ptr_range())
467  for (auto & node : elem->node_ref_range())
468  {
469  libmesh_assert_less (node.id(), nodes_to_elem_map.size());
470  libmesh_assert_less (elem->id(), mesh.n_elem());
471 
472  nodes_to_elem_map[node.id()].push_back(elem->id());
473  }
474 }
475 
476 
477 
479  std::vector<std::vector<const Elem *>> & nodes_to_elem_map)
480 {
481  // A vector indexed over all nodes is too inefficient to use for a
482  // distributed mesh. Use the unordered_map API instead.
483  if (!mesh.is_serial())
484  libmesh_deprecated();
485 
486  nodes_to_elem_map.resize (mesh.max_node_id());
487 
488  for (const auto & elem : mesh.element_ptr_range())
489  for (auto & node : elem->node_ref_range())
490  {
491  libmesh_assert_less (node.id(), nodes_to_elem_map.size());
492 
493  nodes_to_elem_map[node.id()].push_back(elem);
494  }
495 }
496 
497 
498 
500  std::unordered_map<dof_id_type, std::vector<dof_id_type>> & nodes_to_elem_map)
501 {
502  nodes_to_elem_map.clear();
503 
504  for (const auto & elem : mesh.element_ptr_range())
505  for (auto & node : elem->node_ref_range())
506  nodes_to_elem_map[node.id()].push_back(elem->id());
507 }
508 
509 
510 
512  std::unordered_map<dof_id_type, std::vector<const Elem *>> & nodes_to_elem_map)
513 {
514  nodes_to_elem_map.clear();
515 
516  for (const auto & elem : mesh.element_ptr_range())
517  for (auto & node : elem->node_ref_range())
518  nodes_to_elem_map[node.id()].push_back(elem);
519 }
520 
521 
522 
523 std::unordered_set<dof_id_type>
525 {
526  std::unordered_set<dof_id_type> boundary_nodes;
527 
528  // Loop over elements, find those on boundary, and
529  // mark them as true in on_boundary.
530  for (const auto & elem : mesh.active_element_ptr_range())
531  for (auto s : elem->side_index_range())
532  if (elem->neighbor_ptr(s) == nullptr) // on the boundary
533  {
534  auto nodes_on_side = elem->nodes_on_side(s);
535 
536  for (auto & local_id : nodes_on_side)
537  boundary_nodes.insert(elem->node_ptr(local_id)->id());
538  }
539 
540  return boundary_nodes;
541 }
542 
543 std::unordered_set<dof_id_type>
545 {
546  std::unordered_set<dof_id_type> block_boundary_nodes;
547 
548  // Loop over elements, find those on boundary, and
549  // mark them as true in on_boundary.
550  for (const auto & elem : mesh.active_element_ptr_range())
551  for (auto s : elem->side_index_range())
552  if (elem->neighbor_ptr(s) && (elem->neighbor_ptr(s)->subdomain_id() != elem->subdomain_id()))
553  {
554  auto nodes_on_side = elem->nodes_on_side(s);
555 
556  for (auto & local_id : nodes_on_side)
557  block_boundary_nodes.insert(elem->node_ptr(local_id)->id());
558  }
559 
560  return block_boundary_nodes;
561 }
562 
563 
564 
567 {
568  // This function must be run on all processors at once
569  libmesh_parallel_only(mesh.comm());
570 
571  FindBBox find_bbox;
572 
573  // Start with any unpartitioned elements we know about locally
575  mesh.pid_elements_end(DofObject::invalid_processor_id)),
576  find_bbox);
577 
578  // And combine with our local elements
579  find_bbox.bbox().union_with(create_local_bounding_box(mesh));
580 
581  // Compare the bounding boxes across processors
582  mesh.comm().min(find_bbox.min());
583  mesh.comm().max(find_bbox.max());
584 
585  return find_bbox.bbox();
586 }
587 
588 
589 
592 {
593  // This function must be run on all processors at once
594  libmesh_parallel_only(mesh.comm());
595 
596  FindBBox find_bbox;
597 
598  // Start with any unpartitioned nodes we know about locally
600  mesh.pid_nodes_end(DofObject::invalid_processor_id)),
601  find_bbox);
602 
603  // Add our local nodes
604  Threads::parallel_reduce (ConstNodeRange (mesh.local_nodes_begin(),
605  mesh.local_nodes_end()),
606  find_bbox);
607 
608  // Compare the bounding boxes across processors
609  mesh.comm().min(find_bbox.min());
610  mesh.comm().max(find_bbox.max());
611 
612  return find_bbox.bbox();
613 }
614 
615 
616 
617 Sphere
619 {
621 
622  const Real diag = (bbox.second - bbox.first).norm();
623  const Point cent = (bbox.second + bbox.first)/2;
624 
625  return Sphere (cent, .5*diag);
626 }
627 
628 
629 
632 {
633  FindBBox find_bbox;
634 
635  Threads::parallel_reduce (ConstElemRange (mesh.local_elements_begin(),
636  mesh.local_elements_end()),
637  find_bbox);
638 
639  return find_bbox.bbox();
640 }
641 
642 
643 
646  const processor_id_type pid)
647 {
648  // This can only be run in parallel, with consistent arguments.
649  libmesh_parallel_only(mesh.comm());
650  libmesh_assert(mesh.comm().verify(pid));
651 
652  libmesh_assert_less (pid, mesh.n_processors());
653 
654  FindBBox find_bbox;
655 
656  Threads::parallel_reduce (ConstElemRange (mesh.pid_elements_begin(pid),
657  mesh.pid_elements_end(pid)),
658  find_bbox);
659 
660  // Compare the bounding boxes across processors
661  mesh.comm().min(find_bbox.min());
662  mesh.comm().max(find_bbox.max());
663 
664  return find_bbox.bbox();
665 }
666 
667 
668 
669 Sphere
671  const processor_id_type pid)
672 {
673  libMesh::BoundingBox bbox =
675 
676  const Real diag = (bbox.second - bbox.first).norm();
677  const Point cent = (bbox.second + bbox.first)/2;
678 
679  return Sphere (cent, .5*diag);
680 }
681 
682 
683 
686  const subdomain_id_type sid)
687 {
688  // This can only be run in parallel, with consistent arguments.
689  libmesh_parallel_only(mesh.comm());
690  libmesh_assert(mesh.comm().verify(sid));
691 
692  FindBBox find_bbox;
693 
695  (ConstElemRange (mesh.active_local_subdomain_elements_begin(sid),
696  mesh.active_local_subdomain_elements_end(sid)),
697  find_bbox);
698 
699  // Compare the bounding boxes across processors
700  mesh.comm().min(find_bbox.min());
701  mesh.comm().max(find_bbox.max());
702 
703  return find_bbox.bbox();
704 }
705 
706 
707 
708 Sphere
710  const subdomain_id_type sid)
711 {
712  libMesh::BoundingBox bbox =
714 
715  const Real diag = (bbox.second - bbox.first).norm();
716  const Point cent = (bbox.second + bbox.first)/2;
717 
718  return Sphere (cent, .5*diag);
719 }
720 
721 
722 
723 void elem_types (const MeshBase & mesh,
724  std::vector<ElemType> & et)
725 {
726  // Loop over the the elements. If the current element type isn't in
727  // the vector, insert it.
728  for (const auto & elem : mesh.element_ptr_range())
729  if (!std::count(et.begin(), et.end(), elem->type()))
730  et.push_back(elem->type());
731 }
732 
733 
734 
736  const ElemType type)
737 {
738  return static_cast<dof_id_type>(std::distance(mesh.type_elements_begin(type),
739  mesh.type_elements_end (type)));
740 }
741 
742 
743 
745  const ElemType type)
746 {
747  return static_cast<dof_id_type>(std::distance(mesh.active_type_elements_begin(type),
748  mesh.active_type_elements_end (type)));
749 }
750 
752  const ElemType type,
753  const unsigned int level)
754 {
755  dof_id_type cnt = 0;
756 
757  // iterate over the elements of the specified type
758  for (const auto & elem : as_range(mesh.type_elements_begin(type),
759  mesh.type_elements_end(type)))
760  if ((elem->level() == level) && !elem->subactive())
761  cnt++;
762 
763  return cnt;
764 }
765 
766 
767 unsigned int n_active_local_levels(const MeshBase & mesh)
768 {
769  struct LevelCounter {
770  unsigned int nl;
771 
772  LevelCounter () : nl(0) {}
773 
774  LevelCounter (LevelCounter &, Threads::split) :
775  nl(0) {}
776 
777  void operator()(const ConstElemRange & range) {
778  for (const Elem * elem : range)
779  nl = std::max(elem->level() + 1, nl);
780  }
781 
782  void join(const LevelCounter & other) {
783  nl = std::max(nl, other.nl);
784  }
785  };
786 
787  LevelCounter counter;
788 
790 
791  return counter.nl;
792 }
793 
794 
795 
796 unsigned int n_active_levels(const MeshBase & mesh)
797 {
798  libmesh_parallel_only(mesh.comm());
799 
800  unsigned int nl = n_active_local_levels(mesh);
801 
802  for (const auto & elem : as_range(mesh.unpartitioned_elements_begin(),
803  mesh.unpartitioned_elements_end()))
804  if (elem->active())
805  nl = std::max(elem->level() + 1, nl);
806 
807  mesh.comm().max(nl);
808  return nl;
809 }
810 
811 
812 
813 unsigned int n_local_levels(const MeshBase & mesh)
814 {
815  unsigned int nl = 0;
816 
817  for (const auto & elem : as_range(mesh.local_elements_begin(),
818  mesh.local_elements_end()))
819  nl = std::max(elem->level() + 1, nl);
820 
821  return nl;
822 }
823 
824 
825 
826 unsigned int n_levels(const MeshBase & mesh)
827 {
828  libmesh_parallel_only(mesh.comm());
829 
830  unsigned int nl = n_local_levels(mesh);
831 
832  for (const auto & elem : as_range(mesh.unpartitioned_elements_begin(),
833  mesh.unpartitioned_elements_end()))
834  nl = std::max(elem->level() + 1, nl);
835 
836  mesh.comm().max(nl);
837 
838  // n_levels() is only valid and should only be called in cases where
839  // the mesh is validly distributed (or serialized). Let's run an
840  // expensive test in debug mode to make sure this is such a case.
841 #ifdef DEBUG
842  const unsigned int paranoid_nl = paranoid_n_levels(mesh);
843  libmesh_assert_equal_to(nl, paranoid_nl);
844 #endif
845  return nl;
846 }
847 
848 
849 
850 unsigned int paranoid_n_levels(const MeshBase & mesh)
851 {
852  libmesh_parallel_only(mesh.comm());
853 
854  unsigned int nl = 0;
855  for (const auto & elem : mesh.element_ptr_range())
856  nl = std::max(elem->level() + 1, nl);
857 
858  mesh.comm().max(nl);
859  return nl;
860 }
861 
862 
863 
865  Real constraint_tol)
866 {
867  LOG_SCOPE("n_connected_components()", "MeshTools");
868 
869  // Yes, I'm being lazy. This is for mesh analysis before a
870  // simulation, not anything going in any loops.
871  if (!mesh.is_serial_on_zero())
872  libmesh_not_implemented();
873 
874  dof_id_type n_components = 0;
875 
876  if (mesh.processor_id())
877  {
878  mesh.comm().broadcast(n_components);
879  return n_components;
880  }
881 
882  // All nodes in a set here are connected (at least indirectly) to
883  // all other nodes in the same set, but have not yet been discovered
884  // to be connected to nodes in other sets.
885  //
886  // Using an unordered_set of ids rather than a set of pointers seems
887  // to be roughly 150% faster?
888  // typedef const Node * node_entry_type
889  typedef dof_id_type node_entry_type;
890  std::vector<std::unordered_set<node_entry_type>> components;
891 
892  // With a typical mesh with few components and somewhat-contiguous
893  // ordering, vector performance should be fine. With a mesh with
894  // many components or completely scrambled ordering, performance
895  // can be a disaster.
896  auto find_component = [&components](node_entry_type n) {
897  for (auto & c: components)
898  if (c.find(n) != c.end())
899  return &c;
900 
901  return (std::unordered_set<node_entry_type> *)(nullptr);
902  };
903 
904  auto add_to_component =
905  [&find_component]
906  (std::unordered_set<node_entry_type> & component, node_entry_type n) {
907  // We may already be in the desired component
908  if (component.find(n) != component.end())
909  return;
910 
911  auto current_component = find_component(n);
912 
913  // Didn't we *just* check this?
914  libmesh_assert (&component != current_component);
915 
916  // If we're unknown, we should be in the desired component
917  if (!current_component)
918  component.insert(n);
919 
920  // If we think we're in another component, it should actually be
921  // part of the desired component
922  else
923  {
924  // Merge the component likely to be smaller into the one
925  // likely to be larger - this is orders of magnitude faster
926  // than the other way around!
927  current_component->merge(component);
928  current_component->swap(component);
929  libmesh_assert(current_component->empty());
930  }
931  };
932 
933  auto & constraint_rows = mesh.get_constraint_rows();
934 
935  for (const auto & elem : mesh.element_ptr_range())
936  {
937  // const node_entry_type first_node = elem->node_ptr(0);
938  const node_entry_type first_node = elem->node_id(0);
939 
940  auto component = find_component(first_node);
941 
942  // If we didn't find one, make a new one, reusing an existing
943  // slot if possible or growing our vector if necessary
944  if (!component)
945  for (auto & c: components)
946  if (c.empty())
947  component = &c;
948 
949  if (!component)
950  component = &components.emplace_back();
951 
952  for (const Node & node : elem->node_ref_range())
953  {
954  // const node_entry_type n = &node;
955  const node_entry_type n = node.id();
956  add_to_component(*component, n);
957 
958  auto it = constraint_rows.find(&node);
959  if (it == constraint_rows.end())
960  continue;
961 
962  for (const auto & [pr, val] : it->second)
963  {
964  // Ignore too-trivial constraint coefficients if
965  // we get a non-default-0 constraint_tol
966  if (std::abs(val) < constraint_tol)
967  continue;
968 
969  const Elem * spline_elem = pr.first;
970  libmesh_assert(spline_elem == mesh.elem_ptr(spline_elem->id()));
971 
972  const Node * spline_node =
973  spline_elem->node_ptr(pr.second);
974 
975  // add_to_component(*component, spline_node);
976  add_to_component(*component, spline_node->id());
977  }
978  }
979  }
980 
981  for (auto & component : components)
982  if (!component.empty())
983  ++n_components;
984 
985  // We calculated this on proc 0; now let everyone else know too
986  mesh.comm().broadcast(n_components);
987 
988  return n_components;
989 }
990 
991 
992 
994  std::set<dof_id_type> & not_subactive_node_ids)
995 {
996  for (const auto & elem : mesh.element_ptr_range())
997  if (!elem->subactive())
998  for (auto & n : elem->node_ref_range())
999  not_subactive_node_ids.insert(n.id());
1000 }
1001 
1002 
1003 
1006 {
1007  return cast_int<dof_id_type>(std::distance(begin, end));
1008 }
1009 
1010 
1011 
1013  const MeshBase::const_node_iterator & end)
1014 {
1015  return cast_int<dof_id_type>(std::distance(begin, end));
1016 }
1017 
1018 
1019 
1021  unsigned int dim)
1022 {
1023  libmesh_parallel_only(mesh.comm());
1024 
1025  if (dim == libMesh::invalid_uint)
1026  dim = mesh.mesh_dimension();
1027 
1028  Real vol = 0;
1029 
1030  // first my local elements
1031  for (const auto & elem : as_range(mesh.local_elements_begin(),
1032  mesh.local_elements_end()))
1033  if (elem->dim() == dim)
1034  vol += elem->volume();
1035 
1036  // then count any unpartitioned objects, once
1037  if (mesh.processor_id() == 0)
1038  for (const auto & elem : as_range(mesh.unpartitioned_elements_begin(),
1039  mesh.unpartitioned_elements_end()))
1040  if (elem->dim() == dim)
1041  vol += elem->volume();
1042 
1043  mesh.comm().sum(vol);
1044  return vol;
1045 }
1046 
1047 
1048 
1049 unsigned int n_p_levels (const MeshBase & mesh)
1050 {
1051  libmesh_parallel_only(mesh.comm());
1052 
1053  unsigned int max_p_level = 0;
1054 
1055  // first my local elements
1056  for (const auto & elem : as_range(mesh.local_elements_begin(),
1057  mesh.local_elements_end()))
1058  max_p_level = std::max(elem->p_level(), max_p_level);
1059 
1060  // then any unpartitioned objects
1061  for (const auto & elem : as_range(mesh.unpartitioned_elements_begin(),
1062  mesh.unpartitioned_elements_end()))
1063  max_p_level = std::max(elem->p_level(), max_p_level);
1064 
1065  mesh.comm().max(max_p_level);
1066  return max_p_level + 1;
1067 }
1068 
1069 
1070 
1072  const Node & node,
1073  const std::vector<std::vector<const Elem *>> & nodes_to_elem_map,
1074  std::vector<const Node *> & neighbors)
1075 {
1076  find_nodal_neighbors_helper(node.id(), nodes_to_elem_map[node.id()],
1077  neighbors);
1078 }
1079 
1080 
1081 
1083  const Node & node,
1084  const std::unordered_map<dof_id_type, std::vector<const Elem *>> & nodes_to_elem_map,
1085  std::vector<const Node *> & neighbors)
1086 {
1087  const std::vector<const Elem *> node_to_elem_vec =
1088  libmesh_map_find(nodes_to_elem_map, node.id());
1089  find_nodal_neighbors_helper(node.id(), node_to_elem_vec, neighbors);
1090 }
1091 
1093  const MeshBase & mesh,
1094  const Node & node,
1095  const std::unordered_map<dof_id_type, std::vector<const Elem *>> & nodes_to_elem_map,
1096  std::vector<const Node *> & neighbors)
1097 {
1098  // Find all the nodal neighbors... that is the nodes directly connected
1099  // to this node through one edge.
1100  find_nodal_neighbors(mesh, node, nodes_to_elem_map, neighbors);
1101 
1102  // If no neighbors are found, use all nodes on the containing side as
1103  // neighbors.
1104  if (!neighbors.size())
1105  {
1106  // Grab the element containing node
1107  const auto * elem = libmesh_map_find(nodes_to_elem_map, node.id()).front();
1108  // Find the element side containing node
1109  for (const auto &side : elem->side_index_range())
1110  {
1111  const auto &nodes_on_side = elem->nodes_on_side(side);
1112  const auto it =
1113  std::find_if(nodes_on_side.begin(), nodes_on_side.end(), [&](auto local_node_id) {
1114  return elem->node_id(local_node_id) == node.id();
1115  });
1116 
1117  if (it != nodes_on_side.end())
1118  {
1119  for (const auto &local_node_id : nodes_on_side)
1120  // No need to add node itself as a neighbor
1121  if (const auto *node_ptr = elem->node_ptr(local_node_id);
1122  *node_ptr != node)
1123  neighbors.push_back(node_ptr);
1124  break;
1125  }
1126  }
1127  }
1128  libmesh_assert(neighbors.size());
1129 }
1130 
1131 
1132 
1134  std::map<dof_id_type, std::vector<dof_id_type>> & hanging_nodes)
1135 {
1136  // Loop through all the elements
1137  for (auto & elem : mesh.active_local_element_ptr_range())
1138  if (elem->type() == QUAD4)
1139  for (auto s : elem->side_index_range())
1140  {
1141  // Loop over the sides looking for sides that have hanging nodes
1142  // This code is inspired by compute_proj_constraints()
1143  const Elem * neigh = elem->neighbor_ptr(s);
1144 
1145  // If not a boundary side
1146  if (neigh != nullptr)
1147  {
1148  // Is there a coarser element next to this one?
1149  if (neigh->level() < elem->level())
1150  {
1151  const Elem * ancestor = elem;
1152  while (neigh->level() < ancestor->level())
1153  ancestor = ancestor->parent();
1154  unsigned int s_neigh = neigh->which_neighbor_am_i(ancestor);
1155  libmesh_assert_less (s_neigh, neigh->n_neighbors());
1156 
1157  // Couple of helper uints...
1158  unsigned int local_node1=0;
1159  unsigned int local_node2=0;
1160 
1161  bool found_in_neighbor = false;
1162 
1163  // Find the two vertices that make up this side
1164  while (!elem->is_node_on_side(local_node1++,s)) { }
1165  local_node1--;
1166 
1167  // Start looking for the second one with the next node
1168  local_node2=local_node1+1;
1169 
1170  // Find the other one
1171  while (!elem->is_node_on_side(local_node2++,s)) { }
1172  local_node2--;
1173 
1174  //Pull out their global ids:
1175  dof_id_type node1 = elem->node_id(local_node1);
1176  dof_id_type node2 = elem->node_id(local_node2);
1177 
1178  // Now find which node is present in the neighbor
1179  // FIXME This assumes a level one rule!
1180  // The _other_ one is the hanging node
1181 
1182  // First look for the first one
1183  // FIXME could be streamlined a bit
1184  for (unsigned int n=0;n<neigh->n_sides();n++)
1185  if (neigh->node_id(n) == node1)
1186  found_in_neighbor=true;
1187 
1188  dof_id_type hanging_node=0;
1189 
1190  if (!found_in_neighbor)
1191  hanging_node=node1;
1192  else // If it wasn't node1 then it must be node2!
1193  hanging_node=node2;
1194 
1195  // Reset for reuse
1196  local_node1=0;
1197 
1198  // Find the first node that makes up the side in the neighbor (these should be the parent nodes)
1199  while (!neigh->is_node_on_side(local_node1++,s_neigh)) { }
1200  local_node1--;
1201 
1202  local_node2=local_node1+1;
1203 
1204  // Find the second node...
1205  while (!neigh->is_node_on_side(local_node2++,s_neigh)) { }
1206  local_node2--;
1207 
1208  // Save them if we haven't already found the parents for this one
1209  if (hanging_nodes[hanging_node].size()<2)
1210  {
1211  hanging_nodes[hanging_node].push_back(neigh->node_id(local_node1));
1212  hanging_nodes[hanging_node].push_back(neigh->node_id(local_node2));
1213  }
1214  }
1215  }
1216  }
1217 }
1218 
1219 
1220 
1222 {
1223  std::vector<Elem *> nodeelem_to_delete;
1224 
1225  for (auto & elem : mesh.element_ptr_range())
1226  if (elem->type() == NODEELEM &&
1227  elem->mapping_type() == RATIONAL_BERNSTEIN_MAP)
1228  nodeelem_to_delete.push_back(elem);
1229 
1230  auto & constraint_rows = mesh.get_constraint_rows();
1231 
1232  // All our constraint_rows ought to be for spline constraints we're
1233  // about to get rid of.
1234 #ifndef NDEBUG
1235  for (auto & node_row : constraint_rows)
1236  for (auto pr : node_row.second)
1237  {
1238  const Elem * elem = pr.first.first;
1239  libmesh_assert(elem->type() == NODEELEM);
1241  }
1242 #endif
1243 
1244  constraint_rows.clear();
1245 
1246  for (Elem * elem : nodeelem_to_delete)
1247  {
1248  Node * node = elem->node_ptr(0);
1249  mesh.delete_elem(elem);
1250  mesh.delete_node(node);
1251  }
1252 }
1253 
1254 
1255 
1257 {
1258  LOG_SCOPE("valid_is_prepared()", "MeshTools");
1259 
1260  if (!mesh.is_prepared())
1261  return true;
1262 
1263  std::unique_ptr<MeshBase> mesh_clone = mesh.clone();
1264 
1265  // Try preparing (without allowing repartitioning or renumbering, to
1266  // avoid false assertion failures)
1267  bool old_allow_renumbering = mesh_clone->allow_renumbering();
1268  mesh_clone->allow_renumbering(false);
1269 
1270  bool old_skip_partitioning = mesh_clone->skip_partitioning();
1271  mesh_clone->skip_partitioning(true);
1272 
1273  bool old_allow_remote_element_removal = mesh_clone->allow_remote_element_removal();
1274  mesh_clone->allow_remote_element_removal(false);
1275 
1276  // Call prepare_for_use() on the clone
1277  mesh_clone->prepare_for_use();
1278 
1279  // Restore original flag values
1280  mesh_clone->allow_renumbering(old_allow_renumbering);
1281  mesh_clone->skip_partitioning(old_skip_partitioning);
1282  mesh_clone->allow_remote_element_removal(old_allow_remote_element_removal);
1283 
1284  // Check whether the original and clone compare equal
1285  return (mesh == *mesh_clone);
1286 }
1287 
1288 
1289 
1290 #ifndef NDEBUG
1291 
1293 {
1294  LOG_SCOPE("libmesh_assert_equal_n_systems()", "MeshTools");
1295 
1296  unsigned int n_sys = libMesh::invalid_uint;
1297 
1298  for (const auto & elem : mesh.element_ptr_range())
1299  {
1300  if (n_sys == libMesh::invalid_uint)
1301  n_sys = elem->n_systems();
1302  else
1303  libmesh_assert_equal_to (elem->n_systems(), n_sys);
1304  }
1305 
1306  for (const auto & node : mesh.node_ptr_range())
1307  {
1308  if (n_sys == libMesh::invalid_uint)
1309  n_sys = node->n_systems();
1310  else
1311  libmesh_assert_equal_to (node->n_systems(), n_sys);
1312  }
1313 }
1314 
1315 
1316 
1317 #ifdef LIBMESH_ENABLE_AMR
1319 {
1320  LOG_SCOPE("libmesh_assert_old_dof_objects()", "MeshTools");
1321 
1322  for (const auto & elem : mesh.element_ptr_range())
1323  {
1324  if (elem->refinement_flag() == Elem::JUST_REFINED ||
1325  elem->refinement_flag() == Elem::INACTIVE)
1326  continue;
1327 
1328  if (elem->has_dofs())
1329  libmesh_assert(elem->get_old_dof_object());
1330 
1331  for (auto & node : elem->node_ref_range())
1332  if (node.has_dofs())
1333  libmesh_assert(node.get_old_dof_object());
1334  }
1335 }
1336 #else
1337 void libmesh_assert_old_dof_objects (const MeshBase &) {}
1338 #endif // LIBMESH_ENABLE_AMR
1339 
1340 
1341 
1343 {
1344  LOG_SCOPE("libmesh_assert_valid_node_pointers()", "MeshTools");
1345 
1346  // Here we specifically do not want "auto &" because we need to
1347  // reseat the (temporary) pointer variable in the loop below,
1348  // without modifying the original.
1349  for (const Elem * elem : mesh.element_ptr_range())
1350  {
1351  libmesh_assert (elem);
1352  while (elem)
1353  {
1354  elem->libmesh_assert_valid_node_pointers();
1355  for (auto n : elem->neighbor_ptr_range())
1356  if (n && n != remote_elem)
1357  n->libmesh_assert_valid_node_pointers();
1358 
1359  libmesh_assert_not_equal_to (elem->parent(), remote_elem);
1360  elem = elem->parent();
1361  }
1362  }
1363 }
1364 
1365 
1366 
1368 {
1369  LOG_SCOPE("libmesh_assert_valid_remote_elems()", "MeshTools");
1370 
1371  for (const auto & elem : as_range(mesh.local_elements_begin(),
1372  mesh.local_elements_end()))
1373  {
1374  libmesh_assert (elem);
1375 
1376  // We currently don't allow active_local_elements to have
1377  // remote_elem neighbors
1378  if (elem->active())
1379  for (auto n : elem->neighbor_ptr_range())
1380  libmesh_assert_not_equal_to (n, remote_elem);
1381 
1382 #ifdef LIBMESH_ENABLE_AMR
1383  const Elem * parent = elem->parent();
1384  if (parent)
1385  libmesh_assert_not_equal_to (parent, remote_elem);
1386 
1387  // We can only be strict about active elements' subactive
1388  // children
1389  if (elem->active() && elem->has_children())
1390  for (auto & child : elem->child_ref_range())
1391  libmesh_assert_not_equal_to (&child, remote_elem);
1392 #endif
1393  }
1394 }
1395 
1396 
1397 
1399 {
1400  LOG_SCOPE("libmesh_assert_valid_elem_ids()", "MeshTools");
1401 
1402  processor_id_type lastprocid = 0;
1403  dof_id_type lastelemid = 0;
1404 
1405  for (const auto & elem : mesh.active_element_ptr_range())
1406  {
1407  libmesh_assert (elem);
1408  processor_id_type elemprocid = elem->processor_id();
1409  dof_id_type elemid = elem->id();
1410 
1411  libmesh_assert_greater_equal (elemid, lastelemid);
1412  libmesh_assert_greater_equal (elemprocid, lastprocid);
1413 
1414  lastelemid = elemid;
1415  lastprocid = elemprocid;
1416  }
1417 }
1418 
1419 
1420 
1422 {
1423  LOG_SCOPE("libmesh_assert_valid_amr_elem_ids()", "MeshTools");
1424 
1425  for (const auto & elem : mesh.element_ptr_range())
1426  {
1427  libmesh_assert (elem);
1428 
1429  const Elem * parent = elem->parent();
1430 
1431  if (parent)
1432  {
1433  libmesh_assert_greater_equal (elem->id(), parent->id());
1434  libmesh_assert_greater_equal (elem->processor_id(), parent->processor_id());
1435  }
1436  }
1437 }
1438 
1439 
1440 
1442 {
1443  LOG_SCOPE("libmesh_assert_valid_amr_interior_parents()", "MeshTools");
1444 
1445  for (const auto & elem : mesh.element_ptr_range())
1446  {
1447  libmesh_assert (elem);
1448 
1449  // We can skip to the next element if we're full-dimension
1450  // and therefore don't have any interior parents
1451  if (elem->dim() >= LIBMESH_DIM)
1452  continue;
1453 
1454  const Elem * ip = elem->interior_parent();
1455 
1456  const Elem * parent = elem->parent();
1457 
1458  if (ip && (ip != remote_elem) && parent)
1459  {
1460  libmesh_assert_equal_to (ip->top_parent(),
1461  elem->top_parent()->interior_parent());
1462 
1463  if (ip->level() == elem->level())
1464  libmesh_assert_equal_to (ip->parent(),
1465  parent->interior_parent());
1466  else
1467  {
1468  libmesh_assert_less (ip->level(), elem->level());
1469  libmesh_assert_equal_to (ip, parent->interior_parent());
1470  }
1471  }
1472  }
1473 }
1474 
1475 
1476 
1477 void libmesh_assert_contiguous_dof_ids(const MeshBase & mesh, unsigned int sysnum)
1478 {
1479  LOG_SCOPE("libmesh_assert_contiguous_dof_ids()", "MeshTools");
1480 
1481  if (mesh.n_processors() == 1)
1482  return;
1483 
1484  libmesh_parallel_only(mesh.comm());
1485 
1486  dof_id_type min_dof_id = std::numeric_limits<dof_id_type>::max(),
1487  max_dof_id = std::numeric_limits<dof_id_type>::min();
1488 
1489  // Figure out what our local dof id range is
1490  for (const auto * node : mesh.local_node_ptr_range())
1491  {
1492  for (auto v : make_range(node->n_vars(sysnum)))
1493  for (auto c : make_range(node->n_comp(sysnum, v)))
1494  {
1495  dof_id_type id = node->dof_number(sysnum, v, c);
1496  min_dof_id = std::min (min_dof_id, id);
1497  max_dof_id = std::max (max_dof_id, id);
1498  }
1499  }
1500 
1501  // Make sure no other processors' ids are inside it
1502  for (const auto * node : mesh.node_ptr_range())
1503  {
1504  if (node->processor_id() == mesh.processor_id())
1505  continue;
1506  for (auto v : make_range(node->n_vars(sysnum)))
1507  for (auto c : make_range(node->n_comp(sysnum, v)))
1508  {
1509  dof_id_type id = node->dof_number(sysnum, v, c);
1510  libmesh_assert (id < min_dof_id ||
1511  id > max_dof_id);
1512  }
1513  }
1514 }
1515 
1516 
1517 
1518 template <>
1520 {
1521  LOG_SCOPE("libmesh_assert_topology_consistent_procids()", "MeshTools");
1522 
1523  // This parameter is not used when !LIBMESH_ENABLE_AMR
1525 
1526  // If we're adaptively refining, check processor ids for consistency
1527  // between parents and children.
1528 #ifdef LIBMESH_ENABLE_AMR
1529 
1530  // Ancestor elements we won't worry about, but subactive and active
1531  // elements ought to have parents with consistent processor ids
1532  for (const auto & elem : mesh.element_ptr_range())
1533  {
1534  libmesh_assert(elem);
1535 
1536  if (!elem->active() && !elem->subactive())
1537  continue;
1538 
1539  const Elem * parent = elem->parent();
1540 
1541  if (parent)
1542  {
1543  libmesh_assert(parent->has_children());
1544  processor_id_type parent_procid = parent->processor_id();
1545  bool matching_child_id = false;
1546  // If we've got a remote_elem then we don't know whether
1547  // it's responsible for the parent's processor id; all
1548  // we can do is assume it is and let its processor fail
1549  // an assert if there's something wrong.
1550  for (auto & child : parent->child_ref_range())
1551  if (&child == remote_elem ||
1552  child.processor_id() == parent_procid)
1553  matching_child_id = true;
1554  libmesh_assert(matching_child_id);
1555  }
1556  }
1557 #endif
1558 }
1559 
1560 
1561 
1562 template <>
1564 {
1565  LOG_SCOPE("libmesh_assert_topology_consistent_procids()", "MeshTools");
1566 
1567  if (mesh.n_processors() == 1)
1568  return;
1569 
1570  libmesh_parallel_only(mesh.comm());
1571 
1572  // We want this test to be valid even when called after nodes have
1573  // been added asynchronously but before they're renumbered.
1574  //
1575  // Plus, some code (looking at you, stitch_meshes) modifies
1576  // DofObject ids without keeping max_elem_id()/max_node_id()
1577  // consistent, but that's done in a safe way for performance
1578  // reasons, so we'll play along and just figure out new max ids
1579  // ourselves.
1580  dof_id_type parallel_max_node_id = 0;
1581  for (const auto & node : mesh.node_ptr_range())
1582  parallel_max_node_id = std::max<dof_id_type>(parallel_max_node_id,
1583  node->id()+1);
1584  mesh.comm().max(parallel_max_node_id);
1585 
1586 
1587  std::vector<bool> node_touched_by_me(parallel_max_node_id, false);
1588 
1589  for (const auto & elem : as_range(mesh.local_elements_begin(),
1590  mesh.local_elements_end()))
1591  {
1592  libmesh_assert (elem);
1593 
1594  for (auto & node : elem->node_ref_range())
1595  {
1596  dof_id_type nodeid = node.id();
1597  node_touched_by_me[nodeid] = true;
1598  }
1599  }
1600  std::vector<bool> node_touched_by_anyone(node_touched_by_me);
1601  mesh.comm().max(node_touched_by_anyone);
1602 
1603  for (const auto & node : mesh.local_node_ptr_range())
1604  {
1605  libmesh_assert(node);
1606  dof_id_type nodeid = node->id();
1607  libmesh_assert(!node_touched_by_anyone[nodeid] ||
1608  node_touched_by_me[nodeid]);
1609  }
1610 }
1611 
1612 
1613 
1615 {
1616  for (const auto & elem : mesh.active_element_ptr_range())
1617  for (auto & node : elem->node_ref_range())
1618  libmesh_assert_equal_to
1619  (node.processor_id(),
1620  node.choose_processor_id(node.processor_id(),
1621  elem->processor_id()));
1622 }
1623 
1624 
1625 
1626 #ifdef LIBMESH_ENABLE_AMR
1628 {
1629  LOG_SCOPE("libmesh_assert_valid_refinement_tree()", "MeshTools");
1630 
1631  for (const auto & elem : mesh.element_ptr_range())
1632  {
1633  libmesh_assert(elem);
1634  if (elem->has_children())
1635  for (auto & child : elem->child_ref_range())
1636  if (&child != remote_elem)
1637  libmesh_assert_equal_to (child.parent(), elem);
1638  if (elem->active())
1639  {
1640  libmesh_assert(!elem->ancestor());
1641  libmesh_assert(!elem->subactive());
1642  }
1643  else if (elem->ancestor())
1644  {
1645  libmesh_assert(!elem->subactive());
1646  }
1647  else
1648  libmesh_assert(elem->subactive());
1649 
1650  if (elem->p_refinement_flag() == Elem::JUST_REFINED)
1651  libmesh_assert_greater(elem->p_level(), 0);
1652  }
1653 }
1654 #else
1656 {
1657 }
1658 #endif // LIBMESH_ENABLE_AMR
1659 
1660 #endif // !NDEBUG
1661 
1662 
1663 
1664 #ifdef DEBUG
1665 
1667  const Elem * bad_elem)
1668 {
1669  for (const auto & elem : mesh.element_ptr_range())
1670  {
1671  libmesh_assert (elem);
1672  libmesh_assert_not_equal_to (elem->parent(), bad_elem);
1673  for (auto n : elem->neighbor_ptr_range())
1674  libmesh_assert_not_equal_to (n, bad_elem);
1675 
1676 #ifdef LIBMESH_ENABLE_AMR
1677  if (elem->has_children())
1678  for (auto & child : elem->child_ref_range())
1679  libmesh_assert_not_equal_to (&child, bad_elem);
1680 #endif
1681  }
1682 }
1683 
1684 
1686 {
1687  LOG_SCOPE("libmesh_assert_equal_points()", "MeshTools");
1688 
1689  dof_id_type pmax_node_id = mesh.max_node_id();
1690  mesh.comm().max(pmax_node_id);
1691 
1692  for (dof_id_type i=0; i != pmax_node_id; ++i)
1693  {
1694  const Point * p = mesh.query_node_ptr(i);
1695 
1697  }
1698 }
1699 
1700 
1702 {
1703  LOG_SCOPE("libmesh_assert_equal_connectivity()", "MeshTools");
1704 
1705  dof_id_type pmax_elem_id = mesh.max_elem_id();
1706  mesh.comm().max(pmax_elem_id);
1707 
1708  for (dof_id_type i=0; i != pmax_elem_id; ++i)
1709  {
1710  const Elem * e = mesh.query_elem_ptr(i);
1711 
1712  std::vector<dof_id_type> nodes;
1713  if (e)
1714  for (auto n : e->node_index_range())
1715  nodes.push_back(e->node_id(n));
1716 
1717  libmesh_assert(mesh.comm().semiverify(e ? &nodes : nullptr));
1718  }
1719 }
1720 
1721 
1723 {
1724  LOG_SCOPE("libmesh_assert_connected_nodes()", "MeshTools");
1725 
1726  std::set<const Node *> used_nodes;
1727 
1728  for (const auto & elem : mesh.element_ptr_range())
1729  {
1730  libmesh_assert (elem);
1731 
1732  for (auto & n : elem->node_ref_range())
1733  used_nodes.insert(&n);
1734  }
1735 
1736  for (const auto & node : mesh.node_ptr_range())
1737  {
1738  libmesh_assert(node);
1739  libmesh_assert(used_nodes.count(node));
1740  }
1741 }
1742 
1743 
1744 
1746 {
1747  libmesh_parallel_only(mesh.comm());
1748 
1749  const auto & constraint_rows = mesh.get_constraint_rows();
1750 
1751  bool have_constraint_rows = !constraint_rows.empty();
1752  mesh.comm().max(have_constraint_rows);
1753  if (!have_constraint_rows)
1754  return;
1755 
1756  for (auto & row : constraint_rows)
1757  {
1758  const Node * node = row.first;
1759  libmesh_assert(node == mesh.node_ptr(node->id()));
1760 
1761  for (auto & pr : row.second)
1762  {
1763  const Elem * spline_elem = pr.first.first;
1764  libmesh_assert(spline_elem == mesh.elem_ptr(spline_elem->id()));
1765  }
1766  }
1767 
1768  dof_id_type pmax_node_id = mesh.max_node_id();
1769  mesh.comm().max(pmax_node_id);
1770 
1771  for (dof_id_type i=0; i != pmax_node_id; ++i)
1772  {
1773  const Node * node = mesh.query_node_ptr(i);
1774 
1775  bool have_constraint = constraint_rows.count(node);
1776 
1777  const std::size_t my_n_constraints = have_constraint ?
1778  libmesh_map_find(constraint_rows, node).size() : std::size_t(-1);
1779  const std::size_t * n_constraints = node ?
1780  &my_n_constraints : nullptr;
1781 
1782  libmesh_assert(mesh.comm().semiverify(n_constraints));
1783  }
1784 }
1785 
1786 
1787 
1789 {
1790  LOG_SCOPE("libmesh_assert_valid_boundary_ids()", "MeshTools");
1791 
1792  if (mesh.n_processors() == 1)
1793  return;
1794 
1795  libmesh_parallel_only(mesh.comm());
1796 
1797  const BoundaryInfo & boundary_info = mesh.get_boundary_info();
1798 
1799  dof_id_type pmax_elem_id = mesh.max_elem_id();
1800  mesh.comm().max(pmax_elem_id);
1801 
1802  for (dof_id_type i=0; i != pmax_elem_id; ++i)
1803  {
1804  const Elem * elem = mesh.query_elem_ptr(i);
1805  const unsigned int my_n_nodes = elem ? elem->n_nodes() : 0;
1806  const unsigned int my_n_edges = elem ? elem->n_edges() : 0;
1807  const unsigned int my_n_sides = elem ? elem->n_sides() : 0;
1808  unsigned int
1809  n_nodes = my_n_nodes,
1810  n_edges = my_n_edges,
1811  n_sides = my_n_sides;
1812 
1813  mesh.comm().max(n_nodes);
1814  mesh.comm().max(n_edges);
1815  mesh.comm().max(n_sides);
1816 
1817  if (elem)
1818  {
1819  libmesh_assert_equal_to(my_n_nodes, n_nodes);
1820  libmesh_assert_equal_to(my_n_edges, n_edges);
1821  libmesh_assert_equal_to(my_n_sides, n_sides);
1822  }
1823 
1824  // Let's test all IDs on the element with one communication
1825  // rather than n_nodes + n_edges + n_sides communications, to
1826  // cut down on latency in dbg modes.
1827  std::vector<boundary_id_type> all_bcids;
1828 
1829  for (unsigned int n=0; n != n_nodes; ++n)
1830  {
1831  std::vector<boundary_id_type> bcids;
1832  if (elem)
1833  {
1834  boundary_info.boundary_ids(elem->node_ptr(n), bcids);
1835 
1836  // Ordering of boundary ids shouldn't matter
1837  std::sort(bcids.begin(), bcids.end());
1838  }
1839  // libmesh_assert(mesh.comm().semiverify (elem ? &bcids : nullptr));
1840 
1841  all_bcids.insert(all_bcids.end(), bcids.begin(),
1842  bcids.end());
1843  // Separator
1844  all_bcids.push_back(BoundaryInfo::invalid_id);
1845  }
1846 
1847  for (unsigned short e=0; e != n_edges; ++e)
1848  {
1849  std::vector<boundary_id_type> bcids;
1850 
1851  if (elem)
1852  {
1853  boundary_info.edge_boundary_ids(elem, e, bcids);
1854 
1855  // Ordering of boundary ids shouldn't matter
1856  std::sort(bcids.begin(), bcids.end());
1857  }
1858 
1859  // libmesh_assert(mesh.comm().semiverify (elem ? &bcids : nullptr));
1860 
1861  all_bcids.insert(all_bcids.end(), bcids.begin(),
1862  bcids.end());
1863  // Separator
1864  all_bcids.push_back(BoundaryInfo::invalid_id);
1865 
1866  if (elem)
1867  {
1868  boundary_info.raw_edge_boundary_ids(elem, e, bcids);
1869 
1870  // Ordering of boundary ids shouldn't matter
1871  std::sort(bcids.begin(), bcids.end());
1872 
1873  all_bcids.insert(all_bcids.end(), bcids.begin(),
1874  bcids.end());
1875  // Separator
1876  all_bcids.push_back(BoundaryInfo::invalid_id);
1877  }
1878 
1879  // libmesh_assert(mesh.comm().semiverify (elem ? &bcids : nullptr));
1880  }
1881 
1882  for (unsigned short s=0; s != n_sides; ++s)
1883  {
1884  std::vector<boundary_id_type> bcids;
1885 
1886  if (elem)
1887  {
1888  boundary_info.boundary_ids(elem, s, bcids);
1889 
1890  // Ordering of boundary ids shouldn't matter
1891  std::sort(bcids.begin(), bcids.end());
1892 
1893  all_bcids.insert(all_bcids.end(), bcids.begin(),
1894  bcids.end());
1895  // Separator
1896  all_bcids.push_back(BoundaryInfo::invalid_id);
1897  }
1898 
1899  // libmesh_assert(mesh.comm().semiverify (elem ? &bcids : nullptr));
1900 
1901  if (elem)
1902  {
1903  boundary_info.raw_boundary_ids(elem, s, bcids);
1904 
1905  // Ordering of boundary ids shouldn't matter
1906  std::sort(bcids.begin(), bcids.end());
1907 
1908  all_bcids.insert(all_bcids.end(), bcids.begin(),
1909  bcids.end());
1910  // Separator
1911  all_bcids.push_back(BoundaryInfo::invalid_id);
1912  }
1913 
1914  // libmesh_assert(mesh.comm().semiverify (elem ? &bcids : nullptr));
1915  }
1916 
1917  for (unsigned short sf=0; sf != 2; ++sf)
1918  {
1919  std::vector<boundary_id_type> bcids;
1920 
1921  if (elem)
1922  {
1923  boundary_info.shellface_boundary_ids(elem, sf, bcids);
1924 
1925  // Ordering of boundary ids shouldn't matter
1926  std::sort(bcids.begin(), bcids.end());
1927 
1928  all_bcids.insert(all_bcids.end(), bcids.begin(),
1929  bcids.end());
1930  // Separator
1931  all_bcids.push_back(BoundaryInfo::invalid_id);
1932  }
1933 
1934  // libmesh_assert(mesh.comm().semiverify (elem ? &bcids : nullptr));
1935 
1936  if (elem)
1937  {
1938  boundary_info.raw_shellface_boundary_ids(elem, sf, bcids);
1939 
1940  // Ordering of boundary ids shouldn't matter
1941  std::sort(bcids.begin(), bcids.end());
1942 
1943  all_bcids.insert(all_bcids.end(), bcids.begin(),
1944  bcids.end());
1945  // Separator
1946  all_bcids.push_back(BoundaryInfo::invalid_id);
1947  }
1948 
1949  // libmesh_assert(mesh.comm().semiverify (elem ? &bcids : nullptr));
1950  }
1951 
1953  (elem ? &all_bcids : nullptr));
1954  }
1955 }
1956 
1957 
1958 void libmesh_assert_valid_dof_ids(const MeshBase & mesh, unsigned int sysnum)
1959 {
1960  LOG_SCOPE("libmesh_assert_valid_dof_ids()", "MeshTools");
1961 
1962  if (mesh.n_processors() == 1)
1963  return;
1964 
1965  libmesh_parallel_only(mesh.comm());
1966 
1967  dof_id_type pmax_elem_id = mesh.max_elem_id();
1968  mesh.comm().max(pmax_elem_id);
1969 
1970  for (dof_id_type i=0; i != pmax_elem_id; ++i)
1971  assert_semiverify_dofobj(mesh.comm(),
1972  mesh.query_elem_ptr(i),
1973  sysnum);
1974 
1975  dof_id_type pmax_node_id = mesh.max_node_id();
1976  mesh.comm().max(pmax_node_id);
1977 
1978  for (dof_id_type i=0; i != pmax_node_id; ++i)
1979  assert_semiverify_dofobj(mesh.comm(),
1980  mesh.query_node_ptr(i),
1981  sysnum);
1982 }
1983 
1984 
1985 #ifdef LIBMESH_ENABLE_UNIQUE_ID
1987 {
1988  LOG_SCOPE("libmesh_assert_valid_unique_ids()", "MeshTools");
1989 
1990  libmesh_parallel_only(mesh.comm());
1991 
1992  // Storage for semi-local DofObject ids.
1993  std::unordered_set<unique_id_type> semilocal_unique_ids;
1994 
1995  auto gather_elem_ids = [&]()
1996  {
1997  for (auto const & elem : mesh.active_element_ptr_range())
1998  {
1999  auto [it, inserted] = semilocal_unique_ids.insert(elem->unique_id());
2000  libmesh_assert(inserted);
2001  libmesh_ignore(it);
2002  }
2003  };
2004 
2005  auto gather_node_ids = [&]()
2006  {
2007  for (auto const & node : mesh.node_ptr_range())
2008  {
2009  auto [it, inserted] = semilocal_unique_ids.insert(node->unique_id());
2010  libmesh_assert(inserted);
2011  libmesh_ignore(it);
2012  }
2013  };
2014 
2015  auto verify_elems = [&]()
2016  {
2017  dof_id_type pmax_elem_id = mesh.max_elem_id();
2018  mesh.comm().max(pmax_elem_id);
2019 
2020  for (auto i : make_range(pmax_elem_id))
2021  {
2022  const Elem * elem = mesh.query_elem_ptr(i);
2023  assert_dofobj_unique_id(mesh.comm(), elem, semilocal_unique_ids);
2024  }
2025  };
2026 
2027  auto verify_nodes = [&]()
2028  {
2029  dof_id_type pmax_node_id = mesh.max_node_id();
2030  mesh.comm().max(pmax_node_id);
2031 
2032  for (auto i : make_range(pmax_node_id))
2033  {
2034  const Node * node = mesh.query_node_ptr(i);
2035  assert_dofobj_unique_id(mesh.comm(), node, semilocal_unique_ids);
2036  }
2037  };
2038 
2040  {
2041  // First collect all the unique_ids we can see and make sure there's
2042  // no duplicates
2043  gather_elem_ids();
2044  gather_node_ids();
2045 
2046  // Then make sure elements/nodes are all in sync and remote
2047  // elements don't duplicate semilocal
2048  verify_elems();
2049  verify_nodes();
2050  }
2051  else
2052  {
2053  // If the mesh allows Node and Elem unique_ids to overlap, then we only
2054  // check for validity and uniqueness of an Elem (resp. Node) unique id
2055  // within the set of Elem (resp. Node) unique_ids.
2056  gather_elem_ids();
2057  verify_elems();
2058 
2059  // Clear id list before checking Nodes
2060  semilocal_unique_ids.clear();
2061 
2062  // Finally, check Nodes
2063  gather_node_ids();
2064  verify_nodes();
2065  }
2066 }
2067 #endif
2068 
2070 {
2071  libmesh_parallel_only(mesh.comm());
2072 
2073  dof_id_type parallel_max_elem_id = mesh.max_elem_id();
2074  mesh.comm().max(parallel_max_elem_id);
2075 
2076  for (dof_id_type i=0; i != parallel_max_elem_id; ++i)
2077  {
2078  const Elem * elem = mesh.query_elem_ptr(i);
2079  processor_id_type pid =
2081  mesh.comm().min(pid);
2082  libmesh_assert(elem || pid != mesh.processor_id());
2083  }
2084 
2085  dof_id_type parallel_max_node_id = mesh.max_node_id();
2086  mesh.comm().max(parallel_max_node_id);
2087 
2088  for (dof_id_type i=0; i != parallel_max_node_id; ++i)
2089  {
2090  const Node * node = mesh.query_node_ptr(i);
2091  processor_id_type pid =
2093  mesh.comm().min(pid);
2094  libmesh_assert(node || pid != mesh.processor_id());
2095  }
2096 }
2097 
2098 
2100 {
2101  libmesh_parallel_only(mesh.comm());
2102  auto locator = mesh.sub_point_locator();
2103 
2104  dof_id_type parallel_max_elem_id = mesh.max_elem_id();
2105  mesh.comm().max(parallel_max_elem_id);
2106 
2107  for (dof_id_type i=0; i != parallel_max_elem_id; ++i)
2108  {
2109  const Elem * elem = mesh.query_elem_ptr(i);
2110 
2111  const unsigned int my_n_nodes = elem ? elem->n_nodes() : 0;
2112  unsigned int n_nodes = my_n_nodes;
2113  mesh.comm().max(n_nodes);
2114 
2115  if (n_nodes)
2116  libmesh_assert(mesh.comm().semiverify(elem ? &my_n_nodes : nullptr));
2117 
2118  for (unsigned int n=0; n != n_nodes; ++n)
2119  {
2120  const Node * node = elem ? elem->node_ptr(n) : nullptr;
2121  processor_id_type pid =
2123  mesh.comm().min(pid);
2124  libmesh_assert(node || pid != mesh.processor_id());
2125  }
2126  }
2127 }
2128 
2129 
2130 
2131 template <>
2133 {
2134  LOG_SCOPE("libmesh_assert_parallel_consistent_procids()", "MeshTools");
2135 
2136  if (mesh.n_processors() == 1)
2137  return;
2138 
2139  libmesh_parallel_only(mesh.comm());
2140 
2141  // Some code (looking at you, stitch_meshes) modifies DofObject ids
2142  // without keeping max_elem_id()/max_node_id() consistent, but
2143  // that's done in a safe way for performance reasons, so we'll play
2144  // along and just figure out new max ids ourselves.
2145  dof_id_type parallel_max_elem_id = 0;
2146  for (const auto & elem : mesh.element_ptr_range())
2147  parallel_max_elem_id = std::max<dof_id_type>(parallel_max_elem_id,
2148  elem->id()+1);
2149  mesh.comm().max(parallel_max_elem_id);
2150 
2151  // Check processor ids for consistency between processors
2152 
2153  for (dof_id_type i=0; i != parallel_max_elem_id; ++i)
2154  {
2155  const Elem * elem = mesh.query_elem_ptr(i);
2156 
2157  processor_id_type min_id =
2158  elem ? elem->processor_id() :
2159  std::numeric_limits<processor_id_type>::max();
2160  mesh.comm().min(min_id);
2161 
2162  processor_id_type max_id =
2163  elem ? elem->processor_id() :
2164  std::numeric_limits<processor_id_type>::min();
2165  mesh.comm().max(max_id);
2166 
2167  if (elem)
2168  {
2169  libmesh_assert_equal_to (min_id, elem->processor_id());
2170  libmesh_assert_equal_to (max_id, elem->processor_id());
2171  }
2172 
2173  if (min_id == mesh.processor_id())
2174  libmesh_assert(elem);
2175  }
2176 }
2177 
2178 
2179 
2181 {
2182  LOG_SCOPE("libmesh_assert_parallel_consistent_new_node_procids()", "MeshTools");
2183 
2184  if (mesh.n_processors() == 1)
2185  return;
2186 
2187  libmesh_parallel_only(mesh.comm());
2188 
2189  // We want this test to hit every node when called even after nodes
2190  // have been added asynchronously but before everything has been
2191  // renumbered.
2192  dof_id_type parallel_max_elem_id = mesh.max_elem_id();
2193  mesh.comm().max(parallel_max_elem_id);
2194 
2195  std::vector<bool> elem_touched_by_anyone(parallel_max_elem_id, false);
2196 
2197  for (dof_id_type i=0; i != parallel_max_elem_id; ++i)
2198  {
2199  const Elem * elem = mesh.query_elem_ptr(i);
2200 
2201  const unsigned int my_n_nodes = elem ? elem->n_nodes() : 0;
2202  unsigned int n_nodes = my_n_nodes;
2203  mesh.comm().max(n_nodes);
2204 
2205  if (n_nodes)
2206  libmesh_assert(mesh.comm().semiverify(elem ? &my_n_nodes : nullptr));
2207 
2208  for (unsigned int n=0; n != n_nodes; ++n)
2209  {
2210  const Node * node = elem ? elem->node_ptr(n) : nullptr;
2211  const processor_id_type pid = node ? node->processor_id() : 0;
2212  libmesh_assert(mesh.comm().semiverify (node ? &pid : nullptr));
2213  }
2214  }
2215 }
2216 
2217 template <>
2219 {
2220  LOG_SCOPE("libmesh_assert_parallel_consistent_procids()", "MeshTools");
2221 
2222  if (mesh.n_processors() == 1)
2223  return;
2224 
2225  libmesh_parallel_only(mesh.comm());
2226 
2227  // We want this test to be valid even when called even after nodes
2228  // have been added asynchronously but before they're renumbered
2229  //
2230  // Plus, some code (looking at you, stitch_meshes) modifies
2231  // DofObject ids without keeping max_elem_id()/max_node_id()
2232  // consistent, but that's done in a safe way for performance
2233  // reasons, so we'll play along and just figure out new max ids
2234  // ourselves.
2235  dof_id_type parallel_max_node_id = 0;
2236  for (const auto & node : mesh.node_ptr_range())
2237  parallel_max_node_id = std::max<dof_id_type>(parallel_max_node_id,
2238  node->id()+1);
2239  mesh.comm().max(parallel_max_node_id);
2240 
2241  std::vector<bool> node_touched_by_anyone(parallel_max_node_id, false);
2242 
2243  for (const auto & elem : as_range(mesh.local_elements_begin(),
2244  mesh.local_elements_end()))
2245  {
2246  libmesh_assert (elem);
2247 
2248  for (auto & node : elem->node_ref_range())
2249  {
2250  dof_id_type nodeid = node.id();
2251  node_touched_by_anyone[nodeid] = true;
2252  }
2253  }
2254  mesh.comm().max(node_touched_by_anyone);
2255 
2256  // Check processor ids for consistency between processors
2257  // on any node an element touches
2258  for (dof_id_type i=0; i != parallel_max_node_id; ++i)
2259  {
2260  if (!node_touched_by_anyone[i])
2261  continue;
2262 
2263  const Node * node = mesh.query_node_ptr(i);
2264  const processor_id_type pid = node ? node->processor_id() : 0;
2265 
2266  libmesh_assert(mesh.comm().semiverify (node ? &pid : nullptr));
2267  }
2268 }
2269 
2270 
2271 
2272 #ifdef LIBMESH_ENABLE_AMR
2274 {
2275  LOG_SCOPE("libmesh_assert_valid_refinement_flags()", "MeshTools");
2276 
2277  libmesh_parallel_only(mesh.comm());
2278  if (mesh.n_processors() == 1)
2279  return;
2280 
2281  dof_id_type pmax_elem_id = mesh.max_elem_id();
2282  mesh.comm().max(pmax_elem_id);
2283 
2284  std::vector<unsigned char> my_elem_h_state(pmax_elem_id, 255);
2285  std::vector<unsigned char> my_elem_p_state(pmax_elem_id, 255);
2286 
2287  for (const auto & elem : mesh.element_ptr_range())
2288  {
2289  libmesh_assert (elem);
2290  dof_id_type elemid = elem->id();
2291 
2292  my_elem_h_state[elemid] =
2293  static_cast<unsigned char>(elem->refinement_flag());
2294 
2295  my_elem_p_state[elemid] =
2296  static_cast<unsigned char>(elem->p_refinement_flag());
2297  }
2298  std::vector<unsigned char> min_elem_h_state(my_elem_h_state);
2299  mesh.comm().min(min_elem_h_state);
2300 
2301  std::vector<unsigned char> min_elem_p_state(my_elem_p_state);
2302  mesh.comm().min(min_elem_p_state);
2303 
2304  for (dof_id_type i=0; i!= pmax_elem_id; ++i)
2305  {
2306  libmesh_assert(my_elem_h_state[i] == 255 ||
2307  my_elem_h_state[i] == min_elem_h_state[i]);
2308  libmesh_assert(my_elem_p_state[i] == 255 ||
2309  my_elem_p_state[i] == min_elem_p_state[i]);
2310  }
2311 }
2312 #else
2314 {
2315 }
2316 #endif // LIBMESH_ENABLE_AMR
2317 
2318 
2319 
2321  bool assert_valid_remote_elems)
2322 {
2323  LOG_SCOPE("libmesh_assert_valid_neighbors()", "MeshTools");
2324 
2325  for (const auto & elem : mesh.element_ptr_range())
2326  {
2327  libmesh_assert (elem);
2328  elem->libmesh_assert_valid_neighbors();
2329  }
2330 
2331  if (mesh.n_processors() == 1)
2332  return;
2333 
2334  libmesh_parallel_only(mesh.comm());
2335 
2336  dof_id_type pmax_elem_id = mesh.max_elem_id();
2337  mesh.comm().max(pmax_elem_id);
2338 
2339  for (dof_id_type i=0; i != pmax_elem_id; ++i)
2340  {
2341  const Elem * elem = mesh.query_elem_ptr(i);
2342 
2343  const unsigned int my_n_neigh = elem ? elem->n_neighbors() : 0;
2344  unsigned int n_neigh = my_n_neigh;
2345  mesh.comm().max(n_neigh);
2346  if (elem)
2347  libmesh_assert_equal_to (my_n_neigh, n_neigh);
2348 
2349  for (unsigned int n = 0; n != n_neigh; ++n)
2350  {
2351  dof_id_type my_neighbor = DofObject::invalid_id;
2352  dof_id_type * p_my_neighbor = nullptr;
2353 
2354  // If we have a non-remote_elem neighbor link, then we can
2355  // verify it.
2356  if (elem && elem->neighbor_ptr(n) != remote_elem)
2357  {
2358  p_my_neighbor = &my_neighbor;
2359  if (elem->neighbor_ptr(n))
2360  my_neighbor = elem->neighbor_ptr(n)->id();
2361 
2362  // But wait - if we haven't set remote_elem links yet then
2363  // some nullptr links on ghost elements might be
2364  // future-remote_elem links, so we can't verify those.
2365  if (!assert_valid_remote_elems &&
2366  !elem->neighbor_ptr(n) &&
2367  elem->processor_id() != mesh.processor_id())
2368  p_my_neighbor = nullptr;
2369  }
2370  libmesh_assert(mesh.comm().semiverify(p_my_neighbor));
2371  }
2372  }
2373 }
2374 #endif // DEBUG
2375 
2376 
2377 
2378 // Functors for correct_node_proc_ids
2379 namespace {
2380 
2381 typedef std::unordered_map<dof_id_type, processor_id_type> proc_id_map_type;
2382 
2383 struct SyncNodeSet
2384 {
2385  typedef unsigned char datum; // bool but without bit twiddling issues
2386 
2387  SyncNodeSet(std::unordered_set<const Node *> & _set,
2388  MeshBase & _mesh) :
2389  node_set(_set), mesh(_mesh) {}
2390 
2391  std::unordered_set<const Node *> & node_set;
2392 
2394 
2395  // ------------------------------------------------------------
2396  void gather_data (const std::vector<dof_id_type> & ids,
2397  std::vector<datum> & data)
2398  {
2399  // Find whether each requested node belongs in the set
2400  data.resize(ids.size());
2401 
2402  for (auto i : index_range(ids))
2403  {
2404  const dof_id_type id = ids[i];
2405 
2406  // We'd better have every node we're asked for
2407  Node * node = mesh.node_ptr(id);
2408 
2409  // Return if the node is in the set.
2410  data[i] = node_set.count(node);
2411  }
2412  }
2413 
2414  // ------------------------------------------------------------
2415  bool act_on_data (const std::vector<dof_id_type> & ids,
2416  const std::vector<datum> in_set)
2417  {
2418  bool data_changed = false;
2419 
2420  // Add nodes we've been informed of to our own set
2421  for (auto i : index_range(ids))
2422  {
2423  if (in_set[i])
2424  {
2425  Node * node = mesh.node_ptr(ids[i]);
2426  if (!node_set.count(node))
2427  {
2428  node_set.insert(node);
2429  data_changed = true;
2430  }
2431  }
2432  }
2433 
2434  return data_changed;
2435  }
2436 };
2437 
2438 
2439 struct NodesNotInSet
2440 {
2441  NodesNotInSet(const std::unordered_set<const Node *> _set)
2442  : node_set(_set) {}
2443 
2444  bool operator() (const Node * node) const
2445  {
2446  if (node_set.count(node))
2447  return false;
2448  return true;
2449  }
2450 
2451  const std::unordered_set<const Node *> node_set;
2452 };
2453 
2454 
2455 struct SyncProcIdsFromMap
2456 {
2457  typedef processor_id_type datum;
2458 
2459  SyncProcIdsFromMap(const proc_id_map_type & _map,
2460  MeshBase & _mesh) :
2461  new_proc_ids(_map), mesh(_mesh) {}
2462 
2463  const proc_id_map_type & new_proc_ids;
2464 
2465  MeshBase & mesh;
2466 
2467  // ------------------------------------------------------------
2468  void gather_data (const std::vector<dof_id_type> & ids,
2469  std::vector<datum> & data)
2470  {
2471  // Find the new processor id of each requested node
2472  data.resize(ids.size());
2473 
2474  for (auto i : index_range(ids))
2475  {
2476  const dof_id_type id = ids[i];
2477 
2478  // Return the node's new processor id if it has one, or its
2479  // old processor id if not.
2480  if (const auto it = new_proc_ids.find(id);
2481  it != new_proc_ids.end())
2482  data[i] = it->second;
2483  else
2484  {
2485  // We'd better find every node we're asked for
2486  const Node & node = mesh.node_ref(id);
2487  data[i] = node.processor_id();
2488  }
2489  }
2490  }
2491 
2492  // ------------------------------------------------------------
2493  void act_on_data (const std::vector<dof_id_type> & ids,
2494  const std::vector<datum> proc_ids)
2495  {
2496  // Set the node processor ids we've now been informed of
2497  for (auto i : index_range(ids))
2498  {
2499  Node & node = mesh.node_ref(ids[i]);
2500  node.processor_id() = proc_ids[i];
2501  }
2502  }
2503 };
2504 }
2505 
2506 
2507 
2509 {
2510  LOG_SCOPE("correct_node_proc_ids()","MeshTools");
2511 
2512  // This function must be run on all processors at once
2513  libmesh_parallel_only(mesh.comm());
2514 
2515  // We require all processors to agree on nodal processor ids before
2516  // going into this algorithm.
2517 #ifdef DEBUG
2519 #endif
2520 
2521  // If we have any unpartitioned elements at this
2522  // stage there is a problem
2523  libmesh_assert (n_elem(mesh.unpartitioned_elements_begin(),
2524  mesh.unpartitioned_elements_end()) == 0);
2525 
2526  // Fix nodes' processor ids. Coarsening may have left us with nodes
2527  // which are no longer touched by any elements of the same processor
2528  // id, and for DofMap to work we need to fix that.
2529 
2530  // This is harder now that libMesh no longer requires a distributed
2531  // mesh to ghost all nodal neighbors: it is possible for two active
2532  // elements on two different processors to share the same node in
2533  // such a way that neither processor knows the others' element
2534  // exists!
2535 
2536  // While we're at it, if this mesh is configured to allow
2537  // repartitioning, we'll repartition *all* the nodes' processor ids
2538  // using the canonical Node heuristic, to try and improve DoF load
2539  // balancing. But if the mesh is disallowing repartitioning, we
2540  // won't touch processor_id on any node where it's valid, regardless
2541  // of whether or not it's canonical.
2542  bool repartition_all_nodes = !mesh.skip_noncritical_partitioning();
2543  std::unordered_set<const Node *> valid_nodes;
2544 
2545  // If we aren't allowed to repartition, then we're going to leave
2546  // every node we can at its current processor_id, and *only*
2547  // repartition the nodes whose current processor id is incompatible
2548  // with DoFMap (because it doesn't touch an active element, e.g. due
2549  // to coarsening)
2550  if (!repartition_all_nodes)
2551  {
2552  for (const auto & elem : mesh.active_element_ptr_range())
2553  for (const auto & node : elem->node_ref_range())
2554  if (elem->processor_id() == node.processor_id())
2555  valid_nodes.insert(&node);
2556 
2557  SyncNodeSet syncv(valid_nodes, mesh);
2558 
2560  (mesh.comm(), mesh.nodes_begin(), mesh.nodes_end(), syncv);
2561  }
2562 
2563  // We build up a set of compatible processor ids for each node
2564  proc_id_map_type new_proc_ids;
2565 
2566  for (auto & elem : mesh.active_element_ptr_range())
2567  {
2568  processor_id_type pid = elem->processor_id();
2569 
2570  for (auto & node : elem->node_ref_range())
2571  {
2572  const dof_id_type id = node.id();
2573  if (auto it = new_proc_ids.find(id);
2574  it == new_proc_ids.end())
2575  new_proc_ids.emplace(id, pid);
2576  else
2577  it->second = node.choose_processor_id(it->second, pid);
2578  }
2579  }
2580 
2581  // Sort the new pids to push to each processor
2582  std::map<processor_id_type, std::vector<std::pair<dof_id_type, processor_id_type>>>
2583  ids_to_push;
2584 
2585  for (const auto & node : mesh.node_ptr_range())
2586  if (const auto it = std::as_const(new_proc_ids).find(node->id());
2587  it != new_proc_ids.end() && node->processor_id() != DofObject::invalid_processor_id)
2588  ids_to_push[node->processor_id()].emplace_back(node->id(), /*pid=*/it->second);
2589 
2590  auto action_functor =
2591  [& mesh, & new_proc_ids]
2593  const std::vector<std::pair<dof_id_type, processor_id_type>> & data)
2594  {
2595  for (const auto & [id, pid] : data)
2596  {
2597  if (const auto it = new_proc_ids.find(id);
2598  it == new_proc_ids.end())
2599  new_proc_ids.emplace(id, pid);
2600  else
2601  {
2602  const Node & node = mesh.node_ref(id);
2603  it->second = node.choose_processor_id(it->second, pid);
2604  }
2605  }
2606  };
2607 
2608  Parallel::push_parallel_vector_data
2609  (mesh.comm(), ids_to_push, action_functor);
2610 
2611  // Now new_proc_ids is correct for every node we used to own. Let's
2612  // ask every other processor about the nodes they used to own. But
2613  // first we'll need to keep track of which nodes we used to own,
2614  // lest we get them confused with nodes we newly own.
2615  std::unordered_set<Node *> ex_local_nodes;
2616  for (auto & node : mesh.local_node_ptr_range())
2617  if (const auto it = new_proc_ids.find(node->id());
2618  it != new_proc_ids.end() && it->second != mesh.processor_id())
2619  ex_local_nodes.insert(node);
2620 
2621  SyncProcIdsFromMap sync(new_proc_ids, mesh);
2622  if (repartition_all_nodes)
2624  (mesh.comm(), mesh.nodes_begin(), mesh.nodes_end(), sync);
2625  else
2626  {
2627  NodesNotInSet nnis(valid_nodes);
2628 
2630  (mesh.comm(), mesh.nodes_begin(), mesh.nodes_end(), nnis, sync);
2631  }
2632 
2633  // And finally let's update the nodes we used to own.
2634  for (const auto & node : ex_local_nodes)
2635  {
2636  if (valid_nodes.count(node))
2637  continue;
2638 
2639  const dof_id_type id = node->id();
2640  const proc_id_map_type::iterator it = new_proc_ids.find(id);
2641  libmesh_assert(it != new_proc_ids.end());
2642  node->processor_id() = it->second;
2643  }
2644 
2645  // We should still have consistent nodal processor ids coming out of
2646  // this algorithm, but if we're allowed to repartition the mesh then
2647  // they should be canonically correct too.
2648 #ifdef DEBUG
2649  libmesh_assert_valid_procids<Node>(mesh);
2650  //if (repartition_all_nodes)
2651  // libmesh_assert_canonical_node_procids(mesh);
2652 #endif
2653 }
2654 
2655 
2656 
2658 {
2660 }
2661 
2662 } // namespace MeshTools
2663 
2664 } // namespace libMesh
unsigned int n_active_local_levels(const MeshBase &mesh)
Definition: mesh_tools.C:767
static const Order type_to_default_order_map[INVALID_ELEM]
This array maps the integer representation of the ElemType enum to the default approximation order of...
Definition: elem.h:990
void libmesh_assert_equal_points(const MeshBase &mesh)
A function for testing that node locations match across processors.
Definition: mesh_tools.C:1685
ElemType
Defines an enum for geometric element types.
void libmesh_assert_topology_consistent_procids< Node >(const MeshBase &mesh)
Definition: mesh_tools.C:1563
void elem_types(const MeshBase &mesh, std::vector< ElemType > &et)
Fills in a vector of all element types in the mesh.
Definition: mesh_tools.C:723
dof_id_type n_nodes(const MeshBase::const_node_iterator &begin, const MeshBase::const_node_iterator &end)
Count up the number of nodes of a specific type (as defined by an iterator range).
Definition: mesh_tools.C:1012
dof_id_type dof_number(const unsigned int s, const unsigned int var, const unsigned int comp) const
Definition: dof_object.h:1008
const Elem * parent() const
Definition: elem.h:3044
bool is_prepared() const
Definition: mesh_base.C:1057
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
constraint_rows_type & get_constraint_rows()
Constraint rows accessors.
Definition: mesh_base.h:1905
A Node is like a Point, but with more information.
Definition: node.h:52
void libmesh_assert_valid_amr_interior_parents(const MeshBase &mesh)
A function for verifying that any interior_parent pointers on elements are consistent with AMR (paren...
Definition: mesh_tools.C:1441
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
unsigned int n_comp(const unsigned int s, const unsigned int var) const
Definition: dof_object.h:978
std::unique_ptr< PointLocatorBase > sub_point_locator() const
Definition: mesh_base.C:1826
This class defines a sphere.
Definition: sphere.h:72
void libmesh_assert_valid_remote_elems(const MeshBase &mesh)
A function for verifying that active local elements&#39; neighbors are never remote elements.
Definition: mesh_tools.C:1367
void libmesh_assert_consistent_distributed_nodes(const MeshBase &mesh)
A function for verifying that distribution of nodes is parallel consistent (every processor can see e...
Definition: mesh_tools.C:2099
const Elem * interior_parent() const
Definition: elem.C:1160
void correct_node_proc_ids(MeshBase &)
Changes the processor ids on each node so be the same as the id of the lowest element touching that n...
Definition: mesh_tools.C:2508
dof_id_type n_elem(const MeshBase::const_element_iterator &begin, const MeshBase::const_element_iterator &end)
Count up the number of elements of a specific type (as defined by an iterator range).
Definition: mesh_tools.C:1004
libMesh::BoundingBox create_bounding_box(const MeshBase &mesh)
Definition: mesh_tools.C:566
The definition of the const_element_iterator struct.
Definition: mesh_base.h:2521
bool valid_is_prepared(const MeshBase &mesh)
A function for testing whether a mesh&#39;s cached is_prepared() setting is not a false positive...
Definition: mesh_tools.C:1256
unsigned int dim
const Elem * top_parent() const
Definition: elem.h:3070
Sphere processor_bounding_sphere(const MeshBase &mesh, const processor_id_type pid)
Definition: mesh_tools.C:670
Dummy "splitting object" used to distinguish splitting constructors from copy constructors.
Definition: threads_none.h:63
void clear_spline_nodes(MeshBase &)
Remove spline node (for IsoGeometric Analysis meshes) elements and nodes and constraints from the mes...
Definition: mesh_tools.C:1221
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
void sum(T &r) const
std::unordered_set< dof_id_type > find_block_boundary_nodes(const MeshBase &mesh)
Returns a std::set containing Node IDs for all of the block boundary nodes.
Definition: mesh_tools.C:544
This is the base class from which all geometric element types are derived.
Definition: elem.h:94
void assign_global_indices(MeshBase &) const
This method assigns globally unique, partition-agnostic indices to the nodes and elements in the mesh...
void find_nodal_neighbors(const MeshBase &mesh, const Node &n, const std::vector< std::vector< const Elem *>> &nodes_to_elem_map, std::vector< const Node *> &neighbors)
Given a mesh and a node in the mesh, the vector will be filled with every node directly attached to t...
Definition: mesh_tools.C:1071
void libmesh_assert_valid_constraint_rows(const MeshBase &mesh)
A function for verifying that all mesh constraint rows express relations between nodes and elements t...
Definition: mesh_tools.C:1745
virtual bool is_node_on_side(const unsigned int n, const unsigned int s) const =0
unsigned int n_local_levels(const MeshBase &mesh)
Definition: mesh_tools.C:813
void skip_noncritical_partitioning(bool skip)
If true is passed in then the elements on this mesh will no longer be (re)partitioned, and the nodes on this mesh will only be repartitioned if they are found "orphaned" via coarsening or other removal of the last element responsible for their node/element processor id consistency.
Definition: mesh_base.h:1401
unique_id_type unique_id() const
Definition: dof_object.h:835
void libmesh_assert_parallel_consistent_new_node_procids(const MeshBase &mesh)
A function for verifying that processor assignment is parallel consistent (every processor agrees on ...
Definition: mesh_tools.C:2180
const Parallel::Communicator & comm() const
void build_nodes_to_elem_map(const MeshBase &mesh, std::vector< std::vector< dof_id_type >> &nodes_to_elem_map)
After calling this function the input vector nodes_to_elem_map will contain the node to element conne...
Definition: mesh_tools.C:456
The StoredRange class defines a contiguous, divisible set of objects.
Definition: stored_range.h:54
The libMesh namespace provides an interface to certain functionality in the library.
MeshBase & mesh
Definition: mesh_tools.C:2393
const BoundaryInfo & get_boundary_info() const
The information about boundary ids on the mesh.
Definition: mesh_base.h:170
virtual std::unique_ptr< MeshBase > clone() const =0
Virtual "copy constructor".
Real distance(const Point &p)
dof_id_type n_elem_of_type(const MeshBase &mesh, const ElemType type)
Definition: mesh_tools.C:735
processor_id_type choose_processor_id(processor_id_type pid1, processor_id_type pid2) const
Return which of pid1 and pid2 would be preferred by the current load-balancing heuristic applied to t...
Definition: node.C:78
libMesh::BoundingBox create_local_bounding_box(const MeshBase &mesh)
Definition: mesh_tools.C:631
uint8_t processor_id_type
Definition: id_types.h:104
This is the MeshBase class.
Definition: mesh_base.h:80
SimpleRange< ChildRefIter > child_ref_range()
Returns a range with all children of a parent element, usable in range-based for loops.
Definition: elem.h:2352
void libmesh_assert_consistent_distributed(const MeshBase &mesh)
A function for verifying that distribution of dof objects is parallel consistent (every processor can...
Definition: mesh_tools.C:2069
unsigned int paranoid_n_levels(const MeshBase &mesh)
Definition: mesh_tools.C:850
std::unordered_set< dof_id_type > find_boundary_nodes(const MeshBase &mesh)
Calling this function on a 2D mesh will convert all the elements to triangles.
Definition: mesh_tools.C:524
virtual bool is_serial_on_zero() const
Definition: mesh_base.h:354
void libmesh_assert_equal_n_systems(const MeshBase &mesh)
The following functions, only available in builds with NDEBUG undefined, are for asserting internal c...
Definition: mesh_tools.C:1292
void libmesh_assert_valid_dof_ids(const MeshBase &mesh, unsigned int sysnum=libMesh::invalid_uint)
A function for verifying that degree of freedom indexing matches across processors.
Definition: mesh_tools.C:1958
uint8_t processor_id_type
processor_id_type n_processors() const
virtual bool is_serial() const
Definition: mesh_base.h:347
void libmesh_ignore(const Args &...)
const dof_id_type n_nodes
Definition: tecplot_io.C:67
void libmesh_assert_valid_node_pointers(const MeshBase &mesh)
A function for walking across the mesh to try and ferret out invalidated or misassigned pointers...
Definition: mesh_tools.C:1342
static const boundary_id_type invalid_id
Number used for internal use.
virtual void delete_elem(Elem *e)=0
Removes element e from the mesh.
ElemMappingType mapping_type() const
Definition: elem.h:3134
This is the MeshCommunication class.
void libmesh_assert_canonical_node_procids(const MeshBase &mesh)
A function for verifying that processor assignment of nodes matches the heuristic specified in Node::...
Definition: mesh_tools.C:1614
dof_id_type id() const
Definition: dof_object.h:819
void min(const T &r, T &o, Request &req) const
static constexpr dof_id_type invalid_id
An invalid id to distinguish an uninitialized DofObject.
Definition: dof_object.h:473
unsigned int n_vars
virtual unsigned int n_nodes() const =0
void libmesh_assert_no_links_to_elem(const MeshBase &mesh, const Elem *bad_elem)
The following functions, only available in builds with DEBUG defined, typically have surprisingly slo...
Definition: mesh_tools.C:1666
dof_id_type weight(const MeshBase &mesh, const processor_id_type pid)
Definition: mesh_tools.C:444
unsigned int n_vars(const unsigned int s, const unsigned int vg) const
Definition: dof_object.h:943
unsigned int which_neighbor_am_i(const Elem *e) const
This function tells you which neighbor e is.
Definition: elem.h:2933
unsigned int n_systems() const
Definition: dof_object.h:913
SimpleRange< IndexType > as_range(const std::pair< IndexType, IndexType > &p)
Helper function that allows us to treat a homogenous pair as a range.
Definition: simple_range.h:57
unsigned int n_levels(const MeshBase &mesh)
Definition: mesh_tools.C:826
virtual const Node * query_node_ptr(const dof_id_type i) const =0
virtual dof_id_type max_elem_id() const =0
The BoundaryInfo class contains information relevant to boundary conditions including storing faces...
Definition: boundary_info.h:57
libmesh_assert(ctx)
void libmesh_assert_valid_boundary_ids(const MeshBase &mesh)
A function for verifying that boundary condition ids match across processors.
Definition: mesh_tools.C:1788
virtual void delete_node(Node *n)=0
Removes the Node n from the mesh.
void libmesh_assert_valid_amr_elem_ids(const MeshBase &mesh)
A function for verifying that ids of elements are correctly sorted for AMR (parents have lower ids th...
Definition: mesh_tools.C:1421
const ConstElemRange & active_local_element_stored_range() const
Definition: mesh_base.C:1928
void allow_node_and_elem_unique_id_overlap(bool allow)
If true is passed, then this mesh will no longer require unique_ids to be unique across the set of al...
Definition: mesh_base.h:1377
void libmesh_assert_parallel_consistent_procids< Elem >(const MeshBase &mesh)
Definition: mesh_tools.C:2132
Sphere subdomain_bounding_sphere(const MeshBase &mesh, const subdomain_id_type sid)
Definition: mesh_tools.C:709
const proc_id_map_type & new_proc_ids
Definition: mesh_tools.C:2463
virtual unsigned int n_edges() const =0
timpi_pure bool semiverify(const T *r) const
void sync_dofobject_data_by_id(const Communicator &comm, const Iterator &range_begin, const Iterator &range_end, SyncFunctor &sync)
Request data about a range of ghost dofobjects uniquely identified by their id.
void globally_renumber_nodes_and_elements(MeshBase &)
There is no reason for a user to ever call this function.
Definition: mesh_tools.C:2657
Real volume(const MeshBase &mesh, unsigned int dim=libMesh::invalid_uint)
Find the total volume of a mesh (interpreting that as area for dim = 2, or total arc length for dim =...
Definition: mesh_tools.C:1020
void find_hanging_nodes_and_parents(const MeshBase &mesh, std::map< dof_id_type, std::vector< dof_id_type >> &hanging_nodes)
Given a mesh hanging_nodes will be filled with an associative array keyed off the global id of all th...
Definition: mesh_tools.C:1133
dof_id_type total_weight(const MeshBase &mesh)
Definition: mesh_tools.C:421
void broadcast(T &data, const unsigned int root_id=0, const bool identical_sizes=false) const
void libmesh_assert_parallel_consistent_procids< Node >(const MeshBase &mesh)
Definition: mesh_tools.C:2218
dof_id_type n_connected_components(const MeshBase &mesh, Real constraint_tol=0)
Definition: mesh_tools.C:864
void parallel_reduce(const Range &range, Body &body, unsigned int n_threads=libMesh::n_threads())
Execute the provided reduction operation in parallel on the specified range.
Definition: threads_none.h:109
libMesh::BoundingBox create_subdomain_bounding_box(const MeshBase &mesh, const subdomain_id_type sid)
Definition: mesh_tools.C:685
std::string enum_to_string(const T e)
Sphere bounding_sphere(const MeshBase &mesh)
Definition: mesh_tools.C:618
Defines a Cartesian bounding box by the two corner extremum.
Definition: bounding_box.h:40
virtual const Elem * elem_ptr(const dof_id_type i) const =0
virtual unsigned int n_sides() const =0
const Elem * neighbor_ptr(unsigned int i) const
Definition: elem.h:2612
void libmesh_assert_equal_connectivity(const MeshBase &mesh)
A function for testing that element nodal connectivities match across processors. ...
Definition: mesh_tools.C:1701
std::unordered_set< const Node * > & node_set
Definition: mesh_tools.C:2391
unsigned int level() const
Definition: elem.h:3088
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
virtual const Elem * query_elem_ptr(const dof_id_type i) const =0
timpi_pure bool verify(const T &r) const
void libmesh_assert_connected_nodes(const MeshBase &mesh)
A function for verifying that all nodes are connected to at least one element.
Definition: mesh_tools.C:1722
void max(const T &r, T &o, Request &req) const
auto norm(const T &a)
Definition: tensor_tools.h:74
DIE A HORRIBLE DEATH HERE typedef MPI_Comm communicator
const Node * node_ptr(const unsigned int i) const
Definition: elem.h:2513
unsigned int n_neighbors() const
Definition: elem.h:713
void get_not_subactive_node_ids(const MeshBase &mesh, std::set< dof_id_type > &not_subactive_node_ids)
Builds a set of node IDs for nodes which belong to non-subactive elements.
Definition: mesh_tools.C:993
The definition of the const_node_iterator struct.
Definition: mesh_base.h:2572
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
dof_id_type n_active_elem_of_type(const MeshBase &mesh, const ElemType type)
Definition: mesh_tools.C:744
unsigned int mesh_dimension() const
Definition: mesh_base.C:430
IntRange< unsigned short > node_index_range() const
Definition: elem.h:2697
virtual const Node & node_ref(const dof_id_type i) const
Definition: mesh_base.h:735
void find_nodal_or_face_neighbors(const MeshBase &mesh, const Node &node, const std::unordered_map< dof_id_type, std::vector< const Elem *>> &nodes_to_elem_map, std::vector< const Node *> &neighbors)
Given a mesh and a node in the mesh, the vector will be filled with every node directly attached to t...
Definition: mesh_tools.C:1092
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
libMesh::BoundingBox create_nodal_bounding_box(const MeshBase &mesh)
Definition: mesh_tools.C:591
virtual dof_id_type max_node_id() const =0
virtual dof_id_type n_elem() const =0
virtual const Node * node_ptr(const dof_id_type i) const =0
void libmesh_assert_valid_unique_ids(const MeshBase &mesh)
A function for verifying that unique ids match across processors.
Definition: mesh_tools.C:1986
processor_id_type processor_id() const
libMesh::BoundingBox create_processor_bounding_box(const MeshBase &mesh, const processor_id_type pid)
Definition: mesh_tools.C:645
unsigned int n_p_levels(const MeshBase &mesh)
Definition: mesh_tools.C:1049
processor_id_type processor_id() const
Definition: dof_object.h:881
void libmesh_assert_old_dof_objects(const MeshBase &mesh)
A function for testing that all non-recently-created DofObjects within a mesh have old_dof_object dat...
Definition: mesh_tools.C:1318
virtual ElemType type() const =0
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:39
dof_id_type node_id(const unsigned int i) const
Definition: elem.h:2481
uint8_t unique_id_type
Definition: id_types.h:86
bool has_children() const
Definition: elem.h:2993
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
void libmesh_assert_contiguous_dof_ids(const MeshBase &mesh, unsigned int sysnum)
A function for verifying that degree of freedom indexes are contiguous on each processor, as is required by libMesh numeric classes.
Definition: mesh_tools.C:1477
dof_id_type n_non_subactive_elem_of_type_at_level(const MeshBase &mesh, const ElemType type, const unsigned int level)
Definition: mesh_tools.C:751
void libmesh_assert_topology_consistent_procids< Elem >(const MeshBase &mesh)
Definition: mesh_tools.C:1519
uint8_t dof_id_type
Definition: id_types.h:67
unsigned int n_active_levels(const MeshBase &mesh)
Definition: mesh_tools.C:796
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
void libmesh_assert_valid_refinement_flags(const MeshBase &mesh)
A function for verifying that refinement flags on elements are consistent between processors...
Definition: mesh_tools.C:2273
const RemoteElem * remote_elem
Definition: remote_elem.C:57