void Elem::refine (MeshRefinement& mesh_refinement) { libmesh_assert (this->refinement_flag() == Elem::REFINE); libmesh_assert (this->active()); // Create my children if necessary if (!_children) { _children = new Elem*[this->n_children()]; unsigned int parent_p_level = this->p_level(); for (unsigned int c=0; c<this->n_children(); c++) { _children[c] = Elem::build(this->type(), this).release(); _children[c]->set_refinement_flag(Elem::JUST_REFINED); _children[c]->set_p_level(parent_p_level); _children[c]->set_p_refinement_flag(this->p_refinement_flag()); } // Compute new nodal locations // and asssign nodes to children // Make these static. It is unlikely the // sizes will change from call to call, so having these // static should save on reallocations std::vector<std::vector<Point> > p (this->n_children()); std::vector<std::vector<Node*> > nodes(this->n_children()); // compute new nodal locations for (unsigned int c=0; c<this->n_children(); c++) { Elem *child = this->child(c); p[c].resize (child->n_nodes()); nodes[c].resize(child->n_nodes()); for (unsigned int nc=0; nc<child->n_nodes(); nc++) { // zero entries p[c][nc].zero(); nodes[c][nc] = NULL; for (unsigned int n=0; n<this->n_nodes(); n++) { // The value from the embedding matrix const float em_val = this->embedding_matrix(c,nc,n); if (em_val != 0.) { p[c][nc].add_scaled (this->point(n), em_val); // We may have found the node, in which case we // won't need to look it up later. if (em_val == 1.) nodes[c][nc] = this->get_node(n); } } } // assign nodes to children & add them to the mesh const Real pointtol = this->hmin() * TOLERANCE; for (unsigned int nc=0; nc<child->n_nodes(); nc++) { if (nodes[c][nc] != NULL) { child->set_node(nc) = nodes[c][nc]; } else { child->set_node(nc) = mesh_refinement.add_point(p[c][nc], child->processor_id(), pointtol); child->get_node(nc)->set_n_systems (this->n_systems()); } } mesh_refinement.add_elem (child); child->set_n_systems(this->n_systems()); } } else { unsigned int parent_p_level = this->p_level(); for (unsigned int c=0; c<this->n_children(); c++) { Elem *child = this->child(c); libmesh_assert(child->subactive()); child->set_refinement_flag(Elem::JUST_REFINED); child->set_p_level(parent_p_level); child->set_p_refinement_flag(this->p_refinement_flag()); } } // Un-set my refinement flag now this->set_refinement_flag(Elem::INACTIVE); this->set_p_refinement_flag(Elem::INACTIVE); for (unsigned int c=0; c<this->n_children(); c++) { libmesh_assert(this->child(c)->parent() == this); libmesh_assert(this->child(c)->active()); } libmesh_assert (this->ancestor()); }
void UnstructuredMesh::find_neighbors (const bool reset_remote_elements, const bool reset_current_list) { // We might actually want to run this on an empty mesh // (e.g. the boundary mesh for a nonexistant bcid!) // libmesh_assert_not_equal_to (this->n_nodes(), 0); // libmesh_assert_not_equal_to (this->n_elem(), 0); // This function must be run on all processors at once parallel_object_only(); LOG_SCOPE("find_neighbors()", "Mesh"); const element_iterator el_end = this->elements_end(); //TODO:[BSK] This should be removed later?! if (reset_current_list) for (element_iterator el = this->elements_begin(); el != el_end; ++el) { Elem * e = *el; for (unsigned int s=0; s<e->n_neighbors(); s++) if (e->neighbor_ptr(s) != remote_elem || reset_remote_elements) e->set_neighbor(s, libmesh_nullptr); } // Find neighboring elements by first finding elements // with identical side keys and then check to see if they // are neighbors { // data structures -- Use the hash_multimap if available typedef unsigned int key_type; typedef std::pair<Elem *, unsigned char> val_type; typedef std::pair<key_type, val_type> key_val_pair; typedef LIBMESH_BEST_UNORDERED_MULTIMAP<key_type, val_type> map_type; // A map from side keys to corresponding elements & side numbers map_type side_to_elem_map; for (element_iterator el = this->elements_begin(); el != el_end; ++el) { Elem * element = *el; for (unsigned char ms=0; ms<element->n_neighbors(); ms++) { next_side: // If we haven't yet found a neighbor on this side, try. // Even if we think our neighbor is remote, that // information may be out of date. if (element->neighbor_ptr(ms) == libmesh_nullptr || element->neighbor_ptr(ms) == remote_elem) { // Get the key for the side of this element const unsigned int key = element->key(ms); // Look for elements that have an identical side key std::pair <map_type::iterator, map_type::iterator> bounds = side_to_elem_map.equal_range(key); // May be multiple keys, check all the possible // elements which _might_ be neighbors. if (bounds.first != bounds.second) { // Get the side for this element const UniquePtr<Elem> my_side(element->side_ptr(ms)); // Look at all the entries with an equivalent key while (bounds.first != bounds.second) { // Get the potential element Elem * neighbor = bounds.first->second.first; // Get the side for the neighboring element const unsigned int ns = bounds.first->second.second; const UniquePtr<Elem> their_side(neighbor->side_ptr(ns)); //libmesh_assert(my_side.get()); //libmesh_assert(their_side.get()); // If found a match with my side // // We need special tests here for 1D: // since parents and children have an equal // side (i.e. a node), we need to check // ns != ms, and we also check level() to // avoid setting our neighbor pointer to // any of our neighbor's descendants if( (*my_side == *their_side) && (element->level() == neighbor->level()) && ((element->dim() != 1) || (ns != ms)) ) { // So share a side. Is this a mixed pair // of subactive and active/ancestor // elements? // If not, then we're neighbors. // If so, then the subactive's neighbor is if (element->subactive() == neighbor->subactive()) { // an element is only subactive if it has // been coarsened but not deleted element->set_neighbor (ms,neighbor); neighbor->set_neighbor(ns,element); } else if (element->subactive()) { element->set_neighbor(ms,neighbor); } else if (neighbor->subactive()) { neighbor->set_neighbor(ns,element); } side_to_elem_map.erase (bounds.first); // get out of this nested crap goto next_side; } ++bounds.first; } } // didn't find a match... // Build the map entry for this element key_val_pair kvp; kvp.first = key; kvp.second.first = element; kvp.second.second = ms; // use the lower bound as a hint for // where to put it. #if defined(LIBMESH_HAVE_UNORDERED_MAP) || defined(LIBMESH_HAVE_TR1_UNORDERED_MAP) || defined(LIBMESH_HAVE_HASH_MAP) || defined(LIBMESH_HAVE_EXT_HASH_MAP) side_to_elem_map.insert (kvp); #else side_to_elem_map.insert (bounds.first,kvp); #endif } } } } #ifdef LIBMESH_ENABLE_AMR /** * Here we look at all of the child elements which * don't already have valid neighbors. * * If a child element has a NULL neighbor it is * either because it is on the boundary or because * its neighbor is at a different level. In the * latter case we must get the neighbor from the * parent. * * If a child element has a remote_elem neighbor * on a boundary it shares with its parent, that * info may have become out-dated through coarsening * of the neighbor's parent. In this case, if the * parent's neighbor is active then the child should * share it. * * Furthermore, that neighbor better be active, * otherwise we missed a child somewhere. * * * We also need to look through children ordered by increasing * refinement level in order to add new interior_parent() links in * boundary elements which have just been generated by refinement, * and fix links in boundary elements whose previous * interior_parent() has just been coarsened away. */ const unsigned int n_levels = MeshTools::n_levels(*this); for (unsigned int level = 1; level < n_levels; ++level) { element_iterator end = this->level_elements_end(level); for (element_iterator el = this->level_elements_begin(level); el != end; ++el) { Elem * current_elem = *el; libmesh_assert(current_elem); Elem * parent = current_elem->parent(); libmesh_assert(parent); const unsigned int my_child_num = parent->which_child_am_i(current_elem); for (unsigned int s=0; s < current_elem->n_neighbors(); s++) { if (current_elem->neighbor_ptr(s) == libmesh_nullptr || (current_elem->neighbor_ptr(s) == remote_elem && parent->is_child_on_side(my_child_num, s))) { Elem * neigh = parent->neighbor_ptr(s); // If neigh was refined and had non-subactive children // made remote earlier, then a non-subactive elem should // actually have one of those remote children as a // neighbor if (neigh && (neigh->ancestor()) && (!current_elem->subactive())) { #ifdef DEBUG // Let's make sure that "had children made remote" // situation is actually the case libmesh_assert(neigh->has_children()); bool neigh_has_remote_children = false; for (unsigned int c = 0; c != neigh->n_children(); ++c) { if (neigh->child_ptr(c) == remote_elem) neigh_has_remote_children = true; } libmesh_assert(neigh_has_remote_children); // And let's double-check that we don't have // a remote_elem neighboring a local element libmesh_assert_not_equal_to (current_elem->processor_id(), this->processor_id()); #endif // DEBUG neigh = const_cast<RemoteElem *>(remote_elem); } if (!current_elem->subactive()) current_elem->set_neighbor(s, neigh); #ifdef DEBUG if (neigh != libmesh_nullptr && neigh != remote_elem) // We ignore subactive elements here because // we don't care about neighbors of subactive element. if ((!neigh->active()) && (!current_elem->subactive())) { libMesh::err << "On processor " << this->processor_id() << std::endl; libMesh::err << "Bad element ID = " << current_elem->id() << ", Side " << s << ", Bad neighbor ID = " << neigh->id() << std::endl; libMesh::err << "Bad element proc_ID = " << current_elem->processor_id() << ", Bad neighbor proc_ID = " << neigh->processor_id() << std::endl; libMesh::err << "Bad element size = " << current_elem->hmin() << ", Bad neighbor size = " << neigh->hmin() << std::endl; libMesh::err << "Bad element center = " << current_elem->centroid() << ", Bad neighbor center = " << neigh->centroid() << std::endl; libMesh::err << "ERROR: " << (current_elem->active()?"Active":"Ancestor") << " Element at level " << current_elem->level() << std::endl; libMesh::err << "with " << (parent->active()?"active": (parent->subactive()?"subactive":"ancestor")) << " parent share " << (neigh->subactive()?"subactive":"ancestor") << " neighbor at level " << neigh->level() << std::endl; NameBasedIO(*this).write ("bad_mesh.gmv"); libmesh_error_msg("Problematic mesh written to bad_mesh.gmv."); } #endif // DEBUG } } // We can skip to the next element if we're full-dimension // and therefore don't have any interior parents if (current_elem->dim() >= LIBMESH_DIM) continue; // We have no interior parents unless we can find one later current_elem->set_interior_parent(libmesh_nullptr); Elem * pip = parent->interior_parent(); if (!pip) continue; // If there's no interior_parent children, whether due to a // remote element or a non-conformity, then there's no // children to search. if (pip == remote_elem || pip->active()) { current_elem->set_interior_parent(pip); continue; } // For node comparisons we'll need a sensible tolerance Real node_tolerance = current_elem->hmin() * TOLERANCE; // Otherwise our interior_parent should be a child of our // parent's interior_parent. for (unsigned int c=0; c != pip->n_children(); ++c) { Elem * child = pip->child_ptr(c); // If we have a remote_elem, that might be our // interior_parent. We'll set it provisionally now and // keep trying to find something better. if (child == remote_elem) { current_elem->set_interior_parent (const_cast<RemoteElem *>(remote_elem)); continue; } bool child_contains_our_nodes = true; for (unsigned int n=0; n != current_elem->n_nodes(); ++n) { bool child_contains_this_node = false; for (unsigned int cn=0; cn != child->n_nodes(); ++cn) if (child->point(cn).absolute_fuzzy_equals (current_elem->point(n), node_tolerance)) { child_contains_this_node = true; break; } if (!child_contains_this_node) { child_contains_our_nodes = false; break; } } if (child_contains_our_nodes) { current_elem->set_interior_parent(child); break; } } // We should have found *some* interior_parent at this // point, whether semilocal or remote. libmesh_assert(current_elem->interior_parent()); } } #endif // AMR #ifdef DEBUG MeshTools::libmesh_assert_valid_neighbors(*this, !reset_remote_elements); MeshTools::libmesh_assert_valid_amr_interior_parents(*this); #endif }
bool UnstructuredMesh::contract () { LOG_SCOPE ("contract()", "Mesh"); // Flag indicating if this call actually changes the mesh bool mesh_changed = false; element_iterator in = elements_begin(); const element_iterator end = elements_end(); #ifdef DEBUG for ( ; in != end; ++in) if (*in != libmesh_nullptr) { Elem * el = *in; libmesh_assert(el->active() || el->subactive() || el->ancestor()); } in = elements_begin(); #endif // Loop over the elements. for ( ; in != end; ++in) if (*in != libmesh_nullptr) { Elem * el = *in; // Delete all the subactive ones if (el->subactive()) { // No level-0 element should be subactive. // Note that we CAN'T test elem->level(), as that // touches elem->parent()->dim(), and elem->parent() // might have already been deleted! libmesh_assert(el->parent()); // Delete the element // This just sets a pointer to NULL, and doesn't // invalidate any iterators this->delete_elem(el); // the mesh has certainly changed mesh_changed = true; } else { // Compress all the active ones if (el->active()) el->contract(); else libmesh_assert (el->ancestor()); } } // Strip any newly-created NULL voids out of the element array this->renumber_nodes_and_elements(); // FIXME: Need to understand why deleting subactive children // invalidates the point locator. For now we will clear it explicitly this->clear_point_locator(); return mesh_changed; }
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; }