LCOV - code coverage report
Current view: top level - src/parallel - parallel_elem.C (source / functions) Hit Total Coverage
Test: libMesh/libmesh: #4490 (fb4270) with base e59def Lines: 384 404 95.0 %
Date: 2026-07-23 17:02:07 Functions: 8 11 72.7 %
Legend: Lines: hit not hit

          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/enum_to_string.h"
      28             : #include "libmesh/face_c0polygon.h"
      29             : #include "libmesh/int_range.h"
      30             : #include "libmesh/mesh_base.h"
      31             : #include "libmesh/parallel_elem.h"
      32             : #include "libmesh/parallel_mesh.h"
      33             : #include "libmesh/remote_elem.h"
      34             : 
      35             : // Helper functions in anonymous namespace
      36             : 
      37             : namespace
      38             : {
      39             : using namespace libMesh;
      40             : 
      41             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
      42             : static const unsigned int header_size = 12;
      43             : #else
      44             : static const unsigned int header_size = 11;
      45             : #endif
      46             : 
      47             : #ifndef NDEBUG
      48             : // Currently this constant is only used for debugging.
      49             : static const largest_id_type elem_magic_header = 987654321;
      50             : #endif
      51             : }
      52             : 
      53             : 
      54             : namespace libMesh
      55             : {
      56             : 
      57             : namespace Parallel
      58             : {
      59             : 
      60             : template <>
      61             : unsigned int
      62      219293 : Packing<const Elem *>::packed_size (std::vector<largest_id_type>::const_iterator in)
      63             : {
      64             : #ifndef NDEBUG
      65      108932 :   const largest_id_type packed_header = *in++;
      66      108932 :   libmesh_assert_equal_to (packed_header, elem_magic_header);
      67             : #endif
      68             : 
      69             :   // int 0: level
      70             :   const unsigned int level =
      71      219293 :     cast_int<unsigned int>(*in);
      72             : 
      73             :   // int 4: element type
      74      219293 :   const int typeint = cast_int<int>(*(in+4));
      75      108932 :   libmesh_assert_greater_equal (typeint, 0);
      76      108932 :   libmesh_assert_less (typeint, INVALID_ELEM);
      77             :   const ElemType type =
      78      108932 :     cast_int<ElemType>(typeint);
      79             : 
      80      219293 :   unsigned int n_nodes = Elem::type_to_n_nodes_map[type];
      81      219293 :   unsigned int n_sides = Elem::type_to_n_sides_map[type];
      82      219293 :   unsigned int n_edges = Elem::type_to_n_edges_map[type];
      83      108932 :   unsigned int variable_topology_size = 0;
      84             : 
      85      219293 :   if (n_nodes == invalid_uint)
      86             :     {
      87           8 :       libmesh_error_msg_if(type != C0POLYGON && type != C0POLYHEDRON,
      88             :                            "Unsupported variable-topology element "
      89             :                            << Utility::enum_to_string(type));
      90             : 
      91           4 :       auto topology_in = in + header_size;
      92           8 :       n_nodes = cast_int<unsigned int>(*topology_in++);
      93           8 :       n_sides = cast_int<unsigned int>(*topology_in++);
      94           8 :       n_edges = cast_int<unsigned int>(*topology_in++);
      95           4 :       variable_topology_size = 3;
      96             : 
      97           8 :       if (type == C0POLYHEDRON)
      98             :         {
      99           2 :           topology_in += n_nodes;
     100          36 :           for (unsigned int s = 0; s != n_sides; ++s)
     101             :             {
     102             :               const unsigned int n_side_nodes =
     103          32 :                 cast_int<unsigned int>(*topology_in++);
     104          16 :               topology_in += n_side_nodes;
     105          32 :               variable_topology_size += n_side_nodes + 1;
     106             :             }
     107             :         }
     108             :     }
     109             : 
     110      219293 :   const unsigned int pre_indexing_size =
     111      219293 :     header_size + variable_topology_size + n_nodes + n_sides*2;
     112             : 
     113             :   const unsigned int indexing_size =
     114      219293 :     DofObject::unpackable_indexing_size(in+pre_indexing_size);
     115             : 
     116             :   // We communicate if we are on the boundary or not
     117      108932 :   unsigned int total_packed_bc_data = 1;
     118      219293 :   largest_id_type on_boundary = *(in + pre_indexing_size + indexing_size);
     119             : 
     120      219293 :   if (on_boundary)
     121             :   {
     122             :     // Extracting if the children are allowed on the boundary
     123       12299 :     total_packed_bc_data++;
     124       25123 :     largest_id_type allow_children_on_boundary = *(in + pre_indexing_size + indexing_size + 1);
     125             : 
     126             :     // For now, children are only supported on sides, the nodes and shell faces are
     127             :     // treated using the top parents only
     128       25123 :     if (level == 0 || allow_children_on_boundary)
     129             :     {
     130      140295 :       for (unsigned int s = 0; s != n_sides; ++s)
     131             :       {
     132             :         const int n_bcs = cast_int<int>
     133      171304 :           (*(in + pre_indexing_size + indexing_size +
     134      171304 :             total_packed_bc_data++));
     135       56132 :         libmesh_assert_greater_equal (n_bcs, 0);
     136      115172 :         total_packed_bc_data += n_bcs;
     137             :       }
     138             :     }
     139             :   }
     140      219293 :   if (level == 0)
     141             :     {
     142     1442783 :       for (unsigned int e = 0; e != n_edges; ++e)
     143             :         {
     144             :           const int n_bcs = cast_int<int>
     145     1857996 :             (*(in + pre_indexing_size + indexing_size +
     146     1857996 :               total_packed_bc_data++));
     147      617354 :           libmesh_assert_greater_equal (n_bcs, 0);
     148     1240642 :           total_packed_bc_data += n_bcs;
     149             :         }
     150             : 
     151      606423 :       for (unsigned short sf=0; sf != 2; ++sf)
     152             :         {
     153             :           const int n_bcs = cast_int<int>
     154      605442 :             (*(in + pre_indexing_size + indexing_size +
     155      605442 :               total_packed_bc_data++));
     156      201160 :           libmesh_assert_greater_equal (n_bcs, 0);
     157      404282 :           total_packed_bc_data += n_bcs;
     158             :         }
     159             :     }
     160             : 
     161             :   return
     162             : #ifndef NDEBUG
     163             :     1 + // Account for magic header
     164             : #endif
     165      219293 :     pre_indexing_size + indexing_size + total_packed_bc_data;
     166             : }
     167             : 
     168             : 
     169             : 
     170             : template <>
     171             : unsigned int
     172       53956 : Packing<const Elem *>::packed_size (std::vector<largest_id_type>::iterator in)
     173             : {
     174       53956 :   return packed_size(std::vector<largest_id_type>::const_iterator(in));
     175             : }
     176             : 
     177             : 
     178             : 
     179             : template <>
     180             : unsigned int
     181      216346 : Packing<const Elem *>::packable_size (const Elem * const & elem,
     182             :                                       const MeshBase * mesh)
     183             : {
     184      107950 :   unsigned int variable_topology_size = 0;
     185      216346 :   if (elem->type() == C0POLYGON || elem->type() == C0POLYHEDRON)
     186             :     {
     187             :       // Store the dynamic node, side, and edge counts.
     188           4 :       variable_topology_size = 3;
     189             : 
     190             :       // A polygon's node ordering fully specifies its topology.  A
     191             :       // polyhedron additionally needs each side's local node indices.
     192           8 :       if (elem->type() == C0POLYHEDRON)
     193          37 :         for (auto s : elem->side_index_range())
     194          32 :           variable_topology_size +=
     195          40 :             1 + cast_int<unsigned int>(elem->nodes_on_side(s).size());
     196             :     }
     197             : 
     198             :   // We always communicate if we are on a boundary or not
     199      107950 :   unsigned int total_packed_bcs = 1;
     200      216346 :   const unsigned int n_sides = elem->n_sides();
     201             : 
     202      107950 :   largest_id_type on_boundary = 0;
     203     1084406 :   for (auto s : elem->side_index_range())
     204      837757 :     if (mesh->get_boundary_info().n_raw_boundary_ids(elem,s))
     205             :     {
     206       11822 :       on_boundary = 1;
     207       11822 :       break;
     208             :     }
     209             : 
     210      216346 :   if (on_boundary)
     211             :   {
     212             :     // In this case we need another entry to check if we allow children on the boundary.
     213             :     // We only allow children on sides, edges and sheel faces are treated normally using
     214             :     // their top parents.
     215       11822 :     total_packed_bcs++;
     216       23691 :     if (elem->level() == 0 || mesh->get_boundary_info().is_children_on_boundary_side())
     217             :     {
     218       23691 :       total_packed_bcs += n_sides;
     219      130861 :       for (unsigned int s = 0; s != n_sides; ++s)
     220      107170 :         total_packed_bcs +=
     221      107170 :           mesh->get_boundary_info().n_raw_boundary_ids(elem,s);
     222             :     }
     223             :   }
     224             : 
     225      216346 :   if (elem->level() == 0)
     226             :     {
     227      200538 :       const unsigned int n_edges = elem->n_edges();
     228      200538 :       total_packed_bcs += n_edges;
     229     1425474 :       for (unsigned int e = 0; e != n_edges; ++e)
     230     1224936 :         total_packed_bcs +=
     231     1224936 :           mesh->get_boundary_info().n_edge_boundary_ids(elem,e);
     232             : 
     233      200538 :       total_packed_bcs += 2; // shellfaces
     234      601614 :       for (unsigned short sf=0; sf != 2; ++sf)
     235      401076 :         total_packed_bcs +=
     236      401076 :           mesh->get_boundary_info().n_shellface_boundary_ids(elem,sf);
     237             :     }
     238             : 
     239             :   return
     240             : #ifndef NDEBUG
     241             :     1 + // add an int for the magic header when testing
     242             : #endif
     243      216346 :     header_size + variable_topology_size + elem->n_nodes() + n_sides*2 +
     244      216346 :     elem->packed_indexing_size() + total_packed_bcs;
     245             : }
     246             : 
     247             : 
     248             : 
     249             : template <>
     250             : unsigned int
     251       30872 : Packing<const Elem *>::packable_size (const Elem * const & elem,
     252             :                                       const DistributedMesh * mesh)
     253             : {
     254       30872 :   return packable_size(elem, static_cast<const MeshBase *>(mesh));
     255             : }
     256             : 
     257             : 
     258             : 
     259             : template <>
     260             : unsigned int
     261           0 : Packing<const Elem *>::packable_size (const Elem * const & elem,
     262             :                                       const ParallelMesh * mesh)
     263             : {
     264           0 :   return packable_size(elem, static_cast<const MeshBase *>(mesh));
     265             : }
     266             : 
     267             : 
     268             : 
     269             : template <>
     270             : void
     271      162280 : Packing<const Elem *>::pack (const Elem * const & elem,
     272             :                              std::back_insert_iterator<std::vector<largest_id_type>> data_out,
     273             :                              const MeshBase * mesh)
     274             : {
     275       53956 :   libmesh_assert(elem);
     276             : 
     277             : #ifndef NDEBUG
     278       53956 :   *data_out++ = elem_magic_header;
     279             : #endif
     280             : 
     281             : #ifdef LIBMESH_ENABLE_AMR
     282      162280 :   *data_out++ = (static_cast<largest_id_type>(elem->level()));
     283      162280 :   *data_out++ = (static_cast<largest_id_type>(elem->p_level()));
     284             : 
     285             :   // Encode both the refinement flag and whether the element has
     286             :   // children together.  This coding is unambiguous because our
     287             :   // refinement state encoding starts at 0 and ends at
     288             :   // INVALID_REFINEMENTSTATE
     289             :   largest_id_type refinement_info =
     290      162280 :     static_cast<largest_id_type>(elem->refinement_flag());
     291       53956 :   if (elem->has_children())
     292        2790 :     refinement_info +=
     293             :       static_cast<largest_id_type>(Elem::INVALID_REFINEMENTSTATE) + 1;
     294       53956 :   *data_out++ = (refinement_info);
     295             : 
     296      162280 :   *data_out++ = (static_cast<largest_id_type>(elem->p_refinement_flag()));
     297             : #else
     298             :   *data_out++ = (0);
     299             :   *data_out++ = (0);
     300             :   *data_out++ = (0);
     301             :   *data_out++ = (0);
     302             : #endif
     303      162280 :   *data_out++ = (static_cast<largest_id_type>(elem->type()));
     304      162280 :   *data_out++ = (elem->processor_id());
     305      162280 :   *data_out++ = (elem->subdomain_id());
     306      162280 :   *data_out++ = (elem->id());
     307             : 
     308             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
     309      162280 :   if (elem->valid_unique_id())
     310      162280 :     *data_out++ = (static_cast<largest_id_type>(elem->unique_id()));
     311             :   else
     312             :     // OK to send invalid unique id, we must not own this DOF
     313           0 :     *data_out++ = (static_cast<largest_id_type>(DofObject::invalid_unique_id));
     314             : #endif
     315             : 
     316             : #ifdef LIBMESH_ENABLE_AMR
     317             :   // use parent_ID of invalid_id to indicate a level 0 element
     318      162280 :   if (elem->level() == 0)
     319             :     {
     320      100008 :       *data_out++ =(DofObject::invalid_id);
     321      100008 :       *data_out++ =(DofObject::invalid_id);
     322             :     }
     323             :   else
     324             :     {
     325       15808 :       *data_out++ =(elem->parent()->id());
     326       15808 :       *data_out++ =(elem->parent()->which_child_am_i(elem));
     327             :     }
     328             : #else
     329             :   *data_out++ = (DofObject::invalid_id);
     330             :   *data_out++ = (DofObject::invalid_id);
     331             : #endif
     332             : 
     333      219383 :   if ((elem->dim() < LIBMESH_DIM) &&
     334       57103 :       elem->interior_parent())
     335          84 :     *data_out++ =(elem->interior_parent()->id());
     336             :   else
     337      107856 :     *data_out++ =(DofObject::invalid_id);
     338             : 
     339             :   const bool has_variable_topology =
     340      162280 :     elem->type() == C0POLYGON || elem->type() == C0POLYHEDRON;
     341       53956 :   if (has_variable_topology)
     342             :     {
     343           6 :       *data_out++ = elem->n_nodes();
     344           6 :       *data_out++ = elem->n_sides();
     345           6 :       *data_out++ = elem->n_edges();
     346             :     }
     347             : 
     348     1194439 :   for (const Node & node : elem->node_ref_range())
     349      978203 :     *data_out++ = node.id();
     350             : 
     351      162280 :   if (elem->type() == C0POLYHEDRON)
     352          28 :     for (auto s : elem->side_index_range())
     353             :       {
     354             :         const std::vector<unsigned int> side_nodes =
     355          32 :           elem->nodes_on_side(s);
     356          40 :         *data_out++ = side_nodes.size();
     357         132 :         for (const auto node : side_nodes)
     358         144 :           *data_out++ = node;
     359             :       }
     360             : 
     361             :   // Add the id of and the side for any return link from each neighbor
     362      887411 :   for (auto neigh : elem->neighbor_ptr_range())
     363             :     {
     364      671175 :       if (neigh)
     365             :       {
     366      124418 :         *data_out++ = (neigh->id());
     367      124418 :         if (neigh == remote_elem)
     368        5970 :           *data_out++ = (DofObject::invalid_id);
     369             :         else
     370      115455 :           *data_out++ = neigh->which_neighbor_am_i(elem);
     371             :       }
     372             :       else
     373             :       {
     374      364294 :         *data_out++ = (DofObject::invalid_id);
     375      364294 :         *data_out++ = (DofObject::invalid_id);
     376             :       }
     377             :     }
     378             : 
     379             :   // Add any DofObject indices
     380      162280 :   elem->pack_indexing(data_out);
     381             : 
     382             :   // We check if this is a boundary cell. We use the raw
     383             :   // IDs because we also communicate the parents which
     384             :   // will bring their associated IDs
     385      162280 :   largest_id_type on_boundary = 0;
     386      826722 :   for (auto s : elem->side_index_range())
     387      628185 :     if (mesh->get_boundary_info().n_raw_boundary_ids(elem,s))
     388             :     {
     389       17699 :       on_boundary = 1;
     390       17699 :       break;
     391             :     }
     392             : 
     393       53956 :   *data_out++ = on_boundary;
     394             : 
     395      162280 :   if (on_boundary)
     396             :   {
     397       17699 :     *data_out++ = mesh->get_boundary_info().is_children_on_boundary_side();
     398             :     // Again, only do this if we allow children to hold boundary sides, the edges and
     399             :     // shell faces are treated normally using their top parents
     400       17699 :     if (elem->level() == 0 || mesh->get_boundary_info().is_children_on_boundary_side())
     401             :     {
     402       11788 :       std::vector<boundary_id_type> bcs;
     403      103711 :       for (auto s : elem->side_index_range())
     404             :       {
     405       80118 :         mesh->get_boundary_info().raw_boundary_ids(elem, s, bcs);
     406             : 
     407      133570 :         *data_out++ =(bcs.size());
     408             : 
     409      103230 :         for (const auto & bid : bcs)
     410       30840 :           *data_out++ = bid;
     411             :       }
     412             :     }
     413             :   }
     414             : 
     415             :   // If this is a coarse element,
     416             :   // Add any element side boundary condition ids
     417      162280 :   if (elem->level() == 0)
     418             :   {
     419      100008 :     std::vector<boundary_id_type> bcs;
     420     1118945 :     for (auto e : elem->edge_index_range())
     421             :       {
     422      918517 :         mesh->get_boundary_info().edge_boundary_ids(elem, e, bcs);
     423             : 
     424     1531049 :         *data_out++ =(bcs.size());
     425             : 
     426      918661 :         for (const auto & bid : bcs)
     427         192 :           *data_out++ = bid;
     428             :       }
     429             : 
     430      451272 :     for (unsigned short sf=0; sf != 2; ++sf)
     431             :       {
     432      300848 :         mesh->get_boundary_info().shellface_boundary_ids(elem, sf, bcs);
     433             : 
     434      501688 :         *data_out++ =(bcs.size());
     435             : 
     436      310832 :         for (const auto & bid : bcs)
     437       13312 :           *data_out++ = bid;
     438             :       }
     439             :   }
     440      162280 : }
     441             : 
     442             : 
     443             : 
     444             : template <>
     445             : void
     446       23070 : Packing<const Elem *>::pack (const Elem * const & elem,
     447             :                              std::back_insert_iterator<std::vector<largest_id_type>> data_out,
     448             :                              const DistributedMesh * mesh)
     449             : {
     450       23070 :   pack(elem, data_out, static_cast<const MeshBase*>(mesh));
     451       23070 : }
     452             : 
     453             : 
     454             : 
     455             : template <>
     456             : void
     457           0 : Packing<const Elem *>::pack (const Elem * const & elem,
     458             :                              std::back_insert_iterator<std::vector<largest_id_type>> data_out,
     459             :                              const ParallelMesh * mesh)
     460             : {
     461           0 :   pack(elem, data_out, static_cast<const MeshBase*>(mesh));
     462           0 : }
     463             : 
     464             : 
     465             : 
     466             : // FIXME - this needs serious work to be 64-bit compatible
     467             : template <>
     468             : Elem *
     469      165337 : Packing<Elem *>::unpack (std::vector<largest_id_type>::const_iterator in,
     470             :                          MeshBase * mesh)
     471             : {
     472             : #ifndef NDEBUG
     473       54976 :   const std::vector<largest_id_type>::const_iterator original_in = in;
     474             : 
     475       54976 :   const largest_id_type incoming_header = *in++;
     476       54976 :   libmesh_assert_equal_to (incoming_header, elem_magic_header);
     477             : #endif
     478             : 
     479             :   // int 0: level
     480             :   const unsigned int level =
     481      165337 :     cast_int<unsigned int>(*in++);
     482             : 
     483             : #ifdef LIBMESH_ENABLE_AMR
     484             :   // int 1: p level
     485             :   const unsigned int p_level =
     486      165337 :     cast_int<unsigned int>(*in++);
     487             : 
     488             :   // int 2: refinement flag and encoded has_children
     489      165337 :   const int rflag = cast_int<int>(*in++);
     490             :   const int invalid_rflag =
     491       54976 :     cast_int<int>(Elem::INVALID_REFINEMENTSTATE);
     492       54976 :   libmesh_assert_greater_equal (rflag, 0);
     493             : 
     494       54976 :   libmesh_assert_less (rflag, invalid_rflag*2+1);
     495             : 
     496       54976 :   const bool has_children = (rflag > invalid_rflag);
     497             : 
     498      165337 :   const Elem::RefinementState refinement_flag = has_children ?
     499        3192 :     cast_int<Elem::RefinementState>(rflag - invalid_rflag - 1) :
     500       53912 :     cast_int<Elem::RefinementState>(rflag);
     501             : 
     502             :   // int 3: p refinement flag
     503      165337 :   const int pflag = cast_int<int>(*in++);
     504       54976 :   libmesh_assert_greater_equal (pflag, 0);
     505       54976 :   libmesh_assert_less (pflag, Elem::INVALID_REFINEMENTSTATE);
     506             :   const Elem::RefinementState p_refinement_flag =
     507       54976 :     cast_int<Elem::RefinementState>(pflag);
     508             : #else
     509             :   in += 3;
     510             : #endif // LIBMESH_ENABLE_AMR
     511             : 
     512             :   // int 4: element type
     513      165337 :   const int typeint = cast_int<int>(*in++);
     514       54976 :   libmesh_assert_greater_equal (typeint, 0);
     515       54976 :   libmesh_assert_less (typeint, INVALID_ELEM);
     516             :   const ElemType type =
     517       54976 :     cast_int<ElemType>(typeint);
     518             : 
     519      165337 :   unsigned int n_nodes = Elem::type_to_n_nodes_map[type];
     520      165337 :   unsigned int n_sides = Elem::type_to_n_sides_map[type];
     521      165337 :   unsigned int n_edges = Elem::type_to_n_edges_map[type];
     522             : 
     523             :   // int 5: processor id
     524             :   const processor_id_type processor_id =
     525      165337 :     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      165337 :     cast_int<subdomain_id_type>(*in++);
     532             : 
     533             :   // int 7: dof object id
     534             :   const dof_id_type id =
     535      165337 :     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      165337 :     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      165337 :     ? static_cast<dof_id_type>(*in++)
     553       13200 :     : 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      165337 :     ? static_cast<unsigned int>(*in++)
     563       13200 :     : 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      165337 :     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      165337 :   if (n_nodes == invalid_uint)
     576             :     {
     577           6 :       libmesh_error_msg_if(type != C0POLYGON && type != C0POLYHEDRON,
     578             :                            "Unsupported variable-topology element "
     579             :                            << Utility::enum_to_string(type));
     580             : 
     581           6 :       n_nodes = cast_int<unsigned int>(*in++);
     582           6 :       n_sides = cast_int<unsigned int>(*in++);
     583           6 :       n_edges = cast_int<unsigned int>(*in++);
     584             : 
     585           6 :       if (type == C0POLYGON)
     586           3 :         libmesh_error_msg_if
     587             :           (n_nodes < 3 || n_sides != n_nodes || n_edges != n_nodes,
     588             :            "Invalid packed C0POLYGON topology with "
     589             :            << n_nodes << " nodes, " << n_sides << " sides, and "
     590             :            << n_edges << " edges");
     591             :       else
     592           3 :         libmesh_error_msg_if
     593             :           (n_nodes < 4 || n_sides < 4,
     594             :            "Invalid packed C0POLYHEDRON topology with "
     595             :            << n_nodes << " nodes and " << n_sides << " sides");
     596             :     }
     597             : 
     598       54976 :   const auto node_ids_in = in;
     599      110361 :   in += n_nodes;
     600             : 
     601      109952 :   std::vector<std::vector<unsigned int>> polyhedron_side_nodes;
     602      165337 :   if (type == C0POLYHEDRON)
     603             :     {
     604           3 :       polyhedron_side_nodes.resize(n_sides);
     605           4 :       std::vector<bool> node_seen(n_nodes, false);
     606           1 :       unsigned int next_new_node = 0;
     607          27 :       for (auto & side_nodes : polyhedron_side_nodes)
     608             :         {
     609             :           const unsigned int n_side_nodes =
     610          24 :             cast_int<unsigned int>(*in++);
     611          24 :           libmesh_error_msg_if(n_side_nodes < 3,
     612             :                                "Cannot unpack a C0POLYHEDRON side with only "
     613             :                                << n_side_nodes << " nodes");
     614          24 :           side_nodes.resize(n_side_nodes);
     615         132 :           for (auto & node : side_nodes)
     616             :             {
     617         108 :               node = cast_int<unsigned int>(*in++);
     618         108 :               libmesh_error_msg_if(node >= n_nodes,
     619             :                                    "Invalid local node " << node
     620             :                                    << " in packed C0POLYHEDRON side");
     621             : 
     622         144 :               if (!node_seen[node])
     623             :                 {
     624          36 :                   libmesh_error_msg_if
     625             :                     (node != next_new_node,
     626             :                      "Packed C0POLYHEDRON side connectivity first encounters "
     627             :                      "local node " << node << " where local node "
     628             :                      << next_new_node << " was expected");
     629          12 :                   node_seen[node] = true;
     630          36 :                   ++next_new_node;
     631             :                 }
     632             :             }
     633             :         }
     634             : 
     635           3 :       libmesh_error_msg_if
     636             :         (next_new_node != n_nodes && next_new_node + 1 != n_nodes,
     637             :          "Packed C0POLYHEDRON sides reference " << next_new_node
     638             :          << " vertices, but the element has " << n_nodes
     639             :          << " nodes; at most one unreferenced midpoint node is permitted");
     640             :     }
     641             : 
     642      165337 :   Elem * elem = mesh->query_elem_ptr(id);
     643             : 
     644             :   // if we already have this element, make sure its
     645             :   // properties match, and update any missing neighbor
     646             :   // links, but then go on
     647      165337 :   if (elem)
     648             :     {
     649        9690 :       libmesh_assert_equal_to (elem->level(), level);
     650        9690 :       libmesh_assert_equal_to (elem->id(), id);
     651             :       //#ifdef LIBMESH_ENABLE_UNIQUE_ID
     652             :       // No check for unique id sanity
     653             :       //#endif
     654        9690 :       libmesh_assert_equal_to (elem->processor_id(), processor_id);
     655        9690 :       libmesh_assert_equal_to (elem->subdomain_id(), subdomain_id);
     656        9690 :       libmesh_assert_equal_to (elem->type(), type);
     657             : 
     658       29061 :       if (type == C0POLYGON || type == C0POLYHEDRON)
     659             :         {
     660           0 :           libmesh_error_msg_if
     661             :             (elem->type() != type ||
     662             :              elem->n_nodes() != n_nodes ||
     663             :              elem->n_sides() != n_sides ||
     664             :              elem->n_edges() != n_edges,
     665             :              "Existing " << Utility::enum_to_string(type)
     666             :              << " topology does not match its packed topology");
     667             : 
     668           0 :           for (unsigned int n = 0; n != n_nodes; ++n)
     669           0 :             libmesh_error_msg_if
     670             :               (elem->node_id(n) !=
     671             :                cast_int<dof_id_type>(*(node_ids_in + n)),
     672             :                "Existing " << Utility::enum_to_string(type)
     673             :                << " local node " << n
     674             :                << " does not match its packed node");
     675             : 
     676           0 :           if (type == C0POLYHEDRON)
     677           0 :             for (auto s : elem->side_index_range())
     678           0 :               libmesh_error_msg_if
     679             :                 (elem->nodes_on_side(s) != polyhedron_side_nodes[s],
     680             :                  "Existing C0POLYHEDRON side " << s
     681             :                  << " does not match its packed topology");
     682             :         }
     683             : 
     684        9690 :       libmesh_assert_equal_to (elem->n_nodes(), n_nodes);
     685        9690 :       libmesh_assert_equal_to (elem->n_sides(), n_sides);
     686        9690 :       libmesh_assert_equal_to (elem->n_edges(), n_edges);
     687             : 
     688             : #ifndef NDEBUG
     689             :       // All our nodes should be correct
     690      105990 :       for (unsigned int i=0; i != n_nodes; ++i)
     691       96300 :         libmesh_assert(elem->node_id(i) ==
     692             :                        cast_int<dof_id_type>(*(node_ids_in + i)));
     693             : #endif
     694             : 
     695             : #ifdef LIBMESH_ENABLE_AMR
     696        9690 :       libmesh_assert_equal_to (elem->refinement_flag(), refinement_flag);
     697        9690 :       libmesh_assert_equal_to (elem->has_children(), has_children);
     698             : 
     699             : #ifdef DEBUG
     700        9690 :       if (elem->active())
     701             :         {
     702        8712 :           libmesh_assert_equal_to (elem->p_level(), p_level);
     703        8712 :           libmesh_assert_equal_to (elem->p_refinement_flag(), p_refinement_flag);
     704             :         }
     705             : #endif
     706             : 
     707        9690 :       libmesh_assert (!level || elem->parent() != nullptr);
     708        9690 :       libmesh_assert (!level || elem->parent()->id() == parent_id);
     709        9690 :       libmesh_assert (!level || elem->parent()->child_ptr(which_child_am_i) == elem);
     710             : #endif
     711             :       // Our interior_parent link should be "close to" correct - we
     712             :       // may have to update it, but we can check for some
     713             :       // inconsistencies.
     714             :       {
     715             :         // If the sending processor sees no interior_parent here, we'd
     716             :         // better agree.
     717       29061 :         if (interior_parent_id == DofObject::invalid_id)
     718             :           {
     719       28977 :             if (elem->dim() < LIBMESH_DIM)
     720        2623 :               libmesh_assert (!(elem->interior_parent()));
     721             :           }
     722             : 
     723             :         // If the sending processor has a remote_elem interior_parent,
     724             :         // then all we know is that we'd better have *some*
     725             :         // interior_parent
     726          84 :         else if (interior_parent_id == remote_elem->id())
     727             :           {
     728           0 :             libmesh_assert(elem->interior_parent());
     729             :           }
     730             :         else
     731             :           {
     732             :             Elem * ip =
     733          84 :               mesh->interior_mesh().query_elem_ptr(interior_parent_id);
     734             : 
     735             :             // The sending processor sees an interior parent here, so
     736             :             // if we don't have that interior element, then we'd
     737             :             // better have a remote_elem signifying that fact.
     738          84 :             if (!ip)
     739           0 :               libmesh_assert_equal_to (elem->interior_parent(), remote_elem);
     740             :             else
     741             :               {
     742             :                 // The sending processor has an interior_parent here,
     743             :                 // and we have that element, but that does *NOT* mean
     744             :                 // we're already linking to it.  Perhaps we initially
     745             :                 // received elem from a processor on which the
     746             :                 // interior_parent link was remote?
     747          28 :                 libmesh_assert(elem->interior_parent() == ip ||
     748             :                                elem->interior_parent() == remote_elem);
     749             : 
     750             :                 // If the link was originally remote, update it
     751          84 :                 if (elem->interior_parent() == remote_elem)
     752             :                   {
     753           0 :                     elem->set_interior_parent(ip);
     754             :                   }
     755             :               }
     756             :           }
     757             :       }
     758             : 
     759             :       // Our neighbor links should be "close to" correct - we may have
     760             :       // to update a remote_elem link, and we can check for possible
     761             :       // inconsistencies along the way.
     762             :       //
     763             :       // Even for subactive elements, we'll try to keep neighbor links
     764             :       // in good shape now, if only so any future find_neighbors() is
     765             :       // idempotent.
     766      173823 :       for (auto n : elem->side_index_range())
     767             :         {
     768             :           const dof_id_type neighbor_id =
     769      144762 :             cast_int<dof_id_type>(*in++);
     770             : 
     771             :           const dof_id_type neighbor_side =
     772      144762 :             cast_int<dof_id_type>(*in++);
     773             : 
     774             :           // If the sending processor sees a domain boundary here,
     775             :           // we'd better agree ... unless all we see is a remote_elem?
     776             :           // In that case maybe we just couldn't keep up with a user's
     777             :           // delete_elem.  Let's trust them.
     778      144762 :           if (neighbor_id == DofObject::invalid_id)
     779             :             {
     780       14634 :               const Elem * my_neigh = elem->neighbor_ptr(n);
     781       14634 :               if (my_neigh == remote_elem)
     782           1 :                 elem->set_neighbor(n, nullptr);
     783             :               else
     784        4883 :                 libmesh_assert (!my_neigh);
     785       14634 :               continue;
     786        4866 :             }
     787             : 
     788             :           // If the sending processor has a remote_elem neighbor here,
     789             :           // then all we know is that we'd better *not* have a domain
     790             :           // boundary ... except that maybe it's the *sending*
     791             :           // processor who missed a delete_elem we saw.
     792      130128 :           if (neighbor_id == remote_elem->id())
     793             :             {
     794             :               // At this level of the code we can't even assert in
     795             :               // cases where the neighbor should know what they're
     796             :               // talking about, so skip it.
     797             : 
     798             :               // libmesh_assert(elem->neighbor_ptr(n));
     799        6104 :               continue;
     800             :             }
     801             : 
     802      120979 :           Elem * neigh = mesh->query_elem_ptr(neighbor_id);
     803             : 
     804             :           // The sending processor sees a neighbor here, so if we
     805             :           // don't have that neighboring element, then we'd better
     806             :           // have a remote_elem signifying that fact.
     807      120979 :           if (!neigh)
     808             :             {
     809        2442 :               libmesh_assert_equal_to (elem->neighbor_ptr(n), remote_elem);
     810        4884 :               continue;
     811             :             }
     812             : 
     813             :           // The sending processor has a neighbor here, and we have
     814             :           // that element, but that does *NOT* mean we're already
     815             :           // linking to it.  Perhaps we initially received both elem
     816             :           // and neigh from processors on which their mutual link was
     817             :           // remote?
     818       37895 :           libmesh_assert(elem->neighbor_ptr(n) == neigh ||
     819             :                          elem->neighbor_ptr(n) == remote_elem);
     820             : 
     821             :           // If the link was originally remote, we should update it,
     822             :           // and make sure the appropriate parts of its family link
     823             :           // back to us.
     824      151548 :           if (elem->neighbor_ptr(n) == remote_elem)
     825             :             {
     826           0 :               elem->set_neighbor(n, neigh);
     827             :             }
     828             :           else
     829       37895 :             libmesh_assert(elem->subactive() ||
     830             :                            neigh->level() < elem->level() ||
     831             :                            neigh->neighbor_ptr(neighbor_side) == elem);
     832             : 
     833      113653 :           if (neighbor_side != libMesh::invalid_uint)
     834      113653 :             elem->make_links_to_me_local(n, neighbor_side);
     835             :         }
     836             : 
     837             :       // Our p level and refinement flags should be "close to" correct
     838             :       // if we're not an active element - we might have a p level
     839             :       // increased or decreased by changes in remote_elem children.
     840             :       //
     841             :       // But if we have remote_elem children, then we shouldn't be
     842             :       // doing a projection on this inactive element on this
     843             :       // processor, so we won't need correct p settings.  Couldn't
     844             :       // hurt to update, though.
     845             : #ifdef LIBMESH_ENABLE_AMR
     846       38751 :       if (elem->processor_id() != mesh->processor_id())
     847             :         {
     848             :           // Do this simultaneously; otherwise we can get a false
     849             :           // positive when a hack_p_level or set_p_refineemnt_flag
     850             :           // assertion sees inconsistency between an old flag and new
     851             :           // value or vice-versa
     852        4106 :           elem->hack_p_level_and_refinement_flag(p_level, p_refinement_flag);
     853             :         }
     854             : #endif // LIBMESH_ENABLE_AMR
     855             : 
     856             :       // FIXME: We should add some debug mode tests to ensure that the
     857             :       // encoded indexing and boundary conditions are consistent.
     858             :     }
     859             :   else
     860             :     {
     861             :       // We don't already have the element, so we need to create it.
     862             : 
     863             :       // Find the parent if necessary
     864       90990 :       Elem * parent = nullptr;
     865             : #ifdef LIBMESH_ENABLE_AMR
     866             :       // Find a child element's parent
     867      136276 :       if (level > 0)
     868             :         {
     869             :           // Note that we must be very careful to construct the send
     870             :           // connectivity so that parents are encountered before
     871             :           // children.  If we get here and can't find the parent that
     872             :           // is a fatal error.
     873        1056 :           parent = mesh->elem_ptr(parent_id);
     874             :         }
     875             :       // Or assert that the sending processor sees no parent
     876             :       else
     877       44934 :         libmesh_assert_equal_to (parent_id, DofObject::invalid_id);
     878             : #else
     879             :       // No non-level-0 elements without AMR
     880             :       libmesh_assert_equal_to (level, 0);
     881             : #endif
     882             : 
     883      136276 :       if (type == C0POLYGON)
     884           3 :         elem = std::make_unique<C0Polygon>(n_nodes, parent).release();
     885      136273 :       else if (type == C0POLYHEDRON)
     886             :         {
     887           5 :           std::vector<std::shared_ptr<Polygon>> sides(n_sides);
     888          27 :           for (auto s : index_range(sides))
     889             :             {
     890          16 :               const auto & side_nodes = polyhedron_side_nodes[s];
     891             :               auto side = std::make_shared<C0Polygon>
     892          40 :                 (cast_int<unsigned int>(side_nodes.size()));
     893         132 :               for (auto n : index_range(side_nodes))
     894             :                 {
     895             :                   const dof_id_type node_id =
     896             :                     cast_int<dof_id_type>
     897         180 :                     (*(node_ids_in + side_nodes[n]));
     898         108 :                   side->set_node(n, mesh->node_ptr(node_id));
     899             :                 }
     900          16 :               sides[s] = std::move(side);
     901             :             }
     902             : 
     903           3 :           std::unique_ptr<Node> generated_mid_node;
     904             :           auto polyhedron = std::make_unique<C0Polyhedron>
     905           3 :             (sides, generated_mid_node, parent);
     906             : 
     907           3 :           libmesh_error_msg_if
     908             :             (polyhedron->n_nodes() != n_nodes,
     909             :              "Packed C0POLYHEDRON has " << n_nodes
     910             :              << " nodes, but reconstructing its topology produced "
     911             :              << polyhedron->n_nodes() << " nodes");
     912             : 
     913           3 :           if (generated_mid_node)
     914             :             {
     915             :               const dof_id_type mid_node_id =
     916           3 :                 cast_int<dof_id_type>(*(node_ids_in + n_nodes - 1));
     917           4 :               polyhedron->set_node(n_nodes - 1,
     918           3 :                                    mesh->node_ptr(mid_node_id));
     919             :             }
     920             : 
     921           1 :           elem = polyhedron.release();
     922           1 :         }
     923             :       else
     924      136270 :         elem = Elem::build(type,parent).release();
     925       45286 :       libmesh_assert (elem);
     926             : 
     927             : #ifdef LIBMESH_ENABLE_AMR
     928      136276 :       if (level != 0)
     929             :         {
     930             :           // Since this is a newly created element, the parent must
     931             :           // have previously thought of this child as a remote element.
     932         352 :           libmesh_assert_equal_to (parent->child_ptr(which_child_am_i), remote_elem);
     933             : 
     934        1056 :           parent->add_child(elem, which_child_am_i);
     935             :         }
     936             : 
     937             :       // Assign the refinement flags and levels
     938      136276 :       elem->set_p_level(p_level);
     939       45286 :       elem->set_refinement_flag(refinement_flag);
     940       45286 :       elem->set_p_refinement_flag(p_refinement_flag);
     941       45286 :       libmesh_assert_equal_to (elem->level(), level);
     942             : 
     943             :       // If this element should have children, assign remote_elem to
     944             :       // all of them for now, for consistency.  Later unpacked
     945             :       // elements may overwrite that.
     946      136276 :       if (has_children)
     947             :         {
     948         258 :           const unsigned int nc = elem->n_children();
     949        1206 :           for (unsigned int c=0; c != nc; ++c)
     950         948 :             elem->add_child(const_cast<RemoteElem *>(remote_elem), c);
     951             :         }
     952             : 
     953             : #endif // LIBMESH_ENABLE_AMR
     954             : 
     955             :       // Assign the IDs
     956      136276 :       elem->subdomain_id()  = subdomain_id;
     957      136276 :       elem->processor_id()  = processor_id;
     958      136276 :       elem->set_id()        = id;
     959             : #ifdef LIBMESH_ENABLE_UNIQUE_ID
     960       45286 :       elem->set_unique_id(unique_id);
     961             : #endif
     962             : 
     963             :       // Assign the connectivity
     964       45286 :       libmesh_assert_equal_to (elem->n_nodes(), n_nodes);
     965             : 
     966      136276 :       if (type == C0POLYHEDRON)
     967             :         {
     968           3 :           libmesh_error_msg_if(elem->n_sides() != n_sides,
     969             :                                "Packed C0POLYHEDRON has " << n_sides
     970             :                                << " sides, but reconstructing its topology produced "
     971             :                                << elem->n_sides() << " sides");
     972           3 :           libmesh_error_msg_if(elem->n_edges() != n_edges,
     973             :                                "Packed C0POLYHEDRON has " << n_edges
     974             :                                << " edges, but reconstructing its topology produced "
     975             :                                << elem->n_edges() << " edges");
     976             : 
     977          42 :           for (unsigned int n = 0; n != n_nodes; ++n)
     978          65 :             libmesh_error_msg_if
     979             :               (elem->node_id(n) !=
     980             :                cast_int<dof_id_type>(*(node_ids_in + n)),
     981             :                "Packed C0POLYHEDRON local node ordering was not preserved");
     982             :         }
     983             :       else
     984      855117 :         for (unsigned int n=0; n != n_nodes; n++)
     985             :           elem->set_node
     986      957894 :             (n, mesh->node_ptr
     987      957894 :              (cast_int<dof_id_type>(*(node_ids_in + n))));
     988             : 
     989             :       // Set interior_parent if found
     990             :       {
     991             :         // We may be unpacking an element that was a ghost element on the
     992             :         // sender, in which case the element's interior_parent may not be
     993             :         // known by the packed element.  We'll have to set such
     994             :         // interior_parents to remote_elem ourselves and wait for a
     995             :         // later packed element to give us better information.
     996      136276 :         if (interior_parent_id == remote_elem->id())
     997             :           {
     998             :             elem->set_interior_parent
     999           0 :               (const_cast<RemoteElem *>(remote_elem));
    1000             :           }
    1001      136276 :         else if (interior_parent_id != DofObject::invalid_id)
    1002             :           {
    1003             :             // If we don't have the interior parent element, then it's
    1004             :             // a remote_elem until we get it.
    1005             :             Elem * ip =
    1006          84 :               mesh->interior_mesh().query_elem_ptr(interior_parent_id);
    1007          84 :             if (!ip )
    1008             :               elem->set_interior_parent
    1009           0 :                 (const_cast<RemoteElem *>(remote_elem));
    1010             :             else
    1011          84 :               elem->set_interior_parent(ip);
    1012             :           }
    1013             :       }
    1014             : 
    1015      676789 :       for (auto n : elem->side_index_range())
    1016             :         {
    1017             :           const dof_id_type neighbor_id =
    1018      540513 :             cast_int<dof_id_type>(*in++);
    1019             : 
    1020             :             const dof_id_type neighbor_side =
    1021      540513 :               cast_int<dof_id_type>(*in++);
    1022             : 
    1023      540513 :           if (neighbor_id == DofObject::invalid_id)
    1024      357422 :             continue;
    1025             : 
    1026             :           // We may be unpacking an element that was a ghost element on the
    1027             :           // sender, in which case the element's neighbors may not all be
    1028             :           // known by the packed element.  We'll have to set such
    1029             :           // neighbors to remote_elem ourselves and wait for a later
    1030             :           // packed element to give us better information.
    1031        4544 :           if (neighbor_id == remote_elem->id())
    1032             :             {
    1033          96 :               elem->set_neighbor(n, const_cast<RemoteElem *>(remote_elem));
    1034          96 :               continue;
    1035             :             }
    1036             : 
    1037             :           // If we don't have the neighbor element, then it's a
    1038             :           // remote_elem until we get it.
    1039        4448 :           Elem * neigh = mesh->query_elem_ptr(neighbor_id);
    1040        4448 :           if (!neigh)
    1041             :             {
    1042        2089 :               elem->set_neighbor(n, const_cast<RemoteElem *>(remote_elem));
    1043        2089 :               continue;
    1044             :             }
    1045             : 
    1046             :           // If we have the neighbor element, then link to it, and
    1047             :           // make sure any appropriate parts of its family link back
    1048             :           // to us.
    1049        2359 :           elem->set_neighbor(n, neigh);
    1050             : 
    1051        2359 :           if (neighbor_side != libMesh::invalid_uint)
    1052        2359 :             elem->make_links_to_me_local(n, neighbor_side);
    1053             :         }
    1054             : 
    1055      136276 :       elem->unpack_indexing(in);
    1056             : 
    1057      136276 :       mesh->add_elem(elem);
    1058             :     }
    1059             : 
    1060      165337 :   in += elem->packed_indexing_size();
    1061             : 
    1062             :   // We check if this is cell holds a boundary ID or not
    1063      165337 :   auto on_boundary = *in++;
    1064      165337 :   if (on_boundary)
    1065             :   {
    1066             :     // Only treat the sides with caution. This is because we might hold boundary IDs
    1067             :     // on the sides of the children. This is not supported for edges and shell faces, thus
    1068             :     // they are treated assuming that only top parents can hold the IDs.
    1069       19229 :     auto children_on_boundary = *in++;
    1070       19229 :     if (elem->level() == 0 || children_on_boundary)
    1071             :     {
    1072      107735 :       for (auto s : elem->side_index_range())
    1073             :         {
    1074             :           const boundary_id_type num_bcs =
    1075       88506 :             cast_int<boundary_id_type>(*in++);
    1076             : 
    1077      114870 :           for (boundary_id_type bc_it=0; bc_it < num_bcs; bc_it++)
    1078        8778 :             mesh->get_boundary_info().add_side
    1079       35142 :               (elem, s, cast_int<boundary_id_type>(*in++));
    1080             :         }
    1081             :     }
    1082             :   }
    1083             : 
    1084             :   // If this is a coarse element,
    1085             :   // add any element side or edge boundary condition ids
    1086      165337 :   if (level == 0)
    1087             :     {
    1088     1086794 :       for (auto e : elem->edge_index_range())
    1089             :         {
    1090             :           const boundary_id_type num_bcs =
    1091      934657 :             cast_int<boundary_id_type>(*in++);
    1092             : 
    1093      934801 :           for (boundary_id_type bc_it=0; bc_it < num_bcs; bc_it++)
    1094          48 :             mesh->get_boundary_info().add_edge
    1095         192 :               (elem, e, cast_int<boundary_id_type>(*in++));
    1096             :         }
    1097             : 
    1098      456411 :       for (unsigned short sf=0; sf != 2; ++sf)
    1099             :         {
    1100             :           const boundary_id_type num_bcs =
    1101      304274 :             cast_int<boundary_id_type>(*in++);
    1102             : 
    1103      314258 :           for (boundary_id_type bc_it=0; bc_it < num_bcs; bc_it++)
    1104        3328 :             mesh->get_boundary_info().add_shellface
    1105       13312 :               (elem, sf, cast_int<boundary_id_type>(*in++));
    1106             :         }
    1107             :     }
    1108             : 
    1109             :   // Return the new element
    1110      220313 :   return elem;
    1111       55385 : }
    1112             : 
    1113             : 
    1114             : 
    1115             : template <>
    1116             : Elem *
    1117       23070 : Packing<Elem *>::unpack (std::vector<largest_id_type>::const_iterator in,
    1118             :                          DistributedMesh * mesh)
    1119             : {
    1120       23070 :   return unpack(in, static_cast<MeshBase*>(mesh));
    1121             : }
    1122             : 
    1123             : 
    1124             : 
    1125             : template <>
    1126             : Elem *
    1127           0 : Packing<Elem *>::unpack (std::vector<largest_id_type>::const_iterator in,
    1128             :                          ParallelMesh * mesh)
    1129             : {
    1130           0 :   return unpack(in, static_cast<MeshBase*>(mesh));
    1131             : }
    1132             : 
    1133             : } // namespace Parallel
    1134             : 
    1135             : } // namespace libMesh

Generated by: LCOV version 1.14