$extrastylesheet
tree_node.C
Go to the documentation of this file.
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