libMesh
quadrature_gauss_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_gauss.h"
22 #include "libmesh/quadrature_conical.h"
23 #include "libmesh/quadrature_gm.h"
24 #include "libmesh/enum_to_string.h"
25 #include "libmesh/cell_c0polyhedron.h"
26 
27 namespace libMesh
28 {
29 
31 {
32 #if LIBMESH_DIM == 3
33 
34  //-----------------------------------------------------------------------
35  // 3D quadrature rules
36  switch (_type)
37  {
38  //---------------------------------------------
39  // Hex quadrature rules
40  case HEX8:
41  case HEX20:
42  case HEX27:
43  {
44  // We compute the 3D quadrature rule as a tensor
45  // product of the 1D quadrature rule.
46  QGauss q1D(1, get_order());
47  tensor_product_hex( q1D );
48  return;
49  }
50 
51 
52 
53  //---------------------------------------------
54  // Tetrahedral quadrature rules
55  case TET4:
56  case TET10:
57  case TET14:
58  {
59  switch(get_order())
60  {
61  // Taken from pg. 222 of "The finite element method," vol. 1
62  // ed. 5 by Zienkiewicz & Taylor
63  case CONSTANT:
64  case FIRST:
65  {
66  // Exact for linears
67  _points.resize(1);
68  _weights.resize(1);
69 
70 
71  _points[0](0) = .25;
72  _points[0](1) = .25;
73  _points[0](2) = .25;
74 
75  _weights[0] = Real(1)/6;
76 
77  return;
78  }
79  case SECOND:
80  {
81  // Exact for quadratics
82  _points.resize(4);
83  _weights.resize(4);
84 
85 
86  // Can't be constexpr with my version of Boost quad
87  // precision
88  const Real b = 0.25*(1-std::sqrt(Real(5))/5);
89  const Real a = 1-3*b;
90 
91  _points[0](0) = a;
92  _points[0](1) = b;
93  _points[0](2) = b;
94 
95  _points[1](0) = b;
96  _points[1](1) = a;
97  _points[1](2) = b;
98 
99  _points[2](0) = b;
100  _points[2](1) = b;
101  _points[2](2) = a;
102 
103  _points[3](0) = b;
104  _points[3](1) = b;
105  _points[3](2) = b;
106 
107 
108 
109  _weights[0] = Real(1)/24;
110  _weights[1] = _weights[0];
111  _weights[2] = _weights[0];
112  _weights[3] = _weights[0];
113 
114  return;
115  }
116 
117 
118 
119  // Can be found in the class notes
120  // http://www.cs.rpi.edu/~flaherje/FEM/fem6.ps
121  // by Flaherty.
122  //
123  // Caution: this rule has a negative weight and may be
124  // unsuitable for some problems.
125  // Exact for cubics.
126  //
127  // Note: Keast (see ref. elsewhere in this file) also gives
128  // a third-order rule with positive weights, but it contains points
129  // on the ref. elt. boundary, making it less suitable for FEM calculations.
130  case THIRD:
131  {
133  {
134  _points.resize(5);
135  _weights.resize(5);
136 
137 
138  _points[0](0) = .25;
139  _points[0](1) = .25;
140  _points[0](2) = .25;
141 
142  _points[1](0) = .5;
143  _points[1](1) = Real(1)/6;
144  _points[1](2) = Real(1)/6;
145 
146  _points[2](0) = Real(1)/6;
147  _points[2](1) = .5;
148  _points[2](2) = Real(1)/6;
149 
150  _points[3](0) = Real(1)/6;
151  _points[3](1) = Real(1)/6;
152  _points[3](2) = .5;
153 
154  _points[4](0) = Real(1)/6;
155  _points[4](1) = Real(1)/6;
156  _points[4](2) = Real(1)/6;
157 
158 
159  _weights[0] = Real(-2)/15;
160  _weights[1] = .075;
161  _weights[2] = _weights[1];
162  _weights[3] = _weights[1];
163  _weights[4] = _weights[1];
164 
165  return;
166  } // end if (allow_rules_with_negative_weights)
167  else
168  {
169  // If a rule with positive weights is required, the 2x2x2 conical
170  // product rule is third-order accurate and has less points than
171  // the next-available positive-weight rule at FIFTH order.
172  QConical conical_rule(3, _order);
173  conical_rule.init(*this);
174 
175  // Swap points and weights with the about-to-be destroyed rule.
176  _points.swap (conical_rule.get_points() );
177  _weights.swap(conical_rule.get_weights());
178 
179  return;
180  }
181  // Note: if !allow_rules_with_negative_weights, fall through to next case.
182  }
183 
184 
185 
186  // Originally a Keast rule,
187  // Patrick Keast,
188  // Moderate Degree Tetrahedral Quadrature Formulas,
189  // Computer Methods in Applied Mechanics and Engineering,
190  // Volume 55, Number 3, May 1986, pages 339-348.
191  //
192  // Can also be found the class notes
193  // http://www.cs.rpi.edu/~flaherje/FEM/fem6.ps
194  // by Flaherty.
195  //
196  // Caution: this rule has a negative weight and may be
197  // unsuitable for some problems.
198  case FOURTH:
199  {
201  {
202  _points.resize(11);
203  _weights.resize(11);
204 
205  // The raw data for the quadrature rule.
206  const Real rule_data[3][4] = {
207  {0.250000000000000000e+00_R, 0._R, 0._R, -0.131555555555555556e-01_R}, // 1
208  {0.785714285714285714e+00_R, 0.714285714285714285e-01_R, 0._R, 0.762222222222222222e-02_R}, // 4
209  {0.399403576166799219e+00_R, 0._R, 0.100596423833200785e+00_R, 0.248888888888888889e-01_R} // 6
210  };
211 
212 
213  // Now call the keast routine to generate _points and _weights
214  keast_rule(rule_data, 3);
215 
216  return;
217  } // end if (allow_rules_with_negative_weights)
218  // Note: if !allow_rules_with_negative_weights, fall through to next case.
219  }
220 
221  libmesh_fallthrough();
222 
223 
224  // Walkington's fifth-order 14-point rule from
225  // "Quadrature on Simplices of Arbitrary Dimension"
226  //
227  // We originally had a Keast rule here, but this rule had
228  // more points than an equivalent rule by Walkington and
229  // also contained points on the boundary of the ref. elt,
230  // making it less suitable for FEM calculations.
231  case FIFTH:
232  {
233  _points.resize(14);
234  _weights.resize(14);
235 
236  // permutations of these points and suitably-modified versions of
237  // these points are the quadrature point locations
238  const Real a[3] = {0.31088591926330060980_R, // a1 from the paper
239  0.092735250310891226402_R, // a2 from the paper
240  0.045503704125649649492_R}; // a3 from the paper
241 
242  // weights. a[] and wt[] are the only floating-point inputs required
243  // for this rule.
244  const Real wt[3] = {0.018781320953002641800_R, // w1 from the paper
245  0.012248840519393658257_R, // w2 from the paper
246  0.0070910034628469110730_R}; // w3 from the paper
247 
248  // The first two sets of 4 points are formed in a similar manner
249  for (unsigned int i=0; i<2; ++i)
250  {
251  // Where we will insert values into _points and _weights
252  const unsigned int offset=4*i;
253 
254  // Stuff points and weights values into their arrays
255  const Real b = 1. - 3.*a[i];
256 
257  // Here are the permutations. Order of these is not important,
258  // all have the same weight
259  _points[offset + 0] = Point(a[i], a[i], a[i]);
260  _points[offset + 1] = Point(a[i], b, a[i]);
261  _points[offset + 2] = Point( b, a[i], a[i]);
262  _points[offset + 3] = Point(a[i], a[i], b);
263 
264  // These 4 points all have the same weights
265  for (unsigned int j=0; j<4; ++j)
266  _weights[offset + j] = wt[i];
267  } // end for
268 
269 
270  {
271  // The third set contains 6 points and is formed a little differently
272  const unsigned int offset = 8;
273  const Real b = 0.5*(1. - 2.*a[2]);
274 
275  // Here are the permutations. Order of these is not important,
276  // all have the same weight
277  _points[offset + 0] = Point(b , b, a[2]);
278  _points[offset + 1] = Point(b , a[2], a[2]);
279  _points[offset + 2] = Point(a[2], a[2], b);
280  _points[offset + 3] = Point(a[2], b, a[2]);
281  _points[offset + 4] = Point( b, a[2], b);
282  _points[offset + 5] = Point(a[2], b, b);
283 
284  // These 6 points all have the same weights
285  for (unsigned int j=0; j<6; ++j)
286  _weights[offset + j] = wt[2];
287  }
288 
289 
290  // Original rule by Keast, unsuitable because it has points on the
291  // reference element boundary!
292  // _points.resize(15);
293  // _weights.resize(15);
294 
295  // _points[0](0) = 0.25;
296  // _points[0](1) = 0.25;
297  // _points[0](2) = 0.25;
298 
299  // {
300  // const Real a = 0.;
301  // const Real b = Real(1)/3;
302 
303  // _points[1](0) = a;
304  // _points[1](1) = b;
305  // _points[1](2) = b;
306 
307  // _points[2](0) = b;
308  // _points[2](1) = a;
309  // _points[2](2) = b;
310 
311  // _points[3](0) = b;
312  // _points[3](1) = b;
313  // _points[3](2) = a;
314 
315  // _points[4](0) = b;
316  // _points[4](1) = b;
317  // _points[4](2) = b;
318  // }
319  // {
320  // const Real a = Real(8)/11;
321  // const Real b = Real(1)/11;
322 
323  // _points[5](0) = a;
324  // _points[5](1) = b;
325  // _points[5](2) = b;
326 
327  // _points[6](0) = b;
328  // _points[6](1) = a;
329  // _points[6](2) = b;
330 
331  // _points[7](0) = b;
332  // _points[7](1) = b;
333  // _points[7](2) = a;
334 
335  // _points[8](0) = b;
336  // _points[8](1) = b;
337  // _points[8](2) = b;
338  // }
339  // {
340  // const Real a = 0.066550153573664;
341  // const Real b = 0.433449846426336;
342 
343  // _points[9](0) = b;
344  // _points[9](1) = a;
345  // _points[9](2) = a;
346 
347  // _points[10](0) = a;
348  // _points[10](1) = a;
349  // _points[10](2) = b;
350 
351  // _points[11](0) = a;
352  // _points[11](1) = b;
353  // _points[11](2) = b;
354 
355  // _points[12](0) = b;
356  // _points[12](1) = a;
357  // _points[12](2) = b;
358 
359  // _points[13](0) = b;
360  // _points[13](1) = b;
361  // _points[13](2) = a;
362 
363  // _points[14](0) = a;
364  // _points[14](1) = b;
365  // _points[14](2) = a;
366  // }
367 
368  // _weights[0] = 0.030283678097089;
369  // _weights[1] = 0.006026785714286;
370  // _weights[2] = _weights[1];
371  // _weights[3] = _weights[1];
372  // _weights[4] = _weights[1];
373  // _weights[5] = 0.011645249086029;
374  // _weights[6] = _weights[5];
375  // _weights[7] = _weights[5];
376  // _weights[8] = _weights[5];
377  // _weights[9] = 0.010949141561386;
378  // _weights[10] = _weights[9];
379  // _weights[11] = _weights[9];
380  // _weights[12] = _weights[9];
381  // _weights[13] = _weights[9];
382  // _weights[14] = _weights[9];
383 
384  return;
385  }
386 
387 
388 
389 
390  // This rule is originally from Keast:
391  // Patrick Keast,
392  // Moderate Degree Tetrahedral Quadrature Formulas,
393  // Computer Methods in Applied Mechanics and Engineering,
394  // Volume 55, Number 3, May 1986, pages 339-348.
395  //
396  // It is accurate on 6th-degree polynomials and has 24 points
397  // vs. 64 for the comparable conical product rule.
398  //
399  // Values copied 24th June 2008 from:
400  // http://people.scs.fsu.edu/~burkardt/f_src/keast/keast.f90
401  case SIXTH:
402  {
403  _points.resize (24);
404  _weights.resize(24);
405 
406  // The raw data for the quadrature rule.
407  const Real rule_data[4][4] = {
408  {0.356191386222544953e+00_R , 0.214602871259151684e+00_R , 0._R, 0.00665379170969464506e+00_R}, // 4
409  {0.877978124396165982e+00_R , 0.0406739585346113397e+00_R, 0._R, 0.00167953517588677620e+00_R}, // 4
410  {0.0329863295731730594e+00_R, 0.322337890142275646e+00_R , 0._R, 0.00922619692394239843e+00_R}, // 4
411  {0.0636610018750175299e+00_R, 0.269672331458315867e+00_R , 0.603005664791649076e+00_R, 0.00803571428571428248e+00_R} // 12
412  };
413 
414 
415  // Now call the keast routine to generate _points and _weights
416  keast_rule(rule_data, 4);
417 
418  return;
419  }
420 
421 
422  // Keast's 31 point, 7th-order rule contains points on the reference
423  // element boundary, so we've decided not to include it here.
424  //
425  // Keast's 8th-order rule has 45 points. and a negative
426  // weight, so if you've explicitly disallowed such rules
427  // you will fall through to the conical product rules
428  // below.
429  case SEVENTH:
430  case EIGHTH:
431  {
433  {
434  _points.resize (45);
435  _weights.resize(45);
436 
437  // The raw data for the quadrature rule.
438  const Real rule_data[7][4] = {
439  {0.250000000000000000e+00_R, 0._R, 0._R, -0.393270066412926145e-01_R}, // 1
440  {0.617587190300082967e+00_R, 0.127470936566639015e+00_R, 0._R, 0.408131605934270525e-02_R}, // 4
441  {0.903763508822103123e+00_R, 0.320788303926322960e-01_R, 0._R, 0.658086773304341943e-03_R}, // 4
442  {0.497770956432810185e-01_R, 0._R, 0.450222904356718978e+00_R, 0.438425882512284693e-02_R}, // 6
443  {0.183730447398549945e+00_R, 0._R, 0.316269552601450060e+00_R, 0.138300638425098166e-01_R}, // 6
444  {0.231901089397150906e+00_R, 0.229177878448171174e-01_R, 0.513280033360881072e+00_R, 0.424043742468372453e-02_R}, // 12
445  {0.379700484718286102e-01_R, 0.730313427807538396e+00_R, 0.193746475248804382e+00_R, 0.223873973961420164e-02_R} // 12
446  };
447 
448 
449  // Now call the keast routine to generate _points and _weights
450  keast_rule(rule_data, 7);
451 
452  return;
453  } // end if (allow_rules_with_negative_weights)
454  // Note: if !allow_rules_with_negative_weights, fall through to next case.
455  }
456 
457  libmesh_fallthrough();
458 
459 
460  // Fall back on Grundmann-Moller or Conical Product rules at high orders.
461  default:
462  {
464  {
465  // The Grundmann-Moller rules are defined to arbitrary order and
466  // can have significantly fewer evaluation points than conical product
467  // rules. If you allow rules with negative weights, the GM rules
468  // will be more efficient for degree up to 33 (for degree 34 and
469  // higher, CP is more efficient!) but may be more susceptible
470  // to round-off error. Safest is to disallow rules with negative
471  // weights, but this decision should be made on a case-by-case basis.
472  QGrundmann_Moller gm_rule(3, _order);
473  gm_rule.init(*this);
474 
475  // Swap points and weights with the about-to-be destroyed rule.
476  _points.swap (gm_rule.get_points() );
477  _weights.swap(gm_rule.get_weights());
478 
479  return;
480  }
481 
482  else
483  {
484  // The following quadrature rules are generated as
485  // conical products. These tend to be non-optimal
486  // (use too many points, cluster points in certain
487  // regions of the domain) but they are quite easy to
488  // automatically generate using a 1D Gauss rule on
489  // [0,1] and two 1D Jacobi-Gauss rules on [0,1].
490  QConical conical_rule(3, _order);
491  conical_rule.init(*this);
492 
493  // Swap points and weights with the about-to-be destroyed rule.
494  _points.swap (conical_rule.get_points() );
495  _weights.swap(conical_rule.get_weights());
496 
497  return;
498  }
499  }
500  }
501  } // end case TET
502 
503 
504 
505  //---------------------------------------------
506  // Prism quadrature rules
507  case PRISM6:
508  case PRISM15:
509  case PRISM18:
510  case PRISM20:
511  case PRISM21:
512  {
513  // We compute the 3D quadrature rule as a tensor
514  // product of the 1D quadrature rule and a 2D
515  // triangle quadrature rule
516 
517  QGauss q1D(1,get_order());
518  QGauss q2D(2,_order);
519 
520  // Initialize the 2D rule (1D is pre-initialized)
521  q2D.init(TRI3, _p_level, /*simple_type_only=*/true);
522 
523  tensor_product_prism(q1D, q2D);
524 
525  return;
526  }
527 
528 
529 
530  //---------------------------------------------
531  // Pyramid
532  case PYRAMID5:
533  case PYRAMID13:
534  case PYRAMID14:
535  case PYRAMID18:
536  {
537  // We compute the Pyramid rule as a conical product of a
538  // Jacobi rule with alpha==2 on the interval [0,1] two 1D
539  // Gauss rules with suitably modified points. The idea comes
540  // from: Stroud, A.H. "Approximate Calculation of Multiple
541  // Integrals."
542  QConical conical_rule(3, _order);
543  conical_rule.init(*this);
544 
545  // Swap points and weights with the about-to-be destroyed rule.
546  _points.swap (conical_rule.get_points() );
547  _weights.swap(conical_rule.get_weights());
548 
549  return;
550 
551  }
552 
553 
554  //---------------------------------------------
555  // Arbitrary polyhedron quadrature rules
556  case C0POLYHEDRON:
557  {
558  QGauss tet_rule(3, _order);
559  tet_rule.init(TET4, _p_level, true);
560 
561  std::vector<Point> & tetpoints = tet_rule.get_points();
562  std::vector<Real> & tetweights = tet_rule.get_weights();
563 
564  std::size_t numtetpts = tetpoints.size();
565 
566  // C0Polyhedron requires the newer Quadrature API
567  if (!_elem)
568  libmesh_error();
569 
571 
572  const C0Polyhedron & poly = *cast_ptr<const C0Polyhedron *>(_elem);
573 
574  std::size_t numtets = poly.n_subelements();
575  _points.resize(numtetpts*numtets);
576  _weights.resize(numtetpts*numtets);
577 
578  for (std::size_t t = 0; t != numtets; ++t)
579  {
580  auto master_points = poly.master_subelement(t);
581 
582  const Point v01 = master_points[1] - master_points[0];
583  const Point v02 = master_points[2] - master_points[0];
584  const Point v03 = master_points[3] - master_points[0];
585 
586  // The factor of one sixth from the tetweights cancels out
587  // the factor of six here, so we don't need to do so
588  // ourselves.
589  const Real six_master_tet_vol =
590  triple_product(v01, v02, v03);
591 
592  for (std::size_t i = 0; i != numtetpts; ++i)
593  {
594  _points[numtetpts*t+i] =
595  master_points[0] +
596  v01 * tetpoints[i](0) +
597  v02 * tetpoints[i](1) +
598  v03 * tetpoints[i](2);
599  _weights[numtetpts*t+i] = tetweights[i] *
600  six_master_tet_vol;
601  }
602  }
603  return;
604  }
605 
606  //---------------------------------------------
607  // Unsupported type
608  default:
609  libmesh_error_msg("ERROR: Unsupported type: " << Utility::enum_to_string(_type));
610  }
611 #endif
612 }
613 
614 } // 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
const Elem * _elem
The element for which the current values were computed, or nullptr if values were computed without a ...
Definition: quadrature.h:397
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 tensor_product_prism(const QBase &q1D, const QBase &q2D)
Computes the tensor product of a 1D quadrature rule and a 2D quadrature rule.
Definition: quadrature.C:310
unsigned int _p_level
The p-level of the element for which the current values have been computed.
Definition: quadrature.h:403
T triple_product(const TypeVector< T > &a, const TypeVector< T > &b, const TypeVector< T > &c)
Definition: type_vector.h:1029
void tensor_product_hex(const QBase &q1D)
Computes the tensor product quadrature rule [q1D x q1D x q1D] from the 1D rule q1D.
Definition: quadrature.C:283
unsigned int n_subelements() const
libmesh_assert(ctx)
Order get_order() const
Definition: quadrature.h:249
This class implements the so-called conical product quadrature rules for Tri and Tet elements...
This class implements the Grundmann-Moller quadrature rules for tetrahedra.
Definition: quadrature_gm.h:96
std::string enum_to_string(const T e)
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
void keast_rule(const Real rule_data[][4], const unsigned int n_pts)
The Keast rules are for tets.
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
virtual void init_3D() override
Initializes the 3D quadrature rule by filling the points and weights vectors with the appropriate val...
The C0Polyhedron is an element in 3D with an arbitrary (but fixed) number of polygonal first-order (C...
virtual ElemType type() const =0
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:39