libMesh
quadrature_monomial_3D.C
Go to the documentation of this file.
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 
29 {
30 
31  switch (_type)
32  {
33  //---------------------------------------------
34  // Hex quadrature rules
35  case HEX8:
36  case HEX20:
37  case HEX27:
38  {
39  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  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  const Real data[1][4] =
55  {
56  {1, 0, 0, Real(4)/3}
57  };
58 
59  const unsigned int rule_id[1] = {
60  1 // (x,0,0) -> 6 permutations
61  };
62 
63  _points.resize(6);
64  _weights.resize(6);
65 
66  kim_rule(data, rule_id, 1);
67  return;
68  } // end case SECOND,THIRD
69 
70  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  const Real sqrt19 = std::sqrt(Real(19)); // ~4.35889894354
83  const Real tp = std::sqrt(71440 + 6802*sqrt19); // ~317.945326454
84 
85  // Point data for permutations.
86  const Real eta = 0;
87 
88  const Real lambda = std::sqrt(Real(1919)/3285 - 148*sqrt19/3285 + 4*tp/3285);
89  // 8.8030440669930978047737818209860e-01_R;
90 
91  const Real xi = -std::sqrt(Real(1121)/3285 + 74*sqrt19/3285 - 2*tp/3285);
92  // -4.9584817142571115281421242364290e-01_R;
93 
94  const Real mu = std::sqrt(Real(1121)/3285 + 74*sqrt19/3285 + 2*tp/3285);
95  // 7.9562142216409541542982482567580e-01_R;
96 
97  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  const Real A = Real(32)/19; // ~1.684210560
105  // Stroud: 0.21052632 * 8.0;
106 
107  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  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  _points.resize(13);
114  _weights.resize(13);
115 
116  unsigned int c=0;
117 
118  // Point with weight A (origin)
119  _points[c] = Point(eta, eta, eta);
120  _weights[c++] = A;
121 
122  // Points with weight B
123  _points[c] = Point(lambda, xi, xi);
124  _weights[c++] = B;
125  _points[c] = -_points[c-1];
126  _weights[c++] = B;
127 
128  _points[c] = Point(xi, lambda, xi);
129  _weights[c++] = B;
130  _points[c] = -_points[c-1];
131  _weights[c++] = B;
132 
133  _points[c] = Point(xi, xi, lambda);
134  _weights[c++] = B;
135  _points[c] = -_points[c-1];
136  _weights[c++] = B;
137 
138  // Points with weight C
139  _points[c] = Point(mu, mu, gamma);
140  _weights[c++] = C;
141  _points[c] = -_points[c-1];
142  _weights[c++] = C;
143 
144  _points[c] = Point(mu, gamma, mu);
145  _weights[c++] = C;
146  _points[c] = -_points[c-1];
147  _weights[c++] = C;
148 
149  _points[c] = Point(gamma, mu, mu);
150  _weights[c++] = C;
151  _points[c] = -_points[c-1];
152  _weights[c++] = C;
153 
154  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  case SIXTH:
180  case SEVENTH:
181  {
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  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  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  _points.resize(31);
202  _weights.resize(31);
203 
204  kim_rule(data, rule_id, 3);
205  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  r = std::sqrt(Real(6)/7), // ~0.92582009977
223  s = std::sqrt((Real(960) - 3*std::sqrt(Real(28798))) / 2726), // ~0.40670318642
224  t = std::sqrt((Real(960) + 3*std::sqrt(Real(28798))) / 2726), // ~0.73411252875
225  B1 = Real(8624)/29160, // ~0.29574759945
226  B2 = Real(2744)/29160, // ~0.09410150891
227  B3 = 8*(774*t*t - 230)/(9720*(t*t-s*s)), // ~0.41233386227
228  B4 = 8*(230 - 774*s*s)/(9720*(t*t-s*s)); // ~0.22470317477
229 
230  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  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  _points.resize(34);
246  _weights.resize(34);
247 
248  kim_rule(data, rule_id, 4);
249  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  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  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  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  _points.resize(47);
301  _weights.resize(47);
302 
303  kim_rule(data, rule_id, 5);
304  return;
305  } // end case EIGHTH
306 
307 
308  // By default: construct and use a Gauss quadrature rule
309  default:
310  {
311  // Break out and fall down into the default: case for the
312  // outer switch statement.
313  break;
314  }
315 
316  } // 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  QGauss gauss_rule(3, _order);
325  gauss_rule.init(*this);
326 
327  // Swap points and weights with the about-to-be destroyed rule.
328  _points.swap (gauss_rule.get_points() );
329  _weights.swap(gauss_rule.get_weights());
330 
331  return;
332  }
333  } // end switch (_type)
334 }
335 
336 } // namespace libMesh
bool allow_rules_with_negative_weights
Flag (default true) controlling the use of quadrature rules with negative weights.
Definition: quadrature.h:301
ElemType _type
The type of element for which the current values have been computed.
Definition: quadrature.h:391
const std::vector< Real > & get_weights() const
Definition: quadrature.h:168
The libMesh namespace provides an interface to certain functionality in the library.
std::vector< Point > _points
The locations of the quadrature points in reference element space.
Definition: quadrature.h:409
std::vector< Real > _weights
The quadrature weights.
Definition: quadrature.h:415
void kim_rule(const Real rule_data[][4], const unsigned int *rule_id, const unsigned int n_pts)
Rules from Kim and Song, Comm.
Definition: assembly.h:38
Order get_order() const
Definition: quadrature.h:249
virtual void init_3D() override
Initializes the 3D quadrature rule by filling the points and weights vectors with the appropriate val...
Order _order
The polynomial order which the quadrature rule is capable of integrating exactly. ...
Definition: quadrature.h:385
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
const std::vector< Point > & get_points() const
Definition: quadrature.h:156
This class implements specific orders of Gauss quadrature.
virtual void init(const Elem &e, unsigned int p_level=invalid_uint)
Initializes the data structures for a quadrature rule for the element e.
Definition: quadrature.C:65
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:39