libMesh
mesh_communication.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/boundary_info.h"
22 #include "libmesh/distributed_mesh.h"
23 #include "libmesh/elem.h"
24 #include "libmesh/ghosting_functor.h"
25 #include "libmesh/libmesh_config.h"
26 #include "libmesh/libmesh_common.h"
27 #include "libmesh/libmesh_logging.h"
28 #include "libmesh/mesh_base.h"
29 #include "libmesh/mesh_communication.h"
30 #include "libmesh/null_output_iterator.h"
31 #include "libmesh/mesh_tools.h"
32 #include "libmesh/parallel.h"
33 #include "libmesh/parallel_elem.h"
34 #include "libmesh/parallel_node.h"
35 #include "libmesh/parallel_ghost_sync.h"
36 #include "libmesh/utility.h"
37 #include "libmesh/remote_elem.h"
38 #include "libmesh/int_range.h"
39 #include "libmesh/elem_side_builder.h"
40 
41 // C++ Includes
42 #include <numeric>
43 #include <set>
44 #include <unordered_set>
45 #include <unordered_map>
46 
47 
48 
49 //-----------------------------------------------
50 // anonymous namespace for implementation details
51 namespace {
52 
53 using namespace libMesh;
54 
55 struct SyncNeighbors
56 {
57  typedef std::vector<dof_id_type> datum;
58 
59  SyncNeighbors(MeshBase & _mesh) :
60  mesh(_mesh) {}
61 
62  MeshBase & mesh;
63 
64  // Find the neighbor ids for each requested element
65  void gather_data (const std::vector<dof_id_type> & ids,
66  std::vector<datum> & neighbors) const
67  {
68  neighbors.resize(ids.size());
69 
70  for (auto i : index_range(ids))
71  {
72  // Look for this element in the mesh
73  // We'd better find every element we're asked for
74  const Elem & elem = mesh.elem_ref(ids[i]);
75 
76  // Return the element's neighbors
77  const unsigned int n_neigh = elem.n_neighbors();
78  neighbors[i].resize(n_neigh);
79  for (unsigned int n = 0; n != n_neigh; ++n)
80  {
81  const Elem * neigh = elem.neighbor_ptr(n);
82  if (neigh)
83  {
84  libmesh_assert_not_equal_to(neigh, remote_elem);
85  neighbors[i][n] = neigh->id();
86  }
87  else
88  neighbors[i][n] = DofObject::invalid_id;
89  }
90  }
91  }
92 
93  void act_on_data (const std::vector<dof_id_type> & ids,
94  const std::vector<datum> & neighbors) const
95  {
96  for (auto i : index_range(ids))
97  {
98  Elem & elem = mesh.elem_ref(ids[i]);
99 
100  const datum & new_neigh = neighbors[i];
101 
102  const unsigned int n_neigh = elem.n_neighbors();
103  libmesh_assert_equal_to (n_neigh, new_neigh.size());
104 
105  for (unsigned int n = 0; n != n_neigh; ++n)
106  {
107  const dof_id_type new_neigh_id = new_neigh[n];
108  const Elem * old_neigh = elem.neighbor_ptr(n);
109  if (old_neigh && old_neigh != remote_elem)
110  {
111  libmesh_assert_equal_to(old_neigh->id(), new_neigh_id);
112  }
113  else if (new_neigh_id == DofObject::invalid_id)
114  {
115  libmesh_assert (!old_neigh);
116  }
117  else
118  {
119  Elem * neigh = mesh.query_elem_ptr(new_neigh_id);
120  if (neigh)
121  elem.set_neighbor(n, neigh);
122  else
123  elem.set_neighbor(n, const_cast<RemoteElem *>(remote_elem));
124  }
125  }
126  }
127  }
128 };
129 
130 
131 void
132 connect_element_families(const connected_elem_set_type & connected_elements,
133  const connected_elem_set_type & new_connected_elements,
134  connected_elem_set_type & newer_connected_elements,
135  const MeshBase * mesh)
136 {
137  // mesh was an optional parameter for API backwards compatibility
138  if (mesh && !mesh->get_constraint_rows().empty())
139  {
140  // We start with the constraint connections, not ancestors,
141  // because we don't need constraining nodes of elements'
142  // ancestors' constrained nodes.
143  const auto & constraint_rows = mesh->get_constraint_rows();
144 
145  std::unordered_set<const Elem *> constraining_nodes_elems;
146  for (const Elem * elem : connected_elements)
147  {
148  for (const Node & node : elem->node_ref_range())
149  {
150  // Retain all elements containing constraining nodes
151  if (const auto it = constraint_rows.find(&node);
152  it != constraint_rows.end())
153  for (auto & p : it->second)
154  {
155  const Elem * constraining_elem = p.first.first;
156  libmesh_assert(constraining_elem ==
157  mesh->elem_ptr(constraining_elem->id()));
158  if (!connected_elements.count(constraining_elem) &&
159  !new_connected_elements.count(constraining_elem))
160  constraining_nodes_elems.insert(constraining_elem);
161  }
162  }
163  }
164 
165  newer_connected_elements.insert(constraining_nodes_elems.begin(),
166  constraining_nodes_elems.end());
167  }
168 
169 #ifdef LIBMESH_ENABLE_AMR
170 
171  // Because our set is sorted by ascending level, we can traverse it
172  // in reverse order, adding parents as we go, and end up with all
173  // ancestors added. This is safe for std::set where insert doesn't
174  // invalidate iterators.
175  //
176  // This only works because we do *not* cache
177  // connected_elements.rend(), whose value can change when we insert
178  // elements which are sorted before the original rend.
179  //
180  // We're also going to get subactive descendents here, when any
181  // exist. We're iterating in the wrong direction to do that
182  // non-recursively, so we'll cop out and rely on total_family_tree.
183  // Iterating backwards does mean that we won't be querying the newly
184  // inserted subactive elements redundantly.
185 
186  connected_elem_set_type::reverse_iterator
187  elem_rit = new_connected_elements.rbegin();
188 
189  for (; elem_rit != new_connected_elements.rend(); ++elem_rit)
190  {
191  const Elem * elem = *elem_rit;
192  libmesh_assert(elem);
193 
194  // We let ghosting functors worry about only active elements,
195  // but the remote processor needs all its semilocal elements'
196  // ancestors and active semilocal elements' descendants too.
197  for (const Elem * parent = elem->parent(); parent;
198  parent = parent->parent())
199  if (!connected_elements.count(parent) &&
200  !new_connected_elements.count(parent))
201  newer_connected_elements.insert (parent);
202 
203  auto total_family_insert =
204  [&connected_elements, &new_connected_elements,
205  &newer_connected_elements]
206  (const Elem * e)
207  {
208  if (e->active() && e->has_children())
209  {
210  std::vector<const Elem *> subactive_family;
211  e->total_family_tree(subactive_family);
212  for (const auto & f : subactive_family)
213  {
215  if (!connected_elements.count(f) &&
216  !new_connected_elements.count(f))
217  newer_connected_elements.insert(f);
218  }
219  }
220  };
221 
222  total_family_insert(elem);
223 
224  // We also need any interior parents on this mesh, which will
225  // then need their own ancestors and descendants.
226  const Elem * interior_parent = elem->interior_parent();
227 
228  // Don't try to grab interior parents from other meshes, e.g. if
229  // this was a BoundaryMesh associated with a separate Mesh.
230 
231  // We can't test this if someone's using the pre-mesh-ptr API
232  libmesh_assert(!interior_parent || mesh);
233 
234  if (interior_parent &&
235  interior_parent == mesh->query_elem_ptr(interior_parent->id()) &&
236  !connected_elements.count(interior_parent) &&
237  !new_connected_elements.count(interior_parent))
238  {
239  newer_connected_elements.insert (interior_parent);
240  total_family_insert(interior_parent);
241  }
242  }
243 
244 # ifdef DEBUG
245  // Let's be paranoid and make sure that all our ancestors
246  // really did get inserted. I screwed this up the first time
247  // by caching rend, and I can easily imagine screwing it up in
248  // the future by changing containers.
249  auto check_elem =
250  [&connected_elements,
251  &new_connected_elements,
252  &newer_connected_elements]
253  (const Elem * elem)
254  {
255  libmesh_assert(elem);
256  const Elem * parent = elem->parent();
257  if (parent)
258  libmesh_assert(connected_elements.count(parent) ||
259  new_connected_elements.count(parent) ||
260  newer_connected_elements.count(parent));
261  };
262 
263  for (const auto & elem : connected_elements)
264  check_elem(elem);
265  for (const auto & elem : new_connected_elements)
266  check_elem(elem);
267  for (const auto & elem : newer_connected_elements)
268  check_elem(elem);
269 # endif // DEBUG
270 
271 #endif // LIBMESH_ENABLE_AMR
272 }
273 
274 
275 
276 void connect_nodes (const connected_elem_set_type & new_connected_elements,
277  const connected_node_set_type & connected_nodes,
278  const connected_node_set_type & new_connected_nodes,
279  connected_node_set_type & newer_connected_nodes)
280 {
281  for (const auto & elem : new_connected_elements)
282  for (auto & n : elem->node_ref_range())
283  if (!connected_nodes.count(&n) &&
284  !new_connected_nodes.count(&n))
285  newer_connected_nodes.insert(&n);
286 }
287 
288 
289 } // anonymous namespace
290 
291 
292 
293 namespace libMesh
294 {
295 
296 
298  processor_id_type pid,
301  connected_elem_set_type & connected_elements)
302 {
303  for (auto & gf :
306  {
307  GhostingFunctor::map_type elements_to_ghost;
308  libmesh_assert(gf);
309  (*gf)(elem_it, elem_end, pid, elements_to_ghost);
310 
311  // We can ignore the CouplingMatrix in ->second, but we
312  // need to ghost all the elements in ->first.
313  for (auto & pr : elements_to_ghost)
314  {
315  const Elem * elem = pr.first;
316  libmesh_assert(elem != remote_elem);
317  libmesh_assert(mesh.elem_ptr(elem->id()) == elem);
318  connected_elements.insert(elem);
319  }
320  }
321 
322  // The GhostingFunctors won't be telling us about the elements from
323  // pid; we need to add those ourselves.
324  for (; elem_it != elem_end; ++elem_it)
325  connected_elements.insert(*elem_it);
326 }
327 
328 
332  connected_elem_set_type & connected_elements)
333 {
334  // None of these parameters are used when !LIBMESH_ENABLE_AMR.
335  libmesh_ignore(mesh, elem_it, elem_end, connected_elements);
336 
337 #ifdef LIBMESH_ENABLE_AMR
338  // Our XdrIO output needs inactive local elements to not have any
339  // remote_elem children. Let's make sure that doesn't happen.
340  //
341  for (const auto & elem : as_range(elem_it, elem_end))
342  {
343  if (elem->has_children())
344  for (auto & child : elem->child_ref_range())
345  if (&child != remote_elem)
346  connected_elements.insert(&child);
347  }
348 #endif // LIBMESH_ENABLE_AMR
349 }
350 
351 
352 void reconnect_nodes (connected_elem_set_type & connected_elements,
353  connected_node_set_type & connected_nodes)
354 {
355  // We're done using the nodes list for element decisions; now
356  // let's reuse it for nodes of the elements we've decided on.
357  connected_nodes.clear();
358 
359  // Use the newer API
360  connect_nodes(connected_elements, connected_nodes, connected_nodes,
361  connected_nodes);
362 }
363 
364 
366  connected_elem_set_type & connected_elements,
367  connected_node_set_type & connected_nodes)
368 {
369  // We haven't examined any of these inputs for dependencies yet, so
370  // let's mark them all as to be examined now.
371  connected_elem_set_type new_connected_elements;
372  connected_node_set_type new_connected_nodes;
373  new_connected_elements.swap(connected_elements);
374  new_connected_nodes.swap(connected_nodes);
375 
376  while (!new_connected_elements.empty() ||
377  !new_connected_nodes.empty())
378  {
379  auto [newer_connected_elements,
380  newer_connected_nodes] =
382  (mesh, connected_elements, connected_nodes,
383  new_connected_elements, new_connected_nodes);
384 
385  // These have now been examined
386  connected_elements.merge(new_connected_elements);
387  connected_nodes.merge(new_connected_nodes);
388 
389  // merge() doesn't guarantee empty() unless there are no
390  // duplicates, which there shouldn't be
391  libmesh_assert(new_connected_elements.empty());
392  libmesh_assert(new_connected_nodes.empty());
393 
394  // These now need to be examined
395  new_connected_elements.swap(newer_connected_elements);
396  new_connected_nodes.swap(newer_connected_nodes);
397  }
398 }
399 
400 
401 std::pair<connected_elem_set_type, connected_node_set_type>
403  const connected_elem_set_type & connected_elements,
404  const connected_node_set_type & connected_nodes,
405  const connected_elem_set_type & new_connected_elements,
406  const connected_node_set_type & new_connected_nodes)
407 {
408  std::pair<connected_elem_set_type, connected_node_set_type> returnval;
409  auto & [newer_connected_elements, newer_connected_nodes] = returnval;
410  connect_element_families(connected_elements, new_connected_elements,
411  newer_connected_elements, &mesh);
412 
413  connect_nodes(new_connected_elements, connected_nodes,
414  new_connected_nodes, newer_connected_nodes);
415 
416  return returnval;
417 }
418 
419 
420 
421 
422 // ------------------------------------------------------------
423 // MeshCommunication class members
425 {
426  // _neighboring_processors.clear();
427 }
428 
429 
430 
431 #ifndef LIBMESH_HAVE_MPI // avoid spurious gcc warnings
432 // ------------------------------------------------------------
434 {
435  // no MPI == one processor, no redistribution
436  return;
437 }
438 
439 #else
440 // ------------------------------------------------------------
442  bool newly_coarsened_only) const
443 {
444  // This method will be called after a new partitioning has been
445  // assigned to the elements. This partitioning was defined in
446  // terms of the active elements, and "trickled down" to the
447  // parents and nodes as to be consistent.
448  //
449  // The point is that the entire concept of local elements is
450  // kinda shaky in this method. Elements which were previously
451  // local may now be assigned to other processors, so we need to
452  // send those off. Similarly, we need to accept elements from
453  // other processors.
454 
455  // This method is also useful in the more limited case of
456  // post-coarsening redistribution: if elements are only ghosting
457  // neighbors of their active elements, but adaptive coarsening
458  // causes an inactive element to become active, then we may need a
459  // copy of that inactive element's neighbors.
460 
461  // The approach is as follows:
462  // (1) send all relevant elements we have stored to their proper homes
463  // (2) receive elements from all processors, watching for duplicates
464  // (3) deleting all nonlocal elements elements
465  // (4) obtaining required ghost elements from neighboring processors
466  libmesh_parallel_only(mesh.comm());
468  libmesh_assert (MeshTools::n_elem(mesh.unpartitioned_elements_begin(),
469  mesh.unpartitioned_elements_end()) == 0);
470 
471  LOG_SCOPE("redistribute()", "MeshCommunication");
472 
473  // Be compatible with both deprecated and corrected MeshBase iterator types
474  typedef std::remove_const<MeshBase::const_element_iterator::value_type>::type nc_v_t;
475 
476  // We're going to sort elements-to-send by pid in one pass, to avoid
477  // sending predicated iterators through the whole mesh N_p times
478  std::unordered_map<processor_id_type, std::vector<nc_v_t>> send_to_pid;
479 
480  const MeshBase::const_element_iterator send_elems_begin =
481 #ifdef LIBMESH_ENABLE_AMR
482  newly_coarsened_only ?
483  mesh.flagged_elements_begin(Elem::JUST_COARSENED) :
484 #endif
485  mesh.active_elements_begin();
486 
487  const MeshBase::const_element_iterator send_elems_end =
488 #ifdef LIBMESH_ENABLE_AMR
489  newly_coarsened_only ?
490  mesh.flagged_elements_end(Elem::JUST_COARSENED) :
491 #endif
492  mesh.active_elements_end();
493 
494  // See what should get sent where. We don't send to ourselves.
495  for (auto & elem : as_range(send_elems_begin, send_elems_end))
496  if (elem->processor_id() != mesh.processor_id())
497  send_to_pid[elem->processor_id()].push_back(elem);
498 
499  std::map<processor_id_type, std::vector<const Node *>> all_nodes_to_send;
500  std::map<processor_id_type, std::vector<const Elem *>> all_elems_to_send;
501 
502  // We may need to send constraint rows too.
503  auto & constraint_rows = mesh.get_constraint_rows();
504  bool have_constraint_rows = !constraint_rows.empty();
505  mesh.comm().broadcast(have_constraint_rows);
506 
507 #ifdef DEBUG
508  const dof_id_type n_constraint_rows =
509  have_constraint_rows ? mesh.n_constraint_rows() : 0;
510 #endif
511 
512  typedef std::vector<std::pair<std::pair<dof_id_type, unsigned int>, Real>>
513  serialized_row_type;
514  std::unordered_map<processor_id_type,
515  std::vector<std::pair<dof_id_type, serialized_row_type>>>
516  all_constraint_rows_to_send;
517 
518  // If we don't have any just-coarsened elements to send to a
519  // pid, then there won't be any nodes or any elements pulled
520  // in by ghosting either, and we're done with this pid.
521  for (const auto & [pid, p_elements] : send_to_pid)
522  {
523  // Build up a list of nodes and elements to send to processor pid.
524  // We will certainly send all the elements assigned to this processor,
525  // but we will also ship off any elements which are required
526  // to be ghosted and any nodes which are used by any of the
527  // above.
528 
529  libmesh_assert(!p_elements.empty());
530 
531  // Be compatible with both deprecated and
532  // corrected MeshBase iterator types
534 
535  v_t * elempp = p_elements.data();
536  v_t * elemend = elempp + p_elements.size();
537 
538 #ifndef LIBMESH_ENABLE_AMR
539  // This parameter is not used when !LIBMESH_ENABLE_AMR.
540  libmesh_ignore(newly_coarsened_only);
541  libmesh_assert(!newly_coarsened_only);
542 #endif
543 
546  (elempp, elemend, Predicates::NotNull<v_t *>());
547 
548  const MeshBase::const_element_iterator elem_end =
550  (elemend, elemend, Predicates::NotNull<v_t *>());
551 
552  connected_elem_set_type elements_to_send;
553 
554  // See which to-be-ghosted elements we need to send
555  query_ghosting_functors (mesh, pid, elem_it, elem_end,
556  elements_to_send);
557 
558  // The inactive elements we need to send should have their
559  // immediate children present.
560  connect_children(mesh, mesh.pid_elements_begin(pid),
561  mesh.pid_elements_end(pid),
562  elements_to_send);
563 
564  // Now see which other elements and nodes they depend on
565  connected_node_set_type connected_nodes;
566  connect_element_dependencies(mesh, elements_to_send,
567  connected_nodes);
568 
569  all_nodes_to_send[pid].assign(connected_nodes.begin(),
570  connected_nodes.end());
571 
572  all_elems_to_send[pid].assign(elements_to_send.begin(),
573  elements_to_send.end());
574 
575  for (auto & [node, row] : constraint_rows)
576  {
577  if (!connected_nodes.count(node))
578  continue;
579 
580  serialized_row_type serialized_row;
581  for (auto [elem_and_node, coef] : row)
582  serialized_row.emplace_back(std::make_pair(elem_and_node.first->id(),
583  elem_and_node.second),
584  coef);
585 
586  all_constraint_rows_to_send[pid].emplace_back
587  (node->id(), std::move(serialized_row));
588  }
589  }
590 
591  // Elem/Node unpack() automatically adds them to the given mesh
592  auto null_node_action = [](processor_id_type, const std::vector<const Node*>&){};
593  auto null_elem_action = [](processor_id_type, const std::vector<const Elem*>&){};
594 
595  // Communicate nodes first since elements will need to attach to them
596  TIMPI::push_parallel_packed_range(mesh.comm(), all_nodes_to_send, &mesh,
597  null_node_action);
598 
599  TIMPI::push_parallel_packed_range(mesh.comm(), all_elems_to_send, &mesh,
600  null_elem_action);
601 
602  // At this point we have all the nodes and elems we need, so we can
603  // communicate any constraint rows that our targets will need.
604  if (have_constraint_rows)
605  {
606  auto constraint_row_action =
607  [&mesh, &constraint_rows]
608  (processor_id_type /* src_pid */,
609  const std::vector<std::pair<dof_id_type, serialized_row_type>> rows)
610  {
611  for (auto & [node_id, serialized_row] : rows)
612  {
614  for (auto [elem_and_node, coef] : serialized_row)
615  row.emplace_back(std::make_pair(mesh.elem_ptr(elem_and_node.first),
616  elem_and_node.second),
617  coef);
618 
619  constraint_rows[mesh.node_ptr(node_id)] = row;
620  }
621  };
622 
624  all_constraint_rows_to_send,
625  constraint_row_action);
626 
627  }
628 
629  // Check on the redistribution consistency
630 #ifdef DEBUG
632 
634 
635  const dof_id_type new_n_constraint_rows =
636  have_constraint_rows ? mesh.n_constraint_rows() : 0;
637 
638  libmesh_assert_equal_to(n_constraint_rows, new_n_constraint_rows);
639 
641 #endif
642 
643  // If we had a point locator, it's invalid now that there are new
644  // elements it can't locate.
646 
647  // Let the mesh handle any other post-redistribute() tasks, like
648  // notifying GhostingFunctors. Be sure we're just calling the base
649  // class method so we don't recurse back into ourselves here.
650  mesh.MeshBase::redistribute();
651 }
652 #endif // LIBMESH_HAVE_MPI
653 
654 
655 
656 #ifndef LIBMESH_HAVE_MPI // avoid spurious gcc warnings
657 // ------------------------------------------------------------
659 {
660  // no MPI == one processor, no need for this method...
661  return;
662 }
663 #else
664 // ------------------------------------------------------------
666 {
667  // Don't need to do anything if there is
668  // only one processor.
669  if (mesh.n_processors() == 1)
670  return;
671 
672  // This function must be run on all processors at once
673  libmesh_parallel_only(mesh.comm());
674 
675  LOG_SCOPE("gather_neighboring_elements()", "MeshCommunication");
676 
677  //------------------------------------------------------------------
678  // The purpose of this function is to provide neighbor data structure
679  // consistency for a parallel, distributed mesh. In libMesh we require
680  // that each local element have access to a full set of valid face
681  // neighbors. In some cases this requires us to store "ghost elements" -
682  // elements that belong to other processors but we store to provide
683  // data structure consistency. Also, it is assumed that any element
684  // with a nullptr neighbor resides on a physical domain boundary. So,
685  // even our "ghost elements" must have non-nullptr neighbors. To handle
686  // this the concept of "RemoteElem" is used - a special construct which
687  // is used to denote that an element has a face neighbor, but we do
688  // not actually store detailed information about that neighbor. This
689  // is required to prevent data structure explosion.
690  //
691  // So when this method is called we should have only local elements.
692  // These local elements will then find neighbors among the local
693  // element set. After this is completed, any element with a nullptr
694  // neighbor has either (i) a face on the physical boundary of the mesh,
695  // or (ii) a neighboring element which lives on a remote processor.
696  // To handle case (ii), we communicate the global node indices connected
697  // to all such faces to our neighboring processors. They then send us
698  // all their elements with a nullptr neighbor that are connected to any
699  // of the nodes in our list.
700  //------------------------------------------------------------------
701 
702  // Let's begin with finding consistent neighbor data information
703  // for all the elements we currently have. We'll use a clean
704  // slate here - clear any existing information, including RemoteElem's.
705  mesh.find_neighbors (/* reset_remote_elements = */ true,
706  /* reset_current_list = */ true);
707 
708  // Get a unique message tag to use in communications
710  element_neighbors_tag = mesh.comm().get_unique_tag();
711 
712  // Now any element with a nullptr neighbor either
713  // (i) lives on the physical domain boundary, or
714  // (ii) lives on an inter-processor boundary.
715  // We will now gather all the elements from adjacent processors
716  // which are of the same state, which should address all the type (ii)
717  // elements.
718 
719  // A list of all the processors which *may* contain neighboring elements.
720  // (for development simplicity, just make this the identity map)
721  std::vector<processor_id_type> adjacent_processors;
722  for (auto pid : make_range(mesh.n_processors()))
723  if (pid != mesh.processor_id())
724  adjacent_processors.push_back (pid);
725 
726 
727  const processor_id_type n_adjacent_processors =
728  cast_int<processor_id_type>(adjacent_processors.size());
729 
730  //-------------------------------------------------------------------------
731  // Let's build a list of all nodes which live on nullptr-neighbor sides.
732  // For simplicity, we will use a set to build the list, then transfer
733  // it to a vector for communication.
734  std::vector<dof_id_type> my_interface_node_list;
735  std::vector<const Elem *> my_interface_elements;
736  {
737  std::set<dof_id_type> my_interface_node_set;
738 
739  // For avoiding extraneous element side construction
740  ElemSideBuilder side_builder;
741 
742  // since parent nodes are a subset of children nodes, this should be sufficient
743  for (const auto & elem : mesh.active_local_element_ptr_range())
744  {
745  libmesh_assert(elem);
746 
747  if (elem->on_boundary()) // denotes *any* side has a nullptr neighbor
748  {
749  my_interface_elements.push_back(elem); // add the element, but only once, even
750  // if there are multiple nullptr neighbors
751  for (auto s : elem->side_index_range())
752  if (elem->neighbor_ptr(s) == nullptr)
753  {
754  const Elem & side = side_builder(*elem, s);
755 
756  for (auto n : make_range(side.n_vertices()))
757  my_interface_node_set.insert (side.node_id(n));
758  }
759  }
760  }
761 
762  my_interface_node_list.reserve (my_interface_node_set.size());
763  my_interface_node_list.insert (my_interface_node_list.end(),
764  my_interface_node_set.begin(),
765  my_interface_node_set.end());
766  }
767 
768  // we will now send my_interface_node_list to all of the adjacent processors.
769  // note that for the time being we will copy the list to a unique buffer for
770  // each processor so that we can use a nonblocking send and not access the
771  // buffer again until the send completes. it is my understanding that the
772  // MPI 2.1 standard seeks to remove this restriction as unnecessary, so in
773  // the future we should change this to send the same buffer to each of the
774  // adjacent processors. - BSK 11/17/2008
775  std::vector<std::vector<dof_id_type>>
776  my_interface_node_xfer_buffers (n_adjacent_processors, my_interface_node_list);
777  std::map<processor_id_type, unsigned char> n_comm_steps;
778 
779  std::vector<Parallel::Request> send_requests (3*n_adjacent_processors);
780  unsigned int current_request = 0;
781 
782  for (unsigned int comm_step=0; comm_step<n_adjacent_processors; comm_step++)
783  {
784  n_comm_steps[adjacent_processors[comm_step]]=1;
785  mesh.comm().send (adjacent_processors[comm_step],
786  my_interface_node_xfer_buffers[comm_step],
787  send_requests[current_request++],
788  element_neighbors_tag);
789  }
790 
791  //-------------------------------------------------------------------------
792  // processor pairings are symmetric - I expect to receive an interface node
793  // list from each processor in adjacent_processors as well!
794  // now we will catch an incoming node list for each of our adjacent processors.
795  //
796  // we are done with the adjacent_processors list - note that it is in general
797  // a superset of the processors we truly share elements with. so let's
798  // clear the superset list, and we will fill it with the true list.
799  adjacent_processors.clear();
800 
801  std::vector<dof_id_type> common_interface_node_list;
802 
803  // we expect two classes of messages -
804  // (1) incoming interface node lists, to which we will reply with our elements
805  // touching nodes in the list, and
806  // (2) replies from the requests we sent off previously.
807  // (2.a) - nodes
808  // (2.b) - elements
809  // so we expect 3 communications from each adjacent processor.
810  // by structuring the communication in this way we hopefully impose no
811  // order on the handling of the arriving messages. in particular, we
812  // should be able to handle the case where we receive a request and
813  // all replies from processor A before even receiving a request from
814  // processor B.
815 
816  for (unsigned int comm_step=0; comm_step<3*n_adjacent_processors; comm_step++)
817  {
818  //------------------------------------------------------------------
819  // catch incoming node list
820  Parallel::Status
821  status(mesh.comm().probe (Parallel::any_source,
822  element_neighbors_tag));
823  const processor_id_type
824  source_pid_idx = cast_int<processor_id_type>(status.source()),
825  dest_pid_idx = source_pid_idx;
826 
827  //------------------------------------------------------------------
828  // first time - incoming request
829  if (n_comm_steps[source_pid_idx] == 1)
830  {
831  n_comm_steps[source_pid_idx]++;
832 
833  mesh.comm().receive (source_pid_idx,
834  common_interface_node_list,
835  element_neighbors_tag);
836 
837  // const std::size_t
838  // their_interface_node_list_size = common_interface_node_list.size();
839 
840  // we now have the interface node list from processor source_pid_idx.
841  // now we can find all of our elements which touch any of these nodes
842  // and send copies back to this processor. however, we can make our
843  // search more efficient by first excluding all the nodes in
844  // their list which are not also contained in
845  // my_interface_node_list. we can do this in place as a set
846  // intersection.
847  common_interface_node_list.erase
848  (std::set_intersection (my_interface_node_list.begin(),
849  my_interface_node_list.end(),
850  common_interface_node_list.begin(),
851  common_interface_node_list.end(),
852  common_interface_node_list.begin()),
853  common_interface_node_list.end());
854 
855  // if (false)
856  // libMesh::out << "[" << mesh.processor_id() << "] "
857  // << "my_interface_node_list.size()=" << my_interface_node_list.size()
858  // << ", [" << source_pid_idx << "] "
859  // << "their_interface_node_list.size()=" << their_interface_node_list_size
860  // << ", common_interface_node_list.size()=" << common_interface_node_list.size()
861  // << std::endl;
862 
863  // Now we need to see which of our elements touch the nodes in the list.
864  // We will certainly send all the active elements which intersect source_pid_idx,
865  // but we will also ship off the other elements in the same family tree
866  // as the active ones for data structure consistency.
867  //
868  // FIXME - shipping full family trees is unnecessary and inefficient.
869  //
870  // We also ship any nodes connected to these elements. Note
871  // some of these nodes and elements may be replicated from
872  // other processors, but that is OK.
873  connected_elem_set_type elements_to_send;
874 
875  // Technically we're not doing reconnect_nodes on this, but
876  // we might as well use the same data structure since the
877  // performance questions ought to be similar
878  connected_node_set_type connected_nodes;
879 
880  // Check for quick return?
881  if (common_interface_node_list.empty())
882  {
883  // let's try to be smart here - if we have no nodes in common,
884  // we cannot share elements. so post the messages expected
885  // from us here and go on about our business.
886  // note that even though these are nonblocking sends
887  // they should complete essentially instantly, because
888  // in all cases the send buffers are empty
889  mesh.comm().send_packed_range (dest_pid_idx,
890  &mesh,
891  connected_nodes.begin(),
892  connected_nodes.end(),
893  send_requests[current_request++],
894  element_neighbors_tag);
895 
896  mesh.comm().send_packed_range (dest_pid_idx,
897  &mesh,
898  elements_to_send.begin(),
899  elements_to_send.end(),
900  send_requests[current_request++],
901  element_neighbors_tag);
902 
903  continue;
904  }
905  // otherwise, this really *is* an adjacent processor.
906  adjacent_processors.push_back(source_pid_idx);
907 
908  std::vector<const Elem *> family_tree;
909 
910  for (auto & elem : my_interface_elements)
911  {
912  std::size_t n_shared_nodes = 0;
913 
914  for (auto n : make_range(elem->n_vertices()))
915  if (std::binary_search (common_interface_node_list.begin(),
916  common_interface_node_list.end(),
917  elem->node_id(n)))
918  {
919  n_shared_nodes++;
920 
921  // TBD - how many nodes do we need to share
922  // before we care? certainly 2, but 1? not
923  // sure, so let's play it safe...
924  if (n_shared_nodes > 0) break;
925  }
926 
927  if (n_shared_nodes) // share at least one node?
928  {
929  elem = elem->top_parent();
930 
931  // avoid a lot of duplicated effort -- if we already have elem
932  // in the set its entire family tree is already in the set.
933  if (!elements_to_send.count(elem))
934  {
935 #ifdef LIBMESH_ENABLE_AMR
936  elem->family_tree(family_tree);
937 #else
938  family_tree.clear();
939  family_tree.push_back(elem);
940 #endif
941  for (const auto & f : family_tree)
942  {
943  elem = f;
944  elements_to_send.insert (elem);
945 
946  for (auto & n : elem->node_ref_range())
947  connected_nodes.insert (&n);
948  }
949  }
950  }
951  }
952 
953  // The elements_to_send and connected_nodes sets now contain all
954  // the elements and nodes we need to send to this processor.
955  // All that remains is to pack up the objects (along with
956  // any boundary conditions) and send the messages off.
957  {
958  libmesh_assert (connected_nodes.empty() || !elements_to_send.empty());
959  libmesh_assert (!connected_nodes.empty() || elements_to_send.empty());
960 
961  // send the nodes off to the destination processor
962  mesh.comm().send_packed_range (dest_pid_idx,
963  &mesh,
964  connected_nodes.begin(),
965  connected_nodes.end(),
966  send_requests[current_request++],
967  element_neighbors_tag);
968 
969  // send the elements off to the destination processor
970  mesh.comm().send_packed_range (dest_pid_idx,
971  &mesh,
972  elements_to_send.begin(),
973  elements_to_send.end(),
974  send_requests[current_request++],
975  element_neighbors_tag);
976  }
977  }
978  //------------------------------------------------------------------
979  // second time - reply of nodes
980  else if (n_comm_steps[source_pid_idx] == 2)
981  {
982  n_comm_steps[source_pid_idx]++;
983 
984  mesh.comm().receive_packed_range (source_pid_idx,
985  &mesh,
987  (Node**)nullptr,
988  element_neighbors_tag);
989  }
990  //------------------------------------------------------------------
991  // third time - reply of elements
992  else if (n_comm_steps[source_pid_idx] == 3)
993  {
994  n_comm_steps[source_pid_idx]++;
995 
996  mesh.comm().receive_packed_range (source_pid_idx,
997  &mesh,
999  (Elem**)nullptr,
1000  element_neighbors_tag);
1001  }
1002  //------------------------------------------------------------------
1003  // fourth time - shouldn't happen
1004  else
1005  {
1006  libMesh::err << "ERROR: unexpected number of replies: "
1007  << n_comm_steps[source_pid_idx]
1008  << std::endl;
1009  }
1010  } // done catching & processing replies associated with tag ~ 100,000pi
1011 
1012  // allow any pending requests to complete
1013  Parallel::wait (send_requests);
1014 
1015  // If we had a point locator, it's invalid now that there are new
1016  // elements it can't locate.
1018 
1019  // We can now find neighbor information for the interfaces between
1020  // local elements and ghost elements.
1021  mesh.find_neighbors (/* reset_remote_elements = */ true,
1022  /* reset_current_list = */ false);
1023 
1024  // Ghost elements may not have correct remote_elem neighbor links,
1025  // and we may not be able to locally infer correct neighbor links to
1026  // remote elements. So we synchronize ghost element neighbor links.
1027  SyncNeighbors nsync(mesh);
1028 
1030  (mesh.comm(), mesh.elements_begin(), mesh.elements_end(), nsync);
1031 }
1032 #endif // LIBMESH_HAVE_MPI
1033 
1034 
1035 #ifndef LIBMESH_HAVE_MPI // avoid spurious gcc warnings
1036 // ------------------------------------------------------------
1038 {
1039  // no MPI == one processor, no need for this method...
1040  return;
1041 }
1042 #else
1044 {
1045 
1046  // Don't need to do anything if all processors already ghost all non-local
1047  // elements.
1048  if (mesh.is_serial())
1049  return;
1050 
1051  // This algorithm uses the MeshBase::flagged_pid_elements_begin/end iterators
1052  // which are only available when AMR is enabled.
1053 #ifndef LIBMESH_ENABLE_AMR
1054  libmesh_error_msg("Calling MeshCommunication::send_coarse_ghosts() requires AMR to be enabled. "
1055  "Please configure libmesh with --enable-amr.");
1056 #else
1057  // When we coarsen elements on a DistributedMesh, we make their
1058  // parents active. This may increase the ghosting requirements on
1059  // the processor which owns the newly-activated parent element. To
1060  // ensure ghosting requirements are satisfied, processors which
1061  // coarsen an element will send all the associated ghosted elements
1062  // to all processors which own any of the coarsened-away-element's
1063  // siblings.
1064  typedef std::unordered_map<processor_id_type, std::vector<Elem *>> ghost_map;
1065  ghost_map coarsening_elements_to_ghost;
1066 
1067  const processor_id_type proc_id = mesh.processor_id();
1068  // Look for just-coarsened elements
1069  for (auto elem : as_range(mesh.flagged_pid_elements_begin(Elem::COARSEN, proc_id),
1070  mesh.flagged_pid_elements_end(Elem::COARSEN, proc_id)))
1071  {
1072  // If it's flagged for coarsening it had better have a parent
1073  libmesh_assert(elem->parent());
1074 
1075  // On a distributed mesh:
1076  // If we don't own this element's parent but we do own it, then
1077  // there is a chance that we are aware of ghost elements which
1078  // the parent's owner needs us to send them.
1079  const processor_id_type their_proc_id = elem->parent()->processor_id();
1080  if (their_proc_id != proc_id)
1081  coarsening_elements_to_ghost[their_proc_id].push_back(elem);
1082  }
1083 
1084  std::map<processor_id_type, std::vector<const Node *>> all_nodes_to_send;
1085  std::map<processor_id_type, std::vector<const Elem *>> all_elems_to_send;
1086 
1087  const processor_id_type n_proc = mesh.n_processors();
1088 
1089  for (processor_id_type p=0; p != n_proc; ++p)
1090  {
1091  if (p == proc_id)
1092  continue;
1093 
1094  connected_elem_set_type elements_to_send;
1095  std::set<const Node *> nodes_to_send;
1096 
1097  if (const auto it = std::as_const(coarsening_elements_to_ghost).find(p);
1098  it != coarsening_elements_to_ghost.end())
1099  {
1100  const std::vector<Elem *> & elems = it->second;
1101  libmesh_assert(elems.size());
1102 
1103  // Make some fake element iterators defining this vector of
1104  // elements
1105  Elem * const * elempp = const_cast<Elem * const *>(elems.data());
1106  Elem * const * elemend = elempp+elems.size();
1107  const MeshBase::const_element_iterator elem_it =
1109  const MeshBase::const_element_iterator elem_end =
1111 
1112  for (auto & gf : as_range(mesh.ghosting_functors_begin(),
1114  {
1115  GhostingFunctor::map_type elements_to_ghost;
1116  libmesh_assert(gf);
1117  (*gf)(elem_it, elem_end, p, elements_to_ghost);
1118 
1119  // We can ignore the CouplingMatrix in ->second, but we
1120  // need to ghost all the elements in ->first.
1121  for (auto & pr : elements_to_ghost)
1122  {
1123  const Elem * elem = pr.first;
1124  libmesh_assert(elem);
1125  while (elem)
1126  {
1127  libmesh_assert(elem != remote_elem);
1128  elements_to_send.insert(elem);
1129  for (auto & n : elem->node_ref_range())
1130  nodes_to_send.insert(&n);
1131  elem = elem->parent();
1132  }
1133  }
1134  }
1135 
1136  all_nodes_to_send[p].assign(nodes_to_send.begin(), nodes_to_send.end());
1137  all_elems_to_send[p].assign(elements_to_send.begin(), elements_to_send.end());
1138  }
1139  }
1140 
1141  // Elem/Node unpack() automatically adds them to the given mesh
1142  auto null_node_action = [](processor_id_type, const std::vector<const Node*>&){};
1143  auto null_elem_action = [](processor_id_type, const std::vector<const Elem*>&){};
1144 
1145  // Communicate nodes first since elements will need to attach to them
1146  TIMPI::push_parallel_packed_range(mesh.comm(), all_nodes_to_send, &mesh,
1147  null_node_action);
1148 
1149  TIMPI::push_parallel_packed_range(mesh.comm(), all_elems_to_send, &mesh,
1150  null_elem_action);
1151 
1152 #endif // LIBMESH_ENABLE_AMR
1153 }
1154 
1155 #endif // LIBMESH_HAVE_MPI
1156 
1157 #ifndef LIBMESH_HAVE_MPI // avoid spurious gcc warnings
1158 // ------------------------------------------------------------
1160 {
1161  // no MPI == one processor, no need for this method...
1162  return;
1163 }
1164 #else
1165 // ------------------------------------------------------------
1167 {
1168  // Don't need to do anything if there is
1169  // only one processor.
1170  if (mesh.n_processors() == 1)
1171  return;
1172 
1173  // This function must be run on all processors at once
1174  libmesh_parallel_only(mesh.comm());
1175 
1176  LOG_SCOPE("broadcast()", "MeshCommunication");
1177 
1178  // Explicitly clear the mesh on all but processor 0.
1179  if (mesh.processor_id() != 0)
1180  mesh.clear();
1181 
1182  // We may have set extra data only on processor 0 in a read()
1187 
1188  // We may have set mapping data only on processor 0 in a read()
1189  unsigned char map_type = mesh.default_mapping_type();
1190  unsigned char map_data = mesh.default_mapping_data();
1191  mesh.comm().broadcast(map_type);
1192  mesh.comm().broadcast(map_data);
1194  mesh.set_default_mapping_data(map_data);
1195 
1196  // Broadcast nodes
1198  mesh.nodes_begin(),
1199  mesh.nodes_end(),
1200  &mesh,
1202 
1203  // Broadcast elements from coarsest to finest, so that child
1204  // elements will see their parents already in place.
1205  //
1206  // When restarting from a checkpoint, we may have elements which are
1207  // assigned to a processor but which have not yet been sent to that
1208  // processor, so we need to use a paranoid n_levels() count and not
1209  // the usual fast algorithm.
1210  const unsigned int n_levels = MeshTools::paranoid_n_levels(mesh);
1211 
1212  for (unsigned int l=0; l != n_levels; ++l)
1214  mesh.level_elements_begin(l),
1215  mesh.level_elements_end(l),
1216  &mesh,
1218 
1219  // Make sure mesh_dimension and elem_dimensions are consistent.
1221 
1222  // Make sure mesh id counts are consistent.
1224 
1225  // We may have constraint rows on IsoGeometric Analysis meshes. We
1226  // don't want to send these along with constrained nodes (like we
1227  // send boundary info for those nodes) because the associated rows'
1228  // elements may not exist at that point.
1229  auto & constraint_rows = mesh.get_constraint_rows();
1230  bool have_constraint_rows = !constraint_rows.empty();
1231  mesh.comm().broadcast(have_constraint_rows);
1232  if (have_constraint_rows)
1233  {
1234  std::map<dof_id_type,
1235  std::vector<std::tuple<dof_id_type, unsigned int, Real>>>
1236  serialized_rows;
1237 
1238  for (auto & row : constraint_rows)
1239  {
1240  const Node * node = row.first;
1241  const dof_id_type rowid = node->id();
1242  libmesh_assert(node == mesh.node_ptr(rowid));
1243 
1244  std::vector<std::tuple<dof_id_type, unsigned int, Real>>
1245  serialized_row;
1246  for (auto & entry : row.second)
1247  serialized_row.push_back
1248  (std::make_tuple(entry.first.first->id(),
1249  entry.first.second, entry.second));
1250 
1251  serialized_rows.emplace(rowid, std::move(serialized_row));
1252  }
1253 
1254  mesh.comm().broadcast(serialized_rows);
1255  if (mesh.processor_id() != 0)
1256  {
1257  constraint_rows.clear();
1258 
1259  for (auto & row : serialized_rows)
1260  {
1261  const dof_id_type rowid = row.first;
1262  const Node * node = mesh.node_ptr(rowid);
1263 
1264  std::vector<std::pair<std::pair<const Elem *, unsigned int>, Real>>
1265  deserialized_row;
1266  for (auto & entry : row.second)
1267  deserialized_row.push_back
1268  (std::make_pair(std::make_pair(mesh.elem_ptr(std::get<0>(entry)),
1269  std::get<1>(entry)),
1270  std::get<2>(entry)));
1271 
1272  constraint_rows.emplace(node, deserialized_row);
1273  }
1274  }
1275  }
1276 
1277  // Broadcast all of the named entity information
1281 
1282  // If we had a point locator, it's invalid now that there are new
1283  // elements it can't locate.
1285 
1288 
1289 #ifdef DEBUG
1290  MeshTools::libmesh_assert_valid_procids<Elem>(mesh);
1291  MeshTools::libmesh_assert_valid_procids<Node>(mesh);
1292 #endif
1293 }
1294 #endif // LIBMESH_HAVE_MPI
1295 
1296 
1297 
1298 #ifndef LIBMESH_HAVE_MPI // avoid spurious gcc warnings
1299 // ------------------------------------------------------------
1301 {
1302  // no MPI == one processor, no need for this method...
1303  return;
1304 }
1305 #else
1306 // ------------------------------------------------------------
1307 void MeshCommunication::gather (const processor_id_type root_id, MeshBase & mesh) const
1308 {
1309  // Check for quick return
1310  if (mesh.n_processors() == 1)
1311  return;
1312 
1313  // This function must be run on all processors at once
1314  libmesh_parallel_only(mesh.comm());
1315 
1316  LOG_SCOPE("(all)gather()", "MeshCommunication");
1317 
1318  // Ensure we don't build too big a buffer at once
1319  static const std::size_t approx_total_buffer_size = 1e8;
1320  const std::size_t approx_each_buffer_size =
1321  approx_total_buffer_size / mesh.comm().size();
1322 
1323  (root_id == DofObject::invalid_processor_id) ?
1324 
1326  mesh.nodes_begin(),
1327  mesh.nodes_end(),
1329  approx_each_buffer_size) :
1330 
1331  mesh.comm().gather_packed_range (root_id,
1332  &mesh,
1333  mesh.nodes_begin(),
1334  mesh.nodes_end(),
1336  approx_each_buffer_size);
1337 
1338  // Gather elements from coarsest to finest, so that child
1339  // elements will see their parents already in place.
1340  const unsigned int n_levels = MeshTools::n_levels(mesh);
1341 
1342  for (unsigned int l=0; l != n_levels; ++l)
1343  (root_id == DofObject::invalid_processor_id) ?
1344 
1346  mesh.level_elements_begin(l),
1347  mesh.level_elements_end(l),
1349  approx_each_buffer_size) :
1350 
1351  mesh.comm().gather_packed_range (root_id,
1352  &mesh,
1353  mesh.level_elements_begin(l),
1354  mesh.level_elements_end(l),
1356  approx_each_buffer_size);
1357 
1358  // If we had a point locator, it's invalid now that there are new
1359  // elements it can't locate.
1361 
1362  // We may have constraint rows on IsoGeometric Analysis meshes. We
1363  // don't want to send these along with constrained nodes (like we
1364  // send boundary info for those nodes) because the associated rows'
1365  // elements may not exist at that point.
1366  auto & constraint_rows = mesh.get_constraint_rows();
1367  bool have_constraint_rows = !constraint_rows.empty();
1368  mesh.comm().max(have_constraint_rows);
1369  if (have_constraint_rows)
1370  {
1371  std::map<dof_id_type,
1372  std::vector<std::tuple<dof_id_type, unsigned int, Real>>>
1373  serialized_rows;
1374 
1375  for (auto & row : constraint_rows)
1376  {
1377  const Node * node = row.first;
1378  const dof_id_type rowid = node->id();
1379  libmesh_assert(node == mesh.node_ptr(rowid));
1380 
1381  std::vector<std::tuple<dof_id_type, unsigned int, Real>>
1382  serialized_row;
1383  for (auto & entry : row.second)
1384  serialized_row.push_back
1385  (std::make_tuple(entry.first.first->id(),
1386  entry.first.second, entry.second));
1387 
1388  serialized_rows.emplace(rowid, std::move(serialized_row));
1389  }
1390 
1391  if (root_id == DofObject::invalid_processor_id)
1392  mesh.comm().set_union(serialized_rows);
1393  else
1394  mesh.comm().set_union(serialized_rows, root_id);
1395 
1396  if (root_id == DofObject::invalid_processor_id ||
1397  root_id == mesh.processor_id())
1398  {
1399  for (auto & row : serialized_rows)
1400  {
1401  const dof_id_type rowid = row.first;
1402  const Node * node = mesh.node_ptr(rowid);
1403 
1404  std::vector<std::pair<std::pair<const Elem *, unsigned int>, Real>>
1405  deserialized_row;
1406  for (auto & entry : row.second)
1407  deserialized_row.push_back
1408  (std::make_pair(std::make_pair(mesh.elem_ptr(std::get<0>(entry)),
1409  std::get<1>(entry)),
1410  std::get<2>(entry)));
1411 
1412  constraint_rows.emplace(node, deserialized_row);
1413  }
1414  }
1415 #ifdef DEBUG
1417 #endif
1418  }
1419 
1420 
1421  // If we are doing an allgather(), perform sanity check on the result.
1422  if (root_id == DofObject::invalid_processor_id)
1423  {
1426  }
1427 
1428  // Inform new elements of their neighbors,
1429  // while resetting all remote_elem links on
1430  // the ranks which did the gather.
1431  if (mesh.allow_find_neighbors())
1433  root_id == mesh.processor_id());
1434 
1435  // All done, but let's make sure it's done correctly
1436 
1437 #ifdef DEBUG
1439 #endif
1440 }
1441 #endif // LIBMESH_HAVE_MPI
1442 
1443 
1444 
1445 // Functor for make_elems_parallel_consistent and
1446 // make_node_ids_parallel_consistent
1447 namespace {
1448 
1449 struct SyncIds
1450 {
1451  typedef dof_id_type datum;
1452  typedef void (MeshBase::*renumber_obj)(dof_id_type, dof_id_type);
1453 
1454  SyncIds(MeshBase & _mesh, renumber_obj _renumberer) :
1455  mesh(_mesh),
1456  renumber(_renumberer) {}
1457 
1459  renumber_obj renumber;
1460  // renumber_obj & renumber;
1461 
1462  // Find the id of each requested DofObject -
1463  // Parallel::sync_* already did the work for us
1464  void gather_data (const std::vector<dof_id_type> & ids,
1465  std::vector<datum> & ids_out) const
1466  {
1467  ids_out = ids;
1468  }
1469 
1470  void act_on_data (const std::vector<dof_id_type> & old_ids,
1471  const std::vector<datum> & new_ids) const
1472  {
1473  for (auto i : index_range(old_ids))
1474  if (old_ids[i] != new_ids[i])
1475  (mesh.*renumber)(old_ids[i], new_ids[i]);
1476  }
1477 };
1478 
1479 
1480 struct SyncNodeIds
1481 {
1482  typedef dof_id_type datum;
1483 
1484  SyncNodeIds(MeshBase & _mesh) :
1485  mesh(_mesh) {}
1486 
1487  MeshBase & mesh;
1488 
1489  // We only know a Node id() is definitive if we own the Node or if
1490  // we're told it's definitive. We keep track of the latter cases by
1491  // putting definitively id'd ghost nodes into this set.
1492  typedef std::unordered_set<const Node *> uset_type;
1493  uset_type definitive_ids;
1494 
1495  // We should never be told two different definitive ids for the same
1496  // node, but let's check on that in debug mode.
1497 #ifdef DEBUG
1498  typedef std::unordered_map<dof_id_type, dof_id_type> umap_type;
1500 #endif
1501 
1502  // Find the id of each requested DofObject -
1503  // Parallel::sync_* already tried to do the work for us, but we can
1504  // only say the result is definitive if we own the DofObject or if
1505  // we were given the definitive result from another processor.
1506  void gather_data (const std::vector<dof_id_type> & ids,
1507  std::vector<datum> & ids_out) const
1508  {
1509  ids_out.clear();
1510  ids_out.resize(ids.size(), DofObject::invalid_id);
1511 
1512  for (auto i : index_range(ids))
1513  {
1514  const dof_id_type id = ids[i];
1515  const Node * node = mesh.query_node_ptr(id);
1516  if (node && (node->processor_id() == mesh.processor_id() ||
1517  definitive_ids.count(node)))
1518  ids_out[i] = id;
1519  }
1520  }
1521 
1522  bool act_on_data (const std::vector<dof_id_type> & old_ids,
1523  const std::vector<datum> & new_ids)
1524  {
1525  bool data_changed = false;
1526  for (auto i : index_range(old_ids))
1527  {
1528  const dof_id_type new_id = new_ids[i];
1529 
1530  const dof_id_type old_id = old_ids[i];
1531 
1532  Node * node = mesh.query_node_ptr(old_id);
1533 
1534  // If we can't find the node we were asking about, another
1535  // processor must have already given us the definitive id
1536  // for it
1537  if (!node)
1538  {
1539  // But let's check anyway in debug mode
1540 #ifdef DEBUG
1542  (definitive_renumbering.count(old_id));
1543  libmesh_assert_equal_to
1544  (new_id, definitive_renumbering[old_id]);
1545 #endif
1546  continue;
1547  }
1548 
1549  // If we asked for an id but there's no definitive id ready
1550  // for us yet, then we can't quit trying to sync yet.
1551  if (new_id == DofObject::invalid_id)
1552  {
1553  // But we might have gotten a definitive id from a
1554  // different request
1555  if (!definitive_ids.count(mesh.node_ptr(old_id)))
1556  data_changed = true;
1557  }
1558  else
1559  {
1560  if (node->processor_id() != mesh.processor_id())
1561  definitive_ids.insert(node);
1562  if (old_id != new_id)
1563  {
1564 #ifdef DEBUG
1566  (!definitive_renumbering.count(old_id));
1567  definitive_renumbering[old_id] = new_id;
1568 #endif
1569  mesh.renumber_node(old_id, new_id);
1570  data_changed = true;
1571  }
1572  }
1573  }
1574  return data_changed;
1575  }
1576 };
1577 
1578 
1579 #ifdef LIBMESH_ENABLE_AMR
1580 struct SyncPLevels
1581 {
1582  typedef std::pair<unsigned char,unsigned char> datum;
1583 
1584  SyncPLevels(MeshBase & _mesh) :
1585  mesh(_mesh) {}
1586 
1587  MeshBase & mesh;
1588 
1589  // Find the p_level of each requested Elem
1590  void gather_data (const std::vector<dof_id_type> & ids,
1591  std::vector<datum> & ids_out) const
1592  {
1593  ids_out.reserve(ids.size());
1594 
1595  for (const auto & id : ids)
1596  {
1597  Elem & elem = mesh.elem_ref(id);
1598  ids_out.push_back
1599  (std::make_pair(cast_int<unsigned char>(elem.p_level()),
1600  static_cast<unsigned char>(elem.p_refinement_flag())));
1601  }
1602  }
1603 
1604  void act_on_data (const std::vector<dof_id_type> & old_ids,
1605  const std::vector<datum> & new_p_levels) const
1606  {
1607  for (auto i : index_range(old_ids))
1608  {
1609  Elem & elem = mesh.elem_ref(old_ids[i]);
1610  // Make sure these are consistent
1612  (new_p_levels[i].first,
1613  static_cast<Elem::RefinementState>(new_p_levels[i].second));
1614  // Make sure parents' levels are consistent
1615  elem.set_p_level(new_p_levels[i].first);
1616  }
1617  }
1618 };
1619 #endif // LIBMESH_ENABLE_AMR
1620 
1621 
1622 #ifdef LIBMESH_ENABLE_UNIQUE_ID
1623 template <typename DofObjSubclass>
1624 struct SyncUniqueIds
1625 {
1626  typedef unique_id_type datum;
1627  typedef DofObjSubclass* (MeshBase::*query_obj)(const dof_id_type);
1628 
1629  SyncUniqueIds(MeshBase &_mesh, query_obj _querier) :
1630  mesh(_mesh),
1631  query(_querier) {}
1632 
1633  MeshBase & mesh;
1634  query_obj query;
1635 
1636  // Find the id of each requested DofObject -
1637  // Parallel::sync_* already did the work for us
1638  void gather_data (const std::vector<dof_id_type> & ids,
1639  std::vector<datum> & ids_out) const
1640  {
1641  ids_out.reserve(ids.size());
1642 
1643  for (const auto & id : ids)
1644  {
1645  DofObjSubclass * d = (mesh.*query)(id);
1646  libmesh_assert(d);
1647  ids_out.push_back(d->unique_id());
1648  }
1649  }
1650 
1651  void act_on_data (const std::vector<dof_id_type> & ids,
1652  const std::vector<datum> & unique_ids) const
1653  {
1654  for (auto i : index_range(ids))
1655  {
1656  DofObjSubclass * d = (mesh.*query)(ids[i]);
1657  libmesh_assert(d);
1658  d->set_unique_id(unique_ids[i]);
1659  }
1660  }
1661 };
1662 #endif // LIBMESH_ENABLE_UNIQUE_ID
1663 
1664 template <typename DofObjSubclass>
1665 struct SyncBCIds
1666 {
1667  typedef std::vector<boundary_id_type> datum;
1668 
1669  SyncBCIds(MeshBase &_mesh) :
1670  mesh(_mesh) {}
1671 
1672  MeshBase & mesh;
1673 
1674  // Find the id of each requested DofObject -
1675  // Parallel::sync_* already did the work for us
1676  void gather_data (const std::vector<dof_id_type> & ids,
1677  std::vector<datum> & ids_out) const
1678  {
1679  ids_out.reserve(ids.size());
1680 
1681  const BoundaryInfo & boundary_info = mesh.get_boundary_info();
1682 
1683  for (const auto & id : ids)
1684  {
1685  Node * n = mesh.query_node_ptr(id);
1686  libmesh_assert(n);
1687  std::vector<boundary_id_type> bcids;
1688  boundary_info.boundary_ids(n, bcids);
1689  ids_out.push_back(std::move(bcids));
1690  }
1691  }
1692 
1693  void act_on_data (const std::vector<dof_id_type> & ids,
1694  const std::vector<datum> & bcids) const
1695  {
1696  BoundaryInfo & boundary_info = mesh.get_boundary_info();
1697 
1698  for (auto i : index_range(ids))
1699  {
1700  Node * n = mesh.query_node_ptr(ids[i]);
1701  libmesh_assert(n);
1702  boundary_info.add_node(n, bcids[i]);
1703  }
1704  }
1705 };
1706 
1707 }
1708 
1709 
1710 
1711 // ------------------------------------------------------------
1713 {
1714  // This function must be run on all processors at once
1715  libmesh_parallel_only(mesh.comm());
1716 
1717  // We need to agree on which processor owns every node, but we can't
1718  // easily assert that here because we don't currently agree on which
1719  // id every node has, and some of our temporary ids on unrelated
1720  // nodes will "overlap".
1721 //#ifdef DEBUG
1722 // MeshTools::libmesh_assert_parallel_consistent_procids<Node> (mesh);
1723 //#endif // DEBUG
1724 
1725  LOG_SCOPE ("make_node_ids_parallel_consistent()", "MeshCommunication");
1726 
1727  SyncNodeIds syncids(mesh);
1729  (mesh, mesh.elements_begin(), mesh.elements_end(),
1731 
1732  // At this point, with both ids and processor ids synced, we can
1733  // finally check for topological consistency of node processor ids.
1734 #ifdef DEBUG
1736 #endif
1737 }
1738 
1739 
1740 
1742 {
1743  // Avoid unused variable warnings if unique ids aren't enabled.
1745 
1746  // This function must be run on all processors at once
1747  libmesh_parallel_only(mesh.comm());
1748 
1749 #ifdef LIBMESH_ENABLE_UNIQUE_ID
1750  LOG_SCOPE ("make_node_unique_ids_parallel_consistent()", "MeshCommunication");
1751 
1752  SyncUniqueIds<Node> syncuniqueids(mesh, &MeshBase::query_node_ptr);
1754  mesh.nodes_begin(),
1755  mesh.nodes_end(),
1756  syncuniqueids);
1757 
1758 #endif
1759 }
1760 
1761 
1763 {
1764  // Avoid unused variable warnings if unique ids aren't enabled.
1766 
1767  // This function must be run on all processors at once
1768  libmesh_parallel_only(mesh.comm());
1769 
1770  LOG_SCOPE ("make_node_bcids_parallel_consistent()", "MeshCommunication");
1771 
1772  SyncBCIds<Node> syncbcids(mesh);
1774  mesh.nodes_begin(),
1775  mesh.nodes_end(),
1776  syncbcids);
1777 }
1778 
1779 
1780 
1781 
1782 
1783 // ------------------------------------------------------------
1785 {
1786  // This function must be run on all processors at once
1787  libmesh_parallel_only(mesh.comm());
1788 
1789  LOG_SCOPE ("make_elems_parallel_consistent()", "MeshCommunication");
1790 
1791  SyncIds syncids(mesh, &MeshBase::renumber_elem);
1793  (mesh, mesh.active_elements_begin(),
1794  mesh.active_elements_end(), syncids);
1795 
1796 #ifdef LIBMESH_ENABLE_UNIQUE_ID
1797  SyncUniqueIds<Elem> syncuniqueids(mesh, &MeshBase::query_elem_ptr);
1799  (mesh.comm(), mesh.active_elements_begin(),
1800  mesh.active_elements_end(), syncuniqueids);
1801 #endif
1802 }
1803 
1804 
1805 
1806 // ------------------------------------------------------------
1807 #ifdef LIBMESH_ENABLE_AMR
1809 {
1810  // This function must be run on all processors at once
1811  libmesh_parallel_only(mesh.comm());
1812 
1813  LOG_SCOPE ("make_p_levels_parallel_consistent()", "MeshCommunication");
1814 
1815  SyncPLevels syncplevels(mesh);
1817  (mesh.comm(), mesh.elements_begin(), mesh.elements_end(),
1818  syncplevels);
1819 }
1820 #endif // LIBMESH_ENABLE_AMR
1821 
1822 
1823 
1824 // Functors for make_node_proc_ids_parallel_consistent
1825 namespace {
1826 
1827 struct SyncProcIds
1828 {
1829  typedef processor_id_type datum;
1830 
1831  SyncProcIds(MeshBase & _mesh) : mesh(_mesh) {}
1832 
1833  MeshBase & mesh;
1834 
1835  // ------------------------------------------------------------
1836  void gather_data (const std::vector<dof_id_type> & ids,
1837  std::vector<datum> & data)
1838  {
1839  // Find the processor id of each requested node
1840  data.resize(ids.size());
1841 
1842  for (auto i : index_range(ids))
1843  {
1844  // Look for this point in the mesh
1845  if (ids[i] != DofObject::invalid_id)
1846  {
1847  Node & node = mesh.node_ref(ids[i]);
1848 
1849  // Return the node's correct processor id,
1850  data[i] = node.processor_id();
1851  }
1852  else
1854  }
1855  }
1856 
1857  // ------------------------------------------------------------
1858  bool act_on_data (const std::vector<dof_id_type> & ids,
1859  const std::vector<datum> proc_ids)
1860  {
1861  bool data_changed = false;
1862 
1863  // Set the ghost node processor ids we've now been informed of
1864  for (auto i : index_range(ids))
1865  {
1866  Node & node = mesh.node_ref(ids[i]);
1867 
1868  // We may not have ids synched when this synchronization is done, so we
1869  // *can't* use id to load-balance processor id properly; we have to use
1870  // the old heuristic of choosing the smallest valid processor id.
1871  //
1872  // If someone tells us our node processor id is too low, then
1873  // they're wrong. If they tell us our node processor id is
1874  // too high, then we're wrong.
1875  if (node.processor_id() > proc_ids[i])
1876  {
1877  data_changed = true;
1878  node.processor_id() = proc_ids[i];
1879  }
1880  }
1881 
1882  return data_changed;
1883  }
1884 };
1885 
1886 
1887 struct ElemNodesMaybeNew
1888 {
1889  ElemNodesMaybeNew() {}
1890 
1891  bool operator() (const Elem * elem) const
1892  {
1893  // If this element was just refined then it may have new nodes we
1894  // need to work on
1895 #ifdef LIBMESH_ENABLE_AMR
1896  if (elem->refinement_flag() == Elem::JUST_REFINED)
1897  return true;
1898 #endif
1899 
1900  // If this element has remote_elem neighbors then there may have
1901  // been refinement of those neighbors that affect its nodes'
1902  // processor_id()
1903  for (auto neigh : elem->neighbor_ptr_range())
1904  if (neigh == remote_elem)
1905  return true;
1906  return false;
1907  }
1908 };
1909 
1910 
1911 struct NodeWasNew
1912 {
1913  NodeWasNew(const MeshBase & mesh)
1914  {
1915  for (const auto & node : mesh.node_ptr_range())
1917  was_new.insert(node);
1918  }
1919 
1920  bool operator() (const Elem * elem, unsigned int local_node_num) const
1921  {
1922  if (was_new.count(elem->node_ptr(local_node_num)))
1923  return true;
1924  return false;
1925  }
1926 
1927  std::unordered_set<const Node *> was_new;
1928 };
1929 
1930 }
1931 
1932 
1933 
1934 // ------------------------------------------------------------
1936 {
1937  LOG_SCOPE ("make_node_proc_ids_parallel_consistent()", "MeshCommunication");
1938 
1939  // This function must be run on all processors at once
1940  libmesh_parallel_only(mesh.comm());
1941 
1942  // When this function is called, each section of a parallelized mesh
1943  // should be in the following state:
1944  //
1945  // All nodes should have the exact same physical location on every
1946  // processor where they exist.
1947  //
1948  // Local nodes should have unique authoritative ids,
1949  // and processor ids consistent with all processors which own
1950  // an element touching them.
1951  //
1952  // Ghost nodes touching local elements should have processor ids
1953  // consistent with all processors which own an element touching
1954  // them.
1955  SyncProcIds sync(mesh);
1957  (mesh, mesh.elements_begin(), mesh.elements_end(),
1959 }
1960 
1961 
1962 
1963 // ------------------------------------------------------------
1965 {
1966  LOG_SCOPE ("make_new_node_proc_ids_parallel_consistent()", "MeshCommunication");
1967 
1968  // This function must be run on all processors at once
1969  libmesh_parallel_only(mesh.comm());
1970 
1971  // When this function is called, each section of a parallelized mesh
1972  // should be in the following state:
1973  //
1974  // Local nodes should have unique authoritative ids,
1975  // and new nodes should be unpartitioned.
1976  //
1977  // New ghost nodes touching local elements should be unpartitioned.
1978 
1979  // We may not have consistent processor ids for new nodes (because a
1980  // node may be old and partitioned on one processor but new and
1981  // unpartitioned on another) when we start
1982 #ifdef DEBUG
1984  // MeshTools::libmesh_assert_parallel_consistent_new_node_procids(mesh);
1985 #endif
1986 
1987  // We have two kinds of new nodes. *NEW* nodes are unpartitioned on
1988  // all processors: we need to use a id-independent (i.e. dumb)
1989  // heuristic to partition them. But "new" nodes are newly created
1990  // on some processors (when ghost elements are refined) yet
1991  // correspond to existing nodes on other processors: we need to use
1992  // the existing processor id for them.
1993  //
1994  // A node which is "new" on one processor will be associated with at
1995  // least one ghost element, and we can just query that ghost
1996  // element's owner to find out the correct processor id.
1997 
1998  auto node_unpartitioned =
1999  [](const Elem * elem, unsigned int local_node_num)
2000  { return elem->node_ref(local_node_num).processor_id() ==
2002 
2003  SyncProcIds sync(mesh);
2004 
2006  (mesh, mesh.not_local_elements_begin(),
2007  mesh.not_local_elements_end(), Parallel::SyncEverything(),
2008  node_unpartitioned, sync);
2009 
2010  // Nodes should now be unpartitioned iff they are truly new; those
2011  // are the *only* nodes we will touch.
2012 #ifdef DEBUG
2014 #endif
2015 
2016  NodeWasNew node_was_new(mesh);
2017 
2018  // Set the lowest processor id we can on truly new nodes
2019  for (auto & elem : mesh.element_ptr_range())
2020  for (auto & node : elem->node_ref_range())
2021  if (node_was_new.was_new.count(&node))
2022  {
2023  processor_id_type & pid = node.processor_id();
2024  pid = std::min(pid, elem->processor_id());
2025  }
2026 
2027  // Then finally see if other processors have a lower option
2029  (mesh, mesh.elements_begin(), mesh.elements_end(),
2030  ElemNodesMaybeNew(), node_was_new, sync);
2031 
2032  // We should have consistent processor ids when we're done.
2033 #ifdef DEBUG
2036 #endif
2037 }
2038 
2039 
2040 
2041 // ------------------------------------------------------------
2043 {
2044  // This function must be run on all processors at once
2045  libmesh_parallel_only(mesh.comm());
2046 
2047  // When this function is called, each section of a parallelized mesh
2048  // should be in the following state:
2049  //
2050  // Element ids and locations should be consistent on every processor
2051  // where they exist.
2052  //
2053  // All nodes should have the exact same physical location on every
2054  // processor where they exist.
2055  //
2056  // Local nodes should have unique authoritative ids,
2057  // and processor ids consistent with all processors which own
2058  // an element touching them.
2059  //
2060  // Ghost nodes touching local elements should have processor ids
2061  // consistent with all processors which own an element touching
2062  // them.
2063  //
2064  // Ghost nodes should have ids which are either already correct
2065  // or which are in the "unpartitioned" id space.
2066 
2067  // First, let's sync up processor ids. Some of these processor ids
2068  // may be "wrong" from coarsening, but they're right in the sense
2069  // that they'll tell us who has the authoritative dofobject ids for
2070  // each node.
2071 
2073 
2074  // Second, sync up dofobject ids.
2076 
2077  // Third, sync up dofobject unique_ids if applicable.
2079 
2080  // Finally, correct the processor ids to make DofMap happy
2082 }
2083 
2084 
2085 
2086 // ------------------------------------------------------------
2088 {
2089  // This function must be run on all processors at once
2090  libmesh_parallel_only(mesh.comm());
2091 
2092  // When this function is called, each section of a parallelized mesh
2093  // should be in the following state:
2094  //
2095  // All nodes should have the exact same physical location on every
2096  // processor where they exist.
2097  //
2098  // Local nodes should have unique authoritative ids,
2099  // and new nodes should be unpartitioned.
2100  //
2101  // New ghost nodes touching local elements should be unpartitioned.
2102  //
2103  // New ghost nodes should have ids which are either already correct
2104  // or which are in the "unpartitioned" id space.
2105  //
2106  // Non-new nodes should have correct ids and processor ids already.
2107 
2108  // First, let's sync up new nodes' processor ids.
2109 
2111 
2112  // Second, sync up dofobject ids.
2114 
2115  // Third, sync up dofobject unique_ids if applicable.
2117 
2118  // Fourth, sync up any nodal boundary conditions
2120 
2121  // Finally, correct the processor ids to make DofMap happy
2123 }
2124 
2125 
2126 
2127 // ------------------------------------------------------------
2128 void
2130  const std::set<Elem *> & extra_ghost_elem_ids) const
2131 {
2132  // The mesh should know it's about to be parallelized
2134 
2135  LOG_SCOPE("delete_remote_elements()", "MeshCommunication");
2136 
2137 #ifdef DEBUG
2138  // We expect maximum ids to be in sync so we can use them to size
2139  // vectors
2142  const dof_id_type par_max_node_id = mesh.parallel_max_node_id();
2143  const dof_id_type par_max_elem_id = mesh.parallel_max_elem_id();
2144  libmesh_assert_equal_to (par_max_node_id, mesh.max_node_id());
2145  libmesh_assert_equal_to (par_max_elem_id, mesh.max_elem_id());
2146  const dof_id_type n_constraint_rows = mesh.n_constraint_rows();
2147 #endif
2148 
2149  connected_elem_set_type elements_to_keep;
2150 
2151  // Don't delete elements that we were explicitly told not to
2152  for (const auto & elem : extra_ghost_elem_ids)
2153  {
2154  std::vector<const Elem *> active_family;
2155 #ifdef LIBMESH_ENABLE_AMR
2156  if (!elem->subactive())
2157  elem->active_family_tree(active_family);
2158  else
2159 #endif
2160  active_family.push_back(elem);
2161 
2162  for (const auto & f : active_family)
2163  elements_to_keep.insert(f);
2164  }
2165 
2166  // See which elements we still need to keep ghosted, given that
2167  // we're keeping local and unpartitioned elements.
2169  (mesh, mesh.processor_id(),
2170  mesh.active_pid_elements_begin(mesh.processor_id()),
2171  mesh.active_pid_elements_end(mesh.processor_id()),
2172  elements_to_keep);
2175  mesh.active_pid_elements_begin(DofObject::invalid_processor_id),
2176  mesh.active_pid_elements_end(DofObject::invalid_processor_id),
2177  elements_to_keep);
2178 
2179  // The inactive elements we need to send should have their
2180  // immediate children present.
2181  connect_children(mesh, mesh.pid_elements_begin(mesh.processor_id()),
2182  mesh.pid_elements_end(mesh.processor_id()),
2183  elements_to_keep);
2185  mesh.pid_elements_begin(DofObject::invalid_processor_id),
2186  mesh.pid_elements_end(DofObject::invalid_processor_id),
2187  elements_to_keep);
2188 
2189  // And see which elements and nodes they depend on
2190  connected_node_set_type connected_nodes;
2191  connect_element_dependencies(mesh, elements_to_keep, connected_nodes);
2192 
2193  // Delete all the elements we have no reason to save,
2194  // starting with the most refined so that the mesh
2195  // is valid at all intermediate steps
2196  unsigned int n_levels = MeshTools::n_levels(mesh);
2197 
2198  for (int l = n_levels - 1; l >= 0; --l)
2199  for (auto & elem : as_range(mesh.level_elements_begin(l),
2200  mesh.level_elements_end(l)))
2201  {
2202  libmesh_assert (elem);
2203  // Make sure we don't leave any invalid pointers
2204  const bool keep_me = elements_to_keep.count(elem);
2205 
2206  if (!keep_me)
2207  elem->make_links_to_me_remote();
2208 
2209  // delete_elem doesn't currently invalidate element
2210  // iterators... that had better not change
2211  if (!keep_me)
2212  mesh.delete_elem(elem);
2213  }
2214 
2215  // Delete all the nodes we have no reason to save
2216  for (auto & node : mesh.node_ptr_range())
2217  {
2218  libmesh_assert(node);
2219  if (!connected_nodes.count(node))
2220  {
2221  libmesh_assert_not_equal_to(node->processor_id(),
2222  mesh.processor_id());
2223  mesh.delete_node(node);
2224  }
2225  }
2226 
2227  // If we had a point locator, it's invalid now that some of the
2228  // elements it pointed to have been deleted.
2230 
2231  // We now have all remote elements and nodes deleted; our ghosting
2232  // functors should be ready to delete any now-redundant cached data
2233  // they use too.
2235  gf->delete_remote_elements();
2236 
2237 #ifdef DEBUG
2238  const dof_id_type n_new_constraint_rows = mesh.n_constraint_rows();
2239  libmesh_assert_equal_to(n_constraint_rows, n_new_constraint_rows);
2240 
2243 #endif
2244 }
2245 
2246 } // namespace libMesh
GhostingFunctorIterator ghosting_functors_begin() const
Beginning of range of ghosting functors.
Definition: mesh_base.h:1462
OStreamProxy err
void set_p_level(const unsigned int p)
Sets the value of the p-refinement level for the element.
void gather_packed_range(const unsigned int root_id, Context *context, Iter range_begin, const Iter range_end, OutputIter out, std::size_t approx_buffer_size=1000000) const
RefinementState refinement_flag() const
Definition: elem.h:3224
void libmesh_assert_topology_consistent_procids< Node >(const MeshBase &mesh)
Definition: mesh_tools.C:1563
const Elem * parent() const
Definition: elem.h:3044
void broadcast_packed_range(const Context *context1, Iter range_begin, const Iter range_end, OutputContext *context2, OutputIter out, const unsigned int root_id=0, std::size_t approx_buffer_size=1000000) const
void make_node_unique_ids_parallel_consistent(MeshBase &)
Assuming all unique_ids on local nodes are globally unique, and assuming all processor ids are parall...
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
virtual void renumber_node(dof_id_type old_id, dof_id_type new_id)=0
Changes the id of node old_id, both by changing node(old_id)->id() and by moving node(old_id) in the ...
std::vector< std::string > _elem_integer_names
The array of names for integer data associated with each element in the mesh.
Definition: mesh_base.h:2338
const Elem * interior_parent() const
Definition: elem.C:1160
void reconnect_nodes(connected_elem_set_type &connected_elements, connected_node_set_type &connected_nodes)
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
IntRange< unsigned short > side_index_range() const
Definition: elem.h:2724
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
The definition of the const_element_iterator struct.
Definition: mesh_base.h:2521
const Elem * top_parent() const
Definition: elem.h:3070
std::vector< std::pair< std::pair< const Elem *, unsigned int >, Real > > constraint_rows_mapped_type
Definition: mesh_base.h:1899
MessageTag get_unique_tag(int tagvalue=MessageTag::invalid_tag) const
void make_elems_parallel_consistent(MeshBase &)
Copy ids of ghost elements from their local processors.
RefinementState p_refinement_flag() const
Definition: elem.h:3240
void libmesh_assert_valid_refinement_tree(const MeshBase &mesh)
A function for verifying that elements on this processor have valid descendants and consistent active...
Definition: mesh_tools.C:1627
std::unordered_set< const Node * > was_new
virtual void find_neighbors(const bool reset_remote_elements=false, const bool reset_current_list=true, const bool assert_valid=true)=0
Locate element face (edge in 2D) neighbors.
void clear()
Clears all data structures and resets to a pristine state.
void family_tree(std::vector< const Elem *> &family, bool reset=true) const
Fills the vector family with the children of this element, recursively.
Definition: elem.C:2110
This is the base class from which all geometric element types are derived.
Definition: elem.h:94
MeshBase & mesh
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
void active_family_tree(std::vector< const Elem *> &active_family, bool reset=true) const
Same as the family_tree() member, but only adds the active children.
Definition: elem.C:2142
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
unsigned int p_level() const
Definition: elem.h:3122
void allgather_packed_range(Context *context, Iter range_begin, const Iter range_end, OutputIter out, std::size_t approx_buffer_size=1000000) const
void boundary_ids(const Node *node, std::vector< boundary_id_type > &vec_to_fill) const
Fills a user-provided std::vector with the boundary ids associated with Node node.
std::map< const Elem *, const CouplingMatrix *, CompareDofObjectsByPIDAndThenID > map_type
What elements do we care about and what variables do we care about on each element?
void make_node_bcids_parallel_consistent(MeshBase &)
Assuming all processor ids are parallel consistent, this function makes all ghost boundary ids on nod...
GhostingFunctorIterator ghosting_functors_end() const
End of range of ghosting functors.
Definition: mesh_base.h:1468
void make_links_to_me_remote()
Resets this element&#39;s neighbors&#39; appropriate neighbor pointers and its parent&#39;s and children&#39;s approp...
Definition: elem.C:1542
The libMesh namespace provides an interface to certain functionality in the library.
const BoundaryInfo & get_boundary_info() const
The information about boundary ids on the mesh.
Definition: mesh_base.h:170
std::vector< std::string > _node_integer_names
The array of names for integer data associated with each node in the mesh.
Definition: mesh_base.h:2350
void send_packed_range(const unsigned int dest_processor_id, const Context *context, Iter range_begin, const Iter range_end, const MessageTag &tag=no_tag, std::size_t approx_buffer_size=1000000) const
dof_id_type n_constraint_rows() const
Definition: mesh_base.C:2431
Used to iterate over non-nullptr entries in a container.
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
unsigned int paranoid_n_levels(const MeshBase &mesh)
Definition: mesh_tools.C:850
ElemMappingType default_mapping_type() const
Returns the default master space to physical space mapping basis functions to be used on newly added ...
Definition: mesh_base.h:931
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
MPI_Status status
processor_id_type size() const
void push_parallel_vector_data(const Communicator &comm, MapToVectors &&data, const ActionFunctor &act_on_data)
uint8_t processor_id_type
std::map< boundary_id_type, std::string > & set_sideset_name_map()
processor_id_type n_processors() const
virtual bool is_serial() const
Definition: mesh_base.h:347
void libmesh_ignore(const Args &...)
void add_node(const Node *node, const boundary_id_type id)
Add Node node with boundary id id to the boundary information data structures.
Status receive(const unsigned int dest_processor_id, T &buf, const MessageTag &tag=any_tag) const
void make_new_node_proc_ids_parallel_consistent(MeshBase &)
Assuming all processor ids on nodes touching local elements are parallel consistent, this function makes processor ids on new nodes on other processors parallel consistent as well.
virtual void delete_elem(Elem *e)=0
Removes element e from the mesh.
const Node & node_ref(const unsigned int i) const
Definition: elem.h:2535
dof_id_type id() const
Definition: dof_object.h:819
void query_ghosting_functors(const MeshBase &mesh, processor_id_type pid, MeshBase::const_element_iterator elem_it, MeshBase::const_element_iterator elem_end, connected_elem_set_type &connected_elements)
static constexpr dof_id_type invalid_id
An invalid id to distinguish an uninitialized DofObject.
Definition: dof_object.h:473
void push_parallel_packed_range(const Communicator &comm, MapToContainers &&data, Context *context, const ActionFunctor &act_on_data)
void receive_packed_range(const unsigned int dest_processor_id, Context *context, OutputIter out, const T *output_type, const MessageTag &tag=any_tag) const
unsigned char default_mapping_data() const
Returns any default data value used by the master space to physical space mapping.
Definition: mesh_base.h:949
virtual void update_parallel_id_counts()=0
Updates parallel caches so that methods like n_elem() accurately reflect changes on other processors...
void sync_node_data_by_element_id(MeshBase &mesh, const MeshBase::const_element_iterator &range_begin, const MeshBase::const_element_iterator &range_end, const ElemCheckFunctor &elem_check, const NodeCheckFunctor &node_check, SyncFunctor &sync)
Synchronize data about a range of ghost nodes uniquely identified by an element id and local node id...
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
status probe(const unsigned int src_processor_id, const MessageTag &tag=any_tag) const
void cache_elem_data()
Definition: mesh_base.C:1959
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
void make_p_levels_parallel_consistent(MeshBase &)
Copy p levels of ghost elements from their local processors.
void set_default_mapping_type(const ElemMappingType type)
Set the default master space to physical space mapping basis functions to be used on newly added elem...
Definition: mesh_base.h:940
virtual dof_id_type max_elem_id() const =0
void clear_point_locator()
Releases the current PointLocator object.
Definition: mesh_base.C:1859
The BoundaryInfo class contains information relevant to boundary conditions including storing faces...
Definition: boundary_info.h:57
void family_tree(T elem, std::vector< T > &family, bool reset=true)
Definition: elem_internal.h:41
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.
Helper for building element sides that minimizes the construction of new elements.
void allow_find_neighbors(bool allow)
If false is passed then this mesh will no longer work to find element neighbors when being prepared f...
Definition: mesh_base.h:1352
void hack_p_level_and_refinement_flag(const unsigned int p, RefinementState pflag)
Sets the value of the p-refinement level for the element without altering the p-level of its ancestor...
Definition: elem.h:3289
std::map< subdomain_id_type, std::string > & set_subdomain_name_map()
Definition: mesh_base.h:1894
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 set_neighbor(const unsigned int i, Elem *n)
Assigns n as the neighbor.
Definition: elem.h:2632
The DistributedMesh class is derived from the MeshBase class, and is intended to provide identical fu...
virtual void clear()
Deletes all the element and node data that is currently stored.
Definition: mesh_base.C:1029
void broadcast(T &data, const unsigned int root_id=0, const bool identical_sizes=false) const
umap_type definitive_renumbering
void gather_neighboring_elements(DistributedMesh &) const
bool on_boundary() const
Definition: elem.h:2923
void libmesh_assert_parallel_consistent_procids< Node >(const MeshBase &mesh)
Definition: mesh_tools.C:2218
A do-nothing class for templated methods that expect output iterator arguments.
void connect_children(const MeshBase &mesh, MeshBase::const_element_iterator elem_it, MeshBase::const_element_iterator elem_end, connected_elem_set_type &connected_elements)
std::set< const Node * > connected_node_set_type
SimpleRange< NodeRefIter > node_ref_range()
Returns a range with all nodes of an element, usable in range-based for loops.
Definition: elem.h:2679
virtual const Elem * elem_ptr(const dof_id_type i) const =0
query_obj query
ElemMappingType
Enumeration of possible element master->physical mapping types.
void send_coarse_ghosts(MeshBase &) const
Examine a just-coarsened mesh, and for any newly-coarsened elements, send the associated ghosted elem...
void make_node_ids_parallel_consistent(MeshBase &)
Assuming all ids on local nodes are globally unique, and assuming all processor ids are parallel cons...
std::vector< dof_id_type > _node_integer_default_values
The array of default initialization values for integer data associated with each node in the mesh...
Definition: mesh_base.h:2356
const Elem * neighbor_ptr(unsigned int i) const
Definition: elem.h:2612
std::vector< dof_id_type > _elem_integer_default_values
The array of default initialization values for integer data associated with each element in the mesh...
Definition: mesh_base.h:2344
virtual unsigned int n_vertices() const =0
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
void gather(const processor_id_type root_id, MeshBase &) const
This method takes an input DistributedMesh which may be distributed among all the processors...
virtual const Elem * query_elem_ptr(const dof_id_type i) const =0
timpi_pure bool verify(const T &r) const
virtual void renumber_elem(dof_id_type old_id, dof_id_type new_id)=0
Changes the id of element old_id, both by changing elem(old_id)->id() and by moving elem(old_id) in t...
void max(const T &r, T &o, Request &req) const
const Node * node_ptr(const unsigned int i) const
Definition: elem.h:2513
std::map< boundary_id_type, std::string > & set_nodeset_name_map()
bool sync_node_data_by_element_id_once(MeshBase &mesh, const MeshBase::const_element_iterator &range_begin, const MeshBase::const_element_iterator &range_end, const ElemCheckFunctor &elem_check, const NodeCheckFunctor &node_check, SyncFunctor &sync)
Synchronize data about a range of ghost nodes uniquely identified by an element id and local node id...
void make_nodes_parallel_consistent(MeshBase &)
Copy processor_ids and ids on ghost nodes from their local processors.
void send(const unsigned int dest_processor_id, const T &buf, const MessageTag &tag=no_tag) const
unsigned int n_neighbors() const
Definition: elem.h:713
void broadcast(MeshBase &) const
Finds all the processors that may contain elements that neighbor my elements.
void make_node_proc_ids_parallel_consistent(MeshBase &)
Assuming all processor ids on nodes touching local elements are parallel consistent, this function makes all other processor ids parallel consistent as well.
bool subactive() const
Definition: elem.h:2973
virtual const Elem & elem_ref(const dof_id_type i) const
Definition: mesh_base.h:778
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
void connect_element_dependencies(const MeshBase &mesh, connected_elem_set_type &connected_elements, connected_node_set_type &connected_nodes)
std::set< const Elem *, CompareElemIdsByLevel > connected_elem_set_type
void set_default_mapping_data(const unsigned char data)
Set the default master space to physical space mapping basis functions to be used on newly added elem...
Definition: mesh_base.h:958
virtual const Node & node_ref(const dof_id_type i) const
Definition: mesh_base.h:735
uset_type definitive_ids
SimpleRange< NeighborPtrIter > neighbor_ptr_range()
Returns a range with all neighbors of an element, usable in range-based for loops.
Definition: elem.h:3517
renumber_obj renumber
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
processor_id_type processor_id() const
void make_new_nodes_parallel_consistent(MeshBase &)
Copy processor_ids and ids on new nodes from their local processors.
processor_id_type processor_id() const
Definition: dof_object.h:881
void delete_remote_elements(DistributedMesh &, const std::set< Elem *> &) const
This method takes an input DistributedMesh which may be distributed among all the processors...
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
void redistribute(DistributedMesh &mesh, bool newly_coarsened_only=false) const
This method takes a parallel distributed mesh and redistributes the elements.
auto index_range(const T &sizable)
Helper function that returns an IntRange<std::size_t> representing all the indices of the passed-in v...
Definition: int_range.h:153
virtual dof_id_type n_nodes() const =0
void sync_element_data_by_parent_id(MeshBase &mesh, const Iterator &range_begin, const Iterator &range_end, SyncFunctor &sync)
Request data about a range of ghost elements uniquely identified by their parent id and which child t...
uint8_t dof_id_type
Definition: id_types.h:67
void set_union(T &data, const unsigned int root_id) const
const RemoteElem * remote_elem
Definition: remote_elem.C:57