Line data Source code
1 : // The libMesh Finite Element Library.
2 : // Copyright (C) 2002-2026 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3 :
4 : // This library is free software; you can redistribute it and/or
5 : // modify it under the terms of the GNU Lesser General Public
6 : // License as published by the Free Software Foundation; either
7 : // version 2.1 of the License, or (at your option) any later version.
8 :
9 : // This library is distributed in the hope that it will be useful,
10 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 : // Lesser General Public License for more details.
13 :
14 : // You should have received a copy of the GNU Lesser General Public
15 : // License along with this library; if not, write to the Free Software
16 : // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 :
18 :
19 :
20 : // Local Includes
21 : #include "libmesh/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 414 : SyncNeighbors(MeshBase & _mesh) :
60 414 : mesh(_mesh) {}
61 :
62 : MeshBase & mesh;
63 :
64 : // Find the neighbor ids for each requested element
65 490 : void gather_data (const std::vector<dof_id_type> & ids,
66 : std::vector<datum> & neighbors) const
67 : {
68 490 : neighbors.resize(ids.size());
69 :
70 1232 : 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 742 : const Elem & elem = mesh.elem_ref(ids[i]);
75 :
76 : // Return the element's neighbors
77 38 : const unsigned int n_neigh = elem.n_neighbors();
78 742 : neighbors[i].resize(n_neigh);
79 3692 : for (unsigned int n = 0; n != n_neigh; ++n)
80 : {
81 150 : const Elem * neigh = elem.neighbor_ptr(n);
82 2950 : if (neigh)
83 : {
84 98 : libmesh_assert_not_equal_to(neigh, remote_elem);
85 2066 : neighbors[i][n] = neigh->id();
86 : }
87 : else
88 884 : neighbors[i][n] = DofObject::invalid_id;
89 : }
90 : }
91 490 : }
92 :
93 490 : void act_on_data (const std::vector<dof_id_type> & ids,
94 : const std::vector<datum> & neighbors) const
95 : {
96 1232 : for (auto i : index_range(ids))
97 : {
98 742 : Elem & elem = mesh.elem_ref(ids[i]);
99 :
100 38 : const datum & new_neigh = neighbors[i];
101 :
102 38 : const unsigned int n_neigh = elem.n_neighbors();
103 38 : libmesh_assert_equal_to (n_neigh, new_neigh.size());
104 :
105 3692 : for (unsigned int n = 0; n != n_neigh; ++n)
106 : {
107 2950 : const dof_id_type new_neigh_id = new_neigh[n];
108 150 : const Elem * old_neigh = elem.neighbor_ptr(n);
109 2950 : if (old_neigh && old_neigh != remote_elem)
110 : {
111 98 : libmesh_assert_equal_to(old_neigh->id(), new_neigh_id);
112 : }
113 1236 : else if (new_neigh_id == DofObject::invalid_id)
114 : {
115 52 : libmesh_assert (!old_neigh);
116 : }
117 : else
118 : {
119 352 : Elem * neigh = mesh.query_elem_ptr(new_neigh_id);
120 352 : if (neigh)
121 0 : elem.set_neighbor(n, neigh);
122 : else
123 352 : elem.set_neighbor(n, const_cast<RemoteElem *>(remote_elem));
124 : }
125 : }
126 : }
127 490 : }
128 : };
129 :
130 :
131 : void
132 1484270 : 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 1484270 : 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 0 : const auto & constraint_rows = mesh->get_constraint_rows();
144 :
145 0 : std::unordered_set<const Elem *> constraining_nodes_elems;
146 668110 : for (const Elem * elem : connected_elements)
147 : {
148 3081386 : for (const Node & node : elem->node_ref_range())
149 : {
150 : // Retain all elements containing constraining nodes
151 2425324 : if (const auto it = constraint_rows.find(&node);
152 0 : it != constraint_rows.end())
153 25872779 : for (auto & p : it->second)
154 : {
155 23670819 : const Elem * constraining_elem = p.first.first;
156 0 : libmesh_assert(constraining_elem ==
157 : mesh->elem_ptr(constraining_elem->id()));
158 0 : if (!connected_elements.count(constraining_elem) &&
159 0 : !new_connected_elements.count(constraining_elem))
160 0 : constraining_nodes_elems.insert(constraining_elem);
161 : }
162 : }
163 : }
164 :
165 12048 : 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 1102 : elem_rit = new_connected_elements.rbegin();
188 :
189 34089352 : for (; elem_rit != new_connected_elements.rend(); ++elem_rit)
190 : {
191 32605082 : const Elem * elem = *elem_rit;
192 25322 : 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 67185053 : for (const Elem * parent = elem->parent(); parent;
198 34568333 : parent = parent->parent())
199 27368 : if (!connected_elements.count(parent) &&
200 13684 : !new_connected_elements.count(parent))
201 18808025 : newer_connected_elements.insert (parent);
202 :
203 : auto total_family_insert =
204 32554438 : [&connected_elements, &new_connected_elements,
205 : &newer_connected_elements]
206 384732 : (const Elem * e)
207 : {
208 25322 : if (e->active() && e->has_children())
209 : {
210 0 : std::vector<const Elem *> subactive_family;
211 37868 : e->total_family_tree(subactive_family);
212 204912 : for (const auto & f : subactive_family)
213 : {
214 0 : libmesh_assert(f != remote_elem);
215 0 : if (!connected_elements.count(f) &&
216 0 : !new_connected_elements.count(f))
217 31032 : newer_connected_elements.insert(f);
218 : }
219 : }
220 32605082 : };
221 :
222 32605082 : 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 32605082 : 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 25322 : libmesh_assert(!interior_parent || mesh);
233 :
234 43726 : if (interior_parent &&
235 18404 : interior_parent == mesh->query_elem_ptr(interior_parent->id()) &&
236 32605176 : !connected_elements.count(interior_parent) &&
237 0 : !new_connected_elements.count(interior_parent))
238 : {
239 0 : newer_connected_elements.insert (interior_parent);
240 0 : 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 92012 : (const Elem * elem)
254 : {
255 54894 : libmesh_assert(elem);
256 54894 : const Elem * parent = elem->parent();
257 54894 : if (parent)
258 20106 : libmesh_assert(connected_elements.count(parent) ||
259 : new_connected_elements.count(parent) ||
260 : newer_connected_elements.count(parent));
261 54894 : };
262 :
263 29730 : for (const auto & elem : connected_elements)
264 28628 : check_elem(elem);
265 26424 : for (const auto & elem : new_connected_elements)
266 25322 : check_elem(elem);
267 2046 : for (const auto & elem : newer_connected_elements)
268 944 : check_elem(elem);
269 : # endif // DEBUG
270 :
271 : #endif // LIBMESH_ENABLE_AMR
272 1484270 : }
273 :
274 :
275 :
276 1484270 : 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 34089352 : for (const auto & elem : new_connected_elements)
282 359345804 : for (auto & n : elem->node_ref_range())
283 326966809 : if (!connected_nodes.count(&n) &&
284 337502959 : !new_connected_nodes.count(&n))
285 316164974 : newer_connected_nodes.insert(&n);
286 1484270 : }
287 :
288 :
289 : } // anonymous namespace
290 :
291 :
292 :
293 : namespace libMesh
294 : {
295 :
296 :
297 1399345 : void query_ghosting_functors(const MeshBase & mesh,
298 : processor_id_type pid,
299 : MeshBase::const_element_iterator elem_it,
300 : MeshBase::const_element_iterator elem_end,
301 : connected_elem_set_type & connected_elements)
302 : {
303 1398538 : for (auto & gf :
304 927 : as_range(mesh.ghosting_functors_begin(),
305 3212015 : mesh.ghosting_functors_end()))
306 : {
307 2094 : GhostingFunctor::map_type elements_to_ghost;
308 1047 : libmesh_assert(gf);
309 1810696 : (*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 21627877 : for (auto & pr : elements_to_ghost)
314 : {
315 19817181 : const Elem * elem = pr.first;
316 8665 : libmesh_assert(elem != remote_elem);
317 8665 : libmesh_assert(mesh.elem_ptr(elem->id()) == elem);
318 19808516 : 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 21693053 : for (; elem_it != elem_end; ++elem_it)
325 10161770 : connected_elements.insert(*elem_it);
326 1399345 : }
327 :
328 :
329 1399345 : void connect_children(const MeshBase & mesh,
330 : MeshBase::const_element_iterator elem_it,
331 : MeshBase::const_element_iterator elem_end,
332 : connected_elem_set_type & connected_elements)
333 : {
334 : // None of these parameters are used when !LIBMESH_ENABLE_AMR.
335 927 : 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 26552215 : for (const auto & elem : as_range(elem_it, elem_end))
342 : {
343 11893168 : if (elem->has_children())
344 9652940 : for (auto & child : elem->child_ref_range())
345 7995322 : if (&child != remote_elem)
346 7720460 : connected_elements.insert(&child);
347 1397491 : }
348 : #endif // LIBMESH_ENABLE_AMR
349 1399345 : }
350 :
351 :
352 0 : 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 0 : connected_nodes.clear();
358 :
359 : // Use the newer API
360 0 : connect_nodes(connected_elements, connected_nodes, connected_nodes,
361 : connected_nodes);
362 0 : }
363 :
364 :
365 917394 : void connect_element_dependencies(const MeshBase & mesh,
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 1098 : connected_elem_set_type new_connected_elements;
372 1098 : connected_node_set_type new_connected_nodes;
373 549 : new_connected_elements.swap(connected_elements);
374 549 : new_connected_nodes.swap(connected_nodes);
375 :
376 2402669 : while (!new_connected_elements.empty() ||
377 1005 : !new_connected_nodes.empty())
378 : {
379 : auto [newer_connected_elements,
380 1102 : newer_connected_nodes] =
381 : connect_element_dependencies
382 : (mesh, connected_elements, connected_nodes,
383 1486474 : new_connected_elements, new_connected_nodes);
384 :
385 : // These have now been examined
386 1102 : connected_elements.merge(new_connected_elements);
387 1102 : 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 1102 : libmesh_assert(new_connected_elements.empty());
392 1102 : libmesh_assert(new_connected_nodes.empty());
393 :
394 : // These now need to be examined
395 1102 : new_connected_elements.swap(newer_connected_elements);
396 1102 : new_connected_nodes.swap(newer_connected_nodes);
397 1482066 : }
398 917394 : }
399 :
400 :
401 : std::pair<connected_elem_set_type, connected_node_set_type>
402 1484270 : connect_element_dependencies(const MeshBase & mesh,
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 1102 : std::pair<connected_elem_set_type, connected_node_set_type> returnval;
409 1102 : auto & [newer_connected_elements, newer_connected_nodes] = returnval;
410 1484270 : connect_element_families(connected_elements, new_connected_elements,
411 : newer_connected_elements, &mesh);
412 :
413 1484270 : connect_nodes(new_connected_elements, connected_nodes,
414 : new_connected_nodes, newer_connected_nodes);
415 :
416 1484270 : return returnval;
417 0 : }
418 :
419 :
420 :
421 :
422 : // ------------------------------------------------------------
423 : // MeshCommunication class members
424 0 : void MeshCommunication::clear ()
425 : {
426 : // _neighboring_processors.clear();
427 0 : }
428 :
429 :
430 :
431 : #ifndef LIBMESH_HAVE_MPI // avoid spurious gcc warnings
432 : // ------------------------------------------------------------
433 : void MeshCommunication::redistribute (DistributedMesh &, bool) const
434 : {
435 : // no MPI == one processor, no redistribution
436 : return;
437 : }
438 :
439 : #else
440 : // ------------------------------------------------------------
441 75882 : void MeshCommunication::redistribute (DistributedMesh & mesh,
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 136 : libmesh_parallel_only(mesh.comm());
467 136 : libmesh_assert (!mesh.is_serial());
468 136 : libmesh_assert (MeshTools::n_elem(mesh.unpartitioned_elements_begin(),
469 : mesh.unpartitioned_elements_end()) == 0);
470 :
471 408 : 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 272 : 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 75882 : newly_coarsened_only ?
483 : mesh.flagged_elements_begin(Elem::JUST_COARSENED) :
484 : #endif
485 272 : mesh.active_elements_begin();
486 :
487 : const MeshBase::const_element_iterator send_elems_end =
488 : #ifdef LIBMESH_ENABLE_AMR
489 75882 : newly_coarsened_only ?
490 : mesh.flagged_elements_end(Elem::JUST_COARSENED) :
491 : #endif
492 272 : mesh.active_elements_end();
493 :
494 : // See what should get sent where. We don't send to ourselves.
495 10888130 : for (auto & elem : as_range(send_elems_begin, send_elems_end))
496 5391259 : if (elem->processor_id() != mesh.processor_id())
497 3976955 : send_to_pid[elem->processor_id()].push_back(elem);
498 :
499 272 : std::map<processor_id_type, std::vector<const Node *>> all_nodes_to_send;
500 272 : std::map<processor_id_type, std::vector<const Elem *>> all_elems_to_send;
501 :
502 : // We may need to send constraint rows too.
503 : //
504 : // We know we're not changing n_constraint_rows(), so we're using
505 : // friend class status here rather than using the setter that
506 : // invalidates caches.
507 75882 : auto & constraint_rows = mesh._constraint_rows;
508 75882 : bool have_constraint_rows = !constraint_rows.empty();
509 75882 : mesh.comm().broadcast(have_constraint_rows);
510 :
511 : #ifdef DEBUG
512 : const dof_id_type n_constraint_rows =
513 136 : have_constraint_rows ? mesh.n_constraint_rows() : 0;
514 : #endif
515 :
516 : typedef std::vector<std::pair<std::pair<dof_id_type, unsigned int>, Real>>
517 : serialized_row_type;
518 : std::unordered_map<processor_id_type,
519 : std::vector<std::pair<dof_id_type, serialized_row_type>>>
520 272 : all_constraint_rows_to_send;
521 :
522 : // If we don't have any just-coarsened elements to send to a
523 : // pid, then there won't be any nodes or any elements pulled
524 : // in by ghosting either, and we're done with this pid.
525 510665 : for (const auto & [pid, p_elements] : send_to_pid)
526 : {
527 : // Build up a list of nodes and elements to send to processor pid.
528 : // We will certainly send all the elements assigned to this processor,
529 : // but we will also ship off any elements which are required
530 : // to be ghosted and any nodes which are used by any of the
531 : // above.
532 :
533 133 : libmesh_assert(!p_elements.empty());
534 :
535 : // Be compatible with both deprecated and
536 : // corrected MeshBase iterator types
537 : typedef MeshBase::const_element_iterator::value_type v_t;
538 :
539 434783 : v_t * elempp = p_elements.data();
540 434783 : v_t * elemend = elempp + p_elements.size();
541 :
542 : #ifndef LIBMESH_ENABLE_AMR
543 : // This parameter is not used when !LIBMESH_ENABLE_AMR.
544 : libmesh_ignore(newly_coarsened_only);
545 : libmesh_assert(!newly_coarsened_only);
546 : #endif
547 :
548 : MeshBase::const_element_iterator elem_it =
549 : MeshBase::const_element_iterator
550 434916 : (elempp, elemend, Predicates::NotNull<v_t *>());
551 :
552 : const MeshBase::const_element_iterator elem_end =
553 : MeshBase::const_element_iterator
554 869566 : (elemend, elemend, Predicates::NotNull<v_t *>());
555 :
556 266 : connected_elem_set_type elements_to_send;
557 :
558 : // See which to-be-ghosted elements we need to send
559 869433 : query_ghosting_functors (mesh, pid, elem_it, elem_end,
560 : elements_to_send);
561 :
562 : // The inactive elements we need to send should have their
563 : // immediate children present.
564 1304083 : connect_children(mesh, mesh.pid_elements_begin(pid),
565 869566 : mesh.pid_elements_end(pid),
566 : elements_to_send);
567 :
568 : // Now see which other elements and nodes they depend on
569 266 : connected_node_set_type connected_nodes;
570 434783 : connect_element_dependencies(mesh, elements_to_send,
571 : connected_nodes);
572 :
573 434783 : all_nodes_to_send[pid].assign(connected_nodes.begin(),
574 : connected_nodes.end());
575 :
576 434783 : all_elems_to_send[pid].assign(elements_to_send.begin(),
577 : elements_to_send.end());
578 :
579 524026 : for (auto & [node, row] : constraint_rows)
580 : {
581 29318 : if (!connected_nodes.count(node))
582 29318 : continue;
583 :
584 0 : serialized_row_type serialized_row;
585 637951 : for (auto [elem_and_node, coef] : row)
586 578026 : serialized_row.emplace_back(std::make_pair(elem_and_node.first->id(),
587 0 : elem_and_node.second),
588 0 : coef);
589 :
590 0 : all_constraint_rows_to_send[pid].emplace_back
591 59925 : (node->id(), std::move(serialized_row));
592 : }
593 : }
594 :
595 : // Elem/Node unpack() automatically adds them to the given mesh
596 133 : auto null_node_action = [](processor_id_type, const std::vector<const Node*>&){};
597 133 : auto null_elem_action = [](processor_id_type, const std::vector<const Elem*>&){};
598 :
599 : // Communicate nodes first since elements will need to attach to them
600 75882 : TIMPI::push_parallel_packed_range(mesh.comm(), all_nodes_to_send, &mesh,
601 : null_node_action);
602 :
603 75882 : TIMPI::push_parallel_packed_range(mesh.comm(), all_elems_to_send, &mesh,
604 : null_elem_action);
605 :
606 : // At this point we have all the nodes and elems we need, so we can
607 : // communicate any constraint rows that our targets will need.
608 75882 : if (have_constraint_rows)
609 : {
610 : auto constraint_row_action =
611 1698 : [&mesh, &constraint_rows]
612 : (processor_id_type /* src_pid */,
613 637363 : const std::vector<std::pair<dof_id_type, serialized_row_type>> rows)
614 : {
615 61427 : for (auto & [node_id, serialized_row] : rows)
616 : {
617 0 : MeshBase::constraint_rows_mapped_type row;
618 637363 : for (auto [elem_and_node, coef] : serialized_row)
619 577634 : row.emplace_back(std::make_pair(mesh.elem_ptr(elem_and_node.first),
620 0 : elem_and_node.second),
621 0 : coef);
622 :
623 59729 : constraint_rows[mesh.node_ptr(node_id)] = row;
624 : }
625 1917 : };
626 :
627 219 : TIMPI::push_parallel_vector_data(mesh.comm(),
628 : all_constraint_rows_to_send,
629 : constraint_row_action);
630 :
631 : }
632 :
633 : // Check on the redistribution consistency
634 : #ifdef DEBUG
635 136 : MeshTools::libmesh_assert_equal_n_systems(mesh);
636 :
637 136 : MeshTools::libmesh_assert_valid_refinement_tree(mesh);
638 :
639 : const dof_id_type new_n_constraint_rows =
640 136 : have_constraint_rows ? mesh.n_constraint_rows() : 0;
641 :
642 136 : libmesh_assert_equal_to(n_constraint_rows, new_n_constraint_rows);
643 :
644 136 : MeshTools::libmesh_assert_valid_constraint_rows(mesh);
645 : #endif
646 :
647 : // If we had a point locator, it's invalid now that there are new
648 : // elements it can't locate.
649 75882 : mesh.clear_point_locator();
650 :
651 : // Let the mesh handle any other post-redistribute() tasks, like
652 : // notifying GhostingFunctors. Be sure we're just calling the base
653 : // class method so we don't recurse back into ourselves here.
654 75882 : mesh.MeshBase::redistribute();
655 75882 : }
656 : #endif // LIBMESH_HAVE_MPI
657 :
658 :
659 :
660 : #ifndef LIBMESH_HAVE_MPI // avoid spurious gcc warnings
661 : // ------------------------------------------------------------
662 : void MeshCommunication::gather_neighboring_elements (DistributedMesh &) const
663 : {
664 : // no MPI == one processor, no need for this method...
665 : return;
666 : }
667 : #else
668 : // ------------------------------------------------------------
669 425 : void MeshCommunication::gather_neighboring_elements (DistributedMesh & mesh) const
670 : {
671 : // Don't need to do anything if there is
672 : // only one processor.
673 437 : if (mesh.n_processors() == 1)
674 11 : return;
675 :
676 : // This function must be run on all processors at once
677 12 : libmesh_parallel_only(mesh.comm());
678 :
679 36 : LOG_SCOPE("gather_neighboring_elements()", "MeshCommunication");
680 :
681 : //------------------------------------------------------------------
682 : // The purpose of this function is to provide neighbor data structure
683 : // consistency for a parallel, distributed mesh. In libMesh we require
684 : // that each local element have access to a full set of valid face
685 : // neighbors. In some cases this requires us to store "ghost elements" -
686 : // elements that belong to other processors but we store to provide
687 : // data structure consistency. Also, it is assumed that any element
688 : // with a nullptr neighbor resides on a physical domain boundary. So,
689 : // even our "ghost elements" must have non-nullptr neighbors. To handle
690 : // this the concept of "RemoteElem" is used - a special construct which
691 : // is used to denote that an element has a face neighbor, but we do
692 : // not actually store detailed information about that neighbor. This
693 : // is required to prevent data structure explosion.
694 : //
695 : // So when this method is called we should have only local elements.
696 : // These local elements will then find neighbors among the local
697 : // element set. After this is completed, any element with a nullptr
698 : // neighbor has either (i) a face on the physical boundary of the mesh,
699 : // or (ii) a neighboring element which lives on a remote processor.
700 : // To handle case (ii), we communicate the global node indices connected
701 : // to all such faces to our neighboring processors. They then send us
702 : // all their elements with a nullptr neighbor that are connected to any
703 : // of the nodes in our list.
704 : //------------------------------------------------------------------
705 :
706 : // Let's begin with finding consistent neighbor data information
707 : // for all the elements we currently have. We'll use a clean
708 : // slate here - clear any existing information, including RemoteElem's.
709 438 : mesh.find_neighbors (/* reset_remote_elements = */ true,
710 24 : /* reset_current_list = */ true);
711 :
712 : // Get a unique message tag to use in communications
713 : Parallel::MessageTag
714 438 : element_neighbors_tag = mesh.comm().get_unique_tag();
715 :
716 : // Now any element with a nullptr neighbor either
717 : // (i) lives on the physical domain boundary, or
718 : // (ii) lives on an inter-processor boundary.
719 : // We will now gather all the elements from adjacent processors
720 : // which are of the same state, which should address all the type (ii)
721 : // elements.
722 :
723 : // A list of all the processors which *may* contain neighboring elements.
724 : // (for development simplicity, just make this the identity map)
725 24 : std::vector<processor_id_type> adjacent_processors;
726 4560 : for (auto pid : make_range(mesh.n_processors()))
727 4170 : if (pid != mesh.processor_id())
728 3732 : adjacent_processors.push_back (pid);
729 :
730 :
731 : const processor_id_type n_adjacent_processors =
732 24 : cast_int<processor_id_type>(adjacent_processors.size());
733 :
734 : //-------------------------------------------------------------------------
735 : // Let's build a list of all nodes which live on nullptr-neighbor sides.
736 : // For simplicity, we will use a set to build the list, then transfer
737 : // it to a vector for communication.
738 24 : std::vector<dof_id_type> my_interface_node_list;
739 24 : std::vector<const Elem *> my_interface_elements;
740 : {
741 24 : std::set<dof_id_type> my_interface_node_set;
742 :
743 : // For avoiding extraneous element side construction
744 12 : ElemSideBuilder side_builder;
745 :
746 : // since parent nodes are a subset of children nodes, this should be sufficient
747 1518 : for (const auto & elem : mesh.active_local_element_ptr_range())
748 : {
749 39 : libmesh_assert(elem);
750 :
751 429 : if (elem->on_boundary()) // denotes *any* side has a nullptr neighbor
752 : {
753 390 : my_interface_elements.push_back(elem); // add the element, but only once, even
754 : // if there are multiple nullptr neighbors
755 1969 : for (auto s : elem->side_index_range())
756 1694 : if (elem->neighbor_ptr(s) == nullptr)
757 : {
758 1140 : const Elem & side = side_builder(*elem, s);
759 :
760 3420 : for (auto n : make_range(side.n_vertices()))
761 2476 : my_interface_node_set.insert (side.node_id(n));
762 : }
763 : }
764 390 : }
765 :
766 414 : my_interface_node_list.reserve (my_interface_node_set.size());
767 402 : my_interface_node_list.insert (my_interface_node_list.end(),
768 : my_interface_node_set.begin(),
769 36 : my_interface_node_set.end());
770 : }
771 :
772 : // we will now send my_interface_node_list to all of the adjacent processors.
773 : // note that for the time being we will copy the list to a unique buffer for
774 : // each processor so that we can use a nonblocking send and not access the
775 : // buffer again until the send completes. it is my understanding that the
776 : // MPI 2.1 standard seeks to remove this restriction as unnecessary, so in
777 : // the future we should change this to send the same buffer to each of the
778 : // adjacent processors. - BSK 11/17/2008
779 : std::vector<std::vector<dof_id_type>>
780 438 : my_interface_node_xfer_buffers (n_adjacent_processors, my_interface_node_list);
781 24 : std::map<processor_id_type, unsigned char> n_comm_steps;
782 :
783 438 : std::vector<Parallel::Request> send_requests (3*n_adjacent_processors);
784 12 : unsigned int current_request = 0;
785 :
786 4146 : for (unsigned int comm_step=0; comm_step<n_adjacent_processors; comm_step++)
787 : {
788 3744 : n_comm_steps[adjacent_processors[comm_step]]=1;
789 3756 : mesh.comm().send (adjacent_processors[comm_step],
790 24 : my_interface_node_xfer_buffers[comm_step],
791 3732 : send_requests[current_request++],
792 : element_neighbors_tag);
793 : }
794 :
795 : //-------------------------------------------------------------------------
796 : // processor pairings are symmetric - I expect to receive an interface node
797 : // list from each processor in adjacent_processors as well!
798 : // now we will catch an incoming node list for each of our adjacent processors.
799 : //
800 : // we are done with the adjacent_processors list - note that it is in general
801 : // a superset of the processors we truly share elements with. so let's
802 : // clear the superset list, and we will fill it with the true list.
803 12 : adjacent_processors.clear();
804 :
805 12 : std::vector<dof_id_type> common_interface_node_list;
806 :
807 : // we expect two classes of messages -
808 : // (1) incoming interface node lists, to which we will reply with our elements
809 : // touching nodes in the list, and
810 : // (2) replies from the requests we sent off previously.
811 : // (2.a) - nodes
812 : // (2.b) - elements
813 : // so we expect 3 communications from each adjacent processor.
814 : // by structuring the communication in this way we hopefully impose no
815 : // order on the handling of the arriving messages. in particular, we
816 : // should be able to handle the case where we receive a request and
817 : // all replies from processor A before even receiving a request from
818 : // processor B.
819 :
820 11610 : for (unsigned int comm_step=0; comm_step<3*n_adjacent_processors; comm_step++)
821 : {
822 : //------------------------------------------------------------------
823 : // catch incoming node list
824 : Parallel::Status
825 11196 : status(mesh.comm().probe (Parallel::any_source,
826 72 : element_neighbors_tag));
827 : const processor_id_type
828 11196 : source_pid_idx = cast_int<processor_id_type>(status.source()),
829 36 : dest_pid_idx = source_pid_idx;
830 :
831 : //------------------------------------------------------------------
832 : // first time - incoming request
833 11196 : if (n_comm_steps[source_pid_idx] == 1)
834 : {
835 3732 : n_comm_steps[source_pid_idx]++;
836 :
837 3732 : mesh.comm().receive (source_pid_idx,
838 : common_interface_node_list,
839 24 : element_neighbors_tag);
840 :
841 : // const std::size_t
842 : // their_interface_node_list_size = common_interface_node_list.size();
843 :
844 : // we now have the interface node list from processor source_pid_idx.
845 : // now we can find all of our elements which touch any of these nodes
846 : // and send copies back to this processor. however, we can make our
847 : // search more efficient by first excluding all the nodes in
848 : // their list which are not also contained in
849 : // my_interface_node_list. we can do this in place as a set
850 : // intersection.
851 : common_interface_node_list.erase
852 3708 : (std::set_intersection (my_interface_node_list.begin(),
853 : my_interface_node_list.end(),
854 : common_interface_node_list.begin(),
855 : common_interface_node_list.end(),
856 12 : common_interface_node_list.begin()),
857 24 : common_interface_node_list.end());
858 :
859 : // if (false)
860 : // libMesh::out << "[" << mesh.processor_id() << "] "
861 : // << "my_interface_node_list.size()=" << my_interface_node_list.size()
862 : // << ", [" << source_pid_idx << "] "
863 : // << "their_interface_node_list.size()=" << their_interface_node_list_size
864 : // << ", common_interface_node_list.size()=" << common_interface_node_list.size()
865 : // << std::endl;
866 :
867 : // Now we need to see which of our elements touch the nodes in the list.
868 : // We will certainly send all the active elements which intersect source_pid_idx,
869 : // but we will also ship off the other elements in the same family tree
870 : // as the active ones for data structure consistency.
871 : //
872 : // FIXME - shipping full family trees is unnecessary and inefficient.
873 : //
874 : // We also ship any nodes connected to these elements. Note
875 : // some of these nodes and elements may be replicated from
876 : // other processors, but that is OK.
877 12 : connected_elem_set_type elements_to_send;
878 :
879 : // Technically we're not doing reconnect_nodes on this, but
880 : // we might as well use the same data structure since the
881 : // performance questions ought to be similar
882 12 : connected_node_set_type connected_nodes;
883 :
884 : // Check for quick return?
885 6960 : if (common_interface_node_list.empty())
886 : {
887 : // let's try to be smart here - if we have no nodes in common,
888 : // we cannot share elements. so post the messages expected
889 : // from us here and go on about our business.
890 : // note that even though these are nonblocking sends
891 : // they should complete essentially instantly, because
892 : // in all cases the send buffers are empty
893 3234 : mesh.comm().send_packed_range (dest_pid_idx,
894 : &mesh,
895 : connected_nodes.begin(),
896 : connected_nodes.end(),
897 3232 : send_requests[current_request++],
898 : element_neighbors_tag);
899 :
900 3234 : mesh.comm().send_packed_range (dest_pid_idx,
901 : &mesh,
902 : elements_to_send.begin(),
903 : elements_to_send.end(),
904 3232 : send_requests[current_request++],
905 : element_neighbors_tag);
906 :
907 2 : continue;
908 : }
909 : // otherwise, this really *is* an adjacent processor.
910 500 : adjacent_processors.push_back(source_pid_idx);
911 :
912 20 : std::vector<const Elem *> family_tree;
913 :
914 1408 : for (auto & elem : my_interface_elements)
915 : {
916 38 : std::size_t n_shared_nodes = 0;
917 :
918 2136 : for (auto n : make_range(elem->n_vertices()))
919 2008 : if (std::binary_search (common_interface_node_list.begin(),
920 : common_interface_node_list.end(),
921 2124 : elem->node_id(n)))
922 : {
923 38 : n_shared_nodes++;
924 :
925 : // TBD - how many nodes do we need to share
926 : // before we care? certainly 2, but 1? not
927 : // sure, so let's play it safe...
928 38 : if (n_shared_nodes > 0) break;
929 : }
930 :
931 908 : if (n_shared_nodes) // share at least one node?
932 : {
933 1522 : elem = elem->top_parent();
934 :
935 : // avoid a lot of duplicated effort -- if we already have elem
936 : // in the set its entire family tree is already in the set.
937 38 : if (!elements_to_send.count(elem))
938 : {
939 : #ifdef LIBMESH_ENABLE_AMR
940 780 : elem->family_tree(family_tree);
941 : #else
942 : family_tree.clear();
943 : family_tree.push_back(elem);
944 : #endif
945 1560 : for (const auto & f : family_tree)
946 : {
947 780 : elem = f;
948 742 : elements_to_send.insert (elem);
949 :
950 3978 : for (auto & n : elem->node_ref_range())
951 3160 : connected_nodes.insert (&n);
952 : }
953 : }
954 : }
955 : }
956 :
957 : // The elements_to_send and connected_nodes sets now contain all
958 : // the elements and nodes we need to send to this processor.
959 : // All that remains is to pack up the objects (along with
960 : // any boundary conditions) and send the messages off.
961 : {
962 10 : libmesh_assert (connected_nodes.empty() || !elements_to_send.empty());
963 10 : libmesh_assert (!connected_nodes.empty() || elements_to_send.empty());
964 :
965 : // send the nodes off to the destination processor
966 510 : mesh.comm().send_packed_range (dest_pid_idx,
967 : &mesh,
968 : connected_nodes.begin(),
969 : connected_nodes.end(),
970 500 : send_requests[current_request++],
971 : element_neighbors_tag);
972 :
973 : // send the elements off to the destination processor
974 510 : mesh.comm().send_packed_range (dest_pid_idx,
975 : &mesh,
976 : elements_to_send.begin(),
977 : elements_to_send.end(),
978 500 : send_requests[current_request++],
979 : element_neighbors_tag);
980 : }
981 : }
982 : //------------------------------------------------------------------
983 : // second time - reply of nodes
984 7464 : else if (n_comm_steps[source_pid_idx] == 2)
985 : {
986 3732 : n_comm_steps[source_pid_idx]++;
987 :
988 3732 : mesh.comm().receive_packed_range (source_pid_idx,
989 : &mesh,
990 : null_output_iterator<Node>(),
991 : (Node**)nullptr,
992 : element_neighbors_tag);
993 : }
994 : //------------------------------------------------------------------
995 : // third time - reply of elements
996 3732 : else if (n_comm_steps[source_pid_idx] == 3)
997 : {
998 3732 : n_comm_steps[source_pid_idx]++;
999 :
1000 3732 : mesh.comm().receive_packed_range (source_pid_idx,
1001 : &mesh,
1002 : null_output_iterator<Elem>(),
1003 : (Elem**)nullptr,
1004 : element_neighbors_tag);
1005 : }
1006 : //------------------------------------------------------------------
1007 : // fourth time - shouldn't happen
1008 : else
1009 : {
1010 0 : libMesh::err << "ERROR: unexpected number of replies: "
1011 0 : << n_comm_steps[source_pid_idx]
1012 0 : << std::endl;
1013 : }
1014 : } // done catching & processing replies associated with tag ~ 100,000pi
1015 :
1016 : // allow any pending requests to complete
1017 414 : Parallel::wait (send_requests);
1018 :
1019 : // If we had a point locator, it's invalid now that there are new
1020 : // elements it can't locate.
1021 414 : mesh.clear_point_locator();
1022 :
1023 : // We can now find neighbor information for the interfaces between
1024 : // local elements and ghost elements.
1025 426 : mesh.find_neighbors (/* reset_remote_elements = */ true,
1026 24 : /* reset_current_list = */ false);
1027 :
1028 : // Ghost elements may not have correct remote_elem neighbor links,
1029 : // and we may not be able to locally infer correct neighbor links to
1030 : // remote elements. So we synchronize ghost element neighbor links.
1031 12 : SyncNeighbors nsync(mesh);
1032 :
1033 : Parallel::sync_dofobject_data_by_id
1034 816 : (mesh.comm(), mesh.elements_begin(), mesh.elements_end(), nsync);
1035 1170 : }
1036 : #endif // LIBMESH_HAVE_MPI
1037 :
1038 :
1039 : #ifndef LIBMESH_HAVE_MPI // avoid spurious gcc warnings
1040 : // ------------------------------------------------------------
1041 : void MeshCommunication::send_coarse_ghosts(MeshBase &) const
1042 : {
1043 : // no MPI == one processor, no need for this method...
1044 : return;
1045 : }
1046 : #else
1047 7086 : void MeshCommunication::send_coarse_ghosts(MeshBase & mesh) const
1048 : {
1049 :
1050 : // Don't need to do anything if all processors already ghost all non-local
1051 : // elements.
1052 7086 : if (mesh.is_serial())
1053 5858 : return;
1054 :
1055 : // This algorithm uses the MeshBase::flagged_pid_elements_begin/end iterators
1056 : // which are only available when AMR is enabled.
1057 : #ifndef LIBMESH_ENABLE_AMR
1058 : libmesh_error_msg("Calling MeshCommunication::send_coarse_ghosts() requires AMR to be enabled. "
1059 : "Please configure libmesh with --enable-amr.");
1060 : #else
1061 : // When we coarsen elements on a DistributedMesh, we make their
1062 : // parents active. This may increase the ghosting requirements on
1063 : // the processor which owns the newly-activated parent element. To
1064 : // ensure ghosting requirements are satisfied, processors which
1065 : // coarsen an element will send all the associated ghosted elements
1066 : // to all processors which own any of the coarsened-away-element's
1067 : // siblings.
1068 : typedef std::unordered_map<processor_id_type, std::vector<Elem *>> ghost_map;
1069 8 : ghost_map coarsening_elements_to_ghost;
1070 :
1071 8 : const processor_id_type proc_id = mesh.processor_id();
1072 : // Look for just-coarsened elements
1073 3172 : for (auto elem : as_range(mesh.flagged_pid_elements_begin(Elem::COARSEN, proc_id),
1074 212965 : mesh.flagged_pid_elements_end(Elem::COARSEN, proc_id)))
1075 : {
1076 : // If it's flagged for coarsening it had better have a parent
1077 720 : libmesh_assert(elem->parent());
1078 :
1079 : // On a distributed mesh:
1080 : // If we don't own this element's parent but we do own it, then
1081 : // there is a chance that we are aware of ghost elements which
1082 : // the parent's owner needs us to send them.
1083 104048 : const processor_id_type their_proc_id = elem->parent()->processor_id();
1084 104048 : if (their_proc_id != proc_id)
1085 685 : coarsening_elements_to_ghost[their_proc_id].push_back(elem);
1086 1220 : }
1087 :
1088 8 : std::map<processor_id_type, std::vector<const Node *>> all_nodes_to_send;
1089 8 : std::map<processor_id_type, std::vector<const Elem *>> all_elems_to_send;
1090 :
1091 8 : const processor_id_type n_proc = mesh.n_processors();
1092 :
1093 14172 : for (processor_id_type p=0; p != n_proc; ++p)
1094 : {
1095 12944 : if (p == proc_id)
1096 1228 : continue;
1097 :
1098 8 : connected_elem_set_type elements_to_send;
1099 8 : std::set<const Node *> nodes_to_send;
1100 :
1101 11716 : if (const auto it = std::as_const(coarsening_elements_to_ghost).find(p);
1102 4 : it != coarsening_elements_to_ghost.end())
1103 : {
1104 0 : const std::vector<Elem *> & elems = it->second;
1105 0 : libmesh_assert(elems.size());
1106 :
1107 : // Make some fake element iterators defining this vector of
1108 : // elements
1109 230 : Elem * const * elempp = const_cast<Elem * const *>(elems.data());
1110 230 : Elem * const * elemend = elempp+elems.size();
1111 : const MeshBase::const_element_iterator elem_it =
1112 230 : MeshBase::const_element_iterator(elempp, elemend, Predicates::NotNull<Elem * const *>());
1113 : const MeshBase::const_element_iterator elem_end =
1114 460 : MeshBase::const_element_iterator(elemend, elemend, Predicates::NotNull<Elem * const *>());
1115 :
1116 230 : for (auto & gf : as_range(mesh.ghosting_functors_begin(),
1117 944 : mesh.ghosting_functors_end()))
1118 : {
1119 0 : GhostingFunctor::map_type elements_to_ghost;
1120 0 : libmesh_assert(gf);
1121 714 : (*gf)(elem_it, elem_end, p, elements_to_ghost);
1122 :
1123 : // We can ignore the CouplingMatrix in ->second, but we
1124 : // need to ghost all the elements in ->first.
1125 5429 : for (auto & pr : elements_to_ghost)
1126 : {
1127 4715 : const Elem * elem = pr.first;
1128 0 : libmesh_assert(elem);
1129 16262 : while (elem)
1130 : {
1131 0 : libmesh_assert(elem != remote_elem);
1132 11547 : elements_to_send.insert(elem);
1133 108958 : for (auto & n : elem->node_ref_range())
1134 97411 : nodes_to_send.insert(&n);
1135 11547 : elem = elem->parent();
1136 : }
1137 : }
1138 : }
1139 :
1140 230 : all_nodes_to_send[p].assign(nodes_to_send.begin(), nodes_to_send.end());
1141 230 : all_elems_to_send[p].assign(elements_to_send.begin(), elements_to_send.end());
1142 : }
1143 : }
1144 :
1145 : // Elem/Node unpack() automatically adds them to the given mesh
1146 0 : auto null_node_action = [](processor_id_type, const std::vector<const Node*>&){};
1147 0 : auto null_elem_action = [](processor_id_type, const std::vector<const Elem*>&){};
1148 :
1149 : // Communicate nodes first since elements will need to attach to them
1150 1228 : TIMPI::push_parallel_packed_range(mesh.comm(), all_nodes_to_send, &mesh,
1151 : null_node_action);
1152 :
1153 1228 : TIMPI::push_parallel_packed_range(mesh.comm(), all_elems_to_send, &mesh,
1154 : null_elem_action);
1155 :
1156 : #endif // LIBMESH_ENABLE_AMR
1157 : }
1158 :
1159 : #endif // LIBMESH_HAVE_MPI
1160 :
1161 : #ifndef LIBMESH_HAVE_MPI // avoid spurious gcc warnings
1162 : // ------------------------------------------------------------
1163 : void MeshCommunication::broadcast (MeshBase &) const
1164 : {
1165 : // no MPI == one processor, no need for this method...
1166 : return;
1167 : }
1168 : #else
1169 : // ------------------------------------------------------------
1170 15095 : void MeshCommunication::broadcast (MeshBase & mesh) const
1171 : {
1172 : // Don't need to do anything if there is
1173 : // only one processor.
1174 15529 : if (mesh.n_processors() == 1)
1175 433 : return;
1176 :
1177 : // This function must be run on all processors at once
1178 430 : libmesh_parallel_only(mesh.comm());
1179 :
1180 1290 : LOG_SCOPE("broadcast()", "MeshCommunication");
1181 :
1182 : // Explicitly clear the mesh on all but processor 0.
1183 15092 : if (mesh.processor_id() != 0)
1184 12525 : mesh.clear();
1185 :
1186 : // We may have set extra data only on processor 0 in a read()
1187 14662 : mesh.comm().broadcast(mesh._node_integer_names);
1188 14662 : mesh.comm().broadcast(mesh._node_integer_default_values);
1189 14662 : mesh.comm().broadcast(mesh._elem_integer_names);
1190 14662 : mesh.comm().broadcast(mesh._elem_integer_default_values);
1191 :
1192 : // We may have set mapping data only on processor 0 in a read()
1193 14662 : unsigned char map_type = mesh.default_mapping_type();
1194 14662 : unsigned char map_data = mesh.default_mapping_data();
1195 14662 : mesh.comm().broadcast(map_type);
1196 14662 : mesh.comm().broadcast(map_data);
1197 14662 : mesh.set_default_mapping_type(ElemMappingType(map_type));
1198 14662 : mesh.set_default_mapping_data(map_data);
1199 :
1200 : // Broadcast nodes
1201 15092 : mesh.comm().broadcast_packed_range(&mesh,
1202 29324 : mesh.nodes_begin(),
1203 15092 : mesh.nodes_end(),
1204 : &mesh,
1205 : null_output_iterator<Node>());
1206 :
1207 : // Broadcast elements from coarsest to finest, so that child
1208 : // elements will see their parents already in place.
1209 : //
1210 : // When restarting from a checkpoint, we may have elements which are
1211 : // assigned to a processor but which have not yet been sent to that
1212 : // processor, so we need to use a paranoid n_levels() count and not
1213 : // the usual fast algorithm.
1214 14662 : const unsigned int n_levels = MeshTools::paranoid_n_levels(mesh);
1215 :
1216 29324 : for (unsigned int l=0; l != n_levels; ++l)
1217 15092 : mesh.comm().broadcast_packed_range(&mesh,
1218 29324 : mesh.level_elements_begin(l),
1219 29324 : mesh.level_elements_end(l),
1220 : &mesh,
1221 : null_output_iterator<Elem>());
1222 :
1223 : // Make sure mesh_dimension and elem_dimensions are consistent.
1224 14662 : mesh.cache_elem_data();
1225 :
1226 : // Make sure mesh id counts are consistent.
1227 14662 : mesh.update_parallel_id_counts();
1228 :
1229 : // We may have constraint rows on IsoGeometric Analysis meshes. We
1230 : // don't want to send these along with constrained nodes (like we
1231 : // send boundary info for those nodes) because the associated rows'
1232 : // elements may not exist at that point.
1233 : //
1234 : // We know we're not changing n_constraint_rows(), so we're using
1235 : // friend class status here rather than using the setter that
1236 : // invalidates caches.
1237 14232 : auto & constraint_rows = mesh._constraint_rows;
1238 :
1239 14662 : bool have_constraint_rows = !constraint_rows.empty();
1240 14662 : mesh.comm().broadcast(have_constraint_rows);
1241 14662 : if (have_constraint_rows)
1242 : {
1243 : std::map<dof_id_type,
1244 : std::vector<std::tuple<dof_id_type, unsigned int, Real>>>
1245 40 : serialized_rows;
1246 :
1247 60074 : for (auto & row : constraint_rows)
1248 : {
1249 59366 : const Node * node = row.first;
1250 59366 : const dof_id_type rowid = node->id();
1251 5850 : libmesh_assert(node == mesh.node_ptr(rowid));
1252 :
1253 : std::vector<std::tuple<dof_id_type, unsigned int, Real>>
1254 11700 : serialized_row;
1255 183373 : for (auto & entry : row.second)
1256 : serialized_row.push_back
1257 124007 : (std::make_tuple(entry.first.first->id(),
1258 12215 : entry.first.second, entry.second));
1259 :
1260 53516 : serialized_rows.emplace(rowid, std::move(serialized_row));
1261 : }
1262 :
1263 708 : mesh.comm().broadcast(serialized_rows);
1264 728 : if (mesh.processor_id() != 0)
1265 : {
1266 10 : constraint_rows.clear();
1267 :
1268 346615 : for (auto & row : serialized_rows)
1269 : {
1270 346016 : const dof_id_type rowid = row.first;
1271 346016 : const Node * node = mesh.node_ptr(rowid);
1272 :
1273 : std::vector<std::pair<std::pair<const Elem *, unsigned int>, Real>>
1274 11700 : deserialized_row;
1275 1068558 : for (auto & entry : row.second)
1276 : deserialized_row.push_back
1277 1445084 : (std::make_pair(std::make_pair(mesh.elem_ptr(std::get<0>(entry)),
1278 36645 : std::get<1>(entry)),
1279 36645 : std::get<2>(entry)));
1280 :
1281 340166 : constraint_rows.emplace(node, deserialized_row);
1282 : }
1283 : }
1284 : }
1285 :
1286 : // Broadcast all of the named entity information
1287 14662 : mesh.comm().broadcast(mesh.set_subdomain_name_map());
1288 14662 : mesh.comm().broadcast(mesh.get_boundary_info().set_sideset_name_map());
1289 14662 : mesh.comm().broadcast(mesh.get_boundary_info().set_nodeset_name_map());
1290 :
1291 : // If we had a point locator, it's invalid now that there are new
1292 : // elements it can't locate.
1293 14662 : mesh.clear_point_locator();
1294 :
1295 430 : libmesh_assert (mesh.comm().verify(mesh.n_elem()));
1296 430 : libmesh_assert (mesh.comm().verify(mesh.max_elem_id()));
1297 430 : libmesh_assert (mesh.comm().verify(mesh.n_nodes()));
1298 430 : libmesh_assert (mesh.comm().verify(mesh.max_node_id()));
1299 :
1300 : #ifdef DEBUG
1301 430 : MeshTools::libmesh_assert_valid_procids<Elem>(mesh);
1302 430 : MeshTools::libmesh_assert_valid_procids<Node>(mesh);
1303 : #endif
1304 : }
1305 : #endif // LIBMESH_HAVE_MPI
1306 :
1307 :
1308 :
1309 : #ifndef LIBMESH_HAVE_MPI // avoid spurious gcc warnings
1310 : // ------------------------------------------------------------
1311 : void MeshCommunication::gather (const processor_id_type, MeshBase &) const
1312 : {
1313 : // no MPI == one processor, no need for this method...
1314 : return;
1315 : }
1316 : #else
1317 : // ------------------------------------------------------------
1318 116894 : void MeshCommunication::gather (const processor_id_type root_id, MeshBase & mesh) const
1319 : {
1320 : // Check for quick return
1321 116966 : if (mesh.n_processors() == 1)
1322 1099 : return;
1323 :
1324 : // This function must be run on all processors at once
1325 72 : libmesh_parallel_only(mesh.comm());
1326 :
1327 216 : LOG_SCOPE("(all)gather()", "MeshCommunication");
1328 :
1329 : // Ensure we don't build too big a buffer at once
1330 : static const std::size_t approx_total_buffer_size = 1e8;
1331 : const std::size_t approx_each_buffer_size =
1332 115795 : approx_total_buffer_size / mesh.comm().size();
1333 :
1334 115795 : (root_id == DofObject::invalid_processor_id) ?
1335 :
1336 101967 : mesh.comm().allgather_packed_range (&mesh,
1337 101967 : mesh.nodes_begin(),
1338 217700 : mesh.nodes_end(),
1339 : null_output_iterator<Node>(),
1340 : approx_each_buffer_size) :
1341 :
1342 13900 : mesh.comm().gather_packed_range (root_id,
1343 : &mesh,
1344 129685 : mesh.nodes_begin(),
1345 143565 : mesh.nodes_end(),
1346 : null_output_iterator<Node>(),
1347 : approx_each_buffer_size);
1348 :
1349 : // Gather elements from coarsest to finest, so that child
1350 : // elements will see their parents already in place.
1351 115795 : const unsigned int n_levels = MeshTools::n_levels(mesh);
1352 :
1353 311364 : for (unsigned int l=0; l != n_levels; ++l)
1354 195569 : (root_id == DofObject::invalid_processor_id) ?
1355 :
1356 175063 : mesh.comm().allgather_packed_range (&mesh,
1357 175063 : mesh.level_elements_begin(l),
1358 545473 : mesh.level_elements_end(l),
1359 : null_output_iterator<Elem>(),
1360 : approx_each_buffer_size) :
1361 :
1362 20594 : mesh.comm().gather_packed_range (root_id,
1363 : &mesh,
1364 216149 : mesh.level_elements_begin(l),
1365 236715 : mesh.level_elements_end(l),
1366 : null_output_iterator<Elem>(),
1367 : approx_each_buffer_size);
1368 :
1369 : // If we had a point locator, it's invalid now that there are new
1370 : // elements it can't locate.
1371 115795 : mesh.clear_point_locator();
1372 :
1373 : // We may have constraint rows on IsoGeometric Analysis meshes. We
1374 : // don't want to send these along with constrained nodes (like we
1375 : // send boundary info for those nodes) because the associated rows'
1376 : // elements may not exist at that point.
1377 : //
1378 : // We know we're not changing n_constraint_rows(), so we're using
1379 : // friend class status here rather than using the setter that
1380 : // invalidates caches.
1381 115723 : auto & constraint_rows = mesh._constraint_rows;
1382 115795 : bool have_constraint_rows = !constraint_rows.empty();
1383 115795 : mesh.comm().max(have_constraint_rows);
1384 115795 : if (have_constraint_rows)
1385 : {
1386 : std::map<dof_id_type,
1387 : std::vector<std::tuple<dof_id_type, unsigned int, Real>>>
1388 0 : serialized_rows;
1389 :
1390 361 : for (auto & row : constraint_rows)
1391 : {
1392 238 : const Node * node = row.first;
1393 238 : const dof_id_type rowid = node->id();
1394 0 : libmesh_assert(node == mesh.node_ptr(rowid));
1395 :
1396 : std::vector<std::tuple<dof_id_type, unsigned int, Real>>
1397 0 : serialized_row;
1398 714 : for (auto & entry : row.second)
1399 : serialized_row.push_back
1400 476 : (std::make_tuple(entry.first.first->id(),
1401 0 : entry.first.second, entry.second));
1402 :
1403 238 : serialized_rows.emplace(rowid, std::move(serialized_row));
1404 : }
1405 :
1406 123 : if (root_id == DofObject::invalid_processor_id)
1407 123 : mesh.comm().set_union(serialized_rows);
1408 : else
1409 0 : mesh.comm().set_union(serialized_rows, root_id);
1410 :
1411 123 : if (root_id == DofObject::invalid_processor_id ||
1412 0 : root_id == mesh.processor_id())
1413 : {
1414 918 : for (auto & row : serialized_rows)
1415 : {
1416 795 : const dof_id_type rowid = row.first;
1417 795 : const Node * node = mesh.node_ptr(rowid);
1418 :
1419 : std::vector<std::pair<std::pair<const Elem *, unsigned int>, Real>>
1420 0 : deserialized_row;
1421 2385 : for (auto & entry : row.second)
1422 : deserialized_row.push_back
1423 3180 : (std::make_pair(std::make_pair(mesh.elem_ptr(std::get<0>(entry)),
1424 0 : std::get<1>(entry)),
1425 0 : std::get<2>(entry)));
1426 :
1427 795 : constraint_rows.emplace(node, deserialized_row);
1428 : }
1429 : }
1430 : #ifdef DEBUG
1431 0 : MeshTools::libmesh_assert_valid_constraint_rows(mesh);
1432 : #endif
1433 : }
1434 :
1435 :
1436 : // If we are doing an allgather(), perform sanity check on the result.
1437 72 : if (root_id == DofObject::invalid_processor_id)
1438 : {
1439 62 : libmesh_assert (mesh.comm().verify(mesh.n_elem()));
1440 62 : libmesh_assert (mesh.comm().verify(mesh.n_nodes()));
1441 : }
1442 :
1443 : // Inform new elements of their neighbors,
1444 : // while resetting all remote_elem links on
1445 : // the ranks which did the gather.
1446 115795 : if (mesh.allow_find_neighbors())
1447 208322 : mesh.find_neighbors(root_id == DofObject::invalid_processor_id ||
1448 144 : root_id == mesh.processor_id());
1449 :
1450 : // All done, but let's make sure it's done correctly
1451 :
1452 : #ifdef DEBUG
1453 72 : MeshTools::libmesh_assert_valid_boundary_ids(mesh);
1454 : #endif
1455 : }
1456 : #endif // LIBMESH_HAVE_MPI
1457 :
1458 :
1459 :
1460 : // Functor for make_elems_parallel_consistent and
1461 : // make_node_ids_parallel_consistent
1462 : namespace {
1463 :
1464 : struct SyncIds
1465 : {
1466 : typedef dof_id_type datum;
1467 : typedef void (MeshBase::*renumber_obj)(dof_id_type, dof_id_type);
1468 :
1469 22593 : SyncIds(MeshBase & _mesh, renumber_obj _renumberer) :
1470 22517 : mesh(_mesh),
1471 22593 : renumber(_renumberer) {}
1472 :
1473 : MeshBase & mesh;
1474 : renumber_obj renumber;
1475 : // renumber_obj & renumber;
1476 :
1477 : // Find the id of each requested DofObject -
1478 : // Parallel::sync_* already did the work for us
1479 34 : void gather_data (const std::vector<dof_id_type> & ids,
1480 : std::vector<datum> & ids_out) const
1481 : {
1482 67936 : ids_out = ids;
1483 67902 : }
1484 :
1485 67936 : void act_on_data (const std::vector<dof_id_type> & old_ids,
1486 : const std::vector<datum> & new_ids) const
1487 : {
1488 2753571 : for (auto i : index_range(old_ids))
1489 2688099 : if (old_ids[i] != new_ids[i])
1490 2640442 : (mesh.*renumber)(old_ids[i], new_ids[i]);
1491 67936 : }
1492 : };
1493 :
1494 :
1495 31442 : struct SyncNodeIds
1496 : {
1497 : typedef dof_id_type datum;
1498 :
1499 31538 : SyncNodeIds(MeshBase & _mesh) :
1500 31538 : mesh(_mesh) {}
1501 :
1502 : MeshBase & mesh;
1503 :
1504 : // We only know a Node id() is definitive if we own the Node or if
1505 : // we're told it's definitive. We keep track of the latter cases by
1506 : // putting definitively id'd ghost nodes into this set.
1507 : typedef std::unordered_set<const Node *> uset_type;
1508 : uset_type definitive_ids;
1509 :
1510 : // We should never be told two different definitive ids for the same
1511 : // node, but let's check on that in debug mode.
1512 : #ifdef DEBUG
1513 : typedef std::unordered_map<dof_id_type, dof_id_type> umap_type;
1514 : umap_type definitive_renumbering;
1515 : #endif
1516 :
1517 : // Find the id of each requested DofObject -
1518 : // Parallel::sync_* already tried to do the work for us, but we can
1519 : // only say the result is definitive if we own the DofObject or if
1520 : // we were given the definitive result from another processor.
1521 299860 : void gather_data (const std::vector<dof_id_type> & ids,
1522 : std::vector<datum> & ids_out) const
1523 : {
1524 132 : ids_out.clear();
1525 299992 : ids_out.resize(ids.size(), DofObject::invalid_id);
1526 :
1527 61280806 : for (auto i : index_range(ids))
1528 : {
1529 60980946 : const dof_id_type id = ids[i];
1530 60980946 : const Node * node = mesh.query_node_ptr(id);
1531 60980946 : if (node && (node->processor_id() == mesh.processor_id() ||
1532 33924 : definitive_ids.count(node)))
1533 61014586 : ids_out[i] = id;
1534 : }
1535 299860 : }
1536 :
1537 299860 : bool act_on_data (const std::vector<dof_id_type> & old_ids,
1538 : const std::vector<datum> & new_ids)
1539 : {
1540 132 : bool data_changed = false;
1541 61280806 : for (auto i : index_range(old_ids))
1542 : {
1543 60980946 : const dof_id_type new_id = new_ids[i];
1544 :
1545 60980946 : const dof_id_type old_id = old_ids[i];
1546 :
1547 60980946 : Node * node = mesh.query_node_ptr(old_id);
1548 :
1549 : // If we can't find the node we were asking about, another
1550 : // processor must have already given us the definitive id
1551 : // for it
1552 60980946 : if (!node)
1553 : {
1554 : // But let's check anyway in debug mode
1555 : #ifdef DEBUG
1556 5626 : libmesh_assert
1557 : (definitive_renumbering.count(old_id));
1558 5626 : libmesh_assert_equal_to
1559 : (new_id, definitive_renumbering[old_id]);
1560 : #endif
1561 11662092 : continue;
1562 : }
1563 :
1564 : // If we asked for an id but there's no definitive id ready
1565 : // for us yet, then we can't quit trying to sync yet.
1566 49313228 : if (new_id == DofObject::invalid_id)
1567 : {
1568 : // But we might have gotten a definitive id from a
1569 : // different request
1570 284 : if (!definitive_ids.count(mesh.node_ptr(old_id)))
1571 0 : data_changed = true;
1572 : }
1573 : else
1574 : {
1575 49341242 : if (node->processor_id() != mesh.processor_id())
1576 46812 : definitive_ids.insert(node);
1577 49312944 : if (old_id != new_id)
1578 : {
1579 : #ifdef DEBUG
1580 3234 : libmesh_assert
1581 : (!definitive_renumbering.count(old_id));
1582 3234 : definitive_renumbering[old_id] = new_id;
1583 : #endif
1584 4941362 : mesh.renumber_node(old_id, new_id);
1585 3234 : data_changed = true;
1586 : }
1587 : }
1588 : }
1589 299860 : return data_changed;
1590 : }
1591 : };
1592 :
1593 :
1594 : #ifdef LIBMESH_ENABLE_AMR
1595 : struct SyncPLevels
1596 : {
1597 : typedef std::pair<unsigned char,unsigned char> datum;
1598 :
1599 2560 : SyncPLevels(MeshBase & _mesh) :
1600 2560 : mesh(_mesh) {}
1601 :
1602 : MeshBase & mesh;
1603 :
1604 : // Find the p_level of each requested Elem
1605 3346 : void gather_data (const std::vector<dof_id_type> & ids,
1606 : std::vector<datum> & ids_out) const
1607 : {
1608 3346 : ids_out.reserve(ids.size());
1609 :
1610 18571 : for (const auto & id : ids)
1611 : {
1612 15225 : Elem & elem = mesh.elem_ref(id);
1613 : ids_out.push_back
1614 15225 : (std::make_pair(cast_int<unsigned char>(elem.p_level()),
1615 0 : static_cast<unsigned char>(elem.p_refinement_flag())));
1616 : }
1617 3346 : }
1618 :
1619 3346 : void act_on_data (const std::vector<dof_id_type> & old_ids,
1620 : const std::vector<datum> & new_p_levels) const
1621 : {
1622 18571 : for (auto i : index_range(old_ids))
1623 : {
1624 15225 : Elem & elem = mesh.elem_ref(old_ids[i]);
1625 : // Make sure these are consistent
1626 : elem.hack_p_level_and_refinement_flag
1627 15225 : (new_p_levels[i].first,
1628 15225 : static_cast<Elem::RefinementState>(new_p_levels[i].second));
1629 : // Make sure parents' levels are consistent
1630 15225 : elem.set_p_level(new_p_levels[i].first);
1631 : }
1632 3346 : }
1633 : };
1634 : #endif // LIBMESH_ENABLE_AMR
1635 :
1636 :
1637 : #ifdef LIBMESH_ENABLE_UNIQUE_ID
1638 : template <typename DofObjSubclass>
1639 : struct SyncUniqueIds
1640 : {
1641 : typedef unique_id_type datum;
1642 : typedef DofObjSubclass* (MeshBase::*query_obj)(const dof_id_type);
1643 :
1644 57590 : SyncUniqueIds(MeshBase &_mesh, query_obj _querier) :
1645 57342 : mesh(_mesh),
1646 57590 : query(_querier) {}
1647 :
1648 : MeshBase & mesh;
1649 : query_obj query;
1650 :
1651 : // Find the id of each requested DofObject -
1652 : // Parallel::sync_* already did the work for us
1653 214617 : void gather_data (const std::vector<dof_id_type> & ids,
1654 : std::vector<datum> & ids_out) const
1655 : {
1656 214713 : ids_out.reserve(ids.size());
1657 :
1658 9993919 : for (const auto & id : ids)
1659 : {
1660 9779302 : DofObjSubclass * d = (mesh.*query)(id);
1661 6712 : libmesh_assert(d);
1662 9779302 : ids_out.push_back(d->unique_id());
1663 : }
1664 214617 : }
1665 :
1666 214617 : void act_on_data (const std::vector<dof_id_type> & ids,
1667 : const std::vector<datum> & unique_ids) const
1668 : {
1669 9993919 : for (auto i : index_range(ids))
1670 : {
1671 9779302 : DofObjSubclass * d = (mesh.*query)(ids[i]);
1672 6712 : libmesh_assert(d);
1673 9786014 : d->set_unique_id(unique_ids[i]);
1674 : }
1675 214617 : }
1676 : };
1677 : #endif // LIBMESH_ENABLE_UNIQUE_ID
1678 :
1679 : template <typename DofObjSubclass>
1680 : struct SyncBCIds
1681 : {
1682 : typedef std::vector<boundary_id_type> datum;
1683 :
1684 22593 : SyncBCIds(MeshBase &_mesh) :
1685 22593 : mesh(_mesh) {}
1686 :
1687 : MeshBase & mesh;
1688 :
1689 : // Find the id of each requested DofObject -
1690 : // Parallel::sync_* already did the work for us
1691 92767 : void gather_data (const std::vector<dof_id_type> & ids,
1692 : std::vector<datum> & ids_out) const
1693 : {
1694 92767 : ids_out.reserve(ids.size());
1695 :
1696 92767 : const BoundaryInfo & boundary_info = mesh.get_boundary_info();
1697 :
1698 6177481 : for (const auto & id : ids)
1699 : {
1700 6084714 : Node * n = mesh.query_node_ptr(id);
1701 2981 : libmesh_assert(n);
1702 5962 : std::vector<boundary_id_type> bcids;
1703 6084714 : boundary_info.boundary_ids(n, bcids);
1704 2981 : ids_out.push_back(std::move(bcids));
1705 : }
1706 92767 : }
1707 :
1708 92767 : void act_on_data (const std::vector<dof_id_type> & ids,
1709 : const std::vector<datum> & bcids) const
1710 : {
1711 92767 : BoundaryInfo & boundary_info = mesh.get_boundary_info();
1712 :
1713 6177481 : for (auto i : index_range(ids))
1714 : {
1715 6084714 : Node * n = mesh.query_node_ptr(ids[i]);
1716 2981 : libmesh_assert(n);
1717 6084714 : boundary_info.add_node(n, bcids[i]);
1718 : }
1719 92767 : }
1720 : };
1721 :
1722 : }
1723 :
1724 :
1725 :
1726 : // ------------------------------------------------------------
1727 31538 : void MeshCommunication::make_node_ids_parallel_consistent (MeshBase & mesh)
1728 : {
1729 : // This function must be run on all processors at once
1730 48 : libmesh_parallel_only(mesh.comm());
1731 :
1732 : // We need to agree on which processor owns every node, but we can't
1733 : // easily assert that here because we don't currently agree on which
1734 : // id every node has, and some of our temporary ids on unrelated
1735 : // nodes will "overlap".
1736 : //#ifdef DEBUG
1737 : // MeshTools::libmesh_assert_parallel_consistent_procids<Node> (mesh);
1738 : //#endif // DEBUG
1739 :
1740 144 : LOG_SCOPE ("make_node_ids_parallel_consistent()", "MeshCommunication");
1741 :
1742 96 : SyncNodeIds syncids(mesh);
1743 : Parallel::sync_node_data_by_element_id
1744 94518 : (mesh, mesh.elements_begin(), mesh.elements_end(),
1745 31490 : Parallel::SyncEverything(), Parallel::SyncEverything(), syncids);
1746 :
1747 : // At this point, with both ids and processor ids synced, we can
1748 : // finally check for topological consistency of node processor ids.
1749 : #ifdef DEBUG
1750 48 : MeshTools::libmesh_assert_topology_consistent_procids<Node> (mesh);
1751 : #endif
1752 31538 : }
1753 :
1754 :
1755 :
1756 34997 : void MeshCommunication::make_node_unique_ids_parallel_consistent (MeshBase & mesh)
1757 : {
1758 : // Avoid unused variable warnings if unique ids aren't enabled.
1759 86 : libmesh_ignore(mesh);
1760 :
1761 : // This function must be run on all processors at once
1762 86 : libmesh_parallel_only(mesh.comm());
1763 :
1764 : #ifdef LIBMESH_ENABLE_UNIQUE_ID
1765 172 : LOG_SCOPE ("make_node_unique_ids_parallel_consistent()", "MeshCommunication");
1766 :
1767 86 : SyncUniqueIds<Node> syncuniqueids(mesh, &MeshBase::query_node_ptr);
1768 172 : Parallel::sync_dofobject_data_by_id(mesh.comm(),
1769 69994 : mesh.nodes_begin(),
1770 35169 : mesh.nodes_end(),
1771 : syncuniqueids);
1772 :
1773 : #endif
1774 34997 : }
1775 :
1776 :
1777 22593 : void MeshCommunication::make_node_bcids_parallel_consistent (MeshBase & mesh)
1778 : {
1779 : // Avoid unused variable warnings if unique ids aren't enabled.
1780 38 : libmesh_ignore(mesh);
1781 :
1782 : // This function must be run on all processors at once
1783 38 : libmesh_parallel_only(mesh.comm());
1784 :
1785 76 : LOG_SCOPE ("make_node_bcids_parallel_consistent()", "MeshCommunication");
1786 :
1787 38 : SyncBCIds<Node> syncbcids(mesh);
1788 76 : Parallel::sync_dofobject_data_by_id(mesh.comm(),
1789 45186 : mesh.nodes_begin(),
1790 22669 : mesh.nodes_end(),
1791 : syncbcids);
1792 22593 : }
1793 :
1794 :
1795 :
1796 :
1797 :
1798 : // ------------------------------------------------------------
1799 22593 : void MeshCommunication::make_elems_parallel_consistent(MeshBase & mesh)
1800 : {
1801 : // This function must be run on all processors at once
1802 38 : libmesh_parallel_only(mesh.comm());
1803 :
1804 76 : LOG_SCOPE ("make_elems_parallel_consistent()", "MeshCommunication");
1805 :
1806 38 : SyncIds syncids(mesh, &MeshBase::renumber_elem);
1807 : Parallel::sync_element_data_by_parent_id
1808 45148 : (mesh, mesh.active_elements_begin(),
1809 22631 : mesh.active_elements_end(), syncids);
1810 :
1811 : #ifdef LIBMESH_ENABLE_UNIQUE_ID
1812 38 : SyncUniqueIds<Elem> syncuniqueids(mesh, &MeshBase::query_elem_ptr);
1813 : Parallel::sync_dofobject_data_by_id
1814 45148 : (mesh.comm(), mesh.active_elements_begin(),
1815 22669 : mesh.active_elements_end(), syncuniqueids);
1816 : #endif
1817 22593 : }
1818 :
1819 :
1820 :
1821 : // ------------------------------------------------------------
1822 : #ifdef LIBMESH_ENABLE_AMR
1823 2560 : void MeshCommunication::make_p_levels_parallel_consistent(MeshBase & mesh)
1824 : {
1825 : // This function must be run on all processors at once
1826 0 : libmesh_parallel_only(mesh.comm());
1827 :
1828 0 : LOG_SCOPE ("make_p_levels_parallel_consistent()", "MeshCommunication");
1829 :
1830 0 : SyncPLevels syncplevels(mesh);
1831 : Parallel::sync_dofobject_data_by_id
1832 5120 : (mesh.comm(), mesh.elements_begin(), mesh.elements_end(),
1833 : syncplevels);
1834 2560 : }
1835 : #endif // LIBMESH_ENABLE_AMR
1836 :
1837 :
1838 :
1839 : // Functors for make_node_proc_ids_parallel_consistent
1840 : namespace {
1841 :
1842 : struct SyncProcIds
1843 : {
1844 : typedef processor_id_type datum;
1845 :
1846 31538 : SyncProcIds(MeshBase & _mesh) : mesh(_mesh) {}
1847 :
1848 : MeshBase & mesh;
1849 :
1850 : // ------------------------------------------------------------
1851 250831 : void gather_data (const std::vector<dof_id_type> & ids,
1852 : std::vector<datum> & data)
1853 : {
1854 : // Find the processor id of each requested node
1855 250831 : data.resize(ids.size());
1856 :
1857 51104519 : for (auto i : index_range(ids))
1858 : {
1859 : // Look for this point in the mesh
1860 50853688 : if (ids[i] != DofObject::invalid_id)
1861 : {
1862 50853688 : Node & node = mesh.node_ref(ids[i]);
1863 :
1864 : // Return the node's correct processor id,
1865 50853688 : data[i] = node.processor_id();
1866 : }
1867 : else
1868 0 : data[i] = DofObject::invalid_processor_id;
1869 : }
1870 250831 : }
1871 :
1872 : // ------------------------------------------------------------
1873 250831 : bool act_on_data (const std::vector<dof_id_type> & ids,
1874 : const std::vector<datum> proc_ids)
1875 : {
1876 86 : bool data_changed = false;
1877 :
1878 : // Set the ghost node processor ids we've now been informed of
1879 51104519 : for (auto i : index_range(ids))
1880 : {
1881 50853688 : Node & node = mesh.node_ref(ids[i]);
1882 :
1883 : // We may not have ids synched when this synchronization is done, so we
1884 : // *can't* use id to load-balance processor id properly; we have to use
1885 : // the old heuristic of choosing the smallest valid processor id.
1886 : //
1887 : // If someone tells us our node processor id is too low, then
1888 : // they're wrong. If they tell us our node processor id is
1889 : // too high, then we're wrong.
1890 50853688 : if (node.processor_id() > proc_ids[i])
1891 : {
1892 0 : data_changed = true;
1893 87746 : node.processor_id() = proc_ids[i];
1894 : }
1895 : }
1896 :
1897 250831 : return data_changed;
1898 : }
1899 : };
1900 :
1901 :
1902 : struct ElemNodesMaybeNew
1903 : {
1904 38 : ElemNodesMaybeNew() {}
1905 :
1906 16932906 : bool operator() (const Elem * elem) const
1907 : {
1908 : // If this element was just refined then it may have new nodes we
1909 : // need to work on
1910 : #ifdef LIBMESH_ENABLE_AMR
1911 16932906 : if (elem->refinement_flag() == Elem::JUST_REFINED)
1912 7896 : return true;
1913 : #endif
1914 :
1915 : // If this element has remote_elem neighbors then there may have
1916 : // been refinement of those neighbors that affect its nodes'
1917 : // processor_id()
1918 14025554 : for (auto neigh : elem->neighbor_ptr_range())
1919 11681530 : if (neigh == remote_elem)
1920 896608 : return true;
1921 2344024 : return false;
1922 : }
1923 : };
1924 :
1925 :
1926 22517 : struct NodeWasNew
1927 : {
1928 22593 : NodeWasNew(const MeshBase & mesh)
1929 22593 : {
1930 17271606 : for (const auto & node : mesh.node_ptr_range())
1931 8625575 : if (node->processor_id() == DofObject::invalid_processor_id)
1932 32995 : was_new.insert(node);
1933 22593 : }
1934 :
1935 95031778 : bool operator() (const Elem * elem, unsigned int local_node_num) const
1936 : {
1937 95031778 : if (was_new.count(elem->node_ptr(local_node_num)))
1938 61754910 : return true;
1939 9602 : return false;
1940 : }
1941 :
1942 : std::unordered_set<const Node *> was_new;
1943 : };
1944 :
1945 : }
1946 :
1947 :
1948 :
1949 : // ------------------------------------------------------------
1950 8945 : void MeshCommunication::make_node_proc_ids_parallel_consistent(MeshBase & mesh)
1951 : {
1952 10 : LOG_SCOPE ("make_node_proc_ids_parallel_consistent()", "MeshCommunication");
1953 :
1954 : // This function must be run on all processors at once
1955 10 : libmesh_parallel_only(mesh.comm());
1956 :
1957 : // When this function is called, each section of a parallelized mesh
1958 : // should be in the following state:
1959 : //
1960 : // All nodes should have the exact same physical location on every
1961 : // processor where they exist.
1962 : //
1963 : // Local nodes should have unique authoritative ids,
1964 : // and processor ids consistent with all processors which own
1965 : // an element touching them.
1966 : //
1967 : // Ghost nodes touching local elements should have processor ids
1968 : // consistent with all processors which own an element touching
1969 : // them.
1970 10 : SyncProcIds sync(mesh);
1971 : Parallel::sync_node_data_by_element_id
1972 26815 : (mesh, mesh.elements_begin(), mesh.elements_end(),
1973 8945 : Parallel::SyncEverything(), Parallel::SyncEverything(), sync);
1974 8945 : }
1975 :
1976 :
1977 :
1978 : // ------------------------------------------------------------
1979 22593 : void MeshCommunication::make_new_node_proc_ids_parallel_consistent(MeshBase & mesh)
1980 : {
1981 114 : LOG_SCOPE ("make_new_node_proc_ids_parallel_consistent()", "MeshCommunication");
1982 :
1983 : // This function must be run on all processors at once
1984 38 : libmesh_parallel_only(mesh.comm());
1985 :
1986 : // When this function is called, each section of a parallelized mesh
1987 : // should be in the following state:
1988 : //
1989 : // Local nodes should have unique authoritative ids,
1990 : // and new nodes should be unpartitioned.
1991 : //
1992 : // New ghost nodes touching local elements should be unpartitioned.
1993 :
1994 : // We may not have consistent processor ids for new nodes (because a
1995 : // node may be old and partitioned on one processor but new and
1996 : // unpartitioned on another) when we start
1997 : #ifdef DEBUG
1998 38 : MeshTools::libmesh_assert_parallel_consistent_procids<Node>(mesh);
1999 : // MeshTools::libmesh_assert_parallel_consistent_new_node_procids(mesh);
2000 : #endif
2001 :
2002 : // We have two kinds of new nodes. *NEW* nodes are unpartitioned on
2003 : // all processors: we need to use a id-independent (i.e. dumb)
2004 : // heuristic to partition them. But "new" nodes are newly created
2005 : // on some processors (when ghost elements are refined) yet
2006 : // correspond to existing nodes on other processors: we need to use
2007 : // the existing processor id for them.
2008 : //
2009 : // A node which is "new" on one processor will be associated with at
2010 : // least one ghost element, and we can just query that ghost
2011 : // element's owner to find out the correct processor id.
2012 :
2013 : auto node_unpartitioned =
2014 24034 : [](const Elem * elem, unsigned int local_node_num)
2015 24034 : { return elem->node_ref(local_node_num).processor_id() ==
2016 24034 : DofObject::invalid_processor_id; };
2017 :
2018 38 : SyncProcIds sync(mesh);
2019 :
2020 : sync_node_data_by_element_id_once
2021 67703 : (mesh, mesh.not_local_elements_begin(),
2022 22631 : mesh.not_local_elements_end(), Parallel::SyncEverything(),
2023 : node_unpartitioned, sync);
2024 :
2025 : // Nodes should now be unpartitioned iff they are truly new; those
2026 : // are the *only* nodes we will touch.
2027 : #ifdef DEBUG
2028 38 : MeshTools::libmesh_assert_parallel_consistent_new_node_procids(mesh);
2029 : #endif
2030 :
2031 22631 : NodeWasNew node_was_new(mesh);
2032 :
2033 : // Set the lowest processor id we can on truly new nodes
2034 9522250 : for (auto & elem : mesh.element_ptr_range())
2035 44405758 : for (auto & node : elem->node_ref_range())
2036 39656171 : if (node_was_new.was_new.count(&node))
2037 : {
2038 18292 : processor_id_type & pid = node.processor_id();
2039 29535475 : pid = std::min(pid, elem->processor_id());
2040 22517 : }
2041 :
2042 : // Then finally see if other processors have a lower option
2043 : Parallel::sync_node_data_by_element_id
2044 67703 : (mesh, mesh.elements_begin(), mesh.elements_end(),
2045 22555 : ElemNodesMaybeNew(), node_was_new, sync);
2046 :
2047 : // We should have consistent processor ids when we're done.
2048 : #ifdef DEBUG
2049 38 : MeshTools::libmesh_assert_parallel_consistent_procids<Node>(mesh);
2050 38 : MeshTools::libmesh_assert_parallel_consistent_new_node_procids(mesh);
2051 : #endif
2052 22593 : }
2053 :
2054 :
2055 :
2056 : // ------------------------------------------------------------
2057 8865 : void MeshCommunication::make_nodes_parallel_consistent (MeshBase & mesh)
2058 : {
2059 : // This function must be run on all processors at once
2060 10 : libmesh_parallel_only(mesh.comm());
2061 :
2062 : // When this function is called, each section of a parallelized mesh
2063 : // should be in the following state:
2064 : //
2065 : // Element ids and locations should be consistent on every processor
2066 : // where they exist.
2067 : //
2068 : // All nodes should have the exact same physical location on every
2069 : // processor where they exist.
2070 : //
2071 : // Local nodes should have unique authoritative ids,
2072 : // and processor ids consistent with all processors which own
2073 : // an element touching them.
2074 : //
2075 : // Ghost nodes touching local elements should have processor ids
2076 : // consistent with all processors which own an element touching
2077 : // them.
2078 : //
2079 : // Ghost nodes should have ids which are either already correct
2080 : // or which are in the "unpartitioned" id space.
2081 :
2082 : // First, let's sync up processor ids. Some of these processor ids
2083 : // may be "wrong" from coarsening, but they're right in the sense
2084 : // that they'll tell us who has the authoritative dofobject ids for
2085 : // each node.
2086 :
2087 8865 : this->make_node_proc_ids_parallel_consistent(mesh);
2088 :
2089 : // Second, sync up dofobject ids.
2090 8865 : this->make_node_ids_parallel_consistent(mesh);
2091 :
2092 : // Third, sync up dofobject unique_ids if applicable.
2093 8865 : this->make_node_unique_ids_parallel_consistent(mesh);
2094 :
2095 : // Finally, correct the processor ids to make DofMap happy
2096 8865 : MeshTools::correct_node_proc_ids(mesh);
2097 8865 : }
2098 :
2099 :
2100 :
2101 : // ------------------------------------------------------------
2102 22593 : void MeshCommunication::make_new_nodes_parallel_consistent (MeshBase & mesh)
2103 : {
2104 : // This function must be run on all processors at once
2105 38 : libmesh_parallel_only(mesh.comm());
2106 :
2107 : // When this function is called, each section of a parallelized mesh
2108 : // should be in the following state:
2109 : //
2110 : // All nodes should have the exact same physical location on every
2111 : // processor where they exist.
2112 : //
2113 : // Local nodes should have unique authoritative ids,
2114 : // and new nodes should be unpartitioned.
2115 : //
2116 : // New ghost nodes touching local elements should be unpartitioned.
2117 : //
2118 : // New ghost nodes should have ids which are either already correct
2119 : // or which are in the "unpartitioned" id space.
2120 : //
2121 : // Non-new nodes should have correct ids and processor ids already.
2122 :
2123 : // First, let's sync up new nodes' processor ids.
2124 :
2125 22593 : this->make_new_node_proc_ids_parallel_consistent(mesh);
2126 :
2127 : // Second, sync up dofobject ids.
2128 22593 : this->make_node_ids_parallel_consistent(mesh);
2129 :
2130 : // Third, sync up dofobject unique_ids if applicable.
2131 22593 : this->make_node_unique_ids_parallel_consistent(mesh);
2132 :
2133 : // Fourth, sync up any nodal boundary conditions
2134 22593 : this->make_node_bcids_parallel_consistent(mesh);
2135 :
2136 : // Finally, correct the processor ids to make DofMap happy
2137 22593 : MeshTools::correct_node_proc_ids(mesh);
2138 22593 : }
2139 :
2140 :
2141 :
2142 : // ------------------------------------------------------------
2143 : void
2144 482223 : MeshCommunication::delete_remote_elements (DistributedMesh & mesh,
2145 : const std::set<Elem *> & extra_ghost_elem_ids) const
2146 : {
2147 : // The mesh should know it's about to be parallelized
2148 392 : libmesh_assert (!mesh.is_serial());
2149 :
2150 1176 : LOG_SCOPE("delete_remote_elements()", "MeshCommunication");
2151 :
2152 : #ifdef DEBUG
2153 : // We expect maximum ids to be in sync so we can use them to size
2154 : // vectors
2155 392 : libmesh_assert(mesh.comm().verify(mesh.max_node_id()));
2156 392 : libmesh_assert(mesh.comm().verify(mesh.max_elem_id()));
2157 392 : const dof_id_type par_max_node_id = mesh.parallel_max_node_id();
2158 392 : const dof_id_type par_max_elem_id = mesh.parallel_max_elem_id();
2159 392 : libmesh_assert_equal_to (par_max_node_id, mesh.max_node_id());
2160 392 : libmesh_assert_equal_to (par_max_elem_id, mesh.max_elem_id());
2161 :
2162 : // n_constraint_rows might not be cached, but we're in dbg mode,
2163 : // let's just (re)count them
2164 392 : const dof_id_type n_constraint_rows = mesh.count_constraint_rows();
2165 : #endif
2166 :
2167 784 : connected_elem_set_type elements_to_keep;
2168 :
2169 : // Don't delete elements that we were explicitly told not to
2170 482223 : for (const auto & elem : extra_ghost_elem_ids)
2171 : {
2172 0 : std::vector<const Elem *> active_family;
2173 : #ifdef LIBMESH_ENABLE_AMR
2174 0 : if (!elem->subactive())
2175 0 : elem->active_family_tree(active_family);
2176 : else
2177 : #endif
2178 0 : active_family.push_back(elem);
2179 :
2180 0 : for (const auto & f : active_family)
2181 0 : elements_to_keep.insert(f);
2182 : }
2183 :
2184 : // See which elements we still need to keep ghosted, given that
2185 : // we're keeping local and unpartitioned elements.
2186 : query_ghosting_functors
2187 483791 : (mesh, mesh.processor_id(),
2188 964838 : mesh.active_pid_elements_begin(mesh.processor_id()),
2189 483007 : mesh.active_pid_elements_end(mesh.processor_id()),
2190 : elements_to_keep);
2191 : query_ghosting_functors
2192 483399 : (mesh, DofObject::invalid_processor_id,
2193 964446 : mesh.active_pid_elements_begin(DofObject::invalid_processor_id),
2194 964054 : mesh.active_pid_elements_end(DofObject::invalid_processor_id),
2195 : elements_to_keep);
2196 :
2197 : // The inactive elements we need to send should have their
2198 : // immediate children present.
2199 1446277 : connect_children(mesh, mesh.pid_elements_begin(mesh.processor_id()),
2200 483007 : mesh.pid_elements_end(mesh.processor_id()),
2201 : elements_to_keep);
2202 483399 : connect_children(mesh,
2203 964446 : mesh.pid_elements_begin(DofObject::invalid_processor_id),
2204 964446 : mesh.pid_elements_end(DofObject::invalid_processor_id),
2205 : elements_to_keep);
2206 :
2207 : // And see which elements and nodes they depend on
2208 784 : connected_node_set_type connected_nodes;
2209 482223 : connect_element_dependencies(mesh, elements_to_keep, connected_nodes);
2210 :
2211 : // Delete all the elements we have no reason to save,
2212 : // starting with the most refined so that the mesh
2213 : // is valid at all intermediate steps
2214 482223 : unsigned int n_levels = MeshTools::n_levels(mesh);
2215 :
2216 1079195 : for (int l = n_levels - 1; l >= 0; --l)
2217 1212710 : for (auto & elem : as_range(mesh.level_elements_begin(l),
2218 103253592 : mesh.level_elements_end(l)))
2219 : {
2220 19252 : libmesh_assert (elem);
2221 : // Make sure we don't leave any invalid pointers
2222 55955 : const bool keep_me = elements_to_keep.count(elem);
2223 :
2224 19252 : if (!keep_me)
2225 36156743 : elem->make_links_to_me_remote();
2226 :
2227 : // delete_elem doesn't currently invalidate element
2228 : // iterators... that had better not change
2229 38504 : if (!keep_me)
2230 36156743 : mesh.delete_elem(elem);
2231 596000 : }
2232 :
2233 : // Delete all the nodes we have no reason to save
2234 175288448 : for (auto & node : mesh.node_ptr_range())
2235 : {
2236 51778 : libmesh_assert(node);
2237 152235 : if (!connected_nodes.count(node))
2238 : {
2239 3099 : libmesh_assert_not_equal_to(node->processor_id(),
2240 : mesh.processor_id());
2241 51085952 : mesh.delete_node(node);
2242 : }
2243 481439 : }
2244 :
2245 : // If we had a point locator, it's invalid now that some of the
2246 : // elements it pointed to have been deleted.
2247 482223 : mesh.clear_point_locator();
2248 :
2249 : // We now have all remote elements and nodes deleted; our ghosting
2250 : // functors should be ready to delete any now-redundant cached data
2251 : // they use too.
2252 1097318 : for (auto & gf : as_range(mesh.ghosting_functors_begin(), mesh.ghosting_functors_end()))
2253 615095 : gf->delete_remote_elements();
2254 :
2255 : #ifdef DEBUG
2256 392 : const dof_id_type n_new_constraint_rows = mesh.count_constraint_rows();
2257 392 : libmesh_assert_equal_to(n_constraint_rows, n_new_constraint_rows);
2258 :
2259 392 : MeshTools::libmesh_assert_valid_refinement_tree(mesh);
2260 392 : MeshTools::libmesh_assert_valid_constraint_rows(mesh);
2261 : #endif
2262 482223 : }
2263 :
2264 : } // namespace libMesh
|