LCOV - code coverage report
Current view: top level - src/geom - cell_polyhedron.C (source / functions) Hit Total Coverage
Test: libMesh/libmesh: #4503 (40b389) with base bc1d1a Lines: 237 316 75.0 %
Date: 2026-07-25 09:10:44 Functions: 18 28 64.3 %
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             : #include "libmesh/cell_polyhedron.h"
      19             : 
      20             : // Local includes
      21             : #include "libmesh/face_polygon.h"
      22             : #include "libmesh/enum_elem_quality.h"
      23             : #include "libmesh/hashword.h"
      24             : 
      25             : // C++ includes
      26             : #include <array>
      27             : #include <unordered_map>
      28             : #include <unordered_set>
      29             : 
      30             : 
      31             : namespace libMesh
      32             : {
      33             : 
      34             : // ------------------------------------------------------------
      35             : // Polyhedron class static member initializations
      36             : const int Polyhedron::num_children;
      37             : 
      38             : // ------------------------------------------------------------
      39             : // Polyhedron class member functions
      40             : 
      41             : 
      42        6121 : Polyhedron::Polyhedron (const std::vector<std::shared_ptr<Polygon>> & sides,
      43        6121 :                         Elem * p) :
      44         348 :     Cell(/* unused here */ 0, sides.size(), p, nullptr, nullptr),
      45         348 :     _elemlinks_data(sides.size()+2), // neighbors + parent + interior_parent
      46        5773 :     _nodelinks_data(0), // We'll have to resize *this* later too!
      47       12068 :     _sidelinks_data(sides.size())
      48             :   {
      49             :     // Set our sides, and while we're at it figure out our node maps
      50             :     // and side normal directions and edge lookup table, and count our
      51             :     // sides' nodes.  If we have internal nodes too then the subclass
      52             :     // will append those afterward.
      53        6121 :     unsigned int nn = 0;
      54         348 :     std::unordered_map<Node *, unsigned int> local_node_number;
      55             :     std::unordered_set<std::pair<const Node *, const Node *>,
      56         348 :                        libMesh::hash> edges_seen;
      57        6121 :     std::unique_ptr<const Elem> edge;
      58       43131 :     for (unsigned int s : index_range(sides))
      59             :       {
      60        1052 :         libmesh_assert(sides[s].get());
      61       37010 :         auto & side_tuple = _sidelinks_data[s];
      62        2104 :         std::get<0>(side_tuple) = sides[s];
      63             : 
      64        2104 :         Polygon & side = *sides[s]; // not const, for writeable nodes
      65      185618 :         for (auto n : make_range(side.n_nodes()))
      66             :           {
      67      152832 :             Node * node = side.node_ptr(n);
      68      148608 :             if (auto it = local_node_number.find(node);
      69        4224 :                 it != local_node_number.end())
      70             :               {
      71       99072 :                 std::get<2>(side_tuple).push_back(it->second);
      72             :               }
      73             :             else
      74             :               {
      75       49536 :                 std::get<2>(side_tuple).push_back(nn);
      76       49536 :                 local_node_number[node] = nn++;
      77       49536 :                 _nodelinks_data.push_back(node);
      78             :               }
      79             :           }
      80             : 
      81      185618 :         for (unsigned int e : make_range(side.n_edges()))
      82             :           {
      83      148608 :             side.build_edge_ptr(edge, e);
      84      148608 :             auto edge_vertices = std::make_pair(edge->node_ptr(0), edge->node_ptr(1));
      85      148608 :             if (edge_vertices.first > edge_vertices.second)
      86        2116 :               std::swap(edge_vertices.first, edge_vertices.second);
      87             : 
      88        8448 :             if (!edges_seen.count(edge_vertices))
      89             :               {
      90        2112 :                 edges_seen.insert(edge_vertices);
      91       74304 :                 _edge_lookup.emplace_back(s, e);
      92             :               }
      93             :           }
      94             :       }
      95             : 
      96             :     // Plan room for an extra node so we don't invalidate this->_nodes when we add to
      97             :     // nodelinks_data in the derived class
      98        6295 :     _nodelinks_data.reserve(_nodelinks_data.size() + 1);
      99             : 
     100             :     // Do the manual initialization that Elem::Elem and Cell::Cell
     101             :     // couldn't, now that we've resized both our vectors.  No need to
     102             :     // manually set nullptr, though, since std::vector does that.
     103        6121 :     this->_elemlinks = _elemlinks_data.data();
     104        6121 :     this->_nodes = _nodelinks_data.data();
     105        6121 :     this->_elemlinks[0] = p;
     106             : 
     107         174 :     libmesh_assert_equal_to(nn, this->n_nodes());
     108             : 
     109             :     // Figure out the orientation of our sides, now that we've got our
     110             :     // nodes organized enough to find our center.  The algorithm below
     111             :     // only works for convex polyhedra, but that's all we're
     112             :     // supporting for now.
     113         174 :     Point center;
     114       55657 :     for (auto n : make_range(nn))
     115        1408 :       center.add (this->point(n));
     116        6121 :     center /= static_cast<Real>(nn);
     117             : 
     118       43131 :     for (unsigned int s : index_range(sides))
     119             :       {
     120        2104 :         const Polygon & side = *sides[s];
     121       38062 :         const Point x_i = side.point(0);
     122             :         const Point n_i =
     123       35958 :           (side.point(1) - side.point(0)).cross
     124       38062 :           (side.point(0) - side.point(side.n_sides()-1)).unit();
     125             : 
     126        2104 :         bool & inward_normal = std::get<1>(_sidelinks_data[s]);
     127       37010 :         inward_normal = (n_i * (center - x_i) > TOLERANCE);
     128             :       }
     129             : 
     130             :     // We're betting a lot on "our polyhedra are all convex", so let's
     131             :     // check that if we have time.
     132             : #ifdef DEBUG
     133        1226 :     for (unsigned int s : index_range(sides))
     134             :       {
     135        1052 :         const Polygon & side = *sides[s];
     136        1052 :         const Point x_i = side.point(0);
     137        1052 :         const bool inward_normal = std::get<1>(this->_sidelinks_data[s]);
     138             : 
     139             :         const Point n_i =
     140        1052 :           (side.point(1) - side.point(0)).cross
     141        1052 :           (side.point(0) - side.point(side.n_sides()-1)).unit() *
     142        2104 :           (inward_normal ? -1 : 1);
     143             : 
     144        9596 :         for (const Point & node : this->node_ref_range())
     145             :           {
     146        8544 :             const Point d_n = node - x_i;
     147        8544 :             if (d_n * n_i > TOLERANCE * d_n.norm())
     148           0 :               libmesh_not_implemented_msg
     149             :                 ("Cannot create a non-convex polyhedron");
     150             :           }
     151             :       }
     152             : #endif
     153             : 
     154             :     // Is this likely to ever be used?  We may do refinement with
     155             :     // polyhedra but it's probably not going to have a hierarchy...
     156        6121 :     if (p)
     157             :       {
     158           0 :         this->subdomain_id() = p->subdomain_id();
     159           0 :         this->processor_id() = p->processor_id();
     160           0 :         _map_type = p->mapping_type();
     161           0 :         _map_data = p->mapping_data();
     162             : 
     163             : #ifdef LIBMESH_ENABLE_AMR
     164           0 :         this->set_p_level(p->p_level());
     165             : #endif
     166             :       }
     167             : 
     168             :     // Make sure the interior parent isn't undefined
     169        6121 :     this->set_interior_parent(nullptr);
     170       11894 :   }
     171             : 
     172             : 
     173             : 
     174   884547804 : Point Polyhedron::master_point (const unsigned int i) const
     175             : {
     176   957286596 :   return this->point(i);
     177             : }
     178             : 
     179             : 
     180             : 
     181           0 : bool Polyhedron::convex()
     182             : {
     183           0 :   for (unsigned int s : make_range(this->n_sides()))
     184             :     {
     185           0 :       const Polygon & side = *std::get<0>(this->_sidelinks_data[s]);
     186           0 :       const Point x_i = side.point(0);
     187           0 :       const bool inward_normal = std::get<1>(this->_sidelinks_data[s]);
     188             : 
     189             :       const Point n_i =
     190           0 :         (side.point(1) - side.point(0)).cross
     191           0 :         (side.point(0) - side.point(side.n_sides()-1)).unit() *
     192           0 :         (inward_normal ? -1 : 1);
     193             : 
     194           0 :       for (const Point & node : this->node_ref_range())
     195             :         {
     196           0 :           const Point d_n = node - x_i;
     197           0 :           if (d_n * n_i > TOLERANCE * d_n.norm())
     198           0 :             return false;
     199             :         }
     200             :     }
     201           0 :   return true;
     202             : }
     203             : 
     204             : 
     205             : 
     206      442986 : bool Polyhedron::on_reference_element(const Point & p,
     207             :                                       const Real eps) const
     208             : {
     209       57898 :   const unsigned int ns = this->n_sides();
     210             : 
     211             :   // Check that the point is on the same side of all the faces by
     212             :   // testing whether:
     213             :   //
     214             :   // n_i.(p - x_i) <= 0
     215             :   //
     216             :   // for each i, where:
     217             :   //   n_i is the outward normal of face i,
     218             :   //   x_i is a point on face i.
     219             : 
     220     2349102 :   for (auto i : make_range(ns))
     221             :     {
     222     2051436 :       const Polygon & face = *std::get<0>(this->_sidelinks_data[i]);
     223     2051436 :       const bool inward_normal = std::get<1>(this->_sidelinks_data[i]);
     224             : 
     225     2051436 :       const Point x_i = face.point(0);
     226             : 
     227             :       const Point n_i =
     228     1891928 :         (face.point(1) - face.point(0)).cross
     229     2210944 :         (face.point(0) - face.point(face.n_sides()-1)).unit() *
     230     2348284 :         (inward_normal ? -1 : 1);
     231             : 
     232             :   // This only works for polyhedra with flat sides.
     233             : #ifdef DEBUG
     234     1187392 :       for (auto j : make_range(face.n_sides()-1))
     235             :         {
     236      890544 :           const Point x_j = face.point(j+1);
     237      890544 :           const Point d_j = x_j - x_i;
     238      890544 :           if (std::abs(d_j * n_i) > eps * d_j.norm())
     239           0 :             libmesh_not_implemented_msg
     240             :               ("Polyhedra with non-flat sides are not fully supported.");
     241             :         }
     242             : #endif
     243             : 
     244     2051436 :       if (n_i * (p - x_i) > eps)
     245      133210 :         return false;
     246             :     }
     247             : 
     248       68686 :   return true;
     249             : }
     250             : 
     251             : 
     252             : 
     253           0 : dof_id_type Polyhedron::key (const unsigned int s) const
     254             : {
     255           0 :   libmesh_assert_less (s, this->n_sides());
     256             : 
     257           0 :   const Polygon & face = *std::get<0>(this->_sidelinks_data[s]);
     258             : 
     259           0 :   return face.key();
     260             : }
     261             : 
     262             : 
     263             : 
     264       36068 : dof_id_type Polyhedron::low_order_key (const unsigned int s) const
     265             : {
     266        1016 :   libmesh_assert_less (s, this->n_sides());
     267             : 
     268       36068 :   const Polygon & face = *std::get<0>(this->_sidelinks_data[s]);
     269             : 
     270        1016 :   const unsigned int nv = face.n_vertices();
     271       37084 :   std::vector<dof_id_type> vertex_ids(nv);
     272      180908 :   for (unsigned int v : make_range(nv))
     273      153000 :     vertex_ids[v] = face.node_id(v);
     274             : 
     275       37084 :   return Utility::hashword(vertex_ids);
     276             : }
     277             : 
     278             : 
     279             : 
     280           0 : unsigned int Polyhedron::local_side_node(unsigned int side,
     281             :                                          unsigned int side_node) const
     282             : {
     283           0 :   libmesh_assert_less (side, this->n_sides());
     284             : 
     285             :   const std::vector<unsigned int> & node_map =
     286           0 :     std::get<2>(this->_sidelinks_data[side]);
     287           0 :   libmesh_assert_less (side_node, node_map.size());
     288             : 
     289           0 :   return node_map[side_node];
     290             : }
     291             : 
     292             : 
     293             : 
     294        3312 : unsigned int Polyhedron::local_edge_node(unsigned int edge,
     295             :                                          unsigned int edge_node) const
     296             : {
     297         276 :   libmesh_assert_less (edge, this->n_edges());
     298         276 :   libmesh_assert_less (edge, _edge_lookup.size());
     299             : 
     300        3312 :   auto [side, edge_of_side] = _edge_lookup[edge];
     301             : 
     302        3312 :   const Polygon & face = *std::get<0>(this->_sidelinks_data[side]);
     303             : 
     304             :   const std::vector<unsigned int> & node_map =
     305         276 :     std::get<2>(this->_sidelinks_data[side]);
     306             : 
     307        3312 :   return node_map[face.local_edge_node(edge_of_side, edge_node)];
     308             : }
     309             : 
     310             : 
     311             : 
     312           0 : dof_id_type Polyhedron::key () const
     313             : {
     314           0 :   std::vector<dof_id_type> node_ids;
     315           0 :   for (const auto & n : this->node_ref_range())
     316           0 :     node_ids.push_back(n.id());
     317             : 
     318           0 :   return Utility::hashword(node_ids);
     319             : }
     320             : 
     321             : 
     322             : 
     323        2492 : std::unique_ptr<Elem> Polyhedron::side_ptr (const unsigned int i)
     324             : {
     325        2492 :   return const_cast<const Polyhedron *>(this)->side_ptr(i);
     326             : }
     327             : 
     328             : 
     329             : 
     330        3344 : std::unique_ptr<Elem> Polyhedron::side_ptr (const unsigned int i) const
     331             : {
     332         122 :   libmesh_assert_less (i, this->n_sides());
     333             : 
     334        3344 :   Polygon & face = *std::get<0>(this->_sidelinks_data[i]);
     335        3344 :   std::unique_ptr<Elem> face_copy = face.disconnected_clone();
     336       17288 :   for (auto n : face.node_index_range())
     337       14448 :     face_copy->set_node(n, face.node_ptr(n));
     338             : 
     339        3344 :   return face_copy;
     340           0 : }
     341             : 
     342             : 
     343             : 
     344        1270 : void Polyhedron::side_ptr (std::unique_ptr<Elem> & side,
     345             :                            const unsigned int i)
     346             : {
     347          51 :   libmesh_assert_less (i, this->n_sides());
     348             : 
     349             :   // Polyhedra are irregular enough that we're not even going to try
     350             :   // and bother optimizing heap access here.
     351        2438 :   side = this->side_ptr(i);
     352        1270 : }
     353             : 
     354             : 
     355             : 
     356        1222 : std::unique_ptr<Elem> Polyhedron::build_side_ptr (const unsigned int i)
     357             : {
     358        1222 :   auto returnval = this->side_ptr(i);
     359        1222 :   returnval->set_interior_parent(this);
     360        1175 :   returnval->inherit_data_from(*this);
     361        1222 :   return returnval;
     362           0 : }
     363             : 
     364             : 
     365             : 
     366        1270 : void Polyhedron::build_side_ptr (std::unique_ptr<Elem> & side,
     367             :                                  const unsigned int i)
     368             : {
     369        1270 :   this->side_ptr(side, i);
     370        1270 :   side->set_interior_parent(this);
     371        1219 :   side->inherit_data_from(*this);
     372        1270 : }
     373             : 
     374             : 
     375             : 
     376           0 : std::unique_ptr<Elem> Polyhedron::build_edge_ptr (const unsigned int i)
     377             : {
     378           0 :   auto [s, se] = _edge_lookup[i];
     379           0 :   Polygon & face = *std::get<0>(_sidelinks_data[s]);
     380           0 :   return face.build_edge_ptr(se);
     381             : }
     382             : 
     383             : 
     384             : 
     385           0 : void Polyhedron::build_edge_ptr (std::unique_ptr<Elem> & elem,
     386             :                                  const unsigned int i)
     387             : {
     388           0 :   auto [s, se] = _edge_lookup[i];
     389           0 :   Polygon & face = *std::get<0>(_sidelinks_data[s]);
     390           0 :   face.build_edge_ptr(elem, se);
     391           0 : }
     392             : 
     393             : 
     394             : 
     395           0 : bool Polyhedron::is_child_on_side(const unsigned int /*c*/,
     396             :                                   const unsigned int /*s*/) const
     397             : {
     398           0 :   libmesh_not_implemented();
     399             :   return false;
     400             : }
     401             : 
     402             : 
     403             : 
     404           0 : unsigned int Polyhedron::opposite_side(const unsigned int /* side_in */) const
     405             : {
     406             :   // This is too ambiguous in general.
     407           0 :   libmesh_not_implemented();
     408             :   return libMesh::invalid_uint;
     409             : }
     410             : 
     411             : 
     412             : 
     413           0 : unsigned int Polyhedron::opposite_node(const unsigned int /* n */,
     414             :                                        const unsigned int /* s */) const
     415             : {
     416             :   // This is too ambiguous in general.
     417           0 :   libmesh_not_implemented();
     418             :   return libMesh::invalid_uint;
     419             : }
     420             : 
     421             : 
     422             : 
     423         205 : bool Polyhedron::is_flipped() const
     424             : {
     425         205 :   if (this->_triangulation.empty())
     426           0 :     return false;
     427             : 
     428          10 :   auto & tet = this->_triangulation[0];
     429             : 
     430         215 :   const Point v01 = this->point(tet[1]) - this->point(tet[0]);
     431         205 :   const Point v02 = this->point(tet[2]) - this->point(tet[0]);
     432         205 :   const Point v03 = this->point(tet[3]) - this->point(tet[0]);
     433             : 
     434         205 :   return (triple_product(v01, v02, v03) < 0);
     435             : }
     436             : 
     437             : 
     438             : std::vector<unsigned int>
     439         420 : Polyhedron::edges_adjacent_to_node(const unsigned int n) const
     440             : {
     441          35 :   libmesh_assert_less(n, this->n_nodes());
     442             : 
     443             :   // For mid-edge or mid-face nodes, the subclass had better have
     444             :   // overridden this.
     445          35 :   libmesh_assert_less(n, this->n_vertices());
     446             : 
     447          35 :   libmesh_assert_equal_to(this->n_edges(), _edge_lookup.size());
     448             : 
     449          35 :   std::vector<unsigned int> adjacent_edges;
     450             : 
     451        5460 :   for (const auto edge : index_range(_edge_lookup))
     452             :     {
     453        5040 :       const auto [side, side_edge] = _edge_lookup[edge];
     454        5040 :       const Polygon & face = *std::get<0>(_sidelinks_data[side]);
     455             :       const std::vector<unsigned int> & node_map =
     456         420 :         std::get<2>(_sidelinks_data[side]);
     457             : 
     458         420 :       const unsigned int fnv = face.n_vertices();
     459         420 :       libmesh_assert_equal_to(fnv, face.n_edges());
     460         420 :       libmesh_assert_equal_to(fnv, face.n_sides());
     461         420 :       libmesh_assert_less_equal(fnv, node_map.size());
     462         420 :       libmesh_assert_less(side_edge, fnv);
     463             : 
     464        5040 :       const unsigned int vn = node_map[side_edge];
     465        5040 :       const unsigned int vnp = node_map[(side_edge + 1) % fnv];
     466         420 :       libmesh_assert_less(vn, this->n_vertices());
     467         420 :       libmesh_assert_less(vnp, this->n_vertices());
     468        5040 :       if (vn == n || vnp == n)
     469        1260 :         adjacent_edges.push_back(edge);
     470             :     }
     471             : 
     472         420 :   return adjacent_edges;
     473             : }
     474             : 
     475             : 
     476           0 : std::pair<Real, Real> Polyhedron::qual_bounds (const ElemQuality q) const
     477             : {
     478           0 :   std::pair<Real, Real> bounds;
     479             : 
     480           0 :   switch (q)
     481             :     {
     482           0 :     case EDGE_LENGTH_RATIO:
     483           0 :       bounds.first  = 1.;
     484           0 :       bounds.second = 4.;
     485           0 :       break;
     486             : 
     487           0 :     case MIN_ANGLE:
     488           0 :       bounds.first  = 30.;
     489           0 :       bounds.second = 180.;
     490           0 :       break;
     491             : 
     492           0 :     case MAX_ANGLE:
     493           0 :       bounds.first  = 60.;
     494           0 :       bounds.second = 180.;
     495           0 :       break;
     496             : 
     497           0 :     case JACOBIAN:
     498             :     case SCALED_JACOBIAN:
     499           0 :       bounds.first  = 0.5;
     500           0 :       bounds.second = 1.;
     501           0 :       break;
     502             : 
     503           0 :     default:
     504           0 :       libMesh::out << "Warning: Invalid quality measure chosen." << std::endl;
     505           0 :       bounds.first  = -1;
     506           0 :       bounds.second = -1;
     507             :     }
     508             : 
     509           0 :   return bounds;
     510             : }
     511             : 
     512             : 
     513             : 
     514             : std::vector<std::shared_ptr<Polygon>>
     515          15 : Polyhedron::side_clones() const
     516             : {
     517           2 :   const auto ns = this->n_sides();
     518             : 
     519           2 :   libmesh_assert_equal_to(ns, _sidelinks_data.size());
     520             : 
     521          15 :   std::vector<std::shared_ptr<Polygon>> cloned_sides(ns);
     522             : 
     523         105 :   for (auto i : make_range(ns))
     524             :     {
     525          90 :       const Polygon & face = *std::get<0>(this->_sidelinks_data[i]);
     526             : 
     527          90 :       Elem * clone = face.disconnected_clone().release();
     528          12 :       Polygon * polygon_clone = cast_ptr<Polygon *>(clone);
     529          90 :       cloned_sides[i] = std::shared_ptr<Polygon>(polygon_clone);
     530             : 
     531             :       // We can't actually use a *disconnected* clone to reconstruct
     532             :       // links between sides, so we'll temporarily give the clone our
     533             :       // own nodes; user code that typically replaces the usual
     534             :       // nullptr with permanent nodes will then instead place our
     535             :       // nodes with permanent nodes.
     536         528 :       for (auto n : make_range(face.n_nodes()))
     537          96 :         cloned_sides[i]->set_node
     538         408 :           (n, const_cast<Node *>(face.node_ptr(n)));
     539             :     }
     540             : 
     541          17 :   return cloned_sides;
     542           0 : }
     543             : 
     544             : 
     545             : 
     546        2304 : bool Polyhedron::side_has_edge_nodes(unsigned int s,
     547             :                                      unsigned int min_node,
     548             :                                      unsigned int max_node) const
     549             : {
     550        2304 :   const Polygon & face = *std::get<0>(_sidelinks_data[s]);
     551             :   const std::vector<unsigned int> & node_map =
     552         192 :     std::get<2>(this->_sidelinks_data[s]);
     553             : 
     554        9780 :   for (unsigned int e : make_range(face.n_sides()))
     555             :     {
     556             :       std::vector<unsigned int> nodes_on_edge =
     557        8196 :         face.nodes_on_side(e);
     558         683 :       libmesh_assert_equal_to(nodes_on_edge.size(), 2);
     559        8196 :       nodes_on_edge[0] = node_map[nodes_on_edge[0]];
     560        8196 :       nodes_on_edge[1] = node_map[nodes_on_edge[1]];
     561        8271 :       if ((nodes_on_edge[0] == min_node) &&
     562          75 :           (nodes_on_edge[1] == max_node))
     563          50 :         return true;
     564        7981 :       if ((nodes_on_edge[1] == min_node) &&
     565          85 :           (nodes_on_edge[0] == max_node))
     566          70 :         return true;
     567             :     }
     568             : 
     569         264 :   return false;
     570             : }
     571             : 
     572             : 
     573             : 
     574             : std::vector<unsigned int>
     575         576 : Polyhedron::sides_on_edge(const unsigned int e) const
     576             : {
     577         576 :   std::vector<unsigned int> returnval(2);
     578         576 :   auto [s1, s1e] = _edge_lookup[e];
     579         576 :   returnval[0] = s1;
     580             : 
     581         576 :   const Polygon & face1 = *std::get<0>(_sidelinks_data[s1]);
     582             :   const std::vector<unsigned int> & node_map =
     583          48 :     std::get<2>(this->_sidelinks_data[s1]);
     584             : 
     585             :   std::vector<unsigned int> nodes_on_edge =
     586         576 :     face1.nodes_on_side(s1e);
     587          48 :   libmesh_assert_equal_to(nodes_on_edge.size(), 2);
     588         576 :   nodes_on_edge[0] = node_map[nodes_on_edge[0]];
     589         576 :   nodes_on_edge[1] = node_map[nodes_on_edge[1]];
     590             : 
     591         576 :   if (nodes_on_edge[0] > nodes_on_edge[1])
     592          12 :     std::swap(nodes_on_edge[0], nodes_on_edge[1]);
     593             : 
     594        2736 :   for (unsigned int s2 : make_range(this->n_sides()))
     595             :     {
     596        2736 :       if (s2 == s1)
     597         528 :         continue;
     598             : 
     599        2160 :       if (this->side_has_edge_nodes(s2, nodes_on_edge[0],
     600         360 :                                     nodes_on_edge[1]))
     601             :         {
     602         576 :           returnval[1] = s2;
     603         624 :           return returnval;
     604             :         }
     605             :     }
     606             : 
     607           0 :   libmesh_error();
     608             : 
     609             :   return returnval;
     610             : }
     611             : 
     612             : 
     613             : 
     614         288 : bool Polyhedron::is_edge_on_side(const unsigned int e,
     615             :                                  const unsigned int s) const
     616             : {
     617         288 :   auto [s1, s1e] = _edge_lookup[e];
     618             : 
     619             :   // Did we get lucky with our cache?
     620         288 :   if (s1 == s)
     621          12 :     return true;
     622             : 
     623         144 :   const Polygon & face1 = *std::get<0>(_sidelinks_data[s1]);
     624             :   const std::vector<unsigned int> & node_map =
     625          12 :     std::get<2>(this->_sidelinks_data[s1]);
     626             :   std::vector<unsigned int> nodes_on_edge1 =
     627         156 :     face1.nodes_on_side(s1e);
     628          12 :   libmesh_assert_equal_to(nodes_on_edge1.size(), 2);
     629             : 
     630         144 :   nodes_on_edge1[0] = node_map[nodes_on_edge1[0]];
     631         144 :   nodes_on_edge1[1] = node_map[nodes_on_edge1[1]];
     632         144 :   if (nodes_on_edge1[0] > nodes_on_edge1[1])
     633           3 :     std::swap(nodes_on_edge1[0], nodes_on_edge1[1]);
     634             : 
     635         144 :   return this->side_has_edge_nodes(s,
     636          12 :                                    nodes_on_edge1[0],
     637          24 :                                    nodes_on_edge1[1]);
     638             : }
     639             : 
     640             : 
     641             : 
     642   221136927 : std::array<Point, 4> Polyhedron::master_subelement (unsigned int i) const
     643             : {
     644    19024346 :   libmesh_assert_less(i, this->_triangulation.size());
     645             : 
     646   221136927 :   const auto & tet = this->_triangulation[i];
     647             : 
     648   221136927 :   return { this->master_point(tet[0]),
     649   221136927 :            this->master_point(tet[1]),
     650   221136927 :            this->master_point(tet[2]),
     651   221136927 :            this->master_point(tet[3]) };
     652             : }
     653             : 
     654             : 
     655             : 
     656             : std::tuple<unsigned int, Real, Real, Real>
     657    58943010 : Polyhedron::subelement_coordinates (const Point & p, Real tol) const
     658             : {
     659     5071145 :   std::tuple<unsigned int, Real, Real, Real> returnval =
     660             :     {libMesh::invalid_uint, -1, -1, -1};
     661             : 
     662     5071145 :   Real best_bad_coord = -1;
     663             : 
     664   204762016 :   for (auto s : make_range(this->n_subelements()))
     665             :     {
     666             :       const std::array<Point, 4> subtet =
     667   199861240 :         this->master_subelement(s);
     668             : 
     669             :       // Find barycentric coordinates in subelem
     670    17257345 :       const Point v0 = p - subtet[0];
     671             :       // const Point v1 = p - subtet[1];
     672             : 
     673    17257345 :       const Point v01 = subtet[1] - subtet[0];
     674    17257345 :       const Point v02 = subtet[2] - subtet[0];
     675    17257345 :       const Point v03 = subtet[3] - subtet[0];
     676             : 
     677             :       // const Point v12 = subtet[2] - subtet[1];
     678             :       // const Point v13 = subtet[3] - subtet[1];
     679             : 
     680             :       // const Real tp0 = triple_product(v1, v13, v12);
     681   183443545 :       const Real tp1 = triple_product(v0, v02, v03);
     682   183443545 :       const Real tp2 = triple_product(v0, v03, v01);
     683   183443545 :       const Real tp3 = triple_product(v0, v01, v02);
     684             : 
     685   183443545 :       const Real six_vol = triple_product(v01, v02, v03);
     686             : 
     687   199861240 :       const Real xi   = tp1 / six_vol;
     688   199861240 :       const Real eta  = tp2 / six_vol;
     689   199861240 :       const Real zeta = tp3 / six_vol;
     690             : 
     691   199861240 :       if (xi>=0 && eta>=0 && zeta>=0 && xi+eta+zeta<=1)
     692    54042234 :         return { s, xi, eta, zeta };
     693             : 
     694             :       const Real my_best_bad_coord =
     695   145819006 :         std::min(std::min(std::min(xi, eta), zeta), 1-xi-eta-zeta);
     696             : 
     697   145819006 :       if (my_best_bad_coord > best_bad_coord)
     698             :         {
     699     5202878 :           best_bad_coord = my_best_bad_coord;
     700     5202878 :           returnval = { s, xi, eta, zeta };
     701             :         }
     702             :     }
     703             : 
     704     4900776 :   if (best_bad_coord > -tol)
     705      408398 :     return returnval;
     706             : 
     707           0 :   return {libMesh::invalid_uint, -1, -1, -1};
     708             : }
     709             : 
     710             : 
     711             : } // namespace libMesh

Generated by: LCOV version 1.14