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 277019 : DistributedMesh::DistributedMesh (const Parallel::Communicator & comm_in,
43 277019 : unsigned char d) :
44 276535 : UnstructuredMesh (comm_in,d), _is_serial(true),
45 276535 : _is_serial_on_proc_0(true),
46 276535 : _deleted_coarse_elements(false),
47 276535 : _n_nodes(0), _n_elem(0), _max_node_id(0), _max_elem_id(0),
48 277261 : _next_free_local_node_id(this->processor_id()),
49 277019 : _next_free_local_elem_id(this->processor_id()),
50 277019 : _next_free_unpartitioned_node_id(this->n_processors()),
51 277019 : _next_free_unpartitioned_elem_id(this->n_processors())
52 : #ifdef LIBMESH_ENABLE_UNIQUE_ID
53 277019 : , _next_unpartitioned_unique_id(this->n_processors())
54 : #endif
55 : {
56 : #ifdef LIBMESH_ENABLE_UNIQUE_ID
57 277019 : _next_unique_id = this->processor_id();
58 : #endif
59 :
60 277261 : const std::string default_partitioner = "parmetis";
61 : const std::string my_partitioner =
62 : libMesh::command_line_value("--default-partitioner",
63 554038 : default_partitioner);
64 : _partitioner = Partitioner::build
65 553796 : (Utility::string_to_enum<PartitionerType>(my_partitioner));
66 277019 : }
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 13026 : std::string_view DistributedMesh::subclass_first_difference_from (const MeshBase & other_mesh_base) const
99 : {
100 708 : const DistributedMesh * dist_mesh_ptr =
101 13026 : dynamic_cast<const DistributedMesh *>(&other_mesh_base);
102 13026 : if (!dist_mesh_ptr)
103 0 : return "DistributedMesh class";
104 708 : 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 13026 : CHECK_MEMBER(_is_serial);
111 13026 : CHECK_MEMBER(_is_serial_on_proc_0);
112 13026 : CHECK_MEMBER(_deleted_coarse_elements);
113 13026 : CHECK_MEMBER(_n_nodes);
114 13026 : CHECK_MEMBER(_n_elem);
115 13026 : CHECK_MEMBER(_max_node_id);
116 13026 : 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 13026 : if (!this->nodes_and_elements_equal(other_mesh))
129 63 : return "nodes and/or elements";
130 :
131 13669 : if (_extra_ghost_elems.size() !=
132 706 : other_mesh._extra_ghost_elems.size())
133 0 : return "_extra_ghost_elems size";
134 12963 : 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 12963 : return "";
144 : }
145 :
146 319596 : DistributedMesh::~DistributedMesh ()
147 : {
148 297507 : this->DistributedMesh::clear(); // Free nodes and elements
149 319596 : }
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 18003 : DistributedMesh::DistributedMesh (const DistributedMesh & other_mesh) :
156 18003 : DistributedMesh(static_cast<const MeshBase &>(other_mesh))
157 : {
158 18003 : _is_serial = other_mesh._is_serial;
159 18003 : _is_serial_on_proc_0 = other_mesh._is_serial_on_proc_0;
160 18003 : _deleted_coarse_elements = other_mesh._deleted_coarse_elements;
161 :
162 18003 : _n_nodes = other_mesh.n_nodes();
163 18003 : _n_elem = other_mesh.n_elem();
164 18003 : _max_node_id = other_mesh.max_node_id();
165 18003 : _max_elem_id = other_mesh.max_elem_id();
166 18003 : _next_free_local_node_id =
167 18003 : other_mesh._next_free_local_node_id;
168 18003 : _next_free_local_elem_id =
169 18003 : other_mesh._next_free_local_elem_id;
170 18003 : _next_free_unpartitioned_node_id =
171 18003 : other_mesh._next_free_unpartitioned_node_id;
172 18003 : _next_free_unpartitioned_elem_id =
173 18003 : other_mesh._next_free_unpartitioned_elem_id;
174 : #ifdef LIBMESH_ENABLE_UNIQUE_ID
175 18003 : _next_unique_id =
176 18003 : other_mesh._next_unique_id;
177 18003 : _next_unpartitioned_unique_id =
178 18003 : other_mesh._next_unpartitioned_unique_id;
179 : #endif
180 :
181 : // Need to copy extra_ghost_elems
182 18003 : for (auto & elem : other_mesh._extra_ghost_elems)
183 0 : _extra_ghost_elems.insert(this->elem_ptr(elem->id()));
184 18003 : }
185 :
186 :
187 :
188 20488 : DistributedMesh::DistributedMesh (const MeshBase & other_mesh) :
189 20488 : UnstructuredMesh (other_mesh), _is_serial(other_mesh.is_serial()),
190 20916 : _is_serial_on_proc_0(other_mesh.is_serial()),
191 19972 : _deleted_coarse_elements(true), // better safe than sorry...
192 19972 : _n_nodes(0), _n_elem(0), _max_node_id(0), _max_elem_id(0),
193 20916 : _next_free_local_node_id(this->processor_id()),
194 20828 : _next_free_local_elem_id(this->processor_id()),
195 20828 : _next_free_unpartitioned_node_id(this->n_processors()),
196 40888 : _next_free_unpartitioned_elem_id(this->n_processors())
197 : {
198 : // Just copy, skipping preparation
199 20488 : this->copy_nodes_and_elements(other_mesh, true, 0, 0, 0, nullptr, true);
200 :
201 516 : this->allow_find_neighbors(other_mesh.allow_find_neighbors());
202 516 : this->allow_detect_interior_parents(other_mesh.allow_detect_interior_parents());
203 516 : this->allow_renumbering(other_mesh.allow_renumbering());
204 516 : this->allow_remote_element_removal(other_mesh.allow_remote_element_removal());
205 516 : this->skip_partitioning(other_mesh.skip_partitioning());
206 :
207 20488 : this->copy_constraint_rows(other_mesh);
208 :
209 428 : auto & this_boundary_info = this->get_boundary_info();
210 428 : const auto & other_boundary_info = other_mesh.get_boundary_info();
211 :
212 20488 : this_boundary_info = other_boundary_info;
213 :
214 428 : this->set_subdomain_name_map() = other_mesh.get_subdomain_name_map();
215 :
216 20488 : this->_preparation = other_mesh.preparation();
217 :
218 : #ifdef LIBMESH_ENABLE_UNIQUE_ID
219 20488 : _next_unique_id = other_mesh.parallel_max_unique_id() +
220 20576 : this->processor_id();
221 20916 : _next_unpartitioned_unique_id = _next_unique_id +
222 20488 : (this->n_processors() - this->processor_id());
223 : #endif
224 20488 : this->update_parallel_id_counts();
225 20488 : }
226 :
227 270 : void DistributedMesh::move_nodes_and_elements(MeshBase && other_meshbase)
228 : {
229 4 : DistributedMesh & other_mesh = cast_ref<DistributedMesh&>(other_meshbase);
230 :
231 4 : this->_nodes = std::move(other_mesh._nodes);
232 270 : this->_n_nodes = other_mesh.n_nodes();
233 :
234 4 : this->_elements = std::move(other_mesh._elements);
235 270 : this->_n_elem = other_mesh.n_elem();
236 :
237 270 : _is_serial = other_mesh.is_serial();
238 270 : _is_serial_on_proc_0 = other_mesh.is_serial_on_zero();
239 270 : _deleted_coarse_elements = true; // Better safe than sorry
240 :
241 270 : _max_node_id = other_mesh.max_node_id();
242 270 : _max_elem_id = other_mesh.max_elem_id();
243 :
244 270 : _next_free_local_node_id = other_mesh._next_free_local_node_id;
245 270 : _next_free_local_elem_id = other_mesh._next_free_local_elem_id;
246 270 : _next_free_unpartitioned_node_id = other_mesh._next_free_unpartitioned_node_id;
247 270 : _next_free_unpartitioned_elem_id = other_mesh._next_free_unpartitioned_elem_id;
248 :
249 : #ifdef LIBMESH_ENABLE_UNIQUE_ID
250 270 : _next_unpartitioned_unique_id = other_mesh._next_unpartitioned_unique_id;
251 : #endif
252 270 : }
253 :
254 : // We use cached values for these so they can be called
255 : // from one processor without bothering the rest, but
256 : // we may need to update those caches before doing a full
257 : // renumbering
258 1888059 : void DistributedMesh::update_parallel_id_counts()
259 : {
260 : // This function must be run on all processors at once
261 2402 : parallel_object_only();
262 :
263 1888059 : _n_elem = this->parallel_n_elem();
264 1888059 : _n_nodes = this->parallel_n_nodes();
265 1888059 : _max_node_id = this->parallel_max_node_id();
266 1888059 : _max_elem_id = this->parallel_max_elem_id();
267 :
268 1888059 : if (_next_free_unpartitioned_elem_id < _max_elem_id)
269 21653 : _next_free_unpartitioned_elem_id =
270 21653 : ((_max_elem_id-1) / (this->n_processors() + 1) + 1) *
271 21653 : (this->n_processors() + 1) + this->n_processors();
272 1888059 : if (_next_free_local_elem_id < _max_elem_id)
273 21135 : _next_free_local_elem_id =
274 21157 : ((_max_elem_id + this->n_processors() - 1) / (this->n_processors() + 1) + 1) *
275 21135 : (this->n_processors() + 1) + this->processor_id();
276 :
277 1888059 : if (_next_free_unpartitioned_node_id < _max_node_id)
278 28280 : _next_free_unpartitioned_node_id =
279 28280 : ((_max_node_id-1) / (this->n_processors() + 1) + 1) *
280 28280 : (this->n_processors() + 1) + this->n_processors();
281 1888059 : if (_next_free_local_node_id < _max_node_id)
282 28925 : _next_free_local_node_id =
283 28950 : ((_max_node_id + this->n_processors() - 1) / (this->n_processors() + 1) + 1) *
284 28925 : (this->n_processors() + 1) + this->processor_id();
285 :
286 : #ifdef LIBMESH_ENABLE_UNIQUE_ID
287 1888059 : _next_unique_id = this->parallel_max_unique_id();
288 1888059 : _next_unpartitioned_unique_id =
289 1889781 : ((_next_unique_id-1) / (this->n_processors() + 1) + 1) *
290 1888059 : (this->n_processors() + 1) + this->n_processors();
291 1888059 : _next_unique_id =
292 1888059 : ((_next_unique_id + this->n_processors() - 1) / (this->n_processors() + 1) + 1) *
293 1888059 : (this->n_processors() + 1) + this->processor_id();
294 : #endif
295 :
296 1888059 : this->_preparation.has_synched_id_counts = true;
297 1888059 : }
298 :
299 :
300 : // Or in debug mode we may want to test the uncached values without
301 : // changing the cache
302 1895770 : dof_id_type DistributedMesh::parallel_n_elem() const
303 : {
304 : // This function must be run on all processors at once
305 3236 : parallel_object_only();
306 :
307 1895770 : dof_id_type n_local = this->n_local_elem();
308 1895770 : this->comm().sum(n_local);
309 1895770 : n_local += this->n_unpartitioned_elem();
310 1895770 : return n_local;
311 : }
312 :
313 :
314 :
315 1894937 : dof_id_type DistributedMesh::parallel_max_elem_id() const
316 : {
317 : // This function must be run on all processors at once
318 9280 : parallel_object_only();
319 :
320 1894937 : dof_id_type max_local = 0;
321 :
322 : dofobject_container<Elem>::const_reverse_veclike_iterator
323 9280 : rit = _elements.rbegin();
324 :
325 : const dofobject_container<Elem>::const_reverse_veclike_iterator
326 9280 : rend = _elements.rend();
327 :
328 : // Look for the maximum element id. Search backwards through
329 : // elements so we can break out early. Beware of nullptr entries that
330 : // haven't yet been cleared from _elements.
331 11315348 : for (; rit != rend; ++rit)
332 : {
333 10791322 : const DofObject *d = *rit;
334 19535 : if (d)
335 : {
336 9043 : libmesh_assert(_elements[d->id()] == d);
337 1370911 : max_local = d->id() + 1;
338 1370911 : break;
339 : }
340 : }
341 :
342 1894937 : this->comm().max(max_local);
343 1894937 : return max_local;
344 : }
345 :
346 :
347 :
348 : #ifdef LIBMESH_ENABLE_UNIQUE_ID
349 1990911 : unique_id_type DistributedMesh::parallel_max_unique_id() const
350 : {
351 : // This function must be run on all processors at once
352 3200 : parallel_object_only();
353 :
354 3981822 : unique_id_type max_local = std::max(_next_unique_id,
355 2302489 : _next_unpartitioned_unique_id);
356 1990911 : this->comm().max(max_local);
357 1990911 : return max_local;
358 : }
359 :
360 :
361 :
362 78212 : void DistributedMesh::set_next_unique_id(unique_id_type id)
363 : {
364 482 : _next_unique_id = id;
365 78212 : _next_unpartitioned_unique_id =
366 78354 : ((_next_unique_id-1) / (this->n_processors() + 1) + 1) *
367 78212 : (this->n_processors() + 1) + this->n_processors();
368 78212 : _next_unique_id =
369 78212 : ((_next_unique_id + this->n_processors() - 1) / (this->n_processors() + 1) + 1) *
370 78212 : (this->n_processors() + 1) + this->processor_id();
371 78212 : }
372 : #endif
373 :
374 :
375 :
376 1896218 : dof_id_type DistributedMesh::parallel_n_nodes() const
377 : {
378 : // This function must be run on all processors at once
379 3236 : parallel_object_only();
380 :
381 1896218 : dof_id_type n_local = this->n_local_nodes();
382 1896218 : this->comm().sum(n_local);
383 1896218 : n_local += this->n_unpartitioned_nodes();
384 1896218 : return n_local;
385 : }
386 :
387 :
388 :
389 1892563 : dof_id_type DistributedMesh::parallel_max_node_id() const
390 : {
391 : // This function must be run on all processors at once
392 6906 : parallel_object_only();
393 :
394 1892563 : dof_id_type max_local = 0;
395 :
396 : dofobject_container<Node>::const_reverse_veclike_iterator
397 6906 : rit = _nodes.rbegin();
398 :
399 : const dofobject_container<Node>::const_reverse_veclike_iterator
400 6906 : rend = _nodes.rend();
401 :
402 : // Look for the maximum node id. Search backwards through
403 : // nodes so we can break out early. Beware of nullptr entries that
404 : // haven't yet been cleared from _nodes
405 39582183 : for (; rit != rend; ++rit)
406 : {
407 39058227 : const DofObject *d = *rit;
408 63819 : if (d)
409 : {
410 6739 : libmesh_assert(_nodes[d->id()] == d);
411 1368607 : max_local = d->id() + 1;
412 1368607 : break;
413 : }
414 : }
415 :
416 1892563 : this->comm().max(max_local);
417 1892563 : return max_local;
418 : }
419 :
420 :
421 :
422 42399244 : const Point & DistributedMesh::point (const dof_id_type i) const
423 : {
424 42399244 : return this->node_ref(i);
425 : }
426 :
427 :
428 :
429 43504633 : const Node * DistributedMesh::node_ptr (const dof_id_type i) const
430 : {
431 136653 : libmesh_assert(_nodes[i]);
432 136653 : libmesh_assert_equal_to (_nodes[i]->id(), i);
433 :
434 43504633 : return _nodes[i];
435 : }
436 :
437 :
438 :
439 :
440 734336431 : Node * DistributedMesh::node_ptr (const dof_id_type i)
441 : {
442 704117 : libmesh_assert(_nodes[i]);
443 704117 : libmesh_assert_equal_to (_nodes[i]->id(), i);
444 :
445 734336431 : return _nodes[i];
446 : }
447 :
448 :
449 :
450 :
451 3539316 : const Node * DistributedMesh::query_node_ptr (const dof_id_type i) const
452 : {
453 3539316 : if (const auto it = _nodes.find(i);
454 1087593 : it != _nodes.end())
455 : {
456 3102772 : const Node * n = *it;
457 651049 : libmesh_assert (!n || n->id() == i);
458 651049 : return n;
459 : }
460 :
461 436544 : return nullptr;
462 : }
463 :
464 :
465 :
466 :
467 367375651 : Node * DistributedMesh::query_node_ptr (const dof_id_type i)
468 : {
469 367375651 : if (auto it = _nodes.find(i);
470 244321 : it != _nodes.end())
471 : {
472 284553977 : Node * n = *it;
473 156798 : libmesh_assert (!n || n->id() == i);
474 156798 : return n;
475 : }
476 :
477 87523 : return nullptr;
478 : }
479 :
480 :
481 :
482 :
483 3049923 : const Elem * DistributedMesh::elem_ptr (const dof_id_type i) const
484 : {
485 10085 : libmesh_assert(_elements[i]);
486 10085 : libmesh_assert_equal_to (_elements[i]->id(), i);
487 :
488 3049923 : return _elements[i];
489 : }
490 :
491 :
492 :
493 :
494 286884998 : Elem * DistributedMesh::elem_ptr (const dof_id_type i)
495 : {
496 177789 : libmesh_assert(_elements[i]);
497 177789 : libmesh_assert_equal_to (_elements[i]->id(), i);
498 :
499 286884998 : return _elements[i];
500 : }
501 :
502 :
503 :
504 :
505 1792857 : const Elem * DistributedMesh::query_elem_ptr (const dof_id_type i) const
506 : {
507 1792857 : if (const auto it = _elements.find(i);
508 953887 : it != _elements.end())
509 : {
510 1246870 : const Elem * e = *it;
511 416781 : libmesh_assert (!e || e->id() == i);
512 416781 : return e;
513 : }
514 :
515 537106 : return nullptr;
516 : }
517 :
518 :
519 :
520 :
521 603582363 : Elem * DistributedMesh::query_elem_ptr (const dof_id_type i)
522 : {
523 603582363 : if (auto it = _elements.find(i);
524 217082 : it != _elements.end())
525 : {
526 518035954 : Elem * e = *it;
527 213403 : libmesh_assert (!e || e->id() == i);
528 213403 : return e;
529 : }
530 :
531 3679 : return nullptr;
532 : }
533 :
534 :
535 :
536 :
537 44055870 : Elem * DistributedMesh::add_elem (Elem * e)
538 : {
539 : // Don't try to add nullptrs!
540 35269 : libmesh_assert(e);
541 :
542 : // Trying to add an existing element is a no-op
543 44055870 : if (e->valid_id() && _elements[e->id()] == e)
544 0 : return e;
545 :
546 44055870 : const processor_id_type elem_procid = e->processor_id();
547 :
548 44055870 : if (!e->valid_id())
549 : {
550 : // We should only be creating new ids past the end of the range
551 : // of existing ids
552 3568 : libmesh_assert_greater_equal(_next_free_unpartitioned_elem_id,
553 : _max_elem_id);
554 3568 : libmesh_assert_greater_equal(_next_free_local_elem_id, _max_elem_id);
555 :
556 : // Use the unpartitioned ids for unpartitioned elems, and
557 : // temporarily for ghost elems
558 3857693 : dof_id_type * next_id = &_next_free_unpartitioned_elem_id;
559 3861261 : if (elem_procid == this->processor_id())
560 1133556 : next_id = &_next_free_local_elem_id;
561 3857693 : e->set_id (*next_id);
562 : }
563 :
564 : {
565 : // Advance next_ids up high enough that each is pointing to an
566 : // unused id and any subsequent increments will still point us
567 : // to unused ids
568 88111740 : _max_elem_id = std::max(_max_elem_id,
569 44055870 : static_cast<dof_id_type>(e->id()+1));
570 :
571 44055870 : if (_next_free_unpartitioned_elem_id < _max_elem_id)
572 5146930 : _next_free_unpartitioned_elem_id =
573 5146930 : ((_max_elem_id-1) / (this->n_processors() + 1) + 1) *
574 5146930 : (this->n_processors() + 1) + this->n_processors();
575 44055870 : if (_next_free_local_elem_id < _max_elem_id)
576 3454280 : _next_free_local_elem_id =
577 3460520 : ((_max_elem_id + this->n_processors() - 1) / (this->n_processors() + 1) + 1) *
578 3454280 : (this->n_processors() + 1) + this->processor_id();
579 :
580 : #ifndef NDEBUG
581 : // We need a const dofobject_container so we don't inadvertently create
582 : // nullptr entries when testing for non-nullptr ones
583 35269 : const dofobject_container<Elem> & const_elements = _elements;
584 : #endif
585 35269 : libmesh_assert(!const_elements[_next_free_unpartitioned_elem_id]);
586 35269 : libmesh_assert(!const_elements[_next_free_local_elem_id]);
587 : }
588 :
589 : // Don't try to overwrite existing elems
590 35269 : libmesh_assert (!_elements[e->id()]);
591 :
592 44055870 : _elements[e->id()] = e;
593 :
594 : // We actually added a new element. Some of our caches might still
595 : // be valid, but we should clear the ones which definitely are not.
596 44055870 : this->clear_point_locator();
597 44055870 : this->clear_stored_ranges();
598 :
599 : // Try to make the cached elem data more accurate
600 44074751 : if (elem_procid == this->processor_id() ||
601 : elem_procid == DofObject::invalid_processor_id)
602 12916533 : _n_elem++;
603 :
604 : #ifdef LIBMESH_ENABLE_UNIQUE_ID
605 44055870 : if (!e->valid_unique_id())
606 : {
607 13502719 : if (processor_id() == e->processor_id())
608 : {
609 1133556 : e->set_unique_id(_next_unique_id);
610 1133556 : _next_unique_id += this->n_processors() + 1;
611 : }
612 : else
613 : {
614 12369163 : e->set_unique_id(_next_unpartitioned_unique_id);
615 12369163 : _next_unpartitioned_unique_id += this->n_processors() + 1;
616 : }
617 : }
618 : else
619 : {
620 30577496 : _next_unique_id = std::max(_next_unique_id, e->unique_id()+1);
621 30553151 : _next_unique_id =
622 30553151 : ((_next_unique_id + this->n_processors() - 1) / (this->n_processors() + 1) + 1) *
623 30553151 : (this->n_processors() + 1) + this->processor_id();
624 : }
625 : #endif
626 :
627 : // Unpartitioned elems should be added on every processor
628 : // And shouldn't be added in the same batch as ghost elems
629 : // But we might be just adding on processor 0 to
630 : // broadcast later
631 : // #ifdef DEBUG
632 : // if (elem_procid == DofObject::invalid_processor_id)
633 : // {
634 : // dof_id_type elem_id = e->id();
635 : // this->comm().max(elem_id);
636 : // libmesh_assert_equal_to (elem_id, e->id());
637 : // }
638 : // #endif
639 :
640 : // Make sure any new element is given space for any extra integers
641 : // we've requested
642 44055870 : e->add_extra_integers(_elem_integer_names.size(),
643 44055870 : _elem_integer_default_values);
644 :
645 : // And set mapping type and data on any new element
646 54150 : e->set_mapping_type(this->default_mapping_type());
647 54150 : e->set_mapping_data(this->default_mapping_data());
648 :
649 44055870 : return e;
650 : }
651 :
652 :
653 :
654 14755106 : Elem * DistributedMesh::add_elem (std::unique_ptr<Elem> e)
655 : {
656 : // The mesh now takes ownership of the Elem. Eventually the guts of
657 : // add_elem() will get moved to a private helper function, and
658 : // calling add_elem() directly will be deprecated.
659 14755106 : return add_elem(e.release());
660 : }
661 :
662 :
663 :
664 3348652 : Elem * DistributedMesh::insert_elem (Elem * e)
665 : {
666 3348652 : if (_elements[e->id()])
667 3348652 : this->delete_elem(_elements[e->id()]);
668 :
669 : #ifdef LIBMESH_ENABLE_UNIQUE_ID
670 3348652 : if (!e->valid_unique_id())
671 : {
672 0 : if (processor_id() == e->processor_id())
673 : {
674 0 : e->set_unique_id(_next_unique_id);
675 0 : _next_unique_id += this->n_processors() + 1;
676 : }
677 : else
678 : {
679 0 : e->set_unique_id(_next_unpartitioned_unique_id);
680 0 : _next_unpartitioned_unique_id += this->n_processors() + 1;
681 : }
682 : }
683 : else
684 : {
685 3374032 : _next_unique_id = std::max(_next_unique_id, e->unique_id()+1);
686 3348652 : _next_unique_id =
687 3352348 : ((_next_unique_id + this->n_processors() - 1) / (this->n_processors() + 1) + 1) *
688 3348652 : (this->n_processors() + 1) + this->processor_id();
689 : }
690 : #endif
691 :
692 : // Try to make the cached elem data more accurate
693 3348652 : processor_id_type elem_procid = e->processor_id();
694 3352348 : if (elem_procid == this->processor_id() ||
695 : elem_procid == DofObject::invalid_processor_id)
696 3219576 : _n_elem++;
697 :
698 3348652 : _elements[e->id()] = e;
699 :
700 : // We actually added a new element. Some of our caches might still
701 : // be valid, but we should clear the ones which definitely are not.
702 3348652 : this->clear_point_locator();
703 3348652 : this->clear_stored_ranges();
704 :
705 : // Make sure any new element is given space for any extra integers
706 : // we've requested
707 3348652 : e->add_extra_integers(_elem_integer_names.size(),
708 3348652 : _elem_integer_default_values);
709 :
710 : // And set mapping type and data on any new element
711 7392 : e->set_mapping_type(this->default_mapping_type());
712 7392 : e->set_mapping_data(this->default_mapping_data());
713 :
714 3348652 : return e;
715 : }
716 :
717 3348652 : Elem * DistributedMesh::insert_elem (std::unique_ptr<Elem> e)
718 : {
719 : // The mesh now takes ownership of the Elem. Eventually the guts of
720 : // insert_elem(Elem*) will get moved to a private helper function, and
721 : // calling insert_elem(Elem*) directly will be deprecated.
722 3348652 : return insert_elem(e.release());
723 : }
724 :
725 :
726 40089690 : void DistributedMesh::delete_elem(Elem * e)
727 : {
728 7586 : libmesh_assert (e);
729 :
730 : // Try to make the cached elem data more accurate
731 40089690 : _n_elem--;
732 :
733 : // Was this a coarse element, not just a coarsening where we still
734 : // have some ancestor structure? Was it a *local* element, that we
735 : // might have been depending on as an owner of local nodes? We'll
736 : // have to be more careful with our nodes in contract() later; no
737 : // telling if we just locally orphaned a node that should be
738 : // globally retained.
739 40099096 : if (e->processor_id() == this->processor_id() &&
740 3640 : !e->parent())
741 80473 : _deleted_coarse_elements = true;
742 :
743 : // Delete the element from the BoundaryInfo object
744 40089690 : this->get_boundary_info().remove(e);
745 :
746 : // But not yet from the container; we might invalidate
747 : // an iterator that way!
748 :
749 : //_elements.erase(e->id());
750 :
751 : // Instead, we set it to nullptr for now
752 :
753 40089690 : _elements[e->id()] = nullptr;
754 :
755 : // delete the element
756 40089690 : delete e;
757 :
758 : // Some of our caches might still be valid, but we should clear the
759 : // ones which definitely are not.
760 40089690 : this->clear_point_locator();
761 40089690 : this->clear_stored_ranges();
762 40089690 : }
763 :
764 :
765 :
766 3207784 : void DistributedMesh::renumber_elem(const dof_id_type old_id,
767 : const dof_id_type new_id)
768 : {
769 : // This could be a no-op
770 3207784 : if (old_id == new_id)
771 0 : return;
772 :
773 3207784 : Elem * el = _elements[old_id];
774 1160 : libmesh_assert (el);
775 1160 : libmesh_assert_equal_to (el->id(), old_id);
776 :
777 3207784 : el->set_id(new_id);
778 1160 : libmesh_assert (!_elements[new_id]);
779 3207784 : _elements[new_id] = el;
780 3207784 : _elements.erase(old_id);
781 :
782 : // Should we delete any caches here? Our point locator indexes by
783 : // element pointer and should be fine with an id change. Our stored
784 : // ranges are no longer sorted, which is *probably* fine, but let's
785 : // just be safe.
786 3207784 : this->clear_stored_ranges();
787 : }
788 :
789 :
790 :
791 40974734 : Node * DistributedMesh::add_point (const Point & p,
792 : const dof_id_type id,
793 : const processor_id_type proc_id)
794 : {
795 40974734 : Node * old_n = this->query_node_ptr(id);
796 :
797 40974734 : if (old_n)
798 : {
799 0 : *old_n = p;
800 0 : old_n->processor_id() = proc_id;
801 :
802 0 : return old_n;
803 : }
804 :
805 40934979 : Node * n = Node::build(p, id).release();
806 40974734 : n->processor_id() = proc_id;
807 :
808 40974734 : return DistributedMesh::add_node(n);
809 : }
810 :
811 :
812 4130 : void DistributedMesh::own_node (Node & n)
813 : {
814 : // This had better be a node in our mesh
815 0 : libmesh_assert(_nodes[n.id()] == &n);
816 :
817 4130 : _nodes[n.id()] = nullptr;
818 4130 : _n_nodes--;
819 :
820 0 : n.set_id(DofObject::invalid_id);
821 4130 : n.processor_id() = this->processor_id();
822 :
823 4130 : this->add_node(&n);
824 4130 : }
825 :
826 :
827 71747743 : Node * DistributedMesh::add_node (Node * n)
828 : {
829 : // Don't try to add nullptrs!
830 81737 : libmesh_assert(n);
831 :
832 : // Trying to add an existing node is a no-op
833 71747743 : if (n->valid_id() && _nodes[n->id()] == n)
834 0 : return n;
835 :
836 71747743 : const processor_id_type node_procid = n->processor_id();
837 :
838 71747743 : if (!n->valid_id())
839 : {
840 : // We should only be creating new ids past the end of the range
841 : // of existing ids
842 17829 : libmesh_assert_greater_equal(_next_free_unpartitioned_node_id,
843 : _max_node_id);
844 17829 : libmesh_assert_greater_equal(_next_free_local_node_id, _max_node_id);
845 :
846 : // Use the unpartitioned ids for unpartitioned nodes,
847 : // and temporarily for ghost nodes
848 17183774 : dof_id_type * next_id = &_next_free_unpartitioned_node_id;
849 17201603 : if (node_procid == this->processor_id())
850 2128321 : next_id = &_next_free_local_node_id;
851 17183774 : n->set_id (*next_id);
852 : }
853 :
854 : {
855 : // Advance next_ids up high enough that each is pointing to an
856 : // unused id and any subsequent increments will still point us
857 : // to unused ids
858 143495486 : _max_node_id = std::max(_max_node_id,
859 71747743 : static_cast<dof_id_type>(n->id()+1));
860 :
861 71747743 : if (_next_free_unpartitioned_node_id < _max_node_id)
862 20123386 : _next_free_unpartitioned_node_id =
863 20123386 : ((_max_node_id-1) / (this->n_processors() + 1) + 1) *
864 20123386 : (this->n_processors() + 1) + this->n_processors();
865 71747743 : if (_next_free_local_node_id < _max_node_id)
866 11730384 : _next_free_local_node_id =
867 11748176 : ((_max_node_id + this->n_processors() - 1) / (this->n_processors() + 1) + 1) *
868 11730384 : (this->n_processors() + 1) + this->processor_id();
869 :
870 : #ifndef NDEBUG
871 : // We need a const dofobject_container so we don't inadvertently create
872 : // nullptr entries when testing for non-nullptr ones
873 81737 : const dofobject_container<Node> & const_nodes = _nodes;
874 : #endif
875 81737 : libmesh_assert(!const_nodes[_next_free_unpartitioned_node_id]);
876 81737 : libmesh_assert(!const_nodes[_next_free_local_node_id]);
877 : }
878 :
879 : // Don't try to overwrite existing nodes
880 81737 : libmesh_assert (!_nodes[n->id()]);
881 :
882 71747743 : _nodes[n->id()] = n;
883 :
884 : // Try to make the cached node data more accurate
885 71789210 : if (node_procid == this->processor_id() ||
886 : node_procid == DofObject::invalid_processor_id)
887 38545498 : _n_nodes++;
888 :
889 : #ifdef LIBMESH_ENABLE_UNIQUE_ID
890 71747743 : if (!n->valid_unique_id())
891 : {
892 40976462 : if (processor_id() == n->processor_id())
893 : {
894 2569114 : n->set_unique_id(_next_unique_id);
895 2569114 : _next_unique_id += this->n_processors() + 1;
896 : }
897 : else
898 : {
899 38407348 : n->set_unique_id(_next_unpartitioned_unique_id);
900 38407348 : _next_unpartitioned_unique_id += this->n_processors() + 1;
901 : }
902 : }
903 : else
904 : {
905 30901702 : _next_unique_id = std::max(_next_unique_id, n->unique_id()+1);
906 30771281 : _next_unique_id =
907 30771281 : ((_next_unique_id + this->n_processors() - 1) / (this->n_processors() + 1) + 1) *
908 30771281 : (this->n_processors() + 1) + this->processor_id();
909 : }
910 : #endif
911 :
912 71747743 : n->add_extra_integers(_node_integer_names.size(),
913 71747743 : _node_integer_default_values);
914 :
915 : // Unpartitioned nodes should be added on every processor
916 : // And shouldn't be added in the same batch as ghost nodes
917 : // But we might be just adding on processor 0 to
918 : // broadcast later
919 : // #ifdef DEBUG
920 : // if (node_procid == DofObject::invalid_processor_id)
921 : // {
922 : // dof_id_type node_id = n->id();
923 : // this->comm().max(node_id);
924 : // libmesh_assert_equal_to (node_id, n->id());
925 : // }
926 : // #endif
927 :
928 71747743 : return n;
929 : }
930 :
931 30768879 : Node * DistributedMesh::add_node (std::unique_ptr<Node> n)
932 : {
933 : // The mesh now takes ownership of the Node. Eventually the guts of
934 : // add_node() will get moved to a private helper function, and
935 : // calling add_node() directly will be deprecated.
936 30768879 : return add_node(n.release());
937 : }
938 :
939 50483394 : void DistributedMesh::delete_node(Node * n)
940 : {
941 4461 : libmesh_assert(n);
942 4461 : libmesh_assert(_nodes[n->id()]);
943 :
944 : // Try to make the cached elem data more accurate
945 50483394 : _n_nodes--;
946 :
947 : // Delete the node from the BoundaryInfo object
948 50483394 : this->get_boundary_info().remove(n);
949 8922 : _constraint_rows.erase(n);
950 :
951 : // But not yet from the container; we might invalidate
952 : // an iterator that way!
953 :
954 : //_nodes.erase(n->id());
955 :
956 : // Instead, we set it to nullptr for now
957 :
958 50483394 : _nodes[n->id()] = nullptr;
959 :
960 : // delete the node
961 50483394 : delete n;
962 50483394 : }
963 :
964 :
965 :
966 6896924 : void DistributedMesh::renumber_node(const dof_id_type old_id,
967 : const dof_id_type new_id)
968 : {
969 : // This could be a no-op
970 6896924 : if (old_id == new_id)
971 0 : return;
972 :
973 6896326 : Node * nd = _nodes[old_id];
974 3234 : libmesh_assert (nd);
975 3234 : libmesh_assert_equal_to (nd->id(), old_id);
976 :
977 : // If we have nodes shipped to this processor for NodeConstraints
978 : // use, then those nodes will exist in _nodes, but may not be
979 : // locatable via a TopologyMap due to the insufficiency of elements
980 : // connecting to them. If local refinement then wants to create a
981 : // *new* node in the same location, it will initially get a temporary
982 : // id, and then make_node_ids_parallel_consistent() will try to move
983 : // it to the canonical id. We need to account for this case to
984 : // avoid false positives and memory leaks.
985 : #ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS
986 6468 : if (_nodes[new_id])
987 : {
988 0 : libmesh_assert_equal_to (*(Point *)_nodes[new_id],
989 : *(Point *)_nodes[old_id]);
990 0 : _nodes.erase(new_id);
991 : }
992 : #else
993 : // If we aren't shipping nodes for NodeConstraints, there should be
994 : // no reason for renumbering one node onto another.
995 : libmesh_assert (!_nodes[new_id]);
996 : #endif
997 6896326 : _nodes[new_id] = nd;
998 6896326 : nd->set_id(new_id);
999 :
1000 6896326 : _nodes.erase(old_id);
1001 : }
1002 :
1003 :
1004 :
1005 555291 : void DistributedMesh::clear ()
1006 : {
1007 : // Call parent clear function
1008 555291 : MeshBase::clear();
1009 :
1010 : // Clear our elements and nodes
1011 : // There is no need to remove them from
1012 : // the BoundaryInfo data structure since we
1013 : // already cleared it.
1014 555291 : this->DistributedMesh::clear_elems();
1015 :
1016 22619057 : for (auto & node : _nodes)
1017 40920444 : delete node;
1018 :
1019 904 : _nodes.clear();
1020 :
1021 : // We're no longer distributed if we were before
1022 555291 : _is_serial = true;
1023 555291 : _is_serial_on_proc_0 = true;
1024 :
1025 : // We deleted a ton of coarse elements, but their nodes got deleted too so
1026 : // all is copacetic.
1027 555291 : _deleted_coarse_elements = false;
1028 :
1029 : // Correct our caches
1030 555291 : _n_nodes = 0;
1031 555291 : _max_node_id = 0;
1032 555855 : _next_free_local_node_id = this->processor_id();
1033 555291 : _next_free_unpartitioned_node_id = this->n_processors();
1034 555291 : }
1035 :
1036 :
1037 :
1038 561563 : void DistributedMesh::clear_elems ()
1039 : {
1040 9222184 : for (auto & elem : _elements)
1041 8660621 : delete elem;
1042 :
1043 904 : _elements.clear();
1044 :
1045 : // Correct our caches
1046 561563 : _n_elem = 0;
1047 561563 : _max_elem_id = 0;
1048 562127 : _next_free_local_elem_id = this->processor_id();
1049 561563 : _next_free_unpartitioned_elem_id = this->n_processors();
1050 561563 : }
1051 :
1052 :
1053 :
1054 554589 : void DistributedMesh::redistribute ()
1055 : {
1056 : // If this is a truly parallel mesh, go through the redistribution/gather/delete remote steps
1057 554589 : if (!this->is_serial())
1058 : {
1059 : // Construct a MeshCommunication object to actually redistribute the nodes
1060 : // and elements according to the partitioner, and then to re-gather the neighbors.
1061 : MeshCommunication mc;
1062 68133 : mc.redistribute(*this);
1063 :
1064 68133 : this->update_parallel_id_counts();
1065 :
1066 : // We communicate valid neighbor links for newly-redistributed
1067 : // elements, but we may still have remote_elem links that should
1068 : // be corrected but whose correction wasn't communicated.
1069 68405 : this->find_neighbors(/*reset_remote_elements*/ false,
1070 : /*reset_current_list*/ false /*non-default*/,
1071 : /*assert_valid*/ false,
1072 272 : /*check_non_remote*/ false /*non-default!*/);
1073 :
1074 : // Is this necessary? If we are called from prepare_for_use(), this will be called
1075 : // anyway... but users can always call partition directly, in which case we do need
1076 : // to call delete_remote_elements()...
1077 : //
1078 : // Regardless of whether it's necessary, it isn't safe. We
1079 : // haven't communicated new node processor_ids yet, and we can't
1080 : // delete nodes until we do.
1081 : // this->delete_remote_elements();
1082 : }
1083 : else
1084 : // The base class can handle non-distributed things, like
1085 : // notifying any GhostingFunctors of changes
1086 486456 : MeshBase::redistribute();
1087 554589 : }
1088 :
1089 :
1090 :
1091 476512 : void DistributedMesh::update_post_partitioning ()
1092 : {
1093 : // this->recalculate_n_partitions();
1094 :
1095 : // Let's do the base class cache clearing first, just in case our
1096 : // later computations are ever changed to make use of a local
1097 : // elements range cache
1098 476512 : this->MeshBase::update_post_partitioning();
1099 :
1100 : // Partitioning changes our numbers of unpartitioned objects
1101 476512 : this->update_parallel_id_counts();
1102 476512 : }
1103 :
1104 :
1105 :
1106 : template <typename T>
1107 3300 : void DistributedMesh::libmesh_assert_valid_parallel_object_ids(const dofobject_container<T> & objects) const
1108 : {
1109 : // This function must be run on all processors at once
1110 3300 : parallel_object_only();
1111 :
1112 3300 : const dof_id_type pmax_node_id = this->parallel_max_node_id();
1113 3300 : const dof_id_type pmax_elem_id = this->parallel_max_elem_id();
1114 3300 : const dof_id_type pmax_id = std::max(pmax_node_id, pmax_elem_id);
1115 :
1116 906732 : for (dof_id_type i=0; i != pmax_id; ++i)
1117 : {
1118 903432 : T * obj = objects[i]; // Returns nullptr if there's no map entry
1119 :
1120 : // Local lookups by id should return the requested object
1121 903432 : libmesh_assert(!obj || obj->id() == i);
1122 :
1123 : // All processors with an object should agree on id
1124 : #ifndef NDEBUG
1125 903432 : const dof_id_type dofid = obj && obj->valid_id() ?
1126 : obj->id() : DofObject::invalid_id;
1127 903432 : libmesh_assert(this->comm().semiverify(obj ? &dofid : nullptr));
1128 : #endif
1129 :
1130 : // All processors with an object should agree on processor id
1131 903432 : const dof_id_type procid = obj && obj->valid_processor_id() ?
1132 : obj->processor_id() : DofObject::invalid_processor_id;
1133 903432 : libmesh_assert(this->comm().semiverify(obj ? &procid : nullptr));
1134 :
1135 903432 : dof_id_type min_procid = procid;
1136 903432 : this->comm().min(min_procid);
1137 :
1138 : // Either:
1139 : // 1.) I own this elem (min_procid == this->processor_id()) *and* I have a valid pointer to it (obj != nullptr)
1140 : // or
1141 : // 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.)
1142 :
1143 : // Original assert logic
1144 : // libmesh_assert (min_procid != this->processor_id() || obj);
1145 :
1146 : // More human-understandable logic...
1147 903432 : libmesh_assert (
1148 : ((min_procid == this->processor_id()) && obj)
1149 : ||
1150 : (min_procid != this->processor_id())
1151 : );
1152 :
1153 : #if defined(LIBMESH_ENABLE_UNIQUE_ID) && !defined(NDEBUG)
1154 : // All processors with an object should agree on unique id
1155 903432 : const unique_id_type uniqueid = obj ? obj->unique_id() : 0;
1156 903432 : libmesh_assert(this->comm().semiverify(obj ? &uniqueid : nullptr));
1157 : #endif
1158 : }
1159 3300 : }
1160 :
1161 :
1162 :
1163 1650 : void DistributedMesh::libmesh_assert_valid_parallel_ids () const
1164 : {
1165 1650 : this->libmesh_assert_valid_parallel_object_ids (this->_elements);
1166 1650 : this->libmesh_assert_valid_parallel_object_ids (this->_nodes);
1167 1650 : }
1168 :
1169 :
1170 :
1171 394 : void DistributedMesh::libmesh_assert_valid_parallel_p_levels () const
1172 : {
1173 : #ifndef NDEBUG
1174 : // This function must be run on all processors at once
1175 394 : parallel_object_only();
1176 :
1177 394 : dof_id_type pmax_elem_id = this->parallel_max_elem_id();
1178 :
1179 21872 : for (dof_id_type i=0; i != pmax_elem_id; ++i)
1180 : {
1181 21478 : Elem * el = _elements[i]; // Returns nullptr if there's no map entry
1182 :
1183 21478 : unsigned int p_level = el ? (el->p_level()) : libMesh::invalid_uint;
1184 :
1185 : // All processors with an active element should agree on p level
1186 21478 : libmesh_assert(this->comm().semiverify((el && el->active()) ? &p_level : nullptr));
1187 : }
1188 : #endif
1189 394 : }
1190 :
1191 :
1192 :
1193 :
1194 1598 : void DistributedMesh::libmesh_assert_valid_parallel_flags () const
1195 : {
1196 : #if defined(LIBMESH_ENABLE_AMR) && !defined(NDEBUG)
1197 : // This function must be run on all processors at once
1198 1598 : parallel_object_only();
1199 :
1200 1598 : dof_id_type pmax_elem_id = this->parallel_max_elem_id();
1201 :
1202 148394 : for (dof_id_type i=0; i != pmax_elem_id; ++i)
1203 : {
1204 146796 : Elem * el = _elements[i]; // Returns nullptr if there's no map entry
1205 :
1206 146796 : unsigned int refinement_flag = el ?
1207 65517 : static_cast<unsigned int> (el->refinement_flag()) : libMesh::invalid_uint;
1208 146796 : unsigned int p_refinement_flag = el ?
1209 65517 : static_cast<unsigned int> (el->p_refinement_flag()) : libMesh::invalid_uint;
1210 :
1211 146796 : libmesh_assert(this->comm().semiverify(el ? &refinement_flag : nullptr));
1212 :
1213 : // p refinement flags aren't always kept correct on inactive
1214 : // ghost elements
1215 146796 : libmesh_assert(this->comm().semiverify((el && el->active()) ? &p_refinement_flag : nullptr));
1216 : }
1217 : #endif // LIBMESH_ENABLE_AMR
1218 1598 : }
1219 :
1220 :
1221 :
1222 : template <typename T>
1223 : dof_id_type
1224 1706118 : DistributedMesh::renumber_dof_objects(dofobject_container<T> & objects)
1225 : {
1226 : // This function must be run on all processors at once
1227 784 : parallel_object_only();
1228 :
1229 : typedef typename dofobject_container<T>::veclike_iterator object_iterator;
1230 :
1231 : // In parallel we may not know what objects other processors have.
1232 : // Start by figuring out how many
1233 784 : dof_id_type unpartitioned_objects = 0;
1234 :
1235 : std::unordered_map<processor_id_type, dof_id_type>
1236 1568 : ghost_objects_from_proc;
1237 :
1238 1706118 : object_iterator it = objects.begin();
1239 784 : object_iterator end = objects.end();
1240 :
1241 109665725 : while (it != end)
1242 : {
1243 107959607 : T * obj = *it;
1244 :
1245 : // Remove any nullptr container entries while we're here.
1246 107959607 : if (!obj)
1247 1437488 : it = objects.erase(it);
1248 : else
1249 : {
1250 106522119 : processor_id_type obj_procid = obj->processor_id();
1251 106522119 : if (obj_procid == DofObject::invalid_processor_id)
1252 42390731 : unpartitioned_objects++;
1253 : else
1254 64131388 : ghost_objects_from_proc[obj_procid]++;
1255 :
1256 : // Finally, increment the iterator
1257 56228 : ++it;
1258 : }
1259 : }
1260 :
1261 1707686 : std::vector<dof_id_type> objects_on_proc(this->n_processors(), 0);
1262 1706902 : auto this_it = ghost_objects_from_proc.find(this->processor_id());
1263 784 : this->comm().allgather
1264 1706601 : ((this_it == ghost_objects_from_proc.end()) ?
1265 483 : dof_id_type(0) : this_it->second, objects_on_proc);
1266 :
1267 : #ifndef NDEBUG
1268 784 : libmesh_assert(this->comm().verify(unpartitioned_objects));
1269 2352 : for (processor_id_type p=0, np=this->n_processors(); p != np; ++p)
1270 1568 : if (ghost_objects_from_proc.count(p))
1271 938 : libmesh_assert_less_equal (ghost_objects_from_proc[p], objects_on_proc[p]);
1272 : else
1273 630 : libmesh_assert_less_equal (0, objects_on_proc[p]);
1274 : #endif
1275 :
1276 : // We'll renumber objects in blocks by processor id
1277 1707686 : std::vector<dof_id_type> first_object_on_proc(this->n_processors());
1278 18104198 : for (processor_id_type i=1, np=this->n_processors(); i != np; ++i)
1279 16401216 : first_object_on_proc[i] = first_object_on_proc[i-1] +
1280 784 : objects_on_proc[i-1];
1281 1706902 : dof_id_type next_id = first_object_on_proc[this->processor_id()];
1282 1706118 : dof_id_type first_free_id =
1283 1707686 : first_object_on_proc[this->n_processors()-1] +
1284 784 : objects_on_proc[this->n_processors()-1] +
1285 : unpartitioned_objects;
1286 :
1287 : // First set new local object ids and build request sets
1288 : // for non-local object ids
1289 :
1290 : // Request sets to send to each processor
1291 : std::map<processor_id_type, std::vector<dof_id_type>>
1292 784 : requested_ids;
1293 :
1294 : // We know how many objects live on each processor, so reserve() space for
1295 : // each.
1296 784 : auto ghost_end = ghost_objects_from_proc.end();
1297 19810316 : for (auto p : make_range(this->n_processors()))
1298 18105766 : if (p != this->processor_id())
1299 : {
1300 16398864 : if (const auto p_it = ghost_objects_from_proc.find(p);
1301 784 : p_it != ghost_end)
1302 3283527 : requested_ids[p].reserve(p_it->second);
1303 : }
1304 :
1305 784 : end = objects.end();
1306 108228237 : for (it = objects.begin(); it != end; ++it)
1307 : {
1308 106522119 : T * obj = *it;
1309 106522119 : if (!obj)
1310 0 : continue;
1311 106578347 : if (obj->processor_id() == this->processor_id())
1312 19759196 : obj->set_id(next_id++);
1313 86762923 : else if (obj->processor_id() != DofObject::invalid_processor_id)
1314 44372192 : requested_ids[obj->processor_id()].push_back(obj->id());
1315 : }
1316 :
1317 : // Next set ghost object ids from other processors
1318 :
1319 1723261 : auto gather_functor =
1320 47622343 : [
1321 : #ifndef NDEBUG
1322 : this,
1323 : &first_object_on_proc,
1324 : &objects_on_proc,
1325 : #endif
1326 : &objects]
1327 : (processor_id_type, const std::vector<dof_id_type> & ids,
1328 910 : std::vector<dof_id_type> & new_ids)
1329 : {
1330 910 : std::size_t ids_size = ids.size();
1331 3283527 : new_ids.resize(ids_size);
1332 :
1333 47655719 : for (std::size_t i=0; i != ids_size; ++i)
1334 : {
1335 44372192 : T * obj = objects[ids[i]];
1336 16233 : libmesh_assert(obj);
1337 16233 : libmesh_assert_equal_to (obj->processor_id(), this->processor_id());
1338 44388425 : new_ids[i] = obj->id();
1339 :
1340 16233 : libmesh_assert_greater_equal (new_ids[i],
1341 : first_object_on_proc[this->processor_id()]);
1342 16233 : libmesh_assert_less (new_ids[i],
1343 : first_object_on_proc[this->processor_id()] +
1344 : objects_on_proc[this->processor_id()]);
1345 : }
1346 : };
1347 :
1348 1723261 : auto action_functor =
1349 47622343 : [
1350 : #ifndef NDEBUG
1351 : &first_object_on_proc,
1352 : &objects_on_proc,
1353 : #endif
1354 : &objects]
1355 : (processor_id_type libmesh_dbg_var(pid),
1356 : const std::vector<dof_id_type> & ids,
1357 910 : const std::vector<dof_id_type> & data)
1358 : {
1359 : // Copy the id changes we've now been informed of
1360 47655719 : for (auto i : index_range(ids))
1361 : {
1362 44372192 : T * obj = objects[ids[i]];
1363 16233 : libmesh_assert (obj);
1364 16233 : libmesh_assert_equal_to (obj->processor_id(), pid);
1365 16233 : libmesh_assert_greater_equal (data[i],
1366 : first_object_on_proc[pid]);
1367 16233 : libmesh_assert_less (data[i],
1368 : first_object_on_proc[pid] +
1369 : objects_on_proc[pid]);
1370 44388425 : obj->set_id(data[i]);
1371 : }
1372 : };
1373 :
1374 784 : const dof_id_type * ex = nullptr;
1375 : Parallel::pull_parallel_vector_data
1376 1706118 : (this->comm(), requested_ids, gather_functor, action_functor, ex);
1377 :
1378 : #ifdef LIBMESH_ENABLE_UNIQUE_ID
1379 1723261 : auto unique_gather_functor =
1380 47622343 : [
1381 : #ifndef NDEBUG
1382 : this,
1383 : #endif
1384 : &objects]
1385 : (processor_id_type, const std::vector<dof_id_type> & ids,
1386 910 : std::vector<unique_id_type> & data)
1387 : {
1388 910 : std::size_t ids_size = ids.size();
1389 3283527 : data.resize(ids_size);
1390 :
1391 47655719 : for (std::size_t i=0; i != ids_size; ++i)
1392 : {
1393 44372192 : T * obj = objects[ids[i]];
1394 16233 : libmesh_assert(obj);
1395 16233 : libmesh_assert_equal_to (obj->processor_id(), this->processor_id());
1396 88744384 : data[i] = obj->valid_unique_id() ? obj->unique_id() : DofObject::invalid_unique_id;
1397 : }
1398 : };
1399 :
1400 1723261 : auto unique_action_functor =
1401 47622343 : [&objects]
1402 : (processor_id_type libmesh_dbg_var(pid),
1403 : const std::vector<dof_id_type> & ids,
1404 910 : const std::vector<unique_id_type> & data)
1405 : {
1406 47655719 : for (auto i : index_range(ids))
1407 : {
1408 44372192 : T * obj = objects[ids[i]];
1409 16233 : libmesh_assert (obj);
1410 16233 : libmesh_assert_equal_to (obj->processor_id(), pid);
1411 44372192 : if (!obj->valid_unique_id() && data[i] != DofObject::invalid_unique_id)
1412 0 : obj->set_unique_id(data[i]);
1413 : }
1414 : };
1415 :
1416 784 : const unique_id_type * unique_ex = nullptr;
1417 : Parallel::pull_parallel_vector_data
1418 1706118 : (this->comm(), requested_ids, unique_gather_functor,
1419 : unique_action_functor, unique_ex);
1420 : #endif
1421 :
1422 : // Next set unpartitioned object ids
1423 784 : next_id = 0;
1424 19810316 : for (auto i : make_range(this->n_processors()))
1425 18105766 : next_id += objects_on_proc[i];
1426 108228237 : for (it = objects.begin(); it != end; ++it)
1427 : {
1428 106522119 : T * obj = *it;
1429 106522119 : if (!obj)
1430 0 : continue;
1431 106522119 : if (obj->processor_id() == DofObject::invalid_processor_id)
1432 42390731 : obj->set_id(next_id++);
1433 : }
1434 :
1435 : // Finally shuffle around objects so that container indices
1436 : // match ids
1437 1706118 : it = objects.begin();
1438 784 : end = objects.end();
1439 114468041 : while (it != end)
1440 : {
1441 112761923 : T * obj = *it;
1442 112761923 : if (obj) // don't try shuffling already-nullptr entries
1443 : {
1444 112761923 : T * next = objects[obj->id()];
1445 : // If we have to move this object
1446 112761923 : if (next != obj)
1447 : {
1448 : // nullptr out its original position for now
1449 : // (our shuffling may put another object there shortly)
1450 39670898 : *it = nullptr;
1451 :
1452 : // There may already be another object with this id that
1453 : // needs to be moved itself
1454 51000278 : while (next)
1455 : {
1456 : // We shouldn't be trying to give two objects the
1457 : // same id
1458 9326 : libmesh_assert_not_equal_to (next->id(), obj->id());
1459 11329380 : objects[obj->id()] = obj;
1460 9326 : obj = next;
1461 11329380 : next = objects[obj->id()];
1462 : }
1463 39670898 : objects[obj->id()] = obj;
1464 : }
1465 : }
1466 :
1467 : // Remove any container entries that were left as nullptr.
1468 114904 : if (!obj)
1469 0 : it = objects.erase(it);
1470 : else
1471 57452 : ++it;
1472 : }
1473 :
1474 1706902 : return first_free_id;
1475 : }
1476 :
1477 :
1478 854729 : void DistributedMesh::renumber_nodes_and_elements ()
1479 : {
1480 394 : parallel_object_only();
1481 :
1482 : #ifdef DEBUG
1483 : // Make sure our ids and flags are consistent
1484 394 : this->libmesh_assert_valid_parallel_ids();
1485 394 : this->libmesh_assert_valid_parallel_flags();
1486 394 : this->libmesh_assert_valid_parallel_p_levels();
1487 : #endif
1488 :
1489 394 : LOG_SCOPE("renumber_nodes_and_elements()", "DistributedMesh");
1490 :
1491 : // Nodes not connected to any elements, and nullptr node entries
1492 : // in our container, should be deleted. But wait! If we've deleted coarse
1493 : // local elements on some processor, other processors might have ghosted
1494 : // nodes from it that are now no longer connected to any elements on it, but
1495 : // that are connected to their own semilocal elements. We'll have to
1496 : // communicate to ascertain if that's the case.
1497 854729 : this->comm().max(_deleted_coarse_elements);
1498 :
1499 : // What used nodes do we see on our proc?
1500 394 : std::set<dof_id_type> used_nodes;
1501 :
1502 : // What used node info should we send from our proc? Could we take ownership
1503 : // of each node if we needed to?
1504 : std::map<processor_id_type, std::map<dof_id_type, bool>>
1505 394 : used_nodes_on_proc;
1506 :
1507 : // flag the nodes we need
1508 56811522 : for (auto & elem : this->element_ptr_range())
1509 296201218 : for (const Node & node : elem->node_ref_range())
1510 : {
1511 268620687 : const dof_id_type n = node.id();
1512 268476573 : used_nodes.insert(n);
1513 268620687 : if (_deleted_coarse_elements)
1514 : {
1515 3123685 : const processor_id_type p = node.processor_id();
1516 3123969 : if (p != this->processor_id())
1517 : {
1518 2237336 : auto & used_nodes_on_p = used_nodes_on_proc[p];
1519 2237478 : if (elem->processor_id() == this->processor_id())
1520 215584 : used_nodes_on_p[n] = true;
1521 : else
1522 105 : if (!used_nodes_on_p.count(n))
1523 516282 : used_nodes_on_p[n] = false;
1524 : }
1525 : }
1526 853941 : }
1527 :
1528 854729 : if (_deleted_coarse_elements)
1529 : {
1530 : // "unsigned char" == "bool, but MPI::BOOL is iffy to use"
1531 : typedef unsigned char boolish;
1532 : std::map<processor_id_type, std::vector<std::pair<dof_id_type, boolish>>>
1533 28 : used_nodes_on_proc_vecs;
1534 70355 : for (auto & [pid, nodemap] : used_nodes_on_proc)
1535 54485 : used_nodes_on_proc_vecs[pid].assign(nodemap.begin(), nodemap.end());
1536 :
1537 28 : std::map<dof_id_type,processor_id_type> repartitioned_node_pids;
1538 : std::map<processor_id_type, std::set<dof_id_type>>
1539 28 : repartitioned_node_sets_to_push;
1540 :
1541 : auto ids_action_functor =
1542 54459 : [&used_nodes, &repartitioned_node_pids,
1543 : &repartitioned_node_sets_to_push]
1544 : (processor_id_type pid,
1545 112 : const std::vector<std::pair<dof_id_type, boolish>> & ids_and_bools)
1546 : {
1547 580910 : for (auto [n, sender_could_become_owner] : ids_and_bools)
1548 : {
1549 : // If we don't see a use for our own node, but someone
1550 : // else does, better figure out who should own it next.
1551 97 : if (!used_nodes.count(n))
1552 : {
1553 2 : if (auto it = repartitioned_node_pids.find(n);
1554 2 : sender_could_become_owner)
1555 : {
1556 1 : if (it != repartitioned_node_pids.end() &&
1557 1 : pid < it->second)
1558 1 : it->second = pid;
1559 : else
1560 0 : repartitioned_node_pids[n] = pid;
1561 : }
1562 : else
1563 1 : if (it == repartitioned_node_pids.end())
1564 1 : repartitioned_node_pids[n] =
1565 : DofObject::invalid_processor_id;
1566 :
1567 2 : repartitioned_node_sets_to_push[pid].insert(n);
1568 : }
1569 : }
1570 15882 : };
1571 :
1572 : // We need two pushes instead of a pull here because we need to
1573 : // know *all* the queries for a particular node before we can
1574 : // respond to *any* of them.
1575 : Parallel::push_parallel_vector_data
1576 15870 : (this->comm(), used_nodes_on_proc_vecs, ids_action_functor);
1577 :
1578 : // Repartition (what used to be) our own nodes first
1579 15871 : for (auto & [n, p] : repartitioned_node_pids)
1580 : {
1581 1 : Node & node = this->node_ref(n);
1582 0 : libmesh_assert_equal_to(node.processor_id(), this->processor_id());
1583 0 : libmesh_assert_not_equal_to_msg(p, DofObject::invalid_processor_id, "Node " << n << " is lost?");
1584 1 : node.processor_id() = p;
1585 : }
1586 :
1587 : // Then push to repartition others' ghosted copies.
1588 :
1589 : std::map<processor_id_type, std::vector<std::pair<dof_id_type,processor_id_type>>>
1590 28 : repartitioned_node_vecs;
1591 :
1592 15872 : for (auto & [p, nodeset] : repartitioned_node_sets_to_push)
1593 : {
1594 2 : auto & rn_vec = repartitioned_node_vecs[p];
1595 4 : for (auto n : nodeset)
1596 2 : rn_vec.emplace_back(n, repartitioned_node_pids[n]);
1597 : }
1598 :
1599 : auto repartition_node_functor =
1600 2 : [this]
1601 : (processor_id_type libmesh_dbg_var(pid),
1602 2 : const std::vector<std::pair<dof_id_type, processor_id_type>> & ids_and_pids)
1603 : {
1604 4 : for (auto [n, p] : ids_and_pids)
1605 : {
1606 0 : libmesh_assert_not_equal_to(p, DofObject::invalid_processor_id);
1607 2 : Node & node = this->node_ref(n);
1608 0 : libmesh_assert_equal_to(node.processor_id(), pid);
1609 2 : node.processor_id() = p;
1610 : }
1611 15842 : };
1612 :
1613 : Parallel::push_parallel_vector_data
1614 15870 : (this->comm(), repartitioned_node_vecs, repartition_node_functor);
1615 : }
1616 :
1617 854729 : _deleted_coarse_elements = false;
1618 :
1619 : // Nodes not connected to any local elements, and nullptr node entries
1620 : // in our container, are deleted
1621 : {
1622 854729 : node_iterator_imp it = _nodes.begin();
1623 394 : node_iterator_imp end = _nodes.end();
1624 :
1625 86628783 : while (it != end)
1626 : {
1627 85774054 : Node * nd = *it;
1628 85774054 : if (!nd)
1629 3471192 : it = _nodes.erase(it);
1630 82302862 : else if (!used_nodes.count(nd->id()))
1631 : {
1632 : // remove any boundary information associated with
1633 : // this node
1634 2327679 : this->get_boundary_info().remove (nd);
1635 2828 : _constraint_rows.erase(nd);
1636 :
1637 : // delete the node
1638 2327679 : delete nd;
1639 :
1640 2327679 : it = _nodes.erase(it);
1641 : }
1642 : else
1643 45139 : ++it;
1644 : }
1645 : }
1646 :
1647 854729 : this->_preparation.has_removed_orphaned_nodes = true;
1648 :
1649 854729 : if (_skip_renumber_nodes_and_elements)
1650 : {
1651 1670 : this->update_parallel_id_counts();
1652 2 : return;
1653 : }
1654 :
1655 : // Finally renumber all the elements
1656 853059 : _n_elem = this->renumber_dof_objects (this->_elements);
1657 :
1658 : // and all the remaining nodes
1659 853059 : _n_nodes = this->renumber_dof_objects (this->_nodes);
1660 :
1661 : // And figure out what IDs we should use when adding new nodes and
1662 : // new elements
1663 853059 : this->update_parallel_id_counts();
1664 :
1665 : // Make sure our caches are up to date and our
1666 : // DofObjects are well packed
1667 : #ifdef DEBUG
1668 392 : libmesh_assert_equal_to (this->n_nodes(), this->parallel_n_nodes());
1669 392 : libmesh_assert_equal_to (this->n_elem(), this->parallel_n_elem());
1670 392 : const dof_id_type pmax_node_id = this->parallel_max_node_id();
1671 392 : const dof_id_type pmax_elem_id = this->parallel_max_elem_id();
1672 392 : libmesh_assert_equal_to (this->max_node_id(), pmax_node_id);
1673 392 : libmesh_assert_equal_to (this->max_elem_id(), pmax_elem_id);
1674 392 : libmesh_assert_equal_to (this->n_nodes(), this->max_node_id());
1675 392 : libmesh_assert_equal_to (this->n_elem(), this->max_elem_id());
1676 :
1677 : // Make sure our ids and flags are consistent
1678 392 : this->libmesh_assert_valid_parallel_ids();
1679 392 : this->libmesh_assert_valid_parallel_flags();
1680 :
1681 : // And make sure we've made our numbering monotonic
1682 392 : MeshTools::libmesh_assert_valid_elem_ids(*this);
1683 : #endif
1684 : }
1685 :
1686 :
1687 :
1688 17410 : void DistributedMesh::fix_broken_node_and_element_numbering ()
1689 : {
1690 : // We can't use range-for here because we need access to the special
1691 : // iterators' methods, not just to their dereferenced values.
1692 :
1693 : // Nodes first
1694 0 : for (auto pr = this->_nodes.begin(),
1695 5444770 : end = this->_nodes.end(); pr != end; ++pr)
1696 : {
1697 5427360 : Node * n = *pr;
1698 5427360 : if (n != nullptr)
1699 : {
1700 0 : const dof_id_type id = pr.index();
1701 5204550 : n->set_id() = id;
1702 0 : libmesh_assert_equal_to(this->node_ptr(id), n);
1703 : }
1704 : }
1705 :
1706 : // Elements next
1707 0 : for (auto pr = this->_elements.begin(),
1708 5671231 : end = this->_elements.end(); pr != end; ++pr)
1709 : {
1710 5653821 : Elem * e = *pr;
1711 5653821 : if (e != nullptr)
1712 : {
1713 0 : const dof_id_type id = pr.index();
1714 5590229 : e->set_id() = id;
1715 0 : libmesh_assert_equal_to(this->elem_ptr(id), e);
1716 : }
1717 : }
1718 17410 : }
1719 :
1720 :
1721 :
1722 632987 : dof_id_type DistributedMesh::n_active_elem () const
1723 : {
1724 540 : parallel_object_only();
1725 :
1726 : // Get local active elements first
1727 : dof_id_type active_elements =
1728 1265434 : static_cast<dof_id_type>(std::distance (this->active_local_elements_begin(),
1729 1897881 : this->active_local_elements_end()));
1730 632987 : this->comm().sum(active_elements);
1731 :
1732 : // Then add unpartitioned active elements, which should exist on
1733 : // every processor
1734 632987 : active_elements +=
1735 632987 : static_cast<dof_id_type>(std::distance
1736 1265434 : (this->active_pid_elements_begin(DofObject::invalid_processor_id),
1737 633527 : this->active_pid_elements_end(DofObject::invalid_processor_id)));
1738 632987 : return active_elements;
1739 : }
1740 :
1741 :
1742 :
1743 403756 : void DistributedMesh::delete_remote_elements()
1744 : {
1745 : #ifdef DEBUG
1746 : // Make sure our neighbor links are all fine
1747 382 : MeshTools::libmesh_assert_valid_neighbors(*this);
1748 :
1749 : // And our child/parent links, and our flags
1750 382 : MeshTools::libmesh_assert_valid_refinement_tree(*this);
1751 :
1752 : // Make sure our ids and flags are consistent
1753 382 : this->libmesh_assert_valid_parallel_ids();
1754 382 : this->libmesh_assert_valid_parallel_flags();
1755 :
1756 382 : libmesh_assert_equal_to (this->n_nodes(), this->parallel_n_nodes());
1757 382 : libmesh_assert_equal_to (this->n_elem(), this->parallel_n_elem());
1758 382 : const dof_id_type pmax_node_id = this->parallel_max_node_id();
1759 382 : const dof_id_type pmax_elem_id = this->parallel_max_elem_id();
1760 382 : libmesh_assert_equal_to (this->max_node_id(), pmax_node_id);
1761 382 : libmesh_assert_equal_to (this->max_elem_id(), pmax_elem_id);
1762 : #endif
1763 :
1764 403756 : _is_serial = false;
1765 403756 : _is_serial_on_proc_0 = false;
1766 :
1767 403756 : MeshCommunication().delete_remote_elements(*this, _extra_ghost_elems);
1768 :
1769 382 : libmesh_assert_equal_to (this->max_elem_id(), this->parallel_max_elem_id());
1770 :
1771 : // Now make sure the containers actually shrink - strip
1772 : // any newly-created nullptr voids out of the element array
1773 403756 : dofobject_container<Elem>::veclike_iterator e_it = _elements.begin();
1774 382 : const dofobject_container<Elem>::veclike_iterator e_end = _elements.end();
1775 53523786 : while (e_it != e_end)
1776 53120030 : if (!*e_it)
1777 39590070 : e_it = _elements.erase(e_it);
1778 : else
1779 17361 : ++e_it;
1780 :
1781 403756 : dofobject_container<Node>::veclike_iterator n_it = _nodes.begin();
1782 382 : const dofobject_container<Node>::veclike_iterator n_end = _nodes.end();
1783 100190784 : while (n_it != n_end)
1784 99787028 : if (!*n_it)
1785 66635675 : n_it = _nodes.erase(n_it);
1786 : else
1787 48503 : ++n_it;
1788 :
1789 : // We may have deleted no-longer-connected nodes or coarsened-away
1790 : // elements; let's update our caches.
1791 403756 : this->update_parallel_id_counts();
1792 :
1793 : // We may have deleted nodes or elements that were the only local
1794 : // representatives of some particular boundary id(s); let's update
1795 : // those caches.
1796 403756 : this->get_boundary_info().regenerate_id_sets();
1797 :
1798 : #ifdef DEBUG
1799 : // We might not have well-packed objects if the user didn't allow us
1800 : // to renumber
1801 : // libmesh_assert_equal_to (this->n_nodes(), this->max_node_id());
1802 : // libmesh_assert_equal_to (this->n_elem(), this->max_elem_id());
1803 :
1804 : // Make sure our neighbor links are all fine
1805 382 : MeshTools::libmesh_assert_valid_neighbors(*this);
1806 :
1807 : // And our child/parent links, and our flags
1808 382 : MeshTools::libmesh_assert_valid_refinement_tree(*this);
1809 :
1810 : // Make sure our ids and flags are consistent
1811 382 : this->libmesh_assert_valid_parallel_ids();
1812 382 : this->libmesh_assert_valid_parallel_flags();
1813 : #endif
1814 :
1815 403756 : this->_preparation.has_removed_remote_elements = true;
1816 403756 : }
1817 :
1818 :
1819 0 : void DistributedMesh::add_extra_ghost_elem(Elem * e)
1820 : {
1821 : // First add the elem like normal
1822 0 : add_elem(e);
1823 :
1824 : // Now add it to the set that won't be deleted when we call
1825 : // delete_remote_elements()
1826 0 : _extra_ghost_elems.insert(e);
1827 0 : }
1828 :
1829 : void
1830 0 : DistributedMesh::clear_extra_ghost_elems(const std::set<Elem *> & extra_ghost_elems)
1831 : {
1832 0 : std::set<Elem *> tmp;
1833 0 : std::set_difference(_extra_ghost_elems.begin(), _extra_ghost_elems.end(),
1834 : extra_ghost_elems.begin(), extra_ghost_elems.end(),
1835 0 : std::inserter(tmp, tmp.begin()));
1836 0 : _extra_ghost_elems = tmp;
1837 0 : }
1838 :
1839 96956 : void DistributedMesh::allgather()
1840 : {
1841 96956 : if (_is_serial)
1842 0 : return;
1843 96954 : MeshCommunication().allgather(*this);
1844 96954 : _is_serial = true;
1845 96954 : _is_serial_on_proc_0 = true;
1846 :
1847 : // Make sure our caches are up to date and our
1848 : // DofObjects are well packed
1849 : #ifdef DEBUG
1850 48 : libmesh_assert_equal_to (this->n_nodes(), this->parallel_n_nodes());
1851 48 : libmesh_assert_equal_to (this->n_elem(), this->parallel_n_elem());
1852 48 : const dof_id_type pmax_node_id = this->parallel_max_node_id();
1853 48 : const dof_id_type pmax_elem_id = this->parallel_max_elem_id();
1854 48 : libmesh_assert_equal_to (this->max_node_id(), pmax_node_id);
1855 48 : libmesh_assert_equal_to (this->max_elem_id(), pmax_elem_id);
1856 :
1857 : // If we've disabled renumbering we can't be sure we're contiguous
1858 : // libmesh_assert_equal_to (this->n_nodes(), this->max_node_id());
1859 : // libmesh_assert_equal_to (this->n_elem(), this->max_elem_id());
1860 :
1861 : // Make sure our neighbor links are all fine
1862 48 : MeshTools::libmesh_assert_valid_neighbors(*this);
1863 :
1864 : // Make sure our ids and flags are consistent
1865 48 : this->libmesh_assert_valid_parallel_ids();
1866 48 : this->libmesh_assert_valid_parallel_flags();
1867 : #endif
1868 : }
1869 :
1870 18096 : void DistributedMesh::gather_to_zero()
1871 : {
1872 18096 : if (_is_serial_on_proc_0)
1873 4 : return;
1874 :
1875 13858 : _is_serial_on_proc_0 = true;
1876 13858 : MeshCommunication().gather(0, *this);
1877 : }
1878 :
1879 :
1880 : } // namespace libMesh
|