mesh_refinement.C
Go to the documentation of this file.00001 // The libMesh Finite Element Library. 00002 // Copyright (C) 2002-2012 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 // C++ includes 00020 #include <cstdlib> // *must* precede <cmath> for proper std:abs() on PGI, Sun Studio CC 00021 #include <cmath> // for isnan(), when it's defined 00022 #include <limits> 00023 00024 // Local includes 00025 #include "libmesh/libmesh_config.h" 00026 00027 // only compile these functions if the user requests AMR support 00028 #ifdef LIBMESH_ENABLE_AMR 00029 00030 #include "libmesh/boundary_info.h" 00031 #include "libmesh/error_vector.h" 00032 #include "libmesh/libmesh_logging.h" 00033 #include "libmesh/mesh_base.h" 00034 #include "libmesh/mesh_communication.h" 00035 #include "libmesh/mesh_refinement.h" 00036 #include "libmesh/parallel.h" 00037 #include "libmesh/parallel_ghost_sync.h" 00038 #include "libmesh/remote_elem.h" 00039 00040 #ifdef DEBUG 00041 // Some extra validation for ParallelMesh 00042 #include "libmesh/mesh_tools.h" 00043 #include "libmesh/parallel_mesh.h" 00044 #endif // DEBUG 00045 00046 #ifdef LIBMESH_ENABLE_PERIODIC 00047 #include "libmesh/periodic_boundaries.h" 00048 #endif 00049 00050 namespace libMesh 00051 { 00052 00053 //----------------------------------------------------------------- 00054 // Mesh refinement methods 00055 MeshRefinement::MeshRefinement (MeshBase& m) : 00056 _mesh(m), 00057 _use_member_parameters(false), 00058 _coarsen_by_parents(false), 00059 _refine_fraction(0.3), 00060 _coarsen_fraction(0.0), 00061 _max_h_level(libMesh::invalid_uint), 00062 _coarsen_threshold(10), 00063 _nelem_target(0), 00064 _absolute_global_tolerance(0.0), 00065 _face_level_mismatch_limit(1), 00066 _edge_level_mismatch_limit(0), 00067 _node_level_mismatch_limit(0) 00068 #ifdef LIBMESH_ENABLE_PERIODIC 00069 , _periodic_boundaries(NULL) 00070 #endif 00071 { 00072 } 00073 00074 00075 00076 #ifdef LIBMESH_ENABLE_PERIODIC 00077 void MeshRefinement::set_periodic_boundaries_ptr(PeriodicBoundaries * pb_ptr) 00078 { 00079 _periodic_boundaries = pb_ptr; 00080 } 00081 #endif 00082 00083 00084 00085 MeshRefinement::~MeshRefinement () 00086 { 00087 this->clear(); 00088 } 00089 00090 00091 00092 void MeshRefinement::clear () 00093 { 00094 _new_nodes_map.clear(); 00095 } 00096 00097 00098 00099 Node* MeshRefinement::add_point (const Point& p, 00100 const processor_id_type processor_id, 00101 const Real tol) 00102 { 00103 START_LOG("add_point()", "MeshRefinement"); 00104 00105 // Return the node if it already exists 00106 Node *node = _new_nodes_map.find(p, tol); 00107 if (node) 00108 { 00109 STOP_LOG("add_point()", "MeshRefinement"); 00110 return node; 00111 } 00112 00113 // Add the node, with a default id and the requested 00114 // processor_id 00115 node = _mesh.add_point (p, DofObject::invalid_id, processor_id); 00116 00117 libmesh_assert(node); 00118 00119 // Add the node to the map. 00120 _new_nodes_map.insert(*node); 00121 00122 // Return the address of the new node 00123 STOP_LOG("add_point()", "MeshRefinement"); 00124 return node; 00125 } 00126 00127 00128 00129 Elem* MeshRefinement::add_elem (Elem* elem) 00130 { 00131 libmesh_assert(elem); 00132 00133 00134 // // If the unused_elements has any iterators from 00135 // // old elements, take the first one 00136 // if (!_unused_elements.empty()) 00137 // { 00138 // std::vector<Elem*>::iterator it = _unused_elements.front(); 00139 00140 // *it = elem; 00141 00142 // _unused_elements.pop_front(); 00143 // } 00144 00145 // // Otherwise, use the conventional add method 00146 // else 00147 // { 00148 // _mesh.add_elem (elem); 00149 // } 00150 00151 // The _unused_elements optimization has been turned off. 00152 _mesh.add_elem (elem); 00153 00154 return elem; 00155 } 00156 00157 00158 00159 void MeshRefinement::create_parent_error_vector 00160 (const ErrorVector& error_per_cell, 00161 ErrorVector& error_per_parent, 00162 Real& parent_error_min, 00163 Real& parent_error_max) 00164 { 00165 // This function must be run on all processors at once 00166 parallel_only(); 00167 00168 // Make sure the input error vector is valid 00169 #ifdef DEBUG 00170 for (std::size_t i=0; i != error_per_cell.size(); ++i) 00171 { 00172 libmesh_assert_greater_equal (error_per_cell[i], 0); 00173 // isnan() isn't standard C++ yet 00174 #ifdef isnan 00175 libmesh_assert(!isnan(error_per_cell[i])); 00176 #endif 00177 } 00178 00179 // Use a reference to std::vector to avoid confusing 00180 // CommWorld.verify 00181 std::vector<ErrorVectorReal> &epc = error_per_parent; 00182 libmesh_assert(CommWorld.verify(epc)); 00183 #endif // #ifdef DEBUG 00184 00185 // error values on uncoarsenable elements will be left at -1 00186 error_per_parent.clear(); 00187 error_per_parent.resize(error_per_cell.size(), 0.0); 00188 00189 { 00190 // Find which elements are uncoarsenable 00191 MeshBase::element_iterator elem_it = _mesh.active_local_elements_begin(); 00192 const MeshBase::element_iterator elem_end = _mesh.active_local_elements_end(); 00193 for (; elem_it != elem_end; ++elem_it) 00194 { 00195 Elem* elem = *elem_it; 00196 Elem* parent = elem->parent(); 00197 00198 // Active elements are uncoarsenable 00199 error_per_parent[elem->id()] = -1.0; 00200 00201 // Grandparents and up are uncoarsenable 00202 while (parent) 00203 { 00204 parent = parent->parent(); 00205 if (parent) 00206 { 00207 const dof_id_type parentid = parent->id(); 00208 libmesh_assert_less (parentid, error_per_parent.size()); 00209 error_per_parent[parentid] = -1.0; 00210 } 00211 } 00212 } 00213 00214 // Sync between processors. 00215 // Use a reference to std::vector to avoid confusing 00216 // CommWorld.min 00217 std::vector<ErrorVectorReal> &epp = error_per_parent; 00218 CommWorld.min(epp); 00219 } 00220 00221 // The parent's error is defined as the square root of the 00222 // sum of the children's errors squared, so errors that are 00223 // Hilbert norms remain Hilbert norms. 00224 // 00225 // Because the children may be on different processors, we 00226 // calculate local contributions to the parents' errors squared 00227 // first, then sum across processors and take the square roots 00228 // second. 00229 { 00230 MeshBase::element_iterator elem_it = _mesh.active_local_elements_begin(); 00231 const MeshBase::element_iterator elem_end = _mesh.active_local_elements_end(); 00232 00233 for (; elem_it != elem_end; ++elem_it) 00234 { 00235 Elem* elem = *elem_it; 00236 Elem* parent = elem->parent(); 00237 00238 // Calculate each contribution to parent cells 00239 if (parent) 00240 { 00241 const dof_id_type parentid = parent->id(); 00242 libmesh_assert_less (parentid, error_per_parent.size()); 00243 00244 // If the parent has grandchildren we won't be able to 00245 // coarsen it, so forget it. Otherwise, add this child's 00246 // contribution to the sum of the squared child errors 00247 if (error_per_parent[parentid] != -1.0) 00248 error_per_parent[parentid] += (error_per_cell[elem->id()] * 00249 error_per_cell[elem->id()]); 00250 } 00251 } 00252 } 00253 00254 // Sum the vector across all processors 00255 CommWorld.sum(static_cast<std::vector<ErrorVectorReal>&>(error_per_parent)); 00256 00257 // Calculate the min and max as we loop 00258 parent_error_min = std::numeric_limits<double>::max(); 00259 parent_error_max = 0.; 00260 00261 for (std::size_t i = 0; i != error_per_parent.size(); ++i) 00262 { 00263 // If this element isn't a coarsenable parent with error, we 00264 // have nothing to do. Just flag it as -1 and move on 00265 // Note that CommWorld.sum might have left uncoarsenable 00266 // elements with error_per_parent=-n_proc, so reset it to 00267 // error_per_parent=-1 00268 if (error_per_parent[i] < 0.) 00269 { 00270 error_per_parent[i] = -1.; 00271 continue; 00272 } 00273 00274 // The error estimator might have already given us an 00275 // estimate on the coarsenable parent elements; if so then 00276 // we want to retain that estimate 00277 if (error_per_cell[i]) 00278 { 00279 error_per_parent[i] = error_per_cell[i]; 00280 continue; 00281 } 00282 // if not, then e_parent = sqrt(sum(e_child^2)) 00283 else 00284 error_per_parent[i] = std::sqrt(error_per_parent[i]); 00285 00286 parent_error_min = std::min (parent_error_min, 00287 error_per_parent[i]); 00288 parent_error_max = std::max (parent_error_max, 00289 error_per_parent[i]); 00290 } 00291 } 00292 00293 00294 00295 void MeshRefinement::update_nodes_map () 00296 { 00297 this->_new_nodes_map.init(_mesh); 00298 } 00299 00300 00301 00302 bool MeshRefinement::test_level_one (bool libmesh_dbg_var(libmesh_assert_pass)) 00303 { 00304 // This function must be run on all processors at once 00305 parallel_only(); 00306 00307 // We may need a PointLocator for topological_neighbor() tests 00308 // later, which we need to make sure gets constructed on all 00309 // processors at once. 00310 AutoPtr<PointLocatorBase> point_locator; 00311 00312 #ifdef LIBMESH_ENABLE_PERIODIC 00313 bool has_periodic_boundaries = 00314 _periodic_boundaries && !_periodic_boundaries->empty(); 00315 libmesh_assert(CommWorld.verify(has_periodic_boundaries)); 00316 00317 if (has_periodic_boundaries) 00318 point_locator = _mesh.sub_point_locator(); 00319 #endif 00320 00321 MeshBase::element_iterator elem_it = _mesh.active_local_elements_begin(); 00322 const MeshBase::element_iterator elem_end = _mesh.active_local_elements_end(); 00323 00324 bool failure = false; 00325 00326 #ifndef NDEBUG 00327 Elem *failed_elem = NULL; 00328 Elem *failed_neighbor = NULL; 00329 #endif // !NDEBUG 00330 00331 for ( ; elem_it != elem_end && !failure; ++elem_it) 00332 { 00333 // Pointer to the element 00334 Elem *elem = *elem_it; 00335 00336 for (unsigned int n=0; n<elem->n_neighbors(); n++) 00337 { 00338 Elem *neighbor = 00339 topological_neighbor(elem, point_locator.get(), n); 00340 00341 if (!neighbor || !neighbor->active() || 00342 neighbor == remote_elem) 00343 continue; 00344 00345 if ((neighbor->level() + 1 < elem->level()) || 00346 (neighbor->p_level() + 1 < elem->p_level()) || 00347 (neighbor->p_level() > elem->p_level() + 1)) 00348 { 00349 failure = true; 00350 #ifndef NDEBUG 00351 failed_elem = elem; 00352 failed_neighbor = neighbor; 00353 #endif // !NDEBUG 00354 break; 00355 } 00356 } 00357 } 00358 00359 // If any processor failed, we failed globally 00360 CommWorld.max(failure); 00361 00362 if (failure) 00363 { 00364 // We didn't pass the level one test, so libmesh_assert that 00365 // we're allowed not to 00366 #ifndef NDEBUG 00367 if (libmesh_assert_pass) 00368 { 00369 libMesh::out << 00370 "MeshRefinement Level one failure, element: " << 00371 *failed_elem << std::endl; 00372 libMesh::out << 00373 "MeshRefinement Level one failure, neighbor: " << 00374 *failed_neighbor << std::endl; 00375 } 00376 #endif // !NDEBUG 00377 libmesh_assert(!libmesh_assert_pass); 00378 return false; 00379 } 00380 return true; 00381 } 00382 00383 00384 00385 bool MeshRefinement::test_unflagged (bool libmesh_dbg_var(libmesh_assert_pass)) 00386 { 00387 // This function must be run on all processors at once 00388 parallel_only(); 00389 00390 bool found_flag = false; 00391 00392 // Search for local flags 00393 MeshBase::element_iterator elem_it = _mesh.active_local_elements_begin(); 00394 const MeshBase::element_iterator elem_end = _mesh.active_local_elements_end(); 00395 00396 #ifndef NDEBUG 00397 Elem *failed_elem = NULL; 00398 #endif 00399 00400 for ( ; elem_it != elem_end; ++elem_it) 00401 { 00402 // Pointer to the element 00403 Elem *elem = *elem_it; 00404 00405 if (elem->refinement_flag() == Elem::REFINE || 00406 elem->refinement_flag() == Elem::COARSEN || 00407 elem->p_refinement_flag() == Elem::REFINE || 00408 elem->p_refinement_flag() == Elem::COARSEN) 00409 { 00410 found_flag = true; 00411 #ifndef NDEBUG 00412 failed_elem = elem; 00413 #endif 00414 break; 00415 } 00416 } 00417 00418 // If we found a flag on any processor, it counts 00419 CommWorld.max(found_flag); 00420 00421 if (found_flag) 00422 { 00423 #ifndef NDEBUG 00424 if (libmesh_assert_pass) 00425 { 00426 libMesh::out << 00427 "MeshRefinement test_unflagged failure, element: " << 00428 *failed_elem << std::endl; 00429 } 00430 #endif 00431 // We didn't pass the "elements are unflagged" test, 00432 // so libmesh_assert that we're allowed not to 00433 libmesh_assert(!libmesh_assert_pass); 00434 return false; 00435 } 00436 return true; 00437 } 00438 00439 00440 00441 bool MeshRefinement::refine_and_coarsen_elements (const bool maintain_level_one) 00442 { 00443 // This function must be run on all processors at once 00444 parallel_only(); 00445 00446 bool _maintain_level_one = maintain_level_one; 00447 00448 // If the user used non-default parameters, let's warn that they're 00449 // deprecated 00450 if (!maintain_level_one) 00451 { 00452 libmesh_deprecated(); 00453 } 00454 else 00455 _maintain_level_one = _face_level_mismatch_limit; 00456 00457 // We can't yet turn a non-level-one mesh into a level-one mesh 00458 if (_maintain_level_one) 00459 libmesh_assert(test_level_one(true)); 00460 00461 // Possibly clean up the refinement flags from 00462 // a previous step 00463 MeshBase::element_iterator elem_it = _mesh.elements_begin(); 00464 const MeshBase::element_iterator elem_end = _mesh.elements_end(); 00465 00466 for ( ; elem_it != elem_end; ++elem_it) 00467 { 00468 // Pointer to the element 00469 Elem *elem = *elem_it; 00470 00471 // Set refinement flag to INACTIVE if the 00472 // element isn't active 00473 if ( !elem->active()) 00474 { 00475 elem->set_refinement_flag(Elem::INACTIVE); 00476 elem->set_p_refinement_flag(Elem::INACTIVE); 00477 } 00478 00479 // This might be left over from the last step 00480 if (elem->refinement_flag() == Elem::JUST_REFINED) 00481 elem->set_refinement_flag(Elem::DO_NOTHING); 00482 } 00483 00484 // Parallel consistency has to come first, or coarsening 00485 // along processor boundaries might occasionally be falsely 00486 // prevented 00487 if (!_mesh.is_serial()) 00488 this->make_flags_parallel_consistent(); 00489 00490 // Repeat until flag changes match on every processor 00491 do 00492 { 00493 // Repeat until coarsening & refinement flags jive 00494 bool satisfied = false; 00495 do 00496 { 00497 const bool coarsening_satisfied = 00498 this->make_coarsening_compatible(maintain_level_one); 00499 00500 const bool refinement_satisfied = 00501 this->make_refinement_compatible(maintain_level_one); 00502 00503 bool smoothing_satisfied = 00504 !this->eliminate_unrefined_patches(); 00505 00506 if (_edge_level_mismatch_limit) 00507 smoothing_satisfied = smoothing_satisfied && 00508 !this->limit_level_mismatch_at_edge (_edge_level_mismatch_limit); 00509 00510 if (_node_level_mismatch_limit) 00511 smoothing_satisfied = smoothing_satisfied && 00512 !this->limit_level_mismatch_at_node (_node_level_mismatch_limit); 00513 00514 satisfied = (coarsening_satisfied && 00515 refinement_satisfied && 00516 smoothing_satisfied); 00517 #ifdef DEBUG 00518 bool max_satisfied = satisfied, 00519 min_satisfied = satisfied; 00520 CommWorld.max(max_satisfied); 00521 CommWorld.min(min_satisfied); 00522 libmesh_assert_equal_to (satisfied, max_satisfied); 00523 libmesh_assert_equal_to (satisfied, min_satisfied); 00524 #endif 00525 } 00526 while (!satisfied); 00527 } 00528 while (!_mesh.is_serial() && !this->make_flags_parallel_consistent()); 00529 00530 // First coarsen the flagged elements. 00531 const bool coarsening_changed_mesh = 00532 this->_coarsen_elements (); 00533 00534 // FIXME: test_level_one now tests consistency across periodic 00535 // boundaries, which requires a point_locator, which just got 00536 // invalidated by _coarsen_elements() and hasn't yet been cleared by 00537 // prepare_for_use(). 00538 00539 // if (_maintain_level_one) 00540 // libmesh_assert(test_level_one(true)); 00541 // libmesh_assert(this->make_coarsening_compatible(maintain_level_one)); 00542 // libmesh_assert(this->make_refinement_compatible(maintain_level_one)); 00543 00544 // FIXME: This won't pass unless we add a redundant find_neighbors() 00545 // call or replace find_neighbors() with on-the-fly neighbor updating 00546 // libmesh_assert(!this->eliminate_unrefined_patches()); 00547 00548 // We can't contract the mesh ourselves anymore - a System might 00549 // need to restrict old coefficient vectors first 00550 // _mesh.contract(); 00551 00552 // Now refine the flagged elements. This will 00553 // take up some space, maybe more than what was freed. 00554 const bool refining_changed_mesh = 00555 this->_refine_elements(); 00556 00557 // Finally, the new mesh needs to be prepared for use 00558 if (coarsening_changed_mesh || refining_changed_mesh) 00559 { 00560 #ifdef DEBUG 00561 _mesh.libmesh_assert_valid_parallel_ids(); 00562 #endif 00563 00564 _mesh.prepare_for_use (/*skip_renumber =*/false); 00565 00566 if (_maintain_level_one) 00567 libmesh_assert(test_level_one(true)); 00568 libmesh_assert(test_unflagged(true)); 00569 libmesh_assert(this->make_coarsening_compatible(maintain_level_one)); 00570 libmesh_assert(this->make_refinement_compatible(maintain_level_one)); 00571 // FIXME: This won't pass unless we add a redundant find_neighbors() 00572 // call or replace find_neighbors() with on-the-fly neighbor updating 00573 // libmesh_assert(!this->eliminate_unrefined_patches()); 00574 00575 return true; 00576 } 00577 else 00578 { 00579 if (_maintain_level_one) 00580 libmesh_assert(test_level_one(true)); 00581 libmesh_assert(test_unflagged(true)); 00582 libmesh_assert(this->make_coarsening_compatible(maintain_level_one)); 00583 libmesh_assert(this->make_refinement_compatible(maintain_level_one)); 00584 } 00585 00586 // Otherwise there was no change in the mesh, 00587 // let the user know. Also, there is no need 00588 // to prepare the mesh for use since it did not change. 00589 return false; 00590 00591 } 00592 00593 00594 00595 00596 00597 00598 00599 bool MeshRefinement::coarsen_elements (const bool maintain_level_one) 00600 { 00601 // This function must be run on all processors at once 00602 parallel_only(); 00603 00604 bool _maintain_level_one = maintain_level_one; 00605 00606 // If the user used non-default parameters, let's warn that they're 00607 // deprecated 00608 if (!maintain_level_one) 00609 { 00610 libmesh_deprecated(); 00611 } 00612 else 00613 _maintain_level_one = _face_level_mismatch_limit; 00614 00615 // We can't yet turn a non-level-one mesh into a level-one mesh 00616 if (_maintain_level_one) 00617 libmesh_assert(test_level_one(true)); 00618 00619 // Possibly clean up the refinement flags from 00620 // a previous step 00621 MeshBase::element_iterator elem_it = _mesh.elements_begin(); 00622 const MeshBase::element_iterator elem_end = _mesh.elements_end(); 00623 00624 for ( ; elem_it != elem_end; ++elem_it) 00625 { 00626 // Pointer to the element 00627 Elem* elem = *elem_it; 00628 00629 // Set refinement flag to INACTIVE if the 00630 // element isn't active 00631 if ( !elem->active()) 00632 { 00633 elem->set_refinement_flag(Elem::INACTIVE); 00634 elem->set_p_refinement_flag(Elem::INACTIVE); 00635 } 00636 00637 // This might be left over from the last step 00638 if (elem->refinement_flag() == Elem::JUST_REFINED) 00639 elem->set_refinement_flag(Elem::DO_NOTHING); 00640 } 00641 00642 // Parallel consistency has to come first, or coarsening 00643 // along processor boundaries might occasionally be falsely 00644 // prevented 00645 if (!_mesh.is_serial()) 00646 this->make_flags_parallel_consistent(); 00647 00648 // Repeat until flag changes match on every processor 00649 do 00650 { 00651 // Repeat until the flags form a conforming mesh. 00652 bool satisfied = false; 00653 do 00654 { 00655 const bool coarsening_satisfied = 00656 this->make_coarsening_compatible(maintain_level_one); 00657 00658 bool smoothing_satisfied = 00659 !this->eliminate_unrefined_patches();// && 00660 00661 if (_edge_level_mismatch_limit) 00662 smoothing_satisfied = smoothing_satisfied && 00663 !this->limit_level_mismatch_at_edge (_edge_level_mismatch_limit); 00664 00665 if (_node_level_mismatch_limit) 00666 smoothing_satisfied = smoothing_satisfied && 00667 !this->limit_level_mismatch_at_node (_node_level_mismatch_limit); 00668 00669 satisfied = (coarsening_satisfied && 00670 smoothing_satisfied); 00671 #ifdef DEBUG 00672 bool max_satisfied = satisfied, 00673 min_satisfied = satisfied; 00674 CommWorld.max(max_satisfied); 00675 CommWorld.min(min_satisfied); 00676 libmesh_assert_equal_to (satisfied, max_satisfied); 00677 libmesh_assert_equal_to (satisfied, min_satisfied); 00678 #endif 00679 } 00680 while (!satisfied); 00681 } 00682 while (!_mesh.is_serial() && !this->make_flags_parallel_consistent()); 00683 00684 // Coarsen the flagged elements. 00685 const bool mesh_changed = 00686 this->_coarsen_elements (); 00687 00688 if (_maintain_level_one) 00689 libmesh_assert(test_level_one(true)); 00690 libmesh_assert(this->make_coarsening_compatible(maintain_level_one)); 00691 // FIXME: This won't pass unless we add a redundant find_neighbors() 00692 // call or replace find_neighbors() with on-the-fly neighbor updating 00693 // libmesh_assert(!this->eliminate_unrefined_patches()); 00694 00695 // We can't contract the mesh ourselves anymore - a System might 00696 // need to restrict old coefficient vectors first 00697 // _mesh.contract(); 00698 00699 // Finally, the new mesh may need to be prepared for use 00700 if (mesh_changed) 00701 _mesh.prepare_for_use (/*skip_renumber =*/false); 00702 00703 return mesh_changed; 00704 } 00705 00706 00707 00708 00709 00710 00711 00712 bool MeshRefinement::refine_elements (const bool maintain_level_one) 00713 { 00714 // This function must be run on all processors at once 00715 parallel_only(); 00716 00717 bool _maintain_level_one = maintain_level_one; 00718 00719 // If the user used non-default parameters, let's warn that they're 00720 // deprecated 00721 if (!maintain_level_one) 00722 { 00723 libmesh_deprecated(); 00724 } 00725 else 00726 _maintain_level_one = _face_level_mismatch_limit; 00727 00728 if (_maintain_level_one) 00729 libmesh_assert(test_level_one(true)); 00730 00731 // Possibly clean up the refinement flags from 00732 // a previous step 00733 MeshBase::element_iterator elem_it = _mesh.elements_begin(); 00734 const MeshBase::element_iterator elem_end = _mesh.elements_end(); 00735 00736 for ( ; elem_it != elem_end; ++elem_it) 00737 { 00738 // Pointer to the element 00739 Elem *elem = *elem_it; 00740 00741 // Set refinement flag to INACTIVE if the 00742 // element isn't active 00743 if ( !elem->active()) 00744 { 00745 elem->set_refinement_flag(Elem::INACTIVE); 00746 elem->set_p_refinement_flag(Elem::INACTIVE); 00747 } 00748 00749 // This might be left over from the last step 00750 if (elem->refinement_flag() == Elem::JUST_REFINED) 00751 elem->set_refinement_flag(Elem::DO_NOTHING); 00752 } 00753 00754 00755 00756 // Parallel consistency has to come first, or coarsening 00757 // along processor boundaries might occasionally be falsely 00758 // prevented 00759 if (!_mesh.is_serial()) 00760 this->make_flags_parallel_consistent(); 00761 00762 // Repeat until flag changes match on every processor 00763 do 00764 { 00765 // Repeat until coarsening & refinement flags jive 00766 bool satisfied = false; 00767 do 00768 { 00769 const bool refinement_satisfied = 00770 this->make_refinement_compatible(maintain_level_one); 00771 00772 bool smoothing_satisfied = 00773 !this->eliminate_unrefined_patches();// && 00774 00775 if (_edge_level_mismatch_limit) 00776 smoothing_satisfied = smoothing_satisfied && 00777 !this->limit_level_mismatch_at_edge (_edge_level_mismatch_limit); 00778 00779 if (_node_level_mismatch_limit) 00780 smoothing_satisfied = smoothing_satisfied && 00781 !this->limit_level_mismatch_at_node (_node_level_mismatch_limit); 00782 00783 satisfied = (refinement_satisfied && 00784 smoothing_satisfied); 00785 #ifdef DEBUG 00786 bool max_satisfied = satisfied, 00787 min_satisfied = satisfied; 00788 CommWorld.max(max_satisfied); 00789 CommWorld.min(min_satisfied); 00790 libmesh_assert_equal_to (satisfied, max_satisfied); 00791 libmesh_assert_equal_to (satisfied, min_satisfied); 00792 #endif 00793 } 00794 while (!satisfied); 00795 } 00796 while (!_mesh.is_serial() && !this->make_flags_parallel_consistent()); 00797 00798 // Now refine the flagged elements. This will 00799 // take up some space, maybe more than what was freed. 00800 const bool mesh_changed = 00801 this->_refine_elements(); 00802 00803 if (_maintain_level_one) 00804 libmesh_assert(test_level_one(true)); 00805 libmesh_assert(this->make_refinement_compatible(maintain_level_one)); 00806 // FIXME: This won't pass unless we add a redundant find_neighbors() 00807 // call or replace find_neighbors() with on-the-fly neighbor updating 00808 // libmesh_assert(!this->eliminate_unrefined_patches()); 00809 00810 // Finally, the new mesh needs to be prepared for use 00811 if (mesh_changed) 00812 _mesh.prepare_for_use (/*skip_renumber =*/false); 00813 00814 return mesh_changed; 00815 } 00816 00817 00818 // Functor for make_flags_parallel_consistent 00819 namespace { 00820 00821 struct SyncRefinementFlags 00822 { 00823 typedef unsigned char datum; 00824 typedef Elem::RefinementState (Elem::*get_a_flag)() const; 00825 typedef void (Elem::*set_a_flag)(const Elem::RefinementState); 00826 00827 SyncRefinementFlags(MeshBase &_mesh, 00828 get_a_flag _getter, 00829 set_a_flag _setter) : 00830 mesh(_mesh), parallel_consistent(true), 00831 get_flag(_getter), set_flag(_setter) {} 00832 00833 MeshBase &mesh; 00834 bool parallel_consistent; 00835 get_a_flag get_flag; 00836 set_a_flag set_flag; 00837 // References to pointers to member functions segfault? 00838 // get_a_flag& get_flag; 00839 // set_a_flag& set_flag; 00840 00841 // Find the refinement flag on each requested element 00842 void gather_data (const std::vector<dof_id_type>& ids, 00843 std::vector<datum>& flags) 00844 { 00845 flags.resize(ids.size()); 00846 00847 for (std::size_t i=0; i != ids.size(); ++i) 00848 { 00849 // Look for this element in the mesh 00850 // We'd better find every element we're asked for 00851 Elem *elem = mesh.elem(ids[i]); 00852 00853 // Return the element's refinement flag 00854 flags[i] = (elem->*get_flag)(); 00855 } 00856 } 00857 00858 void act_on_data (const std::vector<dof_id_type>& ids, 00859 std::vector<datum>& flags) 00860 { 00861 for (std::size_t i=0; i != ids.size(); ++i) 00862 { 00863 Elem *elem = mesh.elem(ids[i]); 00864 00865 datum old_flag = (elem->*get_flag)(); 00866 datum &new_flag = flags[i]; 00867 00868 if (old_flag != new_flag) 00869 { 00870 // It's possible for foreign flags to be (temporarily) more 00871 // conservative than our own, such as when a refinement in 00872 // one of the foreign processor's elements is mandated by a 00873 // refinement in one of our neighboring elements it can see 00874 // which was mandated by a refinement in one of our 00875 // neighboring elements it can't see 00876 // libmesh_assert (!(new_flag != Elem::REFINE && 00877 // old_flag == Elem::REFINE)); 00878 // 00879 (elem->*set_flag) 00880 (static_cast<Elem::RefinementState>(new_flag)); 00881 parallel_consistent = false; 00882 } 00883 } 00884 } 00885 }; 00886 } 00887 00888 00889 00890 bool MeshRefinement::make_flags_parallel_consistent() 00891 { 00892 // This function must be run on all processors at once 00893 parallel_only(); 00894 00895 START_LOG ("make_flags_parallel_consistent()", "MeshRefinement"); 00896 00897 SyncRefinementFlags hsync(_mesh, &Elem::refinement_flag, 00898 &Elem::set_refinement_flag); 00899 Parallel::sync_dofobject_data_by_id 00900 (_mesh.elements_begin(), _mesh.elements_end(), hsync); 00901 00902 SyncRefinementFlags psync(_mesh, &Elem::p_refinement_flag, 00903 &Elem::set_p_refinement_flag); 00904 Parallel::sync_dofobject_data_by_id 00905 (_mesh.elements_begin(), _mesh.elements_end(), psync); 00906 00907 // If we weren't consistent in both h and p on every processor then 00908 // we weren't globally consistent 00909 bool parallel_consistent = hsync.parallel_consistent && 00910 psync.parallel_consistent; 00911 CommWorld.min(parallel_consistent); 00912 00913 STOP_LOG ("make_flags_parallel_consistent()", "MeshRefinement"); 00914 00915 return parallel_consistent; 00916 } 00917 00918 00919 00920 bool MeshRefinement::make_coarsening_compatible(const bool maintain_level_one) 00921 { 00922 // This function must be run on all processors at once 00923 parallel_only(); 00924 00925 // We may need a PointLocator for topological_neighbor() tests 00926 // later, which we need to make sure gets constructed on all 00927 // processors at once. 00928 AutoPtr<PointLocatorBase> point_locator; 00929 00930 #ifdef LIBMESH_ENABLE_PERIODIC 00931 bool has_periodic_boundaries = 00932 _periodic_boundaries && !_periodic_boundaries->empty(); 00933 libmesh_assert(CommWorld.verify(has_periodic_boundaries)); 00934 00935 if (has_periodic_boundaries) 00936 point_locator = _mesh.sub_point_locator(); 00937 #endif 00938 00939 START_LOG ("make_coarsening_compatible()", "MeshRefinement"); 00940 00941 bool _maintain_level_one = maintain_level_one; 00942 00943 // If the user used non-default parameters, let's warn that they're 00944 // deprecated 00945 if (!maintain_level_one) 00946 { 00947 libmesh_deprecated(); 00948 } 00949 else 00950 _maintain_level_one = _face_level_mismatch_limit; 00951 00952 00953 // Unless we encounter a specific situation level-one 00954 // will be satisfied after executing this loop just once 00955 bool level_one_satisfied = true; 00956 00957 00958 // Unless we encounter a specific situation we will be compatible 00959 // with any selected refinement flags 00960 bool compatible_with_refinement = true; 00961 00962 00963 // find the maximum h and p levels in the mesh 00964 unsigned int max_level = 0; 00965 unsigned int max_p_level = 0; 00966 00967 { 00968 // First we look at all the active level-0 elements. Since it doesn't make 00969 // sense to coarsen them we must un-set their coarsen flags if 00970 // they are set. 00971 MeshBase::element_iterator el = _mesh.active_elements_begin(); 00972 const MeshBase::element_iterator end_el = _mesh.active_elements_end(); 00973 00974 for (; el != end_el; ++el) 00975 { 00976 Elem *elem = *el; 00977 max_level = std::max(max_level, elem->level()); 00978 max_p_level = 00979 std::max(max_p_level, 00980 static_cast<unsigned int>(elem->p_level())); 00981 00982 if ((elem->level() == 0) && 00983 (elem->refinement_flag() == Elem::COARSEN)) 00984 elem->set_refinement_flag(Elem::DO_NOTHING); 00985 00986 if ((elem->p_level() == 0) && 00987 (elem->p_refinement_flag() == Elem::COARSEN)) 00988 elem->set_p_refinement_flag(Elem::DO_NOTHING); 00989 } 00990 } 00991 00992 // if there are no refined elements on this processor then 00993 // there is no work for us to do 00994 if (max_level == 0 && max_p_level == 0) 00995 { 00996 STOP_LOG ("make_coarsening_compatible()", "MeshRefinement"); 00997 00998 // But we still have to check with other processors 00999 CommWorld.min(compatible_with_refinement); 01000 01001 return compatible_with_refinement; 01002 } 01003 01004 01005 01006 // Loop over all the active elements. If an element is marked 01007 // for coarsening we better check its neighbors. If ANY of these neighbors 01008 // are marked for refinement AND are at the same level then there is a 01009 // conflict. By convention refinement wins, so we un-mark the element for 01010 // coarsening. Level-one would be violated in this case so we need to re-run 01011 // the loop. 01012 if (_maintain_level_one) 01013 { 01014 01015 repeat: 01016 level_one_satisfied = true; 01017 01018 do 01019 { 01020 level_one_satisfied = true; 01021 01022 MeshBase::element_iterator el = _mesh.active_elements_begin(); 01023 const MeshBase::element_iterator end_el = _mesh.active_elements_end(); 01024 01025 for (; el != end_el; ++el) 01026 { 01027 Elem* elem = *el; 01028 bool my_flag_changed = false; 01029 01030 if (elem->refinement_flag() == Elem::COARSEN) // If the element is active and 01031 // the coarsen flag is set 01032 { 01033 const unsigned int my_level = elem->level(); 01034 01035 for (unsigned int n=0; n<elem->n_neighbors(); n++) 01036 { 01037 const Elem* neighbor = 01038 topological_neighbor(elem, point_locator.get(), n); 01039 01040 if (neighbor != NULL && // I have a 01041 neighbor != remote_elem) // neighbor here 01042 { 01043 if (neighbor->active()) // and it is active 01044 { 01045 if ((neighbor->level() == my_level) && 01046 (neighbor->refinement_flag() == Elem::REFINE)) // the neighbor is at my level 01047 // and wants to be refined 01048 { 01049 elem->set_refinement_flag(Elem::DO_NOTHING); 01050 my_flag_changed = true; 01051 break; 01052 } 01053 } 01054 else // I have a neighbor and it is not active. That means it has children. 01055 { // While it _may_ be possible to coarsen us if all the children of 01056 // that element want to be coarsened, it is impossible to know at this 01057 // stage. Forget about it for the moment... This can be handled in 01058 // two steps. 01059 elem->set_refinement_flag(Elem::DO_NOTHING); 01060 my_flag_changed = true; 01061 break; 01062 } 01063 } 01064 } 01065 } 01066 if (elem->p_refinement_flag() == Elem::COARSEN) // If 01067 // the element is active and the order reduction flag is set 01068 { 01069 const unsigned int my_p_level = elem->p_level(); 01070 01071 for (unsigned int n=0; n<elem->n_neighbors(); n++) 01072 { 01073 const Elem* neighbor = 01074 topological_neighbor(elem, point_locator.get(), n); 01075 01076 if (neighbor != NULL && // I have a 01077 neighbor != remote_elem) // neighbor here 01078 { 01079 if (neighbor->active()) // and it is active 01080 { 01081 if ((neighbor->p_level() > my_p_level && 01082 neighbor->p_refinement_flag() != Elem::COARSEN) 01083 || (neighbor->p_level() == my_p_level && 01084 neighbor->p_refinement_flag() == Elem::REFINE)) 01085 { 01086 elem->set_p_refinement_flag(Elem::DO_NOTHING); 01087 my_flag_changed = true; 01088 break; 01089 } 01090 } 01091 else // I have a neighbor and it is not active. 01092 { // We need to find which of its children 01093 // have me as a neighbor, and maintain 01094 // level one p compatibility with them. 01095 // Because we currently have level one h 01096 // compatibility, we don't need to check 01097 // grandchildren 01098 01099 libmesh_assert(neighbor->has_children()); 01100 for (unsigned int c=0; c!=neighbor->n_children(); c++) 01101 { 01102 Elem *subneighbor = neighbor->child(c); 01103 if (subneighbor != remote_elem && 01104 subneighbor->active() && 01105 has_topological_neighbor(subneighbor, point_locator.get(), elem)) 01106 if ((subneighbor->p_level() > my_p_level && 01107 subneighbor->p_refinement_flag() != Elem::COARSEN) 01108 || (subneighbor->p_level() == my_p_level && 01109 subneighbor->p_refinement_flag() == Elem::REFINE)) 01110 { 01111 elem->set_p_refinement_flag(Elem::DO_NOTHING); 01112 my_flag_changed = true; 01113 break; 01114 } 01115 } 01116 if (my_flag_changed) 01117 break; 01118 } 01119 } 01120 } 01121 } 01122 01123 // If the current element's flag changed, we hadn't 01124 // satisfied the level one rule. 01125 if (my_flag_changed) 01126 level_one_satisfied = false; 01127 01128 // Additionally, if it has non-local neighbors, and 01129 // we're not in serial, then we'll eventually have to 01130 // return compatible_with_refinement = false, because 01131 // our change has to propagate to neighboring 01132 // processors. 01133 if (my_flag_changed && !_mesh.is_serial()) 01134 for (unsigned int n=0; n != elem->n_neighbors(); ++n) 01135 { 01136 Elem* neigh = 01137 topological_neighbor(elem, point_locator.get(), n); 01138 01139 if (!neigh) 01140 continue; 01141 if (neigh == remote_elem || 01142 neigh->processor_id() != 01143 libMesh::processor_id()) 01144 { 01145 compatible_with_refinement = false; 01146 break; 01147 } 01148 // FIXME - for non-level one meshes we should 01149 // test all descendants 01150 if (neigh->has_children()) 01151 for (unsigned int c=0; c != neigh->n_children(); ++c) 01152 if (neigh->child(c) == remote_elem || 01153 neigh->child(c)->processor_id() != 01154 libMesh::processor_id()) 01155 { 01156 compatible_with_refinement = false; 01157 break; 01158 } 01159 } 01160 } 01161 } 01162 while (!level_one_satisfied); 01163 01164 } // end if (_maintain_level_one) 01165 01166 01167 // Next we look at all of the ancestor cells. 01168 // If there is a parent cell with all of its children 01169 // wanting to be unrefined then the element is a candidate 01170 // for unrefinement. If all the children don't 01171 // all want to be unrefined then ALL of them need to have their 01172 // unrefinement flags cleared. 01173 for (int level=(max_level); level >= 0; level--) 01174 { 01175 MeshBase::element_iterator el = _mesh.level_elements_begin(level); 01176 const MeshBase::element_iterator end_el = _mesh.level_elements_end(level); 01177 for (; el != end_el; ++el) 01178 { 01179 Elem *elem = *el; 01180 if (elem->ancestor()) 01181 { 01182 01183 // right now the element hasn't been disqualified 01184 // as a candidate for unrefinement 01185 bool is_a_candidate = true; 01186 bool found_remote_child = false; 01187 01188 for (unsigned int c=0; c<elem->n_children(); c++) 01189 { 01190 Elem *child = elem->child(c); 01191 if (child == remote_elem) 01192 found_remote_child = true; 01193 else if ((child->refinement_flag() != Elem::COARSEN) || 01194 !child->active() ) 01195 is_a_candidate = false; 01196 } 01197 01198 if (!is_a_candidate && !found_remote_child) 01199 { 01200 elem->set_refinement_flag(Elem::INACTIVE); 01201 01202 for (unsigned int c=0; c<elem->n_children(); c++) 01203 { 01204 Elem *child = elem->child(c); 01205 if (child == remote_elem) 01206 continue; 01207 if (child->refinement_flag() == Elem::COARSEN) 01208 { 01209 level_one_satisfied = false; 01210 child->set_refinement_flag(Elem::DO_NOTHING); 01211 } 01212 } 01213 } 01214 } 01215 } 01216 } 01217 01218 if (!level_one_satisfied && _maintain_level_one) goto repeat; 01219 01220 01221 // If all the children of a parent are set to be coarsened 01222 // then flag the parent so that they can kill thier kids... 01223 MeshBase::element_iterator all_el = _mesh.elements_begin(); 01224 const MeshBase::element_iterator all_el_end = _mesh.elements_end(); 01225 for (; all_el != all_el_end; ++all_el) 01226 { 01227 Elem *elem = *all_el; 01228 if (elem->ancestor()) 01229 { 01230 01231 // Presume all the children are local and flagged for 01232 // coarsening and then look for a contradiction 01233 bool all_children_flagged_for_coarsening = true; 01234 bool found_remote_child = false; 01235 01236 for (unsigned int c=0; c<elem->n_children(); c++) 01237 { 01238 Elem *child = elem->child(c); 01239 if (child == remote_elem) 01240 found_remote_child = true; 01241 else if (child->refinement_flag() != Elem::COARSEN) 01242 all_children_flagged_for_coarsening = false; 01243 } 01244 01245 if (!found_remote_child && 01246 all_children_flagged_for_coarsening) 01247 elem->set_refinement_flag(Elem::COARSEN_INACTIVE); 01248 else if (!found_remote_child) 01249 elem->set_refinement_flag(Elem::INACTIVE); 01250 } 01251 } 01252 01253 STOP_LOG ("make_coarsening_compatible()", "MeshRefinement"); 01254 01255 // If one processor finds an incompatibility, we're globally 01256 // incompatible 01257 CommWorld.min(compatible_with_refinement); 01258 01259 return compatible_with_refinement; 01260 } 01261 01262 01263 01264 01265 01266 01267 01268 01269 bool MeshRefinement::make_refinement_compatible(const bool maintain_level_one) 01270 { 01271 // This function must be run on all processors at once 01272 parallel_only(); 01273 01274 // We may need a PointLocator for topological_neighbor() tests 01275 // later, which we need to make sure gets constructed on all 01276 // processors at once. 01277 AutoPtr<PointLocatorBase> point_locator; 01278 01279 #ifdef LIBMESH_ENABLE_PERIODIC 01280 bool has_periodic_boundaries = 01281 _periodic_boundaries && !_periodic_boundaries->empty(); 01282 libmesh_assert(CommWorld.verify(has_periodic_boundaries)); 01283 01284 if (has_periodic_boundaries) 01285 point_locator = _mesh.sub_point_locator(); 01286 #endif 01287 01288 START_LOG ("make_refinement_compatible()", "MeshRefinement"); 01289 01290 bool _maintain_level_one = maintain_level_one; 01291 01292 // If the user used non-default parameters, let's warn that they're 01293 // deprecated 01294 if (!maintain_level_one) 01295 { 01296 libmesh_deprecated(); 01297 } 01298 else 01299 _maintain_level_one = _face_level_mismatch_limit; 01300 01301 // Unless we encounter a specific situation level-one 01302 // will be satisfied after executing this loop just once 01303 bool level_one_satisfied = true; 01304 01305 // Unless we encounter a specific situation we will be compatible 01306 // with any selected coarsening flags 01307 bool compatible_with_coarsening = true; 01308 01309 // This loop enforces the level-1 rule. We should only 01310 // execute it if the user indeed wants level-1 satisfied! 01311 if (_maintain_level_one) 01312 { 01313 do 01314 { 01315 level_one_satisfied = true; 01316 01317 MeshBase::element_iterator el = _mesh.active_elements_begin(); 01318 const MeshBase::element_iterator end_el = _mesh.active_elements_end(); 01319 01320 for (; el != end_el; ++el) 01321 { 01322 Elem *elem = *el; 01323 if (elem->refinement_flag() == Elem::REFINE) // If the element is active and the 01324 // h refinement flag is set 01325 { 01326 const unsigned int my_level = elem->level(); 01327 01328 for (unsigned int side=0; side != elem->n_sides(); side++) 01329 { 01330 Elem* neighbor = 01331 topological_neighbor(elem, point_locator.get(), side); 01332 01333 if (neighbor != NULL && // I have a 01334 neighbor != remote_elem && // neighbor here 01335 neighbor->active()) // and it is active 01336 { 01337 // Case 1: The neighbor is at the same level I am. 01338 // 1a: The neighbor will be refined -> NO PROBLEM 01339 // 1b: The neighbor won't be refined -> NO PROBLEM 01340 // 1c: The neighbor wants to be coarsened -> PROBLEM 01341 if (neighbor->level() == my_level) 01342 { 01343 if (neighbor->refinement_flag() == Elem::COARSEN) 01344 { 01345 neighbor->set_refinement_flag(Elem::DO_NOTHING); 01346 if (neighbor->parent()) 01347 neighbor->parent()->set_refinement_flag(Elem::INACTIVE); 01348 compatible_with_coarsening = false; 01349 level_one_satisfied = false; 01350 } 01351 } 01352 01353 01354 // Case 2: The neighbor is one level lower than I am. 01355 // The neighbor thus MUST be refined to satisfy 01356 // the level-one rule, regardless of whether it 01357 // was originally flagged for refinement. If it 01358 // wasn't flagged already we need to repeat 01359 // this process. 01360 else if ((neighbor->level()+1) == my_level) 01361 { 01362 if (neighbor->refinement_flag() != Elem::REFINE) 01363 { 01364 neighbor->set_refinement_flag(Elem::REFINE); 01365 if (neighbor->parent()) 01366 neighbor->parent()->set_refinement_flag(Elem::INACTIVE); 01367 compatible_with_coarsening = false; 01368 level_one_satisfied = false; 01369 } 01370 } 01371 #ifdef DEBUG 01372 01373 // Sanity check. We should never get into a 01374 // case when our neighbot is more than one 01375 // level away. 01376 else if ((neighbor->level()+1) < my_level) 01377 { 01378 libmesh_error(); 01379 } 01380 01381 01382 // Note that the only other possibility is that the 01383 // neighbor is already refined, in which case it isn't 01384 // active and we should never get here. 01385 else 01386 { 01387 libmesh_error(); 01388 } 01389 #endif 01390 } 01391 } 01392 } 01393 if (elem->p_refinement_flag() == Elem::REFINE) // If the element is active and the 01394 // p refinement flag is set 01395 { 01396 const unsigned int my_p_level = elem->p_level(); 01397 01398 for (unsigned int side=0; side != elem->n_sides(); side++) 01399 { 01400 Elem* neighbor = 01401 topological_neighbor(elem, point_locator.get(), side); 01402 01403 if (neighbor != NULL && // I have a 01404 neighbor != remote_elem) // neighbor here 01405 { 01406 if (neighbor->active()) // and it is active 01407 { 01408 if (neighbor->p_level() < my_p_level && 01409 neighbor->p_refinement_flag() != Elem::REFINE) 01410 { 01411 neighbor->set_p_refinement_flag(Elem::REFINE); 01412 level_one_satisfied = false; 01413 compatible_with_coarsening = false; 01414 } 01415 if (neighbor->p_level() == my_p_level && 01416 neighbor->p_refinement_flag() == Elem::COARSEN) 01417 { 01418 neighbor->set_p_refinement_flag(Elem::DO_NOTHING); 01419 level_one_satisfied = false; 01420 compatible_with_coarsening = false; 01421 } 01422 } 01423 else // I have an inactive neighbor 01424 { 01425 libmesh_assert(neighbor->has_children()); 01426 for (unsigned int c=0; c!=neighbor->n_children(); c++) 01427 { 01428 Elem *subneighbor = neighbor->child(c); 01429 if (subneighbor == remote_elem) 01430 continue; 01431 if (subneighbor->active() && 01432 has_topological_neighbor(subneighbor, point_locator.get(), elem)) 01433 { 01434 if (subneighbor->p_level() < my_p_level && 01435 subneighbor->p_refinement_flag() != Elem::REFINE) 01436 { 01437 // We should already be level one 01438 // compatible 01439 libmesh_assert_greater (subneighbor->p_level() + 2u, 01440 my_p_level); 01441 subneighbor->set_p_refinement_flag(Elem::REFINE); 01442 level_one_satisfied = false; 01443 compatible_with_coarsening = false; 01444 } 01445 if (subneighbor->p_level() == my_p_level && 01446 subneighbor->p_refinement_flag() == Elem::COARSEN) 01447 { 01448 subneighbor->set_p_refinement_flag(Elem::DO_NOTHING); 01449 level_one_satisfied = false; 01450 compatible_with_coarsening = false; 01451 } 01452 } 01453 } 01454 } 01455 } 01456 } 01457 } 01458 } 01459 } 01460 01461 while (!level_one_satisfied); 01462 } // end if (_maintain_level_one) 01463 01464 // If we're not compatible on one processor, we're globally not 01465 // compatible 01466 CommWorld.min(compatible_with_coarsening); 01467 01468 STOP_LOG ("make_refinement_compatible()", "MeshRefinement"); 01469 01470 return compatible_with_coarsening; 01471 } 01472 01473 01474 01475 01476 bool MeshRefinement::_coarsen_elements () 01477 { 01478 // This function must be run on all processors at once 01479 parallel_only(); 01480 01481 START_LOG ("_coarsen_elements()", "MeshRefinement"); 01482 01483 // Flag indicating if this call actually changes the mesh 01484 bool mesh_changed = false; 01485 01486 // Clear the unused_elements data structure. 01487 // The elements have been packed since it was built, 01488 // so there are _no_ unused elements. We cannot trust 01489 // any iterators currently in this data structure. 01490 // _unused_elements.clear(); 01491 01492 MeshBase::element_iterator it = _mesh.elements_begin(); 01493 const MeshBase::element_iterator end = _mesh.elements_end(); 01494 01495 // Loop over the elements. 01496 for ( ; it != end; ++it) 01497 { 01498 Elem* elem = *it; 01499 01500 // Not necessary when using elem_iterator 01501 // libmesh_assert(elem); 01502 01503 // active elements flagged for coarsening will 01504 // no longer be deleted until MeshRefinement::contract() 01505 if (elem->refinement_flag() == Elem::COARSEN) 01506 { 01507 // Huh? no level-0 element should be active 01508 // and flagged for coarsening. 01509 libmesh_assert_not_equal_to (elem->level(), 0); 01510 01511 // Remove this element from any neighbor 01512 // lists that point to it. 01513 elem->nullify_neighbors(); 01514 01515 // Remove any boundary information associated 01516 // with this element 01517 _mesh.boundary_info->remove (elem); 01518 01519 // Add this iterator to the _unused_elements 01520 // data structure so we might fill it. 01521 // The _unused_elements optimization is currently off. 01522 // _unused_elements.push_back (it); 01523 01524 // Don't delete the element until 01525 // MeshRefinement::contract() 01526 // _mesh.delete_elem(elem); 01527 01528 // the mesh has certainly changed 01529 mesh_changed = true; 01530 } 01531 01532 // inactive elements flagged for coarsening 01533 // will become active 01534 else if (elem->refinement_flag() == Elem::COARSEN_INACTIVE) 01535 { 01536 elem->coarsen(); 01537 libmesh_assert (elem->active()); 01538 01539 // the mesh has certainly changed 01540 mesh_changed = true; 01541 } 01542 if (elem->p_refinement_flag() == Elem::COARSEN) 01543 { 01544 if (elem->p_level() > 0) 01545 { 01546 elem->set_p_refinement_flag(Elem::JUST_COARSENED); 01547 elem->set_p_level(elem->p_level() - 1); 01548 mesh_changed = true; 01549 } 01550 else 01551 { 01552 elem->set_p_refinement_flag(Elem::DO_NOTHING); 01553 } 01554 } 01555 } 01556 01557 // If the mesh changed on any processor, it changed globally 01558 CommWorld.max(mesh_changed); 01559 // And we may need to update ParallelMesh values reflecting the changes 01560 if (mesh_changed) 01561 _mesh.update_parallel_id_counts(); 01562 01563 // Node processor ids may need to change if an element of that id 01564 // was coarsened away 01565 if (mesh_changed && !_mesh.is_serial()) 01566 { 01567 // Update the _new_nodes_map so that processors can 01568 // find requested nodes 01569 this->update_nodes_map (); 01570 01571 MeshCommunication().make_nodes_parallel_consistent 01572 (_mesh, _new_nodes_map); 01573 01574 // Clear the _new_nodes_map 01575 this->clear(); 01576 01577 #ifdef DEBUG 01578 MeshTools::libmesh_assert_valid_procids<Node>(_mesh); 01579 #endif 01580 } 01581 01582 STOP_LOG ("_coarsen_elements()", "MeshRefinement"); 01583 01584 return mesh_changed; 01585 } 01586 01587 01588 01589 bool MeshRefinement::_refine_elements () 01590 { 01591 // This function must be run on all processors at once 01592 parallel_only(); 01593 01594 // Update the _new_nodes_map so that elements can 01595 // find nodes to connect to. 01596 this->update_nodes_map (); 01597 01598 START_LOG ("_refine_elements()", "MeshRefinement"); 01599 01600 // Iterate over the elements, counting the elements 01601 // flagged for h refinement. 01602 dof_id_type n_elems_flagged = 0; 01603 01604 MeshBase::element_iterator it = _mesh.elements_begin(); 01605 const MeshBase::element_iterator end = _mesh.elements_end(); 01606 01607 for (; it != end; ++it) 01608 { 01609 Elem* elem = *it; 01610 if (elem->refinement_flag() == Elem::REFINE) 01611 n_elems_flagged++; 01612 } 01613 01614 // Construct a local vector of Elem* which have been 01615 // previously marked for refinement. We reserve enough 01616 // space to allow for every element to be refined. 01617 std::vector<Elem*> local_copy_of_elements; 01618 local_copy_of_elements.reserve(n_elems_flagged); 01619 01620 // Iterate over the elements, looking for elements 01621 // flagged for refinement. 01622 for (it = _mesh.elements_begin(); it != end; ++it) 01623 { 01624 Elem* elem = *it; 01625 if (elem->refinement_flag() == Elem::REFINE) 01626 local_copy_of_elements.push_back(elem); 01627 if (elem->p_refinement_flag() == Elem::REFINE && 01628 elem->active()) 01629 { 01630 elem->set_p_level(elem->p_level()+1); 01631 elem->set_p_refinement_flag(Elem::JUST_REFINED); 01632 } 01633 } 01634 01635 // Now iterate over the local copies and refine each one. 01636 // This may resize the mesh's internal container and invalidate 01637 // any existing iterators. 01638 01639 for (std::size_t e = 0; e != local_copy_of_elements.size(); ++e) 01640 local_copy_of_elements[e]->refine(*this); 01641 01642 // The mesh changed if there were elements h refined 01643 bool mesh_changed = !local_copy_of_elements.empty(); 01644 01645 // If the mesh changed on any processor, it changed globally 01646 CommWorld.max(mesh_changed); 01647 01648 // And we may need to update ParallelMesh values reflecting the changes 01649 if (mesh_changed) 01650 _mesh.update_parallel_id_counts(); 01651 01652 if (mesh_changed && !_mesh.is_serial()) 01653 { 01654 MeshCommunication().make_elems_parallel_consistent (_mesh); 01655 MeshCommunication().make_nodes_parallel_consistent 01656 (_mesh, _new_nodes_map); 01657 #ifdef DEBUG 01658 _mesh.libmesh_assert_valid_parallel_ids(); 01659 #endif 01660 } 01661 01662 // Clear the _new_nodes_map and _unused_elements data structures. 01663 this->clear(); 01664 01665 STOP_LOG ("_refine_elements()", "MeshRefinement"); 01666 01667 return mesh_changed; 01668 } 01669 01670 01671 01672 void MeshRefinement::uniformly_p_refine (unsigned int n) 01673 { 01674 // Refine n times 01675 for (unsigned int rstep=0; rstep<n; rstep++) 01676 { 01677 // P refine all the active elements 01678 MeshBase::element_iterator elem_it = _mesh.active_elements_begin(); 01679 const MeshBase::element_iterator elem_end = _mesh.active_elements_end(); 01680 01681 for ( ; elem_it != elem_end; ++elem_it) 01682 { 01683 (*elem_it)->set_p_level((*elem_it)->p_level()+1); 01684 (*elem_it)->set_p_refinement_flag(Elem::JUST_REFINED); 01685 } 01686 } 01687 } 01688 01689 01690 01691 void MeshRefinement::uniformly_p_coarsen (unsigned int n) 01692 { 01693 // Coarsen p times 01694 for (unsigned int rstep=0; rstep<n; rstep++) 01695 { 01696 // P coarsen all the active elements 01697 MeshBase::element_iterator elem_it = _mesh.active_elements_begin(); 01698 const MeshBase::element_iterator elem_end = _mesh.active_elements_end(); 01699 01700 for ( ; elem_it != elem_end; ++elem_it) 01701 { 01702 if ((*elem_it)->p_level() > 0) 01703 { 01704 (*elem_it)->set_p_level((*elem_it)->p_level()-1); 01705 (*elem_it)->set_p_refinement_flag(Elem::JUST_COARSENED); 01706 } 01707 } 01708 } 01709 } 01710 01711 01712 01713 void MeshRefinement::uniformly_refine (unsigned int n) 01714 { 01715 // Refine n times 01716 // FIXME - this won't work if n>1 and the mesh 01717 // has already been attached to an equation system 01718 for (unsigned int rstep=0; rstep<n; rstep++) 01719 { 01720 // Clean up the refinement flags 01721 this->clean_refinement_flags(); 01722 01723 // Flag all the active elements for refinement. 01724 MeshBase::element_iterator elem_it = _mesh.active_elements_begin(); 01725 const MeshBase::element_iterator elem_end = _mesh.active_elements_end(); 01726 01727 for ( ; elem_it != elem_end; ++elem_it) 01728 (*elem_it)->set_refinement_flag(Elem::REFINE); 01729 01730 // Refine all the elements we just flagged. 01731 this->_refine_elements(); 01732 } 01733 01734 // Finally, the new mesh probably needs to be prepared for use 01735 if (n > 0) 01736 _mesh.prepare_for_use (/*skip_renumber =*/false); 01737 } 01738 01739 01740 01741 void MeshRefinement::uniformly_coarsen (unsigned int n) 01742 { 01743 // Coarsen n times 01744 for (unsigned int rstep=0; rstep<n; rstep++) 01745 { 01746 // Clean up the refinement flags 01747 this->clean_refinement_flags(); 01748 01749 // Flag all the active elements for coarsening 01750 MeshBase::element_iterator elem_it = _mesh.active_elements_begin(); 01751 const MeshBase::element_iterator elem_end = _mesh.active_elements_end(); 01752 01753 for ( ; elem_it != elem_end; ++elem_it) 01754 { 01755 (*elem_it)->set_refinement_flag(Elem::COARSEN); 01756 if ((*elem_it)->parent()) 01757 (*elem_it)->parent()->set_refinement_flag(Elem::COARSEN_INACTIVE); 01758 } 01759 01760 // Coarsen all the elements we just flagged. 01761 this->_coarsen_elements(); 01762 } 01763 01764 01765 // Finally, the new mesh probably needs to be prepared for use 01766 if (n > 0) 01767 _mesh.prepare_for_use (/*skip_renumber =*/false); 01768 } 01769 01770 01771 01772 Elem* MeshRefinement::topological_neighbor(Elem* elem, 01773 const PointLocatorBase* point_locator, 01774 const unsigned int side) 01775 { 01776 #ifdef LIBMESH_ENABLE_PERIODIC 01777 if (_periodic_boundaries && !_periodic_boundaries->empty()) 01778 { 01779 libmesh_assert(point_locator); 01780 return elem->topological_neighbor(side, _mesh, *point_locator, _periodic_boundaries); 01781 } 01782 #endif 01783 return elem->neighbor(side); 01784 } 01785 01786 01787 01788 bool MeshRefinement::has_topological_neighbor(Elem* elem, 01789 const PointLocatorBase* point_locator, 01790 Elem* neighbor) 01791 { 01792 #ifdef LIBMESH_ENABLE_PERIODIC 01793 if (_periodic_boundaries && !_periodic_boundaries->empty()) 01794 { 01795 libmesh_assert(point_locator); 01796 return elem->has_topological_neighbor(neighbor, _mesh, *point_locator, _periodic_boundaries); 01797 } 01798 #endif 01799 return elem->has_neighbor(neighbor); 01800 } 01801 01802 01803 01804 } // namespace libMesh 01805 01806 01807 #endif
Site Created By: libMesh Developers
Last modified: February 05 2013 19:54:47 UTC
Hosted By: