LCOV - code coverage report
Current view: top level - src/utils - tree_node.C (source / functions) Hit Total Coverage
Test: libMesh/libmesh: #4229 (6a9aeb) with base 727f46 Lines: 210 279 75.3 %
Date: 2025-08-19 19:27:09 Functions: 21 51 41.2 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // The libMesh Finite Element Library.
       2             : // Copyright (C) 2002-2025 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
       3             : 
       4             : // This library is free software; you can redistribute it and/or
       5             : // modify it under the terms of the GNU Lesser General Public
       6             : // License as published by the Free Software Foundation; either
       7             : // version 2.1 of the License, or (at your option) any later version.
       8             : 
       9             : // This library is distributed in the hope that it will be useful,
      10             : // but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12             : // Lesser General Public License for more details.
      13             : 
      14             : // You should have received a copy of the GNU Lesser General Public
      15             : // License along with this library; if not, write to the Free Software
      16             : // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
      17             : 
      18             : 
      19             : 
      20             : // C++ includes
      21             : #include <set>
      22             : #include <array>
      23             : 
      24             : // Local includes
      25             : #include "libmesh/libmesh_config.h"
      26             : #include "libmesh/tree_node.h"
      27             : #include "libmesh/mesh_base.h"
      28             : #include "libmesh/elem.h"
      29             : 
      30             : namespace libMesh
      31             : {
      32             : 
      33             : // ------------------------------------------------------------
      34             : // TreeNode class methods
      35             : template <unsigned int N>
      36      126430 : bool TreeNode<N>::insert (const Node * nd)
      37             : {
      38       49762 :   libmesh_assert(nd);
      39       49762 :   libmesh_assert_less (nd->id(), mesh.n_nodes());
      40             : 
      41             :   // Return if we don't bound the node
      42      126430 :   if (!this->bounds_node(nd))
      43       38928 :     return false;
      44             : 
      45             :   // Add the node to ourself if we are active
      46       27583 :   if (this->active())
      47             :     {
      48       21813 :       nodes.push_back (nd);
      49             : 
      50             :       // Refine ourself if we reach the target bin size for a TreeNode.
      51       30349 :       if (nodes.size() == tgt_bin_size)
      52          46 :         this->refine();
      53             : 
      54       21813 :       return true;
      55             :     }
      56             : 
      57             :   // If we are not active simply pass the node along to
      58             :   // our children
      59        2298 :   libmesh_assert_equal_to (children.size(), N);
      60             : 
      61        2298 :   bool was_inserted = false;
      62       51930 :   for (unsigned int c=0; c<N; c++)
      63       64544 :     if (children[c]->insert (nd))
      64        2962 :       was_inserted = true;
      65        2298 :   return was_inserted;
      66             : }
      67             : 
      68             : 
      69             : 
      70             : template <unsigned int N>
      71    21050651 : bool TreeNode<N>::insert (const Elem * elem)
      72             : {
      73     2184147 :   libmesh_assert(elem);
      74             : 
      75             :   // We first want to find the corners of the cuboid surrounding the cell.
      76    21050651 :   const BoundingBox bbox = elem->loose_bounding_box();
      77             : 
      78             :   // If we are using a QuadTree, it's either because LIBMESH_DIM==2 or
      79             :   // we have a planar xy mesh.  Either way, the bounding box
      80             :   // comparison in this case needs to do something slightly different
      81             :   // for the z-coordinate.
      82     2184147 :   bool bboxes_intersect = false;
      83             : 
      84             :   if (N == 8) // OctTree
      85     7682413 :     bboxes_intersect = this->bounding_box.intersects(bbox);
      86             :   else if (N == 4) // QuadTree
      87             :     {
      88             :       // Perform a specialized BoundingBox intersection check that
      89             :       // ignores z-coords.  Copied from geom/bounding_box.C Check for
      90             :       // "real" intersection in the x and y directions, then check
      91             :       // that the z-coordinate is "close".
      92             : 
      93             :       // Helper macro
      94             : #define IS_BETWEEN(min, check, max)             \
      95             :       ((min) <= (check) && (check) <= (max))
      96             : 
      97             :       // Make local variables first to make things more clear in a moment
      98     1954713 :       const Real & elem_min_x = bbox.first(0);
      99     1954713 :       const Real & elem_max_x = bbox.second(0);
     100     1954713 :       const Real & tree_min_x = this->bounding_box.first(0);
     101     1954713 :       const Real & tree_max_x = this->bounding_box.second(0);
     102             : 
     103     1954713 :       const Real & elem_min_y = bbox.first(1);
     104     1954713 :       const Real & elem_max_y = bbox.second(1);
     105     1954713 :       const Real & tree_min_y = this->bounding_box.first(1);
     106     1954713 :       const Real & tree_max_y = this->bounding_box.second(1);
     107             : 
     108     1954713 :       bool x_int =
     109     3420557 :         IS_BETWEEN(elem_min_x, tree_min_x, elem_max_x) ||
     110    12775415 :         IS_BETWEEN(elem_min_x, tree_max_x, elem_max_x) ||
     111    24446093 :         IS_BETWEEN(tree_min_x, elem_min_x, tree_max_x) ||
     112     5458516 :         IS_BETWEEN(tree_min_x, elem_max_x, tree_max_x);
     113             : 
     114     1954713 :       bool y_int =
     115     9723888 :         IS_BETWEEN(elem_min_y, tree_min_y, elem_max_y) ||
     116     4464898 :         IS_BETWEEN(elem_min_y, tree_max_y, elem_max_y) ||
     117    18181875 :         IS_BETWEEN(tree_min_y, elem_min_y, tree_max_y) ||
     118     1506212 :         IS_BETWEEN(tree_min_y, elem_max_y, tree_max_y);
     119             : 
     120             :       // When LIBMESH_DIM==3, check that the z-coordinates of the elem
     121             :       // bbox and the tree bbox are "close" since the QuadTree is
     122             :       // meant to work in the case when the mesh is planar_xy but not
     123             :       // necessarily lying in the z=0 plane.
     124     1954713 :       bool z_match = true;
     125             :       if (LIBMESH_DIM == 3)
     126             :         {
     127     1954713 :           const Real & elem_min_z = bbox.first(2);
     128     1954713 :           const Real & elem_max_z = bbox.second(2);
     129     1954713 :           const Real & tree_min_z = this->bounding_box.first(2);
     130     1954713 :           const Real & tree_max_z = this->bounding_box.second(2);
     131             : 
     132     1954713 :           z_match =
     133    15093517 :             (std::abs(elem_min_z - elem_max_z) < TOLERANCE) &&
     134    15093517 :             (std::abs(tree_min_z - tree_max_z) < TOLERANCE) &&
     135    13138804 :             (std::abs(elem_min_z - tree_max_z) < TOLERANCE);
     136             :         }
     137             : 
     138    13138804 :       bboxes_intersect = z_match && x_int && y_int;
     139             :     }
     140             :   else // binary tree
     141             :     {
     142             :       // TODO: implement 1D bounding box intersection check
     143           0 :       libmesh_not_implemented();
     144             :     }
     145             : 
     146             :   // Next, find out whether this cuboid has got non-empty intersection
     147             :   // with the bounding box of the current tree node.
     148             :   //
     149             :   // If not, we should not care about this element.
     150     9866560 :   if (!bboxes_intersect)
     151     1375064 :     return false;
     152             : 
     153             :   // Only add the element if we are active
     154     8345119 :   if (this->active())
     155             :     {
     156     6385051 :       elements.push_back (elem);
     157             : 
     158             : #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
     159             : 
     160             :       // flag indicating this node contains
     161             :       // infinite elements
     162     1376368 :       if (elem->infinite())
     163           0 :         this->contains_ifems = true;
     164             : 
     165             : #endif
     166             : 
     167     1142814 :       unsigned int element_count = cast_int<unsigned int>(elements.size());
     168     6385051 :       if (!mesh.get_count_lower_dim_elems_in_point_locator())
     169             :         {
     170           0 :           const std::set<unsigned char> & elem_dimensions = mesh.elem_dimensions();
     171           0 :           if (elem_dimensions.size() > 1)
     172             :             {
     173           0 :               element_count = 0;
     174           0 :               unsigned char highest_dim_elem = *elem_dimensions.rbegin();
     175           0 :               for (const Elem * other_elem : elements)
     176           0 :                 if (other_elem->dim() == highest_dim_elem)
     177           0 :                   element_count++;
     178             :             }
     179             :         }
     180             : 
     181             :       // Refine ourself if we reach the target bin size for a TreeNode.
     182     6385051 :       if (element_count == tgt_bin_size)
     183       10120 :         this->refine();
     184             : 
     185     6385051 :       return true;
     186             :     }
     187             : 
     188             :   // If we are not active simply pass the element along to
     189             :   // our children
     190      237676 :   libmesh_assert_equal_to (children.size(), N);
     191             : 
     192      237676 :   bool was_inserted = false;
     193    12158648 :   for (unsigned int c=0; c<N; c++)
     194    11217732 :     if (children[c]->insert (elem))
     195      306008 :       was_inserted = true;
     196      237676 :   return was_inserted;
     197             : }
     198             : 
     199             : 
     200             : 
     201             : template <unsigned int N>
     202       10166 : void TreeNode<N>::refine ()
     203             : {
     204             :   // Huh?  better be active...
     205        1198 :   libmesh_assert (this->active());
     206        1198 :   libmesh_assert (children.empty());
     207             : 
     208             :   // A TreeNode<N> has by definition N children
     209       10166 :   children.resize(N);
     210             : 
     211             :   // Scale up the target bin size in child TreeNodes if we have reached
     212             :   // the maximum number of refinement levels.
     213       10166 :   unsigned int new_target_bin_size = tgt_bin_size;
     214       10166 :   if (level() >= target_bin_size_increase_level)
     215             :     {
     216           0 :       new_target_bin_size *= 2;
     217             :     }
     218             : 
     219       57702 :   for (unsigned int c=0; c<N; c++)
     220             :     {
     221             :       // Create the child and set its bounding box.
     222       47536 :       children[c] = std::make_unique<TreeNode<N>>(mesh, new_target_bin_size, this);
     223       52592 :       children[c]->set_bounding_box(this->create_bounding_box(c));
     224             : 
     225             :       // Pass off our nodes to our children
     226      121136 :       for (const Node * node : nodes)
     227      102400 :         children[c]->insert(node);
     228             : 
     229             :       // Pass off our elements to our children
     230     9481136 :       for (const Elem * elem : elements)
     231    10416000 :         children[c]->insert(elem);
     232             :     }
     233             : 
     234             :   // We don't need to store nodes or elements any more, they have been
     235             :   // added to the children.  Use the "swap trick" to actually reduce
     236             :   // the capacity of these vectors.
     237        8968 :   std::vector<const Node *>().swap(nodes);
     238        8968 :   std::vector<const Elem *>().swap(elements);
     239             : 
     240        1198 :   libmesh_assert_equal_to (nodes.capacity(), 0);
     241        1198 :   libmesh_assert_equal_to (elements.capacity(), 0);
     242       10166 : }
     243             : 
     244             : 
     245             : 
     246             : template <unsigned int N>
     247       60083 : void TreeNode<N>::set_bounding_box (const std::pair<Point, Point> & bbox)
     248             : {
     249       60083 :   bounding_box = bbox;
     250       60083 : }
     251             : 
     252             : 
     253             : 
     254             : template <unsigned int N>
     255       99524 : bool TreeNode<N>::bounds_node (const Node * nd,
     256             :                                Real relative_tol) const
     257             : {
     258       49762 :   libmesh_assert(nd);
     259      126430 :   return bounds_point(*nd, relative_tol);
     260             : }
     261             : 
     262             : 
     263             : 
     264             : template <unsigned int N>
     265     2003097 : bool TreeNode<N>::bounds_point (const Point & p,
     266             :                                 Real relative_tol) const
     267             : {
     268      320866 :   const Point & min = bounding_box.first;
     269      320866 :   const Point & max = bounding_box.second;
     270             : 
     271     2003097 :   const Real tol = (max - min).norm() * relative_tol;
     272             : 
     273     2003097 :   if ((p(0) >= min(0) - tol)
     274     1785889 :       && (p(0) <= max(0) + tol)
     275             : #if LIBMESH_DIM > 1
     276     1523895 :       && (p(1) >= min(1) - tol)
     277     1425245 :       && (p(1) <= max(1) + tol)
     278             : #endif
     279             : #if LIBMESH_DIM > 2
     280     1282983 :       && (p(2) >= min(2) - tol)
     281     3401820 :       && (p(2) <= max(2) + tol)
     282             : #endif
     283             :       )
     284     1209691 :     return true;
     285             : 
     286      201254 :   return false;
     287             : }
     288             : 
     289             : 
     290             : 
     291             : template <unsigned int N>
     292             : BoundingBox
     293       47536 : TreeNode<N>::create_bounding_box (unsigned int c) const
     294             : {
     295             :   switch (N)
     296             :     {
     297             :       // How to refine an OctTree Node
     298             :     case 8:
     299             :       {
     300       13744 :         const Real xmin = bounding_box.first(0);
     301       13744 :         const Real ymin = bounding_box.first(1);
     302       13744 :         const Real zmin = bounding_box.first(2);
     303             : 
     304       13744 :         const Real xmax = bounding_box.second(0);
     305       13744 :         const Real ymax = bounding_box.second(1);
     306       13744 :         const Real zmax = bounding_box.second(2);
     307             : 
     308       13744 :         const Real xc = .5*(xmin + xmax);
     309       13744 :         const Real yc = .5*(ymin + ymax);
     310       13744 :         const Real zc = .5*(zmin + zmax);
     311             : 
     312       13744 :         switch (c)
     313             :           {
     314          66 :           case 0:
     315             :             return BoundingBox (Point(xmin, ymin, zmin),
     316          66 :                                 Point(xc,   yc,   zc));
     317          66 :           case 1:
     318             :             return BoundingBox (Point(xc,   ymin, zmin),
     319          66 :                                 Point(xmax, yc,   zc));
     320          66 :           case 2:
     321             :             return BoundingBox (Point(xmin, yc,   zmin),
     322          66 :                                 Point(xc,   ymax, zc));
     323          66 :           case 3:
     324             :             return BoundingBox (Point(xc,   yc,   zmin),
     325          66 :                                 Point(xmax, ymax, zc));
     326          66 :           case 4:
     327             :             return BoundingBox (Point(xmin, ymin, zc),
     328          66 :                                 Point(xc,   yc,   zmax));
     329          66 :           case 5:
     330             :             return BoundingBox (Point(xc,   ymin, zc),
     331          66 :                                 Point(xmax, yc,   zmax));
     332          66 :           case 6:
     333             :             return BoundingBox (Point(xmin, yc,   zc),
     334          66 :                                 Point(xc,   ymax, zmax));
     335          66 :           case 7:
     336             :             return BoundingBox (Point(xc,   yc,   zc),
     337          66 :                                 Point(xmax, ymax, zmax));
     338           0 :           default:
     339           0 :             libmesh_error_msg("c >= N! : " << c);
     340             :           }
     341             : 
     342             :         break;
     343             :       } // case 8
     344             : 
     345             :       // How to refine an QuadTree Node
     346             :     case 4:
     347             :       {
     348       33792 :         const Real xmin = bounding_box.first(0);
     349       33792 :         const Real ymin = bounding_box.first(1);
     350             : 
     351       33792 :         const Real xmax = bounding_box.second(0);
     352       33792 :         const Real ymax = bounding_box.second(1);
     353             : 
     354       33792 :         const Real xc = .5*(xmin + xmax);
     355       33792 :         const Real yc = .5*(ymin + ymax);
     356             : 
     357       33792 :         switch (c)
     358             :           {
     359        1132 :           case 0:
     360             :             return BoundingBox (Point(xmin, ymin),
     361        1132 :                                 Point(xc,   yc));
     362        1132 :           case 1:
     363             :             return BoundingBox (Point(xc,   ymin),
     364        1132 :                                 Point(xmax, yc));
     365        1132 :           case 2:
     366             :             return BoundingBox (Point(xmin, yc),
     367        1132 :                                 Point(xc,   ymax));
     368        1132 :           case 3:
     369             :             return BoundingBox (Point(xc,   yc),
     370        1132 :                                 Point(xmax, ymax));
     371           0 :           default:
     372           0 :             libmesh_error_msg("c >= N!");
     373             :           }
     374             : 
     375             :         break;
     376             :       } // case 4
     377             : 
     378             :       // How to refine a BinaryTree Node
     379             :     case 2:
     380             :       {
     381           0 :         const Real xmin = bounding_box.first(0);
     382             : 
     383           0 :         const Real xmax = bounding_box.second(0);
     384             : 
     385           0 :         const Real xc = .5*(xmin + xmax);
     386             : 
     387           0 :         switch (c)
     388             :           {
     389           0 :           case 0:
     390             :             return BoundingBox (Point(xmin),
     391           0 :                                 Point(xc));
     392           0 :           case 1:
     393             :             return BoundingBox (Point(xc),
     394           0 :                                 Point(xmax));
     395           0 :           default:
     396           0 :             libmesh_error_msg("c >= N!");
     397             :           }
     398             : 
     399             :         break;
     400             :       } // case 2
     401             : 
     402             :     default:
     403             :       libmesh_error_msg("Only implemented for Octrees, QuadTrees, and Binary Trees!");
     404             :     }
     405             : }
     406             : 
     407             : 
     408             : 
     409             : template <unsigned int N>
     410           0 : void TreeNode<N>::print_nodes(std::ostream & out_stream) const
     411             : {
     412           0 :   if (this->active())
     413             :     {
     414           0 :       out_stream << "TreeNode Level: " << this->level() << std::endl;
     415             : 
     416           0 :       for (const Node * node : nodes)
     417           0 :         out_stream << " " << node->id();
     418             : 
     419           0 :       out_stream << std::endl << std::endl;
     420             :     }
     421             :   else
     422           0 :     for (const auto & child : children)
     423           0 :       child->print_nodes();
     424           0 : }
     425             : 
     426             : 
     427             : 
     428             : template <unsigned int N>
     429           0 : void TreeNode<N>::print_elements(std::ostream & out_stream) const
     430             : {
     431           0 :   if (this->active())
     432             :     {
     433           0 :       out_stream << "TreeNode Level: " << this->level() << std::endl;
     434             : 
     435           0 :       for (const auto & elem : elements)
     436           0 :         out_stream << " " << elem;
     437             : 
     438           0 :       out_stream << std::endl << std::endl;
     439             :     }
     440             :   else
     441           0 :     for (const auto & child : children)
     442           0 :       child->print_elements();
     443           0 : }
     444             : 
     445             : 
     446             : 
     447             : template <unsigned int N>
     448           0 : void TreeNode<N>::transform_nodes_to_elements (std::vector<std::vector<const Elem *>> & nodes_to_elem)
     449             : {
     450           0 :   if (this->active())
     451             :     {
     452           0 :       elements.clear();
     453             : 
     454             :       // Temporarily use a set. Since multiple nodes
     455             :       // will likely map to the same element we use a
     456             :       // set to eliminate the duplication.
     457           0 :       std::set<const Elem *> elements_set;
     458             : 
     459           0 :       for (const Node * node : nodes)
     460             :         {
     461             :           // the actual global node number we are replacing
     462             :           // with the connected elements
     463           0 :           const dof_id_type node_number = node->id();
     464             : 
     465           0 :           libmesh_assert_less (node_number, mesh.n_nodes());
     466           0 :           libmesh_assert_less (node_number, nodes_to_elem.size());
     467             : 
     468           0 :           for (const Elem * elem : nodes_to_elem[node_number])
     469           0 :             elements_set.insert(elem);
     470             :         }
     471             : 
     472             :       // Done with the nodes.
     473           0 :       std::vector<const Node *>().swap(nodes);
     474             : 
     475             :       // Now the set is built.  We can copy this to the
     476             :       // vector.  Note that the resulting vector will
     477             :       // already be sorted, and will require less memory
     478             :       // than the set.
     479           0 :       elements.reserve(elements_set.size());
     480             : 
     481           0 :       for (const auto & elem : elements_set)
     482             :         {
     483           0 :           elements.push_back(elem);
     484             : 
     485             : #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
     486             : 
     487             :           // flag indicating this node contains
     488             :           // infinite elements
     489           0 :           if (elem->infinite())
     490           0 :             this->contains_ifems = true;
     491             : 
     492             : #endif
     493             :         }
     494             :     }
     495             :   else
     496           0 :     for (auto & child : children)
     497           0 :       child->transform_nodes_to_elements (nodes_to_elem);
     498           0 : }
     499             : 
     500             : 
     501             : 
     502             : template <unsigned int N>
     503         374 : void TreeNode<N>::transform_nodes_to_elements (std::unordered_map<dof_id_type, std::vector<const Elem *>> & nodes_to_elem)
     504             : {
     505         374 :   if (this->active())
     506             :     {
     507         328 :       elements.clear();
     508             : 
     509             :       // Temporarily use a set. Since multiple nodes
     510             :       // will likely map to the same element we use a
     511             :       // set to eliminate the duplication.
     512         256 :       std::set<const Elem *> elements_set;
     513             : 
     514       12941 :       for (const Node * node : nodes)
     515             :         {
     516             :           // the actual global node number we are replacing
     517             :           // with the connected elements
     518       12613 :           const dof_id_type node_number = node->id();
     519             : 
     520        4936 :           libmesh_assert_less (node_number, mesh.n_nodes());
     521             : 
     522        4936 :           auto & my_elems = nodes_to_elem[node_number];
     523        7677 :           elements_set.insert(my_elems.begin(), my_elems.end());
     524             :         }
     525             : 
     526             :       // Done with the nodes.
     527         200 :       std::vector<const Node *>().swap(nodes);
     528             : 
     529             :       // Now the set is built.  We can copy this to the
     530             :       // vector.  Note that the resulting vector will
     531             :       // already be sorted, and will require less memory
     532             :       // than the set.
     533         328 :       elements.reserve(elements_set.size());
     534             : 
     535        9238 :       for (const auto & elem : elements_set)
     536             :         {
     537        8910 :           elements.push_back(elem);
     538             : 
     539             : #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
     540             : 
     541             :           // flag indicating this node contains
     542             :           // infinite elements
     543        8910 :           if (elem->infinite())
     544        5197 :             this->contains_ifems = true;
     545             : 
     546             : #endif
     547             :         }
     548             :     }
     549             :   else
     550         414 :     for (auto & child : children)
     551         368 :       child->transform_nodes_to_elements (nodes_to_elem);
     552         374 : }
     553             : 
     554             : 
     555             : 
     556             : template <unsigned int N>
     557           0 : unsigned int TreeNode<N>::n_active_bins() const
     558             : {
     559           0 :   if (this->active())
     560           0 :     return 1;
     561             : 
     562             :   else
     563             :     {
     564           0 :       unsigned int sum=0;
     565             : 
     566           0 :       for (const auto & child : children)
     567           0 :         sum += child->n_active_bins();
     568             : 
     569           0 :       return sum;
     570             :     }
     571             : }
     572             : 
     573             : 
     574             : 
     575             : template <unsigned int N>
     576             : const Elem *
     577      810649 : TreeNode<N>::find_element (const Point & p,
     578             :                            const std::set<subdomain_id_type> * allowed_subdomains,
     579             :                            Real relative_tol) const
     580             : {
     581      810649 :   if (this->active())
     582             :     {
     583             :       // Only check our children if the point is in our bounding box
     584             :       // or if the node contains infinite elements
     585      718521 :       if (this->bounds_point(p, relative_tol) || this->contains_ifems)
     586             :         // Search the active elements in the active TreeNode.
     587    25951418 :         for (const auto & elem : elements)
     588    25799317 :           if (!allowed_subdomains || allowed_subdomains->count(elem->subdomain_id()))
     589    25078350 :             if (elem->active())
     590             :               {
     591     1826130 :                 bool found = relative_tol > TOLERANCE
     592    23270970 :                   ? elem->close_to_point(p, relative_tol)
     593    24956755 :                   : elem->contains_point(p);
     594             : 
     595    25078236 :                 if (found)
     596      566390 :                   return elem;
     597             :               }
     598             : 
     599             :       // The point was not found in any element
     600      152131 :       return nullptr;
     601             :     }
     602             :   else
     603       77012 :     return this->find_element_in_children(p,allowed_subdomains,
     604       92128 :                                           relative_tol);
     605             : }
     606             : 
     607             : 
     608             : 
     609             : template <unsigned int N>
     610             : void
     611      368049 : TreeNode<N>::find_elements (const Point & p,
     612             :                             std::set<const Elem *> & candidate_elements,
     613             :                             const std::set<subdomain_id_type> * allowed_subdomains,
     614             :                             Real relative_tol) const
     615             : {
     616      368049 :   if (this->active())
     617             :     {
     618             :       // Only check our children if the point is in our bounding box
     619             :       // or if the node contains infinite elements
     620      260133 :       if (this->bounds_point(p, relative_tol) || this->contains_ifems)
     621             :         // Search the active elements in the active TreeNode.
     622    15054371 :         for (const auto & elem : elements)
     623    14794238 :           if (!allowed_subdomains || allowed_subdomains->count(elem->subdomain_id()))
     624    13985846 :             if (elem->active())
     625             :               {
     626     4301842 :                 bool found = relative_tol > TOLERANCE
     627     9684004 :                   ? elem->close_to_point(p, relative_tol)
     628    13985846 :                   : elem->contains_point(p);
     629             : 
     630    13985846 :                 if (found)
     631      465126 :                   candidate_elements.insert(elem);
     632             :               }
     633             :     }
     634             :   else
     635      107916 :     this->find_elements_in_children(p, candidate_elements,
     636             :                                     allowed_subdomains, relative_tol);
     637      368049 : }
     638             : 
     639             : 
     640             : 
     641             : template <unsigned int N>
     642       92128 : const Elem * TreeNode<N>::find_element_in_children (const Point & p,
     643             :                                                     const std::set<subdomain_id_type> * allowed_subdomains,
     644             :                                                     Real relative_tol) const
     645             : {
     646        7558 :   libmesh_assert (!this->active());
     647             : 
     648             :   // value-initialization sets all array members to false
     649       99022 :   auto searched_child = std::array<bool, N>();
     650             : 
     651             :   // First only look in the children whose bounding box
     652             :   // contain the point p.
     653      406627 :   for (auto c : index_range(children))
     654      440397 :     if (children[c]->bounds_point(p, relative_tol))
     655             :       {
     656       15116 :         const Elem * e =
     657       92128 :           children[c]->find_element(p,allowed_subdomains,
     658             :                                     relative_tol);
     659             : 
     660       92128 :         if (e != nullptr)
     661        7556 :           return e;
     662             : 
     663             :         // If we get here then a child that bounds the
     664             :         // point does not have any elements that contain
     665             :         // the point.  So, we will search all our children.
     666             :         // However, we have already searched child c so there
     667             :         // is no use searching her again.
     668          10 :         searched_child[c] = true;
     669             :       }
     670             : 
     671             : 
     672             :   // If we get here then our child whose bounding box
     673             :   // was searched and did not find any elements containing
     674             :   // the point p.  So, let's look at the other children
     675             :   // but exclude the one we have already searched.
     676          50 :   for (auto c : index_range(children))
     677          40 :     if (!searched_child[c])
     678             :       {
     679          12 :         const Elem * e =
     680          30 :           children[c]->find_element(p,allowed_subdomains,
     681             :                                     relative_tol);
     682             : 
     683          30 :         if (e != nullptr)
     684           0 :           return e;
     685             :       }
     686             : 
     687             :   // If we get here we have searched all our children.
     688             :   // Since this process was started at the root node then
     689             :   // we have searched all the elements in the tree without
     690             :   // success.  So, we should return nullptr since at this point
     691             :   // _no_ elements in the tree claim to contain point p.
     692           4 :   return nullptr;
     693             : }
     694             : 
     695             : 
     696             : 
     697             : template <unsigned int N>
     698      107916 : void TreeNode<N>::find_elements_in_children (const Point & p,
     699             :                                              std::set<const Elem *> & candidate_elements,
     700             :                                              const std::set<subdomain_id_type> * allowed_subdomains,
     701             :                                              Real relative_tol) const
     702             : {
     703       43334 :   libmesh_assert (!this->active());
     704             : 
     705             :   // First only look in the children whose bounding box
     706             :   // contain the point p.
     707      632768 :   for (std::size_t c=0; c<children.size(); c++)
     708      491396 :     if (children[c]->bounds_point(p, relative_tol))
     709      145180 :       children[c]->find_elements(p, candidate_elements,
     710             :                                  allowed_subdomains, relative_tol);
     711      107916 : }
     712             : 
     713             : 
     714             : 
     715             : // ------------------------------------------------------------
     716             : // Explicit Instantiations
     717             : template class LIBMESH_EXPORT TreeNode<2>;
     718             : template class LIBMESH_EXPORT TreeNode<4>;
     719             : template class LIBMESH_EXPORT TreeNode<8>;
     720             : 
     721             : } // namespace libMesh

Generated by: LCOV version 1.14