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 : // 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 :
36 : namespace
37 : {
38 : using namespace libMesh;
39 :
40 : #ifdef LIBMESH_ENABLE_UNIQUE_ID
41 : static const unsigned int header_size = 12;
42 : #else
43 : static const unsigned int header_size = 11;
44 : #endif
45 :
46 : #ifndef NDEBUG
47 : // Currently this constant is only used for debugging.
48 : static const largest_id_type elem_magic_header = 987654321;
49 : #endif
50 : }
51 :
52 :
53 : namespace libMesh
54 : {
55 :
56 : namespace Parallel
57 : {
58 :
59 : template <>
60 : unsigned int
61 80124442 : Packing<const Elem *>::packed_size (std::vector<largest_id_type>::const_iterator in)
62 : {
63 : #ifndef NDEBUG
64 108932 : const largest_id_type packed_header = *in++;
65 108932 : libmesh_assert_equal_to (packed_header, elem_magic_header);
66 : #endif
67 :
68 : // int 0: level
69 : const unsigned int level =
70 80124442 : cast_int<unsigned int>(*in);
71 :
72 : // int 4: element type
73 80124442 : const int typeint = cast_int<int>(*(in+4));
74 108932 : libmesh_assert_greater_equal (typeint, 0);
75 108932 : libmesh_assert_less (typeint, INVALID_ELEM);
76 : const ElemType type =
77 108932 : cast_int<ElemType>(typeint);
78 :
79 80124442 : unsigned int n_nodes = Elem::type_to_n_nodes_map[type];
80 80124442 : unsigned int n_sides = Elem::type_to_n_sides_map[type];
81 80124442 : unsigned int n_edges = Elem::type_to_n_edges_map[type];
82 108932 : 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 108932 : const bool has_runtime_topology = (n_nodes == invalid_uint);
86 :
87 80124442 : if (has_runtime_topology)
88 : {
89 4 : auto topology_in = in + header_size;
90 244 : n_nodes = cast_int<unsigned int>(*topology_in++);
91 244 : n_sides = cast_int<unsigned int>(*topology_in++);
92 244 : n_edges = cast_int<unsigned int>(*topology_in++);
93 4 : variable_topology_size = 3;
94 :
95 244 : if (Elem::type_to_dim_map[type] == 3)
96 : {
97 2 : topology_in += n_nodes;
98 1387 : for (unsigned int s = 0; s != n_sides; ++s)
99 : {
100 : const unsigned int n_side_nodes =
101 1210 : cast_int<unsigned int>(*topology_in++);
102 16 : topology_in += n_side_nodes;
103 1210 : variable_topology_size += n_side_nodes + 1;
104 : }
105 : }
106 : }
107 :
108 80124442 : const unsigned int pre_indexing_size =
109 80124442 : header_size + variable_topology_size + n_nodes + n_sides*2;
110 :
111 : const unsigned int indexing_size =
112 80124442 : DofObject::unpackable_indexing_size(in+pre_indexing_size);
113 :
114 : // We communicate if we are on the boundary or not
115 108932 : unsigned int total_packed_bc_data = 1;
116 80124442 : largest_id_type on_boundary = *(in + pre_indexing_size + indexing_size);
117 :
118 80124442 : if (on_boundary)
119 : {
120 : // Extracting if the children are allowed on the boundary
121 12299 : total_packed_bc_data++;
122 12568486 : 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 12568486 : if (level == 0 || allow_children_on_boundary)
127 : {
128 66925652 : for (unsigned int s = 0; s != n_sides; ++s)
129 : {
130 : const int n_bcs = cast_int<int>
131 54413298 : (*(in + pre_indexing_size + indexing_size +
132 54413298 : total_packed_bc_data++));
133 56132 : libmesh_assert_greater_equal (n_bcs, 0);
134 54357166 : total_packed_bc_data += n_bcs;
135 : }
136 : }
137 : }
138 80124442 : if (level == 0)
139 : {
140 210843056 : for (unsigned int e = 0; e != n_edges; ++e)
141 : {
142 : const int n_bcs = cast_int<int>
143 183202101 : (*(in + pre_indexing_size + indexing_size +
144 183202101 : total_packed_bc_data++));
145 617354 : libmesh_assert_greater_equal (n_bcs, 0);
146 182584747 : total_packed_bc_data += n_bcs;
147 : }
148 :
149 84774927 : for (unsigned short sf=0; sf != 2; ++sf)
150 : {
151 : const int n_bcs = cast_int<int>
152 56717778 : (*(in + pre_indexing_size + indexing_size +
153 56717778 : total_packed_bc_data++));
154 201160 : libmesh_assert_greater_equal (n_bcs, 0);
155 56516618 : total_packed_bc_data += n_bcs;
156 : }
157 : }
158 :
159 : return
160 : #ifndef NDEBUG
161 : 1 + // Account for magic header
162 : #endif
163 80124442 : pre_indexing_size + indexing_size + total_packed_bc_data;
164 : }
165 :
166 :
167 :
168 : template <>
169 : unsigned int
170 53956 : Packing<const Elem *>::packed_size (std::vector<largest_id_type>::iterator in)
171 : {
172 53956 : return packed_size(std::vector<largest_id_type>::const_iterator(in));
173 : }
174 :
175 :
176 :
177 : template <>
178 : unsigned int
179 24357242 : Packing<const Elem *>::packable_size (const Elem * const & elem,
180 : const MeshBase * mesh)
181 : {
182 107950 : unsigned int variable_topology_size = 0;
183 24357242 : if (elem->runtime_topology())
184 : {
185 : // Store the dynamic node, side, and edge counts.
186 4 : 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 99 : if (elem->dim() == 3)
191 618 : for (auto s : elem->side_index_range())
192 536 : variable_topology_size +=
193 544 : 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 107950 : unsigned int total_packed_bcs = 1;
198 24357242 : const unsigned int n_sides = elem->n_sides();
199 :
200 107950 : largest_id_type on_boundary = 0;
201 108539259 : for (auto s : elem->side_index_range())
202 89463841 : if (mesh->get_boundary_info().n_raw_boundary_ids(elem,s))
203 : {
204 11822 : on_boundary = 1;
205 11822 : break;
206 : }
207 :
208 24357242 : 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 11822 : total_packed_bcs++;
214 5335818 : if (elem->level() == 0 || mesh->get_boundary_info().is_children_on_boundary_side())
215 : {
216 5335818 : total_packed_bcs += n_sides;
217 27994226 : for (unsigned int s = 0; s != n_sides; ++s)
218 22658408 : total_packed_bcs +=
219 22658408 : mesh->get_boundary_info().n_raw_boundary_ids(elem,s);
220 : }
221 : }
222 :
223 24357242 : if (elem->level() == 0)
224 : {
225 12872209 : const unsigned int n_edges = elem->n_edges();
226 12872209 : total_packed_bcs += n_edges;
227 97357661 : for (unsigned int e = 0; e != n_edges; ++e)
228 84485452 : total_packed_bcs +=
229 84485452 : mesh->get_boundary_info().n_edge_boundary_ids(elem,e);
230 :
231 12872209 : total_packed_bcs += 2; // shellfaces
232 38616627 : for (unsigned short sf=0; sf != 2; ++sf)
233 25744418 : total_packed_bcs +=
234 25744418 : mesh->get_boundary_info().n_shellface_boundary_ids(elem,sf);
235 : }
236 :
237 : return
238 : #ifndef NDEBUG
239 : 1 + // add an int for the magic header when testing
240 : #endif
241 24357242 : header_size + variable_topology_size + elem->n_nodes() + n_sides*2 +
242 24357242 : elem->packed_indexing_size() + total_packed_bcs;
243 : }
244 :
245 :
246 :
247 : template <>
248 : unsigned int
249 16345716 : Packing<const Elem *>::packable_size (const Elem * const & elem,
250 : const DistributedMesh * mesh)
251 : {
252 16345716 : return packable_size(elem, static_cast<const MeshBase *>(mesh));
253 : }
254 :
255 :
256 :
257 : template <>
258 : unsigned int
259 0 : Packing<const Elem *>::packable_size (const Elem * const & elem,
260 : const ParallelMesh * mesh)
261 : {
262 0 : return packable_size(elem, static_cast<const MeshBase *>(mesh));
263 : }
264 :
265 :
266 :
267 : template <>
268 : void
269 24302506 : Packing<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 53956 : libmesh_assert(elem);
274 :
275 : #ifndef NDEBUG
276 53956 : *data_out++ = elem_magic_header;
277 : #endif
278 :
279 : #ifdef LIBMESH_ENABLE_AMR
280 24302506 : *data_out++ = (static_cast<largest_id_type>(elem->level()));
281 24302506 : *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 24302506 : static_cast<largest_id_type>(elem->refinement_flag());
289 53956 : if (elem->has_children())
290 3164915 : refinement_info +=
291 : static_cast<largest_id_type>(Elem::INVALID_REFINEMENTSTATE) + 1;
292 53956 : *data_out++ = (refinement_info);
293 :
294 24302506 : *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 24302506 : *data_out++ = (static_cast<largest_id_type>(elem->type()));
302 24302506 : *data_out++ = (elem->processor_id());
303 24302506 : *data_out++ = (elem->subdomain_id());
304 24302506 : *data_out++ = (elem->id());
305 :
306 : #ifdef LIBMESH_ENABLE_UNIQUE_ID
307 24302506 : if (elem->valid_unique_id())
308 24302506 : *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 0 : *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 24302506 : if (elem->level() == 0)
317 : {
318 100008 : *data_out++ =(DofObject::invalid_id);
319 100008 : *data_out++ =(DofObject::invalid_id);
320 : }
321 : else
322 : {
323 11485033 : *data_out++ =(elem->parent()->id());
324 11485033 : *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 31410921 : if ((elem->dim() < LIBMESH_DIM) &&
332 7108415 : elem->interior_parent())
333 4588 : *data_out++ =(elem->interior_parent()->id());
334 : else
335 107856 : *data_out++ =(DofObject::invalid_id);
336 :
337 24302506 : const bool has_variable_topology = elem->runtime_topology();
338 24302506 : if (has_variable_topology)
339 : {
340 97 : *data_out++ = elem->n_nodes();
341 97 : *data_out++ = elem->n_sides();
342 97 : *data_out++ = elem->n_edges();
343 : }
344 :
345 260421249 : for (const Node & node : elem->node_ref_range())
346 236064787 : *data_out++ = node.id();
347 :
348 24302506 : if (has_variable_topology && elem->dim() == 3) // AKA, is c0polyhedron
349 609 : for (auto s : elem->side_index_range())
350 : {
351 : const std::vector<unsigned int> side_nodes =
352 536 : elem->nodes_on_side(s);
353 1048 : *data_out++ = side_nodes.size();
354 2736 : for (const auto node : side_nodes)
355 4344 : *data_out++ = node;
356 : }
357 :
358 : // Add the id of and the side for any return link from each neighbor
359 127896497 : for (auto neigh : elem->neighbor_ptr_range())
360 : {
361 103540035 : if (neigh)
362 : {
363 93366572 : *data_out++ = (neigh->id());
364 93366572 : if (neigh == remote_elem)
365 5970 : *data_out++ = (DofObject::invalid_id);
366 : else
367 85547068 : *data_out++ = neigh->which_neighbor_am_i(elem);
368 : }
369 : else
370 : {
371 364294 : *data_out++ = (DofObject::invalid_id);
372 364294 : *data_out++ = (DofObject::invalid_id);
373 : }
374 : }
375 :
376 : // Add any DofObject indices
377 24302506 : 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 24302506 : largest_id_type on_boundary = 0;
383 108279826 : for (auto s : elem->side_index_range())
384 89252632 : if (mesh->get_boundary_info().n_raw_boundary_ids(elem,s))
385 : {
386 5329268 : on_boundary = 1;
387 5329268 : break;
388 : }
389 :
390 53956 : *data_out++ = on_boundary;
391 :
392 24302506 : if (on_boundary)
393 : {
394 5329268 : *data_out++ = mesh->get_boundary_info().is_children_on_boundary_side();
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
397 5329268 : if (elem->level() == 0 || mesh->get_boundary_info().is_children_on_boundary_side())
398 : {
399 11788 : std::vector<boundary_id_type> bcs;
400 27964300 : for (auto s : elem->side_index_range())
401 : {
402 22629138 : mesh->get_boundary_info().raw_boundary_ids(elem, s, bcs);
403 :
404 45231610 : *data_out++ =(bcs.size());
405 :
406 28541672 : for (const auto & bid : bcs)
407 11809684 : *data_out++ = bid;
408 : }
409 : }
410 : }
411 :
412 : // If this is a coarse element,
413 : // Add any element side boundary condition ids
414 24302506 : if (elem->level() == 0)
415 : {
416 100008 : std::vector<boundary_id_type> bcs;
417 97047796 : for (auto e : elem->edge_index_range())
418 : {
419 84176367 : mesh->get_boundary_info().edge_boundary_ids(elem, e, bcs);
420 :
421 168046749 : *data_out++ =(bcs.size());
422 :
423 84177023 : for (const auto & bid : bcs)
424 1216 : *data_out++ = bid;
425 : }
426 :
427 38464275 : for (unsigned short sf=0; sf != 2; ++sf)
428 : {
429 25642850 : mesh->get_boundary_info().shellface_boundary_ids(elem, sf, bcs);
430 :
431 51185692 : *data_out++ =(bcs.size());
432 :
433 25710610 : for (const auto & bid : bcs)
434 128864 : *data_out++ = bid;
435 : }
436 : }
437 24302506 : }
438 :
439 :
440 :
441 : template <>
442 : void
443 16337244 : Packing<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 16337244 : pack(elem, data_out, static_cast<const MeshBase*>(mesh));
448 16337244 : }
449 :
450 :
451 :
452 : template <>
453 : void
454 0 : Packing<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 0 : pack(elem, data_out, static_cast<const MeshBase*>(mesh));
459 0 : }
460 :
461 :
462 :
463 : // FIXME - this needs serious work to be 64-bit compatible
464 : template <>
465 : Elem *
466 80070486 : Packing<Elem *>::unpack (std::vector<largest_id_type>::const_iterator in,
467 : MeshBase * mesh)
468 : {
469 : #ifndef NDEBUG
470 54976 : const std::vector<largest_id_type>::const_iterator original_in = in;
471 :
472 54976 : const largest_id_type incoming_header = *in++;
473 54976 : libmesh_assert_equal_to (incoming_header, elem_magic_header);
474 : #endif
475 :
476 : // int 0: level
477 : const unsigned int level =
478 80070486 : cast_int<unsigned int>(*in++);
479 :
480 : #ifdef LIBMESH_ENABLE_AMR
481 : // int 1: p level
482 : const unsigned int p_level =
483 80070486 : cast_int<unsigned int>(*in++);
484 :
485 : // int 2: refinement flag and encoded has_children
486 80070486 : const int rflag = cast_int<int>(*in++);
487 : const int invalid_rflag =
488 54976 : cast_int<int>(Elem::INVALID_REFINEMENTSTATE);
489 54976 : libmesh_assert_greater_equal (rflag, 0);
490 :
491 54976 : libmesh_assert_less (rflag, invalid_rflag*2+1);
492 :
493 54976 : const bool has_children = (rflag > invalid_rflag);
494 :
495 80070486 : const Elem::RefinementState refinement_flag = has_children ?
496 15270495 : cast_int<Elem::RefinementState>(rflag - invalid_rflag - 1) :
497 53912 : cast_int<Elem::RefinementState>(rflag);
498 :
499 : // int 3: p refinement flag
500 80070486 : const int pflag = cast_int<int>(*in++);
501 54976 : libmesh_assert_greater_equal (pflag, 0);
502 54976 : libmesh_assert_less (pflag, Elem::INVALID_REFINEMENTSTATE);
503 : const Elem::RefinementState p_refinement_flag =
504 54976 : cast_int<Elem::RefinementState>(pflag);
505 : #else
506 : in += 3;
507 : #endif // LIBMESH_ENABLE_AMR
508 :
509 : // int 4: element type
510 80070486 : const int typeint = cast_int<int>(*in++);
511 54976 : libmesh_assert_greater_equal (typeint, 0);
512 54976 : libmesh_assert_less (typeint, INVALID_ELEM);
513 : const ElemType type =
514 54976 : cast_int<ElemType>(typeint);
515 :
516 80070486 : unsigned int n_nodes = Elem::type_to_n_nodes_map[type];
517 80070486 : unsigned int n_sides = Elem::type_to_n_sides_map[type];
518 54976 : 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 54976 : const bool has_runtime_topology = (n_nodes == invalid_uint);
522 :
523 : // int 5: processor id
524 : const processor_id_type processor_id =
525 80070486 : cast_int<processor_id_type>(*in++);
526 54976 : 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 80070486 : cast_int<subdomain_id_type>(*in++);
532 :
533 : // int 7: dof object id
534 : const dof_id_type id =
535 80070486 : cast_int<dof_id_type>(*in++);
536 54976 : 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 80070486 : 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 54976 : (level == 0)
552 80070486 : ? static_cast<dof_id_type>(*in++)
553 51862181 : : cast_int<dof_id_type>(*in++);
554 54976 : libmesh_assert (level == 0 || parent_id != DofObject::invalid_id);
555 54976 : 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 54976 : (level == 0)
562 80070486 : ? static_cast<unsigned int>(*in++)
563 51862181 : : 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 80070486 : 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 54976 : libmesh_assert_equal_to (in - original_in, header_size + 1);
574 :
575 80070486 : if (has_runtime_topology)
576 : {
577 242 : n_nodes = cast_int<unsigned int>(*in++);
578 242 : n_sides = cast_int<unsigned int>(*in++);
579 2 : n_edges = cast_int<unsigned int>(*in++);
580 :
581 2 : if (Elem::type_to_dim_map[type] == 2)
582 : {
583 1 : libmesh_assert_less (2, n_sides);
584 1 : libmesh_assert_equal_to (n_nodes % n_sides, 0);
585 1 : libmesh_assert_equal_to (n_edges, n_sides);
586 : }
587 1 : else if (Elem::type_to_dim_map[type] == 3)
588 : {
589 1 : libmesh_assert_less (3, n_nodes);
590 1 : libmesh_assert_less (3, n_sides);
591 : }
592 : }
593 54976 : libmesh_ignore(n_edges); // unused outside dbg/devel
594 :
595 54976 : const auto node_ids_in = in;
596 80015510 : in += n_nodes;
597 :
598 109952 : std::vector<std::vector<unsigned int>> polyhedron_side_nodes;
599 80070486 : if (has_runtime_topology && Elem::type_to_dim_map[type] == 3)
600 : {
601 176 : polyhedron_side_nodes.resize(n_sides);
602 : #ifndef NDEBUG
603 2 : std::vector<bool> node_seen(n_nodes, false);
604 1 : unsigned int next_new_node = 0;
605 : #endif
606 1378 : for (auto & side_nodes : polyhedron_side_nodes)
607 : {
608 : const unsigned int n_side_nodes =
609 1202 : cast_int<unsigned int>(*in++);
610 8 : libmesh_assert_less (2, n_side_nodes);
611 1202 : side_nodes.resize(n_side_nodes);
612 6302 : for (auto & node : side_nodes)
613 : {
614 5136 : node = cast_int<unsigned int>(*in++);
615 36 : libmesh_assert_less (node, n_nodes);
616 :
617 : #ifndef NDEBUG
618 36 : if (type == C0POLYHEDRON && !node_seen[node])
619 : {
620 12 : libmesh_assert_equal_to (node, next_new_node);
621 12 : node_seen[node] = true;
622 12 : ++next_new_node;
623 : }
624 : #endif
625 : }
626 : }
627 :
628 : #ifndef NDEBUG
629 1 : if (type == C0POLYHEDRON)
630 1 : libmesh_assert (next_new_node == n_nodes ||
631 : next_new_node + 1 == n_nodes);
632 : #endif
633 : }
634 :
635 80070486 : 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 80070486 : if (elem)
641 : {
642 9690 : libmesh_assert_equal_to (elem->level(), level);
643 9690 : libmesh_assert_equal_to (elem->id(), id);
644 : //#ifdef LIBMESH_ENABLE_UNIQUE_ID
645 : // No check for unique id sanity
646 : //#endif
647 9690 : libmesh_assert_equal_to (elem->processor_id(), processor_id);
648 9690 : libmesh_assert_equal_to (elem->subdomain_id(), subdomain_id);
649 9690 : libmesh_assert_equal_to (elem->type(), type);
650 9690 : libmesh_assert_equal_to (elem->n_nodes(), n_nodes);
651 9690 : libmesh_assert_equal_to (elem->n_sides(), n_sides);
652 9690 : libmesh_assert_equal_to (elem->n_edges(), n_edges);
653 :
654 : #ifndef NDEBUG
655 9690 : if (elem->runtime_topology() && elem->dim() == 3)
656 0 : for (auto s : elem->side_index_range())
657 0 : 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 105990 : for (unsigned int i=0; i != n_nodes; ++i)
664 96300 : 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 9690 : libmesh_assert_equal_to (elem->refinement_flag(), refinement_flag);
671 9690 : libmesh_assert_equal_to (elem->has_children(), has_children);
672 :
673 : #ifdef DEBUG
674 9690 : if (elem->active())
675 : {
676 8712 : libmesh_assert_equal_to (elem->p_level(), p_level);
677 8712 : libmesh_assert_equal_to (elem->p_refinement_flag(), p_refinement_flag);
678 : }
679 : #endif
680 :
681 9690 : libmesh_assert (!level || elem->parent() != nullptr);
682 9690 : libmesh_assert (!level || elem->parent()->id() == parent_id);
683 9690 : 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 49954485 : if (interior_parent_id == DofObject::invalid_id)
692 : {
693 49936788 : if (elem->dim() < LIBMESH_DIM)
694 2623 : 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 17697 : else if (interior_parent_id == remote_elem->id())
701 : {
702 0 : libmesh_assert(elem->interior_parent());
703 : }
704 : else
705 : {
706 : Elem * ip =
707 17697 : 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 17697 : if (!ip)
713 0 : 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 28 : libmesh_assert(elem->interior_parent() == ip ||
722 : elem->interior_parent() == remote_elem);
723 :
724 : // If the link was originally remote, update it
725 17138 : if (elem->interior_parent() == remote_elem)
726 : {
727 0 : 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 260843130 : for (auto n : elem->side_index_range())
741 : {
742 : const dof_id_type neighbor_id =
743 210888645 : cast_int<dof_id_type>(*in++);
744 :
745 : const dof_id_type neighbor_side =
746 210888645 : 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 210888645 : if (neighbor_id == DofObject::invalid_id)
753 : {
754 20013611 : const Elem * my_neigh = elem->neighbor_ptr(n);
755 20013611 : if (my_neigh == remote_elem)
756 1 : elem->set_neighbor(n, nullptr);
757 : else
758 4883 : libmesh_assert (!my_neigh);
759 20013611 : continue;
760 20003843 : }
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 190875034 : 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 18715306 : continue;
774 : }
775 :
776 172156683 : 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 172156683 : if (!neigh)
782 : {
783 2442 : libmesh_assert_equal_to (elem->neighbor_ptr(n), remote_elem);
784 5785889 : 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 37895 : 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 166406247 : if (elem->neighbor_ptr(n) == remote_elem)
799 : {
800 0 : elem->set_neighbor(n, neigh);
801 : }
802 : else
803 37895 : libmesh_assert(elem->subactive() ||
804 : neigh->level() < elem->level() ||
805 : neigh->neighbor_ptr(neighbor_side) == elem);
806 :
807 166368352 : if (neighbor_side != libMesh::invalid_uint)
808 166361849 : 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 49964175 : 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 4106 : 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 30070715 : Elem * parent = nullptr;
839 : #ifdef LIBMESH_ENABLE_AMR
840 : // Find a child element's parent
841 30116001 : 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 25281983 : parent = mesh->elem_ptr(parent_id);
848 : }
849 : // Or assert that the sending processor sees no parent
850 : else
851 44934 : 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 30116001 : if (type == C0POLYGON)
858 59 : elem = std::make_unique<C0Polygon>(n_nodes, parent).release();
859 30115942 : else if (type == C0POLYHEDRON)
860 : {
861 108 : std::vector<std::shared_ptr<Polygon>> sides(n_sides);
862 860 : for (auto s : index_range(sides))
863 : {
864 16 : const auto & side_nodes = polyhedron_side_nodes[s];
865 : auto side = std::make_shared<C0Polygon>
866 770 : (cast_int<unsigned int>(side_nodes.size()));
867 4006 : for (auto n : index_range(side_nodes))
868 : {
869 : const dof_id_type node_id =
870 : cast_int<dof_id_type>
871 3324 : (*(node_ids_in + side_nodes[n]));
872 3252 : side->set_node(n, mesh->node_ptr(node_id));
873 : }
874 16 : sides[s] = std::move(side);
875 : }
876 :
877 106 : std::unique_ptr<Node> generated_mid_node;
878 : auto polyhedron = std::make_unique<C0Polyhedron>
879 106 : (sides, generated_mid_node, parent);
880 :
881 1 : libmesh_assert_equal_to (polyhedron->n_nodes(), n_nodes);
882 :
883 106 : if (generated_mid_node)
884 : {
885 : const dof_id_type mid_node_id =
886 59 : cast_int<dof_id_type>(*(node_ids_in + n_nodes - 1));
887 60 : polyhedron->set_node(n_nodes - 1,
888 59 : mesh->node_ptr(mid_node_id));
889 : }
890 :
891 1 : elem = polyhedron.release();
892 104 : }
893 : else
894 30115836 : elem = Elem::build(type,parent).release();
895 45286 : libmesh_assert (elem);
896 :
897 : #ifdef LIBMESH_ENABLE_AMR
898 30116001 : 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 352 : libmesh_assert_equal_to (parent->child_ptr(which_child_am_i), remote_elem);
903 :
904 25281983 : parent->add_child(elem, which_child_am_i);
905 : }
906 :
907 : // Assign the refinement flags and levels
908 30116001 : elem->set_p_level(p_level);
909 45286 : elem->set_refinement_flag(refinement_flag);
910 45286 : elem->set_p_refinement_flag(p_refinement_flag);
911 45286 : 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 30116001 : if (has_children)
917 : {
918 6020952 : const unsigned int nc = elem->n_children();
919 30373338 : for (unsigned int c=0; c != nc; ++c)
920 24352386 : elem->add_child(const_cast<RemoteElem *>(remote_elem), c);
921 : }
922 :
923 : #endif // LIBMESH_ENABLE_AMR
924 :
925 : // Assign the IDs
926 30116001 : elem->subdomain_id() = subdomain_id;
927 30116001 : elem->processor_id() = processor_id;
928 30116001 : elem->set_id() = id;
929 : #ifdef LIBMESH_ENABLE_UNIQUE_ID
930 45286 : elem->set_unique_id(unique_id);
931 : #endif
932 :
933 : // Assign the connectivity
934 45286 : libmesh_assert_equal_to (elem->n_nodes(), n_nodes);
935 45286 : libmesh_assert_equal_to (elem->n_sides(), n_sides);
936 45286 : libmesh_assert_equal_to (elem->n_edges(), n_edges);
937 :
938 30116001 : if (!elem->runtime_topology() || elem->dim() != 3)
939 170692281 : for (unsigned int n=0; n != n_nodes; n++)
940 : elem->set_node
941 140815436 : (n, mesh->node_ptr
942 140815436 : (cast_int<dof_id_type>(*(node_ids_in + n))));
943 :
944 : #ifndef NDEBUG
945 284349 : for (unsigned int n = 0; n != n_nodes; ++n)
946 239063 : 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 30116001 : if (interior_parent_id == remote_elem->id())
959 : {
960 : elem->set_interior_parent
961 0 : (const_cast<RemoteElem *>(remote_elem));
962 : }
963 30116001 : 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 11209 : mesh->interior_mesh().query_elem_ptr(interior_parent_id);
969 11209 : if (!ip )
970 : elem->set_interior_parent
971 1065 : (const_cast<RemoteElem *>(remote_elem));
972 : else
973 10144 : elem->set_interior_parent(ip);
974 : }
975 : }
976 :
977 151256434 : for (auto n : elem->side_index_range())
978 : {
979 : const dof_id_type neighbor_id =
980 121140433 : cast_int<dof_id_type>(*in++);
981 :
982 : const dof_id_type neighbor_side =
983 121140433 : cast_int<dof_id_type>(*in++);
984 :
985 121140433 : if (neighbor_id == DofObject::invalid_id)
986 14133694 : 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 106828192 : if (neighbor_id == remote_elem->id())
994 : {
995 3899205 : elem->set_neighbor(n, const_cast<RemoteElem *>(remote_elem));
996 3899205 : continue;
997 : }
998 :
999 : // If we don't have the neighbor element, then it's a
1000 : // remote_elem until we get it.
1001 102928987 : Elem * neigh = mesh->query_elem_ptr(neighbor_id);
1002 102928987 : if (!neigh)
1003 : {
1004 48650132 : elem->set_neighbor(n, const_cast<RemoteElem *>(remote_elem));
1005 48650132 : 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 54278855 : elem->set_neighbor(n, neigh);
1012 :
1013 54278855 : if (neighbor_side != libMesh::invalid_uint)
1014 54277703 : elem->make_links_to_me_local(n, neighbor_side);
1015 : }
1016 :
1017 30116001 : elem->unpack_indexing(in);
1018 :
1019 30116001 : mesh->add_elem(elem);
1020 : }
1021 :
1022 80070486 : in += elem->packed_indexing_size();
1023 :
1024 : // We check if this is cell holds a boundary ID or not
1025 80070486 : auto on_boundary = *in++;
1026 80070486 : 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 12562592 : auto children_on_boundary = *in++;
1032 12562592 : if (elem->level() == 0 || children_on_boundary)
1033 : {
1034 66893092 : for (auto s : elem->side_index_range())
1035 : {
1036 : const boundary_id_type num_bcs =
1037 54330500 : cast_int<boundary_id_type>(*in++);
1038 :
1039 69470893 : for (boundary_id_type bc_it=0; bc_it < num_bcs; bc_it++)
1040 8778 : mesh->get_boundary_info().add_side
1041 15149171 : (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 80070486 : if (level == 0)
1049 : {
1050 210487067 : for (auto e : elem->edge_index_range())
1051 : {
1052 : const boundary_id_type num_bcs =
1053 182278762 : cast_int<boundary_id_type>(*in++);
1054 :
1055 182281946 : for (boundary_id_type bc_it=0; bc_it < num_bcs; bc_it++)
1056 48 : mesh->get_boundary_info().add_edge
1057 3232 : (elem, e, cast_int<boundary_id_type>(*in++));
1058 : }
1059 :
1060 84624915 : for (unsigned short sf=0; sf != 2; ++sf)
1061 : {
1062 : const boundary_id_type num_bcs =
1063 56416610 : cast_int<boundary_id_type>(*in++);
1064 :
1065 56677518 : for (boundary_id_type bc_it=0; bc_it < num_bcs; bc_it++)
1066 3328 : mesh->get_boundary_info().add_shellface
1067 264236 : (elem, sf, cast_int<boundary_id_type>(*in++));
1068 : }
1069 : }
1070 :
1071 : // Return the new element
1072 80125462 : return elem;
1073 79960534 : }
1074 :
1075 :
1076 :
1077 : template <>
1078 : Elem *
1079 16337244 : Packing<Elem *>::unpack (std::vector<largest_id_type>::const_iterator in,
1080 : DistributedMesh * mesh)
1081 : {
1082 16337244 : return unpack(in, static_cast<MeshBase*>(mesh));
1083 : }
1084 :
1085 :
1086 :
1087 : template <>
1088 : Elem *
1089 0 : Packing<Elem *>::unpack (std::vector<largest_id_type>::const_iterator in,
1090 : ParallelMesh * mesh)
1091 : {
1092 0 : return unpack(in, static_cast<MeshBase*>(mesh));
1093 : }
1094 :
1095 : } // namespace Parallel
1096 :
1097 : } // namespace libMesh
|