LCOV - code coverage report
Current view: top level - src/geom - face_tri6.C (source / functions) Hit Total Coverage
Test: libMesh/libmesh: #4554 (5a536d) with base 54e0d5 Lines: 110 161 68.3 %
Date: 2026-09-16 12:37:14 Functions: 18 22 81.8 %
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             : // Local includes
      19             : #include "libmesh/edge_edge3.h"
      20             : #include "libmesh/face_tri6.h"
      21             : #include "libmesh/fe_reference_element_traits.h"
      22             : #include "libmesh/enum_io_package.h"
      23             : #include "libmesh/enum_order.h"
      24             : 
      25             : namespace libMesh
      26             : {
      27             : 
      28             : 
      29             : 
      30             : 
      31             : // ------------------------------------------------------------
      32             : // Tri6 class static member initializations
      33             : const int Tri6::num_nodes;
      34             : const int Tri6::nodes_per_side;
      35             : 
      36             : const ReferenceElementTable<Tri6::num_sides, Tri6::nodes_per_side>
      37             : Tri6::side_nodes_map = build_side_nodes<Tri6::num_sides, Tri6::nodes_per_side>(TRI6);
      38             : 
      39             : 
      40             : #ifdef LIBMESH_ENABLE_AMR
      41             : 
      42             : const Real Tri6::_embedding_matrix[Tri6::num_children][Tri6::num_nodes][Tri6::num_nodes] =
      43             :   {
      44             :     // embedding matrix for child 0
      45             :     {
      46             :       //  0      1      2    3    4    5
      47             :       { 1.0,   0.0,   0.0, 0.0, 0.0, 0.0}, // 0
      48             :       { 0.0,   0.0,   0.0, 1.0, 0.0, 0.0}, // 1
      49             :       { 0.0,   0.0,   0.0, 0.0, 0.0, 1.0}, // 2
      50             :       {.375, -.125,   0.0, .75, 0.0, 0.0}, // 3
      51             :       { 0.0, -.125, -.125, 0.5, .25, 0.5}, // 4
      52             :       {.375,   0.0, -.125, 0.0, 0.0, .75}  // 5
      53             :     },
      54             : 
      55             :     // embedding matrix for child 1
      56             :     {
      57             :       //  0      1      2    3    4    5
      58             :       {  0.0,  0.0,   0.0, 1.0, 0.0, 0.0}, // 0
      59             :       {  0.0,  1.0,   0.0, 0.0, 0.0, 0.0}, // 1
      60             :       {  0.0,  0.0,   0.0, 0.0, 1.0, 0.0}, // 2
      61             :       {-.125, .375,   0.0, .75, 0.0, 0.0}, // 3
      62             :       {  0.0, .375, -.125, 0.0, .75, 0.0}, // 4
      63             :       {-.125,  0.0, -.125, 0.5, 0.5, .25}  // 5
      64             :     },
      65             : 
      66             :     // embedding matrix for child 2
      67             :     {
      68             :       //  0       1     2    3    4    5
      69             :       {  0.0,   0.0,  0.0, 0.0, 0.0, 1.0}, // 0
      70             :       {  0.0,   0.0,  0.0, 0.0, 1.0, 0.0}, // 1
      71             :       {  0.0,   0.0,  1.0, 0.0, 0.0, 0.0}, // 2
      72             :       {-.125, -.125,  0.0, .25, 0.5, 0.5}, // 3
      73             :       {  0.0, -.125, .375, 0.0, .75, 0.0}, // 4
      74             :       {-.125,   0.0, .375, 0.0, 0.0, .75}  // 5
      75             :     },
      76             : 
      77             :     // embedding matrix for child 3
      78             :     {
      79             :       //  0       1      2    3    4    5
      80             :       {  0.0,   0.0,   0.0, 1.0, 0.0, 0.0}, // 0
      81             :       {  0.0,   0.0,   0.0, 0.0, 1.0, 0.0}, // 1
      82             :       {  0.0,   0.0,   0.0, 0.0, 0.0, 1.0}, // 2
      83             :       {-.125,   0.0, -.125, 0.5, 0.5, .25}, // 3
      84             :       {-.125, -.125,   0.0, .25, 0.5, 0.5}, // 4
      85             :       {  0.0, -.125, -.125, 0.5, .25, 0.5}  // 5
      86             :     }
      87             :   };
      88             : 
      89             : #endif
      90             : 
      91             : 
      92             : 
      93             : // ------------------------------------------------------------
      94             : // Tri6 class member functions
      95             : 
      96     9391846 : bool Tri6::is_vertex(const unsigned int i) const
      97             : {
      98     9391846 :   if (i < 3)
      99     4517123 :     return true;
     100     1492535 :   return false;
     101             : }
     102             : 
     103      521276 : bool Tri6::is_edge(const unsigned int i) const
     104             : {
     105      521276 :   if (i < 3)
     106           0 :     return false;
     107      173762 :   return true;
     108             : }
     109             : 
     110           0 : bool Tri6::is_face(const unsigned int) const
     111             : {
     112           0 :   return false;
     113             : }
     114             : 
     115      461248 : bool Tri6::is_node_on_side(const unsigned int n,
     116             :                            const unsigned int s) const
     117             : {
     118      140545 :   libmesh_assert_less (s, n_sides());
     119      140545 :   return std::find(std::begin(side_nodes_map[s]),
     120      140545 :                    std::end(side_nodes_map[s]),
     121      461248 :                    n) != std::end(side_nodes_map[s]);
     122             : }
     123             : 
     124             : std::vector<unsigned>
     125       77318 : Tri6::nodes_on_side(const unsigned int s) const
     126             : {
     127       19828 :   libmesh_assert_less(s, n_sides());
     128       77318 :   return {std::begin(side_nodes_map[s]), std::end(side_nodes_map[s])};
     129             : }
     130             : 
     131             : std::vector<unsigned>
     132         501 : Tri6::nodes_on_edge(const unsigned int e) const
     133             : {
     134         501 :   return nodes_on_side(e);
     135             : }
     136             : 
     137     2767633 : bool Tri6::has_affine_map() const
     138             : {
     139             :   // Make sure edges are straight
     140     1537608 :   Point v = this->point(1) - this->point(0);
     141     3536437 :   if (!v.relative_fuzzy_equals
     142     2767633 :       ((this->point(3) - this->point(0))*2, affine_tol))
     143         485 :     return false;
     144     3534029 :   v = this->point(2) - this->point(1);
     145     3534029 :   if (!v.relative_fuzzy_equals
     146     2765710 :       ((this->point(4) - this->point(1))*2, affine_tol))
     147          14 :     return false;
     148     3533959 :   v = this->point(2) - this->point(0);
     149     3533959 :   if (!v.relative_fuzzy_equals
     150     2765654 :       ((this->point(5) - this->point(0))*2, affine_tol))
     151          14 :     return false;
     152             : 
     153      768298 :   return true;
     154             : }
     155             : 
     156             : 
     157             : 
     158   106555997 : Order Tri6::default_order() const
     159             : {
     160   106555997 :   return SECOND;
     161             : }
     162             : 
     163             : 
     164             : 
     165         168 : dof_id_type Tri6::key (const unsigned int s) const
     166             : {
     167          42 :   libmesh_assert_less (s, this->n_sides());
     168             : 
     169         168 :   switch (s)
     170             :     {
     171          56 :     case 0:
     172             : 
     173             :       return
     174          70 :         this->compute_key (this->node_id(3));
     175             : 
     176          56 :     case 1:
     177             : 
     178             :       return
     179          70 :         this->compute_key (this->node_id(4));
     180             : 
     181          56 :     case 2:
     182             : 
     183             :       return
     184          70 :         this->compute_key (this->node_id(5));
     185             : 
     186           0 :     default:
     187           0 :       libmesh_error_msg("Invalid side s = " << s);
     188             :     }
     189             : }
     190             : 
     191             : 
     192             : 
     193    25719709 : unsigned int Tri6::local_side_node(unsigned int side,
     194             :                                    unsigned int side_node) const
     195             : {
     196     6446100 :   libmesh_assert_less (side, this->n_sides());
     197     6446100 :   libmesh_assert_less (side_node, Tri6::nodes_per_side);
     198             : 
     199    25719709 :   return Tri6::side_nodes_map[side][side_node];
     200             : }
     201             : 
     202             : 
     203             : 
     204     2446312 : std::unique_ptr<Elem> Tri6::build_side_ptr (const unsigned int i)
     205             : {
     206     2446312 :   return this->simple_build_side_ptr<Edge3, Tri6>(i);
     207             : }
     208             : 
     209             : 
     210             : 
     211       37869 : void Tri6::build_side_ptr (std::unique_ptr<Elem> & side,
     212             :                            const unsigned int i)
     213             : {
     214       37869 :   this->simple_build_side_ptr<Tri6>(side, i, EDGE3);
     215       37869 : }
     216             : 
     217             : 
     218             : 
     219           0 : void Tri6::connectivity(const unsigned int sf,
     220             :                         const IOPackage iop,
     221             :                         std::vector<dof_id_type> & conn) const
     222             : {
     223           0 :   libmesh_assert_less (sf, this->n_sub_elem());
     224           0 :   libmesh_assert_not_equal_to (iop, INVALID_IO_PACKAGE);
     225             : 
     226           0 :   switch (iop)
     227             :     {
     228           0 :     case TECPLOT:
     229             :       {
     230           0 :         conn.resize(4);
     231           0 :         switch(sf)
     232             :           {
     233           0 :           case 0:
     234             :             // linear sub-triangle 0
     235           0 :             conn[0] = this->node_id(0)+1;
     236           0 :             conn[1] = this->node_id(3)+1;
     237           0 :             conn[2] = this->node_id(5)+1;
     238           0 :             conn[3] = this->node_id(5)+1;
     239             : 
     240           0 :             return;
     241             : 
     242           0 :           case 1:
     243             :             // linear sub-triangle 1
     244           0 :             conn[0] = this->node_id(3)+1;
     245           0 :             conn[1] = this->node_id(1)+1;
     246           0 :             conn[2] = this->node_id(4)+1;
     247           0 :             conn[3] = this->node_id(4)+1;
     248             : 
     249           0 :             return;
     250             : 
     251           0 :           case 2:
     252             :             // linear sub-triangle 2
     253           0 :             conn[0] = this->node_id(5)+1;
     254           0 :             conn[1] = this->node_id(4)+1;
     255           0 :             conn[2] = this->node_id(2)+1;
     256           0 :             conn[3] = this->node_id(2)+1;
     257             : 
     258           0 :             return;
     259             : 
     260           0 :           case 3:
     261             :             // linear sub-triangle 3
     262           0 :             conn[0] = this->node_id(3)+1;
     263           0 :             conn[1] = this->node_id(4)+1;
     264           0 :             conn[2] = this->node_id(5)+1;
     265           0 :             conn[3] = this->node_id(5)+1;
     266             : 
     267           0 :             return;
     268             : 
     269           0 :           default:
     270           0 :             libmesh_error_msg("Invalid sf = " << sf);
     271             :           }
     272             :       }
     273             : 
     274           0 :     case VTK:
     275             :       {
     276             :         // VTK_QUADRATIC_TRIANGLE has same numbering as libmesh TRI6
     277           0 :         conn.resize(Tri6::num_nodes);
     278           0 :         for (auto i : index_range(conn))
     279           0 :           conn[i] = this->node_id(i);
     280           0 :         return;
     281             :       }
     282             : 
     283           0 :     default:
     284           0 :       libmesh_error_msg("Unsupported IO package " << iop);
     285             :     }
     286             : }
     287             : 
     288             : 
     289             : 
     290     1296333 : BoundingBox Tri6::loose_bounding_box () const
     291             : {
     292             :   // This might have curved edges, or might be a curved surface in
     293             :   // 3-space, in which case the full bounding box can be larger than
     294             :   // the bounding box of just the nodes.
     295             :   //
     296             :   //
     297             :   // FIXME - I haven't yet proven the formula below to be correct for
     298             :   // quadratics in 2D - RHS
     299      431461 :   Point pmin, pmax;
     300             : 
     301     5185332 :   for (unsigned d=0; d<LIBMESH_DIM; ++d)
     302             :     {
     303     5183382 :       Real center = this->point(0)(d);
     304    23333994 :       for (unsigned int p=1; p != 6; ++p)
     305    19444995 :         center += this->point(p)(d);
     306     3888999 :       center /= 6;
     307             : 
     308     5183382 :       Real hd = std::abs(center - this->point(0)(d));
     309    23333994 :       for (unsigned int p=1; p != 6; ++p)
     310    27385943 :         hd = std::max(hd, std::abs(center - this->point(p)(d)));
     311             : 
     312     3888999 :       pmin(d) = center - hd;
     313     3888999 :       pmax(d) = center + hd;
     314             :     }
     315             : 
     316     1727794 :   return BoundingBox(pmin, pmax);
     317             : }
     318             : 
     319             : 
     320             : 
     321        3821 : Real Tri6::volume () const
     322             : {
     323             :   // This specialization is good for Lagrange mappings only in general
     324        3821 :   if (this->mapping_type() != LAGRANGE_MAP)
     325        1876 :     return this->Elem::volume();
     326             : 
     327         486 :   Real vol=0.;
     328             : 
     329             : #if LIBMESH_DIM > 1
     330             :   // Make copies of our points.  It makes the subsequent calculations a bit
     331             :   // shorter and avoids dereferencing the same pointer multiple times.
     332             :   Point
     333        3397 :     x0 = point(0), x1 = point(1), x2 = point(2),
     334        2913 :     x3 = point(3), x4 = point(4), x5 = point(5);
     335             : 
     336             :   // Construct constant data vectors.
     337             :   // \vec{x}_{\xi}  = \vec{a1}*xi + \vec{b1}*eta + \vec{c1}
     338             :   // \vec{x}_{\eta} = \vec{a2}*xi + \vec{b2}*eta + \vec{c2}
     339             :   Point
     340         486 :     a1 =  4*x0 + 4*x1 - 8*x3,
     341         486 :     b1 =  4*x0 - 4*x3 + 4*x4 - 4*x5, /*=a2*/
     342         486 :     c1 = -3*x0 - 1*x1 + 4*x3,
     343         486 :     b2 =  4*x0 + 4*x2 - 8*x5,
     344         486 :     c2 = -3*x0 - 1*x2 + 4*x5;
     345             : 
     346             :   // If a1 == b1 == a2 == b2 == 0, this is a TRI6 with straight sides,
     347             :   // and we can use the TRI3 formula to compute the volume.
     348        1156 :   if (a1.relative_fuzzy_equals(Point(0,0,0)) &&
     349        2292 :       b1.relative_fuzzy_equals(Point(0,0,0)) &&
     350        1768 :       b2.relative_fuzzy_equals(Point(0,0,0)))
     351         347 :     return 0.5 * cross_norm(c1, c2);
     352             : 
     353             :   // 7-point rule, exact for quintics.
     354         401 :   const unsigned int N = 7;
     355             : 
     356             :   // Parameters of the quadrature rule
     357             :   static const Real
     358             :     w1 = Real(31)/480 + std::sqrt(Real(15))/2400,
     359             :     w2 = Real(31)/480 - std::sqrt(Real(15))/2400,
     360             :     q1 = Real(2)/7 + std::sqrt(Real(15))/21,
     361             :     q2 = Real(2)/7 - std::sqrt(Real(15))/21;
     362             : 
     363             :   static const Real xi[N]  = {Real(1)/3,  q1, q1,     1-2*q1, q2, q2,     1-2*q2};
     364             :   static const Real eta[N] = {Real(1)/3,  q1, 1-2*q1, q1,     q2, 1-2*q2, q2};
     365             :   static const Real wts[N] = {Real(9)/80, w1, w1,     w1,     w2, w2,     w2};
     366             : 
     367             :   // Approximate the area with quadrature
     368       12784 :   for (unsigned int q=0; q<N; ++q)
     369       11186 :     vol += wts[q] * cross_norm(xi[q]*a1 + eta[q]*b1 + c1,
     370       16786 :                                xi[q]*b1 + eta[q]*b2 + c2);
     371             : #endif // LIBMESH_DIM > 1
     372             : 
     373         401 :   return vol;
     374             : }
     375             : 
     376             : 
     377             : 
     378       19930 : unsigned short int Tri6::second_order_adjacent_vertex (const unsigned int n,
     379             :                                                        const unsigned int v) const
     380             : {
     381        5708 :   libmesh_assert_greater_equal (n, this->n_vertices());
     382        5708 :   libmesh_assert_less (n, this->n_nodes());
     383        5708 :   libmesh_assert_less (v, 2);
     384       19930 :   return _second_order_adjacent_vertices[n-this->n_vertices()][v];
     385             : }
     386             : 
     387             : 
     388             : 
     389             : const unsigned short int Tri6::_second_order_adjacent_vertices[Tri6::num_sides][2] =
     390             :   {
     391             :     {0, 1}, // vertices adjacent to node 3
     392             :     {1, 2}, // vertices adjacent to node 4
     393             :     {0, 2}  // vertices adjacent to node 5
     394             :   };
     395             : 
     396             : 
     397             : 
     398             : std::pair<unsigned short int, unsigned short int>
     399           0 : Tri6::second_order_child_vertex (const unsigned int n) const
     400             : {
     401           0 :   libmesh_assert_greater_equal (n, this->n_vertices());
     402           0 :   libmesh_assert_less (n, this->n_nodes());
     403           0 :   return std::pair<unsigned short int, unsigned short int>
     404           0 :     (_second_order_vertex_child_number[n],
     405           0 :      _second_order_vertex_child_index[n]);
     406             : }
     407             : 
     408             : 
     409             : 
     410             : const unsigned short int Tri6::_second_order_vertex_child_number[Tri6::num_nodes] =
     411             :   {
     412             :     99,99,99, // Vertices
     413             :     0,1,0     // Edges
     414             :   };
     415             : 
     416             : 
     417             : 
     418             : const unsigned short int Tri6::_second_order_vertex_child_index[Tri6::num_nodes] =
     419             :   {
     420             :     99,99,99, // Vertices
     421             :     1,2,2     // Edges
     422             :   };
     423             : 
     424             : 
     425       47606 : void Tri6::permute(unsigned int perm_num)
     426             : {
     427       12884 :   libmesh_assert_less (perm_num, 3);
     428             : 
     429       93816 :   for (unsigned int i = 0; i != perm_num; ++i)
     430             :     {
     431       46210 :       swap3nodes(0,1,2);
     432       33714 :       swap3nodes(3,4,5);
     433       33714 :       swap3neighbors(0,1,2);
     434             :     }
     435       47606 : }
     436             : 
     437             : 
     438         621 : void Tri6::flip(BoundaryInfo * boundary_info)
     439             : {
     440         174 :   libmesh_assert(boundary_info);
     441             : 
     442         621 :   swap2nodes(0,1);
     443         621 :   swap2nodes(4,5);
     444         174 :   swap2neighbors(1,2);
     445         621 :   swap2boundarysides(1,2,boundary_info);
     446         621 :   swap2boundaryedges(1,2,boundary_info);
     447         621 : }
     448             : 
     449             : 
     450          96 : unsigned int Tri6::center_node_on_side(const unsigned short side) const
     451             : {
     452          24 :   libmesh_assert_less (side, Tri6::num_sides);
     453          96 :   return side + 3;
     454             : }
     455             : 
     456             : 
     457             : ElemType
     458        3926 : Tri6::side_type (const unsigned int libmesh_dbg_var(s)) const
     459             : {
     460        1047 :   libmesh_assert_less (s, 3);
     461        3926 :   return EDGE3;
     462             : }
     463             : 
     464             : 
     465             : } // namespace libMesh

Generated by: LCOV version 1.14