Chi-Tech
quadrature_tetrahedron.cc
Go to the documentation of this file.
2
4
5#include <cmath>
6#include <stdexcept>
7#include <cassert>
8
9//###################################################################
10/**Initialzes a set of points for a quadrature integration over
11 * the volume of a tetrahedron.*/
14 Quadrature(order)
15{
16 double x=0.0,y=0.0,z=0.0;
17
18 switch (order)
19 {
21 {
22 x = 0.25;
23 y = 0.25;
24 z = 0.25;
25 qpoints_.emplace_back(x, y, z);
26 weights_.push_back(1.0 / 6.0);
27 break;
28 }
30 {
31 double a = (5.0+3.0*sqrt(5))/20.0;
32 double b = (5.0- sqrt(5))/20.0;
33
34 x = a;
35 y = b;
36 z = b;
37 qpoints_.emplace_back(x, y, z);
38 weights_.push_back(1.0 / 24.0);
39
40 x = b;
41 y = a;
42 z = b;
43 qpoints_.emplace_back(x, y, z);
44 weights_.push_back(1.0 / 24.0);
45
46 x = b;
47 y = b;
48 z = a;
49 qpoints_.emplace_back(x, y, z);
50 weights_.push_back(1.0 / 24.0);
51
52 x = b;
53 y = b;
54 z = b;
55 qpoints_.emplace_back(x, y, z);
56 weights_.push_back(1.0 / 24.0);
57 break;
58 }
60 {
61 chi_math::QuadratureConical conical(order);
63 qpoints_.swap(conical.qpoints_);
64 weights_.swap(conical.weights_);
65 break;
66 }
68
69 // Walkington's fifth-order 14-point rule from
70 // "Quadrature on Simplices of Arbitrary Dimension"
72 {
73 qpoints_.resize(14);
74 weights_.resize(14);
75
76 // permutations of these points and suitably-modified versions of
77 // these points are the quadrature point locations
78 const double a[3] = {0.31088591926330060980, // a1 from the paper
79 0.092735250310891226402, // a2 from the paper
80 0.045503704125649649492}; // a3 from the paper
81
82 // weights. a[] and wt[] are the only floating-point inputs required
83 // for this rule.
84 const double wt[3] = {0.018781320953002641800, // w1 from the paper
85 0.012248840519393658257, // w2 from the paper
86 0.0070910034628469110730}; // w3 from the paper
87
88 // The first two sets of 4 points are formed in a similar manner
89 for (unsigned int i=0; i<2; ++i)
90 {
91 // Where we will insert values into qpoints and weights
92 const unsigned int offset=4*i;
93
94 // Stuff points and weights values into their arrays
95 const double b = 1. - 3.*a[i];
96
97 // Here are the permutations. Order of these is not important,
98 // all have the same weight
99 qpoints_[offset + 0] = chi_mesh::Vector3(a[i], a[i], a[i]);
100 qpoints_[offset + 1] = chi_mesh::Vector3(a[i], b, a[i]);
101 qpoints_[offset + 2] = chi_mesh::Vector3(b, a[i], a[i]);
102 qpoints_[offset + 3] = chi_mesh::Vector3(a[i], a[i], b);
103
104 // These 4 points all have the same weights
105 for (unsigned int j=0; j<4; ++j)
106 weights_[offset + j] = wt[i];
107 } // end for
108
109
110 {
111 // The third set contains 6 points and is formed a little differently
112 const unsigned int offset = 8;
113 const double b = 0.5*(1. - 2.*a[2]);
114
115 // Here are the permutations. Order of these is not important,
116 // all have the same weight
117 qpoints_[offset + 0] = chi_mesh::Vector3(b , b, a[2]);
118 qpoints_[offset + 1] = chi_mesh::Vector3(b , a[2], a[2]);
119 qpoints_[offset + 2] = chi_mesh::Vector3(a[2], a[2], b);
120 qpoints_[offset + 3] = chi_mesh::Vector3(a[2], b, a[2]);
121 qpoints_[offset + 4] = chi_mesh::Vector3(b, a[2], b);
122 qpoints_[offset + 5] = chi_mesh::Vector3(a[2], b, b);
123
124 // These 6 points all have the same weights
125 for (unsigned int j=0; j<6; ++j)
126 weights_[offset + j] = wt[2];
127 }
128 break;
129 }
130
131 // This rule is originally from Keast:
132 // Patrick Keast,
133 // Moderate Degree Tetrahedral Quadrature Formulas,
134 // Computer Methods in Applied Mechanics and Engineering,
135 // Volume 55, Number 3, May 1986, pages 339-348.
136 //
137 // It is accurate on 6th-degree polynomials and has 24 points
138 // vs. 64 for the comparable conical product rule.
139 //
140 // Values copied 24th June 2008 from:
141 // http://people.scs.fsu.edu/~burkardt/f_src/keast/keast.f90
143 {
144 qpoints_.resize (24);
145 weights_.resize(24);
146
147 // The raw data for the quadrature rule.
148 const std::vector<std::vector<double>> rule_data =
149 {
150 {0.356191386222544953e+00 , 0.214602871259151684e+00 , 0., 0.00665379170969464506e+00}, // 4
151 {0.877978124396165982e+00 , 0.0406739585346113397e+00, 0., 0.00167953517588677620e+00}, // 4
152 {0.0329863295731730594e+00, 0.322337890142275646e+00 , 0., 0.00922619692394239843e+00}, // 4
153 {0.0636610018750175299e+00, 0.269672331458315867e+00 , 0.603005664791649076e+00, 0.00803571428571428248e+00} // 12
154 };
155
156
157 // Now call the keast routine to generate _points and _weights
158 KeastRule(rule_data, 4);
159 break;
160 }
161 default:
162 {
163 chi_math::QuadratureConical conical(order);
165 qpoints_.swap(conical.qpoints_);
166 weights_.swap(conical.weights_);
167 }
168 }//switch order
169
170}
171
172/** The Keast rules are for tets. This function takes permutation
173points and weights in a specific format as input and fills the
174_points and _weights vectors.*/
175void chi_math::QuadratureTetrahedron::KeastRule(const std::vector<std::vector<double>>& rule_data,
176 const unsigned int n_pts)
177{
178 auto& _points = qpoints_;
179 auto& _weights = weights_;
180
181 typedef chi_mesh::Vector3 Point;
182
183 // Like the Dunavant rule, the input data should have 4 columns. These columns
184 // have the following format and implied permutations (w=weight).
185 // {a, 0, 0, w} = 1-permutation (a,a,a)
186 // {a, b, 0, w} = 4-permutation (a,b,b), (b,a,b), (b,b,a), (b,b,b)
187 // {a, 0, b, w} = 6-permutation (a,a,b), (a,b,b), (b,b,a), (b,a,b), (b,a,a), (a,b,a)
188 // {a, b, c, w} = 12-permutation (a,a,b), (a,a,c), (b,a,a), (c,a,a), (a,b,a), (a,c,a)
189 // (a,b,c), (a,c,b), (b,a,c), (b,c,a), (c,a,b), (c,b,a)
190
191 // Always insert into the points & weights vector relative to the offset
192 unsigned int offset=0;
193
194
195 for (unsigned int p=0; p<n_pts; ++p)
196 {
197
198 // There must always be a non-zero entry to start the row
199 assert (rule_data[p][0] != static_cast<double>(0.0));
200
201 // A zero weight may imply you did not set up the raw data correctly
202 assert (rule_data[p][3] != static_cast<double>(0.0));
203
204 // What kind of point is this?
205 // One non-zero entry in first 3 cols ? 1-perm (centroid) point = 1
206 // Two non-zero entries in first 3 cols ? 3-perm point = 3
207 // Three non-zero entries ? 6-perm point = 6
208 unsigned int pointtype=1;
209
210 if (rule_data[p][1] != static_cast<double>(0.0))
211 {
212 if (rule_data[p][2] != static_cast<double>(0.0))
213 pointtype = 12;
214 else
215 pointtype = 4;
216 }
217 else
218 {
219 // The second entry is zero. What about the third?
220 if (rule_data[p][2] != static_cast<double>(0.0))
221 pointtype = 6;
222 }
223
224
225 switch (pointtype)
226 {
227 case 1:
228 {
229 // Be sure we have enough space to insert this point
230 assert (offset + 0 < _points.size());
231
232 const double a = rule_data[p][0];
233
234 // The point has only a single permutation (the centroid!)
235 _points[offset + 0] = Point(a,a,a);
236
237 // The weight is always the last entry in the row.
238 _weights[offset + 0] = rule_data[p][3];
239
240 offset += pointtype;
241 break;
242 }
243
244 case 4:
245 {
246 // Be sure we have enough space to insert these points
247 assert (offset + 3 < _points.size());
248
249 const double a = rule_data[p][0];
250 const double b = rule_data[p][1];
251 const double wt = rule_data[p][3];
252
253 // Here it's understood the second entry is to be used twice, and
254 // thus there are three possible permutations.
255 _points[offset + 0] = Point(a,b,b);
256 _points[offset + 1] = Point(b,a,b);
257 _points[offset + 2] = Point(b,b,a);
258 _points[offset + 3] = Point(b,b,b);
259
260 for (unsigned int j=0; j<pointtype; ++j)
261 _weights[offset + j] = wt;
262
263 offset += pointtype;
264 break;
265 }
266
267 case 6:
268 {
269 // Be sure we have enough space to insert these points
270 assert (offset + 5 < _points.size());
271
272 const double a = rule_data[p][0];
273 const double b = rule_data[p][2];
274 const double wt = rule_data[p][3];
275
276 // Three individual entries with six permutations.
277 _points[offset + 0] = Point(a,a,b);
278 _points[offset + 1] = Point(a,b,b);
279 _points[offset + 2] = Point(b,b,a);
280 _points[offset + 3] = Point(b,a,b);
281 _points[offset + 4] = Point(b,a,a);
282 _points[offset + 5] = Point(a,b,a);
283
284 for (unsigned int j=0; j<pointtype; ++j)
285 _weights[offset + j] = wt;
286
287 offset += pointtype;
288 break;
289 }
290
291
292 case 12:
293 {
294 // Be sure we have enough space to insert these points
295 assert(offset + 11 < _points.size());
296
297 const double a = rule_data[p][0];
298 const double b = rule_data[p][1];
299 const double c = rule_data[p][2];
300 const double wt = rule_data[p][3];
301
302 // Three individual entries with six permutations.
303 _points[offset + 0] = Point(a,a,b); _points[offset + 6] = Point(a,b,c);
304 _points[offset + 1] = Point(a,a,c); _points[offset + 7] = Point(a,c,b);
305 _points[offset + 2] = Point(b,a,a); _points[offset + 8] = Point(b,a,c);
306 _points[offset + 3] = Point(c,a,a); _points[offset + 9] = Point(b,c,a);
307 _points[offset + 4] = Point(a,b,a); _points[offset + 10] = Point(c,a,b);
308 _points[offset + 5] = Point(a,c,a); _points[offset + 11] = Point(c,b,a);
309
310 for (unsigned int j=0; j<pointtype; ++j)
311 _weights[offset + j] = wt;
312
313 offset += pointtype;
314 break;
315 }
316
317 default:
318 throw std::invalid_argument(std::string(__FUNCTION__) +
319 ": Don't know what to do with this many permutation points!");
320 }
321
322 }
323
324}
std::vector< chi_math::QuadraturePointXYZ > qpoints_
Definition: quadrature.h:37
std::vector< double > weights_
Definition: quadrature.h:38
QuadratureTetrahedron(QuadratureOrder order)
void KeastRule(const std::vector< std::vector< double > > &rule_data, const unsigned int n_pts)
QuadratureOrder
Definition: quadrature.h:12
VectorN< 3 > Vector3