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