serial_mesh.C
Go to the documentation of this file.00001 // The libMesh Finite Element Library. 00002 // Copyright (C) 2002-2012 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner 00003 00004 // This library is free software; you can redistribute it and/or 00005 // modify it under the terms of the GNU Lesser General Public 00006 // License as published by the Free Software Foundation; either 00007 // version 2.1 of the License, or (at your option) any later version. 00008 00009 // This library is distributed in the hope that it will be useful, 00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 // Lesser General Public License for more details. 00013 00014 // You should have received a copy of the GNU Lesser General Public 00015 // License along with this library; if not, write to the Free Software 00016 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00017 00018 00019 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 00027 #include LIBMESH_INCLUDE_UNORDERED_SET 00028 LIBMESH_DEFINE_HASH_POINTERS 00029 00030 namespace libMesh 00031 { 00032 00033 // ------------------------------------------------------------ 00034 // SerialMesh class member functions 00035 SerialMesh::SerialMesh (unsigned int d) : 00036 UnstructuredMesh (d) 00037 { 00038 _partitioner = AutoPtr<Partitioner>(new MetisPartitioner()); 00039 } 00040 00041 00042 SerialMesh::~SerialMesh () 00043 { 00044 this->clear(); // Free nodes and elements 00045 } 00046 00047 00048 // This might be specialized later, but right now it's just here to 00049 // make sure the compiler doesn't give us a default (non-deep) copy 00050 // constructor instead. 00051 SerialMesh::SerialMesh (const SerialMesh &other_mesh) : 00052 UnstructuredMesh (other_mesh) 00053 { 00054 this->copy_nodes_and_elements(other_mesh); 00055 *this->boundary_info = *other_mesh.boundary_info; 00056 } 00057 00058 00059 SerialMesh::SerialMesh (const UnstructuredMesh &other_mesh) : 00060 UnstructuredMesh (other_mesh) 00061 { 00062 this->copy_nodes_and_elements(other_mesh); 00063 *this->boundary_info = *other_mesh.boundary_info; 00064 } 00065 00066 00067 const Point& SerialMesh::point (const dof_id_type i) const 00068 { 00069 libmesh_assert_less (i, this->n_nodes()); 00070 libmesh_assert(_nodes[i]); 00071 libmesh_assert_equal_to (_nodes[i]->id(), i); // This will change soon 00072 00073 return (*_nodes[i]); 00074 } 00075 00076 00077 00078 00079 00080 const Node& SerialMesh::node (const dof_id_type i) const 00081 { 00082 libmesh_assert_less (i, this->n_nodes()); 00083 libmesh_assert(_nodes[i]); 00084 libmesh_assert_equal_to (_nodes[i]->id(), i); // This will change soon 00085 00086 return (*_nodes[i]); 00087 } 00088 00089 00090 00091 00092 00093 Node& SerialMesh::node (const dof_id_type i) 00094 { 00095 if (i >= this->n_nodes()) 00096 { 00097 libMesh::out << " i=" << i 00098 << ", n_nodes()=" << this->n_nodes() 00099 << std::endl; 00100 libmesh_error(); 00101 } 00102 00103 libmesh_assert_less (i, this->n_nodes()); 00104 libmesh_assert(_nodes[i]); 00105 libmesh_assert_equal_to (_nodes[i]->id(), i); // This will change soon 00106 00107 return (*_nodes[i]); 00108 } 00109 00110 00111 00112 const Node* SerialMesh::node_ptr (const dof_id_type i) const 00113 { 00114 libmesh_assert_less (i, this->n_nodes()); 00115 libmesh_assert(_nodes[i]); 00116 libmesh_assert_equal_to (_nodes[i]->id(), i); // This will change soon 00117 00118 return _nodes[i]; 00119 } 00120 00121 00122 00123 00124 Node* SerialMesh::node_ptr (const dof_id_type i) 00125 { 00126 libmesh_assert_less (i, this->n_nodes()); 00127 libmesh_assert(_nodes[i]); 00128 libmesh_assert_equal_to (_nodes[i]->id(), i); // This will change soon 00129 00130 return _nodes[i]; 00131 } 00132 00133 00134 00135 00136 const Node* SerialMesh::query_node_ptr (const dof_id_type i) const 00137 { 00138 if (i >= this->n_nodes()) 00139 return NULL; 00140 libmesh_assert (_nodes[i] == NULL || 00141 _nodes[i]->id() == i); // This will change soon 00142 00143 return _nodes[i]; 00144 } 00145 00146 00147 00148 00149 Node* SerialMesh::query_node_ptr (const dof_id_type i) 00150 { 00151 if (i >= this->n_nodes()) 00152 return NULL; 00153 libmesh_assert (_nodes[i] == NULL || 00154 _nodes[i]->id() == i); // This will change soon 00155 00156 return _nodes[i]; 00157 } 00158 00159 00160 00161 00162 const Elem* SerialMesh::elem (const dof_id_type i) const 00163 { 00164 libmesh_assert_less (i, this->n_elem()); 00165 libmesh_assert(_elements[i]); 00166 libmesh_assert_equal_to (_elements[i]->id(), i); // This will change soon 00167 00168 return _elements[i]; 00169 } 00170 00171 00172 00173 00174 Elem* SerialMesh::elem (const dof_id_type i) 00175 { 00176 libmesh_assert_less (i, this->n_elem()); 00177 libmesh_assert(_elements[i]); 00178 libmesh_assert_equal_to (_elements[i]->id(), i); // This will change soon 00179 00180 return _elements[i]; 00181 } 00182 00183 00184 00185 00186 const Elem* SerialMesh::query_elem (const dof_id_type i) const 00187 { 00188 if (i >= this->n_elem()) 00189 return NULL; 00190 libmesh_assert (_elements[i] == NULL || 00191 _elements[i]->id() == i); // This will change soon 00192 00193 return _elements[i]; 00194 } 00195 00196 00197 00198 00199 Elem* SerialMesh::query_elem (const dof_id_type i) 00200 { 00201 if (i >= this->n_elem()) 00202 return NULL; 00203 libmesh_assert (_elements[i] == NULL || 00204 _elements[i]->id() == i); // This will change soon 00205 00206 return _elements[i]; 00207 } 00208 00209 00210 00211 00212 Elem* SerialMesh::add_elem (Elem* e) 00213 { 00214 libmesh_assert(e); 00215 00216 // We no longer merely append elements with SerialMesh 00217 00218 // If the user requests a valid id that doesn't correspond to an 00219 // existing element, let's give them that id, resizing the elements 00220 // container if necessary. 00221 if (!e->valid_id()) 00222 e->set_id (_elements.size()); 00223 00224 const dof_id_type id = e->id(); 00225 00226 if (id < _elements.size()) 00227 { 00228 // Overwriting existing elements is still probably a mistake. 00229 libmesh_assert(!_elements[id]); 00230 } 00231 else 00232 { 00233 _elements.resize(id+1, NULL); 00234 } 00235 00236 _elements[id] = e; 00237 00238 return e; 00239 } 00240 00241 00242 00243 Elem* SerialMesh::insert_elem (Elem* e) 00244 { 00245 dof_id_type eid = e->id(); 00246 libmesh_assert_less (eid, _elements.size()); 00247 Elem *oldelem = _elements[eid]; 00248 00249 if (oldelem) 00250 { 00251 libmesh_assert_equal_to (oldelem->id(), eid); 00252 this->delete_elem(oldelem); 00253 } 00254 00255 _elements[e->id()] = e; 00256 00257 return e; 00258 } 00259 00260 00261 00262 void SerialMesh::delete_elem(Elem* e) 00263 { 00264 libmesh_assert(e); 00265 00266 // Initialize an iterator to eventually point to the element we want to delete 00267 std::vector<Elem*>::iterator pos = _elements.end(); 00268 00269 // In many cases, e->id() gives us a clue as to where e 00270 // is located in the _elements vector. Try that first 00271 // before trying the O(n_elem) search. 00272 libmesh_assert_less (e->id(), _elements.size()); 00273 00274 if (_elements[e->id()] == e) 00275 { 00276 // We found it! 00277 pos = _elements.begin(); 00278 std::advance(pos, e->id()); 00279 } 00280 00281 else 00282 { 00283 // This search is O(n_elem) 00284 pos = std::find (_elements.begin(), 00285 _elements.end(), 00286 e); 00287 } 00288 00289 // Huh? Element not in the vector? 00290 libmesh_assert (pos != _elements.end()); 00291 00292 // Remove the element from the BoundaryInfo object 00293 this->boundary_info->remove(e); 00294 00295 // delete the element 00296 delete e; 00297 00298 // explicitly NULL the pointer 00299 *pos = NULL; 00300 } 00301 00302 00303 00304 void SerialMesh::renumber_elem(const dof_id_type old_id, 00305 const dof_id_type new_id) 00306 { 00307 // This doesn't get used in serial yet 00308 Elem *el = _elements[old_id]; 00309 libmesh_assert (el); 00310 00311 el->set_id(new_id); 00312 libmesh_assert (!_elements[new_id]); 00313 _elements[new_id] = el; 00314 _elements[old_id] = NULL; 00315 } 00316 00317 00318 00319 Node* SerialMesh::add_point (const Point& p, 00320 const dof_id_type id, 00321 const processor_id_type proc_id) 00322 { 00323 // // We only append points with SerialMesh 00324 // libmesh_assert(id == DofObject::invalid_id || id == _nodes.size()); 00325 // Node *n = Node::build(p, _nodes.size()).release(); 00326 // n->processor_id() = proc_id; 00327 // _nodes.push_back (n); 00328 00329 Node *n = NULL; 00330 00331 // If the user requests a valid id, either 00332 // provide the existing node or resize the container 00333 // to fit the new node. 00334 if (id != DofObject::invalid_id) 00335 if (id < _nodes.size()) 00336 n = _nodes[id]; 00337 else 00338 _nodes.resize(id+1); 00339 else 00340 _nodes.push_back (static_cast<Node*>(NULL)); 00341 00342 // if the node already exists, then assign new (x,y,z) values 00343 if (n) 00344 *n = p; 00345 // otherwise build a new node, put it in the right spot, and return 00346 // a valid pointer. 00347 else 00348 { 00349 n = Node::build(p, (id == DofObject::invalid_id) ? _nodes.size()-1 : id).release(); 00350 n->processor_id() = proc_id; 00351 00352 if (id == DofObject::invalid_id) 00353 _nodes.back() = n; 00354 else 00355 _nodes[id] = n; 00356 } 00357 00358 // better not pass back a NULL pointer. 00359 libmesh_assert (n); 00360 00361 return n; 00362 } 00363 00364 00365 00366 Node* SerialMesh::add_node (Node* n) 00367 { 00368 libmesh_assert(n); 00369 // We only append points with SerialMesh 00370 libmesh_assert(!n->valid_id() || n->id() == _nodes.size()); 00371 00372 n->set_id (_nodes.size()); 00373 00374 _nodes.push_back(n); 00375 00376 return n; 00377 } 00378 00379 00380 00381 void SerialMesh::delete_node(Node* n) 00382 { 00383 libmesh_assert(n); 00384 libmesh_assert_less (n->id(), _nodes.size()); 00385 00386 // Initialize an iterator to eventually point to the element we want 00387 // to delete 00388 std::vector<Node*>::iterator pos; 00389 00390 // In many cases, e->id() gives us a clue as to where e 00391 // is located in the _elements vector. Try that first 00392 // before trying the O(n_elem) search. 00393 if (_nodes[n->id()] == n) 00394 { 00395 pos = _nodes.begin(); 00396 std::advance(pos, n->id()); 00397 } 00398 else 00399 { 00400 pos = std::find (_nodes.begin(), 00401 _nodes.end(), 00402 n); 00403 } 00404 00405 // Huh? Node not in the vector? 00406 libmesh_assert (pos != _nodes.end()); 00407 00408 // Delete the node from the BoundaryInfo object 00409 this->boundary_info->remove(n); 00410 00411 // delete the node 00412 delete n; 00413 00414 // explicitly NULL the pointer 00415 *pos = NULL; 00416 } 00417 00418 00419 00420 void SerialMesh::renumber_node(const dof_id_type old_id, 00421 const dof_id_type new_id) 00422 { 00423 // This doesn't get used in serial yet 00424 Node *nd = _nodes[old_id]; 00425 libmesh_assert (nd); 00426 00427 nd->set_id(new_id); 00428 libmesh_assert (!_nodes[new_id]); 00429 _nodes[new_id] = nd; 00430 _nodes[old_id] = NULL; 00431 } 00432 00433 00434 00435 void SerialMesh::clear () 00436 { 00437 // Call parent clear function 00438 MeshBase::clear(); 00439 00440 00441 // Clear our elements and nodes 00442 { 00443 std::vector<Elem*>::iterator it = _elements.begin(); 00444 const std::vector<Elem*>::iterator end = _elements.end(); 00445 00446 // There is no need to remove the elements from 00447 // the BoundaryInfo data structure since we 00448 // already cleared it. 00449 for (; it != end; ++it) 00450 delete *it; 00451 00452 _elements.clear(); 00453 } 00454 00455 // clear the nodes data structure 00456 { 00457 std::vector<Node*>::iterator it = _nodes.begin(); 00458 const std::vector<Node*>::iterator end = _nodes.end(); 00459 00460 // There is no need to remove the nodes from 00461 // the BoundaryInfo data structure since we 00462 // already cleared it. 00463 for (; it != end; ++it) 00464 delete *it; 00465 00466 _nodes.clear(); 00467 } 00468 } 00469 00470 00471 00472 void SerialMesh::renumber_nodes_and_elements () 00473 { 00474 00475 START_LOG("renumber_nodes_and_elem()", "Mesh"); 00476 00477 // node and element id counters 00478 dof_id_type next_free_elem = 0; 00479 dof_id_type next_free_node = 0; 00480 00481 // Will hold the set of nodes that are currently connected to elements 00482 LIBMESH_BEST_UNORDERED_SET<Node*> connected_nodes; 00483 00484 // Loop over the elements. Note that there may 00485 // be NULLs in the _elements vector from the coarsening 00486 // process. Pack the elements in to a contiguous array 00487 // and then trim any excess. 00488 { 00489 std::vector<Elem*>::iterator in = _elements.begin(); 00490 std::vector<Elem*>::iterator out_iter = _elements.begin(); 00491 const std::vector<Elem*>::iterator end = _elements.end(); 00492 00493 for (; in != end; ++in) 00494 if (*in != NULL) 00495 { 00496 Elem* el = *in; 00497 00498 *out_iter = *in; 00499 ++out_iter; 00500 00501 // Increment the element counter 00502 el->set_id (next_free_elem++); 00503 00504 if(_skip_renumber_nodes_and_elements) 00505 { 00506 // Add this elements nodes to the connected list 00507 for (unsigned int n=0; n<el->n_nodes(); n++) 00508 connected_nodes.insert(el->get_node(n)); 00509 } 00510 else // We DO want node renumbering 00511 { 00512 // Loop over this element's nodes. Number them, 00513 // if they have not been numbered already. Also, 00514 // position them in the _nodes vector so that they 00515 // are packed contiguously from the beginning. 00516 for (unsigned int n=0; n<el->n_nodes(); n++) 00517 if (el->node(n) == next_free_node) // don't need to process 00518 next_free_node++; // [(src == dst) below] 00519 00520 else if (el->node(n) > next_free_node) // need to process 00521 { 00522 // The source and destination indices 00523 // for this node 00524 const dof_id_type src_idx = el->node(n); 00525 const dof_id_type dst_idx = next_free_node++; 00526 00527 // ensure we want to swap a valid nodes 00528 libmesh_assert(_nodes[src_idx]); 00529 00530 // Swap the source and destination nodes 00531 std::swap(_nodes[src_idx], 00532 _nodes[dst_idx] ); 00533 00534 // Set proper indices where that makes sense 00535 if (_nodes[src_idx] != NULL) 00536 _nodes[src_idx]->set_id (src_idx); 00537 _nodes[dst_idx]->set_id (dst_idx); 00538 } 00539 } 00540 } 00541 00542 // Erase any additional storage. These elements have been 00543 // copied into NULL voids by the procedure above, and are 00544 // thus repeated and unnecessary. 00545 _elements.erase (out_iter, end); 00546 } 00547 00548 00549 if(_skip_renumber_nodes_and_elements) 00550 { 00551 // Loop over the nodes. Note that there may 00552 // be NULLs in the _nodes vector from the coarsening 00553 // process. Pack the nodes in to a contiguous array 00554 // and then trim any excess. 00555 00556 std::vector<Node*>::iterator in = _nodes.begin(); 00557 std::vector<Node*>::iterator out_iter = _nodes.begin(); 00558 const std::vector<Node*>::iterator end = _nodes.end(); 00559 00560 for (; in != end; ++in) 00561 if (*in != NULL) 00562 { 00563 // This is a reference so that if we change the pointer it will change in the vector 00564 Node* & nd = *in; 00565 00566 // If this node is still connected to an elem, put it in the list 00567 if(connected_nodes.find(nd) != connected_nodes.end()) 00568 { 00569 *out_iter = nd; 00570 ++out_iter; 00571 00572 // Increment the node counter 00573 nd->set_id (next_free_node++); 00574 } 00575 else // This node is orphaned, delete it! 00576 { 00577 this->boundary_info->remove (nd); 00578 00579 // delete the node 00580 delete nd; 00581 nd = NULL; 00582 } 00583 } 00584 00585 // Erase any additional storage. Whatever was 00586 _nodes.erase (out_iter, end); 00587 } 00588 else // We really DO want node renumbering 00589 { 00590 // Any nodes in the vector >= _nodes[next_free_node] 00591 // are not connected to any elements and may be deleted 00592 // if desired. 00593 00594 // (This code block will erase the unused nodes) 00595 // Now, delete the unused nodes 00596 { 00597 std::vector<Node*>::iterator nd = _nodes.begin(); 00598 const std::vector<Node*>::iterator end = _nodes.end(); 00599 00600 std::advance (nd, next_free_node); 00601 00602 for (std::vector<Node*>::iterator it=nd; 00603 it != end; ++it) 00604 { 00605 // Mesh modification code might have already deleted some 00606 // nodes 00607 if (*it == NULL) 00608 continue; 00609 00610 // remove any boundary information associated with 00611 // this node 00612 this->boundary_info->remove (*it); 00613 00614 // delete the node 00615 delete *it; 00616 *it = NULL; 00617 } 00618 00619 _nodes.erase (nd, end); 00620 } 00621 } 00622 00623 libmesh_assert_equal_to (next_free_elem, _elements.size()); 00624 libmesh_assert_equal_to (next_free_node, _nodes.size()); 00625 00626 STOP_LOG("renumber_nodes_and_elem()", "Mesh"); 00627 } 00628 00629 00630 00631 void SerialMesh::fix_broken_node_and_element_numbering () 00632 { 00633 // Nodes first 00634 for (dof_id_type n=0; n<this->_nodes.size(); n++) 00635 if (this->_nodes[n] != NULL) 00636 this->_nodes[n]->set_id() = n; 00637 00638 // Elements next 00639 for (dof_id_type e=0; e<this->_elements.size(); e++) 00640 if (this->_elements[e] != NULL) 00641 this->_elements[e]->set_id() = e; 00642 } 00643 00644 00645 void SerialMesh::stitch_meshes (SerialMesh& other_mesh, 00646 boundary_id_type this_mesh_boundary_id, 00647 boundary_id_type other_mesh_boundary_id, 00648 Real tol, 00649 bool clear_stitched_boundary_ids, 00650 bool verbose) 00651 { 00652 std::map<dof_id_type, dof_id_type> node_to_node_map; 00653 std::map<dof_id_type, std::vector<dof_id_type> > node_to_elems_map; 00654 00655 if( (this_mesh_boundary_id != BoundaryInfo::invalid_id) && 00656 (other_mesh_boundary_id != BoundaryInfo::invalid_id) ) 00657 { 00658 std::set<dof_id_type> this_boundary_node_ids; 00659 MeshBase::element_iterator elem_it = this->elements_begin(); 00660 MeshBase::element_iterator elem_end = this->elements_end(); 00661 for ( ; elem_it != elem_end; ++elem_it) 00662 { 00663 Elem *el = *elem_it; 00664 00665 // Now check whether elem has a face on the specified boundary 00666 for (unsigned int side_id=0; side_id<el->n_sides(); side_id++) 00667 if (el->neighbor(side_id) == NULL) 00668 { 00669 boundary_id_type bc_id = this->boundary_info->boundary_id (el, side_id); 00670 00671 if(bc_id == this_mesh_boundary_id) 00672 { 00673 AutoPtr<Elem> side (el->build_side(side_id)); 00674 for (unsigned int node_id=0; node_id<side->n_nodes(); node_id++) 00675 { 00676 this_boundary_node_ids.insert( side->node(node_id) ); 00677 } 00678 } 00679 } 00680 } 00681 00682 std::set<dof_id_type> other_boundary_node_ids; 00683 elem_it = other_mesh.elements_begin(); 00684 elem_end = other_mesh.elements_end(); 00685 for ( ; elem_it != elem_end; ++elem_it) 00686 { 00687 Elem *el = *elem_it; 00688 00689 // Now check whether elem has a face on the specified boundary 00690 for (unsigned int side_id=0; side_id<el->n_sides(); side_id++) 00691 if (el->neighbor(side_id) == NULL) 00692 { 00693 boundary_id_type bc_id = other_mesh.boundary_info->boundary_id (el, side_id); 00694 00695 if(bc_id == other_mesh_boundary_id) 00696 { 00697 AutoPtr<Elem> side (el->build_side(side_id)); 00698 for (unsigned int node_id=0; node_id<side->n_nodes(); node_id++) 00699 { 00700 other_boundary_node_ids.insert( side->node(node_id) ); 00701 } 00702 } 00703 } 00704 } 00705 00706 std::set<dof_id_type>::iterator set_it = this_boundary_node_ids.begin(); 00707 std::set<dof_id_type>::iterator set_it_end = this_boundary_node_ids.end(); 00708 for( ; set_it != set_it_end; ++set_it) 00709 { 00710 dof_id_type this_node_id = *set_it; 00711 Node& this_node = this->node(this_node_id); 00712 00713 bool found_matching_nodes = false; 00714 00715 std::set<dof_id_type>::iterator other_set_it = other_boundary_node_ids.begin(); 00716 std::set<dof_id_type>::iterator other_set_it_end = other_boundary_node_ids.end(); 00717 for( ; other_set_it != other_set_it_end; ++other_set_it) 00718 { 00719 dof_id_type other_node_id = *other_set_it; 00720 Node& other_node = other_mesh.node(other_node_id); 00721 00722 Real node_distance = (this_node - other_node).size(); 00723 00724 if(node_distance < tol) 00725 { 00726 // Make sure we didn't already find a matching node! 00727 if(found_matching_nodes) 00728 { 00729 libMesh::out << "Error: Found multiple matching nodes in stitch_meshes" << std::endl; 00730 libmesh_error(); 00731 } 00732 00733 node_to_node_map[this_node_id] = other_node_id; 00734 00735 // Build a vector of all the elements in other_mesh that contain other_node 00736 std::vector<dof_id_type> other_elem_ids; 00737 MeshBase::element_iterator other_elem_it = other_mesh.elements_begin(); 00738 MeshBase::element_iterator other_elem_end = other_mesh.elements_end(); 00739 for (; other_elem_it != other_elem_end; ++other_elem_it) 00740 { 00741 Elem *el = *other_elem_it; 00742 00743 if(el->contains_point(other_node)) 00744 other_elem_ids.push_back(el->id()); 00745 } 00746 00747 node_to_elems_map[this_node_id] = other_elem_ids; 00748 00749 found_matching_nodes = true; 00750 } 00751 } 00752 } 00753 00754 if(verbose) 00755 { 00756 libMesh::out << "In SerialMesh::stitch_meshes:" << std::endl 00757 << "This mesh has " << this_boundary_node_ids.size() << " nodes on specified boundary" << std::endl 00758 << "Other mesh has " << other_boundary_node_ids.size() << " nodes on specified boundary" << std::endl 00759 << "Found " << node_to_node_map.size() << " matching nodes." << std::endl << std::endl; 00760 } 00761 } 00762 else 00763 { 00764 if(verbose) 00765 { 00766 libMesh::out << "Skip node merging in SerialMesh::stitch_meshes:" << std::endl; 00767 } 00768 } 00769 00770 00771 00772 dof_id_type node_delta = this->n_nodes(); 00773 dof_id_type elem_delta = this->n_elem(); 00774 00775 // need to increment node and element IDs of other_mesh before copying to this mesh 00776 MeshBase::node_iterator node_it = other_mesh.nodes_begin(); 00777 MeshBase::node_iterator node_end = other_mesh.nodes_end(); 00778 for (; node_it != node_end; ++node_it) 00779 { 00780 Node *nd = *node_it; 00781 dof_id_type new_id = nd->id() + node_delta; 00782 nd->set_id(new_id); 00783 } 00784 00785 MeshBase::element_iterator elem_it = other_mesh.elements_begin(); 00786 MeshBase::element_iterator elem_end = other_mesh.elements_end(); 00787 for (; elem_it != elem_end; ++elem_it) 00788 { 00789 Elem *el = *elem_it; 00790 dof_id_type new_id = el->id() + elem_delta; 00791 el->set_id(new_id); 00792 } 00793 00794 // Also, increment the node_to_node_map and node_to_elems_map 00795 std::map<dof_id_type, dof_id_type>::iterator node_map_it = node_to_node_map.begin(); 00796 std::map<dof_id_type, dof_id_type>::iterator node_map_it_end = node_to_node_map.end(); 00797 for( ; node_map_it != node_map_it_end; ++node_map_it) 00798 { 00799 node_map_it->second += node_delta; 00800 } 00801 std::map<dof_id_type, std::vector<dof_id_type> >::iterator elem_map_it = node_to_elems_map.begin(); 00802 std::map<dof_id_type, std::vector<dof_id_type> >::iterator elem_map_it_end = node_to_elems_map.end(); 00803 for( ; elem_map_it != elem_map_it_end; ++elem_map_it) 00804 { 00805 dof_id_type n_elems = elem_map_it->second.size(); 00806 for(dof_id_type i=0; i<n_elems; i++) 00807 { 00808 (elem_map_it->second)[i] += elem_delta; 00809 } 00810 } 00811 00812 // Copy mesh data 00813 this->copy_nodes_and_elements(other_mesh); 00814 00815 // then decrement node and element IDs of mesh_i to return to original state 00816 node_it = other_mesh.nodes_begin(); 00817 node_end = other_mesh.nodes_end(); 00818 for (; node_it != node_end; ++node_it) 00819 { 00820 Node *nd = *node_it; 00821 dof_id_type new_id = nd->id() - node_delta; 00822 nd->set_id(new_id); 00823 } 00824 00825 elem_it = other_mesh.elements_begin(); 00826 elem_end = other_mesh.elements_end(); 00827 for (; elem_it != elem_end; ++elem_it) 00828 { 00829 Elem *el = *elem_it; 00830 00831 // First copy boundary info to the stitched mesh 00832 for (unsigned int side_id=0; side_id<el->n_sides(); side_id++) 00833 if (el->neighbor(side_id) == NULL) 00834 { 00835 boundary_id_type bc_id = other_mesh.boundary_info->boundary_id (el, side_id); 00836 00837 if(bc_id != BoundaryInfo::invalid_id) 00838 { 00839 this->boundary_info->add_side(el->id(), side_id, bc_id); 00840 } 00841 } 00842 00843 // Then decrement 00844 dof_id_type new_id = el->id() - elem_delta; 00845 el->set_id(new_id); 00846 } 00847 00848 // Finally, we need to "merge" the overlapping nodes 00849 // We do this by iterating over node_to_elems_map and updating 00850 // the elements so that they "point" to the nodes that came 00851 // from this mesh, rather than from other_mesh. 00852 // Then we iterate over node_to_node_map and delete the 00853 // duplicate nodes that came from other_mesh. 00854 elem_map_it = node_to_elems_map.begin(); 00855 elem_map_it_end = node_to_elems_map.end(); 00856 for( ; elem_map_it != elem_map_it_end; ++elem_map_it) 00857 { 00858 dof_id_type target_node_id = elem_map_it->first; 00859 dof_id_type other_node_id = node_to_node_map[target_node_id]; 00860 Node& target_node = this->node(target_node_id); 00861 00862 dof_id_type n_elems = elem_map_it->second.size(); 00863 for(unsigned int i=0; i<n_elems; i++) 00864 { 00865 dof_id_type elem_id = elem_map_it->second[i]; 00866 Elem* el = this->elem(elem_id); 00867 00868 // find the local node index that we want to update 00869 unsigned int local_node_index = el->local_node(other_node_id); 00870 00871 el->set_node(local_node_index) = &target_node; 00872 } 00873 } 00874 00875 node_map_it = node_to_node_map.begin(); 00876 node_map_it_end = node_to_node_map.end(); 00877 for( ; node_map_it != node_map_it_end; ++node_map_it) 00878 { 00879 dof_id_type node_id = node_map_it->second; 00880 this->delete_node( this->node_ptr(node_id) ); 00881 } 00882 00883 this->prepare_for_use( /*skip_renumber_nodes_and_elements= */ false); 00884 00885 // After the stitching, we may want to clear boundary IDs from element 00886 // faces that are now internal to the mesh 00887 if(clear_stitched_boundary_ids) 00888 { 00889 elem_it = this->elements_begin(); 00890 elem_end = this->elements_end(); 00891 for (; elem_it != elem_end; ++elem_it) 00892 { 00893 Elem *el = *elem_it; 00894 00895 for (unsigned int side_id=0; side_id<el->n_sides(); side_id++) 00896 { 00897 if (el->neighbor(side_id) != NULL) 00898 { 00899 boundary_id_type bc_id = this->boundary_info->boundary_id (el, side_id); 00900 00901 if( (bc_id == this_mesh_boundary_id) || 00902 (bc_id == other_mesh_boundary_id) ) 00903 { 00904 this->boundary_info->remove_side(el, side_id); 00905 } 00906 } 00907 } 00908 } 00909 } 00910 00911 } 00912 00913 00914 dof_id_type SerialMesh::n_active_elem () const 00915 { 00916 return static_cast<dof_id_type>(std::distance (this->active_elements_begin(), 00917 this->active_elements_end())); 00918 } 00919 00920 } // namespace libMesh
Site Created By: libMesh Developers
Last modified: February 05 2013 19:54:48 UTC
Hosted By: