LCOV - code coverage report
Current view: top level - include/geom - elem_internal.h (source / functions) Hit Total Coverage
Test: libMesh/libmesh: #4476 (4beb67) with base a68cc6 Lines: 163 219 74.4 %
Date: 2026-06-03 20:22:46 Functions: 15 28 53.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // The libMesh Finite Element Library.
       2             : // Copyright (C) 2002-2026 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             : #ifndef LIBMESH_ELEM_INTERNAL_H
      19             : #define LIBMESH_ELEM_INTERNAL_H
      20             : 
      21             : // libMesh includes
      22             : #include "libmesh/elem.h"
      23             : 
      24             : namespace libMesh
      25             : {
      26             : 
      27             : // Forward declarations
      28             : class PointLocatorBase;
      29             : class PeriodicBoundaries;
      30             : 
      31             : /**
      32             :  * The ElemInternal namespace holds helper functions that are used
      33             :  * internally by the Elem class. These should not be called directly,
      34             :  * call the appropriate member functions on the Elem class instead.
      35             :  */
      36             : namespace ElemInternal
      37             : {
      38             : 
      39             : template<class T>
      40             : void
      41       76113 : family_tree (T elem,
      42             :              std::vector<T> & family,
      43             :              bool reset = true)
      44             : {
      45             :   // The "family tree" doesn't include subactive elements
      46        6339 :   libmesh_assert(!elem->subactive());
      47             : 
      48             :   // Clear the vector if the flag reset tells us to.
      49       76113 :   if (reset)
      50         770 :     family.clear();
      51             : 
      52             :   // Add this element to the family tree.
      53       76113 :   family.push_back(elem);
      54             : 
      55             :   // Recurse into the elements children, if it has them.
      56             :   // Do not clear the vector any more.
      57       76113 :   if (!elem->active())
      58       75333 :     for (auto & c : elem->child_ref_range())
      59       66612 :       if (!c.is_remote())
      60       66612 :         ElemInternal::family_tree (&c, family, false);
      61       76113 : }
      62             : 
      63             : 
      64             : 
      65             : template<class T>
      66             : void
      67    32115819 : total_family_tree(T elem,
      68             :                   std::vector<T> & family,
      69             :                   bool reset)
      70             : {
      71             :   // Clear the vector if the flag reset tells us to.
      72    32115819 :   if (reset)
      73     1102934 :     family.clear();
      74             : 
      75             :   // Add this element to the family tree.
      76    32115819 :   family.push_back(elem);
      77             : 
      78             :   // Recurse into the elements children, if it has them.
      79             :   // Do not clear the vector any more.
      80    32115819 :   if (elem->has_children())
      81     1847564 :     for (auto & c : elem->child_ref_range())
      82     1486120 :       if (!c.is_remote())
      83     1456333 :         ElemInternal::total_family_tree (&c, family, false);
      84    32115819 : }
      85             : 
      86             : 
      87             : 
      88             : template<class T>
      89             : void
      90    10912674 : active_family_tree(T elem,
      91             :                    std::vector<T> & active_family,
      92             :                    bool reset = true)
      93             : {
      94             :   // The "family tree" doesn't include subactive elements
      95      291059 :   libmesh_assert(!elem->subactive());
      96             : 
      97             :   // Clear the vector if the flag reset tells us to.
      98    10912674 :   if (reset)
      99       45596 :     active_family.clear();
     100             : 
     101             :   // Add this element to the family tree if it is active
     102    10912674 :   if (elem->active())
     103     8817763 :     active_family.push_back(elem);
     104             : 
     105             :   // Otherwise recurse into the element's children.
     106             :   // Do not clear the vector any more.
     107             :   else
     108    12662435 :     for (auto & c : elem->child_ref_range())
     109    10567524 :       if (!c.is_remote())
     110     9892193 :         ElemInternal::active_family_tree (&c, active_family, false);
     111    10912674 : }
     112             : 
     113             : 
     114             : 
     115             : template <class T>
     116             : void
     117           0 : family_tree_by_side (T elem,
     118             :                      std::vector<T> & family,
     119             :                      unsigned int s,
     120             :                      bool reset)
     121             : {
     122             :   // The "family tree" doesn't include subactive elements
     123           0 :   libmesh_assert(!elem->subactive());
     124             : 
     125             :   // Clear the vector if the flag reset tells us to.
     126           0 :   if (reset)
     127           0 :     family.clear();
     128             : 
     129           0 :   libmesh_assert_less (s, elem->n_sides());
     130             : 
     131             :   // Add this element to the family tree.
     132           0 :   family.push_back(elem);
     133             : 
     134             :   // Recurse into the elements children, if it has them.
     135             :   // Do not clear the vector any more.
     136           0 :   if (!elem->active())
     137             :     {
     138           0 :       const unsigned int nc = elem->n_children();
     139           0 :       for (unsigned int c = 0; c != nc; c++)
     140           0 :         if (!elem->child_ptr(c)->is_remote() && elem->is_child_on_side(c, s))
     141           0 :           ElemInternal::family_tree_by_side (elem->child_ptr(c), family, s, false);
     142             :     }
     143           0 : }
     144             : 
     145             : 
     146             : 
     147             : template <class T>
     148             : void
     149   280961941 : total_family_tree_by_side (T elem,
     150             :                            std::vector<T> & family,
     151             :                            unsigned int s,
     152             :                            bool reset)
     153             : {
     154             :   // Clear the vector if the flag reset tells us to.
     155   280961941 :   if (reset)
     156       38682 :     family.clear();
     157             : 
     158       51062 :   libmesh_assert_less (s, elem->n_sides());
     159             : 
     160             :   // Add this element to the family tree.
     161   280961941 :   family.push_back(elem);
     162             : 
     163             :   // Recurse into the elements children, if it has them.
     164             :   // Do not clear the vector any more.
     165   280961941 :   if (elem->has_children())
     166             :     {
     167    52204775 :       const unsigned int nc = elem->n_children();
     168   291178291 :       for (unsigned int c = 0; c != nc; c++)
     169   239000870 :         if (!elem->child_ptr(c)->is_remote() && elem->is_child_on_side(c, s))
     170    63161704 :           ElemInternal::total_family_tree_by_side (elem->child_ptr(c), family, s, false);
     171             :     }
     172   280961941 : }
     173             : 
     174             : 
     175             : 
     176             : template <class T>
     177             : void
     178      824200 : active_family_tree_by_side (T elem,
     179             :                             std::vector<T> & family,
     180             :                             unsigned int side,
     181             :                             bool reset = true)
     182             : {
     183             :   // The "family tree" doesn't include subactive or remote elements
     184       66732 :   libmesh_assert(!elem->subactive());
     185       66732 :   libmesh_assert(!elem->is_remote());
     186             : 
     187             :   // Clear the vector if the flag reset tells us to.
     188      824200 :   if (reset)
     189        3045 :     family.clear();
     190             : 
     191       66732 :   libmesh_assert_less (side, elem->n_sides());
     192             : 
     193             :   // Add an active element to the family tree.
     194      824200 :   if (elem->active())
     195      745033 :     family.push_back(elem);
     196             : 
     197             :   // Or recurse into an ancestor element's children.
     198             :   // Do not clear the vector any more.
     199             :   else
     200             :     {
     201       79167 :       const unsigned int nc = elem->n_children();
     202      570577 :       for (unsigned int c = 0; c != nc; c++)
     203      530232 :         if (!elem->child_ptr(c)->is_remote() && elem->is_child_on_side(c, side))
     204      252488 :           ElemInternal::active_family_tree_by_side(elem->child_ptr(c), family, side, false);
     205             :     }
     206      824200 : }
     207             : 
     208             : 
     209             : template <class T>
     210             : void
     211           0 : family_tree_by_neighbor (T elem,
     212             :                          std::vector<T> & family,
     213             :                          T neighbor_in,
     214             :                          bool reset = true)
     215             : {
     216             :   // The "family tree" doesn't include subactive elements
     217           0 :   libmesh_assert(!elem->subactive());
     218             : 
     219             :   // Clear the vector if the flag reset tells us to.
     220           0 :   if (reset)
     221           0 :     family.clear();
     222             : 
     223             :   // This only makes sense if we're already a neighbor
     224           0 :   libmesh_assert (elem->has_neighbor(neighbor_in));
     225             : 
     226             :   // Add this element to the family tree.
     227           0 :   family.push_back(elem);
     228             : 
     229             :   // Recurse into the elements children, if it's not active.
     230             :   // Do not clear the vector any more.
     231           0 :   if (!elem->active())
     232           0 :     for (auto & c : elem->child_ref_range())
     233           0 :       if (!c.is_remote() && c.has_neighbor(neighbor_in))
     234           0 :         ElemInternal::family_tree_by_neighbor (&c, family, neighbor_in, false);
     235           0 : }
     236             : 
     237             : 
     238             : template <class T>
     239             : void
     240    70050669 : total_family_tree_by_neighbor (T elem,
     241             :                                std::vector<T> & family,
     242             :                                T neighbor_in,
     243             :                                bool reset = true)
     244             : {
     245             :   // Clear the vector if the flag reset tells us to.
     246    70050669 :   if (reset)
     247        3917 :     family.clear();
     248             : 
     249             :   // This only makes sense if we're already a neighbor
     250        3917 :   libmesh_assert (elem->has_neighbor(neighbor_in));
     251             : 
     252             :   // Add this element to the family tree.
     253    70050669 :   family.push_back(elem);
     254             : 
     255             :   // Recurse into the elements children, if it has any.
     256             :   // Do not clear the vector any more.
     257    70050669 :   if (elem->has_children())
     258    61132121 :     for (auto & c : elem->child_ref_range())
     259    49223142 :       if (!c.is_remote() && c.has_neighbor(neighbor_in))
     260        7794 :         ElemInternal::total_family_tree_by_neighbor (&c, family, neighbor_in, false);
     261    70050669 : }
     262             : 
     263             : 
     264             : template <class T>
     265             : void
     266           0 : family_tree_by_subneighbor (T elem,
     267             :                             std::vector<T> & family,
     268             :                             T neighbor_in,
     269             :                             T subneighbor,
     270             :                             bool reset = true)
     271             : {
     272             :   // The "family tree" doesn't include subactive elements
     273           0 :   libmesh_assert(!elem->subactive());
     274             : 
     275             :   // Clear the vector if the flag reset tells us to.
     276           0 :   if (reset)
     277           0 :     family.clear();
     278             : 
     279             :   // To simplify this function we need an existing neighbor
     280           0 :   libmesh_assert (neighbor_in);
     281           0 :   libmesh_assert (!neighbor_in->is_remote());
     282           0 :   libmesh_assert (elem->has_neighbor(neighbor_in));
     283             : 
     284             :   // This only makes sense if subneighbor descends from neighbor
     285           0 :   libmesh_assert (subneighbor);
     286           0 :   libmesh_assert (!subneighbor->is_remote());
     287           0 :   libmesh_assert (neighbor_in->is_ancestor_of(subneighbor));
     288             : 
     289             :   // Add this element to the family tree if applicable.
     290           0 :   if (neighbor_in == subneighbor)
     291           0 :     family.push_back(elem);
     292             : 
     293             :   // Recurse into the elements children, if it's not active.
     294             :   // Do not clear the vector any more.
     295           0 :   if (!elem->active())
     296           0 :     for (auto & c : elem->child_ref_range())
     297           0 :       if (!c.is_remote())
     298           0 :         for (auto child_neigh : c.neighbor_ptr_range())
     299           0 :           if (child_neigh &&
     300           0 :               (child_neigh == neighbor_in || (child_neigh->parent() == neighbor_in &&
     301             :                                               child_neigh->is_ancestor_of(subneighbor))))
     302           0 :             ElemInternal::family_tree_by_subneighbor (&c, family, child_neigh, subneighbor, false);
     303           0 : }
     304             : 
     305             : 
     306             : 
     307             : template <class T>
     308             : void
     309        2874 : total_family_tree_by_subneighbor(T elem,
     310             :                                  std::vector<T> & family,
     311             :                                  T neighbor_in,
     312             :                                  T subneighbor,
     313             :                                  bool reset = true)
     314             : {
     315             :   // Clear the vector if the flag reset tells us to.
     316        2874 :   if (reset)
     317           0 :     family.clear();
     318             : 
     319             :   // To simplify this function we need an existing neighbor
     320           0 :   libmesh_assert (neighbor_in);
     321           0 :   libmesh_assert (!neighbor_in->is_remote());
     322           0 :   libmesh_assert (elem->has_neighbor(neighbor_in));
     323             : 
     324             :   // This only makes sense if subneighbor descends from neighbor
     325           0 :   libmesh_assert (subneighbor);
     326           0 :   libmesh_assert (!subneighbor->is_remote());
     327           0 :   libmesh_assert (neighbor_in->is_ancestor_of(subneighbor));
     328             : 
     329             :   // Add this element to the family tree if applicable.
     330        2874 :   if (neighbor_in == subneighbor)
     331        1114 :     family.push_back(elem);
     332             : 
     333             :   // Recurse into the elements children, if it has any.
     334             :   // Do not clear the vector any more.
     335        2874 :   if (elem->has_children())
     336       12740 :     for (auto & c : elem->child_ref_range())
     337       10980 :       if (!c.is_remote())
     338       51274 :         for (auto child_neigh : c.neighbor_ptr_range())
     339       43618 :           if (child_neigh &&
     340       41585 :               (child_neigh == neighbor_in ||
     341        3102 :                (child_neigh->parent() == neighbor_in && child_neigh->is_ancestor_of(subneighbor))))
     342        1114 :             c.total_family_tree_by_subneighbor(family, child_neigh, subneighbor, false);
     343        2874 : }
     344             : 
     345             : 
     346             : 
     347             : template <class T>
     348             : void
     349    51463115 : active_family_tree_by_neighbor(T elem,
     350             :                                std::vector<T> & family,
     351             :                                T neighbor_in,
     352             :                                bool reset = true)
     353             : {
     354             :   // The "family tree" doesn't include subactive elements or
     355             :   // remote_elements
     356     2980654 :   libmesh_assert(!elem->subactive());
     357     2980654 :   libmesh_assert(!elem->is_remote());
     358             : 
     359             :   // Clear the vector if the flag reset tells us to.
     360    51463115 :   if (reset)
     361     2693985 :     family.clear();
     362             : 
     363             :   // This only makes sense if we're already a neighbor
     364             : #ifndef NDEBUG
     365     2980654 :   if (elem->level() >= neighbor_in->level())
     366     2835431 :     libmesh_assert (elem->has_neighbor(neighbor_in));
     367             : #endif
     368             : 
     369             :   // Add an active element to the family tree.
     370    51463115 :   if (elem->active())
     371    48242531 :     family.push_back(elem);
     372             : 
     373             :   // Or recurse into an ancestor element's children.
     374             :   // Do not clear the vector any more.
     375      139849 :   else if (!elem->active())
     376    21950976 :     for (auto & c : elem->child_ref_range())
     377    19303730 :       if (!c.is_remote() && c.has_neighbor(neighbor_in))
     378     9220422 :         ElemInternal::active_family_tree_by_neighbor (&c, family, neighbor_in, false);
     379    51463115 : }
     380             : 
     381             : 
     382             : 
     383             : template <class T>
     384             : void
     385       26334 : active_family_tree_by_topological_neighbor (T elem,
     386             :                                             std::vector<T> & family,
     387             :                                             T neighbor_in,
     388             :                                             const MeshBase & mesh,
     389             :                                             const PointLocatorBase & point_locator,
     390             :                                             const PeriodicBoundaries * pb,
     391             :                                             bool reset = true)
     392             : {
     393             :   // The "family tree" doesn't include subactive elements or
     394             :   // remote_elements
     395       10514 :   libmesh_assert(!elem->subactive());
     396       10514 :   libmesh_assert(!elem->is_remote());
     397             : 
     398             :   // Clear the vector if the flag reset tells us to.
     399       26334 :   if (reset)
     400        5290 :     family.clear();
     401             : 
     402             :   // This only makes sense if we're already a topological neighbor
     403             : #ifndef NDEBUG
     404       10514 :   if (elem->level() >= neighbor_in->level())
     405        8718 :     libmesh_assert (elem->has_topological_neighbor(neighbor_in,
     406             :                                                    mesh,
     407             :                                                    point_locator,
     408             :                                                    pb));
     409             : #endif
     410             : 
     411             :   // Add an active element to the family tree.
     412       26334 :   if (elem->active())
     413       23512 :     family.push_back(elem);
     414             : 
     415             :   // Or recurse into an ancestor element's children.
     416             :   // Do not clear the vector any more.
     417        1306 :   else if (!elem->active())
     418       14110 :     for (auto & c : elem->child_ref_range())
     419       12128 :       if (!c.is_remote() &&
     420         840 :           c.has_topological_neighbor(neighbor_in, mesh, point_locator, pb))
     421       10448 :         c.active_family_tree_by_topological_neighbor
     422         840 :           (family, neighbor_in, mesh, point_locator, pb, false);
     423       26334 : }
     424             : 
     425             : 
     426             : 
     427             : template <class T>
     428             : void
     429     9672974 : find_point_neighbors(T this_elem,
     430             :                      std::set<T> & neighbor_set,
     431             :                      T start_elem)
     432             : {
     433       16767 :   libmesh_assert(start_elem);
     434       16767 :   libmesh_assert(start_elem->active());
     435       16767 :   libmesh_assert(start_elem->contains_vertex_of(this_elem, true) ||
     436             :                  this_elem->contains_vertex_of(start_elem, true));
     437             : 
     438       16767 :   neighbor_set.clear();
     439     9656207 :   neighbor_set.insert(start_elem);
     440             : 
     441       33534 :   std::set<T> untested_set, next_untested_set;
     442     9656207 :   untested_set.insert(start_elem);
     443             : 
     444    59760179 :   while (!untested_set.empty())
     445             :     {
     446             :       // Loop over all the elements in the patch that haven't already
     447             :       // been tested
     448   330020158 :       for (const auto & elem : untested_set)
     449  1447731244 :           for (auto current_neighbor : elem->neighbor_ptr_range())
     450             :             {
     451  2284549687 :               if (current_neighbor &&
     452  1117143980 :                   !current_neighbor->is_remote())    // we have a real neighbor on this side
     453             :                 {
     454     3392790 :                   if (current_neighbor->active())                // ... if it is active
     455             :                     {
     456  1081227754 :                       if (this_elem->contains_vertex_of(current_neighbor, true) // ... and touches us
     457  1082923921 :                           || current_neighbor->contains_vertex_of(this_elem, true))
     458             :                         {
     459             :                           // Make sure we'll test it
     460     1293470 :                           if (!neighbor_set.count(current_neighbor))
     461   269033602 :                             next_untested_set.insert (current_neighbor);
     462             : 
     463             :                           // And add it
     464   864857825 :                           neighbor_set.insert (current_neighbor);
     465             :                         }
     466             :                     }
     467             : #ifdef LIBMESH_ENABLE_AMR
     468             :                   else                                 // ... the neighbor is *not* active,
     469             :                     {                                  // ... so add *all* neighboring
     470             :                                                        // active children
     471         456 :                       std::vector<T> active_neighbor_children;
     472             : 
     473         456 :                       current_neighbor->active_family_tree_by_neighbor
     474     2116273 :                         (active_neighbor_children, elem);
     475             : 
     476     9020812 :                       for (const auto & current_child : active_neighbor_children)
     477             :                         {
     478    10958615 :                           if (this_elem->contains_vertex_of(current_child, true) ||
     479     4054532 :                               current_child->contains_vertex_of(this_elem, true))
     480             :                             {
     481             :                               // Make sure we'll test it
     482         328 :                               if (!neighbor_set.count(current_child))
     483      850560 :                                 next_untested_set.insert (current_child);
     484             : 
     485     2848455 :                               neighbor_set.insert (current_child);
     486             :                             }
     487             :                         }
     488             :                     }
     489             : #endif // #ifdef LIBMESH_ENABLE_AMR
     490             :                 }
     491             :             }
     492       81353 :       untested_set.swap(next_untested_set);
     493       81353 :       next_untested_set.clear();
     494             :     }
     495     9672974 : }
     496             : 
     497             : 
     498             : 
     499             : template <class T>
     500             : void
     501       11629 : find_interior_neighbors(T this_elem,
     502             :                         std::set<T> & neighbor_set)
     503             : {
     504        1268 :   neighbor_set.clear();
     505             : 
     506       23258 :   if ((this_elem->dim() >= LIBMESH_DIM) ||
     507       11629 :       !this_elem->interior_parent())
     508           0 :     return;
     509             : 
     510       11629 :   T ip = this_elem->interior_parent();
     511        1268 :   libmesh_assert (ip->contains_vertex_of(this_elem, true) ||
     512             :                   this_elem->contains_vertex_of(ip, true));
     513             : 
     514        1268 :   libmesh_assert (!ip->subactive());
     515             : 
     516             : #ifdef LIBMESH_ENABLE_AMR
     517        1268 :   while (!ip->active()) // only possible with AMR, be careful because
     518             :     {                   // ip->child_ptr(c) is only good with AMR.
     519           0 :       for (auto & child : ip->child_ref_range())
     520             :         {
     521           0 :           if (child.contains_vertex_of(this_elem, true) ||
     522           0 :               this_elem->contains_vertex_of(&child, true))
     523             :             {
     524           0 :               ip = &child;
     525           0 :               break;
     526             :             }
     527             :         }
     528             :     }
     529             : #endif
     530             : 
     531       11629 :   ElemInternal::find_point_neighbors(this_elem, neighbor_set, ip);
     532             : 
     533             :   // Now we have all point neighbors from the interior manifold, but
     534             :   // we need to weed out any neighbors that *only* intersect us at one
     535             :   // point (or at one edge, if we're a 1-D element in 3D).
     536             :   //
     537             :   // The refinement hierarchy helps us here: if the interior element
     538             :   // has a lower or equal refinement level then we can discard it iff
     539             :   // it doesn't contain all our vertices.  If it has a higher
     540             :   // refinement level then we can discard it iff we don't contain at
     541             :   // least dim()+1 of its vertices
     542        1268 :   auto it = neighbor_set.begin();
     543        1268 :   const auto end = neighbor_set.end();
     544             : 
     545       68201 :   while (it != end)
     546             :     {
     547        4524 :       auto current = it++;
     548       56572 :       T current_elem = *current;
     549             : 
     550             :       // This won't invalidate iterator it, because it is already
     551             :       // pointing to the next element
     552       56572 :       if (current_elem->level() > this_elem->level())
     553             :         {
     554          28 :           unsigned int vertices_contained = 0;
     555        1940 :           for (auto & n : current_elem->node_ref_range())
     556        1746 :             if (this_elem->contains_point(n))
     557         194 :               vertices_contained++;
     558             : 
     559         194 :           if (vertices_contained <= this_elem->dim())
     560             :             {
     561         166 :               neighbor_set.erase(current);
     562          28 :               continue;
     563             :             }
     564             :         }
     565             :       else
     566             :         {
     567      123024 :           for (auto & n : this_elem->node_ref_range())
     568             :             {
     569      106790 :               if (!current_elem->contains_point(n))
     570             :                 {
     571       37092 :                   neighbor_set.erase(current);
     572        3052 :                   break;
     573             :                 }
     574             :             }
     575             :         }
     576             :     }
     577             : }
     578             : 
     579             : } // namespace ElemInternal
     580             : } // namespace libMesh
     581             : 
     582             : #endif

Generated by: LCOV version 1.14