$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 <set> 00022 00023 // Local includes 00024 #include "libmesh/libmesh_config.h" 00025 #include "libmesh/tree_node.h" 00026 #include "libmesh/mesh_base.h" 00027 #include "libmesh/elem.h" 00028 00029 namespace libMesh 00030 { 00031 00032 // ------------------------------------------------------------ 00033 // TreeNode class methods 00034 template <unsigned int N> 00035 bool TreeNode<N>::insert (const Node* nd) 00036 { 00037 libmesh_assert(nd); 00038 libmesh_assert_less (nd->id(), mesh.n_nodes()); 00039 00040 // Return if we don't bound the node 00041 if (!this->bounds_node(nd)) 00042 return false; 00043 00044 // Add the node to ourself if we are active 00045 if (this->active()) 00046 { 00047 nodes.push_back (nd); 00048 00049 // Refine ourself if we reach the target bin size for a TreeNode. 00050 if (nodes.size() == tgt_bin_size) 00051 this->refine(); 00052 00053 return true; 00054 } 00055 00056 // If we are not active simply pass the node along to 00057 // our children 00058 libmesh_assert_equal_to (children.size(), N); 00059 00060 bool was_inserted = false; 00061 for (unsigned int c=0; c<N; c++) 00062 if (children[c]->insert (nd)) 00063 was_inserted = true; 00064 return was_inserted; 00065 } 00066 00067 00068 00069 template <unsigned int N> 00070 bool TreeNode<N>::insert (const Elem* elem) 00071 { 00072 libmesh_assert(elem); 00073 00074 // We first want to find the corners of the cuboid surrounding the cell. 00075 Point min_coord = elem->point(0); 00076 Point max_coord = min_coord; 00077 for (unsigned i=1; i<elem->n_nodes(); ++i) 00078 { 00079 Point p = elem->point(i); 00080 00081 // LIBMESH_DIM gives the number of non-zero components in a Point 00082 for (unsigned d=0; d<LIBMESH_DIM; ++d) 00083 { 00084 if (min_coord(d) > p(d)) 00085 min_coord(d) = p(d); 00086 00087 if (max_coord(d) < p(d)) 00088 max_coord(d) = p(d); 00089 } 00090 } 00091 00092 // Next, find out whether this cuboid has got non-empty intersection 00093 // with the bounding box of the current tree node. 00094 bool intersects = true; 00095 00096 // LIBMESH_DIM gives the number of non-zero components in a Point 00097 for (unsigned int d=0; d<LIBMESH_DIM; d++) 00098 { 00099 if (max_coord(d) < this->bounding_box.first(d) || min_coord(d) > this->bounding_box.second(d)) 00100 intersects = false; 00101 } 00102 00103 // If not, we should not care about this element. 00104 if (!intersects) 00105 return false; 00106 00107 // Only add the element if we are active 00108 if (this->active()) 00109 { 00110 elements.push_back (elem); 00111 00112 #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS 00113 00114 // flag indicating this node contains 00115 // infinite elements 00116 if (elem->infinite()) 00117 this->contains_ifems = true; 00118 00119 #endif 00120 00121 // Refine ourself if we reach the target bin size for a TreeNode. 00122 if (elements.size() == tgt_bin_size) 00123 this->refine(); 00124 00125 return true; 00126 } 00127 00128 // If we are not active simply pass the element along to 00129 // our children 00130 libmesh_assert_equal_to (children.size(), N); 00131 00132 bool was_inserted = false; 00133 for (unsigned int c=0; c<N; c++) 00134 if (children[c]->insert (elem)) 00135 was_inserted = true; 00136 return was_inserted; 00137 } 00138 00139 00140 00141 template <unsigned int N> 00142 void TreeNode<N>::refine () 00143 { 00144 // Huh? better be active... 00145 libmesh_assert (this->active()); 00146 libmesh_assert (children.empty()); 00147 00148 // A TreeNode<N> has by definition N children 00149 children.resize(N); 00150 00151 for (unsigned int c=0; c<N; c++) 00152 { 00153 // Create the child and set its bounding box. 00154 children[c] = new TreeNode<N> (mesh, tgt_bin_size, this); 00155 children[c]->set_bounding_box(this->create_bounding_box(c)); 00156 00157 // Pass off our nodes to our children 00158 for (unsigned int n=0; n<nodes.size(); n++) 00159 children[c]->insert(nodes[n]); 00160 00161 // Pass off our elements to our children 00162 for (unsigned int e=0; e<elements.size(); e++) 00163 children[c]->insert(elements[e]); 00164 } 00165 00166 // We don't need to store nodes or elements any more, they have been 00167 // added to the children. Use the "swap trick" to actually reduce 00168 // the capacity of these vectors. 00169 std::vector<const Node*>().swap(nodes); 00170 std::vector<const Elem*>().swap(elements); 00171 00172 libmesh_assert_equal_to (nodes.capacity(), 0); 00173 libmesh_assert_equal_to (elements.capacity(), 0); 00174 } 00175 00176 00177 00178 template <unsigned int N> 00179 void TreeNode<N>::set_bounding_box (const std::pair<Point, Point>& bbox) 00180 { 00181 bounding_box = bbox; 00182 } 00183 00184 00185 00186 template <unsigned int N> 00187 bool TreeNode<N>::bounds_node (const Node* nd, 00188 Real relative_tol) const 00189 { 00190 libmesh_assert(nd); 00191 return bounds_point(*nd, relative_tol); 00192 } 00193 00194 00195 00196 template <unsigned int N> 00197 bool TreeNode<N>::bounds_point (const Point& p, 00198 Real relative_tol) const 00199 { 00200 const Point& min = bounding_box.first; 00201 const Point& max = bounding_box.second; 00202 00203 const Real tol = (max - min).size() * relative_tol; 00204 00205 if ((p(0) >= min(0) - tol) 00206 && (p(0) <= max(0) + tol) 00207 #if LIBMESH_DIM > 1 00208 && (p(1) >= min(1) - tol) 00209 && (p(1) <= max(1) + tol) 00210 #endif 00211 #if LIBMESH_DIM > 2 00212 && (p(2) >= min(2) - tol) 00213 && (p(2) <= max(2) + tol) 00214 #endif 00215 ) 00216 return true; 00217 00218 return false; 00219 } 00220 00221 00222 00223 template <unsigned int N> 00224 std::pair<Point, Point> 00225 TreeNode<N>::create_bounding_box (unsigned int c) const 00226 { 00227 switch (N) 00228 { 00229 // How to refine an OctTree Node 00230 case 8: 00231 { 00232 const Real xmin = bounding_box.first(0); 00233 const Real ymin = bounding_box.first(1); 00234 const Real zmin = bounding_box.first(2); 00235 00236 const Real xmax = bounding_box.second(0); 00237 const Real ymax = bounding_box.second(1); 00238 const Real zmax = bounding_box.second(2); 00239 00240 const Real xc = .5*(xmin + xmax); 00241 const Real yc = .5*(ymin + ymax); 00242 const Real zc = .5*(zmin + zmax); 00243 00244 switch (c) 00245 { 00246 case 0: 00247 return std::make_pair (Point(xmin, ymin, zmin), 00248 Point(xc, yc, zc)); 00249 case 1: 00250 return std::make_pair (Point(xc, ymin, zmin), 00251 Point(xmax, yc, zc)); 00252 case 2: 00253 return std::make_pair (Point(xmin, yc, zmin), 00254 Point(xc, ymax, zc)); 00255 case 3: 00256 return std::make_pair (Point(xc, yc, zmin), 00257 Point(xmax, ymax, zc)); 00258 case 4: 00259 return std::make_pair (Point(xmin, ymin, zc), 00260 Point(xc, yc, zmax)); 00261 case 5: 00262 return std::make_pair (Point(xc, ymin, zc), 00263 Point(xmax, yc, zmax)); 00264 case 6: 00265 return std::make_pair (Point(xmin, yc, zc), 00266 Point(xc, ymax, zmax)); 00267 case 7: 00268 return std::make_pair (Point(xc, yc, zc), 00269 Point(xmax, ymax, zmax)); 00270 default: 00271 libmesh_error_msg("c >= N! : " << c); 00272 } 00273 00274 break; 00275 } // case 8 00276 00277 // How to refine an QuadTree Node 00278 case 4: 00279 { 00280 const Real xmin = bounding_box.first(0); 00281 const Real ymin = bounding_box.first(1); 00282 00283 const Real xmax = bounding_box.second(0); 00284 const Real ymax = bounding_box.second(1); 00285 00286 const Real xc = .5*(xmin + xmax); 00287 const Real yc = .5*(ymin + ymax); 00288 00289 switch (c) 00290 { 00291 case 0: 00292 return std::make_pair (Point(xmin, ymin), 00293 Point(xc, yc)); 00294 case 1: 00295 return std::make_pair (Point(xc, ymin), 00296 Point(xmax, yc)); 00297 case 2: 00298 return std::make_pair (Point(xmin, yc), 00299 Point(xc, ymax)); 00300 case 3: 00301 return std::make_pair (Point(xc, yc), 00302 Point(xmax, ymax)); 00303 default: 00304 libmesh_error_msg("c >= N!"); 00305 } 00306 00307 break; 00308 } // case 4 00309 00310 // How to refine a BinaryTree Node 00311 case 2: 00312 { 00313 const Real xmin = bounding_box.first(0); 00314 00315 const Real xmax = bounding_box.second(0); 00316 00317 const Real xc = .5*(xmin + xmax); 00318 00319 switch (c) 00320 { 00321 case 0: 00322 return std::make_pair (Point(xmin), 00323 Point(xc)); 00324 case 1: 00325 return std::make_pair (Point(xc), 00326 Point(xmax)); 00327 default: 00328 libmesh_error_msg("c >= N!"); 00329 } 00330 00331 break; 00332 } // case 2 00333 00334 default: 00335 libmesh_error_msg("Only implemented for Octrees, QuadTrees, and Binary Trees!"); 00336 } 00337 00338 libmesh_error_msg("We'll never get here!"); 00339 Point min, max; 00340 return std::make_pair (min, max); 00341 } 00342 00343 00344 00345 template <unsigned int N> 00346 void TreeNode<N>::print_nodes(std::ostream& out_stream) const 00347 { 00348 if (this->active()) 00349 { 00350 out_stream << "TreeNode Level: " << this->level() << std::endl; 00351 00352 for (unsigned int n=0; n<nodes.size(); n++) 00353 out_stream << " " << nodes[n]->id(); 00354 00355 out_stream << std::endl << std::endl; 00356 } 00357 else 00358 { 00359 for (unsigned int child=0; child<children.size(); child++) 00360 children[child]->print_nodes(); 00361 } 00362 } 00363 00364 00365 00366 template <unsigned int N> 00367 void TreeNode<N>::print_elements(std::ostream& out_stream) const 00368 { 00369 if (this->active()) 00370 { 00371 out_stream << "TreeNode Level: " << this->level() << std::endl; 00372 00373 for (std::vector<const Elem*>::const_iterator pos=elements.begin(); 00374 pos != elements.end(); ++pos) 00375 out_stream << " " << *pos; 00376 00377 out_stream << std::endl << std::endl; 00378 } 00379 else 00380 { 00381 for (unsigned int child=0; child<children.size(); child++) 00382 children[child]->print_elements(); 00383 } 00384 } 00385 00386 00387 00388 template <unsigned int N> 00389 void TreeNode<N>::transform_nodes_to_elements (std::vector<std::vector<const Elem*> >& nodes_to_elem) 00390 { 00391 if (this->active()) 00392 { 00393 elements.clear(); 00394 00395 // Temporarily use a set. Since multiple nodes 00396 // will likely map to the same element we use a 00397 // set to eliminate the duplication. 00398 std::set<const Elem*> elements_set; 00399 00400 for (unsigned int n=0; n<nodes.size(); n++) 00401 { 00402 // the actual global node number we are replacing 00403 // with the connected elements 00404 const dof_id_type node_number = nodes[n]->id(); 00405 00406 libmesh_assert_less (node_number, mesh.n_nodes()); 00407 libmesh_assert_less (node_number, nodes_to_elem.size()); 00408 00409 for (unsigned int e=0; e<nodes_to_elem[node_number].size(); e++) 00410 elements_set.insert(nodes_to_elem[node_number][e]); 00411 } 00412 00413 // Done with the nodes. 00414 std::vector<const Node*>().swap(nodes); 00415 00416 // Now the set is built. We can copy this to the 00417 // vector. Note that the resulting vector will 00418 // already be sorted, and will require less memory 00419 // than the set. 00420 elements.reserve(elements_set.size()); 00421 00422 for (std::set<const Elem*>::iterator pos=elements_set.begin(); 00423 pos != elements_set.end(); ++pos) 00424 { 00425 elements.push_back(*pos); 00426 00427 #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS 00428 00429 // flag indicating this node contains 00430 // infinite elements 00431 if ((*pos)->infinite()) 00432 this->contains_ifems = true; 00433 00434 #endif 00435 } 00436 } 00437 else 00438 { 00439 for (unsigned int child=0; child<children.size(); child++) 00440 children[child]->transform_nodes_to_elements (nodes_to_elem); 00441 } 00442 00443 } 00444 00445 00446 00447 template <unsigned int N> 00448 unsigned int TreeNode<N>::n_active_bins() const 00449 { 00450 if (this->active()) 00451 return 1; 00452 00453 else 00454 { 00455 unsigned int sum=0; 00456 00457 for (unsigned int c=0; c<children.size(); c++) 00458 sum += children[c]->n_active_bins(); 00459 00460 return sum; 00461 } 00462 } 00463 00464 00465 00466 template <unsigned int N> 00467 const Elem* 00468 TreeNode<N>::find_element 00469 (const Point& p, 00470 const std::set<subdomain_id_type> *allowed_subdomains, 00471 Real relative_tol) const 00472 { 00473 if (this->active()) 00474 { 00475 // Only check our children if the point is in our bounding box 00476 // or if the node contains infinite elements 00477 if (this->bounds_point(p, relative_tol) || this->contains_ifems) 00478 // Search the active elements in the active TreeNode. 00479 for (std::vector<const Elem*>::const_iterator pos=elements.begin(); 00480 pos != elements.end(); ++pos) 00481 if (!allowed_subdomains || allowed_subdomains->count((*pos)->subdomain_id())) 00482 if ((*pos)->active() && (*pos)->contains_point(p, relative_tol)) 00483 return *pos; 00484 00485 // The point was not found in any element 00486 return NULL; 00487 } 00488 else 00489 return this->find_element_in_children(p,allowed_subdomains, 00490 relative_tol); 00491 00492 libmesh_error_msg("We'll never get here!"); 00493 return NULL; 00494 } 00495 00496 00497 00498 00499 template <unsigned int N> 00500 const Elem* TreeNode<N>::find_element_in_children 00501 (const Point& p, 00502 const std::set<subdomain_id_type> *allowed_subdomains, 00503 Real relative_tol) const 00504 { 00505 libmesh_assert (!this->active()); 00506 00507 std::vector<bool> searched_child(children.size(), false); 00508 00509 // First only look in the children whose bounding box 00510 // contain the point p. 00511 for (unsigned int c=0; c<children.size(); c++) 00512 if (children[c]->bounds_point(p, relative_tol)) 00513 { 00514 const Elem* e = 00515 children[c]->find_element(p,allowed_subdomains, 00516 relative_tol); 00517 00518 if (e != NULL) 00519 return e; 00520 00521 // If we get here then a child that bounds the 00522 // point does not have any elements that contain 00523 // the point. So, we will search all our children. 00524 // However, we have already searched child c so there 00525 // is no use searching her again. 00526 searched_child[c] = true; 00527 } 00528 00529 00530 // If we get here then our child whose bounding box 00531 // was searched and did not find any elements containing 00532 // the point p. So, let's look at the other children 00533 // but exclude the one we have already searched. 00534 for (unsigned int c=0; c<children.size(); c++) 00535 if (!searched_child[c]) 00536 { 00537 const Elem* e = 00538 children[c]->find_element(p,allowed_subdomains, 00539 relative_tol); 00540 00541 if (e != NULL) 00542 return e; 00543 } 00544 00545 // If we get here we have searched all our children. 00546 // Since this process was started at the root node then 00547 // we have searched all the elements in the tree without 00548 // success. So, we should return NULL since at this point 00549 // _no_ elements in the tree claim to contain point p. 00550 00551 return NULL; 00552 } 00553 00554 00555 00556 // ------------------------------------------------------------ 00557 // Explicit Instantiations 00558 template class TreeNode<2>; 00559 template class TreeNode<4>; 00560 template class TreeNode<8>; 00561 00562 } // namespace libMesh