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