$extrastylesheet
00001 // The libMesh Finite Element Library. 00002 // Copyright (C) 2002-2014 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner 00003 00004 // This library is free software; you can redistribute it and/or 00005 // modify it under the terms of the GNU Lesser General Public 00006 // License as published by the Free Software Foundation; either 00007 // version 2.1 of the License, or (at your option) any later version. 00008 00009 // This library is distributed in the hope that it will be useful, 00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 // Lesser General Public License for more details. 00013 00014 // You should have received a copy of the GNU Lesser General Public 00015 // License along with this library; if not, write to the Free Software 00016 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00017 00018 00019 00020 // Local includes 00021 #include "libmesh/libmesh_config.h" 00022 00023 // only compile these functions if the user requests AMR support 00024 #ifdef LIBMESH_ENABLE_AMR 00025 00026 #include "libmesh/elem.h" 00027 #include "libmesh/mesh_base.h" 00028 #include "libmesh/mesh_refinement.h" 00029 #include "libmesh/parallel.h" 00030 #include "libmesh/remote_elem.h" 00031 00032 namespace libMesh 00033 { 00034 00035 00036 00037 //----------------------------------------------------------------- 00038 // Mesh refinement methods 00039 bool MeshRefinement::limit_level_mismatch_at_node (const unsigned int max_mismatch) 00040 { 00041 // This function must be run on all processors at once 00042 parallel_object_only(); 00043 00044 bool flags_changed = false; 00045 00046 00047 // Vector holding the maximum element level that touches a node. 00048 std::vector<unsigned char> max_level_at_node (_mesh.n_nodes(), 0); 00049 std::vector<unsigned char> max_p_level_at_node (_mesh.n_nodes(), 0); 00050 00051 // Loop over all the active elements & fill the vector 00052 { 00053 MeshBase::element_iterator elem_it = _mesh.active_elements_begin(); 00054 const MeshBase::element_iterator elem_end = _mesh.active_elements_end(); 00055 00056 for (; elem_it != elem_end; ++elem_it) 00057 { 00058 const Elem* elem = *elem_it; 00059 const unsigned char elem_level = 00060 cast_int<unsigned char>(elem->level() + 00061 ((elem->refinement_flag() == Elem::REFINE) ? 1 : 0)); 00062 const unsigned char elem_p_level = 00063 cast_int<unsigned char>(elem->p_level() + 00064 ((elem->p_refinement_flag() == Elem::REFINE) ? 1 : 0)); 00065 00066 // Set the max_level at each node 00067 for (unsigned int n=0; n<elem->n_nodes(); n++) 00068 { 00069 const dof_id_type node_number = elem->node(n); 00070 00071 libmesh_assert_less (node_number, max_level_at_node.size()); 00072 00073 max_level_at_node[node_number] = 00074 std::max (max_level_at_node[node_number], elem_level); 00075 max_p_level_at_node[node_number] = 00076 std::max (max_p_level_at_node[node_number], elem_p_level); 00077 } 00078 } 00079 } 00080 00081 00082 // Now loop over the active elements and flag the elements 00083 // who violate the requested level mismatch. Alternatively, if 00084 // _enforce_mismatch_limit_prior_to_refinement is true, swap refinement flags 00085 // accordingly. 00086 { 00087 MeshBase::element_iterator elem_it = _mesh.active_elements_begin(); 00088 const MeshBase::element_iterator elem_end = _mesh.active_elements_end(); 00089 00090 for (; elem_it != elem_end; ++elem_it) 00091 { 00092 Elem* elem = *elem_it; 00093 const unsigned int elem_level = elem->level(); 00094 const unsigned int elem_p_level = elem->p_level(); 00095 00096 // Skip the element if it is already fully flagged 00097 // unless we are enforcing mismatch prior to refienemnt and may need to 00098 // remove the refinement flag(s) 00099 if (elem->refinement_flag() == Elem::REFINE && 00100 elem->p_refinement_flag() == Elem::REFINE 00101 && !_enforce_mismatch_limit_prior_to_refinement) 00102 continue; 00103 00104 // Loop over the nodes, check for possible mismatch 00105 for (unsigned int n=0; n<elem->n_nodes(); n++) 00106 { 00107 const dof_id_type node_number = elem->node(n); 00108 00109 // Flag the element for refinement if it violates 00110 // the requested level mismatch 00111 if ((elem_level + max_mismatch) < max_level_at_node[node_number] 00112 && elem->refinement_flag() != Elem::REFINE) 00113 { 00114 elem->set_refinement_flag (Elem::REFINE); 00115 flags_changed = true; 00116 } 00117 if ((elem_p_level + max_mismatch) < max_p_level_at_node[node_number] 00118 && elem->p_refinement_flag() != Elem::REFINE) 00119 { 00120 elem->set_p_refinement_flag (Elem::REFINE); 00121 flags_changed = true; 00122 } 00123 00124 // Possibly enforce limit mismatch prior to refinement 00125 flags_changed |= this->enforce_mismatch_limit_prior_to_refinement(elem, POINT, max_mismatch); 00126 } 00127 } 00128 } 00129 00130 // If flags changed on any processor then they changed globally 00131 this->comm().max(flags_changed); 00132 00133 return flags_changed; 00134 } 00135 00136 00137 00138 //----------------------------------------------------------------- 00139 // Mesh refinement methods 00140 bool MeshRefinement::limit_level_mismatch_at_edge (const unsigned int max_mismatch) 00141 { 00142 // This function must be run on all processors at once 00143 parallel_object_only(); 00144 00145 bool flags_changed = false; 00146 00147 00148 // Maps holding the maximum element level that touches an edge 00149 std::map<std::pair<unsigned int, unsigned int>, unsigned char> 00150 max_level_at_edge; 00151 std::map<std::pair<unsigned int, unsigned int>, unsigned char> 00152 max_p_level_at_edge; 00153 00154 // Loop over all the active elements & fill the maps 00155 { 00156 MeshBase::element_iterator elem_it = _mesh.active_elements_begin(); 00157 const MeshBase::element_iterator elem_end = _mesh.active_elements_end(); 00158 00159 for (; elem_it != elem_end; ++elem_it) 00160 { 00161 const Elem* elem = *elem_it; 00162 const unsigned char elem_level = 00163 cast_int<unsigned char>(elem->level() + 00164 ((elem->refinement_flag() == Elem::REFINE) ? 1 : 0)); 00165 const unsigned char elem_p_level = 00166 cast_int<unsigned char>(elem->p_level() + 00167 ((elem->p_refinement_flag() == Elem::REFINE) ? 1 : 0)); 00168 00169 // Set the max_level at each edge 00170 for (unsigned int n=0; n<elem->n_edges(); n++) 00171 { 00172 UniquePtr<Elem> edge = elem->build_edge(n); 00173 dof_id_type childnode0 = edge->node(0); 00174 dof_id_type childnode1 = edge->node(1); 00175 if (childnode1 < childnode0) 00176 std::swap(childnode0, childnode1); 00177 00178 for (const Elem *p = elem; p != NULL; p = p->parent()) 00179 { 00180 UniquePtr<Elem> pedge = p->build_edge(n); 00181 dof_id_type node0 = pedge->node(0); 00182 dof_id_type node1 = pedge->node(1); 00183 00184 if (node1 < node0) 00185 std::swap(node0, node1); 00186 00187 // If elem does not share this edge with its ancestor 00188 // p, refinement levels of elements sharing p's edge 00189 // are not restricted by refinement levels of elem. 00190 // Furthermore, elem will not share this edge with any 00191 // of p's ancestors, so we can safely break out of the 00192 // for loop early. 00193 if (node0 != childnode0 && node1 != childnode1) 00194 break; 00195 00196 childnode0 = node0; 00197 childnode1 = node1; 00198 00199 std::pair<unsigned int, unsigned int> edge_key = 00200 std::make_pair(node0, node1); 00201 00202 if (max_level_at_edge.find(edge_key) == 00203 max_level_at_edge.end()) 00204 { 00205 max_level_at_edge[edge_key] = elem_level; 00206 max_p_level_at_edge[edge_key] = elem_p_level; 00207 } 00208 else 00209 { 00210 max_level_at_edge[edge_key] = 00211 std::max (max_level_at_edge[edge_key], elem_level); 00212 max_p_level_at_edge[edge_key] = 00213 std::max (max_p_level_at_edge[edge_key], elem_p_level); 00214 } 00215 } 00216 } 00217 } 00218 } 00219 00220 00221 // Now loop over the active elements and flag the elements 00222 // who violate the requested level mismatch 00223 { 00224 MeshBase::element_iterator elem_it = _mesh.active_elements_begin(); 00225 const MeshBase::element_iterator elem_end = _mesh.active_elements_end(); 00226 00227 for (; elem_it != elem_end; ++elem_it) 00228 { 00229 Elem* elem = *elem_it; 00230 const unsigned int elem_level = elem->level(); 00231 const unsigned int elem_p_level = elem->p_level(); 00232 00233 // Skip the element if it is already fully flagged 00234 if (elem->refinement_flag() == Elem::REFINE && 00235 elem->p_refinement_flag() == Elem::REFINE 00236 && !_enforce_mismatch_limit_prior_to_refinement) 00237 continue; 00238 00239 // Loop over the nodes, check for possible mismatch 00240 for (unsigned int n=0; n<elem->n_edges(); n++) 00241 { 00242 UniquePtr<Elem> edge = elem->build_edge(n); 00243 dof_id_type node0 = edge->node(0); 00244 dof_id_type node1 = edge->node(1); 00245 if (node1 < node0) 00246 std::swap(node0, node1); 00247 00248 std::pair<dof_id_type, dof_id_type> edge_key = 00249 std::make_pair(node0, node1); 00250 00251 // Flag the element for refinement if it violates 00252 // the requested level mismatch 00253 if ((elem_level + max_mismatch) < max_level_at_edge[edge_key] 00254 && elem->refinement_flag() != Elem::REFINE) 00255 { 00256 elem->set_refinement_flag (Elem::REFINE); 00257 flags_changed = true; 00258 } 00259 00260 if ((elem_p_level + max_mismatch) < max_p_level_at_edge[edge_key] 00261 && elem->p_refinement_flag() != Elem::REFINE) 00262 { 00263 elem->set_p_refinement_flag (Elem::REFINE); 00264 flags_changed = true; 00265 } 00266 00267 // Possibly enforce limit mismatch prior to refinement 00268 flags_changed |= this->enforce_mismatch_limit_prior_to_refinement(elem, EDGE, max_mismatch); 00269 } // loop over edges 00270 } // loop over active elements 00271 } 00272 00273 // If flags changed on any processor then they changed globally 00274 this->comm().max(flags_changed); 00275 00276 return flags_changed; 00277 } 00278 00279 00280 00281 00282 bool MeshRefinement::eliminate_unrefined_patches () 00283 { 00284 // This function must be run on all processors at once 00285 parallel_object_only(); 00286 00287 bool flags_changed = false; 00288 00289 MeshBase::element_iterator elem_it = _mesh.active_elements_begin(); 00290 const MeshBase::element_iterator elem_end = _mesh.active_elements_end(); 00291 00292 for (; elem_it != elem_end; ++elem_it) 00293 { 00294 Elem* elem = *elem_it; 00295 // First assume that we'll have to flag this element for both h 00296 // and p refinement, then change our minds if we see any 00297 // neighbors that are as coarse or coarser than us. 00298 bool h_flag_me = true, 00299 p_flag_me = true; 00300 00301 00302 // Skip the element if it is already fully flagged for refinement 00303 if (elem->p_refinement_flag() == Elem::REFINE) 00304 p_flag_me = false; 00305 if (elem->refinement_flag() == Elem::REFINE) 00306 { 00307 h_flag_me = false; 00308 if (!p_flag_me) 00309 continue; 00310 } 00311 // Test the parent if that is already flagged for coarsening 00312 else if (elem->refinement_flag() == Elem::COARSEN) 00313 { 00314 libmesh_assert(elem->parent()); 00315 elem = elem->parent(); 00316 // FIXME - this doesn't seem right - RHS 00317 if (elem->refinement_flag() != Elem::COARSEN_INACTIVE) 00318 continue; 00319 p_flag_me = false; 00320 } 00321 00322 const unsigned int my_level = elem->level(); 00323 int my_p_adjustment = 0; 00324 if (elem->p_refinement_flag() == Elem::REFINE) 00325 my_p_adjustment = 1; 00326 else if (elem->p_refinement_flag() == Elem::COARSEN) 00327 { 00328 libmesh_assert_greater (elem->p_level(), 0); 00329 my_p_adjustment = -1; 00330 } 00331 const unsigned int my_new_p_level = elem->p_level() + 00332 my_p_adjustment; 00333 00334 // Check all the element neighbors 00335 for (unsigned int n=0; n<elem->n_neighbors(); n++) 00336 { 00337 const Elem *neighbor = elem->neighbor(n); 00338 // Quit if the element is on a local boundary 00339 if (neighbor == NULL || neighbor == remote_elem) 00340 { 00341 h_flag_me = false; 00342 p_flag_me = false; 00343 break; 00344 } 00345 // if the neighbor will be equally or less refined than 00346 // we are, then we will not become an unrefined island. 00347 // So if we are still considering h refinement: 00348 if (h_flag_me && 00349 // If our neighbor is already at a lower level, 00350 // it can't end up at a higher level even if it 00351 // is flagged for refinement once 00352 ((neighbor->level() < my_level) || 00353 // If our neighbor is at the same level but isn't 00354 // flagged for refinement, it won't end up at a 00355 // higher level 00356 ((neighbor->active()) && 00357 (neighbor->refinement_flag() != Elem::REFINE)) || 00358 // If our neighbor is currently more refined but is 00359 // a parent flagged for coarsening, it will end up 00360 // at the same level. 00361 (neighbor->refinement_flag() == Elem::COARSEN_INACTIVE))) 00362 { 00363 // We've proven we won't become an unrefined island, 00364 // so don't h refine to avoid that. 00365 h_flag_me = false; 00366 00367 // If we've also proven we don't need to p refine, 00368 // we don't need to check more neighbors 00369 if (!p_flag_me) 00370 break; 00371 } 00372 if (p_flag_me) 00373 { 00374 // if active neighbors will have a p level 00375 // equal to or lower than ours, then we do not need to p 00376 // refine ourselves. 00377 if (neighbor->active()) 00378 { 00379 int p_adjustment = 0; 00380 if (neighbor->p_refinement_flag() == Elem::REFINE) 00381 p_adjustment = 1; 00382 else if (neighbor->p_refinement_flag() == Elem::COARSEN) 00383 { 00384 libmesh_assert_greater (neighbor->p_level(), 0); 00385 p_adjustment = -1; 00386 } 00387 if (my_new_p_level >= neighbor->p_level() + p_adjustment) 00388 { 00389 p_flag_me = false; 00390 if (!h_flag_me) 00391 break; 00392 } 00393 } 00394 // If we have inactive neighbors, we need to 00395 // test all their active descendants which neighbor us 00396 else if (neighbor->ancestor()) 00397 { 00398 if (neighbor->min_new_p_level_by_neighbor(elem, 00399 my_new_p_level + 2) <= my_new_p_level) 00400 { 00401 p_flag_me = false; 00402 if (!h_flag_me) 00403 break; 00404 } 00405 } 00406 } 00407 } 00408 00409 if (h_flag_me) 00410 { 00411 // Parents that would create islands should no longer 00412 // coarsen 00413 if (elem->refinement_flag() == Elem::COARSEN_INACTIVE) 00414 { 00415 for (unsigned int c=0; c<elem->n_children(); c++) 00416 { 00417 libmesh_assert_equal_to (elem->child(c)->refinement_flag(), 00418 Elem::COARSEN); 00419 elem->child(c)->set_refinement_flag(Elem::DO_NOTHING); 00420 } 00421 elem->set_refinement_flag(Elem::INACTIVE); 00422 } 00423 else 00424 elem->set_refinement_flag(Elem::REFINE); 00425 flags_changed = true; 00426 } 00427 if (p_flag_me) 00428 { 00429 if (elem->p_refinement_flag() == Elem::COARSEN) 00430 elem->set_p_refinement_flag(Elem::DO_NOTHING); 00431 else 00432 elem->set_p_refinement_flag(Elem::REFINE); 00433 flags_changed = true; 00434 } 00435 } 00436 00437 // If flags changed on any processor then they changed globally 00438 this->comm().max(flags_changed); 00439 00440 return flags_changed; 00441 } 00442 00443 00444 00445 bool MeshRefinement::enforce_mismatch_limit_prior_to_refinement(Elem* elem, 00446 NeighborType nt, 00447 unsigned max_mismatch) 00448 { 00449 // Eventual return value 00450 bool flags_changed = false; 00451 00452 // If we are enforcing the limit prior to refinement then we 00453 // need to remove flags from any elements marked for refinement that 00454 // would cause a mismatch 00455 if (_enforce_mismatch_limit_prior_to_refinement 00456 && elem->refinement_flag() == Elem::REFINE) 00457 { 00458 // get all the POINT neighbors since we may have to refine 00459 // elements off the corner as well 00460 std::set<const Elem*> neighbor_set; 00461 00462 if (nt == POINT) 00463 elem->find_point_neighbors(neighbor_set); 00464 else if (nt == EDGE) 00465 elem->find_edge_neighbors(neighbor_set); 00466 else 00467 libmesh_error_msg("Unrecognized NeighborType: " << nt); 00468 00469 // Loop over the neighbors of element e 00470 std::set<const Elem*>::iterator n_it = neighbor_set.begin(); 00471 for (; n_it != neighbor_set.end(); ++n_it) 00472 { 00473 const Elem* neighbor = *n_it; 00474 00475 if ((elem->level() + 1 - max_mismatch) > neighbor->level()) 00476 { 00477 elem->set_refinement_flag(Elem::DO_NOTHING); 00478 flags_changed = true; 00479 } 00480 if ((elem->p_level() + 1 - max_mismatch) > neighbor->p_level()) 00481 { 00482 elem->set_p_refinement_flag(Elem::DO_NOTHING); 00483 flags_changed = true; 00484 } 00485 } // loop over edge/point neighbors 00486 } // if _enforce_mismatch_limit_prior_to_refinement 00487 00488 return flags_changed; 00489 } 00490 00491 } // namespace libMesh 00492 00493 00494 #endif