$extrastylesheet
00001 // The libMesh Finite Element Library. 00002 // Copyright (C) 2002-2014 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner 00003 00004 // This library is free software; you can redistribute it and/or 00005 // modify it under the terms of the GNU Lesser General Public 00006 // License as published by the Free Software Foundation; either 00007 // version 2.1 of the License, or (at your option) any later version. 00008 00009 // This library is distributed in the hope that it will be useful, 00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 // Lesser General Public License for more details. 00013 00014 // You should have received a copy of the GNU Lesser General Public 00015 // License along with this library; if not, write to the Free Software 00016 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00017 00018 00019 00020 // C++ includes 00021 #include <fstream> 00022 #include <sstream> 00023 #include <iomanip> 00024 00025 // C includes 00026 #include <sys/types.h> // for pid_t 00027 #include <unistd.h> // for getpid(), unlink() 00028 00029 // Local includes 00030 #include "libmesh/boundary_info.h" 00031 #include "libmesh/unstructured_mesh.h" 00032 #include "libmesh/libmesh_logging.h" 00033 #include "libmesh/elem.h" 00034 #include "libmesh/mesh_tools.h" // For n_levels 00035 #include "libmesh/parallel.h" 00036 #include "libmesh/remote_elem.h" 00037 00038 // For most I/O 00039 #include "libmesh/namebased_io.h" 00040 00041 // for MeshData backward compatibility 00042 #include "libmesh/unv_io.h" 00043 #include "libmesh/tetgen_io.h" 00044 00045 #include LIBMESH_INCLUDE_UNORDERED_MAP 00046 00047 00048 namespace libMesh 00049 { 00050 00051 00052 // ------------------------------------------------------------ 00053 // UnstructuredMesh class member functions 00054 UnstructuredMesh::UnstructuredMesh (const Parallel::Communicator &comm_in, 00055 unsigned char d) : 00056 MeshBase (comm_in,d) 00057 { 00058 libmesh_assert (libMesh::initialized()); 00059 } 00060 00061 00062 00063 #ifndef LIBMESH_DISABLE_COMMWORLD 00064 UnstructuredMesh::UnstructuredMesh (unsigned char d) : 00065 MeshBase (d) 00066 { 00067 libmesh_assert (libMesh::initialized()); 00068 } 00069 #endif 00070 00071 00072 00073 void UnstructuredMesh::copy_nodes_and_elements 00074 (const UnstructuredMesh& other_mesh, const bool skip_find_neighbors) 00075 { 00076 // We're assuming our subclass data needs no copy 00077 libmesh_assert_equal_to (_n_parts, other_mesh._n_parts); 00078 libmesh_assert (std::equal(_elem_dims.begin(), _elem_dims.end(), other_mesh._elem_dims.begin())); 00079 libmesh_assert_equal_to (_is_prepared, other_mesh._is_prepared); 00080 00081 // We're assuming the other mesh has proper element number ordering, 00082 // so that we add parents before their children. 00083 #ifdef DEBUG 00084 MeshTools::libmesh_assert_valid_amr_elem_ids(other_mesh); 00085 #endif 00086 00087 //Copy in Nodes 00088 { 00089 //Preallocate Memory if necessary 00090 this->reserve_nodes(other_mesh.n_nodes()); 00091 00092 const_node_iterator it = other_mesh.nodes_begin(); 00093 const_node_iterator end = other_mesh.nodes_end(); 00094 00095 for (; it != end; ++it) 00096 { 00097 const Node *oldn = *it; 00098 00099 // Add new nodes in old node Point locations 00100 /*Node *newn =*/ this->add_point(*oldn, oldn->id(), oldn->processor_id()); 00101 00102 // And start them off in the same subdomain 00103 // newn->processor_id() = oldn->processor_id(); 00104 } 00105 } 00106 00107 //Copy in Elements 00108 { 00109 //Preallocate Memory if necessary 00110 this->reserve_elem(other_mesh.n_elem()); 00111 00112 // Declare a map linking old and new elements, needed to copy the neighbor lists 00113 std::map<const Elem*, Elem*> old_elems_to_new_elems; 00114 00115 // Loop over the elements 00116 MeshBase::const_element_iterator it = other_mesh.elements_begin(); 00117 const MeshBase::const_element_iterator end = other_mesh.elements_end(); 00118 00119 // FIXME: Where do we set element IDs?? 00120 for (; it != end; ++it) 00121 { 00122 //Look at the old element 00123 const Elem *old = *it; 00124 //Build a new element 00125 Elem *newparent = old->parent() ? 00126 this->elem(old->parent()->id()) : NULL; 00127 UniquePtr<Elem> ap = Elem::build(old->type(), newparent); 00128 Elem * el = ap.release(); 00129 00130 el->subdomain_id() = old->subdomain_id(); 00131 00132 for (unsigned int s=0; s != old->n_sides(); ++s) 00133 if (old->neighbor(s) == remote_elem) 00134 el->set_neighbor(s, const_cast<RemoteElem*>(remote_elem)); 00135 00136 #ifdef LIBMESH_ENABLE_AMR 00137 if (old->has_children()) 00138 for (unsigned int c=0; c != old->n_children(); ++c) 00139 if (old->child(c) == remote_elem) 00140 el->add_child(const_cast<RemoteElem*>(remote_elem), c); 00141 00142 //Create the parent's child pointers if necessary 00143 if (newparent) 00144 { 00145 unsigned int oldc = old->parent()->which_child_am_i(old); 00146 newparent->add_child(el, oldc); 00147 } 00148 00149 // Copy the refinement flags 00150 el->set_refinement_flag(old->refinement_flag()); 00151 el->set_p_refinement_flag(old->p_refinement_flag()); 00152 #endif // #ifdef LIBMESH_ENABLE_AMR 00153 00154 //Assign all the nodes 00155 for(unsigned int i=0;i<el->n_nodes();i++) 00156 el->set_node(i) = &this->node(old->node(i)); 00157 00158 // And start it off in the same subdomain 00159 el->processor_id() = old->processor_id(); 00160 00161 // Give it the same id 00162 el->set_id(old->id()); 00163 00164 //Hold onto it 00165 if(!skip_find_neighbors) 00166 { 00167 this->add_elem(el); 00168 } 00169 else 00170 { 00171 Elem* new_el = this->add_elem(el); 00172 old_elems_to_new_elems[old] = new_el; 00173 } 00174 00175 // Add the link between the original element and this copy to the map 00176 if(skip_find_neighbors) 00177 old_elems_to_new_elems[old] = el; 00178 } 00179 00180 // Loop (again) over the elements to fill in the neighbors 00181 if(skip_find_neighbors) 00182 { 00183 it = other_mesh.elements_begin(); 00184 for (; it != end; ++it) 00185 { 00186 Elem* old_elem = *it; 00187 Elem* new_elem = old_elems_to_new_elems[old_elem]; 00188 for (unsigned int s=0; s != old_elem->n_neighbors(); ++s) 00189 { 00190 const Elem* old_neighbor = old_elem->neighbor(s); 00191 Elem* new_neighbor = old_elems_to_new_elems[old_neighbor]; 00192 new_elem->set_neighbor(s, new_neighbor); 00193 } 00194 } 00195 } 00196 } 00197 00198 //Finally prepare the new Mesh for use. Keep the same numbering and 00199 //partitioning but also the same renumbering and partitioning 00200 //policies as our source mesh. 00201 this->allow_renumbering(false); 00202 this->skip_partitioning(true); 00203 this->prepare_for_use(false, skip_find_neighbors); 00204 this->allow_renumbering(other_mesh.allow_renumbering()); 00205 this->skip_partitioning(other_mesh.skip_partitioning()); 00206 } 00207 00208 00209 00210 UnstructuredMesh::~UnstructuredMesh () 00211 { 00212 // this->clear (); // Nothing to clear at this level 00213 00214 libmesh_exceptionless_assert (!libMesh::closed()); 00215 } 00216 00217 00218 00219 00220 00221 void UnstructuredMesh::find_neighbors (const bool reset_remote_elements, 00222 const bool reset_current_list) 00223 { 00224 // We might actually want to run this on an empty mesh 00225 // (e.g. the boundary mesh for a nonexistant bcid!) 00226 // libmesh_assert_not_equal_to (this->n_nodes(), 0); 00227 // libmesh_assert_not_equal_to (this->n_elem(), 0); 00228 00229 // This function must be run on all processors at once 00230 parallel_object_only(); 00231 00232 START_LOG("find_neighbors()", "Mesh"); 00233 00234 const element_iterator el_end = this->elements_end(); 00235 00236 //TODO:[BSK] This should be removed later?! 00237 if (reset_current_list) 00238 for (element_iterator el = this->elements_begin(); el != el_end; ++el) 00239 { 00240 Elem* e = *el; 00241 for (unsigned int s=0; s<e->n_neighbors(); s++) 00242 if (e->neighbor(s) != remote_elem || 00243 reset_remote_elements) 00244 e->set_neighbor(s,NULL); 00245 } 00246 00247 // Find neighboring elements by first finding elements 00248 // with identical side keys and then check to see if they 00249 // are neighbors 00250 { 00251 // data structures -- Use the hash_multimap if available 00252 typedef unsigned int key_type; 00253 typedef std::pair<Elem*, unsigned char> val_type; 00254 typedef std::pair<key_type, val_type> key_val_pair; 00255 00256 typedef LIBMESH_BEST_UNORDERED_MULTIMAP<key_type, val_type> map_type; 00257 00258 // A map from side keys to corresponding elements & side numbers 00259 map_type side_to_elem_map; 00260 00261 00262 00263 for (element_iterator el = this->elements_begin(); el != el_end; ++el) 00264 { 00265 Elem* element = *el; 00266 00267 for (unsigned char ms=0; ms<element->n_neighbors(); ms++) 00268 { 00269 next_side: 00270 // If we haven't yet found a neighbor on this side, try. 00271 // Even if we think our neighbor is remote, that 00272 // information may be out of date. 00273 if (element->neighbor(ms) == NULL || 00274 element->neighbor(ms) == remote_elem) 00275 { 00276 // Get the key for the side of this element 00277 const unsigned int key = element->key(ms); 00278 00279 // Look for elements that have an identical side key 00280 std::pair <map_type::iterator, map_type::iterator> 00281 bounds = side_to_elem_map.equal_range(key); 00282 00283 // May be multiple keys, check all the possible 00284 // elements which _might_ be neighbors. 00285 if (bounds.first != bounds.second) 00286 { 00287 // Get the side for this element 00288 const UniquePtr<Elem> my_side(element->side(ms)); 00289 00290 // Look at all the entries with an equivalent key 00291 while (bounds.first != bounds.second) 00292 { 00293 // Get the potential element 00294 Elem* neighbor = bounds.first->second.first; 00295 00296 // Get the side for the neighboring element 00297 const unsigned int ns = bounds.first->second.second; 00298 const UniquePtr<Elem> their_side(neighbor->side(ns)); 00299 //libmesh_assert(my_side.get()); 00300 //libmesh_assert(their_side.get()); 00301 00302 // If found a match with my side 00303 // 00304 // We need special tests here for 1D: 00305 // since parents and children have an equal 00306 // side (i.e. a node), we need to check 00307 // ns != ms, and we also check level() to 00308 // avoid setting our neighbor pointer to 00309 // any of our neighbor's descendants 00310 if( (*my_side == *their_side) && 00311 (element->level() == neighbor->level()) && 00312 ((element->dim() != 1) || (ns != ms)) ) 00313 { 00314 // So share a side. Is this a mixed pair 00315 // of subactive and active/ancestor 00316 // elements? 00317 // If not, then we're neighbors. 00318 // If so, then the subactive's neighbor is 00319 00320 if (element->subactive() == 00321 neighbor->subactive()) 00322 { 00323 // an element is only subactive if it has 00324 // been coarsened but not deleted 00325 element->set_neighbor (ms,neighbor); 00326 neighbor->set_neighbor(ns,element); 00327 } 00328 else if (element->subactive()) 00329 { 00330 element->set_neighbor(ms,neighbor); 00331 } 00332 else if (neighbor->subactive()) 00333 { 00334 neighbor->set_neighbor(ns,element); 00335 } 00336 side_to_elem_map.erase (bounds.first); 00337 00338 // get out of this nested crap 00339 goto next_side; 00340 } 00341 00342 ++bounds.first; 00343 } 00344 } 00345 00346 // didn't find a match... 00347 // Build the map entry for this element 00348 key_val_pair kvp; 00349 00350 kvp.first = key; 00351 kvp.second.first = element; 00352 kvp.second.second = ms; 00353 00354 // use the lower bound as a hint for 00355 // where to put it. 00356 #if defined(LIBMESH_HAVE_UNORDERED_MAP) || defined(LIBMESH_HAVE_TR1_UNORDERED_MAP) || defined(LIBMESH_HAVE_HASH_MAP) || defined(LIBMESH_HAVE_EXT_HASH_MAP) 00357 side_to_elem_map.insert (kvp); 00358 #else 00359 side_to_elem_map.insert (bounds.first,kvp); 00360 #endif 00361 } 00362 } 00363 } 00364 } 00365 00366 #ifdef LIBMESH_ENABLE_AMR 00367 00388 const unsigned int n_levels = MeshTools::n_levels(*this); 00389 for (unsigned int level = 1; level < n_levels; ++level) 00390 { 00391 element_iterator end = this->level_elements_end(level); 00392 for (element_iterator el = this->level_elements_begin(level); 00393 el != end; ++el) 00394 { 00395 Elem* current_elem = *el; 00396 libmesh_assert(current_elem); 00397 Elem* parent = current_elem->parent(); 00398 libmesh_assert(parent); 00399 const unsigned int my_child_num = parent->which_child_am_i(current_elem); 00400 00401 for (unsigned int s=0; s < current_elem->n_neighbors(); s++) 00402 { 00403 if (current_elem->neighbor(s) == NULL || 00404 (current_elem->neighbor(s) == remote_elem && 00405 parent->is_child_on_side(my_child_num, s))) 00406 { 00407 Elem *neigh = parent->neighbor(s); 00408 00409 // If neigh was refined and had non-subactive children 00410 // made remote earlier, then a non-subactive elem should 00411 // actually have one of those remote children as a 00412 // neighbor 00413 if (neigh && (neigh->ancestor()) && (!current_elem->subactive())) 00414 { 00415 #ifdef DEBUG 00416 // Let's make sure that "had children made remote" 00417 // situation is actually the case 00418 libmesh_assert(neigh->has_children()); 00419 bool neigh_has_remote_children = false; 00420 for (unsigned int c = 0; c != neigh->n_children(); ++c) 00421 { 00422 if (neigh->child(c) == remote_elem) 00423 neigh_has_remote_children = true; 00424 } 00425 libmesh_assert(neigh_has_remote_children); 00426 00427 // And let's double-check that we don't have 00428 // a remote_elem neighboring a local element 00429 libmesh_assert_not_equal_to (current_elem->processor_id(), 00430 this->processor_id()); 00431 #endif // DEBUG 00432 neigh = const_cast<RemoteElem*>(remote_elem); 00433 } 00434 00435 current_elem->set_neighbor(s, neigh); 00436 #ifdef DEBUG 00437 if (neigh != NULL && neigh != remote_elem) 00438 // We ignore subactive elements here because 00439 // we don't care about neighbors of subactive element. 00440 if ((!neigh->active()) && (!current_elem->subactive())) 00441 { 00442 libMesh::err << "On processor " << this->processor_id() 00443 << std::endl; 00444 libMesh::err << "Bad element ID = " << current_elem->id() 00445 << ", Side " << s << ", Bad neighbor ID = " << neigh->id() << std::endl; 00446 libMesh::err << "Bad element proc_ID = " << current_elem->processor_id() 00447 << ", Bad neighbor proc_ID = " << neigh->processor_id() << std::endl; 00448 libMesh::err << "Bad element size = " << current_elem->hmin() 00449 << ", Bad neighbor size = " << neigh->hmin() << std::endl; 00450 libMesh::err << "Bad element center = " << current_elem->centroid() 00451 << ", Bad neighbor center = " << neigh->centroid() << std::endl; 00452 libMesh::err << "ERROR: " 00453 << (current_elem->active()?"Active":"Ancestor") 00454 << " Element at level " 00455 << current_elem->level() << std::endl; 00456 libMesh::err << "with " 00457 << (parent->active()?"active": 00458 (parent->subactive()?"subactive":"ancestor")) 00459 << " parent share " 00460 << (neigh->subactive()?"subactive":"ancestor") 00461 << " neighbor at level " << neigh->level() 00462 << std::endl; 00463 NameBasedIO(*this).write ("bad_mesh.gmv"); 00464 libmesh_error_msg("Problematic mesh written to bad_mesh.gmv."); 00465 } 00466 #endif // DEBUG 00467 } 00468 } 00469 } 00470 } 00471 00472 #endif // AMR 00473 00474 00475 #ifdef DEBUG 00476 MeshTools::libmesh_assert_valid_neighbors(*this); 00477 #endif 00478 00479 STOP_LOG("find_neighbors()", "Mesh"); 00480 } 00481 00482 00483 00484 void UnstructuredMesh::read (const std::string& name, 00485 MeshData* mesh_data, 00486 bool skip_renumber_nodes_and_elements) 00487 { 00488 // Set the skip_renumber_nodes_and_elements flag on all processors 00489 // if necessary. 00490 // This ensures that renumber_nodes_and_elements is *not* called 00491 // during prepare_for_use() for certain types of mesh files. 00492 // This is required in cases where there is an associated solution 00493 // file which expects a certain ordering of the nodes. 00494 if(name.rfind(".gmv")+4==name.size()) 00495 { 00496 skip_renumber_nodes_and_elements = true; 00497 } 00498 00499 if (mesh_data) 00500 { 00501 libmesh_deprecated(); 00502 if (name.rfind(".unv") < name.size()) 00503 UNVIO(*this, mesh_data).read (name); 00504 else if ((name.rfind(".node") < name.size()) || 00505 (name.rfind(".ele") < name.size())) 00506 TetGenIO(*this,mesh_data).read (name); 00507 } 00508 else 00509 NameBasedIO(*this).read(name); 00510 00511 if (skip_renumber_nodes_and_elements) 00512 { 00513 // Use MeshBase::allow_renumbering() yourself instead. 00514 libmesh_deprecated(); 00515 this->allow_renumbering(false); 00516 } 00517 00518 // Done reading the mesh. Now prepare it for use. 00519 this->prepare_for_use(); 00520 } 00521 00522 00523 00524 void UnstructuredMesh::write (const std::string& name, 00525 MeshData* mesh_data) 00526 { 00527 START_LOG("write()", "Mesh"); 00528 00529 if (mesh_data) 00530 { 00531 libmesh_deprecated(); 00532 if (name.rfind(".unv") < name.size()) 00533 UNVIO(*this, mesh_data).write (name); 00534 else 00535 libmesh_error_msg("Only UNV output supports MeshData"); 00536 } 00537 00538 NameBasedIO(*this).write(name); 00539 00540 STOP_LOG("write()", "Mesh"); 00541 } 00542 00543 00544 00545 void UnstructuredMesh::write (const std::string& name, 00546 const std::vector<Number>& v, 00547 const std::vector<std::string>& vn) 00548 { 00549 START_LOG("write()", "Mesh"); 00550 00551 NameBasedIO(*this).write_nodal_data(name, v, vn); 00552 00553 STOP_LOG("write()", "Mesh"); 00554 } 00555 00556 00557 00558 00559 00560 void UnstructuredMesh::create_pid_mesh(UnstructuredMesh& pid_mesh, 00561 const processor_id_type pid) const 00562 { 00563 00564 // Issue a warning if the number the number of processors 00565 // currently available is less that that requested for 00566 // partitioning. This is not necessarily an error since 00567 // you may run on one processor and still partition the 00568 // mesh into several partitions. 00569 #ifdef DEBUG 00570 if (this->n_processors() < pid) 00571 { 00572 libMesh::out << "WARNING: You are creating a " 00573 << "mesh for a processor id (=" 00574 << pid 00575 << ") greater than " 00576 << "the number of processors available for " 00577 << "the calculation. (=" 00578 << this->n_processors() 00579 << ")." 00580 << std::endl; 00581 } 00582 #endif 00583 00584 // Create iterators to loop over the list of elements 00585 // const_active_pid_elem_iterator it(this->elements_begin(), pid); 00586 // const const_active_pid_elem_iterator it_end(this->elements_end(), pid); 00587 00588 const_element_iterator it = this->active_pid_elements_begin(pid); 00589 const const_element_iterator it_end = this->active_pid_elements_end(pid); 00590 00591 this->create_submesh (pid_mesh, it, it_end); 00592 } 00593 00594 00595 00596 00597 00598 00599 00600 void UnstructuredMesh::create_submesh (UnstructuredMesh& new_mesh, 00601 const_element_iterator& it, 00602 const const_element_iterator& it_end) const 00603 { 00604 // Just in case the subdomain_mesh already has some information 00605 // in it, get rid of it. 00606 new_mesh.clear(); 00607 00608 // Fail if (*this == new_mesh), we cannot create a submesh inside ourself! 00609 // This may happen if the user accidently passes the original mesh into 00610 // this function! We will check this by making sure we did not just 00611 // clear ourself. 00612 libmesh_assert_not_equal_to (this->n_nodes(), 0); 00613 libmesh_assert_not_equal_to (this->n_elem(), 0); 00614 00615 // How the nodes on this mesh will be renumbered to nodes 00616 // on the new_mesh. 00617 std::vector<dof_id_type> new_node_numbers (this->n_nodes()); 00618 00619 std::fill (new_node_numbers.begin(), 00620 new_node_numbers.end(), 00621 DofObject::invalid_id); 00622 00623 00624 00625 // the number of nodes on the new mesh, will be incremented 00626 dof_id_type n_new_nodes = 0; 00627 dof_id_type n_new_elem = 0; 00628 00629 for (; it != it_end; ++it) 00630 { 00631 // increment the new element counter 00632 n_new_elem++; 00633 00634 const Elem* old_elem = *it; 00635 00636 // Add an equivalent element type to the new_mesh 00637 Elem* new_elem = 00638 new_mesh.add_elem (Elem::build(old_elem->type()).release()); 00639 00640 libmesh_assert(new_elem); 00641 00642 // Loop over the nodes on this element. 00643 for (unsigned int n=0; n<old_elem->n_nodes(); n++) 00644 { 00645 libmesh_assert_less (old_elem->node(n), new_node_numbers.size()); 00646 00647 if (new_node_numbers[old_elem->node(n)] == DofObject::invalid_id) 00648 { 00649 new_node_numbers[old_elem->node(n)] = n_new_nodes; 00650 00651 // Add this node to the new mesh 00652 new_mesh.add_point (old_elem->point(n)); 00653 00654 // Increment the new node counter 00655 n_new_nodes++; 00656 } 00657 00658 // Define this element's connectivity on the new mesh 00659 libmesh_assert_less (new_node_numbers[old_elem->node(n)], new_mesh.n_nodes()); 00660 00661 new_elem->set_node(n) = new_mesh.node_ptr (new_node_numbers[old_elem->node(n)]); 00662 } 00663 00664 // Copy ids for this element 00665 new_elem->subdomain_id() = old_elem->subdomain_id(); 00666 new_elem->processor_id() = old_elem->processor_id(); 00667 00668 // Maybe add boundary conditions for this element 00669 for (unsigned short s=0; s<old_elem->n_sides(); s++) 00670 // We're supporting boundary ids on internal sides now 00671 //if (old_elem->neighbor(s) == NULL) 00672 { 00673 const std::vector<boundary_id_type>& bc_ids = 00674 this->get_boundary_info().boundary_ids(old_elem, s); 00675 for (std::vector<boundary_id_type>::const_iterator id_it=bc_ids.begin(); id_it!=bc_ids.end(); ++id_it) 00676 { 00677 const boundary_id_type bc_id = *id_it; 00678 if (bc_id != this->get_boundary_info().invalid_id) 00679 new_mesh.get_boundary_info().add_side (new_elem, s, 00680 bc_id); 00681 } 00682 } 00683 } // end loop over elements 00684 00685 00686 // Prepare the new_mesh for use 00687 new_mesh.prepare_for_use(/*skip_renumber =*/false); 00688 00689 } 00690 00691 00692 00693 #ifdef LIBMESH_ENABLE_AMR 00694 bool UnstructuredMesh::contract () 00695 { 00696 START_LOG ("contract()", "Mesh"); 00697 00698 // Flag indicating if this call actually changes the mesh 00699 bool mesh_changed = false; 00700 00701 element_iterator in = elements_begin(); 00702 const element_iterator end = elements_end(); 00703 00704 #ifdef DEBUG 00705 for ( ; in != end; ++in) 00706 if (*in != NULL) 00707 { 00708 Elem* el = *in; 00709 libmesh_assert(el->active() || el->subactive() || el->ancestor()); 00710 } 00711 in = elements_begin(); 00712 #endif 00713 00714 // Loop over the elements. 00715 for ( ; in != end; ++in) 00716 if (*in != NULL) 00717 { 00718 Elem* el = *in; 00719 00720 // Delete all the subactive ones 00721 if (el->subactive()) 00722 { 00723 // No level-0 element should be subactive. 00724 // Note that we CAN'T test elem->level(), as that 00725 // touches elem->parent()->dim(), and elem->parent() 00726 // might have already been deleted! 00727 libmesh_assert(el->parent()); 00728 00729 // Delete the element 00730 // This just sets a pointer to NULL, and doesn't 00731 // invalidate any iterators 00732 this->delete_elem(el); 00733 00734 // the mesh has certainly changed 00735 mesh_changed = true; 00736 } 00737 else 00738 { 00739 // Compress all the active ones 00740 if (el->active()) 00741 el->contract(); 00742 else 00743 libmesh_assert (el->ancestor()); 00744 } 00745 } 00746 00747 // Strip any newly-created NULL voids out of the element array 00748 this->renumber_nodes_and_elements(); 00749 00750 // FIXME: Need to understand why deleting subactive children 00751 // invalidates the point locator. For now we will clear it explicitly 00752 this->clear_point_locator(); 00753 00754 STOP_LOG ("contract()", "Mesh"); 00755 00756 return mesh_changed; 00757 } 00758 #endif // #ifdef LIBMESH_ENABLE_AMR 00759 00760 } // namespace libMesh