$extrastylesheet
00001 // The libMesh Finite Element Library. 00002 // Copyright (C) 2002-2014 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner 00003 00004 // This library is free software; you can redistribute it and/or 00005 // modify it under the terms of the GNU Lesser General Public 00006 // License as published by the Free Software Foundation; either 00007 // version 2.1 of the License, or (at your option) any later version. 00008 00009 // This library is distributed in the hope that it will be useful, 00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 // Lesser General Public License for more details. 00013 00014 // You should have received a copy of the GNU Lesser General Public 00015 // License along with this library; if not, write to the Free Software 00016 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00017 00018 00019 00020 // Local includes 00021 #include "libmesh/boundary_info.h" 00022 #include "libmesh/elem.h" 00023 #include "libmesh/libmesh_logging.h" 00024 #include "libmesh/metis_partitioner.h" 00025 #include "libmesh/serial_mesh.h" 00026 #include "libmesh/utility.h" 00027 00028 #include LIBMESH_INCLUDE_UNORDERED_MAP 00029 #include LIBMESH_INCLUDE_UNORDERED_SET 00030 LIBMESH_DEFINE_HASH_POINTERS 00031 00032 00033 namespace 00034 { 00035 using namespace libMesh; 00036 00037 // A custom comparison function, based on Point::operator<, 00038 // that tries to ignore floating point differences in components 00039 // of the point 00040 class FuzzyPointCompare 00041 { 00042 private: 00043 Real _tol; 00044 00045 public: 00046 // Constructor takes the tolerance to be used in fuzzy comparisons 00047 FuzzyPointCompare(Real tol) : _tol(tol) {} 00048 00049 // This is inspired directly by Point::operator< 00050 bool operator()(const Point& lhs, const Point& rhs) 00051 { 00052 for (unsigned i=0; i<LIBMESH_DIM; ++i) 00053 { 00054 // If the current components are within some tolerance 00055 // of one another, then don't attempt the less-than comparison. 00056 // Note that this may cause something strange to happen, as Roy 00057 // believes he can prove it is not a total ordering... 00058 Real rel_size = std::max(std::abs(lhs(i)), std::abs(rhs(i))); 00059 00060 // Don't use relative tolerance if both numbers are already small. 00061 // How small? Some possible options are: 00062 // * std::numeric_limits<Real>::epsilon() 00063 // * TOLERANCE 00064 // * 1.0 00065 // If we use std::numeric_limits<Real>::epsilon(), we'll 00066 // do more relative comparisons for small numbers, but 00067 // increase the chance for false positives? If we pick 1.0, 00068 // we'll never "increase" the difference between small numbers 00069 // in the test below. 00070 if (rel_size < 1.) 00071 rel_size = 1.; 00072 00073 // Don't attempt the comparison if lhs(i) and rhs(i) are too close 00074 // together. 00075 if ( std::abs(lhs(i) - rhs(i)) / rel_size < _tol) 00076 continue; 00077 00078 if (lhs(i) < rhs(i)) 00079 return true; 00080 if (lhs(i) > rhs(i)) 00081 return false; 00082 } 00083 00084 // We compared all the components without returning yet, so 00085 // each component was neither greater than nor less than they other. 00086 // They might be equal, so return false. 00087 return false; 00088 } 00089 00090 // Needed by std::sort on vector< pair<Point,id> > 00091 bool operator()(const std::pair<Point, dof_id_type>& lhs, 00092 const std::pair<Point, dof_id_type>& rhs) 00093 { 00094 return (*this)(lhs.first, rhs.first); 00095 } 00096 00097 // Comparsion function where lhs is a Point and rhs is a pair<Point,dof_id_type>. 00098 // This is used in routines like lower_bound, where a specific value is being 00099 // searched for. 00100 bool operator()(const Point& lhs, std::pair<Point, dof_id_type>& rhs) 00101 { 00102 return (*this)(lhs, rhs.first); 00103 } 00104 00105 // And the other way around... 00106 bool operator()(std::pair<Point, dof_id_type>& lhs, const Point& rhs) 00107 { 00108 return (*this)(lhs.first, rhs); 00109 } 00110 }; 00111 } 00112 00113 00114 00115 namespace libMesh 00116 { 00117 00118 // ------------------------------------------------------------ 00119 // SerialMesh class member functions 00120 SerialMesh::SerialMesh (const Parallel::Communicator &comm_in, 00121 unsigned char d) : 00122 UnstructuredMesh (comm_in,d) 00123 { 00124 #ifdef LIBMESH_ENABLE_UNIQUE_ID 00125 // In serial we just need to reset the next unique id to zero 00126 // here in the constructor. 00127 _next_unique_id = 0; 00128 #endif 00129 _partitioner = UniquePtr<Partitioner>(new MetisPartitioner()); 00130 } 00131 00132 00133 00134 #ifndef LIBMESH_DISABLE_COMMWORLD 00135 SerialMesh::SerialMesh (unsigned char d) : 00136 UnstructuredMesh (d) 00137 { 00138 #ifdef LIBMESH_ENABLE_UNIQUE_ID 00139 // In serial we just need to reset the next unique id to zero 00140 // here in the constructor. 00141 _next_unique_id = 0; 00142 #endif 00143 _partitioner = UniquePtr<Partitioner>(new MetisPartitioner()); 00144 } 00145 #endif 00146 00147 00148 SerialMesh::~SerialMesh () 00149 { 00150 this->clear(); // Free nodes and elements 00151 } 00152 00153 00154 // This might be specialized later, but right now it's just here to 00155 // make sure the compiler doesn't give us a default (non-deep) copy 00156 // constructor instead. 00157 SerialMesh::SerialMesh (const SerialMesh &other_mesh) : 00158 UnstructuredMesh (other_mesh) 00159 { 00160 this->copy_nodes_and_elements(other_mesh); 00161 this->get_boundary_info() = other_mesh.get_boundary_info(); 00162 } 00163 00164 00165 SerialMesh::SerialMesh (const UnstructuredMesh &other_mesh) : 00166 UnstructuredMesh (other_mesh) 00167 { 00168 this->copy_nodes_and_elements(other_mesh); 00169 this->get_boundary_info() = other_mesh.get_boundary_info(); 00170 } 00171 00172 00173 const Point& SerialMesh::point (const dof_id_type i) const 00174 { 00175 libmesh_assert_less (i, this->n_nodes()); 00176 libmesh_assert(_nodes[i]); 00177 libmesh_assert_equal_to (_nodes[i]->id(), i); // This will change soon 00178 00179 return (*_nodes[i]); 00180 } 00181 00182 00183 00184 00185 00186 const Node& SerialMesh::node (const dof_id_type i) const 00187 { 00188 libmesh_assert_less (i, this->n_nodes()); 00189 libmesh_assert(_nodes[i]); 00190 libmesh_assert_equal_to (_nodes[i]->id(), i); // This will change soon 00191 00192 return (*_nodes[i]); 00193 } 00194 00195 00196 00197 00198 00199 Node& SerialMesh::node (const dof_id_type i) 00200 { 00201 if (i >= this->n_nodes()) 00202 libmesh_error_msg(" i=" << i << ", n_nodes()=" << this->n_nodes()); 00203 00204 libmesh_assert_less (i, this->n_nodes()); 00205 libmesh_assert(_nodes[i]); 00206 libmesh_assert_equal_to (_nodes[i]->id(), i); // This will change soon 00207 00208 return (*_nodes[i]); 00209 } 00210 00211 00212 00213 const Node* SerialMesh::node_ptr (const dof_id_type i) const 00214 { 00215 libmesh_assert_less (i, this->n_nodes()); 00216 libmesh_assert(_nodes[i]); 00217 libmesh_assert_equal_to (_nodes[i]->id(), i); // This will change soon 00218 00219 return _nodes[i]; 00220 } 00221 00222 00223 00224 00225 Node* SerialMesh::node_ptr (const dof_id_type i) 00226 { 00227 libmesh_assert_less (i, this->n_nodes()); 00228 libmesh_assert(_nodes[i]); 00229 libmesh_assert_equal_to (_nodes[i]->id(), i); // This will change soon 00230 00231 return _nodes[i]; 00232 } 00233 00234 00235 00236 00237 const Node* SerialMesh::query_node_ptr (const dof_id_type i) const 00238 { 00239 if (i >= this->n_nodes()) 00240 return NULL; 00241 libmesh_assert (_nodes[i] == NULL || 00242 _nodes[i]->id() == i); // This will change soon 00243 00244 return _nodes[i]; 00245 } 00246 00247 00248 00249 00250 Node* SerialMesh::query_node_ptr (const dof_id_type i) 00251 { 00252 if (i >= this->n_nodes()) 00253 return NULL; 00254 libmesh_assert (_nodes[i] == NULL || 00255 _nodes[i]->id() == i); // This will change soon 00256 00257 return _nodes[i]; 00258 } 00259 00260 00261 00262 00263 const Elem* SerialMesh::elem (const dof_id_type i) const 00264 { 00265 libmesh_assert_less (i, this->n_elem()); 00266 libmesh_assert(_elements[i]); 00267 libmesh_assert_equal_to (_elements[i]->id(), i); // This will change soon 00268 00269 return _elements[i]; 00270 } 00271 00272 00273 00274 00275 Elem* SerialMesh::elem (const dof_id_type i) 00276 { 00277 libmesh_assert_less (i, this->n_elem()); 00278 libmesh_assert(_elements[i]); 00279 libmesh_assert_equal_to (_elements[i]->id(), i); // This will change soon 00280 00281 return _elements[i]; 00282 } 00283 00284 00285 00286 00287 const Elem* SerialMesh::query_elem (const dof_id_type i) const 00288 { 00289 if (i >= this->n_elem()) 00290 return NULL; 00291 libmesh_assert (_elements[i] == NULL || 00292 _elements[i]->id() == i); // This will change soon 00293 00294 return _elements[i]; 00295 } 00296 00297 00298 00299 00300 Elem* SerialMesh::query_elem (const dof_id_type i) 00301 { 00302 if (i >= this->n_elem()) 00303 return NULL; 00304 libmesh_assert (_elements[i] == NULL || 00305 _elements[i]->id() == i); // This will change soon 00306 00307 return _elements[i]; 00308 } 00309 00310 00311 00312 00313 Elem* SerialMesh::add_elem (Elem* e) 00314 { 00315 libmesh_assert(e); 00316 00317 // We no longer merely append elements with SerialMesh 00318 00319 // If the user requests a valid id that doesn't correspond to an 00320 // existing element, let's give them that id, resizing the elements 00321 // container if necessary. 00322 if (!e->valid_id()) 00323 e->set_id (cast_int<dof_id_type>(_elements.size())); 00324 00325 #ifdef LIBMESH_ENABLE_UNIQUE_ID 00326 if (!e->valid_unique_id()) 00327 e->set_unique_id() = _next_unique_id++; 00328 #endif 00329 00330 const dof_id_type id = e->id(); 00331 00332 if (id < _elements.size()) 00333 { 00334 // Overwriting existing elements is still probably a mistake. 00335 libmesh_assert(!_elements[id]); 00336 } 00337 else 00338 { 00339 _elements.resize(id+1, NULL); 00340 } 00341 00342 _elements[id] = e; 00343 00344 return e; 00345 } 00346 00347 00348 00349 Elem* SerialMesh::insert_elem (Elem* e) 00350 { 00351 dof_id_type eid = e->id(); 00352 libmesh_assert_less (eid, _elements.size()); 00353 Elem *oldelem = _elements[eid]; 00354 00355 if (oldelem) 00356 { 00357 libmesh_assert_equal_to (oldelem->id(), eid); 00358 this->delete_elem(oldelem); 00359 } 00360 00361 _elements[e->id()] = e; 00362 00363 return e; 00364 } 00365 00366 00367 00368 void SerialMesh::delete_elem(Elem* e) 00369 { 00370 libmesh_assert(e); 00371 00372 // Initialize an iterator to eventually point to the element we want to delete 00373 std::vector<Elem*>::iterator pos = _elements.end(); 00374 00375 // In many cases, e->id() gives us a clue as to where e 00376 // is located in the _elements vector. Try that first 00377 // before trying the O(n_elem) search. 00378 libmesh_assert_less (e->id(), _elements.size()); 00379 00380 if (_elements[e->id()] == e) 00381 { 00382 // We found it! 00383 pos = _elements.begin(); 00384 std::advance(pos, e->id()); 00385 } 00386 00387 else 00388 { 00389 // This search is O(n_elem) 00390 pos = std::find (_elements.begin(), 00391 _elements.end(), 00392 e); 00393 } 00394 00395 // Huh? Element not in the vector? 00396 libmesh_assert (pos != _elements.end()); 00397 00398 // Remove the element from the BoundaryInfo object 00399 this->get_boundary_info().remove(e); 00400 00401 // delete the element 00402 delete e; 00403 00404 // explicitly NULL the pointer 00405 *pos = NULL; 00406 } 00407 00408 00409 00410 void SerialMesh::renumber_elem(const dof_id_type old_id, 00411 const dof_id_type new_id) 00412 { 00413 // This doesn't get used in serial yet 00414 Elem *el = _elements[old_id]; 00415 libmesh_assert (el); 00416 00417 el->set_id(new_id); 00418 libmesh_assert (!_elements[new_id]); 00419 _elements[new_id] = el; 00420 _elements[old_id] = NULL; 00421 } 00422 00423 00424 00425 Node* SerialMesh::add_point (const Point& p, 00426 const dof_id_type id, 00427 const processor_id_type proc_id) 00428 { 00429 // // We only append points with SerialMesh 00430 // libmesh_assert(id == DofObject::invalid_id || id == _nodes.size()); 00431 // Node *n = Node::build(p, _nodes.size()).release(); 00432 // n->processor_id() = proc_id; 00433 // _nodes.push_back (n); 00434 00435 Node *n = NULL; 00436 00437 // If the user requests a valid id, either 00438 // provide the existing node or resize the container 00439 // to fit the new node. 00440 if (id != DofObject::invalid_id) 00441 if (id < _nodes.size()) 00442 n = _nodes[id]; 00443 else 00444 _nodes.resize(id+1); 00445 else 00446 _nodes.push_back (static_cast<Node*>(NULL)); 00447 00448 // if the node already exists, then assign new (x,y,z) values 00449 if (n) 00450 *n = p; 00451 // otherwise build a new node, put it in the right spot, and return 00452 // a valid pointer. 00453 else 00454 { 00455 n = Node::build(p, (id == DofObject::invalid_id) ? 00456 cast_int<dof_id_type>(_nodes.size()-1) : id).release(); 00457 n->processor_id() = proc_id; 00458 00459 if (id == DofObject::invalid_id) 00460 _nodes.back() = n; 00461 else 00462 _nodes[id] = n; 00463 } 00464 00465 // better not pass back a NULL pointer. 00466 libmesh_assert (n); 00467 00468 return n; 00469 } 00470 00471 00472 00473 Node* SerialMesh::add_node (Node* n) 00474 { 00475 libmesh_assert(n); 00476 // We only append points with SerialMesh 00477 libmesh_assert(!n->valid_id() || n->id() == _nodes.size()); 00478 00479 n->set_id (cast_int<dof_id_type>(_nodes.size())); 00480 00481 #ifdef LIBMESH_ENABLE_UNIQUE_ID 00482 if (!n->valid_unique_id()) 00483 n->set_unique_id() = _next_unique_id++; 00484 #endif 00485 00486 _nodes.push_back(n); 00487 00488 return n; 00489 } 00490 00491 00492 00493 Node* SerialMesh::insert_node(Node* n) 00494 { 00495 if (!n) 00496 libmesh_error_msg("Error, attempting to insert NULL node."); 00497 00498 if (n->id() == DofObject::invalid_id) 00499 libmesh_error_msg("Error, cannot insert node with invalid id."); 00500 00501 if (n->id() < _nodes.size()) 00502 { 00503 // Don't allow inserting on top of an existing Node. 00504 00505 // Doing so doesn't have to be *error*, in the case where a 00506 // redundant insert is done, but when that happens we ought to 00507 // always be able to make the code more efficient by avoiding 00508 // the redundant insert, so let's keep screaming "Error" here. 00509 if (_nodes[ n->id() ] != NULL) 00510 libmesh_error_msg("Error, cannot insert node on top of existing node."); 00511 } 00512 else 00513 { 00514 // Allocate just enough space to store the new node. This will 00515 // cause highly non-ideal memory allocation behavior if called 00516 // repeatedly... 00517 _nodes.resize(n->id() + 1); 00518 } 00519 00520 00521 // We have enough space and this spot isn't already occupied by 00522 // another node, so go ahead and add it. 00523 _nodes[ n->id() ] = n; 00524 00525 // If we made it this far, we just inserted the node the user handed 00526 // us, so we can give it right back. 00527 return n; 00528 } 00529 00530 00531 00532 void SerialMesh::delete_node(Node* n) 00533 { 00534 libmesh_assert(n); 00535 libmesh_assert_less (n->id(), _nodes.size()); 00536 00537 // Initialize an iterator to eventually point to the element we want 00538 // to delete 00539 std::vector<Node*>::iterator pos; 00540 00541 // In many cases, e->id() gives us a clue as to where e 00542 // is located in the _elements vector. Try that first 00543 // before trying the O(n_elem) search. 00544 if (_nodes[n->id()] == n) 00545 { 00546 pos = _nodes.begin(); 00547 std::advance(pos, n->id()); 00548 } 00549 else 00550 { 00551 pos = std::find (_nodes.begin(), 00552 _nodes.end(), 00553 n); 00554 } 00555 00556 // Huh? Node not in the vector? 00557 libmesh_assert (pos != _nodes.end()); 00558 00559 // Delete the node from the BoundaryInfo object 00560 this->get_boundary_info().remove(n); 00561 00562 // delete the node 00563 delete n; 00564 00565 // explicitly NULL the pointer 00566 *pos = NULL; 00567 } 00568 00569 00570 00571 void SerialMesh::renumber_node(const dof_id_type old_id, 00572 const dof_id_type new_id) 00573 { 00574 // This doesn't get used in serial yet 00575 Node *nd = _nodes[old_id]; 00576 libmesh_assert (nd); 00577 00578 nd->set_id(new_id); 00579 libmesh_assert (!_nodes[new_id]); 00580 _nodes[new_id] = nd; 00581 _nodes[old_id] = NULL; 00582 } 00583 00584 00585 00586 void SerialMesh::clear () 00587 { 00588 // Call parent clear function 00589 MeshBase::clear(); 00590 00591 00592 // Clear our elements and nodes 00593 { 00594 std::vector<Elem*>::iterator it = _elements.begin(); 00595 const std::vector<Elem*>::iterator end = _elements.end(); 00596 00597 // There is no need to remove the elements from 00598 // the BoundaryInfo data structure since we 00599 // already cleared it. 00600 for (; it != end; ++it) 00601 delete *it; 00602 00603 _elements.clear(); 00604 } 00605 00606 // clear the nodes data structure 00607 { 00608 std::vector<Node*>::iterator it = _nodes.begin(); 00609 const std::vector<Node*>::iterator end = _nodes.end(); 00610 00611 // There is no need to remove the nodes from 00612 // the BoundaryInfo data structure since we 00613 // already cleared it. 00614 for (; it != end; ++it) 00615 delete *it; 00616 00617 _nodes.clear(); 00618 } 00619 } 00620 00621 00622 00623 void SerialMesh::renumber_nodes_and_elements () 00624 { 00625 00626 START_LOG("renumber_nodes_and_elem()", "Mesh"); 00627 00628 // node and element id counters 00629 dof_id_type next_free_elem = 0; 00630 dof_id_type next_free_node = 0; 00631 00632 // Will hold the set of nodes that are currently connected to elements 00633 LIBMESH_BEST_UNORDERED_SET<Node*> connected_nodes; 00634 00635 // Loop over the elements. Note that there may 00636 // be NULLs in the _elements vector from the coarsening 00637 // process. Pack the elements in to a contiguous array 00638 // and then trim any excess. 00639 { 00640 std::vector<Elem*>::iterator in = _elements.begin(); 00641 std::vector<Elem*>::iterator out_iter = _elements.begin(); 00642 const std::vector<Elem*>::iterator end = _elements.end(); 00643 00644 for (; in != end; ++in) 00645 if (*in != NULL) 00646 { 00647 Elem* el = *in; 00648 00649 *out_iter = *in; 00650 ++out_iter; 00651 00652 // Increment the element counter 00653 el->set_id (next_free_elem++); 00654 00655 if(_skip_renumber_nodes_and_elements) 00656 { 00657 // Add this elements nodes to the connected list 00658 for (unsigned int n=0; n<el->n_nodes(); n++) 00659 connected_nodes.insert(el->get_node(n)); 00660 } 00661 else // We DO want node renumbering 00662 { 00663 // Loop over this element's nodes. Number them, 00664 // if they have not been numbered already. Also, 00665 // position them in the _nodes vector so that they 00666 // are packed contiguously from the beginning. 00667 for (unsigned int n=0; n<el->n_nodes(); n++) 00668 if (el->node(n) == next_free_node) // don't need to process 00669 next_free_node++; // [(src == dst) below] 00670 00671 else if (el->node(n) > next_free_node) // need to process 00672 { 00673 // The source and destination indices 00674 // for this node 00675 const dof_id_type src_idx = el->node(n); 00676 const dof_id_type dst_idx = next_free_node++; 00677 00678 // ensure we want to swap a valid nodes 00679 libmesh_assert(_nodes[src_idx]); 00680 00681 // Swap the source and destination nodes 00682 std::swap(_nodes[src_idx], 00683 _nodes[dst_idx] ); 00684 00685 // Set proper indices where that makes sense 00686 if (_nodes[src_idx] != NULL) 00687 _nodes[src_idx]->set_id (src_idx); 00688 _nodes[dst_idx]->set_id (dst_idx); 00689 } 00690 } 00691 } 00692 00693 // Erase any additional storage. These elements have been 00694 // copied into NULL voids by the procedure above, and are 00695 // thus repeated and unnecessary. 00696 _elements.erase (out_iter, end); 00697 } 00698 00699 00700 if(_skip_renumber_nodes_and_elements) 00701 { 00702 // Loop over the nodes. Note that there may 00703 // be NULLs in the _nodes vector from the coarsening 00704 // process. Pack the nodes in to a contiguous array 00705 // and then trim any excess. 00706 00707 std::vector<Node*>::iterator in = _nodes.begin(); 00708 std::vector<Node*>::iterator out_iter = _nodes.begin(); 00709 const std::vector<Node*>::iterator end = _nodes.end(); 00710 00711 for (; in != end; ++in) 00712 if (*in != NULL) 00713 { 00714 // This is a reference so that if we change the pointer it will change in the vector 00715 Node* & nd = *in; 00716 00717 // If this node is still connected to an elem, put it in the list 00718 if(connected_nodes.find(nd) != connected_nodes.end()) 00719 { 00720 *out_iter = nd; 00721 ++out_iter; 00722 00723 // Increment the node counter 00724 nd->set_id (next_free_node++); 00725 } 00726 else // This node is orphaned, delete it! 00727 { 00728 this->get_boundary_info().remove (nd); 00729 00730 // delete the node 00731 delete nd; 00732 nd = NULL; 00733 } 00734 } 00735 00736 // Erase any additional storage. Whatever was 00737 _nodes.erase (out_iter, end); 00738 } 00739 else // We really DO want node renumbering 00740 { 00741 // Any nodes in the vector >= _nodes[next_free_node] 00742 // are not connected to any elements and may be deleted 00743 // if desired. 00744 00745 // (This code block will erase the unused nodes) 00746 // Now, delete the unused nodes 00747 { 00748 std::vector<Node*>::iterator nd = _nodes.begin(); 00749 const std::vector<Node*>::iterator end = _nodes.end(); 00750 00751 std::advance (nd, next_free_node); 00752 00753 for (std::vector<Node*>::iterator it=nd; 00754 it != end; ++it) 00755 { 00756 // Mesh modification code might have already deleted some 00757 // nodes 00758 if (*it == NULL) 00759 continue; 00760 00761 // remove any boundary information associated with 00762 // this node 00763 this->get_boundary_info().remove (*it); 00764 00765 // delete the node 00766 delete *it; 00767 *it = NULL; 00768 } 00769 00770 _nodes.erase (nd, end); 00771 } 00772 } 00773 00774 libmesh_assert_equal_to (next_free_elem, _elements.size()); 00775 libmesh_assert_equal_to (next_free_node, _nodes.size()); 00776 00777 STOP_LOG("renumber_nodes_and_elem()", "Mesh"); 00778 } 00779 00780 00781 00782 void SerialMesh::fix_broken_node_and_element_numbering () 00783 { 00784 // Nodes first 00785 for (dof_id_type n=0; n<this->_nodes.size(); n++) 00786 if (this->_nodes[n] != NULL) 00787 this->_nodes[n]->set_id() = n; 00788 00789 // Elements next 00790 for (dof_id_type e=0; e<this->_elements.size(); e++) 00791 if (this->_elements[e] != NULL) 00792 this->_elements[e]->set_id() = e; 00793 } 00794 00795 00796 void SerialMesh::stitch_meshes (SerialMesh& other_mesh, 00797 boundary_id_type this_mesh_boundary_id, 00798 boundary_id_type other_mesh_boundary_id, 00799 Real tol, 00800 bool clear_stitched_boundary_ids, 00801 bool verbose, 00802 bool use_binary_search, 00803 bool enforce_all_nodes_match_on_boundaries) 00804 { 00805 START_LOG("stitch_meshes()", "SerialMesh"); 00806 stitching_helper(&other_mesh, 00807 this_mesh_boundary_id, 00808 other_mesh_boundary_id, 00809 tol, 00810 clear_stitched_boundary_ids, 00811 verbose, 00812 use_binary_search, 00813 enforce_all_nodes_match_on_boundaries, 00814 true); 00815 STOP_LOG("stitch_meshes()", "SerialMesh"); 00816 } 00817 00818 void SerialMesh::stitch_surfaces (boundary_id_type boundary_id_1, 00819 boundary_id_type boundary_id_2, 00820 Real tol, 00821 bool clear_stitched_boundary_ids, 00822 bool verbose, 00823 bool use_binary_search, 00824 bool enforce_all_nodes_match_on_boundaries) 00825 { 00826 stitching_helper(NULL, 00827 boundary_id_1, 00828 boundary_id_2, 00829 tol, 00830 clear_stitched_boundary_ids, 00831 verbose, 00832 use_binary_search, 00833 enforce_all_nodes_match_on_boundaries, 00834 true); 00835 } 00836 00837 void SerialMesh::stitching_helper (SerialMesh* other_mesh, 00838 boundary_id_type this_mesh_boundary_id, 00839 boundary_id_type other_mesh_boundary_id, 00840 Real tol, 00841 bool clear_stitched_boundary_ids, 00842 bool verbose, 00843 bool use_binary_search, 00844 bool enforce_all_nodes_match_on_boundaries, 00845 bool skip_find_neighbors) 00846 { 00847 std::map<dof_id_type, dof_id_type> node_to_node_map, other_to_this_node_map; // The second is the inverse map of the first 00848 std::map<dof_id_type, std::vector<dof_id_type> > node_to_elems_map; 00849 00850 typedef dof_id_type key_type; 00851 typedef std::pair<Elem*, unsigned char> val_type; 00852 typedef std::pair<key_type, val_type> key_val_pair; 00853 typedef LIBMESH_BEST_UNORDERED_MULTIMAP<key_type, val_type> map_type; 00854 // Mapping between all side keys in this mesh and elements+side numbers relevant to the boundary in this mesh as well. 00855 map_type side_to_elem_map; 00856 00857 // If there is only one mesh (i.e. other_mesh==NULL), then loop over this mesh twice 00858 if(!other_mesh) 00859 { 00860 other_mesh = this; 00861 } 00862 00863 if( (this_mesh_boundary_id != BoundaryInfo::invalid_id) && 00864 (other_mesh_boundary_id != BoundaryInfo::invalid_id) ) 00865 { 00866 // While finding nodes on the boundary, also find the minimum edge length 00867 // of all faces on both boundaries. This will later be used in relative 00868 // distance checks when stitching nodes. 00869 Real h_min = std::numeric_limits<Real>::max(); 00870 bool h_min_updated = false; 00871 00872 // Loop below fills in these sets for the two meshes. 00873 std::set<dof_id_type> this_boundary_node_ids, other_boundary_node_ids; 00874 { 00875 // Make temporary fixed-size arrays for loop 00876 boundary_id_type id_array[2] = {this_mesh_boundary_id, other_mesh_boundary_id}; 00877 std::set<dof_id_type>* set_array[2] = {&this_boundary_node_ids, &other_boundary_node_ids}; 00878 SerialMesh* mesh_array[2] = {this, other_mesh}; 00879 00880 for (unsigned i=0; i<2; ++i) 00881 { 00882 // First we deal with node boundary IDs. 00883 // We only enter this loop if we have at least one 00884 // nodeset. 00885 if(mesh_array[i]->get_boundary_info().n_nodeset_conds() > 0) 00886 { 00887 // We need to find an element that contains boundary nodes in order 00888 // to update hmin. 00889 UniquePtr<PointLocatorBase> my_locator = mesh_array[i]->sub_point_locator(); 00890 00891 std::vector<numeric_index_type> node_id_list; 00892 std::vector<boundary_id_type> bc_id_list; 00893 00894 // Get the list of nodes with associated boundary IDs 00895 mesh_array[i]->get_boundary_info().build_node_list(node_id_list, bc_id_list); 00896 00897 for(unsigned int node_index=0; node_index<bc_id_list.size(); node_index++) 00898 { 00899 boundary_id_type node_bc_id = bc_id_list[node_index]; 00900 if (node_bc_id == id_array[i]) 00901 { 00902 dof_id_type node_id = node_id_list[node_index]; 00903 set_array[i]->insert( node_id ); 00904 00905 const Elem* near_elem = (*my_locator)( mesh_array[i]->node(node_id) ); 00906 if (near_elem == NULL) 00907 libmesh_error_msg("Error: PointLocator failed to find a valid element"); 00908 00909 h_min = std::min(h_min, near_elem->hmin()); 00910 h_min_updated = true; 00911 } 00912 } 00913 } 00914 00915 MeshBase::element_iterator elem_it = mesh_array[i]->elements_begin(); 00916 MeshBase::element_iterator elem_end = mesh_array[i]->elements_end(); 00917 for ( ; elem_it != elem_end; ++elem_it) 00918 { 00919 Elem *el = *elem_it; 00920 00921 // Now check whether elem has a face on the specified boundary 00922 for (unsigned char side_id=0; side_id<el->n_sides(); ++side_id) 00923 if (el->neighbor(side_id) == NULL) 00924 { 00925 // Get *all* boundary IDs on this side, not just the first one! 00926 std::vector<boundary_id_type> bc_ids = 00927 mesh_array[i]->get_boundary_info().boundary_ids (el, side_id); 00928 00929 if (std::count(bc_ids.begin(), bc_ids.end(), id_array[i])) 00930 { 00931 UniquePtr<Elem> side (el->build_side(side_id)); 00932 for (unsigned int node_id=0; node_id<side->n_nodes(); ++node_id) 00933 set_array[i]->insert( side->node(node_id) ); 00934 00935 h_min = std::min(h_min, side->hmin()); 00936 h_min_updated = true; 00937 00938 // This side is on the boundary, add its information to side_to_elem 00939 if(skip_find_neighbors && (i==0)) 00940 { 00941 key_type key = el->key(side_id); 00942 val_type val; 00943 val.first = el; 00944 val.second = side_id; 00945 00946 key_val_pair kvp; 00947 kvp.first = key; 00948 kvp.second = val; 00949 // side_to_elem_map[key] = val; 00950 #if defined(LIBMESH_HAVE_UNORDERED_MAP) || defined(LIBMESH_HAVE_TR1_UNORDERED_MAP) || defined(LIBMESH_HAVE_HASH_MAP) || defined(LIBMESH_HAVE_EXT_HASH_MAP) 00951 side_to_elem_map.insert (kvp); 00952 #else 00953 side_to_elem_map.insert (side_to_elem_map.begin(),kvp); 00954 #endif 00955 } 00956 } 00957 00958 // Also, check the edges on this side. We don't have to worry about 00959 // updating neighbor info in this case since elements don't store 00960 // neighbor info on edges. 00961 for (unsigned short edge_id=0; edge_id<el->n_edges(); ++edge_id) 00962 { 00963 if(el->is_edge_on_side(edge_id, side_id)) 00964 { 00965 // Get *all* boundary IDs on this edge, not just the first one! 00966 std::vector<boundary_id_type> edge_bc_ids = 00967 mesh_array[i]->get_boundary_info().edge_boundary_ids (el, edge_id); 00968 00969 if (std::count(edge_bc_ids.begin(), edge_bc_ids.end(), id_array[i])) 00970 { 00971 UniquePtr<Elem> edge (el->build_edge(edge_id)); 00972 for (unsigned int node_id=0; node_id<edge->n_nodes(); ++node_id) 00973 set_array[i]->insert( edge->node(node_id) ); 00974 00975 h_min = std::min(h_min, edge->hmin()); 00976 h_min_updated = true; 00977 } 00978 } 00979 } 00980 } 00981 } 00982 } 00983 } 00984 00985 if (verbose) 00986 { 00987 libMesh::out << "In SerialMesh::stitch_meshes:\n" 00988 << "This mesh has " << this_boundary_node_ids.size() 00989 << " nodes on boundary " << this_mesh_boundary_id << ".\n" 00990 << "Other mesh has " << other_boundary_node_ids.size() 00991 << " nodes on boundary " << other_mesh_boundary_id << ".\n"; 00992 00993 if(h_min_updated) 00994 { 00995 libMesh::out << "Minimum edge length on both surfaces is " << h_min << ".\n"; 00996 } 00997 else 00998 { 00999 libMesh::out << "No elements on specified surfaces." << std::endl; 01000 } 01001 } 01002 01003 01004 if(use_binary_search) 01005 { 01006 // Store points from both stitched faces in sorted vectors for faster 01007 // searching later. 01008 typedef std::vector< std::pair<Point, dof_id_type> > PointVector; 01009 PointVector 01010 this_sorted_bndry_nodes(this_boundary_node_ids.size()), 01011 other_sorted_bndry_nodes(other_boundary_node_ids.size()); 01012 01013 // Comparison object that will be used later. So far, I've had reasonable success 01014 // with TOLERANCE... 01015 FuzzyPointCompare mein_comp(TOLERANCE); 01016 01017 // Create and sort the vectors we will use to do the geometric searching 01018 { 01019 std::set<dof_id_type>* set_array[2] = {&this_boundary_node_ids, &other_boundary_node_ids}; 01020 SerialMesh* mesh_array[2] = {this, other_mesh}; 01021 PointVector* vec_array[2] = {&this_sorted_bndry_nodes, &other_sorted_bndry_nodes}; 01022 01023 for (unsigned i=0; i<2; ++i) 01024 { 01025 std::set<dof_id_type>::iterator 01026 set_it = set_array[i]->begin(), 01027 set_it_end = set_array[i]->end(); 01028 01029 // Fill up the vector with the contents of the set... 01030 for (unsigned ctr=0; set_it != set_it_end; ++set_it, ++ctr) 01031 { 01032 (*vec_array[i])[ctr] = std::make_pair( mesh_array[i]->point(*set_it), // The geometric point 01033 *set_it ); // Its ID 01034 } 01035 01036 // Sort the vectors based on the FuzzyPointCompare struct op() 01037 std::sort(vec_array[i]->begin(), vec_array[i]->end(), mein_comp); 01038 } 01039 } 01040 01041 // Build up the node_to_node_map and node_to_elems_map using the sorted vectors of Points. 01042 for (unsigned i=0; i<this_sorted_bndry_nodes.size(); ++i) 01043 { 01044 // Current point we're working on 01045 Point this_point = this_sorted_bndry_nodes[i].first; 01046 01047 // FuzzyPointCompare does a fuzzy equality comparison internally to handle 01048 // slight differences between the list of nodes on each mesh. 01049 PointVector::iterator other_iter = Utility::binary_find(other_sorted_bndry_nodes.begin(), 01050 other_sorted_bndry_nodes.end(), 01051 this_point, 01052 mein_comp); 01053 01054 // Not every node on this_sorted_bndry_nodes will necessarily be stitched, so 01055 // if its pair is not found on other_mesh, just continue. 01056 if (other_iter != other_sorted_bndry_nodes.end()) 01057 { 01058 // Check that the points do indeed match - should not be necessary unless something 01059 // is wrong with binary_find. To be on the safe side, we'll check. 01060 { 01061 // Grab the other point from the iterator 01062 Point other_point = other_iter->first; 01063 01064 if (!this_point.absolute_fuzzy_equals(other_point, tol*h_min)) 01065 libmesh_error_msg("Error: mismatched points: " << this_point << " and " << other_point); 01066 } 01067 01068 01069 // Associate these two nodes in both the node_to_node_map and the other_to_this_node_map 01070 dof_id_type 01071 this_node_id = this_sorted_bndry_nodes[i].second, 01072 other_node_id = other_iter->second; 01073 node_to_node_map[this_node_id] = other_node_id; 01074 other_to_this_node_map[other_node_id] = this_node_id; 01075 } 01076 01077 } 01078 } 01079 else 01080 { 01081 // Otherwise, use a simple N^2 search to find the closest matching points. This can be helpful 01082 // in the case that we have tolerance issues which cause mismatch between the two surfaces 01083 // that are being stitched. 01084 01085 std::set<dof_id_type>::iterator set_it = this_boundary_node_ids.begin(); 01086 std::set<dof_id_type>::iterator set_it_end = this_boundary_node_ids.end(); 01087 for( ; set_it != set_it_end; ++set_it) 01088 { 01089 dof_id_type this_node_id = *set_it; 01090 Node& this_node = this->node(this_node_id); 01091 01092 bool found_matching_nodes = false; 01093 01094 std::set<dof_id_type>::iterator other_set_it = other_boundary_node_ids.begin(); 01095 std::set<dof_id_type>::iterator other_set_it_end = other_boundary_node_ids.end(); 01096 for( ; other_set_it != other_set_it_end; ++other_set_it) 01097 { 01098 dof_id_type other_node_id = *other_set_it; 01099 Node& other_node = other_mesh->node(other_node_id); 01100 01101 Real node_distance = (this_node - other_node).size(); 01102 01103 if(node_distance < tol*h_min) 01104 { 01105 // Make sure we didn't already find a matching node! 01106 if(found_matching_nodes) 01107 libmesh_error_msg("Error: Found multiple matching nodes in stitch_meshes"); 01108 01109 node_to_node_map[this_node_id] = other_node_id; 01110 other_to_this_node_map[other_node_id] = this_node_id; 01111 01112 found_matching_nodes = true; 01113 } 01114 } 01115 } 01116 } 01117 01118 // Build up the node_to_elems_map, using only one loop over other_mesh 01119 { 01120 MeshBase::element_iterator other_elem_it = other_mesh->elements_begin(); 01121 MeshBase::element_iterator other_elem_end = other_mesh->elements_end(); 01122 for (; other_elem_it != other_elem_end; ++other_elem_it) 01123 { 01124 Elem *el = *other_elem_it; 01125 01126 // For each node on the element, find the corresponding node 01127 // on "this" Mesh, 'this_node_id', if it exists, and push 01128 // the current element ID back onto node_to_elems_map[this_node_id]. 01129 // For that we will use the reverse mapping we created at 01130 // the same time as the forward mapping. 01131 for (unsigned n=0; n<el->n_nodes(); ++n) 01132 { 01133 dof_id_type other_node_id = el->node(n); 01134 std::map<dof_id_type, dof_id_type>::iterator it = 01135 other_to_this_node_map.find(other_node_id); 01136 01137 if (it != other_to_this_node_map.end()) 01138 { 01139 dof_id_type this_node_id = it->second; 01140 node_to_elems_map[this_node_id].push_back( el->id() ); 01141 } 01142 } 01143 } 01144 } 01145 01146 if(verbose) 01147 { 01148 libMesh::out << "In SerialMesh::stitch_meshes:\n" 01149 << "Found " << node_to_node_map.size() 01150 << " matching nodes.\n" 01151 << std::endl; 01152 } 01153 01154 if(enforce_all_nodes_match_on_boundaries) 01155 { 01156 std::size_t n_matching_nodes = node_to_node_map.size(); 01157 std::size_t this_mesh_n_nodes = this_boundary_node_ids.size(); 01158 std::size_t other_mesh_n_nodes = other_boundary_node_ids.size(); 01159 if( (n_matching_nodes != this_mesh_n_nodes) || 01160 (n_matching_nodes != other_mesh_n_nodes) ) 01161 libmesh_error_msg("Error: We expected the number of nodes to match."); 01162 } 01163 } 01164 else 01165 { 01166 if(verbose) 01167 { 01168 libMesh::out << "Skip node merging in SerialMesh::stitch_meshes:" << std::endl; 01169 } 01170 } 01171 01172 01173 01174 dof_id_type node_delta = this->n_nodes(); 01175 dof_id_type elem_delta = this->n_elem(); 01176 01177 // If other_mesh!=NULL, then we have to do a bunch of work 01178 // in order to copy it to this mesh 01179 if(this!=other_mesh) 01180 { 01181 // need to increment node and element IDs of other_mesh before copying to this mesh 01182 MeshBase::node_iterator node_it = other_mesh->nodes_begin(); 01183 MeshBase::node_iterator node_end = other_mesh->nodes_end(); 01184 for (; node_it != node_end; ++node_it) 01185 { 01186 Node *nd = *node_it; 01187 dof_id_type new_id = nd->id() + node_delta; 01188 nd->set_id(new_id); 01189 } 01190 01191 MeshBase::element_iterator elem_it = other_mesh->elements_begin(); 01192 MeshBase::element_iterator elem_end = other_mesh->elements_end(); 01193 for (; elem_it != elem_end; ++elem_it) 01194 { 01195 Elem *el = *elem_it; 01196 dof_id_type new_id = el->id() + elem_delta; 01197 el->set_id(new_id); 01198 } 01199 01200 // Also, increment the node_to_node_map and node_to_elems_map 01201 std::map<dof_id_type, dof_id_type>::iterator node_map_it = node_to_node_map.begin(); 01202 std::map<dof_id_type, dof_id_type>::iterator node_map_it_end = node_to_node_map.end(); 01203 for( ; node_map_it != node_map_it_end; ++node_map_it) 01204 { 01205 node_map_it->second += node_delta; 01206 } 01207 std::map<dof_id_type, std::vector<dof_id_type> >::iterator elem_map_it = node_to_elems_map.begin(); 01208 std::map<dof_id_type, std::vector<dof_id_type> >::iterator elem_map_it_end = node_to_elems_map.end(); 01209 for( ; elem_map_it != elem_map_it_end; ++elem_map_it) 01210 { 01211 std::size_t n_elems = elem_map_it->second.size(); 01212 for(std::size_t i=0; i<n_elems; i++) 01213 { 01214 (elem_map_it->second)[i] += elem_delta; 01215 } 01216 } 01217 01218 // Copy mesh data. If we skip the call to find_neighbors(), the lists 01219 // of neighbors will be copied verbatim from the other mesh 01220 this->copy_nodes_and_elements(*other_mesh, skip_find_neighbors); 01221 01222 // Decrement node IDs of mesh to return to original state 01223 node_it = other_mesh->nodes_begin(); 01224 node_end = other_mesh->nodes_end(); 01225 for (; node_it != node_end; ++node_it) 01226 { 01227 Node *nd = *node_it; 01228 dof_id_type new_id = nd->id() - node_delta; 01229 nd->set_id(new_id); 01230 } 01231 01232 elem_it = other_mesh->elements_begin(); 01233 elem_end = other_mesh->elements_end(); 01234 for (; elem_it != elem_end; ++elem_it) 01235 { 01236 Elem *other_elem = *elem_it; 01237 01238 // Find the corresponding element on this mesh 01239 Elem* this_elem = this->elem(other_elem->id()); 01240 01241 // Decrement elem IDs of other_mesh to return it to original state 01242 dof_id_type new_id = other_elem->id() - elem_delta; 01243 other_elem->set_id(new_id); 01244 01245 unsigned int other_n_nodes = other_elem->n_nodes(); 01246 for (unsigned int n=0; n != other_n_nodes; ++n) 01247 { 01248 const std::vector<boundary_id_type>& ids = 01249 other_mesh->get_boundary_info().boundary_ids(other_elem->get_node(n)); 01250 if (!ids.empty()) 01251 { 01252 this->get_boundary_info().add_node(this_elem->get_node(n), ids); 01253 } 01254 } 01255 01256 // Copy edge boundary info 01257 unsigned int n_edges = other_elem->n_edges(); 01258 for (unsigned short edge=0; edge != n_edges; ++edge) 01259 { 01260 const std::vector<boundary_id_type>& ids = 01261 other_mesh->get_boundary_info().edge_boundary_ids(other_elem, edge); 01262 if (!ids.empty()) 01263 { 01264 this->get_boundary_info().add_edge( this_elem, edge, ids); 01265 } 01266 } 01267 01268 unsigned int n_sides = other_elem->n_sides(); 01269 for (unsigned short s=0; s != n_sides; ++s) 01270 { 01271 const std::vector<boundary_id_type>& ids = 01272 other_mesh->get_boundary_info().boundary_ids(other_elem, s); 01273 if (!ids.empty()) 01274 { 01275 this->get_boundary_info().add_side( this_elem, s, ids); 01276 } 01277 } 01278 01279 } 01280 01281 } // end if(other_mesh) 01282 01283 // Finally, we need to "merge" the overlapping nodes 01284 // We do this by iterating over node_to_elems_map and updating 01285 // the elements so that they "point" to the nodes that came 01286 // from this mesh, rather than from other_mesh. 01287 // Then we iterate over node_to_node_map and delete the 01288 // duplicate nodes that came from other_mesh. 01289 std::map<dof_id_type, std::vector<dof_id_type> >::iterator elem_map_it = node_to_elems_map.begin(); 01290 std::map<dof_id_type, std::vector<dof_id_type> >::iterator elem_map_it_end = node_to_elems_map.end(); 01291 for( ; elem_map_it != elem_map_it_end; ++elem_map_it) 01292 { 01293 dof_id_type target_node_id = elem_map_it->first; 01294 dof_id_type other_node_id = node_to_node_map[target_node_id]; 01295 Node& target_node = this->node(target_node_id); 01296 01297 std::size_t n_elems = elem_map_it->second.size(); 01298 for(std::size_t i=0; i<n_elems; i++) 01299 { 01300 dof_id_type elem_id = elem_map_it->second[i]; 01301 Elem* el = this->elem(elem_id); 01302 01303 // find the local node index that we want to update 01304 unsigned int local_node_index = el->local_node(other_node_id); 01305 01306 // We also need to copy over the nodeset info here, 01307 // because the node will get deleted below 01308 const std::vector<boundary_id_type>& ids = 01309 this->get_boundary_info().boundary_ids(el->get_node(local_node_index)); 01310 01311 el->set_node(local_node_index) = &target_node; 01312 01313 this->get_boundary_info().add_node(&target_node, ids); 01314 } 01315 } 01316 01317 std::map<dof_id_type, dof_id_type>::iterator node_map_it = node_to_node_map.begin(); 01318 std::map<dof_id_type, dof_id_type>::iterator node_map_it_end = node_to_node_map.end(); 01319 for( ; node_map_it != node_map_it_end; ++node_map_it) 01320 { 01321 // In the case that this==other_mesh, the two nodes might be the same (e.g. if 01322 // we're stitching a "sliver"), hence we need to skip node deletion in that case. 01323 if ((this == other_mesh) && (node_map_it->second == node_map_it->first)) 01324 continue; 01325 01326 dof_id_type node_id = node_map_it->second; 01327 this->delete_node( this->node_ptr(node_id) ); 01328 } 01329 01330 // If find_neighbors() wasn't called in prepare_for_use(), we need to 01331 // manually loop once more over all elements adjacent to the stitched boundary 01332 // and fix their lists of neighbors. 01333 // This is done according to the following steps: 01334 // 1. Loop over all copied elements adjacent to the boundary using node_to_elems_map (trying to avoid duplicates) 01335 // 2. Look at all their sides with a NULL neighbor and update them using side_to_elem_map if necessary 01336 // 3. Update the corresponding side in side_to_elem_map as well 01337 if(skip_find_neighbors) 01338 { 01339 elem_map_it = node_to_elems_map.begin(); 01340 elem_map_it_end = node_to_elems_map.end(); 01341 std::set<dof_id_type> fixed_elems; 01342 for( ; elem_map_it != elem_map_it_end; ++elem_map_it) 01343 { 01344 std::size_t n_elems = elem_map_it->second.size(); 01345 for(std::size_t i=0; i<n_elems; i++) 01346 { 01347 dof_id_type elem_id = elem_map_it->second[i]; 01348 if(fixed_elems.find(elem_id) == fixed_elems.end()) 01349 { 01350 Elem* el = this->elem(elem_id); 01351 fixed_elems.insert(elem_id); 01352 for(unsigned int s = 0; s < el->n_neighbors(); ++s) 01353 { 01354 if(el->neighbor(s) == NULL) 01355 { 01356 key_type key = el->key(s); 01357 typedef 01358 map_type::iterator key_val_it_type; 01359 std::pair<key_val_it_type, key_val_it_type> 01360 bounds = side_to_elem_map.equal_range(key); 01361 01362 if(bounds.first != bounds.second) 01363 { 01364 // Get the side for this element 01365 const UniquePtr<Elem> my_side(el->side(s)); 01366 01367 // Look at all the entries with an equivalent key 01368 while (bounds.first != bounds.second) 01369 { 01370 // Get the potential element 01371 Elem* neighbor = bounds.first->second.first; 01372 01373 // Get the side for the neighboring element 01374 const unsigned int ns = bounds.first->second.second; 01375 const UniquePtr<Elem> their_side(neighbor->side(ns)); 01376 //libmesh_assert(my_side.get()); 01377 //libmesh_assert(their_side.get()); 01378 01379 // If found a match with my side 01380 // 01381 // We need special tests here for 1D: 01382 // since parents and children have an equal 01383 // side (i.e. a node), we need to check 01384 // ns != ms, and we also check level() to 01385 // avoid setting our neighbor pointer to 01386 // any of our neighbor's descendants 01387 if( (*my_side == *their_side) && 01388 (el->level() == neighbor->level()) && 01389 ((el->dim() != 1) || (ns != s)) ) 01390 { 01391 // So share a side. Is this a mixed pair 01392 // of subactive and active/ancestor 01393 // elements? 01394 // If not, then we're neighbors. 01395 // If so, then the subactive's neighbor is 01396 01397 if (el->subactive() == 01398 neighbor->subactive()) 01399 { 01400 // an element is only subactive if it has 01401 // been coarsened but not deleted 01402 el->set_neighbor (s,neighbor); 01403 neighbor->set_neighbor(ns,el); 01404 } 01405 else if (el->subactive()) 01406 { 01407 el->set_neighbor(s,neighbor); 01408 } 01409 else if (neighbor->subactive()) 01410 { 01411 neighbor->set_neighbor(ns,el); 01412 } 01413 side_to_elem_map.erase (bounds.first); 01414 break; 01415 } 01416 01417 ++bounds.first; 01418 } 01419 } 01420 } 01421 } 01422 } 01423 } 01424 } 01425 } 01426 01427 this->prepare_for_use( /*skip_renumber_nodes_and_elements= */ false, skip_find_neighbors); 01428 01429 // After the stitching, we may want to clear boundary IDs from element 01430 // faces that are now internal to the mesh 01431 if(clear_stitched_boundary_ids) 01432 { 01433 MeshBase::element_iterator elem_it = this->elements_begin(); 01434 MeshBase::element_iterator elem_end = this->elements_end(); 01435 for (; elem_it != elem_end; ++elem_it) 01436 { 01437 Elem *el = *elem_it; 01438 01439 for (unsigned short side_id=0; side_id<el->n_sides(); side_id++) 01440 { 01441 if (el->neighbor(side_id) != NULL) 01442 { 01443 // Completely remove the side from the boundary_info object if it has either 01444 // this_mesh_boundary_id or other_mesh_boundary_id. 01445 std::vector<boundary_id_type> bc_ids = 01446 this->get_boundary_info().boundary_ids (el, side_id); 01447 01448 if (std::count(bc_ids.begin(), bc_ids.end(), this_mesh_boundary_id) || 01449 std::count(bc_ids.begin(), bc_ids.end(), other_mesh_boundary_id)) 01450 this->get_boundary_info().remove_side(el, side_id); 01451 } 01452 } 01453 } 01454 } 01455 01456 } 01457 01458 01459 dof_id_type SerialMesh::n_active_elem () const 01460 { 01461 return static_cast<dof_id_type>(std::distance (this->active_elements_begin(), 01462 this->active_elements_end())); 01463 } 01464 01465 01466 #ifdef LIBMESH_ENABLE_UNIQUE_ID 01467 void SerialMesh::assign_unique_ids() 01468 { 01469 for (dof_id_type i=0; i<_elements.size(); ++i) 01470 if (_elements[i] && ! _elements[i]->valid_unique_id()) 01471 _elements[i]->set_unique_id() = _next_unique_id++; 01472 01473 for (dof_id_type i=0; i<_nodes.size(); ++i) 01474 if (_nodes[i] && ! _nodes[i]->valid_unique_id()) 01475 _nodes[i]->set_unique_id() = _next_unique_id++; 01476 } 01477 #endif 01478 01479 01480 } // namespace libMesh