LCOV - code coverage report
Current view: top level - src/quadrature - quadrature_monomial_3D.C (source / functions) Hit Total Coverage
Test: libMesh/libmesh: #4229 (6a9aeb) with base 727f46 Lines: 75 88 85.2 %
Date: 2025-08-19 19:27:09 Functions: 1 1 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // The libMesh Finite Element Library.
       2             : // Copyright (C) 2002-2025 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
       3             : 
       4             : // This library is free software; you can redistribute it and/or
       5             : // modify it under the terms of the GNU Lesser General Public
       6             : // License as published by the Free Software Foundation; either
       7             : // version 2.1 of the License, or (at your option) any later version.
       8             : 
       9             : // This library is distributed in the hope that it will be useful,
      10             : // but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12             : // Lesser General Public License for more details.
      13             : 
      14             : // You should have received a copy of the GNU Lesser General Public
      15             : // License along with this library; if not, write to the Free Software
      16             : // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
      17             : 
      18             : 
      19             : 
      20             : // Local includes
      21             : #include "libmesh/quadrature_monomial.h"
      22             : #include "libmesh/quadrature_gauss.h"
      23             : 
      24             : namespace libMesh
      25             : {
      26             : 
      27             : 
      28        4828 : void QMonomial::init_3D()
      29             : {
      30             : 
      31        4828 :   switch (_type)
      32             :     {
      33             :       //---------------------------------------------
      34             :       // Hex quadrature rules
      35        1207 :     case HEX8:
      36             :     case HEX20:
      37             :     case HEX27:
      38             :       {
      39          68 :         switch(get_order())
      40             :           {
      41             : 
      42             :             // The CONSTANT/FIRST rule is the 1-point Gauss "product" rule...we fall
      43             :             // through to the default case for this rule.
      44             : 
      45         142 :           case SECOND:
      46             :           case THIRD:
      47             :             {
      48             :               // A degree 3, 6-point, "rotationally-symmetric" rule by
      49             :               // Kim and Song, Comm. Korean Math. Soc vol. 13, no. 4, 1998, pp. 913-931.
      50             :               //
      51             :               // Warning: this rule contains points on the boundary of the reference
      52             :               // element, and therefore may be unsuitable for some problems.  The alternative
      53             :               // would be a 2x2x2 Gauss product rule.
      54         142 :               const Real data[1][4] =
      55             :                 {
      56             :                   {1, 0, 0, Real(4)/3}
      57             :                 };
      58             : 
      59         142 :               const unsigned int rule_id[1] = {
      60             :                 1 // (x,0,0) -> 6 permutations
      61             :               };
      62             : 
      63         142 :               _points.resize(6);
      64         142 :               _weights.resize(6);
      65             : 
      66         142 :               kim_rule(data, rule_id, 1);
      67           4 :               return;
      68             :             } // end case SECOND,THIRD
      69             : 
      70         142 :           case FOURTH:
      71             :           case FIFTH:
      72             :             {
      73             :               // A degree 5, 13-point rule by Stroud,
      74             :               // AH Stroud, "Some Fifth Degree Integration Formulas for Symmetric Regions II.",
      75             :               // Numerische Mathematik 9, pp. 460-468 (1967).
      76             :               //
      77             :               // This rule is provably minimal in the number of points.  The equations given for
      78             :               // the n-cube on pg. 466 of the paper for mu/gamma and gamma are wrong, at least for
      79             :               // the n=3 case.  The analytical values given here were computed by me [JWP] in Maple.
      80             : 
      81             :               // Convenient intermediate values.
      82           4 :               const Real sqrt19 = std::sqrt(Real(19));            // ~4.35889894354
      83           4 :               const Real tp     = std::sqrt(71440 + 6802*sqrt19); // ~317.945326454
      84             : 
      85             :               // Point data for permutations.
      86           4 :               const Real eta    =  0;
      87             : 
      88           4 :               const Real lambda =  std::sqrt(Real(1919)/3285 - 148*sqrt19/3285 + 4*tp/3285);
      89             :               // 8.8030440669930978047737818209860e-01_R;
      90             : 
      91           4 :               const Real xi     = -std::sqrt(Real(1121)/3285 +  74*sqrt19/3285 - 2*tp/3285);
      92             :               // -4.9584817142571115281421242364290e-01_R;
      93             : 
      94           4 :               const Real mu     =  std::sqrt(Real(1121)/3285 +  74*sqrt19/3285 + 2*tp/3285);
      95             :               // 7.9562142216409541542982482567580e-01_R;
      96             : 
      97           4 :               const Real gamma  =  std::sqrt(Real(1919)/3285 - 148*sqrt19/3285 - 4*tp/3285);
      98             :               // 2.5293711744842581347389255929324e-02_R;
      99             : 
     100             :               // Weights: the centroid weight is given analytically.  Weight B (resp C) goes
     101             :               // with the {lambda,xi} (resp {gamma,mu}) permutation.  The single-precision
     102             :               // results reported by Stroud are given for reference.
     103             : 
     104           4 :               const Real A      = Real(32)/19; // ~1.684210560
     105             :               // Stroud: 0.21052632  * 8.0;
     106             : 
     107           4 :               const Real B      = Real(1) / (Real(260072)/133225  - 1520*sqrt19/133225 + (133 - 37*sqrt19)*tp/133225);
     108             :               // 5.4498735127757671684690782180890e-01_R; // Stroud: 0.068123420 * 8.0 = 0.544987360;
     109             : 
     110           4 :               const Real C      = Real(1) / (Real(260072)/133225  - 1520*sqrt19/133225 - (133 - 37*sqrt19)*tp/133225);
     111             :               // 5.0764422766979170420572375713840e-01_R; // Stroud: 0.063455527 * 8.0 = 0.507644216;
     112             : 
     113         142 :               _points.resize(13);
     114         142 :               _weights.resize(13);
     115             : 
     116           4 :               unsigned int c=0;
     117             : 
     118             :               // Point with weight A (origin)
     119         142 :               _points[c] = Point(eta, eta, eta);
     120         142 :               _weights[c++] = A;
     121             : 
     122             :               // Points with weight B
     123         142 :               _points[c] = Point(lambda, xi, xi);
     124         142 :               _weights[c++] = B;
     125         142 :               _points[c] = -_points[c-1];
     126         142 :               _weights[c++] = B;
     127             : 
     128         142 :               _points[c] = Point(xi, lambda, xi);
     129         142 :               _weights[c++] = B;
     130         142 :               _points[c] = -_points[c-1];
     131         142 :               _weights[c++] = B;
     132             : 
     133         142 :               _points[c] = Point(xi, xi, lambda);
     134         142 :               _weights[c++] = B;
     135         142 :               _points[c] = -_points[c-1];
     136         142 :               _weights[c++] = B;
     137             : 
     138             :               // Points with weight C
     139         142 :               _points[c] = Point(mu, mu, gamma);
     140         142 :               _weights[c++] = C;
     141         142 :               _points[c] = -_points[c-1];
     142         142 :               _weights[c++] = C;
     143             : 
     144         142 :               _points[c] = Point(mu, gamma, mu);
     145         142 :               _weights[c++] = C;
     146         142 :               _points[c] = -_points[c-1];
     147         142 :               _weights[c++] = C;
     148             : 
     149         142 :               _points[c] = Point(gamma, mu, mu);
     150         142 :               _weights[c++] = C;
     151         142 :               _points[c] = -_points[c-1];
     152         142 :               _weights[c++] = C;
     153             : 
     154         142 :               return;
     155             : 
     156             : 
     157             :               //       // A degree 5, 14-point, "rotationally-symmetric" rule by
     158             :               //       // Kim and Song, Comm. Korean Math. Soc vol. 13, no. 4, 1998, pp. 913-931.
     159             :               //       // Was also reported in Stroud's 1971 book.
     160             :               //       const Real data[2][4] =
     161             :               // {
     162             :               //   {7.95822425754221463264548820476135e-01_R, 0.00000000000000000000000000000000e+00_R, 0.00000000000000000000000000000000e+00_R, 8.86426592797783933518005540166204e-01_R},
     163             :               //   {7.58786910639328146269034278112267e-01_R, 7.58786910639328146269034278112267e-01_R, 7.58786910639328146269034278112267e-01_R, 3.35180055401662049861495844875346e-01_R}
     164             :               // };
     165             : 
     166             :               //       const unsigned int rule_id[2] = {
     167             :               // 1, // (x,0,0) -> 6 permutations
     168             :               // 4  // (x,x,x) -> 8 permutations
     169             :               //       };
     170             : 
     171             :               //       _points.resize(14);
     172             :               //       _weights.resize(14);
     173             : 
     174             :               //       kim_rule(data, rule_id, 2);
     175             :               //       return;
     176             :             } // end case FOURTH,FIFTH
     177             : 
     178             : 
     179         142 :           case SIXTH:
     180             :           case SEVENTH:
     181             :             {
     182         142 :               if (allow_rules_with_negative_weights)
     183             :                 {
     184             :                   // A degree 7, 31-point, "rotationally-symmetric" rule by
     185             :                   // Kim and Song, Comm. Korean Math. Soc vol. 13, no. 4, 1998, pp. 913-931.
     186             :                   // This rule contains a negative weight, so only use it if such type of
     187             :                   // rules are allowed.
     188         142 :                   const Real data[3][4] =
     189             :                     {
     190             :                       {0.00000000000000000000000000000000e+00_R, 0.00000000000000000000000000000000e+00_R, 0.00000000000000000000000000000000e+00_R, -1.27536231884057971014492753623188e+00_R},
     191             :                       {5.85540043769119907612630781744060e-01_R, 0.00000000000000000000000000000000e+00_R, 0.00000000000000000000000000000000e+00_R,  8.71111111111111111111111111111111e-01_R},
     192             :                       {6.94470135991704766602025803883310e-01_R, 9.37161638568208038511047377665396e-01_R, 4.15659267604065126239606672567031e-01_R,  1.68695652173913043478260869565217e-01_R}
     193             :                     };
     194             : 
     195         142 :                   const unsigned int rule_id[3] = {
     196             :                     0, // (0,0,0) -> 1 permutation
     197             :                     1, // (x,0,0) -> 6 permutations
     198             :                     6  // (x,y,z) -> 24 permutations
     199             :                   };
     200             : 
     201         142 :                   _points.resize(31);
     202         142 :                   _weights.resize(31);
     203             : 
     204         142 :                   kim_rule(data, rule_id, 3);
     205           4 :                   return;
     206             :                 } // end if (allow_rules_with_negative_weights)
     207             : 
     208             : 
     209             :               // A degree 7, 34-point, "fully-symmetric" rule, first published in
     210             :               // P.C. Hammer and A.H. Stroud, "Numerical Evaluation of Multiple Integrals II",
     211             :               // Mathematical Tables and Other Aids to Computation, vol 12., no 64, 1958, pp. 272-280
     212             :               //
     213             :               // This rule happens to fall under the same general
     214             :               // construction as the Kim rules, so we've re-used
     215             :               // that code here.  Stroud gives 16 digits for his rule,
     216             :               // and this is the most accurate version I've found.
     217             :               //
     218             :               // For comparison, a SEVENTH-order Gauss product rule
     219             :               // (which integrates tri-7th order polynomials) would
     220             :               // have 4^3=64 points.
     221             :               const Real
     222           0 :                 r  = std::sqrt(Real(6)/7),                                     // ~0.92582009977
     223           0 :                 s  = std::sqrt((Real(960) - 3*std::sqrt(Real(28798))) / 2726), // ~0.40670318642
     224           0 :                 t  = std::sqrt((Real(960) + 3*std::sqrt(Real(28798))) / 2726), // ~0.73411252875
     225           0 :                 B1 = Real(8624)/29160,                                         // ~0.29574759945
     226           0 :                 B2 = Real(2744)/29160,                                         // ~0.09410150891
     227           0 :                 B3 = 8*(774*t*t - 230)/(9720*(t*t-s*s)),                       // ~0.41233386227
     228           0 :                 B4 = 8*(230 - 774*s*s)/(9720*(t*t-s*s));                       // ~0.22470317477
     229             : 
     230           0 :               const Real data[4][4] =
     231             :                 {
     232             :                   {r,  0,  0, B1},
     233             :                   {r,  r,  0, B2},
     234             :                   {s,  s,  s, B3},
     235             :                   {t,  t,  t, B4}
     236             :                 };
     237             : 
     238           0 :               const unsigned int rule_id[4] = {
     239             :                 1, // (x,0,0) -> 6 permutations
     240             :                 2, // (x,x,0) -> 12 permutations
     241             :                 4, // (x,x,x) -> 8 permutations
     242             :                 4  // (x,x,x) -> 8 permutations
     243             :               };
     244             : 
     245           0 :               _points.resize(34);
     246           0 :               _weights.resize(34);
     247             : 
     248           0 :               kim_rule(data, rule_id, 4);
     249           0 :               return;
     250             : 
     251             : 
     252             :               //      // A degree 7, 38-point, "rotationally-symmetric" rule by
     253             :               //      // Kim and Song, Comm. Korean Math. Soc vol. 13, no. 4, 1998, pp. 913-931.
     254             :               //      //
     255             :               //      // This rule is obviously inferior to the 34-point rule above...
     256             :               //      const Real data[3][4] =
     257             :               //{
     258             :               //  {9.01687807821291289082811566285950e-01_R, 0.00000000000000000000000000000000e+00_R, 0.00000000000000000000000000000000e+00_R, 2.95189738262622903181631100062774e-01_R},
     259             :               //  {4.08372221499474674069588900002128e-01_R, 4.08372221499474674069588900002128e-01_R, 4.08372221499474674069588900002128e-01_R, 4.04055417266200582425904380777126e-01_R},
     260             :               //  {8.59523090201054193116477875786220e-01_R, 8.59523090201054193116477875786220e-01_R, 4.14735913727987720499709244748633e-01_R, 1.24850759678944080062624098058597e-01_R}
     261             :               //};
     262             :               //
     263             :               //      const unsigned int rule_id[3] = {
     264             :               //1, // (x,0,0) -> 6 permutations
     265             :               //4, // (x,x,x) -> 8 permutations
     266             :               //5  // (x,x,z) -> 24 permutations
     267             :               //      };
     268             :               //
     269             :               //      _points.resize(38);
     270             :               //      _weights.resize(38);
     271             :               //
     272             :               //      kim_rule(data, rule_id, 3);
     273             :               //      return;
     274             :             } // end case SIXTH,SEVENTH
     275             : 
     276          71 :           case EIGHTH:
     277             :             {
     278             :               // A degree 8, 47-point, "rotationally-symmetric" rule by
     279             :               // Kim and Song, Comm. Korean Math. Soc vol. 13, no. 4, 1998, pp. 913-931.
     280             :               //
     281             :               // A EIGHTH-order Gauss product rule (which integrates tri-8th order polynomials)
     282             :               // would have 5^3=125 points.
     283          71 :               const Real data[5][4] =
     284             :                 {
     285             :                   {0.00000000000000000000000000000000e+00_R, 0.00000000000000000000000000000000e+00_R, 0.00000000000000000000000000000000e+00_R, 4.51903714875199690490763818699555e-01_R},
     286             :                   {7.82460796435951590652813975429717e-01_R, 0.00000000000000000000000000000000e+00_R, 0.00000000000000000000000000000000e+00_R, 2.99379177352338919703385618576171e-01_R},
     287             :                   {4.88094669706366480526729301468686e-01_R, 4.88094669706366480526729301468686e-01_R, 4.88094669706366480526729301468686e-01_R, 3.00876159371240019939698689791164e-01_R},
     288             :                   {8.62218927661481188856422891110042e-01_R, 8.62218927661481188856422891110042e-01_R, 8.62218927661481188856422891110042e-01_R, 4.94843255877038125738173175714853e-02_R},
     289             :                   {2.81113909408341856058098281846420e-01_R, 9.44196578292008195318687494773744e-01_R, 6.97574833707236996779391729948984e-01_R, 1.22872389222467338799199767122592e-01_R}
     290             :                 };
     291             : 
     292          71 :               const unsigned int rule_id[5] = {
     293             :                 0, // (0,0,0) -> 1 permutation
     294             :                 1, // (x,0,0) -> 6 permutations
     295             :                 4, // (x,x,x) -> 8 permutations
     296             :                 4, // (x,x,x) -> 8 permutations
     297             :                 6  // (x,y,z) -> 24 permutations
     298             :               };
     299             : 
     300          71 :               _points.resize(47);
     301          71 :               _weights.resize(47);
     302             : 
     303          71 :               kim_rule(data, rule_id, 5);
     304           2 :               return;
     305             :             } // end case EIGHTH
     306             : 
     307             : 
     308             :             // By default: construct and use a Gauss quadrature rule
     309          20 :           default:
     310             :             {
     311             :               // Break out and fall down into the default: case for the
     312             :               // outer switch statement.
     313          20 :               break;
     314             :             }
     315             : 
     316         244 :           } // end switch(_order + 2*p)
     317             :       } // end case HEX8/20/27
     318             : 
     319             :       libmesh_fallthrough();
     320             : 
     321             :       // By default: construct and use a Gauss quadrature rule
     322             :     default:
     323             :       {
     324        4453 :         QGauss gauss_rule(3, _order);
     325        4331 :         gauss_rule.init(*this);
     326             : 
     327             :         // Swap points and weights with the about-to-be destroyed rule.
     328         122 :         _points.swap (gauss_rule.get_points() );
     329         122 :         _weights.swap(gauss_rule.get_weights());
     330             : 
     331         122 :         return;
     332             :       }
     333             :     } // end switch (_type)
     334             : }
     335             : 
     336             : } // namespace libMesh

Generated by: LCOV version 1.14