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; }
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 }