$extrastylesheet
quadrature_monomial_3D.C
Go to the documentation of this file.
00001 // The libMesh Finite Element Library.
00002 // Copyright (C) 2002-2014 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
00003 
00004 // This library is free software; you can redistribute it and/or
00005 // modify it under the terms of the GNU Lesser General Public
00006 // License as published by the Free Software Foundation; either
00007 // version 2.1 of the License, or (at your option) any later version.
00008 
00009 // This library is distributed in the hope that it will be useful,
00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012 // Lesser General Public License for more details.
00013 
00014 // You should have received a copy of the GNU Lesser General Public
00015 // License along with this library; if not, write to the Free Software
00016 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017 
00018 
00019 
00020 // Local includes
00021 #include "libmesh/quadrature_monomial.h"
00022 #include "libmesh/quadrature_gauss.h"
00023 
00024 namespace libMesh
00025 {
00026 
00027 
00028 void QMonomial::init_3D(const ElemType type_in,
00029                         unsigned int p)
00030 {
00031 
00032   switch (type_in)
00033     {
00034       //---------------------------------------------
00035       // Hex quadrature rules
00036     case HEX8:
00037     case HEX20:
00038     case HEX27:
00039       {
00040         switch(_order + 2*p)
00041           {
00042 
00043             // The CONSTANT/FIRST rule is the 1-point Gauss "product" rule...we fall
00044             // through to the default case for this rule.
00045 
00046           case SECOND:
00047           case THIRD:
00048             {
00049               // A degree 3, 6-point, "rotationally-symmetric" rule by
00050               // Kim and Song, Comm. Korean Math. Soc vol. 13, no. 4, 1998, pp. 913-931.
00051               //
00052               // Warning: this rule contains points on the boundary of the reference
00053               // element, and therefore may be unsuitable for some problems.  The alternative
00054               // would be a 2x2x2 Gauss product rule.
00055               const Real data[1][4] =
00056                 {
00057                   {1.0L, 0.0L, 0.0L, static_cast<Real>(4.0L/3.0L)}
00058                 };
00059 
00060               const unsigned int rule_id[1] = {
00061                 1 // (x,0,0) -> 6 permutations
00062               };
00063 
00064               _points.resize(6);
00065               _weights.resize(6);
00066 
00067               kim_rule(data, rule_id, 1);
00068               return;
00069             } // end case SECOND,THIRD
00070 
00071           case FOURTH:
00072           case FIFTH:
00073             {
00074               // A degree 5, 13-point rule by Stroud,
00075               // AH Stroud, "Some Fifth Degree Integration Formulas for Symmetric Regions II.",
00076               // Numerische Mathematik 9, pp. 460-468 (1967).
00077               //
00078               // This rule is provably minimal in the number of points.  The equations given for
00079               // the n-cube on pg. 466 of the paper for mu/gamma and gamma are wrong, at least for
00080               // the n=3 case.  The analytical values given here were computed by me [JWP] in Maple.
00081 
00082               // Convenient intermediate values.
00083               const Real sqrt19 = std::sqrt(19.L);
00084               const Real tp     = std::sqrt(71440.L + 6802.L*sqrt19);
00085 
00086               // Point data for permutations.
00087               const Real eta    =  0.00000000000000000000000000000000e+00L;
00088 
00089               const Real lambda =  std::sqrt(1919.L/3285.L - 148.L*sqrt19/3285.L + 4.L*tp/3285.L);
00090               // 8.8030440669930978047737818209860e-01L;
00091 
00092               const Real xi     = -std::sqrt(1121.L/3285.L +  74.L*sqrt19/3285.L - 2.L*tp/3285.L);
00093               // -4.9584817142571115281421242364290e-01L;
00094 
00095               const Real mu     =  std::sqrt(1121.L/3285.L +  74.L*sqrt19/3285.L + 2.L*tp/3285.L);
00096               // 7.9562142216409541542982482567580e-01L;
00097 
00098               const Real gamma  =  std::sqrt(1919.L/3285.L - 148.L*sqrt19/3285.L - 4.L*tp/3285.L);
00099               // 2.5293711744842581347389255929324e-02L;
00100 
00101               // Weights: the centroid weight is given analytically.  Weight B (resp C) goes
00102               // with the {lambda,xi} (resp {gamma,mu}) permutation.  The single-precision
00103               // results reported by Stroud are given for reference.
00104 
00105               const Real A      = 32.0L / 19.0L;
00106               // Stroud: 0.21052632  * 8.0 = 1.684210560;
00107 
00108               const Real B      = 1.L / ( 260072.L/133225.L  - 1520*sqrt19/133225.L + (133.L - 37.L*sqrt19)*tp/133225.L );
00109               // 5.4498735127757671684690782180890e-01L; // Stroud: 0.068123420 * 8.0 = 0.544987360;
00110 
00111               const Real C      = 1.L / ( 260072.L/133225.L  - 1520*sqrt19/133225.L - (133.L - 37.L*sqrt19)*tp/133225.L );
00112               // 5.0764422766979170420572375713840e-01L; // Stroud: 0.063455527 * 8.0 = 0.507644216;
00113 
00114               _points.resize(13);
00115               _weights.resize(13);
00116 
00117               unsigned int c=0;
00118 
00119               // Point with weight A (origin)
00120               _points[c] = Point(eta, eta, eta);
00121               _weights[c++] = A;
00122 
00123               // Points with weight B
00124               _points[c] = Point(lambda, xi, xi);
00125               _weights[c++] = B;
00126               _points[c] = -_points[c-1];
00127               _weights[c++] = B;
00128 
00129               _points[c] = Point(xi, lambda, xi);
00130               _weights[c++] = B;
00131               _points[c] = -_points[c-1];
00132               _weights[c++] = B;
00133 
00134               _points[c] = Point(xi, xi, lambda);
00135               _weights[c++] = B;
00136               _points[c] = -_points[c-1];
00137               _weights[c++] = B;
00138 
00139               // Points with weight C
00140               _points[c] = Point(mu, mu, gamma);
00141               _weights[c++] = C;
00142               _points[c] = -_points[c-1];
00143               _weights[c++] = C;
00144 
00145               _points[c] = Point(mu, gamma, mu);
00146               _weights[c++] = C;
00147               _points[c] = -_points[c-1];
00148               _weights[c++] = C;
00149 
00150               _points[c] = Point(gamma, mu, mu);
00151               _weights[c++] = C;
00152               _points[c] = -_points[c-1];
00153               _weights[c++] = C;
00154 
00155               return;
00156 
00157 
00158               //       // A degree 5, 14-point, "rotationally-symmetric" rule by
00159               //       // Kim and Song, Comm. Korean Math. Soc vol. 13, no. 4, 1998, pp. 913-931.
00160               //       // Was also reported in Stroud's 1971 book.
00161               //       const Real data[2][4] =
00162               // {
00163               //   {7.95822425754221463264548820476135e-01L, 0.00000000000000000000000000000000e+00L, 0.00000000000000000000000000000000e+00L, 8.86426592797783933518005540166204e-01L},
00164               //   {7.58786910639328146269034278112267e-01L, 7.58786910639328146269034278112267e-01L, 7.58786910639328146269034278112267e-01L, 3.35180055401662049861495844875346e-01L}
00165               // };
00166 
00167               //       const unsigned int rule_id[2] = {
00168               // 1, // (x,0,0) -> 6 permutations
00169               // 4  // (x,x,x) -> 8 permutations
00170               //       };
00171 
00172               //       _points.resize(14);
00173               //       _weights.resize(14);
00174 
00175               //       kim_rule(data, rule_id, 2);
00176               //       return;
00177             } // end case FOURTH,FIFTH
00178 
00179           case SIXTH:
00180           case SEVENTH:
00181             {
00182               if (allow_rules_with_negative_weights)
00183                 {
00184                   // A degree 7, 31-point, "rotationally-symmetric" rule by
00185                   // Kim and Song, Comm. Korean Math. Soc vol. 13, no. 4, 1998, pp. 913-931.
00186                   // This rule contains a negative weight, so only use it if such type of
00187                   // rules are allowed.
00188                   const Real data[3][4] =
00189                     {
00190                       {0.00000000000000000000000000000000e+00L, 0.00000000000000000000000000000000e+00L, 0.00000000000000000000000000000000e+00L, -1.27536231884057971014492753623188e+00L},
00191                       {5.85540043769119907612630781744060e-01L, 0.00000000000000000000000000000000e+00L, 0.00000000000000000000000000000000e+00L,  8.71111111111111111111111111111111e-01L},
00192                       {6.94470135991704766602025803883310e-01L, 9.37161638568208038511047377665396e-01L, 4.15659267604065126239606672567031e-01L,  1.68695652173913043478260869565217e-01L}
00193                     };
00194 
00195                   const unsigned int rule_id[3] = {
00196                     0, // (0,0,0) -> 1 permutation
00197                     1, // (x,0,0) -> 6 permutations
00198                     6  // (x,y,z) -> 24 permutations
00199                   };
00200 
00201                   _points.resize(31);
00202                   _weights.resize(31);
00203 
00204                   kim_rule(data, rule_id, 3);
00205                   return;
00206                 } // end if (allow_rules_with_negative_weights)
00207 
00208 
00209               // A degree 7, 34-point, "fully-symmetric" rule, first published in
00210               // P.C. Hammer and A.H. Stroud, "Numerical Evaluation of Multiple Integrals II",
00211               // Mathmatical Tables and Other Aids to Computation, vol 12., no 64, 1958, pp. 272-280
00212               //
00213               // This rule happens to fall under the same general
00214               // construction as the Kim rules, so we've re-used
00215               // that code here.  Stroud gives 16 digits for his rule,
00216               // and this is the most accurate version I've found.
00217               //
00218               // For comparison, a SEVENTH-order Gauss product rule
00219               // (which integrates tri-7th order polynomials) would
00220               // have 4^3=64 points.
00221               const Real
00222                 r  = std::sqrt(6.L/7.L),
00223                 s  = std::sqrt((960.L - 3.L*std::sqrt(28798.L)) / 2726.L),
00224                 t  = std::sqrt((960.L + 3.L*std::sqrt(28798.L)) / 2726.L),
00225                 B1 = 8624.L / 29160.L,
00226                 B2 = 2744.L / 29160.L,
00227                 B3 = 8.L*(774.L*t*t - 230.L)/(9720.L*(t*t-s*s)),
00228                 B4 = 8.L*(230.L - 774.L*s*s)/(9720.L*(t*t-s*s));
00229 
00230               const Real data[4][4] =
00231                 {
00232                   {r, 0.L, 0.L, B1},
00233                   {r,   r, 0.L, B2},
00234                   {s,   s,   s, B3},
00235                   {t,   t,   t, B4}
00236                 };
00237 
00238               const unsigned int rule_id[4] = {
00239                 1, // (x,0,0) -> 6 permutations
00240                 2, // (x,x,0) -> 12 permutations
00241                 4, // (x,x,x) -> 8 permutations
00242                 4  // (x,x,x) -> 8 permutations
00243               };
00244 
00245               _points.resize(34);
00246               _weights.resize(34);
00247 
00248               kim_rule(data, rule_id, 4);
00249               return;
00250 
00251 
00252               //      // A degree 7, 38-point, "rotationally-symmetric" rule by
00253               //      // Kim and Song, Comm. Korean Math. Soc vol. 13, no. 4, 1998, pp. 913-931.
00254               //      //
00255               //      // This rule is obviously inferior to the 34-point rule above...
00256               //      const Real data[3][4] =
00257               //{
00258               //  {9.01687807821291289082811566285950e-01L, 0.00000000000000000000000000000000e+00L, 0.00000000000000000000000000000000e+00L, 2.95189738262622903181631100062774e-01L},
00259               //  {4.08372221499474674069588900002128e-01L, 4.08372221499474674069588900002128e-01L, 4.08372221499474674069588900002128e-01L, 4.04055417266200582425904380777126e-01L},
00260               //  {8.59523090201054193116477875786220e-01L, 8.59523090201054193116477875786220e-01L, 4.14735913727987720499709244748633e-01L, 1.24850759678944080062624098058597e-01L}
00261               //};
00262               //
00263               //      const unsigned int rule_id[3] = {
00264               //1, // (x,0,0) -> 6 permutations
00265               //4, // (x,x,x) -> 8 permutations
00266               //5  // (x,x,z) -> 24 permutations
00267               //      };
00268               //
00269               //      _points.resize(38);
00270               //      _weights.resize(38);
00271               //
00272               //      kim_rule(data, rule_id, 3);
00273               //      return;
00274             } // end case SIXTH,SEVENTH
00275 
00276           case EIGHTH:
00277             {
00278               // A degree 8, 47-point, "rotationally-symmetric" rule by
00279               // Kim and Song, Comm. Korean Math. Soc vol. 13, no. 4, 1998, pp. 913-931.
00280               //
00281               // A EIGHTH-order Gauss product rule (which integrates tri-8th order polynomials)
00282               // would have 5^3=125 points.
00283               const Real data[5][4] =
00284                 {
00285                   {0.00000000000000000000000000000000e+00L, 0.00000000000000000000000000000000e+00L, 0.00000000000000000000000000000000e+00L, 4.51903714875199690490763818699555e-01L},
00286                   {7.82460796435951590652813975429717e-01L, 0.00000000000000000000000000000000e+00L, 0.00000000000000000000000000000000e+00L, 2.99379177352338919703385618576171e-01L},
00287                   {4.88094669706366480526729301468686e-01L, 4.88094669706366480526729301468686e-01L, 4.88094669706366480526729301468686e-01L, 3.00876159371240019939698689791164e-01L},
00288                   {8.62218927661481188856422891110042e-01L, 8.62218927661481188856422891110042e-01L, 8.62218927661481188856422891110042e-01L, 4.94843255877038125738173175714853e-02L},
00289                   {2.81113909408341856058098281846420e-01L, 9.44196578292008195318687494773744e-01L, 6.97574833707236996779391729948984e-01L, 1.22872389222467338799199767122592e-01L}
00290                 };
00291 
00292               const unsigned int rule_id[5] = {
00293                 0, // (0,0,0) -> 1 permutation
00294                 1, // (x,0,0) -> 6 permutations
00295                 4, // (x,x,x) -> 8 permutations
00296                 4, // (x,x,x) -> 8 permutations
00297                 6  // (x,y,z) -> 24 permutations
00298               };
00299 
00300               _points.resize(47);
00301               _weights.resize(47);
00302 
00303               kim_rule(data, rule_id, 5);
00304               return;
00305             } // end case EIGHTH
00306 
00307 
00308             // By default: construct and use a Gauss quadrature rule
00309           default:
00310             {
00311               // Break out and fall down into the default: case for the
00312               // outer switch statement.
00313               break;
00314             }
00315 
00316           } // end switch(_order + 2*p)
00317       } // end case HEX8/20/27
00318 
00319 
00320       // By default: construct and use a Gauss quadrature rule
00321     default:
00322       {
00323         QGauss gauss_rule(3, _order);
00324         gauss_rule.init(type_in, p);
00325 
00326         // Swap points and weights with the about-to-be destroyed rule.
00327         _points.swap (gauss_rule.get_points() );
00328         _weights.swap(gauss_rule.get_weights());
00329 
00330         return;
00331       }
00332     } // end switch (type_in)
00333 }
00334 
00335 } // namespace libMesh