bool MeshRefinement::limit_overrefined_boundary(const unsigned int max_mismatch) { // This function must be run on all processors at once parallel_object_only(); bool flags_changed = false; // Loop over all the active elements & look for mismatches to fix. { MeshBase::element_iterator elem_it = _mesh.active_elements_begin(); const MeshBase::element_iterator elem_end = _mesh.active_elements_end(); for (; elem_it != elem_end; ++elem_it) { Elem* elem = *elem_it; // If we don't have an interior_parent then there's nothing to // be mismatched with. if ((elem->dim() >= LIBMESH_DIM) || !elem->interior_parent()) continue; const unsigned char elem_level = cast_int<unsigned char>(elem->level() + ((elem->refinement_flag() == Elem::REFINE) ? 1 : 0)); const unsigned char elem_p_level = cast_int<unsigned char>(elem->p_level() + ((elem->p_refinement_flag() == Elem::REFINE) ? 1 : 0)); // get all relevant interior elements std::set<const Elem*> neighbor_set; elem->find_interior_neighbors(neighbor_set); std::set<const Elem*>::iterator n_it = neighbor_set.begin(); for (; n_it != neighbor_set.end(); ++n_it) { // FIXME - non-const versions of the Elem set methods // would be nice Elem* neighbor = const_cast<Elem*>(*n_it); if (((elem_level - max_mismatch) > neighbor->level()) && (neighbor->refinement_flag() != Elem::REFINE)) { neighbor->set_refinement_flag(Elem::REFINE); flags_changed = true; } if (((elem_p_level + 1 - max_mismatch) > neighbor->p_level()) && (neighbor->p_refinement_flag() != Elem::REFINE)) { neighbor->set_p_refinement_flag(Elem::REFINE); flags_changed = true; } } // loop over interior neighbors } } return flags_changed; }
void HPSingularity::select_refinement (System &system) { START_LOG("select_refinement()", "HPSingularity"); // The current mesh MeshBase& mesh = system.get_mesh(); MeshBase::element_iterator elem_it = mesh.active_local_elements_begin(); const MeshBase::element_iterator elem_end = mesh.active_local_elements_end(); for (; elem_it != elem_end; ++elem_it) { Elem* elem = *elem_it; // We're only checking elements that are already flagged for h // refinement if (elem->refinement_flag() != Elem::REFINE) continue; elem->set_p_refinement_flag(Elem::REFINE); elem->set_refinement_flag(Elem::DO_NOTHING); for (std::list<Point>::iterator ppoint = singular_points.begin(); ppoint != singular_points.end(); ++ppoint) { if (elem->contains_point(*ppoint)) { elem->set_p_refinement_flag(Elem::DO_NOTHING); elem->set_refinement_flag(Elem::REFINE); break; } } } STOP_LOG("select_refinement()", "HPSingularity"); }
void Elem::coarsen() { libmesh_assert (this->refinement_flag() == Elem::COARSEN_INACTIVE); libmesh_assert (!this->active()); // We no longer delete children until MeshRefinement::contract() // delete [] _children; // _children = NULL; unsigned int parent_p_level = 0; // re-compute hanging node nodal locations for (unsigned int c=0; c<this->n_children(); c++) { Elem *mychild = this->child(c); if (mychild == remote_elem) continue; for (unsigned int nc=0; nc<mychild->n_nodes(); nc++) { Point new_pos; bool calculated_new_pos = false; 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); // The node location is somewhere between existing vertices if ((em_val != 0.) && (em_val != 1.)) { new_pos.add_scaled (this->point(n), em_val); calculated_new_pos = true; } } if(calculated_new_pos) { //Move the existing node back into it's original location for(unsigned int i=0; i<LIBMESH_DIM; i++) { Point & child_node = *(mychild->get_node(nc)); child_node(i)=new_pos(i); } } } } for (unsigned int c=0; c<this->n_children(); c++) { Elem *mychild = this->child(c); if (mychild == remote_elem) continue; libmesh_assert (mychild->refinement_flag() == Elem::COARSEN); mychild->set_refinement_flag(Elem::INACTIVE); if (mychild->p_level() > parent_p_level) parent_p_level = mychild->p_level(); } this->set_refinement_flag(Elem::JUST_COARSENED); this->set_p_level(parent_p_level); libmesh_assert (this->active()); }
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; }
//----------------------------------------------------------------- // Mesh refinement methods bool MeshRefinement::limit_level_mismatch_at_node (const unsigned int max_mismatch) { // This function must be run on all processors at once parallel_only(); bool flags_changed = false; // Vector holding the maximum element level that touches a node. std::vector<unsigned char> max_level_at_node (_mesh.n_nodes(), 0); std::vector<unsigned char> max_p_level_at_node (_mesh.n_nodes(), 0); // Loop over all the active elements & fill the vector { MeshBase::element_iterator elem_it = _mesh.active_elements_begin(); const MeshBase::element_iterator elem_end = _mesh.active_elements_end(); for (; elem_it != elem_end; ++elem_it) { const Elem* elem = *elem_it; const unsigned char elem_level = elem->level() + ((elem->refinement_flag() == Elem::REFINE) ? 1 : 0); const unsigned char elem_p_level = elem->p_level() + ((elem->p_refinement_flag() == Elem::REFINE) ? 1 : 0); // Set the max_level at each node for (unsigned int n=0; n<elem->n_nodes(); n++) { const unsigned int node_number = elem->node(n); libmesh_assert_less (node_number, max_level_at_node.size()); max_level_at_node[node_number] = std::max (max_level_at_node[node_number], elem_level); max_p_level_at_node[node_number] = std::max (max_p_level_at_node[node_number], elem_p_level); } } } // Now loop over the active elements and flag the elements // who violate the requested level mismatch { MeshBase::element_iterator elem_it = _mesh.active_elements_begin(); const MeshBase::element_iterator elem_end = _mesh.active_elements_end(); for (; elem_it != elem_end; ++elem_it) { Elem* elem = *elem_it; const unsigned int elem_level = elem->level(); const unsigned int elem_p_level = elem->p_level(); // Skip the element if it is already fully flagged if (elem->refinement_flag() == Elem::REFINE && elem->p_refinement_flag() == Elem::REFINE) continue; // Loop over the nodes, check for possible mismatch for (unsigned int n=0; n<elem->n_nodes(); n++) { const unsigned int node_number = elem->node(n); // Flag the element for refinement if it violates // the requested level mismatch if ( (elem_level + max_mismatch) < max_level_at_node[node_number] && elem->refinement_flag() != Elem::REFINE) { elem->set_refinement_flag (Elem::REFINE); flags_changed = true; } if ( (elem_p_level + max_mismatch) < max_p_level_at_node[node_number] && elem->p_refinement_flag() != Elem::REFINE) { elem->set_p_refinement_flag (Elem::REFINE); flags_changed = true; } } } } // If flags changed on any processor then they changed globally CommWorld.max(flags_changed); return flags_changed; }
bool MeshRefinement::eliminate_unrefined_patches () { // This function must be run on all processors at once parallel_only(); bool flags_changed = false; MeshBase::element_iterator elem_it = _mesh.active_elements_begin(); const MeshBase::element_iterator elem_end = _mesh.active_elements_end(); for (; elem_it != elem_end; ++elem_it) { Elem* elem = *elem_it; // First assume that we'll have to flag this element for both h // and p refinement, then change our minds if we see any // neighbors that are as coarse or coarser than us. bool h_flag_me = true, p_flag_me = true; // Skip the element if it is already fully flagged for refinement if (elem->p_refinement_flag() == Elem::REFINE) p_flag_me = false; if (elem->refinement_flag() == Elem::REFINE) { h_flag_me = false; if (!p_flag_me) continue; } // Test the parent if that is already flagged for coarsening else if (elem->refinement_flag() == Elem::COARSEN) { libmesh_assert(elem->parent()); elem = elem->parent(); // FIXME - this doesn't seem right - RHS if (elem->refinement_flag() != Elem::COARSEN_INACTIVE) continue; p_flag_me = false; } const unsigned int my_level = elem->level(); int my_p_adjustment = 0; if (elem->p_refinement_flag() == Elem::REFINE) my_p_adjustment = 1; else if (elem->p_refinement_flag() == Elem::COARSEN) { libmesh_assert_greater (elem->p_level(), 0); my_p_adjustment = -1; } const unsigned int my_new_p_level = elem->p_level() + my_p_adjustment; // Check all the element neighbors for (unsigned int n=0; n<elem->n_neighbors(); n++) { const Elem *neighbor = elem->neighbor(n); // Quit if the element is on a local boundary if (neighbor == NULL || neighbor == remote_elem) { h_flag_me = false; p_flag_me = false; break; } // if the neighbor will be equally or less refined than // we are, then we will not become an unrefined island. // So if we are still considering h refinement: if (h_flag_me && // If our neighbor is already at a lower level, // it can't end up at a higher level even if it // is flagged for refinement once ((neighbor->level() < my_level) || // If our neighbor is at the same level but isn't // flagged for refinement, it won't end up at a // higher level ((neighbor->active()) && (neighbor->refinement_flag() != Elem::REFINE)) || // If our neighbor is currently more refined but is // a parent flagged for coarsening, it will end up // at the same level. (neighbor->refinement_flag() == Elem::COARSEN_INACTIVE))) { // We've proven we won't become an unrefined island, // so don't h refine to avoid that. h_flag_me = false; // If we've also proven we don't need to p refine, // we don't need to check more neighbors if (!p_flag_me) break; } if (p_flag_me) { // if active neighbors will have a p level // equal to or lower than ours, then we do not need to p // refine ourselves. if (neighbor->active()) { int p_adjustment = 0; if (neighbor->p_refinement_flag() == Elem::REFINE) p_adjustment = 1; else if (neighbor->p_refinement_flag() == Elem::COARSEN) { libmesh_assert_greater (neighbor->p_level(), 0); p_adjustment = -1; } if (my_new_p_level >= neighbor->p_level() + p_adjustment) { p_flag_me = false; if (!h_flag_me) break; } } // If we have inactive neighbors, we need to // test all their active descendants which neighbor us else if (neighbor->ancestor()) { if (neighbor->min_new_p_level_by_neighbor(elem, my_new_p_level + 2) <= my_new_p_level) { p_flag_me = false; if (!h_flag_me) break; } } } } if (h_flag_me) { // Parents that would create islands should no longer // coarsen if (elem->refinement_flag() == Elem::COARSEN_INACTIVE) { for (unsigned int c=0; c<elem->n_children(); c++) { libmesh_assert_equal_to (elem->child(c)->refinement_flag(), Elem::COARSEN); elem->child(c)->set_refinement_flag(Elem::DO_NOTHING); } elem->set_refinement_flag(Elem::INACTIVE); } else elem->set_refinement_flag(Elem::REFINE); flags_changed = true; } if (p_flag_me) { if (elem->p_refinement_flag() == Elem::COARSEN) elem->set_p_refinement_flag(Elem::DO_NOTHING); else elem->set_p_refinement_flag(Elem::REFINE); flags_changed = true; } } // If flags changed on any processor then they changed globally CommWorld.max(flags_changed); return flags_changed; }
//----------------------------------------------------------------- // Mesh refinement methods bool MeshRefinement::limit_level_mismatch_at_edge (const unsigned int max_mismatch) { // This function must be run on all processors at once parallel_only(); bool flags_changed = false; // Maps holding the maximum element level that touches an edge std::map<std::pair<unsigned int, unsigned int>, unsigned char> max_level_at_edge; std::map<std::pair<unsigned int, unsigned int>, unsigned char> max_p_level_at_edge; // Loop over all the active elements & fill the maps { MeshBase::element_iterator elem_it = _mesh.active_elements_begin(); const MeshBase::element_iterator elem_end = _mesh.active_elements_end(); for (; elem_it != elem_end; ++elem_it) { const Elem* elem = *elem_it; const unsigned char elem_level = elem->level() + ((elem->refinement_flag() == Elem::REFINE) ? 1 : 0); const unsigned char elem_p_level = elem->p_level() + ((elem->p_refinement_flag() == Elem::REFINE) ? 1 : 0); // Set the max_level at each edge for (unsigned int n=0; n<elem->n_edges(); n++) { AutoPtr<Elem> edge = elem->build_edge(n); unsigned int childnode0 = edge->node(0); unsigned int childnode1 = edge->node(1); if (childnode1 < childnode0) std::swap(childnode0, childnode1); for (const Elem *p = elem; p != NULL; p = p->parent()) { AutoPtr<Elem> pedge = p->build_edge(n); unsigned int node0 = pedge->node(0); unsigned int node1 = pedge->node(1); if (node1 < node0) std::swap(node0, node1); // If elem does not share this edge with its ancestor // p, refinement levels of elements sharing p's edge // are not restricted by refinement levels of elem. // Furthermore, elem will not share this edge with any // of p's ancestors, so we can safely break out of the // for loop early. if (node0 != childnode0 && node1 != childnode1) break; childnode0 = node0; childnode1 = node1; std::pair<unsigned int, unsigned int> edge_key = std::make_pair(node0, node1); if (max_level_at_edge.find(edge_key) == max_level_at_edge.end()) { max_level_at_edge[edge_key] = elem_level; max_p_level_at_edge[edge_key] = elem_p_level; } else { max_level_at_edge[edge_key] = std::max (max_level_at_edge[edge_key], elem_level); max_p_level_at_edge[edge_key] = std::max (max_p_level_at_edge[edge_key], elem_p_level); } } } } } // Now loop over the active elements and flag the elements // who violate the requested level mismatch { MeshBase::element_iterator elem_it = _mesh.active_elements_begin(); const MeshBase::element_iterator elem_end = _mesh.active_elements_end(); for (; elem_it != elem_end; ++elem_it) { Elem* elem = *elem_it; const unsigned int elem_level = elem->level(); const unsigned int elem_p_level = elem->p_level(); // Skip the element if it is already fully flagged if (elem->refinement_flag() == Elem::REFINE && elem->p_refinement_flag() == Elem::REFINE) continue; // Loop over the nodes, check for possible mismatch for (unsigned int n=0; n<elem->n_edges(); n++) { AutoPtr<Elem> edge = elem->build_edge(n); unsigned int node0 = edge->node(0); unsigned int node1 = edge->node(1); if (node1 < node0) std::swap(node0, node1); std::pair<unsigned int, unsigned int> edge_key = std::make_pair(node0, node1); // Flag the element for refinement if it violates // the requested level mismatch if ( (elem_level + max_mismatch) < max_level_at_edge[edge_key] && elem->refinement_flag() != Elem::REFINE) { elem->set_refinement_flag (Elem::REFINE); flags_changed = true; } if ( (elem_p_level + max_mismatch) < max_p_level_at_edge[edge_key] && elem->p_refinement_flag() != Elem::REFINE) { elem->set_p_refinement_flag (Elem::REFINE); flags_changed = true; } } } } // If flags changed on any processor then they changed globally CommWorld.max(flags_changed); return flags_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; }
void HPCoarsenTest::select_refinement (System & system) { START_LOG("select_refinement()", "HPCoarsenTest"); // The current mesh MeshBase & mesh = system.get_mesh(); // The dimensionality of the mesh const unsigned int dim = mesh.mesh_dimension(); // The number of variables in the system const unsigned int n_vars = system.n_vars(); // The DofMap for this system const DofMap & dof_map = system.get_dof_map(); // The system number (for doing bad hackery) const unsigned int sys_num = system.number(); // Check for a valid component_scale if (!component_scale.empty()) { if (component_scale.size() != n_vars) libmesh_error_msg("ERROR: component_scale is the wrong size:\n" \ << " component_scale.size()=" \ << component_scale.size() \ << "\n n_vars=" \ << n_vars); } else { // No specified scaling. Scale all variables by one. component_scale.resize (n_vars, 1.0); } // Resize the error_per_cell vectors to handle // the number of elements, initialize them to 0. std::vector<ErrorVectorReal> h_error_per_cell(mesh.max_elem_id(), 0.); std::vector<ErrorVectorReal> p_error_per_cell(mesh.max_elem_id(), 0.); // Loop over all the variables in the system for (unsigned int var=0; var<n_vars; var++) { // Possibly skip this variable if (!component_scale.empty()) if (component_scale[var] == 0.0) continue; // The type of finite element to use for this variable const FEType & fe_type = dof_map.variable_type (var); // Finite element objects for a fine (and probably a coarse) // element will be needed fe = FEBase::build (dim, fe_type); fe_coarse = FEBase::build (dim, fe_type); // Any cached coarse element results have expired coarse = libmesh_nullptr; unsigned int cached_coarse_p_level = 0; const FEContinuity cont = fe->get_continuity(); libmesh_assert (cont == DISCONTINUOUS || cont == C_ZERO || cont == C_ONE); // Build an appropriate quadrature rule qrule = fe_type.default_quadrature_rule(dim); // Tell the refined finite element about the quadrature // rule. The coarse finite element need not know about it fe->attach_quadrature_rule (qrule.get()); // We will always do the integration // on the fine elements. Get their Jacobian values, etc.. JxW = &(fe->get_JxW()); xyz_values = &(fe->get_xyz()); // The shape functions phi = &(fe->get_phi()); phi_coarse = &(fe_coarse->get_phi()); // The shape function derivatives if (cont == C_ZERO || cont == C_ONE) { dphi = &(fe->get_dphi()); dphi_coarse = &(fe_coarse->get_dphi()); } #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES // The shape function second derivatives if (cont == C_ONE) { d2phi = &(fe->get_d2phi()); d2phi_coarse = &(fe_coarse->get_d2phi()); } #endif // defined (LIBMESH_ENABLE_SECOND_DERIVATIVES) // Iterate over all the active elements in the mesh // that live on this processor. MeshBase::const_element_iterator elem_it = mesh.active_local_elements_begin(); const MeshBase::const_element_iterator elem_end = mesh.active_local_elements_end(); for (; elem_it != elem_end; ++elem_it) { const Elem * elem = *elem_it; // We're only checking elements that are already flagged for h // refinement if (elem->refinement_flag() != Elem::REFINE) continue; const dof_id_type e_id = elem->id(); // Find the projection onto the parent element, // if necessary if (elem->parent() && (coarse != elem->parent() || cached_coarse_p_level != elem->p_level())) { Uc.resize(0); coarse = elem->parent(); cached_coarse_p_level = elem->p_level(); unsigned int old_parent_level = coarse->p_level(); (const_cast<Elem *>(coarse))->hack_p_level(elem->p_level()); this->add_projection(system, coarse, var); (const_cast<Elem *>(coarse))->hack_p_level(old_parent_level); // Solve the h-coarsening projection problem Ke.cholesky_solve(Fe, Uc); } fe->reinit(elem); // Get the DOF indices for the fine element dof_map.dof_indices (elem, dof_indices, var); // The number of quadrature points const unsigned int n_qp = qrule->n_points(); // The number of DOFS on the fine element const unsigned int n_dofs = cast_int<unsigned int>(dof_indices.size()); // The number of nodes on the fine element const unsigned int n_nodes = elem->n_nodes(); // The average element value (used as an ugly hack // when we have nothing p-coarsened to compare to) // Real average_val = 0.; Number average_val = 0.; // Calculate this variable's contribution to the p // refinement error if (elem->p_level() == 0) { unsigned int n_vertices = 0; for (unsigned int n = 0; n != n_nodes; ++n) if (elem->is_vertex(n)) { n_vertices++; const Node * const node = elem->get_node(n); average_val += system.current_solution (node->dof_number(sys_num,var,0)); } average_val /= n_vertices; } else { unsigned int old_elem_level = elem->p_level(); (const_cast<Elem *>(elem))->hack_p_level(old_elem_level - 1); fe_coarse->reinit(elem, &(qrule->get_points())); const unsigned int n_coarse_dofs = cast_int<unsigned int>(phi_coarse->size()); (const_cast<Elem *>(elem))->hack_p_level(old_elem_level); Ke.resize(n_coarse_dofs, n_coarse_dofs); Ke.zero(); Fe.resize(n_coarse_dofs); Fe.zero(); // Loop over the quadrature points for (unsigned int qp=0; qp<qrule->n_points(); qp++) { // The solution value at the quadrature point Number val = libMesh::zero; Gradient grad; Tensor hess; for (unsigned int i=0; i != n_dofs; i++) { dof_id_type dof_num = dof_indices[i]; val += (*phi)[i][qp] * system.current_solution(dof_num); if (cont == C_ZERO || cont == C_ONE) grad.add_scaled((*dphi)[i][qp], system.current_solution(dof_num)); // grad += (*dphi)[i][qp] * // system.current_solution(dof_num); if (cont == C_ONE) hess.add_scaled((*d2phi)[i][qp], system.current_solution(dof_num)); // hess += (*d2phi)[i][qp] * // system.current_solution(dof_num); } // The projection matrix and vector for (unsigned int i=0; i != Fe.size(); ++i) { Fe(i) += (*JxW)[qp] * (*phi_coarse)[i][qp]*val; if (cont == C_ZERO || cont == C_ONE) Fe(i) += (*JxW)[qp] * grad * (*dphi_coarse)[i][qp]; if (cont == C_ONE) Fe(i) += (*JxW)[qp] * hess.contract((*d2phi_coarse)[i][qp]); for (unsigned int j=0; j != Fe.size(); ++j) { Ke(i,j) += (*JxW)[qp] * (*phi_coarse)[i][qp]*(*phi_coarse)[j][qp]; if (cont == C_ZERO || cont == C_ONE) Ke(i,j) += (*JxW)[qp] * (*dphi_coarse)[i][qp]*(*dphi_coarse)[j][qp]; if (cont == C_ONE) Ke(i,j) += (*JxW)[qp] * ((*d2phi_coarse)[i][qp].contract((*d2phi_coarse)[j][qp])); } } } // Solve the p-coarsening projection problem Ke.cholesky_solve(Fe, Up); } // loop over the integration points on the fine element for (unsigned int qp=0; qp<n_qp; qp++) { Number value_error = 0.; Gradient grad_error; Tensor hessian_error; for (unsigned int i=0; i<n_dofs; i++) { const dof_id_type dof_num = dof_indices[i]; value_error += (*phi)[i][qp] * system.current_solution(dof_num); if (cont == C_ZERO || cont == C_ONE) grad_error.add_scaled((*dphi)[i][qp], system.current_solution(dof_num)); // grad_error += (*dphi)[i][qp] * // system.current_solution(dof_num); if (cont == C_ONE) hessian_error.add_scaled((*d2phi)[i][qp], system.current_solution(dof_num)); // hessian_error += (*d2phi)[i][qp] * // system.current_solution(dof_num); } if (elem->p_level() == 0) { value_error -= average_val; } else { for (unsigned int i=0; i<Up.size(); i++) { value_error -= (*phi_coarse)[i][qp] * Up(i); if (cont == C_ZERO || cont == C_ONE) grad_error.subtract_scaled((*dphi_coarse)[i][qp], Up(i)); // grad_error -= (*dphi_coarse)[i][qp] * Up(i); if (cont == C_ONE) hessian_error.subtract_scaled((*d2phi_coarse)[i][qp], Up(i)); // hessian_error -= (*d2phi_coarse)[i][qp] * Up(i); } } p_error_per_cell[e_id] += static_cast<ErrorVectorReal> (component_scale[var] * (*JxW)[qp] * TensorTools::norm_sq(value_error)); if (cont == C_ZERO || cont == C_ONE) p_error_per_cell[e_id] += static_cast<ErrorVectorReal> (component_scale[var] * (*JxW)[qp] * grad_error.norm_sq()); if (cont == C_ONE) p_error_per_cell[e_id] += static_cast<ErrorVectorReal> (component_scale[var] * (*JxW)[qp] * hessian_error.norm_sq()); } // Calculate this variable's contribution to the h // refinement error if (!elem->parent()) { // For now, we'll always start with an h refinement h_error_per_cell[e_id] = std::numeric_limits<ErrorVectorReal>::max() / 2; } else { FEInterface::inverse_map (dim, fe_type, coarse, *xyz_values, coarse_qpoints); unsigned int old_parent_level = coarse->p_level(); (const_cast<Elem *>(coarse))->hack_p_level(elem->p_level()); fe_coarse->reinit(coarse, &coarse_qpoints); (const_cast<Elem *>(coarse))->hack_p_level(old_parent_level); // The number of DOFS on the coarse element unsigned int n_coarse_dofs = cast_int<unsigned int>(phi_coarse->size()); // Loop over the quadrature points for (unsigned int qp=0; qp<n_qp; qp++) { // The solution difference at the quadrature point Number value_error = libMesh::zero; Gradient grad_error; Tensor hessian_error; for (unsigned int i=0; i != n_dofs; ++i) { const dof_id_type dof_num = dof_indices[i]; value_error += (*phi)[i][qp] * system.current_solution(dof_num); if (cont == C_ZERO || cont == C_ONE) grad_error.add_scaled((*dphi)[i][qp], system.current_solution(dof_num)); // grad_error += (*dphi)[i][qp] * // system.current_solution(dof_num); if (cont == C_ONE) hessian_error.add_scaled((*d2phi)[i][qp], system.current_solution(dof_num)); // hessian_error += (*d2phi)[i][qp] * // system.current_solution(dof_num); } for (unsigned int i=0; i != n_coarse_dofs; ++i) { value_error -= (*phi_coarse)[i][qp] * Uc(i); if (cont == C_ZERO || cont == C_ONE) // grad_error -= (*dphi_coarse)[i][qp] * Uc(i); grad_error.subtract_scaled((*dphi_coarse)[i][qp], Uc(i)); if (cont == C_ONE) hessian_error.subtract_scaled((*d2phi_coarse)[i][qp], Uc(i)); // hessian_error -= (*d2phi_coarse)[i][qp] * Uc(i); } h_error_per_cell[e_id] += static_cast<ErrorVectorReal> (component_scale[var] * (*JxW)[qp] * TensorTools::norm_sq(value_error)); if (cont == C_ZERO || cont == C_ONE) h_error_per_cell[e_id] += static_cast<ErrorVectorReal> (component_scale[var] * (*JxW)[qp] * grad_error.norm_sq()); if (cont == C_ONE) h_error_per_cell[e_id] += static_cast<ErrorVectorReal> (component_scale[var] * (*JxW)[qp] * hessian_error.norm_sq()); } } } } // Now that we've got our approximations for p_error and h_error, let's see // if we want to switch any h refinement flags to p refinement // Iterate over all the active elements in the mesh // that live on this processor. MeshBase::element_iterator elem_it = mesh.active_local_elements_begin(); const MeshBase::element_iterator elem_end = mesh.active_local_elements_end(); for (; elem_it != elem_end; ++elem_it) { Elem * elem = *elem_it; // We're only checking elements that are already flagged for h // refinement if (elem->refinement_flag() != Elem::REFINE) continue; const dof_id_type e_id = elem->id(); unsigned int dofs_per_elem = 0, dofs_per_p_elem = 0; // Loop over all the variables in the system for (unsigned int var=0; var<n_vars; var++) { // The type of finite element to use for this variable const FEType & fe_type = dof_map.variable_type (var); // FIXME: we're overestimating the number of DOFs added by h // refinement FEType elem_fe_type = fe_type; elem_fe_type.order = static_cast<Order>(fe_type.order + elem->p_level()); dofs_per_elem += FEInterface::n_dofs(dim, elem_fe_type, elem->type()); elem_fe_type.order = static_cast<Order>(fe_type.order + elem->p_level() + 1); dofs_per_p_elem += FEInterface::n_dofs(dim, elem_fe_type, elem->type()); } const unsigned int new_h_dofs = dofs_per_elem * (elem->n_children() - 1); const unsigned int new_p_dofs = dofs_per_p_elem - dofs_per_elem; /* libMesh::err << "Cell " << e_id << ": h = " << elem->hmax() << ", p = " << elem->p_level() + 1 << "," << std::endl << " h_error = " << h_error_per_cell[e_id] << ", p_error = " << p_error_per_cell[e_id] << std::endl << " new_h_dofs = " << new_h_dofs << ", new_p_dofs = " << new_p_dofs << std::endl; */ const Real p_value = std::sqrt(p_error_per_cell[e_id]) * p_weight / new_p_dofs; const Real h_value = std::sqrt(h_error_per_cell[e_id]) / static_cast<Real>(new_h_dofs); if (p_value > h_value) { elem->set_p_refinement_flag(Elem::REFINE); elem->set_refinement_flag(Elem::DO_NOTHING); } } STOP_LOG("select_refinement()", "HPCoarsenTest"); }
//----------------------------------------------------------------- // Mesh refinement methods bool MeshRefinement::limit_level_mismatch_at_node (const unsigned int max_mismatch) { // This function must be run on all processors at once parallel_object_only(); bool flags_changed = false; // Vector holding the maximum element level that touches a node. std::vector<unsigned char> max_level_at_node (_mesh.n_nodes(), 0); std::vector<unsigned char> max_p_level_at_node (_mesh.n_nodes(), 0); // Loop over all the active elements & fill the vector { MeshBase::element_iterator elem_it = _mesh.active_elements_begin(); const MeshBase::element_iterator elem_end = _mesh.active_elements_end(); for (; elem_it != elem_end; ++elem_it) { const Elem* elem = *elem_it; const unsigned char elem_level = cast_int<unsigned char>(elem->level() + ((elem->refinement_flag() == Elem::REFINE) ? 1 : 0)); const unsigned char elem_p_level = cast_int<unsigned char>(elem->p_level() + ((elem->p_refinement_flag() == Elem::REFINE) ? 1 : 0)); // Set the max_level at each node for (unsigned int n=0; n<elem->n_nodes(); n++) { const dof_id_type node_number = elem->node(n); libmesh_assert_less (node_number, max_level_at_node.size()); max_level_at_node[node_number] = std::max (max_level_at_node[node_number], elem_level); max_p_level_at_node[node_number] = std::max (max_p_level_at_node[node_number], elem_p_level); } } } // Now loop over the active elements and flag the elements // who violate the requested level mismatch. Alternatively, if // _enforce_mismatch_limit_prior_to_refinement is true, swap refinement flags // accordingly. { MeshBase::element_iterator elem_it = _mesh.active_elements_begin(); const MeshBase::element_iterator elem_end = _mesh.active_elements_end(); for (; elem_it != elem_end; ++elem_it) { Elem* elem = *elem_it; const unsigned int elem_level = elem->level(); const unsigned int elem_p_level = elem->p_level(); // Skip the element if it is already fully flagged // unless we are enforcing mismatch prior to refienemnt and may need to // remove the refinement flag(s) if (elem->refinement_flag() == Elem::REFINE && elem->p_refinement_flag() == Elem::REFINE && !_enforce_mismatch_limit_prior_to_refinement) continue; // Loop over the nodes, check for possible mismatch for (unsigned int n=0; n<elem->n_nodes(); n++) { const dof_id_type node_number = elem->node(n); // Flag the element for refinement if it violates // the requested level mismatch if ((elem_level + max_mismatch) < max_level_at_node[node_number] && elem->refinement_flag() != Elem::REFINE) { elem->set_refinement_flag (Elem::REFINE); flags_changed = true; } if ((elem_p_level + max_mismatch) < max_p_level_at_node[node_number] && elem->p_refinement_flag() != Elem::REFINE) { elem->set_p_refinement_flag (Elem::REFINE); flags_changed = true; } // Possibly enforce limit mismatch prior to refinement flags_changed |= this->enforce_mismatch_limit_prior_to_refinement(elem, POINT, max_mismatch); } } } // If flags changed on any processor then they changed globally this->comm().max(flags_changed); return flags_changed; }