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

Generated by: LCOV version 1.14