libMesh
Loading...
Searching...
No Matches
quadrature_grid_3D.C
Go to the documentation of this file.
1// The libMesh Finite Element Library.
2// Copyright (C) 2002-2026 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_grid.h"
22#include "libmesh/enum_to_string.h"
23
24namespace libMesh
25{
26
27
29{
30#if LIBMESH_DIM == 3
31
32 switch (_type)
33 {
34 //---------------------------------------------
35 // Hex quadrature rules
36 case HEX8:
37 case HEX20:
38 case HEX27:
39 {
40 // We compute the 3D quadrature rule as a tensor
41 // product of the 1D quadrature rule.
42 //
43 // We ignore p_level in QGrid, since the "order" here is a
44 // user-requested number of grid points, nothing to do with
45 // the order of exactly-integrated polynomial spaces
46 QGrid q1D(1,_order);
47
48 tensor_product_hex( q1D );
49
50 return;
51 }
52
53
54
55 //---------------------------------------------
56 // Tetrahedral quadrature rules
57 case TET4:
58 case TET10:
59 case TET14:
60 {
61 // This is the composite centroid rule on a uniform refinement
62 // of the reference tet with order+1 intervals per edge: one
63 // point at the centroid of each of the (order+1)^3 subtets.
64 // The refinement consists of upright tets, inverted tets,
65 // and octahedra, and we split each octahedron into four tets
66 // about the same diagonal. Every subtet has the same volume
67 // regardless of which diagonal is chosen, so the weights are
68 // equal. The rule is exact for linears and has O(dx^2) error
69 // on smooth functions, like the midpoint grid on hexes.
70 const unsigned int np = (_order+1)*(_order+1)*(_order+1);
71 // Master tet has 1x1 triangle base, height 1, so volume = 1/6
72 const Real weight = Real(1)/Real(6)/np;
73 const Real dx = Real(1)/static_cast<int>(_order+1);
74 _points.resize(np);
75 _weights.resize(np);
76
77 unsigned int pt = 0;
78 auto add_point = [this, &pt, weight, dx](Real x, Real y, Real z)
79 {
80 _points[pt] = Point(x*dx, y*dx, z*dx);
81 _weights[pt] = weight;
82 pt++;
83 };
84
85 for (int i = 0; i != _order + 1; ++i)
86 {
87 for (int j = 0; j != _order + 1 - i; ++j)
88 {
89 for (int k = 0; k != _order + 1 - i - j; ++k)
90 {
91 // Centroid of the upright tet with vertices
92 // (i,j,k), (i+1,j,k), (i,j+1,k), (i,j,k+1)
93 add_point(i+Real(1)/4, j+Real(1)/4, k+Real(1)/4);
94
95 // The octahedron with vertices (i+1,j,k),
96 // (i,j+1,k), (i,j,k+1), (i+1,j+1,k),
97 // (i+1,j,k+1), (i,j+1,k+1) lies inside the
98 // reference tet only if i+j+k < order. We split
99 // it into four tets about the diagonal from
100 // (i+1,j,k) to (i,j+1,k+1); their centroids are
101 // offset from the octahedron center by
102 // (-1/4,0,0), (1/4,0,0), (0,1/4,-1/4), and
103 // (0,-1/4,1/4).
104 if (i + j + k < _order)
105 {
106 const Real ci = i+Real(1)/2;
107 const Real cj = j+Real(1)/2;
108 const Real ck = k+Real(1)/2;
109 add_point(ci-Real(1)/4, cj, ck);
110 add_point(ci+Real(1)/4, cj, ck);
111 add_point(ci, cj+Real(1)/4, ck-Real(1)/4);
112 add_point(ci, cj-Real(1)/4, ck+Real(1)/4);
113 }
114
115 // Centroid of the inverted tet with vertices
116 // (i+1,j+1,k), (i+1,j,k+1), (i,j+1,k+1),
117 // (i+1,j+1,k+1), which lies inside the reference
118 // tet only if i+j+k < order-1
119 if (i + j + k + 1 < _order)
120 add_point(i+Real(3)/4, j+Real(3)/4, k+Real(3)/4);
121 }
122 }
123 }
124 libmesh_assert_equal_to(pt, np);
125 return;
126 }
127
128
129 // Prism quadrature rules
130 case PRISM6:
131 case PRISM15:
132 case PRISM18:
133 case PRISM20:
134 case PRISM21:
135 {
136 // We compute the 3D quadrature rule as a tensor
137 // product of the 1D quadrature rule and a 2D
138 // triangle quadrature rule
139 //
140 // We ignore p_level in QGrid, since the "order" here is a
141 // user-requested number of grid points, nothing to do with
142 // the order of exactly-integrated polynomial spaces
143 QGrid q1D(1,_order);
144 QGrid q2D(2,_order);
145
146 // Initialize the 2D rule (1D is pre-initialized)
147 q2D.init(TRI3, 0, /*simple_type_only=*/true);
148
149 tensor_product_prism(q1D, q2D);
150
151 return;
152 }
153
154
155
156 //---------------------------------------------
157 // Pyramid
158 case PYRAMID5:
159 case PYRAMID13:
160 case PYRAMID14:
161 case PYRAMID18:
162 {
163 // This is the composite centroid rule on a uniform refinement
164 // of the reference pyramid with order+1 intervals per edge.
165 // Layer k of the refinement, between z = k*dz and z =
166 // (k+1)*dz, has an m x m grid of cells on its bottom face and
167 // an (m-1) x (m-1) grid on its top face, where m = order+1-k.
168 // It consists of
169 // * m^2 upright pyramids, one on each bottom cell,
170 // * (m-1)^2 inverted pyramids, one under each top cell, and
171 // * 2m(m-1) tets, one per interior edge of the bottom grid,
172 // between the two upright pyramids sharing that edge.
173 // Each pyramid has twice the volume of each tet, so we split
174 // every pyramid into two tets along a base diagonal, giving
175 // 2(order+1)^3 tets of equal volume. We place one point at
176 // the centroid of each tet. The rule is exact for linears
177 // and has O(dz^2) error on smooth functions.
178 const unsigned int np = 2*(_order+1)*(_order+1)*(_order+1);
179 _points.resize(np);
180 _weights.resize(np);
181 // Master pyramid has 2x2 base, height 1, so volume = 4/3
182 const Real weight = Real(4)/Real(3)/np;
183 const Real dz = Real(1)/static_cast<int>(_order+1);
184
185 // Lattice point (i,j) on the bottom of layer k is at
186 // ((2i+k)*dz - 1, (2j+k)*dz - 1, k*dz). This map is affine,
187 // so each centroid below is computed as the average of its
188 // tet's vertices in (i,j,k) lattice coordinates.
189 unsigned int pt = 0;
190 auto add_point = [this, &pt, weight, dz](Real i, Real j, Real k)
191 {
192 _points[pt] = Point((2*i+k)*dz - 1, (2*j+k)*dz - 1, k*dz);
193 _weights[pt] = weight;
194 pt++;
195 };
196
197 for (int k = 0; k != _order + 1; ++k)
198 {
199 const int m = _order + 1 - k;
200 for (int i = 0; i != m; ++i)
201 {
202 for (int j = 0; j != m; ++j)
203 {
204 // The upright pyramid with base vertices
205 // (i,j,k), (i+1,j,k), (i+1,j+1,k), (i,j+1,k) and
206 // apex (i,j,k+1), split along the diagonal from
207 // (i,j,k) to (i+1,j+1,k)
208 add_point(i+Real(1)/2, j+Real(1)/4, k+Real(1)/4);
209 add_point(i+Real(1)/4, j+Real(1)/2, k+Real(1)/4);
210
211 // The inverted pyramid with base vertices
212 // (i,j,k+1), (i+1,j,k+1), (i+1,j+1,k+1),
213 // (i,j+1,k+1) and apex (i+1,j+1,k), split along
214 // the diagonal from (i,j,k+1) to (i+1,j+1,k+1)
215 if (i + 1 < m && j + 1 < m)
216 {
217 add_point(i+Real(3)/4, j+Real(1)/2, k+Real(3)/4);
218 add_point(i+Real(1)/2, j+Real(3)/4, k+Real(3)/4);
219 }
220
221 // The tet with vertices (i+1,j,k), (i+1,j+1,k),
222 // (i,j,k+1), (i+1,j,k+1), between the upright
223 // pyramids on cells (i,j) and (i+1,j)
224 if (i + 1 < m)
225 add_point(i+Real(3)/4, j+Real(1)/4, k+Real(1)/2);
226
227 // The tet with vertices (i,j+1,k), (i+1,j+1,k),
228 // (i,j,k+1), (i,j+1,k+1), between the upright
229 // pyramids on cells (i,j) and (i,j+1)
230 if (j + 1 < m)
231 add_point(i+Real(1)/4, j+Real(3)/4, k+Real(1)/2);
232 }
233 }
234 }
235 libmesh_assert_equal_to(pt, np);
236 return;
237 }
238
239
240
241 //---------------------------------------------
242 // Unsupported type
243 default:
244 libmesh_error_msg("ERROR: Unsupported type: " << Utility::enum_to_string(_type));
245 }
246#endif
247}
248
249} // namespace libMesh
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition point.h:41
std::vector< Point > _points
The locations of the quadrature points in reference element space.
Definition quadrature.h:409
ElemType _type
The type of element for which the current values have been computed.
Definition quadrature.h:391
std::vector< Real > _weights
The quadrature weights.
Definition quadrature.h:415
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
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
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
Order _order
The polynomial order which the quadrature rule is capable of integrating exactly.
Definition quadrature.h:385
This class creates quadrature points on a uniform grid with order+1 intervals per edge.
virtual void init_3D() override
Initializes the 3D quadrature rule by filling the points and weights vectors with the appropriate val...
std::string enum_to_string(const T e)
The libMesh namespace provides an interface to certain functionality in the library.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real