libMesh
Loading...
Searching...
No Matches
parallel_elem.C
Go to the documentation of this file.
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// C++ includes
21
22// Local includes
23#include "libmesh/boundary_info.h"
24#include "libmesh/cell_c0polyhedron.h"
25#include "libmesh/distributed_mesh.h"
26#include "libmesh/elem.h"
27#include "libmesh/face_c0polygon.h"
28#include "libmesh/int_range.h"
29#include "libmesh/mesh_base.h"
30#include "libmesh/parallel_elem.h"
31#include "libmesh/parallel_mesh.h"
32#include "libmesh/remote_elem.h"
33
34// Helper functions in anonymous namespace
35
36namespace
37{
38using namespace libMesh;
39
40#ifdef LIBMESH_ENABLE_UNIQUE_ID
41static const unsigned int header_size = 12;
42#else
43static const unsigned int header_size = 11;
44#endif
45
46#ifndef NDEBUG
47// Currently this constant is only used for debugging.
48static const largest_id_type elem_magic_header = 987654321;
49#endif
50}
51
52
53namespace libMesh
54{
55
56namespace Parallel
57{
58
59template <>
60unsigned int
61Packing<const Elem *>::packed_size (std::vector<largest_id_type>::const_iterator in)
62{
63#ifndef NDEBUG
64 const largest_id_type packed_header = *in++;
65 libmesh_assert_equal_to (packed_header, elem_magic_header);
66#endif
67
68 // int 0: level
69 const unsigned int level =
70 cast_int<unsigned int>(*in);
71
72 // int 4: element type
73 const int typeint = cast_int<int>(*(in+4));
74 libmesh_assert_greater_equal (typeint, 0);
75 libmesh_assert_less (typeint, INVALID_ELEM);
76 const ElemType type =
77 cast_int<ElemType>(typeint);
78
79 unsigned int n_nodes = Elem::type_to_n_nodes_map[type];
80 unsigned int n_sides = Elem::type_to_n_sides_map[type];
81 unsigned int n_edges = Elem::type_to_n_edges_map[type];
82 unsigned int variable_topology_size = 0;
83 // No Elem exists yet, so use the static-count sentinel corresponding
84 // to Elem::runtime_topology() in type_to_n_nodes_map.
85 const bool has_runtime_topology = (n_nodes == invalid_uint);
86
87 if (has_runtime_topology)
88 {
89 auto topology_in = in + header_size;
90 n_nodes = cast_int<unsigned int>(*topology_in++);
91 n_sides = cast_int<unsigned int>(*topology_in++);
92 n_edges = cast_int<unsigned int>(*topology_in++);
93 variable_topology_size = 3;
94
95 if (Elem::type_to_dim_map[type] == 3)
96 {
97 topology_in += n_nodes;
98 for (unsigned int s = 0; s != n_sides; ++s)
99 {
100 const unsigned int n_side_nodes =
101 cast_int<unsigned int>(*topology_in++);
102 topology_in += n_side_nodes;
103 variable_topology_size += n_side_nodes + 1;
104 }
105 }
106 }
107
108 const unsigned int pre_indexing_size =
109 header_size + variable_topology_size + n_nodes + n_sides*2;
110
111 const unsigned int indexing_size =
112 DofObject::unpackable_indexing_size(in+pre_indexing_size);
113
114 // We communicate if we are on the boundary or not
115 unsigned int total_packed_bc_data = 1;
116 largest_id_type on_boundary = *(in + pre_indexing_size + indexing_size);
117
118 if (on_boundary)
119 {
120 // Extracting if the children are allowed on the boundary
121 total_packed_bc_data++;
122 largest_id_type allow_children_on_boundary = *(in + pre_indexing_size + indexing_size + 1);
123
124 // For now, children are only supported on sides, the nodes and shell faces are
125 // treated using the top parents only
126 if (level == 0 || allow_children_on_boundary)
127 {
128 for (unsigned int s = 0; s != n_sides; ++s)
129 {
130 const int n_bcs = cast_int<int>
131 (*(in + pre_indexing_size + indexing_size +
132 total_packed_bc_data++));
133 libmesh_assert_greater_equal (n_bcs, 0);
134 total_packed_bc_data += n_bcs;
135 }
136 }
137 }
138 if (level == 0)
139 {
140 for (unsigned int e = 0; e != n_edges; ++e)
141 {
142 const int n_bcs = cast_int<int>
143 (*(in + pre_indexing_size + indexing_size +
144 total_packed_bc_data++));
145 libmesh_assert_greater_equal (n_bcs, 0);
146 total_packed_bc_data += n_bcs;
147 }
148
149 for (unsigned short sf=0; sf != 2; ++sf)
150 {
151 const int n_bcs = cast_int<int>
152 (*(in + pre_indexing_size + indexing_size +
153 total_packed_bc_data++));
154 libmesh_assert_greater_equal (n_bcs, 0);
155 total_packed_bc_data += n_bcs;
156 }
157 }
158
159 return
160#ifndef NDEBUG
161 1 + // Account for magic header
162#endif
163 pre_indexing_size + indexing_size + total_packed_bc_data;
164}
165
166
167
168template <>
169unsigned int
170Packing<const Elem *>::packed_size (std::vector<largest_id_type>::iterator in)
171{
172 return packed_size(std::vector<largest_id_type>::const_iterator(in));
173}
174
175
176
177template <>
178unsigned int
179Packing<const Elem *>::packable_size (const Elem * const & elem,
180 const MeshBase * mesh)
181{
182 unsigned int variable_topology_size = 0;
183 if (elem->runtime_topology())
184 {
185 // Store the dynamic node, side, and edge counts.
186 variable_topology_size = 3;
187
188 // A polygon's node ordering fully specifies its topology. A
189 // polyhedron additionally needs each side's local node indices.
190 if (elem->dim() == 3)
191 for (auto s : elem->side_index_range())
192 variable_topology_size +=
193 1 + cast_int<unsigned int>(elem->nodes_on_side(s).size());
194 }
195
196 // We always communicate if we are on a boundary or not
197 unsigned int total_packed_bcs = 1;
198 const unsigned int n_sides = elem->n_sides();
199
200 largest_id_type on_boundary = 0;
201 for (auto s : elem->side_index_range())
202 if (mesh->get_boundary_info().n_raw_boundary_ids(elem,s))
203 {
204 on_boundary = 1;
205 break;
206 }
207
208 if (on_boundary)
209 {
210 // In this case we need another entry to check if we allow children on the boundary.
211 // We only allow children on sides, edges and sheel faces are treated normally using
212 // their top parents.
213 total_packed_bcs++;
215 {
216 total_packed_bcs += n_sides;
217 for (unsigned int s = 0; s != n_sides; ++s)
218 total_packed_bcs +=
220 }
221 }
222
223 if (elem->level() == 0)
224 {
225 const unsigned int n_edges = elem->n_edges();
226 total_packed_bcs += n_edges;
227 for (unsigned int e = 0; e != n_edges; ++e)
228 total_packed_bcs +=
230
231 total_packed_bcs += 2; // shellfaces
232 for (unsigned short sf=0; sf != 2; ++sf)
233 total_packed_bcs +=
235 }
236
237 return
238#ifndef NDEBUG
239 1 + // add an int for the magic header when testing
240#endif
241 header_size + variable_topology_size + elem->n_nodes() + n_sides*2 +
242 elem->packed_indexing_size() + total_packed_bcs;
243}
244
245
246
247template <>
248unsigned int
249Packing<const Elem *>::packable_size (const Elem * const & elem,
250 const DistributedMesh * mesh)
251{
252 return packable_size(elem, static_cast<const MeshBase *>(mesh));
253}
254
255
256
257template <>
258unsigned int
259Packing<const Elem *>::packable_size (const Elem * const & elem,
260 const ParallelMesh * mesh)
261{
262 return packable_size(elem, static_cast<const MeshBase *>(mesh));
263}
264
265
266
267template <>
268void
269Packing<const Elem *>::pack (const Elem * const & elem,
270 std::back_insert_iterator<std::vector<largest_id_type>> data_out,
271 const MeshBase * mesh)
272{
273 libmesh_assert(elem);
274
275#ifndef NDEBUG
276 *data_out++ = elem_magic_header;
277#endif
278
279#ifdef LIBMESH_ENABLE_AMR
280 *data_out++ = (static_cast<largest_id_type>(elem->level()));
281 *data_out++ = (static_cast<largest_id_type>(elem->p_level()));
282
283 // Encode both the refinement flag and whether the element has
284 // children together. This coding is unambiguous because our
285 // refinement state encoding starts at 0 and ends at
286 // INVALID_REFINEMENTSTATE
287 largest_id_type refinement_info =
288 static_cast<largest_id_type>(elem->refinement_flag());
289 if (elem->has_children())
290 refinement_info +=
292 *data_out++ = (refinement_info);
293
294 *data_out++ = (static_cast<largest_id_type>(elem->p_refinement_flag()));
295#else
296 *data_out++ = (0);
297 *data_out++ = (0);
298 *data_out++ = (0);
299 *data_out++ = (0);
300#endif
301 *data_out++ = (static_cast<largest_id_type>(elem->type()));
302 *data_out++ = (elem->processor_id());
303 *data_out++ = (elem->subdomain_id());
304 *data_out++ = (elem->id());
305
306#ifdef LIBMESH_ENABLE_UNIQUE_ID
307 if (elem->valid_unique_id())
308 *data_out++ = (static_cast<largest_id_type>(elem->unique_id()));
309 else
310 // OK to send invalid unique id, we must not own this DOF
311 *data_out++ = (static_cast<largest_id_type>(DofObject::invalid_unique_id));
312#endif
313
314#ifdef LIBMESH_ENABLE_AMR
315 // use parent_ID of invalid_id to indicate a level 0 element
316 if (elem->level() == 0)
317 {
318 *data_out++ =(DofObject::invalid_id);
319 *data_out++ =(DofObject::invalid_id);
320 }
321 else
322 {
323 *data_out++ =(elem->parent()->id());
324 *data_out++ =(elem->parent()->which_child_am_i(elem));
325 }
326#else
327 *data_out++ = (DofObject::invalid_id);
328 *data_out++ = (DofObject::invalid_id);
329#endif
330
331 if ((elem->dim() < LIBMESH_DIM) &&
332 elem->interior_parent())
333 *data_out++ =(elem->interior_parent()->id());
334 else
335 *data_out++ =(DofObject::invalid_id);
336
337 const bool has_variable_topology = elem->runtime_topology();
338 if (has_variable_topology)
339 {
340 *data_out++ = elem->n_nodes();
341 *data_out++ = elem->n_sides();
342 *data_out++ = elem->n_edges();
343 }
344
345 for (const Node & node : elem->node_ref_range())
346 *data_out++ = node.id();
347
348 if (has_variable_topology && elem->dim() == 3) // AKA, is c0polyhedron
349 for (auto s : elem->side_index_range())
350 {
351 const std::vector<unsigned int> side_nodes =
352 elem->nodes_on_side(s);
353 *data_out++ = side_nodes.size();
354 for (const auto node : side_nodes)
355 *data_out++ = node;
356 }
357
358 // Add the id of and the side for any return link from each neighbor
359 for (auto neigh : elem->neighbor_ptr_range())
360 {
361 if (neigh)
362 {
363 *data_out++ = (neigh->id());
364 if (neigh == remote_elem)
365 *data_out++ = (DofObject::invalid_id);
366 else
367 *data_out++ = neigh->which_neighbor_am_i(elem);
368 }
369 else
370 {
371 *data_out++ = (DofObject::invalid_id);
372 *data_out++ = (DofObject::invalid_id);
373 }
374 }
375
376 // Add any DofObject indices
377 elem->pack_indexing(data_out);
378
379 // We check if this is a boundary cell. We use the raw
380 // IDs because we also communicate the parents which
381 // will bring their associated IDs
382 largest_id_type on_boundary = 0;
383 for (auto s : elem->side_index_range())
384 if (mesh->get_boundary_info().n_raw_boundary_ids(elem,s))
385 {
386 on_boundary = 1;
387 break;
388 }
389
390 *data_out++ = on_boundary;
391
392 if (on_boundary)
393 {
395 // Again, only do this if we allow children to hold boundary sides, the edges and
396 // shell faces are treated normally using their top parents
398 {
399 std::vector<boundary_id_type> bcs;
400 for (auto s : elem->side_index_range())
401 {
402 mesh->get_boundary_info().raw_boundary_ids(elem, s, bcs);
403
404 *data_out++ =(bcs.size());
405
406 for (const auto & bid : bcs)
407 *data_out++ = bid;
408 }
409 }
410 }
411
412 // If this is a coarse element,
413 // Add any element side boundary condition ids
414 if (elem->level() == 0)
415 {
416 std::vector<boundary_id_type> bcs;
417 for (auto e : elem->edge_index_range())
418 {
420
421 *data_out++ =(bcs.size());
422
423 for (const auto & bid : bcs)
424 *data_out++ = bid;
425 }
426
427 for (unsigned short sf=0; sf != 2; ++sf)
428 {
430
431 *data_out++ =(bcs.size());
432
433 for (const auto & bid : bcs)
434 *data_out++ = bid;
435 }
436 }
437}
438
439
440
441template <>
442void
443Packing<const Elem *>::pack (const Elem * const & elem,
444 std::back_insert_iterator<std::vector<largest_id_type>> data_out,
445 const DistributedMesh * mesh)
446{
447 pack(elem, data_out, static_cast<const MeshBase*>(mesh));
448}
449
450
451
452template <>
453void
454Packing<const Elem *>::pack (const Elem * const & elem,
455 std::back_insert_iterator<std::vector<largest_id_type>> data_out,
456 const ParallelMesh * mesh)
457{
458 pack(elem, data_out, static_cast<const MeshBase*>(mesh));
459}
460
461
462
463// FIXME - this needs serious work to be 64-bit compatible
464template <>
465Elem *
466Packing<Elem *>::unpack (std::vector<largest_id_type>::const_iterator in,
467 MeshBase * mesh)
468{
469#ifndef NDEBUG
470 const std::vector<largest_id_type>::const_iterator original_in = in;
471
472 const largest_id_type incoming_header = *in++;
473 libmesh_assert_equal_to (incoming_header, elem_magic_header);
474#endif
475
476 // int 0: level
477 const unsigned int level =
478 cast_int<unsigned int>(*in++);
479
480#ifdef LIBMESH_ENABLE_AMR
481 // int 1: p level
482 const unsigned int p_level =
483 cast_int<unsigned int>(*in++);
484
485 // int 2: refinement flag and encoded has_children
486 const int rflag = cast_int<int>(*in++);
487 const int invalid_rflag =
488 cast_int<int>(Elem::INVALID_REFINEMENTSTATE);
489 libmesh_assert_greater_equal (rflag, 0);
490
491 libmesh_assert_less (rflag, invalid_rflag*2+1);
492
493 const bool has_children = (rflag > invalid_rflag);
494
495 const Elem::RefinementState refinement_flag = has_children ?
496 cast_int<Elem::RefinementState>(rflag - invalid_rflag - 1) :
497 cast_int<Elem::RefinementState>(rflag);
498
499 // int 3: p refinement flag
500 const int pflag = cast_int<int>(*in++);
501 libmesh_assert_greater_equal (pflag, 0);
502 libmesh_assert_less (pflag, Elem::INVALID_REFINEMENTSTATE);
503 const Elem::RefinementState p_refinement_flag =
504 cast_int<Elem::RefinementState>(pflag);
505#else
506 in += 3;
507#endif // LIBMESH_ENABLE_AMR
508
509 // int 4: element type
510 const int typeint = cast_int<int>(*in++);
511 libmesh_assert_greater_equal (typeint, 0);
512 libmesh_assert_less (typeint, INVALID_ELEM);
513 const ElemType type =
514 cast_int<ElemType>(typeint);
515
516 unsigned int n_nodes = Elem::type_to_n_nodes_map[type];
517 unsigned int n_sides = Elem::type_to_n_sides_map[type];
518 unsigned int n_edges = Elem::type_to_n_edges_map[type];
519 // No Elem exists yet, so use the static-count sentinel corresponding
520 // to Elem::runtime_topology().
521 const bool has_runtime_topology = (n_nodes == invalid_uint);
522
523 // int 5: processor id
524 const processor_id_type processor_id =
525 cast_int<processor_id_type>(*in++);
526 libmesh_assert (processor_id < mesh->n_processors() ||
527 processor_id == DofObject::invalid_processor_id);
528
529 // int 6: subdomain id
530 const subdomain_id_type subdomain_id =
531 cast_int<subdomain_id_type>(*in++);
532
533 // int 7: dof object id
534 const dof_id_type id =
535 cast_int<dof_id_type>(*in++);
536 libmesh_assert_not_equal_to (id, DofObject::invalid_id);
537
538#ifdef LIBMESH_ENABLE_UNIQUE_ID
539 // int 8: dof object unique id
540 const unique_id_type unique_id =
541 cast_int<unique_id_type>(*in++);
542#endif
543
544#ifdef LIBMESH_ENABLE_AMR
545 // int 9: parent dof object id.
546 // Note: If level==0, then (*in) == invalid_id. In
547 // this case, the equality check in cast_int<unsigned>(*in) will
548 // never succeed. Therefore, we should only attempt the more
549 // rigorous cast verification in cases where level != 0.
550 const dof_id_type parent_id =
551 (level == 0)
552 ? static_cast<dof_id_type>(*in++)
553 : cast_int<dof_id_type>(*in++);
554 libmesh_assert (level == 0 || parent_id != DofObject::invalid_id);
555 libmesh_assert (level != 0 || parent_id == DofObject::invalid_id);
556
557 // int 10: local child id
558 // Note: If level==0, then which_child_am_i is not valid, so don't
559 // do the more rigorous cast verification.
560 const unsigned int which_child_am_i =
561 (level == 0)
562 ? static_cast<unsigned int>(*in++)
563 : cast_int<unsigned int>(*in++);
564#else
565 in += 2;
566#endif // LIBMESH_ENABLE_AMR
567
568 const dof_id_type interior_parent_id =
569 static_cast<dof_id_type>(*in++);
570
571 // Make sure we don't miscount above when adding the "magic" header
572 // plus the real data header
573 libmesh_assert_equal_to (in - original_in, header_size + 1);
574
575 if (has_runtime_topology)
576 {
577 n_nodes = cast_int<unsigned int>(*in++);
578 n_sides = cast_int<unsigned int>(*in++);
579 n_edges = cast_int<unsigned int>(*in++);
580
581 if (Elem::type_to_dim_map[type] == 2)
582 {
583 libmesh_assert_less (2, n_sides);
584 libmesh_assert_equal_to (n_nodes % n_sides, 0);
585 libmesh_assert_equal_to (n_edges, n_sides);
586 }
587 else if (Elem::type_to_dim_map[type] == 3)
588 {
589 libmesh_assert_less (3, n_nodes);
590 libmesh_assert_less (3, n_sides);
591 }
592 }
593 libmesh_ignore(n_edges); // unused outside dbg/devel
594
595 const auto node_ids_in = in;
596 in += n_nodes;
597
598 std::vector<std::vector<unsigned int>> polyhedron_side_nodes;
599 if (has_runtime_topology && Elem::type_to_dim_map[type] == 3)
600 {
601 polyhedron_side_nodes.resize(n_sides);
602#ifndef NDEBUG
603 std::vector<bool> node_seen(n_nodes, false);
604 unsigned int next_new_node = 0;
605#endif
606 for (auto & side_nodes : polyhedron_side_nodes)
607 {
608 const unsigned int n_side_nodes =
609 cast_int<unsigned int>(*in++);
610 libmesh_assert_less (2, n_side_nodes);
611 side_nodes.resize(n_side_nodes);
612 for (auto & node : side_nodes)
613 {
614 node = cast_int<unsigned int>(*in++);
615 libmesh_assert_less (node, n_nodes);
616
617#ifndef NDEBUG
618 if (type == C0POLYHEDRON && !node_seen[node])
619 {
620 libmesh_assert_equal_to (node, next_new_node);
621 node_seen[node] = true;
622 ++next_new_node;
623 }
624#endif
625 }
626 }
627
628#ifndef NDEBUG
629 if (type == C0POLYHEDRON)
630 libmesh_assert (next_new_node == n_nodes ||
631 next_new_node + 1 == n_nodes);
632#endif
633 }
634
635 Elem * elem = mesh->query_elem_ptr(id);
636
637 // if we already have this element, make sure its
638 // properties match, and update any missing neighbor
639 // links, but then go on
640 if (elem)
641 {
642 libmesh_assert_equal_to (elem->level(), level);
643 libmesh_assert_equal_to (elem->id(), id);
644 //#ifdef LIBMESH_ENABLE_UNIQUE_ID
645 // No check for unique id sanity
646 //#endif
647 libmesh_assert_equal_to (elem->processor_id(), processor_id);
648 libmesh_assert_equal_to (elem->subdomain_id(), subdomain_id);
649 libmesh_assert_equal_to (elem->type(), type);
650 libmesh_assert_equal_to (elem->n_nodes(), n_nodes);
651 libmesh_assert_equal_to (elem->n_sides(), n_sides);
652 libmesh_assert_equal_to (elem->n_edges(), n_edges);
653
654#ifndef NDEBUG
655 if (elem->runtime_topology() && elem->dim() == 3)
656 for (auto s : elem->side_index_range())
657 libmesh_assert(elem->nodes_on_side(s) ==
658 polyhedron_side_nodes[s]);
659#endif
660
661#ifndef NDEBUG
662 // All our nodes should be correct
663 for (unsigned int i=0; i != n_nodes; ++i)
664 libmesh_assert_equal_to
665 (elem->node_id(i),
666 cast_int<dof_id_type>(*(node_ids_in + i)));
667#endif
668
669#ifdef LIBMESH_ENABLE_AMR
670 libmesh_assert_equal_to (elem->refinement_flag(), refinement_flag);
671 libmesh_assert_equal_to (elem->has_children(), has_children);
672
673#ifdef DEBUG
674 if (elem->active())
675 {
676 libmesh_assert_equal_to (elem->p_level(), p_level);
677 libmesh_assert_equal_to (elem->p_refinement_flag(), p_refinement_flag);
678 }
679#endif
680
681 libmesh_assert (!level || elem->parent() != nullptr);
682 libmesh_assert (!level || elem->parent()->id() == parent_id);
683 libmesh_assert (!level || elem->parent()->child_ptr(which_child_am_i) == elem);
684#endif
685 // Our interior_parent link should be "close to" correct - we
686 // may have to update it, but we can check for some
687 // inconsistencies.
688 {
689 // If the sending processor sees no interior_parent here, we'd
690 // better agree.
691 if (interior_parent_id == DofObject::invalid_id)
692 {
693 if (elem->dim() < LIBMESH_DIM)
694 libmesh_assert (!(elem->interior_parent()));
695 }
696
697 // If the sending processor has a remote_elem interior_parent,
698 // then all we know is that we'd better have *some*
699 // interior_parent
700 else if (interior_parent_id == remote_elem->id())
701 {
703 }
704 else
705 {
706 Elem * ip =
707 mesh->interior_mesh().query_elem_ptr(interior_parent_id);
708
709 // The sending processor sees an interior parent here, so
710 // if we don't have that interior element, then we'd
711 // better have a remote_elem signifying that fact.
712 if (!ip)
713 libmesh_assert_equal_to (elem->interior_parent(), remote_elem);
714 else
715 {
716 // The sending processor has an interior_parent here,
717 // and we have that element, but that does *NOT* mean
718 // we're already linking to it. Perhaps we initially
719 // received elem from a processor on which the
720 // interior_parent link was remote?
721 libmesh_assert(elem->interior_parent() == ip ||
722 elem->interior_parent() == remote_elem);
723
724 // If the link was originally remote, update it
725 if (elem->interior_parent() == remote_elem)
726 {
727 elem->set_interior_parent(ip);
728 }
729 }
730 }
731 }
732
733 // Our neighbor links should be "close to" correct - we may have
734 // to update a remote_elem link, and we can check for possible
735 // inconsistencies along the way.
736 //
737 // Even for subactive elements, we'll try to keep neighbor links
738 // in good shape now, if only so any future find_neighbors() is
739 // idempotent.
740 for (auto n : elem->side_index_range())
741 {
742 const dof_id_type neighbor_id =
743 cast_int<dof_id_type>(*in++);
744
745 const dof_id_type neighbor_side =
746 cast_int<dof_id_type>(*in++);
747
748 // If the sending processor sees a domain boundary here,
749 // we'd better agree ... unless all we see is a remote_elem?
750 // In that case maybe we just couldn't keep up with a user's
751 // delete_elem. Let's trust them.
752 if (neighbor_id == DofObject::invalid_id)
753 {
754 const Elem * my_neigh = elem->neighbor_ptr(n);
755 if (my_neigh == remote_elem)
756 elem->set_neighbor(n, nullptr);
757 else
758 libmesh_assert (!my_neigh);
759 continue;
760 }
761
762 // If the sending processor has a remote_elem neighbor here,
763 // then all we know is that we'd better *not* have a domain
764 // boundary ... except that maybe it's the *sending*
765 // processor who missed a delete_elem we saw.
766 if (neighbor_id == remote_elem->id())
767 {
768 // At this level of the code we can't even assert in
769 // cases where the neighbor should know what they're
770 // talking about, so skip it.
771
772 // libmesh_assert(elem->neighbor_ptr(n));
773 continue;
774 }
775
776 Elem * neigh = mesh->query_elem_ptr(neighbor_id);
777
778 // The sending processor sees a neighbor here, so if we
779 // don't have that neighboring element, then we'd better
780 // have a remote_elem signifying that fact.
781 if (!neigh)
782 {
783 libmesh_assert_equal_to (elem->neighbor_ptr(n), remote_elem);
784 continue;
785 }
786
787 // The sending processor has a neighbor here, and we have
788 // that element, but that does *NOT* mean we're already
789 // linking to it. Perhaps we initially received both elem
790 // and neigh from processors on which their mutual link was
791 // remote?
792 libmesh_assert(elem->neighbor_ptr(n) == neigh ||
793 elem->neighbor_ptr(n) == remote_elem);
794
795 // If the link was originally remote, we should update it,
796 // and make sure the appropriate parts of its family link
797 // back to us.
798 if (elem->neighbor_ptr(n) == remote_elem)
799 {
800 elem->set_neighbor(n, neigh);
801 }
802 else
803 libmesh_assert(elem->subactive() ||
804 neigh->level() < elem->level() ||
805 neigh->neighbor_ptr(neighbor_side) == elem);
806
807 if (neighbor_side != libMesh::invalid_uint)
808 elem->make_links_to_me_local(n, neighbor_side);
809 }
810
811 // Our p level and refinement flags should be "close to" correct
812 // if we're not an active element - we might have a p level
813 // increased or decreased by changes in remote_elem children.
814 //
815 // But if we have remote_elem children, then we shouldn't be
816 // doing a projection on this inactive element on this
817 // processor, so we won't need correct p settings. Couldn't
818 // hurt to update, though.
819#ifdef LIBMESH_ENABLE_AMR
820 if (elem->processor_id() != mesh->processor_id())
821 {
822 // Do this simultaneously; otherwise we can get a false
823 // positive when a hack_p_level or set_p_refineemnt_flag
824 // assertion sees inconsistency between an old flag and new
825 // value or vice-versa
826 elem->hack_p_level_and_refinement_flag(p_level, p_refinement_flag);
827 }
828#endif // LIBMESH_ENABLE_AMR
829
830 // FIXME: We should add some debug mode tests to ensure that the
831 // encoded indexing and boundary conditions are consistent.
832 }
833 else
834 {
835 // We don't already have the element, so we need to create it.
836
837 // Find the parent if necessary
838 Elem * parent = nullptr;
839#ifdef LIBMESH_ENABLE_AMR
840 // Find a child element's parent
841 if (level > 0)
842 {
843 // Note that we must be very careful to construct the send
844 // connectivity so that parents are encountered before
845 // children. If we get here and can't find the parent that
846 // is a fatal error.
847 parent = mesh->elem_ptr(parent_id);
848 }
849 // Or assert that the sending processor sees no parent
850 else
851 libmesh_assert_equal_to (parent_id, DofObject::invalid_id);
852#else
853 // No non-level-0 elements without AMR
854 libmesh_assert_equal_to (level, 0);
855#endif
856
857 if (type == C0POLYGON)
858 elem = std::make_unique<C0Polygon>(n_nodes, parent).release();
859 else if (type == C0POLYHEDRON)
860 {
861 std::vector<std::shared_ptr<Polygon>> sides(n_sides);
862 for (auto s : index_range(sides))
863 {
864 const auto & side_nodes = polyhedron_side_nodes[s];
865 auto side = std::make_shared<C0Polygon>
866 (cast_int<unsigned int>(side_nodes.size()));
867 for (auto n : index_range(side_nodes))
868 {
869 const dof_id_type node_id =
870 cast_int<dof_id_type>
871 (*(node_ids_in + side_nodes[n]));
872 side->set_node(n, mesh->node_ptr(node_id));
873 }
874 sides[s] = std::move(side);
875 }
876
877 std::unique_ptr<Node> generated_mid_node;
878 auto polyhedron = std::make_unique<C0Polyhedron>
879 (sides, generated_mid_node, parent);
880
881 libmesh_assert_equal_to (polyhedron->n_nodes(), n_nodes);
882
883 if (generated_mid_node)
884 {
885 const dof_id_type mid_node_id =
886 cast_int<dof_id_type>(*(node_ids_in + n_nodes - 1));
887 polyhedron->set_node(n_nodes - 1,
888 mesh->node_ptr(mid_node_id));
889 }
890
891 elem = polyhedron.release();
892 }
893 else
894 elem = Elem::build(type,parent).release();
895 libmesh_assert (elem);
896
897#ifdef LIBMESH_ENABLE_AMR
898 if (level != 0)
899 {
900 // Since this is a newly created element, the parent must
901 // have previously thought of this child as a remote element.
902 libmesh_assert_equal_to (parent->child_ptr(which_child_am_i), remote_elem);
903
904 parent->add_child(elem, which_child_am_i);
905 }
906
907 // Assign the refinement flags and levels
908 elem->set_p_level(p_level);
909 elem->set_refinement_flag(refinement_flag);
910 elem->set_p_refinement_flag(p_refinement_flag);
911 libmesh_assert_equal_to (elem->level(), level);
912
913 // If this element should have children, assign remote_elem to
914 // all of them for now, for consistency. Later unpacked
915 // elements may overwrite that.
916 if (has_children)
917 {
918 const unsigned int nc = elem->n_children();
919 for (unsigned int c=0; c != nc; ++c)
920 elem->add_child(const_cast<RemoteElem *>(remote_elem), c);
921 }
922
923#endif // LIBMESH_ENABLE_AMR
924
925 // Assign the IDs
926 elem->subdomain_id() = subdomain_id;
927 elem->processor_id() = processor_id;
928 elem->set_id() = id;
929#ifdef LIBMESH_ENABLE_UNIQUE_ID
930 elem->set_unique_id(unique_id);
931#endif
932
933 // Assign the connectivity
934 libmesh_assert_equal_to (elem->n_nodes(), n_nodes);
935 libmesh_assert_equal_to (elem->n_sides(), n_sides);
936 libmesh_assert_equal_to (elem->n_edges(), n_edges);
937
938 if (!elem->runtime_topology() || elem->dim() != 3)
939 for (unsigned int n=0; n != n_nodes; n++)
940 elem->set_node
941 (n, mesh->node_ptr
942 (cast_int<dof_id_type>(*(node_ids_in + n))));
943
944#ifndef NDEBUG
945 for (unsigned int n = 0; n != n_nodes; ++n)
946 libmesh_assert_equal_to
947 (elem->node_id(n),
948 cast_int<dof_id_type>(*(node_ids_in + n)));
949#endif
950
951 // Set interior_parent if found
952 {
953 // We may be unpacking an element that was a ghost element on the
954 // sender, in which case the element's interior_parent may not be
955 // known by the packed element. We'll have to set such
956 // interior_parents to remote_elem ourselves and wait for a
957 // later packed element to give us better information.
958 if (interior_parent_id == remote_elem->id())
959 {
961 (const_cast<RemoteElem *>(remote_elem));
962 }
963 else if (interior_parent_id != DofObject::invalid_id)
964 {
965 // If we don't have the interior parent element, then it's
966 // a remote_elem until we get it.
967 Elem * ip =
968 mesh->interior_mesh().query_elem_ptr(interior_parent_id);
969 if (!ip )
971 (const_cast<RemoteElem *>(remote_elem));
972 else
973 elem->set_interior_parent(ip);
974 }
975 }
976
977 for (auto n : elem->side_index_range())
978 {
979 const dof_id_type neighbor_id =
980 cast_int<dof_id_type>(*in++);
981
982 const dof_id_type neighbor_side =
983 cast_int<dof_id_type>(*in++);
984
985 if (neighbor_id == DofObject::invalid_id)
986 continue;
987
988 // We may be unpacking an element that was a ghost element on the
989 // sender, in which case the element's neighbors may not all be
990 // known by the packed element. We'll have to set such
991 // neighbors to remote_elem ourselves and wait for a later
992 // packed element to give us better information.
993 if (neighbor_id == remote_elem->id())
994 {
995 elem->set_neighbor(n, const_cast<RemoteElem *>(remote_elem));
996 continue;
997 }
998
999 // If we don't have the neighbor element, then it's a
1000 // remote_elem until we get it.
1001 Elem * neigh = mesh->query_elem_ptr(neighbor_id);
1002 if (!neigh)
1003 {
1004 elem->set_neighbor(n, const_cast<RemoteElem *>(remote_elem));
1005 continue;
1006 }
1007
1008 // If we have the neighbor element, then link to it, and
1009 // make sure any appropriate parts of its family link back
1010 // to us.
1011 elem->set_neighbor(n, neigh);
1012
1013 if (neighbor_side != libMesh::invalid_uint)
1014 elem->make_links_to_me_local(n, neighbor_side);
1015 }
1016
1017 elem->unpack_indexing(in);
1018
1019 mesh->add_elem(elem);
1020 }
1021
1022 in += elem->packed_indexing_size();
1023
1024 // We check if this is cell holds a boundary ID or not
1025 auto on_boundary = *in++;
1026 if (on_boundary)
1027 {
1028 // Only treat the sides with caution. This is because we might hold boundary IDs
1029 // on the sides of the children. This is not supported for edges and shell faces, thus
1030 // they are treated assuming that only top parents can hold the IDs.
1031 auto children_on_boundary = *in++;
1032 if (elem->level() == 0 || children_on_boundary)
1033 {
1034 for (auto s : elem->side_index_range())
1035 {
1036 const boundary_id_type num_bcs =
1037 cast_int<boundary_id_type>(*in++);
1038
1039 for (boundary_id_type bc_it=0; bc_it < num_bcs; bc_it++)
1041 (elem, s, cast_int<boundary_id_type>(*in++));
1042 }
1043 }
1044 }
1045
1046 // If this is a coarse element,
1047 // add any element side or edge boundary condition ids
1048 if (level == 0)
1049 {
1050 for (auto e : elem->edge_index_range())
1051 {
1052 const boundary_id_type num_bcs =
1053 cast_int<boundary_id_type>(*in++);
1054
1055 for (boundary_id_type bc_it=0; bc_it < num_bcs; bc_it++)
1057 (elem, e, cast_int<boundary_id_type>(*in++));
1058 }
1059
1060 for (unsigned short sf=0; sf != 2; ++sf)
1061 {
1062 const boundary_id_type num_bcs =
1063 cast_int<boundary_id_type>(*in++);
1064
1065 for (boundary_id_type bc_it=0; bc_it < num_bcs; bc_it++)
1067 (elem, sf, cast_int<boundary_id_type>(*in++));
1068 }
1069 }
1070
1071 // Return the new element
1072 return elem;
1073}
1074
1075
1076
1077template <>
1078Elem *
1079Packing<Elem *>::unpack (std::vector<largest_id_type>::const_iterator in,
1081{
1082 return unpack(in, static_cast<MeshBase*>(mesh));
1083}
1084
1085
1086
1087template <>
1088Elem *
1089Packing<Elem *>::unpack (std::vector<largest_id_type>::const_iterator in,
1091{
1092 return unpack(in, static_cast<MeshBase*>(mesh));
1093}
1094
1095} // namespace Parallel
1096
1097} // namespace libMesh
void ErrorVector unsigned int
void add_shellface(const dof_id_type elem, const unsigned short int shellface, const boundary_id_type id)
Add shell face shellface of element number elem with boundary id id to the boundary information data ...
void shellface_boundary_ids(const Elem *const elem, const unsigned short int shellface, std::vector< boundary_id_type > &vec_to_fill) const
unsigned int n_raw_boundary_ids(const Elem *const elem, const unsigned short int side) const
void add_edge(const dof_id_type elem, const unsigned short int edge, const boundary_id_type id)
Add edge edge of element number elem with boundary id id to the boundary information data structure.
void edge_boundary_ids(const Elem *const elem, const unsigned short int edge, std::vector< boundary_id_type > &vec_to_fill) const
unsigned int n_shellface_boundary_ids(const Elem *const elem, const unsigned short int shellface) const
unsigned int n_edge_boundary_ids(const Elem *const elem, const unsigned short int edge) const
void raw_boundary_ids(const Elem *const elem, const unsigned short int side, std::vector< boundary_id_type > &vec_to_fill) const
bool is_children_on_boundary_side() const
void add_side(const dof_id_type elem, const unsigned short int side, const boundary_id_type id)
Add side side of element number elem with boundary id id to the boundary information data structure.
The DistributedMesh class is derived from the MeshBase class, and is intended to provide identical fu...
static unsigned int unpackable_indexing_size(std::vector< largest_id_type >::const_iterator begin)
If we have indices packed into an buffer for communications, how much of that buffer applies to this ...
Definition dof_object.C:567
processor_id_type processor_id() const
Definition dof_object.h:881
dof_id_type & set_id()
Definition dof_object.h:827
static constexpr dof_id_type invalid_id
An invalid id to distinguish an uninitialized DofObject.
Definition dof_object.h:473
unique_id_type unique_id() const
Definition dof_object.h:835
void pack_indexing(std::back_insert_iterator< std::vector< largest_id_type > > target) const
A method for creating packed data from our index buffer - basically a copy with prepended size with o...
Definition dof_object.C:634
static constexpr unique_id_type invalid_unique_id
An invalid unique_id to distinguish an uninitialized DofObject.
Definition dof_object.h:478
bool valid_unique_id() const
Definition dof_object.h:869
dof_id_type id() const
Definition dof_object.h:819
static constexpr processor_id_type invalid_processor_id
An invalid processor_id to distinguish DoFs that have not been assigned to a processor.
Definition dof_object.h:484
void set_unique_id(unique_id_type new_id)
Sets the unique_id for this DofObject.
Definition dof_object.h:848
unsigned int packed_indexing_size() const
If we pack our indices into an buffer for communications, how many ints do we need?
Definition dof_object.C:552
void unpack_indexing(std::vector< largest_id_type >::const_iterator begin)
A method for creating our index buffer from packed data - basically with our current implementation w...
Definition dof_object.C:587
This is the base class from which all geometric element types are derived.
Definition elem.h:96
virtual Node *& set_node(const unsigned int i)
Definition elem.h:2567
void set_p_refinement_flag(const RefinementState pflag)
Sets the value of the p-refinement flag for the element.
Definition elem.h:3251
RefinementState refinement_flag() const
Definition elem.h:3227
static const unsigned int type_to_n_nodes_map[INVALID_ELEM]
This array maps the integer representation of the ElemType enum to the number of nodes in the element...
Definition elem.h:643
bool active() const
Definition elem.h:2958
void hack_p_level_and_refinement_flag(const unsigned int p, RefinementState pflag)
Sets the value of the p-refinement level for the element without altering the p-level of its ancestor...
Definition elem.h:3292
static const unsigned int type_to_n_edges_map[INVALID_ELEM]
This array maps the integer representation of the ElemType enum to the number of edges on the element...
Definition elem.h:742
bool has_children() const
Definition elem.h:2996
virtual unsigned int n_nodes() const =0
const Elem * parent() const
Definition elem.h:3047
void make_links_to_me_local(unsigned int n, unsigned int neighbor_side)
Resets the neighbor_side pointers of our nth neighbor (and its descendants, if appropriate) to point ...
Definition elem.C:1429
void set_neighbor(const unsigned int i, Elem *n)
Assigns n as the neighbor.
Definition elem.h:2635
const Elem * child_ptr(unsigned int i) const
Definition elem.h:3180
RefinementState
Enumeration of possible element refinement states.
Definition elem.h:1446
@ INVALID_REFINEMENTSTATE
Definition elem.h:1453
static std::unique_ptr< Elem > build(const ElemType type, Elem *p=nullptr)
Definition elem.C:442
virtual std::vector< unsigned int > nodes_on_side(const unsigned int) const =0
void set_interior_parent(Elem *p)
Sets the pointer to the element's interior_parent.
Definition elem.C:1222
unsigned int which_child_am_i(const Elem *e) const
Definition elem.h:3209
virtual unsigned short dim() const =0
subdomain_id_type subdomain_id() const
Definition elem.h:2591
static const unsigned int type_to_dim_map[INVALID_ELEM]
This array maps the integer representation of the ElemType enum to the geometric dimension of the ele...
Definition elem.h:628
static const unsigned int type_to_n_sides_map[INVALID_ELEM]
This array maps the integer representation of the ElemType enum to the number of sides on the element...
Definition elem.h:678
unsigned int level() const
Definition elem.h:3091
virtual bool runtime_topology() const
Definition elem.h:254
void add_child(Elem *elem)
Adds a child pointer to the array of children of this element.
Definition elem.C:2053
IntRange< unsigned short > edge_index_range() const
Definition elem.h:2709
virtual unsigned int n_children() const =0
virtual ElemType type() const =0
const Elem * interior_parent() const
Definition elem.C:1160
void set_refinement_flag(const RefinementState rflag)
Sets the value of the refinement flag for the element.
Definition elem.h:3235
virtual unsigned int n_edges() const =0
virtual unsigned int n_sides() const =0
dof_id_type node_id(const unsigned int i) const
Definition elem.h:2484
bool subactive() const
Definition elem.h:2976
unsigned int p_level() const
Definition elem.h:3125
RefinementState p_refinement_flag() const
Definition elem.h:3243
void set_p_level(const unsigned int p)
Sets the value of the p-refinement level for the element.
const Elem * neighbor_ptr(unsigned int i) const
Definition elem.h:2615
IntRange< unsigned short > side_index_range() const
Definition elem.h:2727
This is the MeshBase class.
Definition mesh_base.h:81
const BoundaryInfo & get_boundary_info() const
The information about boundary ids on the mesh.
Definition mesh_base.h:170
virtual const Node * node_ptr(const dof_id_type i) const =0
virtual const Elem * elem_ptr(const dof_id_type i) const =0
const MeshBase & interior_mesh() const
Definition mesh_base.h:2040
virtual const Elem * query_elem_ptr(const dof_id_type i) const =0
virtual Elem * add_elem(Elem *e)=0
Add elem e to the end of the element array.
A Node is like a Point, but with more information.
Definition node.h:55
processor_id_type processor_id() const
std::pair< T1, T2 > unpack(BufferIter in, Context *ctx)
static unsigned int packed_size(BufferIter iter)
unsigned int packable_size(const std::pair< T1, T2 > &pr, const Context *ctx)
void pack(const std::pair< T1, T2 > &pr, OutputIter data_out, const Context *ctx)
In parallel meshes where a ghost element has neighbors which do not exist on the local processor,...
Definition remote_elem.h:61
MeshBase & mesh
uint8_t processor_id_type
Tnew cast_int(Told oldvar)
The libMesh namespace provides an interface to certain functionality in the library.
uint8_t unique_id_type
Definition id_types.h:86
auto index_range(const T &sizable)
Helper function that returns an IntRange<std::size_t> representing all the indices of the passed-in v...
Definition int_range.h:153
ElemType
Defines an enum for geometric element types.
int8_t boundary_id_type
Definition id_types.h:51
void libmesh_ignore(const Args &...)
libmesh_assert(ctx)
const unsigned int invalid_uint
A number which is used quite often to represent an invalid or uninitialized value for an unsigned int...
Definition libmesh.h:303
uint64_t largest_id_type
Definition id_types.h:148
const RemoteElem * remote_elem
Definition remote_elem.C:57
uint8_t dof_id_type
Definition id_types.h:67
const dof_id_type n_nodes
Definition tecplot_io.C:67