void UnstructuredMesh::copy_nodes_and_elements(const UnstructuredMesh & other_mesh,
                                               const bool skip_find_neighbors)
{
  // We're assuming our subclass data needs no copy
  libmesh_assert_equal_to (_n_parts, other_mesh._n_parts);
  libmesh_assert (std::equal(_elem_dims.begin(), _elem_dims.end(), other_mesh._elem_dims.begin()));
  libmesh_assert_equal_to (_is_prepared, other_mesh._is_prepared);

  // We're assuming the other mesh has proper element number ordering,
  // so that we add parents before their children.
#ifdef DEBUG
  MeshTools::libmesh_assert_valid_amr_elem_ids(other_mesh);
#endif

  //Copy in Nodes
  {
    //Preallocate Memory if necessary
    this->reserve_nodes(other_mesh.n_nodes());

    const_node_iterator it = other_mesh.nodes_begin();
    const_node_iterator end = other_mesh.nodes_end();

    for (; it != end; ++it)
      {
        const Node * oldn = *it;

        // Add new nodes in old node Point locations
#ifdef LIBMESH_ENABLE_UNIQUE_ID
        Node *newn =
#endif
          this->add_point(*oldn, oldn->id(), oldn->processor_id());

#ifdef LIBMESH_ENABLE_UNIQUE_ID
        newn->set_unique_id() = oldn->unique_id();
#endif
      }
  }

  //Copy in Elements
  {
    //Preallocate Memory if necessary
    this->reserve_elem(other_mesh.n_elem());

    // Declare a map linking old and new elements, needed to copy the neighbor lists
    std::map<const Elem *, Elem *> old_elems_to_new_elems;

    // Loop over the elements
    MeshBase::const_element_iterator it = other_mesh.elements_begin();
    const MeshBase::const_element_iterator end = other_mesh.elements_end();

    // FIXME: Where do we set element IDs??
    for (; it != end; ++it)
      {
        //Look at the old element
        const Elem * old = *it;
        //Build a new element
        Elem * newparent = old->parent() ?
          this->elem_ptr(old->parent()->id()) : libmesh_nullptr;
        UniquePtr<Elem> ap = Elem::build(old->type(), newparent);
        Elem * el = ap.release();

        el->subdomain_id() = old->subdomain_id();

        for (unsigned int s=0; s != old->n_sides(); ++s)
          if (old->neighbor_ptr(s) == remote_elem)
            el->set_neighbor(s, const_cast<RemoteElem *>(remote_elem));

#ifdef LIBMESH_ENABLE_AMR
        if (old->has_children())
          for (unsigned int c=0; c != old->n_children(); ++c)
            if (old->child_ptr(c) == remote_elem)
              el->add_child(const_cast<RemoteElem *>(remote_elem), c);

        //Create the parent's child pointers if necessary
        if (newparent)
          {
            unsigned int oldc = old->parent()->which_child_am_i(old);
            newparent->add_child(el, oldc);
          }

        // Copy the refinement flags
        el->set_refinement_flag(old->refinement_flag());

        // Use hack_p_level since we may not have sibling elements
        // added yet
        el->hack_p_level(old->p_level());

        el->set_p_refinement_flag(old->p_refinement_flag());
#endif // #ifdef LIBMESH_ENABLE_AMR

        //Assign all the nodes
        for(unsigned int i=0;i<el->n_nodes();i++)
          el->set_node(i) = this->node_ptr(old->node_id(i));

        // And start it off in the same subdomain
        el->processor_id() = old->processor_id();

        // Give it the same ids
        el->set_id(old->id());

#ifdef LIBMESH_ENABLE_UNIQUE_ID
        el->set_unique_id() = old->unique_id();
#endif

        //Hold onto it
        if(!skip_find_neighbors)
          {
            this->add_elem(el);
          }
        else
          {
            Elem * new_el = this->add_elem(el);
            old_elems_to_new_elems[old] = new_el;
          }

        // Add the link between the original element and this copy to the map
        if(skip_find_neighbors)
          old_elems_to_new_elems[old] = el;
      }

    // Loop (again) over the elements to fill in the neighbors
    if(skip_find_neighbors)
      {
        it = other_mesh.elements_begin();
        for (; it != end; ++it)
          {
            Elem * old_elem = *it;
            Elem * new_elem = old_elems_to_new_elems[old_elem];
            for (unsigned int s=0; s != old_elem->n_neighbors(); ++s)
              {
                const Elem * old_neighbor = old_elem->neighbor_ptr(s);
                Elem * new_neighbor = old_elems_to_new_elems[old_neighbor];
                new_elem->set_neighbor(s, new_neighbor);
              }
          }
      }
  }

  //Finally prepare the new Mesh for use.  Keep the same numbering and
  //partitioning but also the same renumbering and partitioning
  //policies as our source mesh.
  this->allow_renumbering(false);
  this->skip_partitioning(true);
  this->prepare_for_use(false, skip_find_neighbors);
  this->allow_renumbering(other_mesh.allow_renumbering());
  this->skip_partitioning(other_mesh.skip_partitioning());
}
Beispiel #2
0
void CheckpointIO::read_connectivity (Xdr & io)
{
  // convenient reference to our mesh
  MeshBase & mesh = MeshInput<MeshBase>::mesh();

  unsigned int n_active_levels;
  io.data(n_active_levels, "# n_active_levels");

  // Keep track of the highest dimensional element we've added to the mesh
  unsigned int highest_elem_dim = 1;

  for(unsigned int level=0; level < n_active_levels; level++)
    {
      xdr_id_type n_elem_at_level = 0;
      io.data (n_elem_at_level, "");

      for (unsigned int i=0; i<n_elem_at_level; i++)
        {
          // id type pid subdomain_id parent_id
          std::vector<largest_id_type> elem_data(5);
          io.data_stream
            (&elem_data[0], cast_int<unsigned int>(elem_data.size()),
             cast_int<unsigned int>(elem_data.size()));

#ifdef LIBMESH_ENABLE_UNIQUE_ID
          largest_id_type unique_id = 0;
          io.data(unique_id, "# unique id");
#endif

#ifdef LIBMESH_ENABLE_AMR
          unsigned int p_level = 0;

          io.data(p_level, "# p_level");
#endif

          unsigned int n_nodes = Elem::type_to_n_nodes_map[elem_data[1]];

          // Snag the node ids this element was connected to
          std::vector<largest_id_type> conn_data(n_nodes);
          io.data_stream
            (&conn_data[0], cast_int<unsigned int>(conn_data.size()),
             cast_int<unsigned int>(conn_data.size()));

          const dof_id_type id                 =
            cast_int<dof_id_type>      (elem_data[0]);
          const ElemType elem_type             =
            static_cast<ElemType>      (elem_data[1]);
          const processor_id_type proc_id      =
            cast_int<processor_id_type>(elem_data[2]);
          const subdomain_id_type subdomain_id =
            cast_int<subdomain_id_type>(elem_data[3]);
          const dof_id_type parent_id          =
            cast_int<dof_id_type>      (elem_data[4]);

          Elem * parent =
            (parent_id == DofObject::invalid_processor_id) ?
            libmesh_nullptr : mesh.elem_ptr(parent_id);

          // Create the element
          Elem * elem = Elem::build(elem_type, parent).release();

#ifdef LIBMESH_ENABLE_UNIQUE_ID
          elem->set_unique_id() = unique_id;
#endif

          if(elem->dim() > highest_elem_dim)
            highest_elem_dim = elem->dim();

          elem->set_id()       = id;
          elem->processor_id() = proc_id;
          elem->subdomain_id() = subdomain_id;

#ifdef LIBMESH_ENABLE_AMR
          elem->hack_p_level(p_level);

          // Set parent connections
          if(parent)
            {
              parent->add_child(elem);
              parent->set_refinement_flag (Elem::INACTIVE);
              elem->set_refinement_flag   (Elem::JUST_REFINED);
            }
#endif

          libmesh_assert(elem->n_nodes() == conn_data.size());

          // Connect all the nodes to this element
          for (unsigned int n=0; n<conn_data.size(); n++)
            elem->set_node(n) =
              mesh.node_ptr(cast_int<dof_id_type>(conn_data[n]));

          mesh.add_elem(elem);
        }
    }

  mesh.set_mesh_dimension(cast_int<unsigned char>(highest_elem_dim));
}
Beispiel #3
0
void unpack(std::vector<largest_id_type>::const_iterator in,
            Elem** out,
            MeshBase* mesh)
{
#ifndef NDEBUG
  const std::vector<largest_id_type>::const_iterator original_in = in;

  const largest_id_type incoming_header = *in++;
  libmesh_assert_equal_to (incoming_header, elem_magic_header);
#endif

  // int 0: level
  const unsigned int level =
    static_cast<unsigned int>(*in++);

#ifdef LIBMESH_ENABLE_AMR
  // int 1: p level
  const unsigned int p_level =
    static_cast<unsigned int>(*in++);

  // int 2: refinement flag
  const int rflag = *in++;
  libmesh_assert_greater_equal (rflag, 0);
  libmesh_assert_less (rflag, Elem::INVALID_REFINEMENTSTATE);
  const Elem::RefinementState refinement_flag =
    static_cast<Elem::RefinementState>(rflag);

  // int 3: p refinement flag
  const int pflag = *in++;
  libmesh_assert_greater_equal (pflag, 0);
  libmesh_assert_less (pflag, Elem::INVALID_REFINEMENTSTATE);
  const Elem::RefinementState p_refinement_flag =
    static_cast<Elem::RefinementState>(pflag);
#else
  in += 3;
#endif // LIBMESH_ENABLE_AMR

  // int 4: element type
  const int typeint = *in++;
  libmesh_assert_greater_equal (typeint, 0);
  libmesh_assert_less (typeint, INVALID_ELEM);
  const ElemType type =
    static_cast<ElemType>(typeint);

  const unsigned int n_nodes =
    Elem::type_to_n_nodes_map[type];

  // int 5: processor id
  const processor_id_type processor_id =
    static_cast<processor_id_type>(*in++);
  libmesh_assert (processor_id < mesh->n_processors() ||
                  processor_id == DofObject::invalid_processor_id);

  // int 6: subdomain id
  const subdomain_id_type subdomain_id =
    static_cast<subdomain_id_type>(*in++);

  // int 7: dof object id
  const dof_id_type id =
    static_cast<dof_id_type>(*in++);
  libmesh_assert_not_equal_to (id, DofObject::invalid_id);

#ifdef LIBMESH_ENABLE_UNIQUE_ID
  // int 8: dof object unique id
  const unique_id_type unique_id =
    static_cast<unique_id_type>(*in++);
#endif

#ifdef LIBMESH_ENABLE_AMR
  // int 9: parent dof object id
  const dof_id_type parent_id =
    static_cast<dof_id_type>(*in++);
  libmesh_assert (level == 0 || parent_id != DofObject::invalid_id);
  libmesh_assert (level != 0 || parent_id == DofObject::invalid_id);

  // int 10: local child id
  const unsigned int which_child_am_i =
    static_cast<unsigned int>(*in++);
#else
  in += 2;
#endif // LIBMESH_ENABLE_AMR

  // Make sure we don't miscount above when adding the "magic" header
  // plus the real data header
  libmesh_assert_equal_to (in - original_in, header_size + 1);

  Elem *elem = mesh->query_elem(id);

  // if we already have this element, make sure its
  // properties match, and update any missing neighbor
  // links, but then go on
  if (elem)
    {
      libmesh_assert_equal_to (elem->level(), level);
      libmesh_assert_equal_to (elem->id(), id);
//#ifdef LIBMESH_ENABLE_UNIQUE_ID
      // No check for unqiue id sanity
//#endif
      libmesh_assert_equal_to (elem->processor_id(), processor_id);
      libmesh_assert_equal_to (elem->subdomain_id(), subdomain_id);
      libmesh_assert_equal_to (elem->type(), type);
      libmesh_assert_equal_to (elem->n_nodes(), n_nodes);

#ifndef NDEBUG
      // All our nodes should be correct
      for (unsigned int i=0; i != n_nodes; ++i)
        libmesh_assert(elem->node(i) ==
                       static_cast<dof_id_type>(*in++));
#else
      in += n_nodes;
#endif

#ifdef LIBMESH_ENABLE_AMR
      libmesh_assert_equal_to (elem->p_level(), p_level);
      libmesh_assert_equal_to (elem->refinement_flag(), refinement_flag);
      libmesh_assert_equal_to (elem->p_refinement_flag(), p_refinement_flag);

      libmesh_assert (!level || elem->parent() != NULL);
      libmesh_assert (!level || elem->parent()->id() == parent_id);
      libmesh_assert (!level || elem->parent()->child(which_child_am_i) == elem);
#endif

      // Our neighbor links should be "close to" correct - we may have
      // to update them, but we can check for some inconsistencies.
      for (unsigned int n=0; n != elem->n_neighbors(); ++n)
        {
          const dof_id_type neighbor_id =
            static_cast<dof_id_type>(*in++);

	  // If the sending processor sees a domain boundary here,
	  // we'd better agree.
          if (neighbor_id == DofObject::invalid_id)
            {
              libmesh_assert (!(elem->neighbor(n)));
              continue;
            }

	  // If the sending processor has a remote_elem neighbor here,
	  // then all we know is that we'd better *not* have a domain
	  // boundary.
          if (neighbor_id == remote_elem->id())
            {
              libmesh_assert(elem->neighbor(n));
              continue;
            }

          Elem *neigh = mesh->query_elem(neighbor_id);

          // The sending processor sees a neighbor here, so if we
          // don't have that neighboring element, then we'd better
          // have a remote_elem signifying that fact.
          if (!neigh)
            {
              libmesh_assert_equal_to (elem->neighbor(n), remote_elem);
              continue;
            }

          // The sending processor has a neighbor here, and we have
          // that element, but that does *NOT* mean we're already
	  // linking to it.  Perhaps we initially received both elem
	  // and neigh from processors on which their mutual link was
	  // remote?
          libmesh_assert(elem->neighbor(n) == neigh ||
			 elem->neighbor(n) == remote_elem);

	  // If the link was originally remote, we should update it,
	  // and make sure the appropriate parts of its family link
	  // back to us.
	  if (elem->neighbor(n) == remote_elem)
            {
              elem->set_neighbor(n, neigh);

              elem->make_links_to_me_local(n);
	    }
	}

      // FIXME: We should add some debug mode tests to ensure that the
      // encoded indexing and boundary conditions are consistent.
    }
  else
    {
      // We don't already have the element, so we need to create it.

      // Find the parent if necessary
      Elem *parent = NULL;
#ifdef LIBMESH_ENABLE_AMR
      // Find a child element's parent
      if (level > 0)
        {
	  // Note that we must be very careful to construct the send
	  // connectivity so that parents are encountered before
	  // children.  If we get here and can't find the parent that
	  // is a fatal error.
          parent = mesh->elem(parent_id);
        }
      // Or assert that the sending processor sees no parent
      else
        libmesh_assert_equal_to (parent_id, static_cast<dof_id_type>(-1));
#else
      // No non-level-0 elements without AMR
      libmesh_assert_equal_to (level, 0);
#endif

      elem = Elem::build(type,parent).release();
      libmesh_assert (elem);

#ifdef LIBMESH_ENABLE_AMR
      if (level != 0)
        {
          // Since this is a newly created element, the parent must
          // have previously thought of this child as a remote element.
          libmesh_assert_equal_to (parent->child(which_child_am_i), remote_elem);

          parent->add_child(elem, which_child_am_i);
        }

      // Assign the refinement flags and levels
      elem->set_p_level(p_level);
      elem->set_refinement_flag(refinement_flag);
      elem->set_p_refinement_flag(p_refinement_flag);
      libmesh_assert_equal_to (elem->level(), level);

      // If this element definitely should have children, assign
      // remote_elem to all of them for now, for consistency.  Later
      // unpacked elements may overwrite that.
      if (!elem->active())
        for (unsigned int c=0; c != elem->n_children(); ++c)
          elem->add_child(const_cast<RemoteElem*>(remote_elem), c);

#endif // LIBMESH_ENABLE_AMR

      // Assign the IDs
      elem->subdomain_id()  = subdomain_id;
      elem->processor_id()  = processor_id;
      elem->set_id()        = id;
#ifdef LIBMESH_ENABLE_UNIQUE_ID
      elem->set_unique_id() = unique_id;
#endif

      // Assign the connectivity
      libmesh_assert_equal_to (elem->n_nodes(), n_nodes);

      for (unsigned int n=0; n != n_nodes; n++)
        elem->set_node(n) =
          mesh->node_ptr
	    (static_cast<dof_id_type>(*in++));

      for (unsigned int n=0; n<elem->n_neighbors(); n++)
        {
          const dof_id_type neighbor_id =
            static_cast<dof_id_type>(*in++);

          if (neighbor_id == DofObject::invalid_id)
	    continue;

          // We may be unpacking an element that was a ghost element on the
          // sender, in which case the element's neighbors may not all be
          // known by the packed element.  We'll have to set such
          // neighbors to remote_elem ourselves and wait for a later
          // packed element to give us better information.
          if (neighbor_id == remote_elem->id())
            {
              elem->set_neighbor(n, const_cast<RemoteElem*>(remote_elem));
	      continue;
	    }

          // If we don't have the neighbor element, then it's a
          // remote_elem until we get it.
          Elem *neigh = mesh->query_elem(neighbor_id);
          if (!neigh)
            {
              elem->set_neighbor(n, const_cast<RemoteElem*>(remote_elem));
	      continue;
	    }

          // If we have the neighbor element, then link to it, and
          // make sure the appropriate parts of its family link back
          // to us.
          elem->set_neighbor(n, neigh);

          elem->make_links_to_me_local(n);
        }

      elem->unpack_indexing(in);
    }

  in += elem->packed_indexing_size();

  // If this is a coarse element,
  // add any element side boundary condition ids
  if (level == 0)
    for (unsigned int s = 0; s != elem->n_sides(); ++s)
      {
        const int num_bcs = *in++;
        libmesh_assert_greater_equal (num_bcs, 0);

        for(int bc_it=0; bc_it < num_bcs; bc_it++)
          mesh->boundary_info->add_side (elem, s, *in++);
      }

  // Return the new element
  *out = elem;
}
Beispiel #4
0
Elem *
Packing<Elem *>::unpack (std::vector<largest_id_type>::const_iterator in,
                         MeshBase * mesh)
{
#ifndef NDEBUG
  const std::vector<largest_id_type>::const_iterator original_in = in;

  const largest_id_type incoming_header = *in++;
  libmesh_assert_equal_to (incoming_header, elem_magic_header);
#endif

  // int 0: level
  const unsigned int level =
    cast_int<unsigned int>(*in++);

#ifdef LIBMESH_ENABLE_AMR
  // int 1: p level
  const unsigned int p_level =
    cast_int<unsigned int>(*in++);

  // int 2: refinement flag and encoded has_children
  const int rflag = cast_int<int>(*in++);
  const int invalid_rflag =
    cast_int<int>(Elem::INVALID_REFINEMENTSTATE);
  libmesh_assert_greater_equal (rflag, 0);

  libmesh_assert_less (rflag, invalid_rflag*2+1);

  const bool has_children = (rflag > invalid_rflag);

  const Elem::RefinementState refinement_flag = has_children ?
    cast_int<Elem::RefinementState>(rflag - invalid_rflag - 1) :
    cast_int<Elem::RefinementState>(rflag);

  // int 3: p refinement flag
  const int pflag = cast_int<int>(*in++);
  libmesh_assert_greater_equal (pflag, 0);
  libmesh_assert_less (pflag, Elem::INVALID_REFINEMENTSTATE);
  const Elem::RefinementState p_refinement_flag =
    cast_int<Elem::RefinementState>(pflag);
#else
  in += 3;
#endif // LIBMESH_ENABLE_AMR

  // int 4: element type
  const int typeint = cast_int<int>(*in++);
  libmesh_assert_greater_equal (typeint, 0);
  libmesh_assert_less (typeint, INVALID_ELEM);
  const ElemType type =
    cast_int<ElemType>(typeint);

  const unsigned int n_nodes =
    Elem::type_to_n_nodes_map[type];

  // int 5: processor id
  const processor_id_type processor_id =
    cast_int<processor_id_type>(*in++);
  libmesh_assert (processor_id < mesh->n_processors() ||
                  processor_id == DofObject::invalid_processor_id);

  // int 6: subdomain id
  const subdomain_id_type subdomain_id =
    cast_int<subdomain_id_type>(*in++);

  // int 7: dof object id
  const dof_id_type id =
    cast_int<dof_id_type>(*in++);
  libmesh_assert_not_equal_to (id, DofObject::invalid_id);

#ifdef LIBMESH_ENABLE_UNIQUE_ID
  // int 8: dof object unique id
  const unique_id_type unique_id =
    cast_int<unique_id_type>(*in++);
#endif

#ifdef LIBMESH_ENABLE_AMR
  // int 9: parent dof object id.
  // Note: If level==0, then (*in) == invalid_id.  In
  // this case, the equality check in cast_int<unsigned>(*in) will
  // never succeed.  Therefore, we should only attempt the more
  // rigorous cast verification in cases where level != 0.
  const dof_id_type parent_id =
    (level == 0)
    ? static_cast<dof_id_type>(*in++)
    : cast_int<dof_id_type>(*in++);
  libmesh_assert (level == 0 || parent_id != DofObject::invalid_id);
  libmesh_assert (level != 0 || parent_id == DofObject::invalid_id);

  // int 10: local child id
  // Note: If level==0, then which_child_am_i is not valid, so don't
  // do the more rigorous cast verification.
  const unsigned int which_child_am_i =
    (level == 0)
    ? static_cast<unsigned int>(*in++)
    : cast_int<unsigned int>(*in++);
#else
  in += 2;
#endif // LIBMESH_ENABLE_AMR

  const dof_id_type interior_parent_id =
    static_cast<dof_id_type>(*in++);

  // Make sure we don't miscount above when adding the "magic" header
  // plus the real data header
  libmesh_assert_equal_to (in - original_in, header_size + 1);

  Elem * elem = mesh->query_elem_ptr(id);

  // if we already have this element, make sure its
  // properties match, and update any missing neighbor
  // links, but then go on
  if (elem)
    {
      libmesh_assert_equal_to (elem->level(), level);
      libmesh_assert_equal_to (elem->id(), id);
      //#ifdef LIBMESH_ENABLE_UNIQUE_ID
      // No check for unique id sanity
      //#endif
      libmesh_assert_equal_to (elem->processor_id(), processor_id);
      libmesh_assert_equal_to (elem->subdomain_id(), subdomain_id);
      libmesh_assert_equal_to (elem->type(), type);
      libmesh_assert_equal_to (elem->n_nodes(), n_nodes);

#ifndef NDEBUG
      // All our nodes should be correct
      for (unsigned int i=0; i != n_nodes; ++i)
        libmesh_assert(elem->node_id(i) ==
                       cast_int<dof_id_type>(*in++));
#else
      in += n_nodes;
#endif

#ifdef LIBMESH_ENABLE_AMR
      libmesh_assert_equal_to (elem->refinement_flag(), refinement_flag);
      libmesh_assert_equal_to (elem->has_children(), has_children);

#ifdef DEBUG
      if (elem->active())
        {
          libmesh_assert_equal_to (elem->p_level(), p_level);
          libmesh_assert_equal_to (elem->p_refinement_flag(), p_refinement_flag);
        }
#endif

      libmesh_assert (!level || elem->parent() != libmesh_nullptr);
      libmesh_assert (!level || elem->parent()->id() == parent_id);
      libmesh_assert (!level || elem->parent()->child_ptr(which_child_am_i) == elem);
#endif
      // Our interior_parent link should be "close to" correct - we
      // may have to update it, but we can check for some
      // inconsistencies.
      {
        // If the sending processor sees no interior_parent here, we'd
        // better agree.
        if (interior_parent_id == DofObject::invalid_id)
          {
            if (elem->dim() < LIBMESH_DIM)
              libmesh_assert (!(elem->interior_parent()));
          }

        // If the sending processor has a remote_elem interior_parent,
        // then all we know is that we'd better have *some*
        // interior_parent
        else if (interior_parent_id == remote_elem->id())
          {
            libmesh_assert(elem->interior_parent());
          }
        else
          {
            Elem * ip = mesh->query_elem_ptr(interior_parent_id);

            // The sending processor sees an interior parent here, so
            // if we don't have that interior element, then we'd
            // better have a remote_elem signifying that fact.
            if (!ip)
              libmesh_assert_equal_to (elem->interior_parent(), remote_elem);
            else
              {
                // The sending processor has an interior_parent here,
                // and we have that element, but that does *NOT* mean
                // we're already linking to it.  Perhaps we initially
                // received elem from a processor on which the
                // interior_parent link was remote?
                libmesh_assert(elem->interior_parent() == ip ||
                               elem->interior_parent() == remote_elem);

                // If the link was originally remote, update it
                if (elem->interior_parent() == remote_elem)
                  {
                    elem->set_interior_parent(ip);
                  }
              }
          }
      }

      // Our neighbor links should be "close to" correct - we may have
      // to update a remote_elem link, and we can check for possible
      // inconsistencies along the way.
      //
      // For subactive elements, we don't bother keeping neighbor
      // links in good shape, so there's nothing we need to set or can
      // safely assert here.
      if (!elem->subactive())
        for (auto n : elem->side_index_range())
          {
            const dof_id_type neighbor_id =
              cast_int<dof_id_type>(*in++);

            // If the sending processor sees a domain boundary here,
            // we'd better agree.
            if (neighbor_id == DofObject::invalid_id)
              {
                libmesh_assert (!(elem->neighbor_ptr(n)));
                continue;
              }

            // If the sending processor has a remote_elem neighbor here,
            // then all we know is that we'd better *not* have a domain
            // boundary.
            if (neighbor_id == remote_elem->id())
              {
                libmesh_assert(elem->neighbor_ptr(n));
                continue;
              }

            Elem * neigh = mesh->query_elem_ptr(neighbor_id);

            // The sending processor sees a neighbor here, so if we
            // don't have that neighboring element, then we'd better
            // have a remote_elem signifying that fact.
            if (!neigh)
              {
                libmesh_assert_equal_to (elem->neighbor_ptr(n), remote_elem);
                continue;
              }

            // The sending processor has a neighbor here, and we have
            // that element, but that does *NOT* mean we're already
            // linking to it.  Perhaps we initially received both elem
            // and neigh from processors on which their mutual link was
            // remote?
            libmesh_assert(elem->neighbor_ptr(n) == neigh ||
                           elem->neighbor_ptr(n) == remote_elem);

            // If the link was originally remote, we should update it,
            // and make sure the appropriate parts of its family link
            // back to us.
            if (elem->neighbor_ptr(n) == remote_elem)
              {
                elem->set_neighbor(n, neigh);

                elem->make_links_to_me_local(n);
              }
          }

      // Our p level and refinement flags should be "close to" correct
      // if we're not an active element - we might have a p level
      // increased or decreased by changes in remote_elem children.
      //
      // But if we have remote_elem children, then we shouldn't be
      // doing a projection on this inactive element on this
      // processor, so we won't need correct p settings.  Couldn't
      // hurt to update, though.
#ifdef LIBMESH_ENABLE_AMR
      if (elem->processor_id() != mesh->processor_id())
        {
          elem->hack_p_level(p_level);
          elem->set_p_refinement_flag(p_refinement_flag);
        }
#endif // LIBMESH_ENABLE_AMR

      // FIXME: We should add some debug mode tests to ensure that the
      // encoded indexing and boundary conditions are consistent.
    }
  else
    {
      // We don't already have the element, so we need to create it.

      // Find the parent if necessary
      Elem * parent = libmesh_nullptr;
#ifdef LIBMESH_ENABLE_AMR
      // Find a child element's parent
      if (level > 0)
        {
          // Note that we must be very careful to construct the send
          // connectivity so that parents are encountered before
          // children.  If we get here and can't find the parent that
          // is a fatal error.
          parent = mesh->elem_ptr(parent_id);
        }
      // Or assert that the sending processor sees no parent
      else
        libmesh_assert_equal_to (parent_id, DofObject::invalid_id);
#else
      // No non-level-0 elements without AMR
      libmesh_assert_equal_to (level, 0);
#endif

      elem = Elem::build(type,parent).release();
      libmesh_assert (elem);

#ifdef LIBMESH_ENABLE_AMR
      if (level != 0)
        {
          // Since this is a newly created element, the parent must
          // have previously thought of this child as a remote element.
          libmesh_assert_equal_to (parent->child_ptr(which_child_am_i), remote_elem);

          parent->add_child(elem, which_child_am_i);
        }

      // Assign the refinement flags and levels
      elem->set_p_level(p_level);
      elem->set_refinement_flag(refinement_flag);
      elem->set_p_refinement_flag(p_refinement_flag);
      libmesh_assert_equal_to (elem->level(), level);

      // If this element should have children, assign remote_elem to
      // all of them for now, for consistency.  Later unpacked
      // elements may overwrite that.
      if (has_children)
        {
          const unsigned int nc = elem->n_children();
          for (unsigned int c=0; c != nc; ++c)
            elem->add_child(const_cast<RemoteElem *>(remote_elem), c);
        }

#endif // LIBMESH_ENABLE_AMR

      // Assign the IDs
      elem->subdomain_id()  = subdomain_id;
      elem->processor_id()  = processor_id;
      elem->set_id()        = id;
#ifdef LIBMESH_ENABLE_UNIQUE_ID
      elem->set_unique_id() = unique_id;
#endif

      // Assign the connectivity
      libmesh_assert_equal_to (elem->n_nodes(), n_nodes);

      for (unsigned int n=0; n != n_nodes; n++)
        elem->set_node(n) =
          mesh->node_ptr
          (cast_int<dof_id_type>(*in++));

      // Set interior_parent if found
      {
        // We may be unpacking an element that was a ghost element on the
        // sender, in which case the element's interior_parent may not be
        // known by the packed element.  We'll have to set such
        // interior_parents to remote_elem ourselves and wait for a
        // later packed element to give us better information.
        if (interior_parent_id == remote_elem->id())
          {
            elem->set_interior_parent
              (const_cast<RemoteElem *>(remote_elem));
          }
        else if (interior_parent_id != DofObject::invalid_id)
          {
            // If we don't have the interior parent element, then it's
            // a remote_elem until we get it.
            Elem * ip = mesh->query_elem_ptr(interior_parent_id);
            if (!ip )
              elem->set_interior_parent
                (const_cast<RemoteElem *>(remote_elem));
            else
              elem->set_interior_parent(ip);
          }
      }

      for (auto n : elem->side_index_range())
        {
          const dof_id_type neighbor_id =
            cast_int<dof_id_type>(*in++);

          if (neighbor_id == DofObject::invalid_id)
            continue;

          // We may be unpacking an element that was a ghost element on the
          // sender, in which case the element's neighbors may not all be
          // known by the packed element.  We'll have to set such
          // neighbors to remote_elem ourselves and wait for a later
          // packed element to give us better information.
          if (neighbor_id == remote_elem->id())
            {
              elem->set_neighbor(n, const_cast<RemoteElem *>(remote_elem));
              continue;
            }

          // If we don't have the neighbor element, then it's a
          // remote_elem until we get it.
          Elem * neigh = mesh->query_elem_ptr(neighbor_id);
          if (!neigh)
            {
              elem->set_neighbor(n, const_cast<RemoteElem *>(remote_elem));
              continue;
            }

          // If we have the neighbor element, then link to it, and
          // make sure the appropriate parts of its family link back
          // to us.
          elem->set_neighbor(n, neigh);

          elem->make_links_to_me_local(n);
        }

      elem->unpack_indexing(in);
    }

  in += elem->packed_indexing_size();

  // If this is a coarse element,
  // add any element side or edge boundary condition ids
  if (level == 0)
    {
      for (auto s : elem->side_index_range())
        {
          const boundary_id_type num_bcs =
            cast_int<boundary_id_type>(*in++);

          for (boundary_id_type bc_it=0; bc_it < num_bcs; bc_it++)
            mesh->get_boundary_info().add_side
              (elem, s, cast_int<boundary_id_type>(*in++));
        }

      for (auto e : elem->edge_index_range())
        {
          const boundary_id_type num_bcs =
            cast_int<boundary_id_type>(*in++);

          for (boundary_id_type bc_it=0; bc_it < num_bcs; bc_it++)
            mesh->get_boundary_info().add_edge
              (elem, e, cast_int<boundary_id_type>(*in++));
        }

      for (unsigned short sf=0; sf != 2; ++sf)
        {
          const boundary_id_type num_bcs =
            cast_int<boundary_id_type>(*in++);

          for (boundary_id_type bc_it=0; bc_it < num_bcs; bc_it++)
            mesh->get_boundary_info().add_shellface
              (elem, sf, cast_int<boundary_id_type>(*in++));
        }
    }

  // Return the new element
  return elem;
}