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