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/distributed_mesh.h"
22 :
23 : // libMesh includes
24 : #include "libmesh/boundary_info.h"
25 : #include "libmesh/elem.h"
26 : #include "libmesh/libmesh_logging.h"
27 : #include "libmesh/mesh_communication.h"
28 : #include "libmesh/mesh_tools.h"
29 : #include "libmesh/partitioner.h"
30 : #include "libmesh/string_to_enum.h"
31 :
32 : // TIMPI includes
33 : #include "timpi/parallel_implementation.h"
34 : #include "timpi/parallel_sync.h"
35 :
36 :
37 : namespace libMesh
38 : {
39 :
40 : // ------------------------------------------------------------
41 : // DistributedMesh class member functions
42 298807 : DistributedMesh::DistributedMesh (const Parallel::Communicator & comm_in,
43 298807 : unsigned char d) :
44 298307 : UnstructuredMesh (comm_in,d), _is_serial(true),
45 298307 : _is_serial_on_proc_0(true),
46 298307 : _deleted_coarse_elements(false),
47 298307 : _n_nodes(0), _n_elem(0), _max_node_id(0), _max_elem_id(0),
48 299057 : _next_free_local_node_id(this->processor_id()),
49 298807 : _next_free_local_elem_id(this->processor_id()),
50 298807 : _next_free_unpartitioned_node_id(this->n_processors()),
51 298807 : _next_free_unpartitioned_elem_id(this->n_processors())
52 : #ifdef LIBMESH_ENABLE_UNIQUE_ID
53 298807 : , _next_unpartitioned_unique_id(this->n_processors())
54 : #endif
55 : {
56 : #ifdef LIBMESH_ENABLE_UNIQUE_ID
57 298807 : _next_unique_id = this->processor_id();
58 : #endif
59 :
60 299057 : const std::string default_partitioner = "parmetis";
61 : const std::string my_partitioner =
62 : libMesh::command_line_value("--default-partitioner",
63 597614 : default_partitioner);
64 : _partitioner = Partitioner::build
65 597364 : (Utility::string_to_enum<PartitionerType>(my_partitioner));
66 298807 : }
67 :
68 270 : DistributedMesh & DistributedMesh::operator= (DistributedMesh && other_mesh)
69 : {
70 4 : LOG_SCOPE("operator=(&&)", "DistributedMesh");
71 :
72 : // Move assign as an UnstructuredMesh.
73 4 : this->UnstructuredMesh::operator=(std::move(other_mesh));
74 :
75 : // Nodes and elements belong to DistributedMesh and have to be
76 : // moved before we can move arbitrary GhostingFunctor, Partitioner,
77 : // etc. subclasses.
78 270 : this->move_nodes_and_elements(std::move(other_mesh));
79 :
80 : // But move_nodes_and_elems misses (or guesses about) some of our
81 : // subclass values, and we want more precision than a guess.
82 270 : _deleted_coarse_elements = other_mesh._deleted_coarse_elements;
83 4 : _extra_ghost_elems = std::move(other_mesh._extra_ghost_elems);
84 :
85 : // Handle remaining MeshBase moves.
86 270 : this->post_dofobject_moves(std::move(other_mesh));
87 :
88 274 : return *this;
89 : }
90 :
91 270 : MeshBase & DistributedMesh::assign(MeshBase && other_mesh)
92 : {
93 270 : *this = std::move(cast_ref<DistributedMesh&>(other_mesh));
94 :
95 270 : return *this;
96 : }
97 :
98 13042 : std::string_view DistributedMesh::subclass_first_difference_from (const MeshBase & other_mesh_base) const
99 : {
100 724 : const DistributedMesh * dist_mesh_ptr =
101 13042 : dynamic_cast<const DistributedMesh *>(&other_mesh_base);
102 13042 : if (!dist_mesh_ptr)
103 0 : return "DistributedMesh class";
104 724 : const DistributedMesh & other_mesh = *dist_mesh_ptr;
105 :
106 : #define CHECK_MEMBER(member_name) \
107 : if (member_name != other_mesh.member_name) \
108 : return #member_name;
109 :
110 13042 : CHECK_MEMBER(_is_serial);
111 13042 : CHECK_MEMBER(_is_serial_on_proc_0);
112 13042 : CHECK_MEMBER(_deleted_coarse_elements);
113 13042 : CHECK_MEMBER(_n_nodes);
114 13042 : CHECK_MEMBER(_n_elem);
115 13042 : CHECK_MEMBER(_max_node_id);
116 13042 : CHECK_MEMBER(_max_elem_id);
117 : // We expect these things to change in a prepare_for_use();
118 : // they're conceptually "mutable"...
119 : /*
120 : CHECK_MEMBER(_next_free_local_node_id);
121 : CHECK_MEMBER(_next_free_local_elem_id);
122 : CHECK_MEMBER(_next_free_unpartitioned_node_id);
123 : CHECK_MEMBER(_next_free_unpartitioned_elem_id);
124 : #ifdef LIBMESH_ENABLE_UNIQUE_ID
125 : CHECK_MEMBER(_next_unpartitioned_unique_id);
126 : #endif
127 : */
128 13042 : if (!this->nodes_and_elements_equal(other_mesh))
129 63 : return "nodes and/or elements";
130 :
131 13701 : if (_extra_ghost_elems.size() !=
132 722 : other_mesh._extra_ghost_elems.size())
133 0 : return "_extra_ghost_elems size";
134 12979 : for (auto & elem : _extra_ghost_elems)
135 : {
136 0 : libmesh_assert(this->query_elem_ptr(elem->id()) == elem);
137 0 : const Elem * other_elem = other_mesh.query_elem_ptr(elem->id());
138 0 : if (!other_elem ||
139 0 : !other_mesh._extra_ghost_elems.count(const_cast<Elem *>(other_elem)))
140 0 : return "_extra_ghost_elems entry";
141 : }
142 :
143 12979 : return "";
144 : }
145 :
146 341968 : DistributedMesh::~DistributedMesh ()
147 : {
148 319516 : this->DistributedMesh::clear(); // Free nodes and elements
149 341968 : }
150 :
151 :
152 : // This might be specialized later, but right now it's just here to
153 : // make sure the compiler doesn't give us a default (non-deep) copy
154 : // constructor instead.
155 18082 : DistributedMesh::DistributedMesh (const DistributedMesh & other_mesh) :
156 : DistributedMesh(static_cast<const MeshBase &>(other_mesh),
157 18082 : /*bool other_is_distributed_type=*/true)
158 : {
159 18082 : _deleted_coarse_elements = other_mesh._deleted_coarse_elements;
160 18082 : _next_free_local_node_id =
161 18082 : other_mesh._next_free_local_node_id;
162 18082 : _next_free_local_elem_id =
163 18082 : other_mesh._next_free_local_elem_id;
164 18082 : _next_free_unpartitioned_node_id =
165 18082 : other_mesh._next_free_unpartitioned_node_id;
166 18082 : _next_free_unpartitioned_elem_id =
167 18082 : other_mesh._next_free_unpartitioned_elem_id;
168 : #ifdef LIBMESH_ENABLE_UNIQUE_ID
169 18082 : _next_unique_id =
170 18082 : other_mesh._next_unique_id;
171 18082 : _next_unpartitioned_unique_id =
172 18082 : other_mesh._next_unpartitioned_unique_id;
173 : #endif
174 :
175 : // Need to copy extra_ghost_elems
176 18082 : for (auto & elem : other_mesh._extra_ghost_elems)
177 0 : _extra_ghost_elems.insert(this->elem_ptr(elem->id()));
178 18082 : }
179 :
180 :
181 :
182 20709 : DistributedMesh::DistributedMesh (const MeshBase & other_mesh, bool other_is_distributed_type) :
183 20709 : UnstructuredMesh (other_mesh), _is_serial(other_mesh.is_serial()),
184 21151 : _is_serial_on_proc_0(other_mesh.is_serial_on_zero()),
185 20173 : _deleted_coarse_elements(true), // better safe than sorry...
186 20173 : _n_nodes(0), _n_elem(0), _max_node_id(0), _max_elem_id(0), // recomputed below
187 21151 : _next_free_local_node_id(this->processor_id()),
188 21057 : _next_free_local_elem_id(this->processor_id()),
189 21057 : _next_free_unpartitioned_node_id(this->n_processors()),
190 41324 : _next_free_unpartitioned_elem_id(this->n_processors())
191 : {
192 : // Just copy, skipping preparation
193 20709 : this->copy_nodes_and_elements(other_mesh, true, 0, 0, 0, nullptr, true);
194 :
195 536 : this->allow_find_neighbors(other_mesh.allow_find_neighbors());
196 536 : this->allow_detect_interior_parents(other_mesh.allow_detect_interior_parents());
197 536 : this->allow_renumbering(other_mesh.allow_renumbering());
198 536 : this->allow_remote_element_removal(other_mesh.allow_remote_element_removal());
199 536 : this->skip_partitioning(other_mesh.skip_partitioning());
200 :
201 20709 : this->copy_constraint_rows(other_mesh);
202 :
203 442 : auto & this_boundary_info = this->get_boundary_info();
204 442 : const auto & other_boundary_info = other_mesh.get_boundary_info();
205 :
206 20709 : this_boundary_info = other_boundary_info;
207 :
208 442 : this->set_subdomain_name_map() = other_mesh.get_subdomain_name_map();
209 :
210 : // add_node()/add_elem() only increment _n_nodes/_n_elem for
211 : // nodes/elements they consider locally owned (or unpartitioned), so after
212 : // copying only the objects visible to this processor, those counts
213 : // reflect an incomplete local view rather than other_mesh's totals,
214 : // and need to be copied afresh.
215 20709 : _n_nodes = other_mesh.n_nodes();
216 20709 : _n_elem = other_mesh.n_elem();
217 20709 : _max_node_id = other_mesh.max_node_id();
218 20709 : _max_elem_id = other_mesh.max_elem_id();
219 :
220 : // If other_mesh is actually a DistributedMesh, we can just copy its raw
221 : // counters directly, mirroring other_mesh's own bookkeeping exactly. This
222 : // is done in the DistributedMesh copy constructor.
223 : // For any other MeshBase subclass (e.g. ReplicatedMesh) we have no
224 : // raw counterpart fields to copy, so derive the free-id-range
225 : // counters from _max_elem_id/_max_node_id the same way
226 : // update_parallel_id_counts() does via the set_next_ids() method. For
227 : // the unique id counters we copy other_mesh's own local next_unique_id()
228 : // and derive the next available unique ids
229 : // (partitioned and unpartitioned) via set_next_unique_ids().
230 20709 : if (!other_is_distributed_type)
231 : {
232 2627 : this->set_next_ids();
233 : #ifdef LIBMESH_ENABLE_UNIQUE_ID
234 2627 : this->set_next_unique_ids(other_mesh.next_unique_id());
235 : #endif
236 : }
237 :
238 : // Copy other_mesh's actual preparation state, including whatever it
239 : // reports for has_synched_id_counts: the counts above are a faithful copy
240 : // of other_mesh's own (possibly not-yet-synced) counts, not a freshly
241 : // verified computation, so our synced-ness should match other_mesh's.
242 20709 : this->_preparation = other_mesh.preparation();
243 20709 : }
244 :
245 270 : void DistributedMesh::move_nodes_and_elements(MeshBase && other_meshbase)
246 : {
247 4 : DistributedMesh & other_mesh = cast_ref<DistributedMesh&>(other_meshbase);
248 :
249 4 : this->_nodes = std::move(other_mesh._nodes);
250 270 : this->_n_nodes = other_mesh.n_nodes();
251 :
252 4 : this->_elements = std::move(other_mesh._elements);
253 270 : this->_n_elem = other_mesh.n_elem();
254 :
255 270 : _is_serial = other_mesh.is_serial();
256 270 : _is_serial_on_proc_0 = other_mesh.is_serial_on_zero();
257 270 : _deleted_coarse_elements = true; // Better safe than sorry
258 :
259 270 : _max_node_id = other_mesh.max_node_id();
260 270 : _max_elem_id = other_mesh.max_elem_id();
261 :
262 270 : _next_free_local_node_id = other_mesh._next_free_local_node_id;
263 270 : _next_free_local_elem_id = other_mesh._next_free_local_elem_id;
264 270 : _next_free_unpartitioned_node_id = other_mesh._next_free_unpartitioned_node_id;
265 270 : _next_free_unpartitioned_elem_id = other_mesh._next_free_unpartitioned_elem_id;
266 :
267 : #ifdef LIBMESH_ENABLE_UNIQUE_ID
268 270 : _next_unpartitioned_unique_id = other_mesh._next_unpartitioned_unique_id;
269 : #endif
270 270 : }
271 :
272 2035216 : void DistributedMesh::set_next_ids()
273 : {
274 2035216 : _next_free_unpartitioned_elem_id =
275 2036990 : ((_max_elem_id-1) / (this->n_processors() + 1) + 1) *
276 2035216 : (this->n_processors() + 1) + this->n_processors();
277 2035216 : _next_free_local_elem_id =
278 2035216 : ((_max_elem_id + this->n_processors() - 1) / (this->n_processors() + 1) + 1) *
279 2035216 : (this->n_processors() + 1) + this->processor_id();
280 :
281 2035216 : _next_free_unpartitioned_node_id =
282 2036990 : ((_max_node_id-1) / (this->n_processors() + 1) + 1) *
283 2035216 : (this->n_processors() + 1) + this->n_processors();
284 2035216 : _next_free_local_node_id =
285 2035216 : ((_max_node_id + this->n_processors() - 1) / (this->n_processors() + 1) + 1) *
286 2035216 : (this->n_processors() + 1) + this->processor_id();
287 2035216 : }
288 :
289 : #ifdef LIBMESH_ENABLE_UNIQUE_ID
290 2035216 : void DistributedMesh::set_next_unique_ids(unique_id_type parallel_max_unique_id)
291 : {
292 : // Unique ids are laid out in repeating groups of (n_processors()+1)
293 : // consecutive integers ("alignment" here means a value's position, i.e.
294 : // its residue mod (n_processors()+1), within one of these groups). In
295 : // every group, the first n_processors() slots (residues 0..n_processors()-1)
296 : // are each permanently earmarked for one processor's locally-owned
297 : // objects, and the last slot (residue n_processors()) is permanently
298 : // earmarked for unpartitioned objects.
299 : //
300 : // parallel_max_unique_id carries no guarantee of landing on any
301 : // particular residue, so rather than simply offsetting it by
302 : // processor_id()/n_processors(), we have to explicitly round up to the
303 : // start of the next full, entirely-unused group before adding this
304 : // processor's (or the unpartitioned pool's) fixed offset into that group.
305 : //
306 : // (parallel_max_unique_id - 1) / (n_processors()+1) + 1 is the standard
307 : // integer idiom for ceil(parallel_max_unique_id / (n_processors()+1)):
308 : // the number of complete groups needed to reach at least past the
309 : // current max id. Multiplying back by (n_processors()+1) gives the first
310 : // id of the next group that is guaranteed to be entirely unused; adding
311 : // n_processors(), the unpartitioned pool's fixed offset within a group,
312 : // lands on that pool's reserved slot in that group.
313 2035216 : _next_unpartitioned_unique_id =
314 2036990 : ((parallel_max_unique_id - 1) / (this->n_processors() + 1) + 1) *
315 2035216 : (this->n_processors() + 1) +
316 2035216 : this->n_processors();
317 :
318 : // Same idiom, but shifted by (n_processors()-1) before dividing so that
319 : // the rounding accounts for processor_id() possibly being less than the
320 : // residue the raw max id already occupies within its group; this can
321 : // land this processor's slot in the same group as the unpartitioned
322 : // pool's above, or push it into the following group, depending on where
323 : // the max id and this processor's offset happen to fall.
324 2035216 : _next_unique_id =
325 2035216 : ((parallel_max_unique_id + this->n_processors() - 1) / (this->n_processors() + 1) + 1) *
326 2035216 : (this->n_processors() + 1) +
327 2035216 : this->processor_id();
328 2035216 : }
329 : #endif
330 :
331 : // We use cached values for these so they can be called
332 : // from one processor without bothering the rest, but
333 : // we may need to update those caches before doing a full
334 : // renumbering
335 2032589 : void DistributedMesh::update_parallel_id_counts()
336 : {
337 : // This function must be run on all processors at once
338 2048 : parallel_object_only();
339 :
340 2032589 : _n_elem = this->parallel_n_elem();
341 2032589 : _n_nodes = this->parallel_n_nodes();
342 2032589 : _max_node_id = this->parallel_max_node_id();
343 2032589 : _max_elem_id = this->parallel_max_elem_id();
344 :
345 2032589 : this->set_next_ids();
346 :
347 : // set_next_unique_ids() needs the true parallel max unique id (not just
348 : // this processor's possibly-stale cached _next_unique_id) since the whole
349 : // point of this function is to recompute counters that may have drifted
350 : // out of sync.
351 : #ifdef LIBMESH_ENABLE_UNIQUE_ID
352 2032589 : this->set_next_unique_ids(this->parallel_max_unique_id());
353 : #endif
354 :
355 2032589 : this->_preparation.has_synched_id_counts = true;
356 2032589 : }
357 :
358 :
359 : // Or in debug mode we may want to test the uncached values without
360 : // changing the cache
361 2040320 : dof_id_type DistributedMesh::parallel_n_elem() const
362 : {
363 : // This function must be run on all processors at once
364 2902 : parallel_object_only();
365 :
366 2040320 : dof_id_type n_local = this->n_local_elem();
367 2040320 : this->comm().sum(n_local);
368 2040320 : n_local += this->n_unpartitioned_elem();
369 2040320 : return n_local;
370 : }
371 :
372 :
373 :
374 2039635 : dof_id_type DistributedMesh::parallel_max_elem_id() const
375 : {
376 : // This function must be run on all processors at once
377 9094 : parallel_object_only();
378 :
379 2039635 : dof_id_type max_local = 0;
380 :
381 : dofobject_container<Elem>::const_reverse_veclike_iterator
382 9094 : rit = _elements.rbegin();
383 :
384 : const dofobject_container<Elem>::const_reverse_veclike_iterator
385 9094 : rend = _elements.rend();
386 :
387 : // Look for the maximum element id. Search backwards through
388 : // elements so we can break out early. Beware of nullptr entries that
389 : // haven't yet been cleared from _elements.
390 10673659 : for (; rit != rend; ++rit)
391 : {
392 10110550 : const DofObject *d = *rit;
393 19375 : if (d)
394 : {
395 8868 : libmesh_assert(_elements[d->id()] == d);
396 1476526 : max_local = d->id() + 1;
397 1476526 : break;
398 : }
399 : }
400 :
401 2039635 : this->comm().max(max_local);
402 2039635 : return max_local;
403 : }
404 :
405 :
406 :
407 : #ifdef LIBMESH_ENABLE_UNIQUE_ID
408 2118413 : unique_id_type DistributedMesh::parallel_max_unique_id() const
409 : {
410 : // This function must be run on all processors at once
411 2498 : parallel_object_only();
412 :
413 4236826 : unique_id_type max_local = std::max(_next_unique_id,
414 2430426 : _next_unpartitioned_unique_id);
415 2118413 : this->comm().max(max_local);
416 2118413 : return max_local;
417 : }
418 :
419 :
420 :
421 80865 : void DistributedMesh::set_next_unique_id(unique_id_type id)
422 : {
423 496 : _next_unique_id = id;
424 80865 : _next_unpartitioned_unique_id =
425 81013 : ((_next_unique_id-1) / (this->n_processors() + 1) + 1) *
426 80865 : (this->n_processors() + 1) + this->n_processors();
427 80865 : _next_unique_id =
428 80865 : ((_next_unique_id + this->n_processors() - 1) / (this->n_processors() + 1) + 1) *
429 80865 : (this->n_processors() + 1) + this->processor_id();
430 80865 : }
431 : #endif
432 :
433 :
434 :
435 2040768 : dof_id_type DistributedMesh::parallel_n_nodes() const
436 : {
437 : // This function must be run on all processors at once
438 2902 : parallel_object_only();
439 :
440 2040768 : dof_id_type n_local = this->n_local_nodes();
441 2040768 : this->comm().sum(n_local);
442 2040768 : n_local += this->n_unpartitioned_nodes();
443 2040768 : return n_local;
444 : }
445 :
446 :
447 :
448 2037201 : dof_id_type DistributedMesh::parallel_max_node_id() const
449 : {
450 : // This function must be run on all processors at once
451 6660 : parallel_object_only();
452 :
453 2037201 : dof_id_type max_local = 0;
454 :
455 : dofobject_container<Node>::const_reverse_veclike_iterator
456 6660 : rit = _nodes.rbegin();
457 :
458 : const dofobject_container<Node>::const_reverse_veclike_iterator
459 6660 : rend = _nodes.rend();
460 :
461 : // Look for the maximum node id. Search backwards through
462 : // nodes so we can break out early. Beware of nullptr entries that
463 : // haven't yet been cleared from _nodes
464 38857374 : for (; rit != rend; ++rit)
465 : {
466 38294335 : const DofObject *d = *rit;
467 63736 : if (d)
468 : {
469 6504 : libmesh_assert(_nodes[d->id()] == d);
470 1474162 : max_local = d->id() + 1;
471 1474162 : break;
472 : }
473 : }
474 :
475 2037201 : this->comm().max(max_local);
476 2037201 : return max_local;
477 : }
478 :
479 :
480 :
481 43030112 : const Point & DistributedMesh::point (const dof_id_type i) const
482 : {
483 43030112 : return this->node_ref(i);
484 : }
485 :
486 :
487 :
488 44147145 : const Node * DistributedMesh::node_ptr (const dof_id_type i) const
489 : {
490 137681 : libmesh_assert(_nodes[i]);
491 137681 : libmesh_assert_equal_to (_nodes[i]->id(), i);
492 :
493 44147145 : return _nodes[i];
494 : }
495 :
496 :
497 :
498 :
499 648238241 : Node * DistributedMesh::node_ptr (const dof_id_type i)
500 : {
501 654169 : libmesh_assert(_nodes[i]);
502 654169 : libmesh_assert_equal_to (_nodes[i]->id(), i);
503 :
504 648238241 : return _nodes[i];
505 : }
506 :
507 :
508 :
509 :
510 3532224 : const Node * DistributedMesh::query_node_ptr (const dof_id_type i) const
511 : {
512 3532224 : if (const auto it = _nodes.find(i);
513 1080501 : it != _nodes.end())
514 : {
515 3104804 : const Node * n = *it;
516 653081 : libmesh_assert (!n || n->id() == i);
517 653081 : return n;
518 : }
519 :
520 427420 : return nullptr;
521 : }
522 :
523 :
524 :
525 :
526 371749761 : Node * DistributedMesh::query_node_ptr (const dof_id_type i)
527 : {
528 371749761 : if (auto it = _nodes.find(i);
529 245619 : it != _nodes.end())
530 : {
531 288258346 : Node * n = *it;
532 157670 : libmesh_assert (!n || n->id() == i);
533 157670 : return n;
534 : }
535 :
536 87949 : return nullptr;
537 : }
538 :
539 :
540 :
541 :
542 3058423 : const Elem * DistributedMesh::elem_ptr (const dof_id_type i) const
543 : {
544 10105 : libmesh_assert(_elements[i]);
545 10105 : libmesh_assert_equal_to (_elements[i]->id(), i);
546 :
547 3058423 : return _elements[i];
548 : }
549 :
550 :
551 :
552 :
553 288522824 : Elem * DistributedMesh::elem_ptr (const dof_id_type i)
554 : {
555 178241 : libmesh_assert(_elements[i]);
556 178241 : libmesh_assert_equal_to (_elements[i]->id(), i);
557 :
558 288522824 : return _elements[i];
559 : }
560 :
561 :
562 :
563 :
564 1766517 : const Elem * DistributedMesh::query_elem_ptr (const dof_id_type i) const
565 : {
566 1766517 : if (const auto it = _elements.find(i);
567 927547 : it != _elements.end())
568 : {
569 1248384 : const Elem * e = *it;
570 418329 : libmesh_assert (!e || e->id() == i);
571 418329 : return e;
572 : }
573 :
574 509218 : return nullptr;
575 : }
576 :
577 :
578 :
579 :
580 608719431 : Elem * DistributedMesh::query_elem_ptr (const dof_id_type i)
581 : {
582 608719431 : if (auto it = _elements.find(i);
583 217474 : it != _elements.end())
584 : {
585 523135823 : Elem * e = *it;
586 213794 : libmesh_assert (!e || e->id() == i);
587 213794 : return e;
588 : }
589 :
590 3680 : return nullptr;
591 : }
592 :
593 :
594 :
595 :
596 44217705 : Elem * DistributedMesh::add_elem (Elem * e)
597 : {
598 : // Don't try to add nullptrs!
599 35493 : libmesh_assert(e);
600 :
601 : // Trying to add an existing element is a no-op
602 44217705 : if (e->valid_id() && _elements[e->id()] == e)
603 0 : return e;
604 :
605 44217705 : const processor_id_type elem_procid = e->processor_id();
606 :
607 44217705 : if (!e->valid_id())
608 : {
609 : // We should only be creating new ids past the end of the range
610 : // of existing ids
611 3568 : libmesh_assert_greater_equal(_next_free_unpartitioned_elem_id,
612 : _max_elem_id);
613 3568 : libmesh_assert_greater_equal(_next_free_local_elem_id, _max_elem_id);
614 :
615 : // Use the unpartitioned ids for unpartitioned elems, and
616 : // temporarily for ghost elems
617 3860793 : dof_id_type * next_id = &_next_free_unpartitioned_elem_id;
618 3864361 : if (elem_procid == this->processor_id())
619 1133696 : next_id = &_next_free_local_elem_id;
620 3860793 : e->set_id (*next_id);
621 : }
622 :
623 : {
624 : // Advance next_ids up high enough that each is pointing to an
625 : // unused id and any subsequent increments will still point us
626 : // to unused ids
627 88435410 : _max_elem_id = std::max(_max_elem_id,
628 44217705 : static_cast<dof_id_type>(e->id()+1));
629 :
630 44217705 : if (_next_free_unpartitioned_elem_id < _max_elem_id)
631 5186369 : _next_free_unpartitioned_elem_id =
632 5186369 : ((_max_elem_id-1) / (this->n_processors() + 1) + 1) *
633 5186369 : (this->n_processors() + 1) + this->n_processors();
634 44217705 : if (_next_free_local_elem_id < _max_elem_id)
635 3483569 : _next_free_local_elem_id =
636 3489852 : ((_max_elem_id + this->n_processors() - 1) / (this->n_processors() + 1) + 1) *
637 3483569 : (this->n_processors() + 1) + this->processor_id();
638 :
639 : #ifndef NDEBUG
640 : // We need a const dofobject_container so we don't inadvertently create
641 : // nullptr entries when testing for non-nullptr ones
642 35493 : const dofobject_container<Elem> & const_elements = _elements;
643 : #endif
644 35493 : libmesh_assert(!const_elements[_next_free_unpartitioned_elem_id]);
645 35493 : libmesh_assert(!const_elements[_next_free_local_elem_id]);
646 : }
647 :
648 : // Don't try to overwrite existing elems
649 35493 : libmesh_assert (!_elements[e->id()]);
650 :
651 44217705 : _elements[e->id()] = e;
652 :
653 : // We actually added a new element. Some of our caches might still
654 : // be valid, but we should clear the ones which definitely are not.
655 44217705 : this->clear_point_locator();
656 44217705 : this->clear_stored_ranges();
657 :
658 : // Try to make the cached elem data more accurate
659 44236762 : if (elem_procid == this->processor_id() ||
660 : elem_procid == DofObject::invalid_processor_id)
661 13069232 : _n_elem++;
662 :
663 : #ifdef LIBMESH_ENABLE_UNIQUE_ID
664 44217705 : if (!e->valid_unique_id())
665 : {
666 13653839 : if (processor_id() == e->processor_id())
667 : {
668 1133696 : e->set_unique_id(_next_unique_id);
669 1133696 : _next_unique_id += this->n_processors() + 1;
670 : }
671 : else
672 : {
673 12520143 : e->set_unique_id(_next_unpartitioned_unique_id);
674 12520143 : _next_unpartitioned_unique_id += this->n_processors() + 1;
675 : }
676 : }
677 : else
678 : {
679 30588243 : _next_unique_id = std::max(_next_unique_id, e->unique_id()+1);
680 30563866 : _next_unique_id =
681 30563866 : ((_next_unique_id + this->n_processors() - 1) / (this->n_processors() + 1) + 1) *
682 30563866 : (this->n_processors() + 1) + this->processor_id();
683 : }
684 : #endif
685 :
686 : // Unpartitioned elems should be added on every processor
687 : // And shouldn't be added in the same batch as ghost elems
688 : // But we might be just adding on processor 0 to
689 : // broadcast later
690 : // #ifdef DEBUG
691 : // if (elem_procid == DofObject::invalid_processor_id)
692 : // {
693 : // dof_id_type elem_id = e->id();
694 : // this->comm().max(elem_id);
695 : // libmesh_assert_equal_to (elem_id, e->id());
696 : // }
697 : // #endif
698 :
699 : // Make sure any new element is given space for any extra integers
700 : // we've requested
701 44217705 : e->add_extra_integers(_elem_integer_names.size(),
702 44217705 : _elem_integer_default_values);
703 :
704 : // And set mapping type and data on any new element
705 54550 : e->set_mapping_type(this->default_mapping_type());
706 54550 : e->set_mapping_data(this->default_mapping_data());
707 :
708 44217705 : return e;
709 : }
710 :
711 :
712 :
713 14910314 : Elem * DistributedMesh::add_elem (std::unique_ptr<Elem> e)
714 : {
715 : // The mesh now takes ownership of the Elem. Eventually the guts of
716 : // add_elem() will get moved to a private helper function, and
717 : // calling add_elem() directly will be deprecated.
718 14910314 : return add_elem(e.release());
719 : }
720 :
721 :
722 :
723 3423532 : Elem * DistributedMesh::insert_elem (Elem * e)
724 : {
725 3423532 : if (_elements[e->id()])
726 3423532 : this->delete_elem(_elements[e->id()]);
727 :
728 : #ifdef LIBMESH_ENABLE_UNIQUE_ID
729 3423532 : if (!e->valid_unique_id())
730 : {
731 0 : if (processor_id() == e->processor_id())
732 : {
733 0 : e->set_unique_id(_next_unique_id);
734 0 : _next_unique_id += this->n_processors() + 1;
735 : }
736 : else
737 : {
738 0 : e->set_unique_id(_next_unpartitioned_unique_id);
739 0 : _next_unpartitioned_unique_id += this->n_processors() + 1;
740 : }
741 : }
742 : else
743 : {
744 3423532 : _next_unique_id = std::max(_next_unique_id, e->unique_id()+1);
745 3423532 : _next_unique_id =
746 3427228 : ((_next_unique_id + this->n_processors() - 1) / (this->n_processors() + 1) + 1) *
747 3423532 : (this->n_processors() + 1) + this->processor_id();
748 : }
749 : #endif
750 :
751 : // Try to make the cached elem data more accurate
752 3423532 : processor_id_type elem_procid = e->processor_id();
753 3427228 : if (elem_procid == this->processor_id() ||
754 : elem_procid == DofObject::invalid_processor_id)
755 3292664 : _n_elem++;
756 :
757 3423532 : _elements[e->id()] = e;
758 :
759 : // We actually added a new element. Some of our caches might still
760 : // be valid, but we should clear the ones which definitely are not.
761 3423532 : this->clear_point_locator();
762 3423532 : this->clear_stored_ranges();
763 :
764 : // Make sure any new element is given space for any extra integers
765 : // we've requested
766 3423532 : e->add_extra_integers(_elem_integer_names.size(),
767 3423532 : _elem_integer_default_values);
768 :
769 : // And set mapping type and data on any new element
770 7392 : e->set_mapping_type(this->default_mapping_type());
771 7392 : e->set_mapping_data(this->default_mapping_data());
772 :
773 3423532 : return e;
774 : }
775 :
776 3423532 : Elem * DistributedMesh::insert_elem (std::unique_ptr<Elem> e)
777 : {
778 : // The mesh now takes ownership of the Elem. Eventually the guts of
779 : // insert_elem(Elem*) will get moved to a private helper function, and
780 : // calling insert_elem(Elem*) directly will be deprecated.
781 3423532 : return insert_elem(e.release());
782 : }
783 :
784 :
785 40222240 : void DistributedMesh::delete_elem(Elem * e)
786 : {
787 7594 : libmesh_assert (e);
788 :
789 : // Try to make the cached elem data more accurate
790 40222240 : _n_elem--;
791 :
792 : // Was this a coarse element, not just a coarsening where we still
793 : // have some ancestor structure? Was it a *local* element, that we
794 : // might have been depending on as an owner of local nodes? We'll
795 : // have to be more careful with our nodes in contract() later; no
796 : // telling if we just locally orphaned a node that should be
797 : // globally retained.
798 40231654 : if (e->processor_id() == this->processor_id() &&
799 3640 : !e->parent())
800 80793 : _deleted_coarse_elements = true;
801 :
802 : // Delete the element from the BoundaryInfo object
803 40222240 : this->get_boundary_info().remove(e);
804 :
805 : // But not yet from the container; we might invalidate
806 : // an iterator that way!
807 :
808 : //_elements.erase(e->id());
809 :
810 : // Instead, we set it to nullptr for now
811 :
812 40222240 : _elements[e->id()] = nullptr;
813 :
814 : // delete the element
815 40222240 : delete e;
816 :
817 : // Some of our caches might still be valid, but we should clear the
818 : // ones which definitely are not.
819 40222240 : this->clear_point_locator();
820 40222240 : this->clear_stored_ranges();
821 40222240 : }
822 :
823 :
824 :
825 3208120 : void DistributedMesh::renumber_elem(const dof_id_type old_id,
826 : const dof_id_type new_id)
827 : {
828 : // This could be a no-op
829 3208120 : if (old_id == new_id)
830 0 : return;
831 :
832 3208120 : Elem * el = _elements[old_id];
833 1160 : libmesh_assert (el);
834 1160 : libmesh_assert_equal_to (el->id(), old_id);
835 :
836 3208120 : el->set_id(new_id);
837 1160 : libmesh_assert (!_elements[new_id]);
838 3208120 : _elements[new_id] = el;
839 3208120 : _elements.erase(old_id);
840 :
841 : // Should we delete any caches here? Our point locator indexes by
842 : // element pointer and should be fine with an id change. Our stored
843 : // ranges are no longer sorted, which is *probably* fine, but let's
844 : // just be safe.
845 3208120 : this->clear_stored_ranges();
846 : }
847 :
848 :
849 :
850 41644964 : Node * DistributedMesh::add_point (const Point & p,
851 : const dof_id_type id,
852 : const processor_id_type proc_id)
853 : {
854 41644964 : Node * old_n = this->query_node_ptr(id);
855 :
856 41644964 : if (old_n)
857 : {
858 0 : *old_n = p;
859 0 : old_n->processor_id() = proc_id;
860 :
861 0 : return old_n;
862 : }
863 :
864 41604915 : Node * n = Node::build(p, id).release();
865 41644964 : n->processor_id() = proc_id;
866 :
867 41644964 : return DistributedMesh::add_node(n);
868 : }
869 :
870 :
871 4130 : void DistributedMesh::own_node (Node & n)
872 : {
873 : // This had better be a node in our mesh
874 0 : libmesh_assert(_nodes[n.id()] == &n);
875 :
876 4130 : _nodes[n.id()] = nullptr;
877 4130 : _n_nodes--;
878 :
879 0 : n.set_id(DofObject::invalid_id);
880 4130 : n.processor_id() = this->processor_id();
881 :
882 4130 : this->add_node(&n);
883 4130 : }
884 :
885 :
886 72435612 : Node * DistributedMesh::add_node (Node * n)
887 : {
888 : // Don't try to add nullptrs!
889 82163 : libmesh_assert(n);
890 :
891 : // Trying to add an existing node is a no-op
892 72435612 : if (n->valid_id() && _nodes[n->id()] == n)
893 0 : return n;
894 :
895 72435612 : const processor_id_type node_procid = n->processor_id();
896 :
897 72435612 : if (!n->valid_id())
898 : {
899 : // We should only be creating new ids past the end of the range
900 : // of existing ids
901 17829 : libmesh_assert_greater_equal(_next_free_unpartitioned_node_id,
902 : _max_node_id);
903 17829 : libmesh_assert_greater_equal(_next_free_local_node_id, _max_node_id);
904 :
905 : // Use the unpartitioned ids for unpartitioned nodes,
906 : // and temporarily for ghost nodes
907 17428175 : dof_id_type * next_id = &_next_free_unpartitioned_node_id;
908 17446004 : if (node_procid == this->processor_id())
909 2128755 : next_id = &_next_free_local_node_id;
910 17428175 : n->set_id (*next_id);
911 : }
912 :
913 : {
914 : // Advance next_ids up high enough that each is pointing to an
915 : // unused id and any subsequent increments will still point us
916 : // to unused ids
917 144871224 : _max_node_id = std::max(_max_node_id,
918 72435612 : static_cast<dof_id_type>(n->id()+1));
919 :
920 72435612 : if (_next_free_unpartitioned_node_id < _max_node_id)
921 20405086 : _next_free_unpartitioned_node_id =
922 20405086 : ((_max_node_id-1) / (this->n_processors() + 1) + 1) *
923 20405086 : (this->n_processors() + 1) + this->n_processors();
924 72435612 : if (_next_free_local_node_id < _max_node_id)
925 11895678 : _next_free_local_node_id =
926 11913883 : ((_max_node_id + this->n_processors() - 1) / (this->n_processors() + 1) + 1) *
927 11895678 : (this->n_processors() + 1) + this->processor_id();
928 :
929 : #ifndef NDEBUG
930 : // We need a const dofobject_container so we don't inadvertently create
931 : // nullptr entries when testing for non-nullptr ones
932 82163 : const dofobject_container<Node> & const_nodes = _nodes;
933 : #endif
934 82163 : libmesh_assert(!const_nodes[_next_free_unpartitioned_node_id]);
935 82163 : libmesh_assert(!const_nodes[_next_free_local_node_id]);
936 : }
937 :
938 : // Don't try to overwrite existing nodes
939 82163 : libmesh_assert (!_nodes[n->id()]);
940 :
941 72435612 : _nodes[n->id()] = n;
942 :
943 : // Try to make the cached node data more accurate
944 72477373 : if (node_procid == this->processor_id() ||
945 : node_procid == DofObject::invalid_processor_id)
946 39210840 : _n_nodes++;
947 :
948 : #ifdef LIBMESH_ENABLE_UNIQUE_ID
949 72435612 : if (!n->valid_unique_id())
950 : {
951 41647036 : if (processor_id() == n->processor_id())
952 : {
953 2570878 : n->set_unique_id(_next_unique_id);
954 2570878 : _next_unique_id += this->n_processors() + 1;
955 : }
956 : else
957 : {
958 39076158 : n->set_unique_id(_next_unpartitioned_unique_id);
959 39076158 : _next_unpartitioned_unique_id += this->n_processors() + 1;
960 : }
961 : }
962 : else
963 : {
964 30919071 : _next_unique_id = std::max(_next_unique_id, n->unique_id()+1);
965 30788576 : _next_unique_id =
966 30788576 : ((_next_unique_id + this->n_processors() - 1) / (this->n_processors() + 1) + 1) *
967 30788576 : (this->n_processors() + 1) + this->processor_id();
968 : }
969 : #endif
970 :
971 72435612 : n->add_extra_integers(_node_integer_names.size(),
972 72435612 : _node_integer_default_values);
973 :
974 : // Unpartitioned nodes should be added on every processor
975 : // And shouldn't be added in the same batch as ghost nodes
976 : // But we might be just adding on processor 0 to
977 : // broadcast later
978 : // #ifdef DEBUG
979 : // if (node_procid == DofObject::invalid_processor_id)
980 : // {
981 : // dof_id_type node_id = n->id();
982 : // this->comm().max(node_id);
983 : // libmesh_assert_equal_to (node_id, n->id());
984 : // }
985 : // #endif
986 :
987 72435612 : return n;
988 : }
989 :
990 30786518 : Node * DistributedMesh::add_node (std::unique_ptr<Node> n)
991 : {
992 : // The mesh now takes ownership of the Node. Eventually the guts of
993 : // add_node() will get moved to a private helper function, and
994 : // calling add_node() directly will be deprecated.
995 30786518 : return add_node(n.release());
996 : }
997 :
998 50733035 : void DistributedMesh::delete_node(Node * n)
999 : {
1000 4469 : libmesh_assert(n);
1001 4469 : libmesh_assert(_nodes[n->id()]);
1002 :
1003 : // Try to make the cached elem data more accurate
1004 50733035 : _n_nodes--;
1005 :
1006 : // Delete the node from the BoundaryInfo object
1007 50733035 : this->get_boundary_info().remove(n);
1008 8938 : _constraint_rows.erase(n);
1009 :
1010 : // But not yet from the container; we might invalidate
1011 : // an iterator that way!
1012 :
1013 : //_nodes.erase(n->id());
1014 :
1015 : // Instead, we set it to nullptr for now
1016 :
1017 50733035 : _nodes[n->id()] = nullptr;
1018 :
1019 : // delete the node
1020 50733035 : delete n;
1021 50733035 : }
1022 :
1023 :
1024 :
1025 6899090 : void DistributedMesh::renumber_node(const dof_id_type old_id,
1026 : const dof_id_type new_id)
1027 : {
1028 : // This could be a no-op
1029 6899090 : if (old_id == new_id)
1030 0 : return;
1031 :
1032 6898485 : Node * nd = _nodes[old_id];
1033 3234 : libmesh_assert (nd);
1034 3234 : libmesh_assert_equal_to (nd->id(), old_id);
1035 :
1036 : // If we have nodes shipped to this processor for NodeConstraints
1037 : // use, then those nodes will exist in _nodes, but may not be
1038 : // locatable via a TopologyMap due to the insufficiency of elements
1039 : // connecting to them. If local refinement then wants to create a
1040 : // *new* node in the same location, it will initially get a temporary
1041 : // id, and then make_node_ids_parallel_consistent() will try to move
1042 : // it to the canonical id. We need to account for this case to
1043 : // avoid false positives and memory leaks.
1044 : #ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS
1045 6468 : if (_nodes[new_id])
1046 : {
1047 0 : libmesh_assert_equal_to (*(Point *)_nodes[new_id],
1048 : *(Point *)_nodes[old_id]);
1049 0 : _nodes.erase(new_id);
1050 : }
1051 : #else
1052 : // If we aren't shipping nodes for NodeConstraints, there should be
1053 : // no reason for renumbering one node onto another.
1054 : libmesh_assert (!_nodes[new_id]);
1055 : #endif
1056 6898485 : _nodes[new_id] = nd;
1057 6898485 : nd->set_id(new_id);
1058 :
1059 6898485 : _nodes.erase(old_id);
1060 : }
1061 :
1062 :
1063 :
1064 597641 : void DistributedMesh::clear ()
1065 : {
1066 : // Call parent clear function
1067 597641 : MeshBase::clear();
1068 :
1069 : // Clear our elements and nodes
1070 : // There is no need to remove them from
1071 : // the BoundaryInfo data structure since we
1072 : // already cleared it.
1073 597641 : this->DistributedMesh::clear_elems();
1074 :
1075 23034224 : for (auto & node : _nodes)
1076 41653567 : delete node;
1077 :
1078 932 : _nodes.clear();
1079 :
1080 : // We're no longer distributed if we were before
1081 597641 : _is_serial = true;
1082 597641 : _is_serial_on_proc_0 = true;
1083 :
1084 : // We deleted a ton of coarse elements, but their nodes got deleted too so
1085 : // all is copacetic.
1086 597641 : _deleted_coarse_elements = false;
1087 :
1088 : // Correct our caches
1089 597641 : _n_nodes = 0;
1090 597641 : _max_node_id = 0;
1091 598225 : _next_free_local_node_id = this->processor_id();
1092 597641 : _next_free_unpartitioned_node_id = this->n_processors();
1093 597641 : }
1094 :
1095 :
1096 :
1097 604041 : void DistributedMesh::clear_elems ()
1098 : {
1099 9375287 : for (auto & elem : _elements)
1100 8771246 : delete elem;
1101 :
1102 932 : _elements.clear();
1103 :
1104 : // Correct our caches
1105 604041 : _n_elem = 0;
1106 604041 : _max_elem_id = 0;
1107 604625 : _next_free_local_elem_id = this->processor_id();
1108 604041 : _next_free_unpartitioned_elem_id = this->n_processors();
1109 604041 : }
1110 :
1111 :
1112 :
1113 595135 : void DistributedMesh::redistribute ()
1114 : {
1115 : // If this is a truly parallel mesh, go through the redistribution/gather/delete remote steps
1116 595135 : if (!this->is_serial())
1117 : {
1118 : // Construct a MeshCommunication object to actually redistribute the nodes
1119 : // and elements according to the partitioner, and then to re-gather the neighbors.
1120 : MeshCommunication mc;
1121 70338 : mc.redistribute(*this);
1122 :
1123 70338 : this->update_parallel_id_counts();
1124 :
1125 : // We communicate valid neighbor links for newly-redistributed
1126 : // elements, but we may still have remote_elem links that should
1127 : // be corrected but whose correction wasn't communicated.
1128 70610 : this->find_neighbors(/*reset_remote_elements*/ false,
1129 : /*reset_current_list*/ false /*non-default*/,
1130 : /*assert_valid*/ false,
1131 272 : /*check_non_remote*/ false /*non-default!*/);
1132 :
1133 : // Is this necessary? If we are called from prepare_for_use(), this will be called
1134 : // anyway... but users can always call partition directly, in which case we do need
1135 : // to call delete_remote_elements()...
1136 : //
1137 : // Regardless of whether it's necessary, it isn't safe. We
1138 : // haven't communicated new node processor_ids yet, and we can't
1139 : // delete nodes until we do.
1140 : // this->delete_remote_elements();
1141 : }
1142 : else
1143 : // The base class can handle non-distributed things, like
1144 : // notifying any GhostingFunctors of changes
1145 524797 : MeshBase::redistribute();
1146 595135 : }
1147 :
1148 :
1149 :
1150 507735 : void DistributedMesh::update_post_partitioning ()
1151 : {
1152 : // this->recalculate_n_partitions();
1153 :
1154 : // Let's do the base class cache clearing first, just in case our
1155 : // later computations are ever changed to make use of a local
1156 : // elements range cache
1157 507735 : this->MeshBase::update_post_partitioning();
1158 :
1159 : // Partitioning changes our numbers of unpartitioned objects
1160 507735 : this->update_parallel_id_counts();
1161 507735 : }
1162 :
1163 :
1164 :
1165 : template <typename T>
1166 3380 : void DistributedMesh::libmesh_assert_valid_parallel_object_ids(const dofobject_container<T> & objects) const
1167 : {
1168 : // This function must be run on all processors at once
1169 3380 : parallel_object_only();
1170 :
1171 3380 : const dof_id_type pmax_node_id = this->parallel_max_node_id();
1172 3380 : const dof_id_type pmax_elem_id = this->parallel_max_elem_id();
1173 3380 : const dof_id_type pmax_id = std::max(pmax_node_id, pmax_elem_id);
1174 :
1175 894412 : for (dof_id_type i=0; i != pmax_id; ++i)
1176 : {
1177 891032 : T * obj = objects[i]; // Returns nullptr if there's no map entry
1178 :
1179 : // Local lookups by id should return the requested object
1180 891032 : libmesh_assert(!obj || obj->id() == i);
1181 :
1182 : // All processors with an object should agree on id
1183 : #ifndef NDEBUG
1184 891032 : const dof_id_type dofid = obj && obj->valid_id() ?
1185 : obj->id() : DofObject::invalid_id;
1186 891032 : libmesh_assert(this->comm().semiverify(obj ? &dofid : nullptr));
1187 : #endif
1188 :
1189 : // All processors with an object should agree on processor id
1190 891032 : const dof_id_type procid = obj && obj->valid_processor_id() ?
1191 : obj->processor_id() : DofObject::invalid_processor_id;
1192 891032 : libmesh_assert(this->comm().semiverify(obj ? &procid : nullptr));
1193 :
1194 891032 : dof_id_type min_procid = procid;
1195 891032 : this->comm().min(min_procid);
1196 :
1197 : // Either:
1198 : // 1.) I own this elem (min_procid == this->processor_id()) *and* I have a valid pointer to it (obj != nullptr)
1199 : // or
1200 : // 2.) I don't own this elem (min_procid != this->processor_id()). (In this case I may or may not have a valid pointer to it.)
1201 :
1202 : // Original assert logic
1203 : // libmesh_assert (min_procid != this->processor_id() || obj);
1204 :
1205 : // More human-understandable logic...
1206 891032 : libmesh_assert (
1207 : ((min_procid == this->processor_id()) && obj)
1208 : ||
1209 : (min_procid != this->processor_id())
1210 : );
1211 :
1212 : #if defined(LIBMESH_ENABLE_UNIQUE_ID) && !defined(NDEBUG)
1213 : // All processors with an object should agree on unique id
1214 891032 : const unique_id_type uniqueid = obj ? obj->unique_id() : 0;
1215 891032 : libmesh_assert(this->comm().semiverify(obj ? &uniqueid : nullptr));
1216 : #endif
1217 : }
1218 3380 : }
1219 :
1220 :
1221 :
1222 1690 : void DistributedMesh::libmesh_assert_valid_parallel_ids () const
1223 : {
1224 1690 : this->libmesh_assert_valid_parallel_object_ids (this->_elements);
1225 1690 : this->libmesh_assert_valid_parallel_object_ids (this->_nodes);
1226 1690 : }
1227 :
1228 :
1229 :
1230 406 : void DistributedMesh::libmesh_assert_valid_parallel_p_levels () const
1231 : {
1232 : #ifndef NDEBUG
1233 : // This function must be run on all processors at once
1234 406 : parallel_object_only();
1235 :
1236 406 : dof_id_type pmax_elem_id = this->parallel_max_elem_id();
1237 :
1238 21970 : for (dof_id_type i=0; i != pmax_elem_id; ++i)
1239 : {
1240 21564 : Elem * el = _elements[i]; // Returns nullptr if there's no map entry
1241 :
1242 21564 : unsigned int p_level = el ? (el->p_level()) : libMesh::invalid_uint;
1243 :
1244 : // All processors with an active element should agree on p level
1245 21564 : libmesh_assert(this->comm().semiverify((el && el->active()) ? &p_level : nullptr));
1246 : }
1247 : #endif
1248 406 : }
1249 :
1250 :
1251 :
1252 :
1253 1638 : void DistributedMesh::libmesh_assert_valid_parallel_flags () const
1254 : {
1255 : #if defined(LIBMESH_ENABLE_AMR) && !defined(NDEBUG)
1256 : // This function must be run on all processors at once
1257 1638 : parallel_object_only();
1258 :
1259 1638 : dof_id_type pmax_elem_id = this->parallel_max_elem_id();
1260 :
1261 144704 : for (dof_id_type i=0; i != pmax_elem_id; ++i)
1262 : {
1263 143066 : Elem * el = _elements[i]; // Returns nullptr if there's no map entry
1264 :
1265 143066 : unsigned int refinement_flag = el ?
1266 65765 : static_cast<unsigned int> (el->refinement_flag()) : libMesh::invalid_uint;
1267 143066 : unsigned int p_refinement_flag = el ?
1268 65765 : static_cast<unsigned int> (el->p_refinement_flag()) : libMesh::invalid_uint;
1269 :
1270 143066 : libmesh_assert(this->comm().semiverify(el ? &refinement_flag : nullptr));
1271 :
1272 : // p refinement flags aren't always kept correct on inactive
1273 : // ghost elements
1274 143066 : libmesh_assert(this->comm().semiverify((el && el->active()) ? &p_refinement_flag : nullptr));
1275 : }
1276 : #endif // LIBMESH_ENABLE_AMR
1277 1638 : }
1278 :
1279 :
1280 :
1281 : template <typename T>
1282 : dof_id_type
1283 1843418 : DistributedMesh::renumber_dof_objects(dofobject_container<T> & objects)
1284 : {
1285 : // This function must be run on all processors at once
1286 808 : parallel_object_only();
1287 :
1288 : typedef typename dofobject_container<T>::veclike_iterator object_iterator;
1289 :
1290 : // In parallel we may not know what objects other processors have.
1291 : // Start by figuring out how many
1292 808 : dof_id_type unpartitioned_objects = 0;
1293 :
1294 : std::unordered_map<processor_id_type, dof_id_type>
1295 1616 : ghost_objects_from_proc;
1296 :
1297 1843418 : object_iterator it = objects.begin();
1298 808 : object_iterator end = objects.end();
1299 :
1300 111877924 : while (it != end)
1301 : {
1302 110034506 : T * obj = *it;
1303 :
1304 : // Remove any nullptr container entries while we're here.
1305 110034506 : if (!obj)
1306 1424841 : it = objects.erase(it);
1307 : else
1308 : {
1309 108609665 : processor_id_type obj_procid = obj->processor_id();
1310 108609665 : if (obj_procid == DofObject::invalid_processor_id)
1311 43120004 : unpartitioned_objects++;
1312 : else
1313 65489661 : ghost_objects_from_proc[obj_procid]++;
1314 :
1315 : // Finally, increment the iterator
1316 56464 : ++it;
1317 : }
1318 : }
1319 :
1320 1845034 : std::vector<dof_id_type> objects_on_proc(this->n_processors(), 0);
1321 1844226 : auto this_it = ghost_objects_from_proc.find(this->processor_id());
1322 808 : this->comm().allgather
1323 1843913 : ((this_it == ghost_objects_from_proc.end()) ?
1324 495 : dof_id_type(0) : this_it->second, objects_on_proc);
1325 :
1326 : #ifndef NDEBUG
1327 808 : libmesh_assert(this->comm().verify(unpartitioned_objects));
1328 2424 : for (processor_id_type p=0, np=this->n_processors(); p != np; ++p)
1329 1616 : if (ghost_objects_from_proc.count(p))
1330 962 : libmesh_assert_less_equal (ghost_objects_from_proc[p], objects_on_proc[p]);
1331 : else
1332 654 : libmesh_assert_less_equal (0, objects_on_proc[p]);
1333 : #endif
1334 :
1335 : // We'll renumber objects in blocks by processor id
1336 1845034 : std::vector<dof_id_type> first_object_on_proc(this->n_processors());
1337 19562274 : for (processor_id_type i=1, np=this->n_processors(); i != np; ++i)
1338 17722088 : first_object_on_proc[i] = first_object_on_proc[i-1] +
1339 808 : objects_on_proc[i-1];
1340 1844226 : dof_id_type next_id = first_object_on_proc[this->processor_id()];
1341 1843418 : dof_id_type first_free_id =
1342 1845034 : first_object_on_proc[this->n_processors()-1] +
1343 808 : objects_on_proc[this->n_processors()-1] +
1344 : unpartitioned_objects;
1345 :
1346 : // First set new local object ids and build request sets
1347 : // for non-local object ids
1348 :
1349 : // Request sets to send to each processor
1350 : std::map<processor_id_type, std::vector<dof_id_type>>
1351 808 : requested_ids;
1352 :
1353 : // We know how many objects live on each processor, so reserve() space for
1354 : // each.
1355 808 : auto ghost_end = ghost_objects_from_proc.end();
1356 21405692 : for (auto p : make_range(this->n_processors()))
1357 19563890 : if (p != this->processor_id())
1358 : {
1359 17719664 : if (const auto p_it = ghost_objects_from_proc.find(p);
1360 808 : p_it != ghost_end)
1361 3482141 : requested_ids[p].reserve(p_it->second);
1362 : }
1363 :
1364 808 : end = objects.end();
1365 110453083 : for (it = objects.begin(); it != end; ++it)
1366 : {
1367 108609665 : T * obj = *it;
1368 108609665 : if (!obj)
1369 0 : continue;
1370 108666129 : if (obj->processor_id() == this->processor_id())
1371 20002755 : obj->set_id(next_id++);
1372 88606910 : else if (obj->processor_id() != DofObject::invalid_processor_id)
1373 45486906 : requested_ids[obj->processor_id()].push_back(obj->id());
1374 : }
1375 :
1376 : // Next set ghost object ids from other processors
1377 :
1378 1860632 : auto gather_functor =
1379 48935553 : [
1380 : #ifndef NDEBUG
1381 : this,
1382 : &first_object_on_proc,
1383 : &objects_on_proc,
1384 : #endif
1385 : &objects]
1386 : (processor_id_type, const std::vector<dof_id_type> & ids,
1387 934 : std::vector<dof_id_type> & new_ids)
1388 : {
1389 934 : std::size_t ids_size = ids.size();
1390 3482141 : new_ids.resize(ids_size);
1391 :
1392 48969047 : for (std::size_t i=0; i != ids_size; ++i)
1393 : {
1394 45486906 : T * obj = objects[ids[i]];
1395 16280 : libmesh_assert(obj);
1396 16280 : libmesh_assert_equal_to (obj->processor_id(), this->processor_id());
1397 45503186 : new_ids[i] = obj->id();
1398 :
1399 16280 : libmesh_assert_greater_equal (new_ids[i],
1400 : first_object_on_proc[this->processor_id()]);
1401 16280 : libmesh_assert_less (new_ids[i],
1402 : first_object_on_proc[this->processor_id()] +
1403 : objects_on_proc[this->processor_id()]);
1404 : }
1405 : };
1406 :
1407 1860632 : auto action_functor =
1408 48935553 : [
1409 : #ifndef NDEBUG
1410 : &first_object_on_proc,
1411 : &objects_on_proc,
1412 : #endif
1413 : &objects]
1414 : (processor_id_type libmesh_dbg_var(pid),
1415 : const std::vector<dof_id_type> & ids,
1416 934 : const std::vector<dof_id_type> & data)
1417 : {
1418 : // Copy the id changes we've now been informed of
1419 48969047 : for (auto i : index_range(ids))
1420 : {
1421 45486906 : T * obj = objects[ids[i]];
1422 16280 : libmesh_assert (obj);
1423 16280 : libmesh_assert_equal_to (obj->processor_id(), pid);
1424 16280 : libmesh_assert_greater_equal (data[i],
1425 : first_object_on_proc[pid]);
1426 16280 : libmesh_assert_less (data[i],
1427 : first_object_on_proc[pid] +
1428 : objects_on_proc[pid]);
1429 45503186 : obj->set_id(data[i]);
1430 : }
1431 : };
1432 :
1433 808 : const dof_id_type * ex = nullptr;
1434 : Parallel::pull_parallel_vector_data
1435 1843418 : (this->comm(), requested_ids, gather_functor, action_functor, ex);
1436 :
1437 : #ifdef LIBMESH_ENABLE_UNIQUE_ID
1438 1860632 : auto unique_gather_functor =
1439 48935553 : [
1440 : #ifndef NDEBUG
1441 : this,
1442 : #endif
1443 : &objects]
1444 : (processor_id_type, const std::vector<dof_id_type> & ids,
1445 934 : std::vector<unique_id_type> & data)
1446 : {
1447 934 : std::size_t ids_size = ids.size();
1448 3482141 : data.resize(ids_size);
1449 :
1450 48969047 : for (std::size_t i=0; i != ids_size; ++i)
1451 : {
1452 45486906 : T * obj = objects[ids[i]];
1453 16280 : libmesh_assert(obj);
1454 16280 : libmesh_assert_equal_to (obj->processor_id(), this->processor_id());
1455 90973812 : data[i] = obj->valid_unique_id() ? obj->unique_id() : DofObject::invalid_unique_id;
1456 : }
1457 : };
1458 :
1459 1860632 : auto unique_action_functor =
1460 48935553 : [&objects]
1461 : (processor_id_type libmesh_dbg_var(pid),
1462 : const std::vector<dof_id_type> & ids,
1463 934 : const std::vector<unique_id_type> & data)
1464 : {
1465 48969047 : for (auto i : index_range(ids))
1466 : {
1467 45486906 : T * obj = objects[ids[i]];
1468 16280 : libmesh_assert (obj);
1469 16280 : libmesh_assert_equal_to (obj->processor_id(), pid);
1470 45486906 : if (!obj->valid_unique_id() && data[i] != DofObject::invalid_unique_id)
1471 0 : obj->set_unique_id(data[i]);
1472 : }
1473 : };
1474 :
1475 808 : const unique_id_type * unique_ex = nullptr;
1476 : Parallel::pull_parallel_vector_data
1477 1843418 : (this->comm(), requested_ids, unique_gather_functor,
1478 : unique_action_functor, unique_ex);
1479 : #endif
1480 :
1481 : // Next set unpartitioned object ids
1482 808 : next_id = 0;
1483 21405692 : for (auto i : make_range(this->n_processors()))
1484 19563890 : next_id += objects_on_proc[i];
1485 110453083 : for (it = objects.begin(); it != end; ++it)
1486 : {
1487 108609665 : T * obj = *it;
1488 108609665 : if (!obj)
1489 0 : continue;
1490 108609665 : if (obj->processor_id() == DofObject::invalid_processor_id)
1491 43120004 : obj->set_id(next_id++);
1492 : }
1493 :
1494 : // Finally shuffle around objects so that container indices
1495 : // match ids
1496 1843418 : it = objects.begin();
1497 808 : end = objects.end();
1498 116951363 : while (it != end)
1499 : {
1500 115107945 : T * obj = *it;
1501 115107945 : if (obj) // don't try shuffling already-nullptr entries
1502 : {
1503 115107945 : T * next = objects[obj->id()];
1504 : // If we have to move this object
1505 115107945 : if (next != obj)
1506 : {
1507 : // nullptr out its original position for now
1508 : // (our shuffling may put another object there shortly)
1509 39995456 : *it = nullptr;
1510 :
1511 : // There may already be another object with this id that
1512 : // needs to be moved itself
1513 51802825 : while (next)
1514 : {
1515 : // We shouldn't be trying to give two objects the
1516 : // same id
1517 9385 : libmesh_assert_not_equal_to (next->id(), obj->id());
1518 11807369 : objects[obj->id()] = obj;
1519 9385 : obj = next;
1520 11807369 : next = objects[obj->id()];
1521 : }
1522 39995456 : objects[obj->id()] = obj;
1523 : }
1524 : }
1525 :
1526 : // Remove any container entries that were left as nullptr.
1527 115380 : if (!obj)
1528 0 : it = objects.erase(it);
1529 : else
1530 57690 : ++it;
1531 : }
1532 :
1533 1844226 : return first_free_id;
1534 : }
1535 :
1536 :
1537 923379 : void DistributedMesh::renumber_nodes_and_elements ()
1538 : {
1539 406 : parallel_object_only();
1540 :
1541 : #ifdef DEBUG
1542 : // Make sure our ids and flags are consistent
1543 406 : this->libmesh_assert_valid_parallel_ids();
1544 406 : this->libmesh_assert_valid_parallel_flags();
1545 406 : this->libmesh_assert_valid_parallel_p_levels();
1546 : #endif
1547 :
1548 406 : LOG_SCOPE("renumber_nodes_and_elements()", "DistributedMesh");
1549 :
1550 : // Nodes not connected to any elements, and nullptr node entries
1551 : // in our container, should be deleted. But wait! If we've deleted coarse
1552 : // local elements on some processor, other processors might have ghosted
1553 : // nodes from it that are now no longer connected to any elements on it, but
1554 : // that are connected to their own semilocal elements. We'll have to
1555 : // communicate to ascertain if that's the case.
1556 923379 : this->comm().max(_deleted_coarse_elements);
1557 :
1558 : // What used nodes do we see on our proc?
1559 406 : std::set<dof_id_type> used_nodes;
1560 :
1561 : // What used node info should we send from our proc? Could we take ownership
1562 : // of each node if we needed to?
1563 : std::map<processor_id_type, std::map<dof_id_type, bool>>
1564 406 : used_nodes_on_proc;
1565 :
1566 : // flag the nodes we need
1567 57820280 : for (auto & elem : this->element_ptr_range())
1568 301183815 : for (const Node & node : elem->node_ref_range())
1569 : {
1570 273167405 : const dof_id_type n = node.id();
1571 273022939 : used_nodes.insert(n);
1572 273167405 : if (_deleted_coarse_elements)
1573 : {
1574 3145701 : const processor_id_type p = node.processor_id();
1575 3145985 : if (p != this->processor_id())
1576 : {
1577 2257624 : auto & used_nodes_on_p = used_nodes_on_proc[p];
1578 2257766 : if (elem->processor_id() == this->processor_id())
1579 216210 : used_nodes_on_p[n] = true;
1580 : else
1581 105 : if (!used_nodes_on_p.count(n))
1582 525626 : used_nodes_on_p[n] = false;
1583 : }
1584 : }
1585 922567 : }
1586 :
1587 923379 : if (_deleted_coarse_elements)
1588 : {
1589 : // "unsigned char" == "bool, but MPI::BOOL is iffy to use"
1590 : typedef unsigned char boolish;
1591 : std::map<processor_id_type, std::vector<std::pair<dof_id_type, boolish>>>
1592 28 : used_nodes_on_proc_vecs;
1593 73209 : for (auto & [pid, nodemap] : used_nodes_on_proc)
1594 56827 : used_nodes_on_proc_vecs[pid].assign(nodemap.begin(), nodemap.end());
1595 :
1596 28 : std::map<dof_id_type,processor_id_type> repartitioned_node_pids;
1597 : std::map<processor_id_type, std::set<dof_id_type>>
1598 28 : repartitioned_node_sets_to_push;
1599 :
1600 : auto ids_action_functor =
1601 56801 : [&used_nodes, &repartitioned_node_pids,
1602 : &repartitioned_node_sets_to_push]
1603 : (processor_id_type pid,
1604 112 : const std::vector<std::pair<dof_id_type, boolish>> & ids_and_bools)
1605 : {
1606 592596 : for (auto [n, sender_could_become_owner] : ids_and_bools)
1607 : {
1608 : // If we don't see a use for our own node, but someone
1609 : // else does, better figure out who should own it next.
1610 97 : if (!used_nodes.count(n))
1611 : {
1612 2 : if (auto it = repartitioned_node_pids.find(n);
1613 2 : sender_could_become_owner)
1614 : {
1615 1 : if (it != repartitioned_node_pids.end() &&
1616 0 : pid < it->second)
1617 0 : it->second = pid;
1618 : else
1619 1 : repartitioned_node_pids[n] = pid;
1620 : }
1621 : else
1622 1 : if (it == repartitioned_node_pids.end())
1623 0 : repartitioned_node_pids[n] =
1624 : DofObject::invalid_processor_id;
1625 :
1626 2 : repartitioned_node_sets_to_push[pid].insert(n);
1627 : }
1628 : }
1629 16394 : };
1630 :
1631 : // We need two pushes instead of a pull here because we need to
1632 : // know *all* the queries for a particular node before we can
1633 : // respond to *any* of them.
1634 : Parallel::push_parallel_vector_data
1635 16382 : (this->comm(), used_nodes_on_proc_vecs, ids_action_functor);
1636 :
1637 : // Repartition (what used to be) our own nodes first
1638 16383 : for (auto & [n, p] : repartitioned_node_pids)
1639 : {
1640 1 : Node & node = this->node_ref(n);
1641 0 : libmesh_assert_equal_to(node.processor_id(), this->processor_id());
1642 0 : libmesh_assert_not_equal_to_msg(p, DofObject::invalid_processor_id, "Node " << n << " is lost?");
1643 1 : node.processor_id() = p;
1644 : }
1645 :
1646 : // Then push to repartition others' ghosted copies.
1647 :
1648 : std::map<processor_id_type, std::vector<std::pair<dof_id_type,processor_id_type>>>
1649 28 : repartitioned_node_vecs;
1650 :
1651 16384 : for (auto & [p, nodeset] : repartitioned_node_sets_to_push)
1652 : {
1653 2 : auto & rn_vec = repartitioned_node_vecs[p];
1654 4 : for (auto n : nodeset)
1655 2 : rn_vec.emplace_back(n, repartitioned_node_pids[n]);
1656 : }
1657 :
1658 : auto repartition_node_functor =
1659 2 : [this]
1660 : (processor_id_type libmesh_dbg_var(pid),
1661 2 : const std::vector<std::pair<dof_id_type, processor_id_type>> & ids_and_pids)
1662 : {
1663 4 : for (auto [n, p] : ids_and_pids)
1664 : {
1665 0 : libmesh_assert_not_equal_to(p, DofObject::invalid_processor_id);
1666 2 : Node & node = this->node_ref(n);
1667 0 : libmesh_assert_equal_to(node.processor_id(), pid);
1668 2 : node.processor_id() = p;
1669 : }
1670 16354 : };
1671 :
1672 : Parallel::push_parallel_vector_data
1673 16382 : (this->comm(), repartitioned_node_vecs, repartition_node_functor);
1674 : }
1675 :
1676 923379 : _deleted_coarse_elements = false;
1677 :
1678 : // Nodes not connected to any local elements, and nullptr node entries
1679 : // in our container, are deleted
1680 : {
1681 923379 : node_iterator_imp it = _nodes.begin();
1682 406 : node_iterator_imp end = _nodes.end();
1683 :
1684 88447045 : while (it != end)
1685 : {
1686 87523666 : Node * nd = *it;
1687 87523666 : if (!nd)
1688 3491561 : it = _nodes.erase(it);
1689 84032105 : else if (!used_nodes.count(nd->id()))
1690 : {
1691 : // remove any boundary information associated with
1692 : // this node
1693 2405183 : this->get_boundary_info().remove (nd);
1694 2828 : _constraint_rows.erase(nd);
1695 :
1696 : // delete the node
1697 2405183 : delete nd;
1698 :
1699 2405183 : it = _nodes.erase(it);
1700 : }
1701 : else
1702 45303 : ++it;
1703 : }
1704 : }
1705 :
1706 923379 : this->_preparation.has_removed_orphaned_nodes = true;
1707 :
1708 923379 : if (_skip_renumber_nodes_and_elements)
1709 : {
1710 1670 : this->update_parallel_id_counts();
1711 2 : return;
1712 : }
1713 :
1714 : // Finally renumber all the elements
1715 921709 : _n_elem = this->renumber_dof_objects (this->_elements);
1716 :
1717 : // and all the remaining nodes
1718 921709 : _n_nodes = this->renumber_dof_objects (this->_nodes);
1719 :
1720 : // And figure out what IDs we should use when adding new nodes and
1721 : // new elements
1722 921709 : this->update_parallel_id_counts();
1723 :
1724 : // Make sure our caches are up to date and our
1725 : // DofObjects are well packed
1726 : #ifdef DEBUG
1727 404 : libmesh_assert_equal_to (this->n_nodes(), this->parallel_n_nodes());
1728 404 : libmesh_assert_equal_to (this->n_elem(), this->parallel_n_elem());
1729 404 : const dof_id_type pmax_node_id = this->parallel_max_node_id();
1730 404 : const dof_id_type pmax_elem_id = this->parallel_max_elem_id();
1731 404 : libmesh_assert_equal_to (this->max_node_id(), pmax_node_id);
1732 404 : libmesh_assert_equal_to (this->max_elem_id(), pmax_elem_id);
1733 404 : libmesh_assert_equal_to (this->n_nodes(), this->max_node_id());
1734 404 : libmesh_assert_equal_to (this->n_elem(), this->max_elem_id());
1735 :
1736 : // Make sure our ids and flags are consistent
1737 404 : this->libmesh_assert_valid_parallel_ids();
1738 404 : this->libmesh_assert_valid_parallel_flags();
1739 :
1740 : // And make sure we've made our numbering monotonic
1741 404 : MeshTools::libmesh_assert_valid_elem_ids(*this);
1742 : #endif
1743 : }
1744 :
1745 :
1746 :
1747 17410 : void DistributedMesh::fix_broken_node_and_element_numbering ()
1748 : {
1749 : // We can't use range-for here because we need access to the special
1750 : // iterators' methods, not just to their dereferenced values.
1751 :
1752 : // Nodes first
1753 0 : for (auto pr = this->_nodes.begin(),
1754 5444770 : end = this->_nodes.end(); pr != end; ++pr)
1755 : {
1756 5427360 : Node * n = *pr;
1757 5427360 : if (n != nullptr)
1758 : {
1759 0 : const dof_id_type id = pr.index();
1760 5204550 : n->set_id() = id;
1761 0 : libmesh_assert_equal_to(this->node_ptr(id), n);
1762 : }
1763 : }
1764 :
1765 : // Elements next
1766 0 : for (auto pr = this->_elements.begin(),
1767 5671231 : end = this->_elements.end(); pr != end; ++pr)
1768 : {
1769 5653821 : Elem * e = *pr;
1770 5653821 : if (e != nullptr)
1771 : {
1772 0 : const dof_id_type id = pr.index();
1773 5590229 : e->set_id() = id;
1774 0 : libmesh_assert_equal_to(this->elem_ptr(id), e);
1775 : }
1776 : }
1777 17410 : }
1778 :
1779 :
1780 :
1781 673988 : dof_id_type DistributedMesh::n_active_elem () const
1782 : {
1783 554 : parallel_object_only();
1784 :
1785 : // Get local active elements first
1786 : dof_id_type active_elements =
1787 1347422 : static_cast<dof_id_type>(std::distance (this->active_local_elements_begin(),
1788 2020856 : this->active_local_elements_end()));
1789 673988 : this->comm().sum(active_elements);
1790 :
1791 : // Then add unpartitioned active elements, which should exist on
1792 : // every processor
1793 673988 : active_elements +=
1794 673988 : static_cast<dof_id_type>(std::distance
1795 1347422 : (this->active_pid_elements_begin(DofObject::invalid_processor_id),
1796 674542 : this->active_pid_elements_end(DofObject::invalid_processor_id)));
1797 673988 : return active_elements;
1798 : }
1799 :
1800 :
1801 :
1802 427240 : void DistributedMesh::delete_remote_elements()
1803 : {
1804 : #ifdef DEBUG
1805 : // Make sure our neighbor links are all fine
1806 390 : MeshTools::libmesh_assert_valid_neighbors(*this);
1807 :
1808 : // And our child/parent links, and our flags
1809 390 : MeshTools::libmesh_assert_valid_refinement_tree(*this);
1810 :
1811 : // Make sure our ids and flags are consistent
1812 390 : this->libmesh_assert_valid_parallel_ids();
1813 390 : this->libmesh_assert_valid_parallel_flags();
1814 :
1815 390 : libmesh_assert_equal_to (this->n_nodes(), this->parallel_n_nodes());
1816 390 : libmesh_assert_equal_to (this->n_elem(), this->parallel_n_elem());
1817 390 : const dof_id_type pmax_node_id = this->parallel_max_node_id();
1818 390 : const dof_id_type pmax_elem_id = this->parallel_max_elem_id();
1819 390 : libmesh_assert_equal_to (this->max_node_id(), pmax_node_id);
1820 390 : libmesh_assert_equal_to (this->max_elem_id(), pmax_elem_id);
1821 : #endif
1822 :
1823 427240 : _is_serial = false;
1824 427240 : _is_serial_on_proc_0 = false;
1825 :
1826 427240 : MeshCommunication().delete_remote_elements(*this, _extra_ghost_elems);
1827 :
1828 390 : libmesh_assert_equal_to (this->max_elem_id(), this->parallel_max_elem_id());
1829 :
1830 : // Now make sure the containers actually shrink - strip
1831 : // any newly-created nullptr voids out of the element array
1832 427240 : dofobject_container<Elem>::veclike_iterator e_it = _elements.begin();
1833 390 : const dofobject_container<Elem>::veclike_iterator e_end = _elements.end();
1834 53652139 : while (e_it != e_end)
1835 53224899 : if (!*e_it)
1836 39540658 : e_it = _elements.erase(e_it);
1837 : else
1838 17409 : ++e_it;
1839 :
1840 427240 : dofobject_container<Node>::veclike_iterator n_it = _nodes.begin();
1841 390 : const dofobject_container<Node>::veclike_iterator n_end = _nodes.end();
1842 101021196 : while (n_it != n_end)
1843 100593956 : if (!*n_it)
1844 66856367 : n_it = _nodes.erase(n_it);
1845 : else
1846 48635 : ++n_it;
1847 :
1848 : // We may have deleted no-longer-connected nodes or coarsened-away
1849 : // elements; let's update our caches.
1850 427240 : this->update_parallel_id_counts();
1851 :
1852 : // We may have deleted nodes or elements that were the only local
1853 : // representatives of some particular boundary id(s); let's update
1854 : // those caches.
1855 427240 : this->get_boundary_info().regenerate_id_sets();
1856 :
1857 : #ifdef DEBUG
1858 : // We might not have well-packed objects if the user didn't allow us
1859 : // to renumber
1860 : // libmesh_assert_equal_to (this->n_nodes(), this->max_node_id());
1861 : // libmesh_assert_equal_to (this->n_elem(), this->max_elem_id());
1862 :
1863 : // Make sure our neighbor links are all fine
1864 390 : MeshTools::libmesh_assert_valid_neighbors(*this);
1865 :
1866 : // And our child/parent links, and our flags
1867 390 : MeshTools::libmesh_assert_valid_refinement_tree(*this);
1868 :
1869 : // Make sure our ids and flags are consistent
1870 390 : this->libmesh_assert_valid_parallel_ids();
1871 390 : this->libmesh_assert_valid_parallel_flags();
1872 : #endif
1873 :
1874 427240 : this->_preparation.has_removed_remote_elements = true;
1875 427240 : }
1876 :
1877 :
1878 0 : void DistributedMesh::add_extra_ghost_elem(Elem * e)
1879 : {
1880 : // First add the elem like normal
1881 0 : add_elem(e);
1882 :
1883 : // Now add it to the set that won't be deleted when we call
1884 : // delete_remote_elements()
1885 0 : _extra_ghost_elems.insert(e);
1886 0 : }
1887 :
1888 : void
1889 0 : DistributedMesh::clear_extra_ghost_elems(const std::set<Elem *> & extra_ghost_elems)
1890 : {
1891 0 : std::set<Elem *> tmp;
1892 0 : std::set_difference(_extra_ghost_elems.begin(), _extra_ghost_elems.end(),
1893 : extra_ghost_elems.begin(), extra_ghost_elems.end(),
1894 0 : std::inserter(tmp, tmp.begin()));
1895 0 : _extra_ghost_elems = tmp;
1896 0 : }
1897 :
1898 98725 : void DistributedMesh::allgather()
1899 : {
1900 98725 : if (_is_serial)
1901 0 : return;
1902 98723 : MeshCommunication().allgather(*this);
1903 98723 : _is_serial = true;
1904 98723 : _is_serial_on_proc_0 = true;
1905 :
1906 : // Make sure our caches are up to date and our
1907 : // DofObjects are well packed
1908 : #ifdef DEBUG
1909 48 : libmesh_assert_equal_to (this->n_nodes(), this->parallel_n_nodes());
1910 48 : libmesh_assert_equal_to (this->n_elem(), this->parallel_n_elem());
1911 48 : const dof_id_type pmax_node_id = this->parallel_max_node_id();
1912 48 : const dof_id_type pmax_elem_id = this->parallel_max_elem_id();
1913 48 : libmesh_assert_equal_to (this->max_node_id(), pmax_node_id);
1914 48 : libmesh_assert_equal_to (this->max_elem_id(), pmax_elem_id);
1915 :
1916 : // If we've disabled renumbering we can't be sure we're contiguous
1917 : // libmesh_assert_equal_to (this->n_nodes(), this->max_node_id());
1918 : // libmesh_assert_equal_to (this->n_elem(), this->max_elem_id());
1919 :
1920 : // Make sure our neighbor links are all fine
1921 48 : MeshTools::libmesh_assert_valid_neighbors(*this);
1922 :
1923 : // Make sure our ids and flags are consistent
1924 48 : this->libmesh_assert_valid_parallel_ids();
1925 48 : this->libmesh_assert_valid_parallel_flags();
1926 : #endif
1927 : }
1928 :
1929 18352 : void DistributedMesh::gather_to_zero()
1930 : {
1931 18352 : if (_is_serial_on_proc_0)
1932 4 : return;
1933 :
1934 14114 : _is_serial_on_proc_0 = true;
1935 14114 : MeshCommunication().gather(0, *this);
1936 : }
1937 :
1938 :
1939 : } // namespace libMesh
|