MFEM v4.10.0
Finite element discretization library
Loading...
Searching...
No Matches
intrules.cpp
Go to the documentation of this file.
1// Copyright (c) 2010-2026, Lawrence Livermore National Security, LLC. Produced
2// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
3// LICENSE and NOTICE for details. LLNL-CODE-806117.
4//
5// This file is part of the MFEM library. For more information and source code
6// availability visit https://mfem.org.
7//
8// MFEM is free software; you can redistribute it and/or modify it under the
9// terms of the BSD-3 license. We welcome feedback and contributions, see file
10// CONTRIBUTING.md for details.
11
12// Implementation of IntegrationRule(s) classes
13
14// Acknowledgment: Some of the high-precision triangular and tetrahedral
15// quadrature rules below were obtained from the Encyclopaedia of Cubature
16// Formulas at http://nines.cs.kuleuven.be/research/ecf/ecf.html
17//
18// Positive-weight simplex quadrature rules from:
19//
20// [1] F.D. Witherden, P.E. Vincent, "On the identification of symmetric
21// quadrature rules for finite element methods", Computers & Mathematics
22// with Applications, 69(10):1232-1241, 2015.
23// Used for: triangles (d=0-20), tetrahedra (d=0-13).
24//
25// [2] G. Chuluunbaatar, O. Chuluunbaatar, A.A. Gusev, S.I. Vinitsky,
26// "PI-type fully symmetric quadrature rules on the 3-,...,6-simplexes",
27// Computers & Mathematics with Applications, 124:89-97, 2022.
28// Used for: tetrahedra (d=14-20).
29
30#include "fem.hpp"
31#include "../mesh/nurbs.hpp"
32#include <cmath>
33
34#ifdef MFEM_USE_MPFR
35#include <mpfr.h>
36#endif
37
38using namespace std;
39
40namespace mfem
41{
42
44{
45 int i, j, nx, ny;
46
47 nx = irx.GetNPoints();
48 ny = iry.GetNPoints();
49 SetSize(nx * ny);
51 Order = std::min(irx.GetOrder(), iry.GetOrder());
52
53 for (j = 0; j < ny; j++)
54 {
55 IntegrationPoint &ipy = iry.IntPoint(j);
56 for (i = 0; i < nx; i++)
57 {
58 IntegrationPoint &ipx = irx.IntPoint(i);
59 IntegrationPoint &ip = IntPoint(j*nx+i);
60
61 ip.x = ipx.x;
62 ip.y = ipy.x;
63 ip.weight = ipx.weight * ipy.weight;
64 }
65 }
66}
67
69 IntegrationRule &irz)
70{
71 const int nx = irx.GetNPoints();
72 const int ny = iry.GetNPoints();
73 const int nz = irz.GetNPoints();
74 SetSize(nx*ny*nz);
76 Order = std::min({irx.GetOrder(), iry.GetOrder(), irz.GetOrder()});
77
78 for (int iz = 0; iz < nz; ++iz)
79 {
80 IntegrationPoint &ipz = irz.IntPoint(iz);
81 for (int iy = 0; iy < ny; ++iy)
82 {
83 IntegrationPoint &ipy = iry.IntPoint(iy);
84 for (int ix = 0; ix < nx; ++ix)
85 {
86 IntegrationPoint &ipx = irx.IntPoint(ix);
87 IntegrationPoint &ip = IntPoint(iz*nx*ny + iy*nx + ix);
88
89 ip.x = ipx.x;
90 ip.y = ipy.x;
91 ip.z = ipz.x;
92 ip.weight = ipx.weight*ipy.weight*ipz.weight;
93 }
94 }
95 }
96}
97
99{
100 if (weights.Size() != GetNPoints())
101 {
102 weights.SetSize(GetNPoints());
103 for (int i = 0; i < GetNPoints(); i++)
104 {
105 weights[i] = IntPoint(i).weight;
106 }
107 }
108 return weights;
109}
110
112{
113 for (int i = 0; i < Size(); i++)
114 {
115 IntPoint(i).index = i;
116 }
117}
118
119void IntegrationRule::GrundmannMollerSimplexRule(int s, int n)
120{
121 // for pow on older compilers
122 using std::pow;
123 const int d = 2*s + 1;
124 Vector fact(d + n + 1);
125 Array<int> beta(n), sums(n);
126
127 fact(0) = 1.;
128 for (int i = 1; i < fact.Size(); i++)
129 {
130 fact(i) = fact(i - 1)*i;
131 }
132
133 // number of points is \binom{n + s + 1}{n + 1}
134 int np = 1, f = 1;
135 for (int i = 0; i <= n; i++)
136 {
137 np *= (s + i + 1), f *= (i + 1);
138 }
139 np /= f;
140 SetSize(np);
142 Order = 2*s + 1;
143
144 int pt = 0;
145 for (int i = 0; i <= s; i++)
146 {
148
149 weight = pow(2., -2*s)*pow(static_cast<real_t>(d + n - 2*i),
150 d)/fact(i)/fact(d + n - i);
151 if (i%2)
152 {
153 weight = -weight;
154 }
155
156 // loop over all beta : beta_0 + ... + beta_{n-1} <= s - i
157 int k = s - i;
158 beta = 0;
159 sums = 0;
160 while (true)
161 {
162 IntegrationPoint &ip = IntPoint(pt++);
163 ip.weight = weight;
164 ip.x = real_t(2*beta[0] + 1)/(d + n - 2*i);
165 ip.y = real_t(2*beta[1] + 1)/(d + n - 2*i);
166 if (n == 3)
167 {
168 ip.z = real_t(2*beta[2] + 1)/(d + n - 2*i);
169 }
170
171 int j = 0;
172 while (sums[j] == k)
173 {
174 beta[j++] = 0;
175 if (j == n)
176 {
177 goto done_beta;
178 }
179 }
180 beta[j]++;
181 sums[j]++;
182 for (j--; j >= 0; j--)
183 {
184 sums[j] = sums[j+1];
185 }
186 }
187 done_beta:
188 ;
189 }
190}
191
192IntegrationRule*
194{
195 const int np = this->GetNPoints();
196 const int ne = kv.GetNE();
197
198 IntegrationRule *kvir = new IntegrationRule(ne * np);
199 kvir->SetOrder(GetOrder());
200
201 real_t x0 = kv[0];
202 real_t x1 = x0;
203
204 int id = 0;
205 for (int e=0; e<ne; ++e)
206 {
207 x0 = x1;
208
209 if (e == ne-1)
210 {
211 x1 = kv[kv.Size() - 1];
212 }
213 else
214 {
215 // Find the next unique knot
216 while (id < kv.Size() - 1)
217 {
218 id++;
219 if (kv[id] != x0)
220 {
221 x1 = kv[id];
222 break;
223 }
224 }
225 }
226
227 const real_t s = x1 - x0;
228
229 for (int j=0; j<this->GetNPoints(); ++j)
230 {
231 const real_t x = x0 + (s * (*this)[j].x);
232 (*kvir)[(e * np) + j].Set1w(x, (*this)[j].weight);
233 }
234 }
235
236 return kvir;
237}
238
240{
241 const int np = GetNPoints();
242 MFEM_VERIFY(np == ordering.Size(), "Invalid permutation size");
243 IntegrationRule ir(np);
244 ir.SetOrder(GetOrder());
245
246 for (int i = 0; i < np; i++)
247 {
248 IntegrationPoint &ip_new = ir.IntPoint(i);
249 const IntegrationPoint &ip_old = IntPoint(ordering[i]);
250 ip_new.Set(ip_old.x, ip_old.y, ip_old.z, ip_old.weight);
251 }
252
253 return ir;
254}
255
257{
258 IntegrationRule ir_mapped(ir.GetNPoints());
259 ir_mapped.SetOrder(ir.GetOrder());
260
261 if (dim == 2)
262 {
263 for (int i = 0; i < ir.GetNPoints(); i++)
264 {
265 IntegrationPoint &ip_mapped = ir_mapped.IntPoint(i);
266 ip_mapped.y = ir.IntPoint(i).y * (1 - ir.IntPoint(i).x);
267 ip_mapped.x = ir.IntPoint(i).x;
268 ip_mapped.weight = ir.IntPoint(i).weight;
269 }
270 return ir_mapped;
271 }
272 else if (dim == 3)
273 {
274 for (int i = 0; i < ir.GetNPoints(); i++)
275 {
276 IntegrationPoint &ip_mapped = ir_mapped.IntPoint(i);
277 ip_mapped.z = ir.IntPoint(i).z * (1 - ir.IntPoint(i).x) * (1 - ir.IntPoint(
278 i).y);
279 ip_mapped.y = ir.IntPoint(i).y * (1 - ir.IntPoint(i).x);
280 ip_mapped.x = ir.IntPoint(i).x;
281 ip_mapped.weight = ir.IntPoint(i).weight;
282 }
283 return ir_mapped;
284 }
285 else
286 {
287 MFEM_ABORT("Duffy transformation not implemented for this dimension!");
288 }
289}
290
291#ifdef MFEM_USE_MPFR
292
293// Class for computing hi-precision (HP) quadrature in 1D
294class HP_Quadrature1D
295{
296protected:
297 mpfr_t pi, z, pp, p1, p2, p3, dz, w, rtol;
298
299public:
300 static const mpfr_rnd_t rnd = GMP_RNDN;
301 static const int default_prec = 128;
302
303 // prec = MPFR precision in bits
304 HP_Quadrature1D(const int prec = default_prec)
305 {
306 mpfr_inits2(prec, pi, z, pp, p1, p2, p3, dz, w, rtol, (mpfr_ptr) 0);
307 mpfr_const_pi(pi, rnd);
308 mpfr_set_si_2exp(rtol, 1, -32, rnd); // 2^(-32) < 2.33e-10
309 }
310
311 // set rtol = 2^exponent
312 // this is a tolerance for the last correction of x_i in Newton's algorithm;
313 // this gives roughly rtol^2 accuracy for the final x_i.
314 void SetRelTol(const int exponent = -32)
315 {
316 mpfr_set_si_2exp(rtol, 1, exponent, rnd);
317 }
318
319 // n - number of quadrature points
320 // k - index of the point to compute, 0 <= k < n
321 // see also: QuadratureFunctions1D::GaussLegendre
322 void ComputeGaussLegendrePoint(const int n, const int k)
323 {
324 MFEM_ASSERT(n > 0 && 0 <= k && k < n, "invalid n = " << n
325 << " and/or k = " << k);
326
327 int i = (k < (n+1)/2) ? k+1 : n-k;
328
329 // Initial guess for the x-coordinate:
330 // set z = cos(pi * (i - 0.25) / (n + 0.5)) =
331 // = sin(pi * ((n+1-2*i) / (2*n+1)))
332 mpfr_set_si(z, n+1-2*i, rnd);
333 mpfr_div_si(z, z, 2*n+1, rnd);
334 mpfr_mul(z, z, pi, rnd);
335 mpfr_sin(z, z, rnd);
336
337 bool done = false;
338 while (1)
339 {
340 mpfr_set_si(p2, 1, rnd);
341 mpfr_set(p1, z, rnd);
342 for (int j = 2; j <= n; j++)
343 {
344 mpfr_set(p3, p2, rnd);
345 mpfr_set(p2, p1, rnd);
346 // p1 = ((2 * j - 1) * z * p2 - (j - 1) * p3) / j;
347 mpfr_mul_si(p1, z, 2*j-1, rnd);
348 mpfr_mul_si(p3, p3, j-1, rnd);
349 mpfr_fms(p1, p1, p2, p3, rnd);
350 mpfr_div_si(p1, p1, j, rnd);
351 }
352 // p1 is Legendre polynomial
353
354 // derivative of the Legendre polynomial:
355 // pp = n * (z*p1-p2) / (z*z - 1);
356 mpfr_fms(pp, z, p1, p2, rnd);
357 mpfr_mul_si(pp, pp, n, rnd);
358 mpfr_sqr(p2, z, rnd);
359 mpfr_sub_si(p2, p2, 1, rnd);
360 mpfr_div(pp, pp, p2, rnd);
361
362 if (done) { break; }
363
364 // set delta_z: dz = p1/pp;
365 mpfr_div(dz, p1, pp, rnd);
366 // compute absolute tolerance: atol = rtol*(1-z)
367 mpfr_t &atol = w;
368 mpfr_si_sub(atol, 1, z, rnd);
369 mpfr_mul(atol, atol, rtol, rnd);
370 if (mpfr_cmpabs(dz, atol) <= 0)
371 {
372 done = true;
373 // continue the computation: get pp at the new point, then exit
374 }
375 // update z = z - dz
376 mpfr_sub(z, z, dz, rnd);
377 }
378
379 // map z to (0,1): z = (1 - z)/2
380 mpfr_si_sub(z, 1, z, rnd);
381 mpfr_div_2si(z, z, 1, rnd);
382
383 // weight: w = 1/(4*z*(1 - z)*pp*pp)
384 mpfr_sqr(w, pp, rnd);
385 mpfr_mul_2si(w, w, 2, rnd);
386 mpfr_mul(w, w, z, rnd);
387 mpfr_si_sub(p1, 1, z, rnd); // p1 = 1-z
388 mpfr_mul(w, w, p1, rnd);
389 mpfr_si_div(w, 1, w, rnd);
390
391 if (k >= (n+1)/2) { mpfr_swap(z, p1); }
392 }
393
394 // n - number of quadrature points
395 // k - index of the point to compute, 0 <= k < n
396 // see also: QuadratureFunctions1D::GaussLobatto
397 void ComputeGaussLobattoPoint(const int n, const int k)
398 {
399 MFEM_ASSERT(n > 1 && 0 <= k && k < n, "invalid n = " << n
400 << " and/or k = " << k);
401
402 int i = (k < (n+1)/2) ? k : n-1-k;
403
404 if (i == 0)
405 {
406 mpfr_set_si(z, 0, rnd);
407 mpfr_set_si(p1, 1, rnd);
408 mpfr_set_si(w, n*(n-1), rnd);
409 mpfr_si_div(w, 1, w, rnd); // weight = 1/(n*(n-1))
410 return;
411 }
412 // initial guess is the corresponding Chebyshev point, z:
413 // z = -cos(pi * i/(n-1)) = sin(pi * (2*i-n+1)/(2*n-2))
414 mpfr_set_si(z, 2*i-n+1, rnd);
415 mpfr_div_si(z, z, 2*(n-1), rnd);
416 mpfr_mul(z, pi, z, rnd);
417 mpfr_sin(z, z, rnd);
418 bool done = false;
419 for (int iter = 0 ; true ; ++iter)
420 {
421 // build Legendre polynomials, up to P_{n}(z)
422 mpfr_set_si(p1, 1, rnd);
423 mpfr_set(p2, z, rnd);
424
425 for (int l = 1 ; l < (n-1) ; ++l)
426 {
427 // P_{l+1}(x) = [ (2*l+1)*x*P_l(x) - l*P_{l-1}(x) ]/(l+1)
428 mpfr_mul_si(p1, p1, l, rnd);
429 mpfr_mul_si(p3, z, 2*l+1, rnd);
430 mpfr_fms(p3, p3, p2, p1, rnd);
431 mpfr_div_si(p3, p3, l+1, rnd);
432
433 mpfr_set(p1, p2, rnd);
434 mpfr_set(p2, p3, rnd);
435 }
436 if (done) { break; }
437 // compute dz = resid/deriv = (z*p2 - p1) / (n*p2);
438 mpfr_fms(dz, z, p2, p1, rnd);
439 mpfr_mul_si(p3, p2, n, rnd);
440 mpfr_div(dz, dz, p3, rnd);
441 // update: z = z - dz
442 mpfr_sub(z, z, dz, rnd);
443 // compute absolute tolerance: atol = rtol*(1 + z)
444 mpfr_t &atol = w;
445 mpfr_add_si(atol, z, 1, rnd);
446 mpfr_mul(atol, atol, rtol, rnd);
447 // check for convergence
448 if (mpfr_cmpabs(dz, atol) <= 0)
449 {
450 done = true;
451 // continue the computation: get p2 at the new point, then exit
452 }
453 // If the iteration does not converge fast, something is wrong.
454 MFEM_VERIFY(iter < 8, "n = " << n << ", i = " << i
455 << ", dz = " << mpfr_get_d(dz, rnd));
456 }
457 // Map to the interval [0,1] and scale the weights
458 mpfr_add_si(z, z, 1, rnd);
459 mpfr_div_2si(z, z, 1, rnd);
460 // set the symmetric point
461 mpfr_si_sub(p1, 1, z, rnd);
462 // w = 1/[ n*(n-1)*[P_{n-1}(z)]^2 ]
463 mpfr_sqr(w, p2, rnd);
464 mpfr_mul_si(w, w, n*(n-1), rnd);
465 mpfr_si_div(w, 1, w, rnd);
466
467 if (k >= (n+1)/2) { mpfr_swap(z, p1); }
468 }
469
470 real_t GetPoint() const { return mpfr_get_d(z, rnd); }
471 real_t GetSymmPoint() const { return mpfr_get_d(p1, rnd); }
472 real_t GetWeight() const { return mpfr_get_d(w, rnd); }
473
474 const mpfr_t &GetHPPoint() const { return z; }
475 const mpfr_t &GetHPSymmPoint() const { return p1; }
476 const mpfr_t &GetHPWeight() const { return w; }
477
478 ~HP_Quadrature1D()
479 {
480 mpfr_clears(pi, z, pp, p1, p2, p3, dz, w, rtol, (mpfr_ptr) 0);
481 mpfr_free_cache();
482 }
483};
484
485#endif // MFEM_USE_MPFR
486
487
489 const real_t beta, IntegrationRule* ir)
490{
491 /* The np-point Gauss-Jacobi quadrature rule is exact for polynomials of
492 degree 2np - 1 with weight function w(x) = (1-x)^alpha * x^beta. The
493 nodes are the zeros of the Jacobi polynomial P_{np}^{alpha,beta} and
494 the weights are
495
496 w_i = C / [(1 - x_i^2) * P'_{np}^{alpha,beta}(x_i)^2]
497 C = 2^{alpha + beta + 1} * Gamma(np + alpha + 1) * Gamma(np + beta + 1)
498 / [Gamma(np + alpha + beta + 1) * Gamma(np + 1)].
499
500 The nodes are computed via nonlinear solve (Newton's method) with an
501 initial guess corresponding to Gatteschi's asymptotic expansions of the
502 Jacobi polynomial roots [1].
503
504 The current initial guess has been tested and performs well for
505 np <= 200 and -1 <= alpha, beta <= 4. For larger np, it may be necessary
506 utilize different initial guesses in the vicinity of x = -1,+1 [2].
507
508 [1] Gautschi, W., & Giordano, C. (2008). Luigi Gatteschi’s work on
509 asymptotics of special functions and their zeros. Numerical Algorithms,
510 49, 11-31.
511 [2] Hale, N., & Townsend, A. (2013). Fast and accurate computation of
512 Gauss--Legendre and Gauss--Jacobi quadrature nodes and weights.
513 SIAM Journal on Scientific Computing, 35(2), A652-A674.
514 */
515 ir->SetSize(np);
516 ir->SetPointIndices();
517 ir->SetOrder(2*np - 1);
518
519 if (alpha <= -1.0 || beta <= -1.0)
520 {
521 MFEM_ABORT("Gauss-Jacobi quadrature only defined for alpha > -1 and beta > -1");
522 }
523 // Jacobi weight function is undefined whenever alpha <= -1 or beta <= -1
524
525 if (alpha > 4.0 || beta > 4.0)
526 {
527 MFEM_ABORT("Current Gauss-Jacobi quadrature implementation only tested for alpha <= 4 and beta <= 4");
528 }
529 // current asymptotic expansions for initial guess may perform poorly for large alpha, beta
530
531 switch (np)
532 {
533 case 1:
534 real_t x = (beta - alpha) / (alpha + beta + 2);
535 real_t w = pow(2, alpha + beta + 1) * tgamma(alpha + 2) * tgamma(
536 beta + 2) / (tgamma(alpha + beta + 2));
537 w = 0.5 * w / pow(2, alpha + beta);
538 // map weight to to [0,1], with additional 1/(2^(alpha + beta)) factor coming from mapping
539 // the weight (1-x)^alpha * (1+x)^beta to [0,1] as well.
540 ir->IntPoint(0).Set1w(0.5 * x + 0.5,
541 4.0 * w / ((1.0 - x*x) * (alpha + beta + 2) * (alpha + beta + 2)));
542 return;
543 }
544
545#ifdef MFEM_USE_MPFR
546 MFEM_WARNING("MPFR implementation of Gauss-Jacobi quadrature not implemented yet. Falling "
547 "back to double precision implementation...");
548#endif
549
550 const int n = np;
551 // common constants for Jacobi polynomials
552 real_t ab = alpha + beta;
553 real_t a2_minus_b2 = (alpha - beta) * (alpha + beta);
554
555 // roots of P^(alpha,beta)_n in the interval [-1,1]
556 for (int i = 1; i <= n; i++)
557 {
558 // rather than using Chebyshev points for initial guess, use Gatteschi's asymptotic expansion for roots of Jacobi
559 // polynomials
560 real_t n_ab_plus_1 = 2 * n + alpha + beta + 1;
561 real_t v = (2 * i + alpha - 0.5) * M_PI / n_ab_plus_1;
562 real_t theta = v + 1.0 / (n_ab_plus_1*n_ab_plus_1) * ((0.25 - alpha*alpha) *
563 1.0/tan(0.5*v) - (0.25 - beta*beta) * tan(0.5*v));
564 real_t z = cos(theta);
565
566 real_t pp, p1, dz, xi = 0.;
567 bool done = false;
568 while (1)
569 {
570 real_t p2 = 1;
571 p1 = ((alpha-beta) + (alpha + beta + 2) * z) / 2;
572 for (int j = 1; j <= n-1; j++)
573 {
574 real_t p3 = p2;
575 p2 = p1;
576
577 real_t jx2_ab = 2 * j + ab;
578 real_t an = (jx2_ab) * (jx2_ab + 2);
579 real_t bn = a2_minus_b2;
580 real_t cn = 2 * (j + alpha) * (j + beta) * (jx2_ab + 2) / (jx2_ab + 1);
581
582 real_t D = (jx2_ab + 1) / (2 * (j + 1) * (j + ab + 1) * (jx2_ab));
583 p1 = ((an * z + bn) * p2 - cn * p3) * D;
584 }
585 // p1 is Jacobi polynomial
586 pp = n * (alpha - beta - (2 * n + ab) * z) * p1 + 2 * (n + alpha) *
587 (n + beta) * p2;
588 pp = pp / ((2 * n + ab) * (1 - z*z));
589 // derivative of the Jacobi polynomial
590 if (done) { break; }
591
592 dz = p1/pp;
593#ifdef MFEM_USE_SINGLE
594 if (std::abs(dz) < 1e-7)
595#elif defined MFEM_USE_DOUBLE
596 if (std::abs(dz) < std::numeric_limits<real_t>::epsilon())
597 // this seems to cause trouble if we try std::abs(dz) < 1e-16
598#else
599 MFEM_ABORT("Floating point type undefined");
600 // if (std::abs(dz) < 1e-16)
601#endif
602 {
603 done = true;
604 xi = z - dz;
605 }
606 z -= dz;
607 }
608 real_t c0 = exp(lgamma(n + alpha + 1) - lgamma(n + ab + 1)) * exp(lgamma(
609 n + beta + 1) - lgamma(n + 1));
610 // ratio of gamma functions prone to overflow for large n, so compute logarithms
611 // of Gamma function instead, i.e. Gamma(a)/Gamma(b) = exp(lgamma(a) - lgamma(b))
612 ir->IntPoint(n-i).x = 0.5 * xi + 0.5;
613 ir->IntPoint(n-i).weight = 0.5 * c0 * pow(2.0,
614 ab + 1) / ((1.0 - xi*xi)*pp*pp) / pow(2, ab);
615 // map nodes and weights to the interval [0,1]
616 }
617}
618
619
621{
622 ir->SetSize(np);
623 ir->SetPointIndices();
624 ir->SetOrder(2*np - 1);
625
626 switch (np)
627 {
628 case 1:
629 ir->IntPoint(0).Set1w(0.5, 1.0);
630 return;
631 case 2:
632 ir->IntPoint(0).Set1w(0.21132486540518711775, 0.5);
633 ir->IntPoint(1).Set1w(0.78867513459481288225, 0.5);
634 return;
635 case 3:
636 ir->IntPoint(0).Set1w(0.11270166537925831148, 5./18.);
637 ir->IntPoint(1).Set1w(0.5, 4./9.);
638 ir->IntPoint(2).Set1w(0.88729833462074168852, 5./18.);
639 return;
640 }
641
642 const int n = np;
643 const int m = (n+1)/2;
644
645#ifndef MFEM_USE_MPFR
646
647 for (int i = 1; i <= m; i++)
648 {
649 real_t z = cos(M_PI * (i - 0.25) / (n + 0.5));
650 real_t pp, p1, dz, xi = 0.;
651 bool done = false;
652 while (1)
653 {
654 real_t p2 = 1;
655 p1 = z;
656 for (int j = 2; j <= n; j++)
657 {
658 real_t p3 = p2;
659 p2 = p1;
660 p1 = ((2 * j - 1) * z * p2 - (j - 1) * p3) / j;
661 }
662 // p1 is Legendre polynomial
663
664 pp = n * (z*p1-p2) / (z*z - 1);
665 if (done) { break; }
666
667 dz = p1/pp;
668#ifdef MFEM_USE_SINGLE
669 if (std::abs(dz) < 1e-7)
670#elif defined MFEM_USE_DOUBLE
671 if (std::abs(dz) < 1e-16)
672#else
673 MFEM_ABORT("Floating point type undefined");
674 if (std::abs(dz) < 1e-16)
675#endif
676 {
677 done = true;
678 // map the new point (z-dz) to (0,1):
679 xi = ((1 - z) + dz)/2; // (1 - (z - dz))/2 has bad round-off
680 // continue the computation: get pp at the new point, then exit
681 }
682 // update: z = z - dz
683 z -= dz;
684 }
685
686 ir->IntPoint(i-1).x = xi;
687 ir->IntPoint(n-i).x = 1 - xi;
688 ir->IntPoint(i-1).weight =
689 ir->IntPoint(n-i).weight = 1./(4*xi*(1 - xi)*pp*pp);
690 }
691
692#else // MFEM_USE_MPFR is defined
693
694 HP_Quadrature1D hp_quad;
695 for (int i = 1; i <= m; i++)
696 {
697 hp_quad.ComputeGaussLegendrePoint(n, i-1);
698
699 ir->IntPoint(i-1).x = hp_quad.GetPoint();
700 ir->IntPoint(n-i).x = hp_quad.GetSymmPoint();
701 ir->IntPoint(i-1).weight = ir->IntPoint(n-i).weight = hp_quad.GetWeight();
702 }
703
704#endif // MFEM_USE_MPFR
705
706}
707
709{
710 /* An np point Gauss-Lobatto quadrature has (np - 2) free abscissa the other
711 (2) abscissa are the interval endpoints.
712
713 The interior x_i are the zeros of P'_{np-1}(x). The weights of the
714 interior points on the interval [-1,1] are:
715
716 w_i = 2/(np*(np-1)*[P_{np-1}(x_i)]^2)
717
718 The end point weights (on [-1,1]) are: w_{end} = 2/(np*(np-1)).
719
720 The interior abscissa are found via a nonlinear solve, the initial guess
721 for each point is the corresponding Chebyshev point.
722
723 After we find all points on the interval [-1,1], we will map and scale the
724 points and weights to the MFEM natural interval [0,1].
725
726 References:
727 [1] E. E. Lewis and W. F. Millier, "Computational Methods of Neutron
728 Transport", Appendix A
729 [2] the QUADRULE software by John Burkardt,
730 https://people.sc.fsu.edu/~jburkardt/cpp_src/quadrule/quadrule.cpp
731 */
732
733 ir->SetSize(np);
734 ir->SetPointIndices();
735 if ( np == 1 )
736 {
737 ir->IntPoint(0).Set1w(0.5, 1.0);
738 ir->SetOrder(1);
739 }
740 else
741 {
742 ir->SetOrder(2*np - 3);
743
744#ifndef MFEM_USE_MPFR
745
746 // endpoints and respective weights
747 ir->IntPoint(0).x = 0.0;
748 ir->IntPoint(np-1).x = 1.0;
749 ir->IntPoint(0).weight = ir->IntPoint(np-1).weight = 1.0/(np*(np-1));
750
751 // interior points and weights
752 // use symmetry and compute just half of the points
753 for (int i = 1 ; i <= (np-1)/2 ; ++i)
754 {
755 // initial guess is the corresponding Chebyshev point, x_i:
756 // x_i = -cos(\pi * (i / (np-1)))
757 real_t x_i = std::sin(M_PI * ((real_t)(i)/(np-1) - 0.5));
758 real_t z_i = 0., p_l;
759 bool done = false;
760 for (int iter = 0 ; true ; ++iter)
761 {
762 // build Legendre polynomials, up to P_{np}(x_i)
763 real_t p_lm1 = 1.0;
764 p_l = x_i;
765
766 for (int l = 1 ; l < (np-1) ; ++l)
767 {
768 // The Legendre polynomials can be built by recursion:
769 // x * P_l(x) = 1/(2*l+1)*[ (l+1)*P_{l+1}(x) + l*P_{l-1} ], i.e.
770 // P_{l+1}(x) = [ (2*l+1)*x*P_l(x) - l*P_{l-1} ]/(l+1)
771 real_t p_lp1 = ( (2*l + 1)*x_i*p_l - l*p_lm1)/(l + 1);
772
773 p_lm1 = p_l;
774 p_l = p_lp1;
775 }
776 if (done) { break; }
777 // after this loop, p_l holds P_{np-1}(x_i)
778 // resid = (x^2-1)*P'_{np-1}(x_i)
779 // but use the recurrence relationship
780 // (x^2 -1)P'_l(x) = l*[ x*P_l(x) - P_{l-1}(x) ]
781 // thus, resid = (np-1) * (x_i*p_l - p_lm1)
782
783 // The derivative of the residual is:
784 // \frac{d}{d x} \left[ (x^2 -1)P'_l(x) ] \right] =
785 // l * (l+1) * P_l(x), with l = np-1,
786 // therefore, deriv = np * (np-1) * p_l;
787
788 // compute dx = resid/deriv
789 real_t dx = (x_i*p_l - p_lm1) / (np*p_l);
790#ifdef MFEM_USE_SINGLE
791 if (std::abs(dx) < 1e-7)
792#elif defined MFEM_USE_DOUBLE
793 if (std::abs(dx) < 1e-16)
794#else
795 MFEM_ABORT("Floating point type undefined");
796 if (std::abs(dx) < 1e-16)
797#endif
798 {
799 done = true;
800 // Map the point to the interval [0,1]
801 z_i = ((1.0 + x_i) - dx)/2;
802 // continue the computation: get p_l at the new point, then exit
803 }
804 // If the iteration does not converge fast, something is wrong.
805 MFEM_VERIFY(iter < 8, "np = " << np << ", i = " << i
806 << ", dx = " << dx);
807 // update x_i:
808 x_i -= dx;
809 }
810 // Map to the interval [0,1] and scale the weights
811 IntegrationPoint &ip = ir->IntPoint(i);
812 ip.x = z_i;
813 // w_i = (2/[ n*(n-1)*[P_{n-1}(x_i)]^2 ]) / 2
814 ip.weight = (real_t)(1.0 / (np*(np-1)*p_l*p_l));
815
816 // set the symmetric point
817 IntegrationPoint &symm_ip = ir->IntPoint(np-1-i);
818 symm_ip.x = 1.0 - z_i;
819 symm_ip.weight = ip.weight;
820 }
821
822#else // MFEM_USE_MPFR is defined
823
824 HP_Quadrature1D hp_quad;
825 // use symmetry and compute just half of the points
826 for (int i = 0 ; i <= (np-1)/2 ; ++i)
827 {
828 hp_quad.ComputeGaussLobattoPoint(np, i);
829 ir->IntPoint(i).x = hp_quad.GetPoint();
830 ir->IntPoint(np-1-i).x = hp_quad.GetSymmPoint();
831 ir->IntPoint(i).weight =
832 ir->IntPoint(np-1-i).weight = hp_quad.GetWeight();
833 }
834
835#endif // MFEM_USE_MPFR
836
837 }
838}
839
841{
842 ir->SetSize(np);
843 ir->SetPointIndices();
844 ir->SetOrder(np - 1 + np%2);
845
846 // The Newton-Cotes quadrature is based on weights that integrate exactly the
847 // interpolatory polynomial through the equally spaced quadrature points.
848 for (int i = 0; i < np ; ++i)
849 {
850 ir->IntPoint(i).x = real_t(i+1) / real_t(np + 1);
851 }
852
853 CalculateUniformWeights(ir, Quadrature1D::OpenUniform);
854}
855
857 IntegrationRule* ir)
858{
859 ir->SetSize(np);
860 ir->SetPointIndices();
861 ir->SetOrder(np - 1 + np%2);
862 if ( np == 1 ) // allow this case as "closed"
863 {
864 ir->IntPoint(0).Set1w(0.5, 1.0);
865 return;
866 }
867
868 for (int i = 0; i < np ; ++i)
869 {
870 ir->IntPoint(i).x = real_t(i) / (np-1);
871 }
872
873 CalculateUniformWeights(ir, Quadrature1D::ClosedUniform);
874}
875
877{
878 ir->SetSize(np);
879 ir->SetPointIndices();
880 ir->SetOrder(np - 1 + np%2);
881
882 // Open half points: the centers of np uniform intervals
883 for (int i = 0; i < np ; ++i)
884 {
885 ir->IntPoint(i).x = real_t(2*i+1) / (2*np);
886 }
887
888 CalculateUniformWeights(ir, Quadrature1D::OpenHalfUniform);
889}
890
892{
893 ir->SetSize(np);
894 ir->SetPointIndices();
895 ir->IntPoint(0).x = 0.0;
896 ir->IntPoint(np-1).x = 1.0;
897 ir->SetOrder(np - 1 + np%2); // Is this the correct order?
898
899 if ( np > 2 )
900 {
901 IntegrationRule gl_ir;
902 GaussLegendre(np-1, &gl_ir);
903
904 for (int i = 1; i < np-1; ++i)
905 {
906 ir->IntPoint(i).x = (gl_ir.IntPoint(i-1).x + gl_ir.IntPoint(i).x)/2;
907 }
908 }
909
910 CalculateUniformWeights(ir, Quadrature1D::ClosedGL);
911}
912
914 const int type)
915{
916 IntegrationRule ir(np);
917
918 switch (type)
919 {
921 {
922 GaussLegendre(np,&ir);
923 break;
924 }
926 {
927 GaussLobatto(np, &ir);
928 break;
929 }
931 {
932 OpenUniform(np,&ir);
933 break;
934 }
936 {
937 ClosedUniform(np,&ir);
938 break;
939 }
941 {
942 OpenHalfUniform(np, &ir);
943 break;
944 }
946 {
947 ClosedGL(np, &ir);
948 break;
949 }
951 {
952 MFEM_ABORT("Asking for an unknown type of 1D Quadrature points, "
953 "type = " << type);
954 }
955 }
956
957 for (int i = 0 ; i < np ; ++i)
958 {
959 pts[i] = ir.IntPoint(i).x;
960 }
961}
962
963void QuadratureFunctions1D::CalculateUniformWeights(IntegrationRule *ir,
964 const int type)
965{
966 /* The Lagrange polynomials are:
967 p_i = \prod_{j \neq i} {\frac{x - x_j }{x_i - x_j}}
968
969 The weight associated with each abscissa is the integral of p_i over
970 [0,1]. To calculate the integral of p_i, we use a Gauss-Legendre
971 quadrature rule. This approach does not suffer from bad round-off/
972 cancellation errors for large number of points.
973 */
974 const int n = ir->Size();
975 switch (n)
976 {
977 case 1:
978 ir->IntPoint(0).weight = 1.;
979 return;
980 case 2:
981 ir->IntPoint(0).weight = .5;
982 ir->IntPoint(1).weight = .5;
983 return;
984 }
985
986#ifndef MFEM_USE_MPFR
987
988 // This algorithm should work for any set of points, not just uniform
989 const IntegrationRule &glob_ir = IntRules.Get(Geometry::SEGMENT, n-1);
990 const int m = glob_ir.GetNPoints();
991 Vector xv(n);
992 for (int j = 0; j < n; j++)
993 {
994 xv(j) = ir->IntPoint(j).x;
995 }
996 Poly_1D::Basis basis(n-1, xv.GetData()); // nodal basis, with nodes at 'xv'
997 Vector w(n);
998 // Integrate all nodal basis functions using 'glob_ir':
999 w = 0.0;
1000 for (int i = 0; i < m; i++)
1001 {
1002 const IntegrationPoint &ip = glob_ir.IntPoint(i);
1003 basis.Eval(ip.x, xv);
1004 w.Add(ip.weight, xv); // w += ip.weight * xv
1005 }
1006 for (int j = 0; j < n; j++)
1007 {
1008 ir->IntPoint(j).weight = w(j);
1009 }
1010
1011#else // MFEM_USE_MPFR is defined
1012
1013 static const mpfr_rnd_t rnd = HP_Quadrature1D::rnd;
1014 HP_Quadrature1D hp_quad;
1015 mpfr_t l, lk, w0, wi, tmp, *weights;
1016 mpfr_inits2(hp_quad.default_prec, l, lk, w0, wi, tmp, (mpfr_ptr) 0);
1017 weights = new mpfr_t[n];
1018 for (int i = 0; i < n; i++)
1019 {
1020 mpfr_init2(weights[i], hp_quad.default_prec);
1021 mpfr_set_si(weights[i], 0, rnd);
1022 }
1023 hp_quad.SetRelTol(-48); // rtol = 2^(-48) ~ 3.5e-15
1024 const int p = n-1;
1025 const int m = p/2+1; // number of points for Gauss-Legendre quadrature
1026 int hinv = 0, ihoffset = 0; // x_i = (i+ihoffset/2)/hinv
1027 switch (type)
1028 {
1030 // x_i = i/p, i=0,...,p
1031 hinv = p;
1032 ihoffset = 0;
1033 break;
1035 // x_i = (i+1)/(p+2), i=0,...,p
1036 hinv = p+2;
1037 ihoffset = 2;
1038 break;
1040 // x_i = (i+1/2)/(p+1), i=0,...,p
1041 hinv = p+1;
1042 ihoffset = 1;
1043 break;
1048 MFEM_ABORT("invalid Quadrature1D type: " << type);
1049 }
1050 // set w0 = (-1)^p*(p!)/(hinv^p)
1051 mpfr_fac_ui(w0, p, rnd);
1052 mpfr_ui_pow_ui(tmp, hinv, p, rnd);
1053 mpfr_div(w0, w0, tmp, rnd);
1054 if (p%2) { mpfr_neg(w0, w0, rnd); }
1055
1056 for (int j = 0; j < m; j++)
1057 {
1058 hp_quad.ComputeGaussLegendrePoint(m, j);
1059
1060 // Compute l = \prod_{i=0}^p (x-x_i) and lk = l/(x-x_k), where
1061 // x = hp_quad.GetHPPoint(), x_i = (i+ihoffset/2)/hinv, and x_k is the
1062 // node closest to x, i.e. k = min(max(round(x*hinv-ihoffset/2),0),p)
1063 mpfr_mul_si(tmp, hp_quad.GetHPPoint(), hinv, rnd);
1064 mpfr_sub_d(tmp, tmp, 0.5*ihoffset, rnd);
1065 mpfr_round(tmp, tmp);
1066 int k = min(max((int)mpfr_get_si(tmp, rnd), 0), p);
1067 mpfr_set_si(lk, 1, rnd);
1068 for (int i = 0; i <= p; i++)
1069 {
1070 mpfr_set_si(tmp, 2*i+ihoffset, rnd);
1071 mpfr_div_si(tmp, tmp, 2*hinv, rnd);
1072 mpfr_sub(tmp, hp_quad.GetHPPoint(), tmp, rnd);
1073 if (i != k)
1074 {
1075 mpfr_mul(lk, lk, tmp, rnd);
1076 }
1077 else
1078 {
1079 mpfr_set(l, tmp, rnd);
1080 }
1081 }
1082 mpfr_mul(l, l, lk, rnd);
1083 mpfr_set(wi, w0, rnd);
1084 for (int i = 0; true; i++)
1085 {
1086 if (i != k)
1087 {
1088 // tmp = l/(wi*(x - x_i))
1089 mpfr_set_si(tmp, 2*i+ihoffset, rnd);
1090 mpfr_div_si(tmp, tmp, 2*hinv, rnd);
1091 mpfr_sub(tmp, hp_quad.GetHPPoint(), tmp, rnd);
1092 mpfr_mul(tmp, tmp, wi, rnd);
1093 mpfr_div(tmp, l, tmp, rnd);
1094 }
1095 else
1096 {
1097 // tmp = lk/wi
1098 mpfr_div(tmp, lk, wi, rnd);
1099 }
1100 // weights[i] += hp_quad.weight*tmp
1101 mpfr_mul(tmp, tmp, hp_quad.GetHPWeight(), rnd);
1102 mpfr_add(weights[i], weights[i], tmp, rnd);
1103
1104 if (i == p) { break; }
1105
1106 // update wi *= (i+1)/(i-p)
1107 mpfr_mul_si(wi, wi, i+1, rnd);
1108 mpfr_div_si(wi, wi, i-p, rnd);
1109 }
1110 }
1111 for (int i = 0; i < n; i++)
1112 {
1113 ir->IntPoint(i).weight = mpfr_get_d(weights[i], rnd);
1114 mpfr_clear(weights[i]);
1115 }
1116 delete [] weights;
1117 mpfr_clears(l, lk, w0, wi, tmp, (mpfr_ptr) 0);
1118
1119#endif // MFEM_USE_MPFR
1120
1121}
1122
1123
1125{
1126 switch (type)
1127 {
1128 case GaussLobatto:
1129 case ClosedUniform:
1130 case ClosedGL:
1131 return type;
1132 default:
1133 return Invalid;
1134 }
1135}
1136
1138{
1139 switch (type)
1140 {
1141 case GaussLegendre:
1142 case GaussLobatto:
1143 case OpenUniform:
1144 case ClosedUniform:
1145 case OpenHalfUniform:
1146 case ClosedGL:
1147 return type; // all types can work as open
1148 default:
1149 return Invalid;
1150 }
1151}
1152
1153
1155
1157
1159 : quad_type(type)
1160{
1161 refined = ref;
1162
1163 if (refined < 0) { own_rules = 0; return; }
1164
1165 own_rules = 1;
1166
1167 const MemoryType h_mt = MemoryType::HOST;
1168 PointIntRules.SetSize(2, h_mt);
1169 PointIntRules = NULL;
1170
1171 SegmentIntRules.SetSize(32, h_mt);
1172 SegmentIntRules = NULL;
1173
1174 // TriangleIntegrationRule() assumes that this size is >= 26
1175 TriangleIntRules.SetSize(32, h_mt);
1176 TriangleIntRules = NULL;
1177
1178 SquareIntRules.SetSize(32, h_mt);
1179 SquareIntRules = NULL;
1180
1181 // TetrahedronIntegrationRule() assumes that this size is >= 22
1182 TetrahedronIntRules.SetSize(32, h_mt);
1183 TetrahedronIntRules = NULL;
1184
1185 PyramidIntRules.SetSize(32, h_mt);
1186 PyramidIntRules = NULL;
1187
1188 PrismIntRules.SetSize(32, h_mt);
1189 PrismIntRules = NULL;
1190
1191 CubeIntRules.SetSize(32, h_mt);
1192 CubeIntRules = NULL;
1193
1194#if defined(MFEM_THREAD_SAFE) && defined(MFEM_USE_OPENMP)
1195 IntRuleLocks.SetSize(Geometry::NUM_GEOMETRIES, h_mt);
1196 for (int i = 0; i < Geometry::NUM_GEOMETRIES; i++)
1197 {
1198 omp_init_lock(&IntRuleLocks[i]);
1199 }
1200#endif
1201}
1202
1203const IntegrationRule &IntegrationRules::Get(int GeomType, int Order)
1204{
1205 Array<IntegrationRule *> *ir_array = NULL;
1206
1207 switch (GeomType)
1208 {
1209 case Geometry::POINT: ir_array = &PointIntRules; Order = 0; break;
1210 case Geometry::SEGMENT: ir_array = &SegmentIntRules; break;
1211 case Geometry::TRIANGLE: ir_array = &TriangleIntRules; break;
1212 case Geometry::SQUARE: ir_array = &SquareIntRules; break;
1213 case Geometry::TETRAHEDRON: ir_array = &TetrahedronIntRules; break;
1214 case Geometry::CUBE: ir_array = &CubeIntRules; break;
1215 case Geometry::PRISM: ir_array = &PrismIntRules; break;
1216 case Geometry::PYRAMID: ir_array = &PyramidIntRules; break;
1217 case Geometry::INVALID:
1219 MFEM_ABORT("Unknown type of reference element!");
1220 }
1221
1222 if (Order < 0)
1223 {
1224 Order = 0;
1225 }
1226
1227#if defined(MFEM_THREAD_SAFE) && defined(MFEM_USE_OPENMP)
1228 omp_set_lock(&IntRuleLocks[GeomType]);
1229#endif
1230
1231 if (!HaveIntRule(*ir_array, Order))
1232 {
1233 IntegrationRule *ir = GenerateIntegrationRule(GeomType, Order);
1234#ifdef MFEM_DEBUG
1235 int RealOrder = Order;
1236 while (RealOrder+1 < ir_array->Size() && (*ir_array)[RealOrder+1] == ir)
1237 {
1238 RealOrder++;
1239 }
1240 MFEM_VERIFY(RealOrder == ir->GetOrder(), "internal error");
1241#else
1242 MFEM_CONTRACT_VAR(ir);
1243#endif
1244 }
1245
1246#if defined(MFEM_THREAD_SAFE) && defined(MFEM_USE_OPENMP)
1247 omp_unset_lock(&IntRuleLocks[GeomType]);
1248#endif
1249
1250 return *(*ir_array)[Order];
1251}
1252
1253void IntegrationRules::Set(int GeomType, int Order, IntegrationRule &IntRule)
1254{
1255 Array<IntegrationRule *> *ir_array = NULL;
1256
1257 switch (GeomType)
1258 {
1259 case Geometry::POINT: ir_array = &PointIntRules; break;
1260 case Geometry::SEGMENT: ir_array = &SegmentIntRules; break;
1261 case Geometry::TRIANGLE: ir_array = &TriangleIntRules; break;
1262 case Geometry::SQUARE: ir_array = &SquareIntRules; break;
1263 case Geometry::TETRAHEDRON: ir_array = &TetrahedronIntRules; break;
1264 case Geometry::CUBE: ir_array = &CubeIntRules; break;
1265 case Geometry::PRISM: ir_array = &PrismIntRules; break;
1266 case Geometry::PYRAMID: ir_array = &PyramidIntRules; break;
1267 case Geometry::INVALID:
1269 MFEM_ABORT("Unknown type of reference element!");
1270 }
1271
1272#if defined(MFEM_THREAD_SAFE) && defined(MFEM_USE_OPENMP)
1273 omp_set_lock(&IntRuleLocks[GeomType]);
1274#endif
1275
1276 if (HaveIntRule(*ir_array, Order))
1277 {
1278 MFEM_ABORT("Overwriting set rules is not supported!");
1279 }
1280
1281 AllocIntRule(*ir_array, Order);
1282
1283 (*ir_array)[Order] = &IntRule;
1284
1285#if defined(MFEM_THREAD_SAFE) && defined(MFEM_USE_OPENMP)
1286 omp_unset_lock(&IntRuleLocks[GeomType]);
1287#endif
1288}
1289
1290void IntegrationRules::DeleteIntRuleArray(
1291 Array<IntegrationRule *> &ir_array) const
1292{
1293 // Many of the intrules have multiple contiguous copies in the ir_array
1294 // so we have to be careful to not delete them twice.
1295 IntegrationRule *ir = NULL;
1296 for (int i = 0; i < ir_array.Size(); i++)
1297 {
1298 if (ir_array[i] != NULL && ir_array[i] != ir)
1299 {
1300 ir = ir_array[i];
1301 delete ir;
1302 }
1303 }
1304}
1305
1307{
1308#if defined(MFEM_THREAD_SAFE) && defined(MFEM_USE_OPENMP)
1309 for (int i = 0; i < Geometry::NUM_GEOMETRIES; i++)
1310 {
1311 omp_destroy_lock(&IntRuleLocks[i]);
1312 }
1313#endif
1314
1315 if (!own_rules) { return; }
1316
1317 DeleteIntRuleArray(PointIntRules);
1318 DeleteIntRuleArray(SegmentIntRules);
1319 DeleteIntRuleArray(TriangleIntRules);
1320 DeleteIntRuleArray(SquareIntRules);
1321 DeleteIntRuleArray(TetrahedronIntRules);
1322 DeleteIntRuleArray(CubeIntRules);
1323 DeleteIntRuleArray(PrismIntRules);
1324 DeleteIntRuleArray(PyramidIntRules);
1325}
1326
1327
1328IntegrationRule *IntegrationRules::GenerateIntegrationRule(int GeomType,
1329 int Order)
1330{
1331 switch (GeomType)
1332 {
1333 case Geometry::POINT:
1334 return PointIntegrationRule(Order);
1335 case Geometry::SEGMENT:
1336 return SegmentIntegrationRule(Order);
1337 case Geometry::TRIANGLE:
1338 return TriangleIntegrationRule(Order);
1339 case Geometry::SQUARE:
1340 return SquareIntegrationRule(Order);
1342 return TetrahedronIntegrationRule(Order);
1343 case Geometry::CUBE:
1344 return CubeIntegrationRule(Order);
1345 case Geometry::PRISM:
1346 return PrismIntegrationRule(Order);
1347 case Geometry::PYRAMID:
1348 return PyramidIntegrationRule(Order);
1349 case Geometry::INVALID:
1351 MFEM_ABORT("Unknown type of reference element!");
1352 }
1353 return NULL;
1354}
1355
1356
1357// Integration rules for a point
1358IntegrationRule *IntegrationRules::PointIntegrationRule(int Order)
1359{
1360 if (Order > 1)
1361 {
1362 MFEM_ABORT("Point Integration Rule of Order > 1 not defined");
1363 return NULL;
1364 }
1365
1366 IntegrationRule *ir = new IntegrationRule(1);
1367 ir->IntPoint(0).x = .0;
1368 ir->IntPoint(0).weight = 1.;
1369 ir->SetOrder(1);
1370
1371 PointIntRules[1] = PointIntRules[0] = ir;
1372
1373 return ir;
1374}
1375
1376// Integration rules for line segment [0,1]
1377IntegrationRule *IntegrationRules::SegmentIntegrationRule(int Order)
1378{
1379 int RealOrder = GetSegmentRealOrder(Order); // RealOrder >= Order
1380 // Order is one of {RealOrder-1,RealOrder}
1381 AllocIntRule(SegmentIntRules, RealOrder);
1382
1383 IntegrationRule *ir = new IntegrationRule;
1384
1385 int n = 0;
1386 // n is the number of points to achieve the exact integral of a
1387 // degree Order polynomial
1388 switch (quad_type)
1389 {
1391 {
1392 // Gauss-Legendre is exact for 2*n-1
1393 n = Order/2 + 1;
1395 break;
1396 }
1398 {
1399 // Gauss-Lobatto is exact for 2*n-3
1400 n = Order/2 + 2;
1402 break;
1403 }
1405 {
1406 // Open Newton Cotes is exact for n-(n+1)%2 = n-1+n%2
1407 n = Order | 1; // n is always odd
1409 break;
1410 }
1412 {
1413 // Closed Newton Cotes is exact for n-(n+1)%2 = n-1+n%2
1414 n = Order | 1; // n is always odd
1416 break;
1417 }
1419 {
1420 // Open half Newton Cotes is exact for n-(n+1)%2 = n-1+n%2
1421 n = Order | 1; // n is always odd
1423 break;
1424 }
1426 {
1427 MFEM_ABORT("unknown Quadrature1D type: " << quad_type);
1428 }
1429 }
1430 if (refined)
1431 {
1432 // Effectively passing memory management to SegmentIntegrationRules
1433 IntegrationRule *refined_ir = new IntegrationRule(2*n);
1434 refined_ir->SetOrder(ir->GetOrder());
1435 for (int j = 0; j < n; j++)
1436 {
1437 refined_ir->IntPoint(j).x = ir->IntPoint(j).x/2.0;
1438 refined_ir->IntPoint(j).weight = ir->IntPoint(j).weight/2.0;
1439 refined_ir->IntPoint(j+n).x = 0.5 + ir->IntPoint(j).x/2.0;
1440 refined_ir->IntPoint(j+n).weight = ir->IntPoint(j).weight/2.0;
1441 }
1442 delete ir;
1443 ir = refined_ir;
1444 }
1445 SegmentIntRules[RealOrder-1] = SegmentIntRules[RealOrder] = ir;
1446 return ir;
1447}
1448
1449// Triangle rules from Witherden & Vincent [1].
1450// Orbit data from PyFR (https://pyfr.org), licensed under CC-BY 4.0.
1451IntegrationRule *IntegrationRules::TriangleIntegrationRule(int Order)
1452{
1453 IntegrationRule *ir = NULL;
1454
1455 switch (Order)
1456 {
1457 case 0:
1458 case 1:
1459 ir = new IntegrationRule(1);
1460 ir->AddTriMidPoint(0, 0.5);
1461 ir->SetOrder(1);
1462 TriangleIntRules[0] =
1463 TriangleIntRules[1] = ir;
1464 return ir;
1465
1466 case 2:
1467 ir = new IntegrationRule(3);
1468 ir->AddTriPoints3(0, 1./6., 1./6.);
1469 ir->SetOrder(2);
1470 TriangleIntRules[2] = ir;
1471 return ir;
1472
1473 case 3:
1474 case 4:
1475 ir = new IntegrationRule(6);
1476 ir->AddTriPoints3(0, 4.45948490915964890213e-01, 1.11690794839005735906e-01);
1477 ir->AddTriPoints3(3, 9.15762135097707430376e-02, 5.49758718276609353870e-02);
1478 ir->SetOrder(4);
1479 TriangleIntRules[3] =
1480 TriangleIntRules[4] = ir;
1481 return ir;
1482
1483 case 5:
1484 ir = new IntegrationRule(7);
1485 ir->AddTriMidPoint(0, 0.1125);
1486 ir->AddTriPoints3(1, 1.01286507323456342888e-01, 6.29695902724135697648e-02);
1487 ir->AddTriPoints3(4, 4.70142064105115109474e-01, 6.61970763942530959767e-02);
1488 ir->SetOrder(5);
1489 TriangleIntRules[5] = ir;
1490 return ir;
1491
1492 case 6:
1493 ir = new IntegrationRule(12);
1494 ir->AddTriPoints3(0, 6.30890144915022266225e-02, 2.54224531851034094010e-02);
1495 ir->AddTriPoints3(3, 2.49286745170910428726e-01, 5.83931378631896841336e-02);
1496 ir->AddTriPoints6(6, 6.36502499121398668258e-01, 3.10352451033784393353e-01,
1497 4.14255378091867854096e-02);
1498 ir->SetOrder(6);
1499 TriangleIntRules[6] = ir;
1500 return ir;
1501
1502 case 7:
1503 ir = new IntegrationRule(15);
1504 ir->AddTriPoints3(0, 3.37306485545878498300e-02, 8.27252505539606552976e-03);
1505 ir->AddTriPoints3(3, 2.41577382595403566956e-01, 6.39720856150777922311e-02);
1506 ir->AddTriPoints3(6, 4.74309692504718327655e-01, 3.85433230929930342734e-02);
1507 ir->AddTriPoints6(9, 7.54280040550053154647e-01, 1.98683314797351684433e-01,
1508 2.79393664515998896292e-02);
1509 ir->SetOrder(7);
1510 TriangleIntRules[7] = ir;
1511 return ir;
1512
1513 case 8:
1514 ir = new IntegrationRule(16);
1515 ir->AddTriMidPoint(0, 7.21578038388935860681e-02);
1516 ir->AddTriPoints3(1, 4.59292588292723236165e-01, 4.75458171336423096598e-02);
1517 ir->AddTriPoints3(4, 1.70569307751760268488e-01, 5.16086852673591223173e-02);
1518 ir->AddTriPoints3(7, 5.05472283170309566458e-02, 1.62292488115990396480e-02);
1519 ir->AddTriPoints6(10, 7.28492392955404244326e-01, 2.63112829634638112353e-01,
1520 1.36151570872174963733e-02);
1521 ir->SetOrder(8);
1522 TriangleIntRules[8] = ir;
1523 return ir;
1524
1525 case 9:
1526 ir = new IntegrationRule(19);
1527 ir->AddTriMidPoint(0, 4.85678981413994181882e-02);
1528 ir->AddTriPoints3(1, 4.37089591492936690997e-01, 3.89137705023871391385e-02);
1529 ir->AddTriPoints3(4, 1.88203535619032802373e-01, 3.98238694636051243636e-02);
1530 ir->AddTriPoints3(7, 4.89682519198737620236e-01, 1.56673501135695357467e-02);
1531 ir->AddTriPoints3(10, 4.47295133944527467662e-02, 1.27888378293490156262e-02);
1532 ir->AddTriPoints6(13, 7.41198598784498008385e-01, 2.21962989160765733487e-01,
1533 2.16417696886446880855e-02);
1534 ir->SetOrder(9);
1535 TriangleIntRules[9] = ir;
1536 return ir;
1537
1538 case 10:
1539 ir = new IntegrationRule(25);
1540 ir->AddTriMidPoint(0, 4.08716645731429864541e-02);
1541 ir->AddTriPoints3(1, 3.20553732169435168231e-02, 6.67648440657478327992e-03);
1542 ir->AddTriPoints3(4, 1.42161101056564431744e-01, 2.29789818023723654838e-02);
1543 ir->AddTriPoints6(7, 5.30054118927343997925e-01, 3.21812995288835446139e-01,
1544 3.19524531982120219009e-02);
1545 ir->AddTriPoints6(13, 6.01233328683459244957e-01, 3.69146781827810910315e-01,
1546 1.70923240814797143539e-02);
1547 ir->AddTriPoints6(19, 8.07930600922879049719e-01, 1.63701733737182442141e-01,
1548 1.26488788536441923438e-02);
1549 ir->SetOrder(10);
1550 TriangleIntRules[10] = ir;
1551 return ir;
1552
1553 case 11:
1554 ir = new IntegrationRule(28);
1555 ir->AddTriMidPoint(0, 4.28805898661121093207e-02);
1556 ir->AddTriPoints3(1, 2.84854176143718995640e-02, 5.21593525644734826857e-03);
1557 ir->AddTriPoints3(4, 2.10219956703178278978e-01, 3.52578420558582877886e-02);
1558 ir->AddTriPoints3(7, 1.02635482712246428605e-01, 1.93153796185096607307e-02);
1559 ir->AddTriPoints3(10, 4.95891900965890919384e-01, 8.30313652729268436570e-03);
1560 ir->AddTriPoints3(13, 4.38465926764352253997e-01, 3.36580770397341480504e-02);
1561 ir->AddTriPoints6(16, 8.43349783661853091843e-01, 1.49324788652082374174e-01,
1562 5.14514478647663895533e-03);
1563 ir->AddTriPoints6(22, 6.64408374196864159877e-01, 2.89581125637705882880e-01,
1564 2.01662383202502772106e-02);
1565 ir->SetOrder(11);
1566 TriangleIntRules[11] = ir;
1567 return ir;
1568
1569 case 12:
1570 ir = new IntegrationRule(33);
1571 ir->AddTriPoints3(0, 4.88203750945541581352e-01, 1.21334190407260157640e-02);
1572 ir->AddTriPoints3(3, 1.09257827659354322947e-01, 1.42430260344387719235e-02);
1573 ir->AddTriPoints3(6, 2.71462507014926135440e-01, 3.12706065979513822550e-02);
1574 ir->AddTriPoints3(9, 2.46463634363356387524e-02, 3.96582125498681943576e-03);
1575 ir->AddTriPoints3(12, 4.40111648658593201944e-01, 2.49591674640304711508e-02);
1576 ir->AddTriPoints6(15, 6.85310163906391878186e-01, 2.91655679738340944951e-01,
1577 1.08917925193037796322e-02);
1578 ir->AddTriPoints6(21, 6.28249751683556123538e-01, 2.55454228638517299999e-01,
1579 2.16136818297071042760e-02);
1580 ir->AddTriPoints6(27, 8.51337792510240110033e-01, 1.27279717233589384495e-01,
1581 7.54183878825571887144e-03);
1582 ir->SetOrder(12);
1583 TriangleIntRules[12] = ir;
1584 return ir;
1585
1586 case 13:
1587 ir = new IntegrationRule(37);
1588 ir->AddTriMidPoint(0, 3.39800182934158201409e-02);
1589 ir->AddTriPoints3(1, 4.89076946452539351728e-01, 1.19972009644473652512e-02);
1590 ir->AddTriPoints3(4, 2.21372286291832920391e-01, 2.91392425595999905730e-02);
1591 ir->AddTriPoints3(7, 4.26941414259800422482e-01, 2.78009837652266646180e-02);
1592 ir->AddTriPoints3(10, 2.15096811088433259584e-02, 3.02616855176958583773e-03);
1593 ir->AddTriPoints6(13, 7.48507115899952224503e-01, 1.63597401067850478640e-01,
1594 1.20895199057969096601e-02);
1595 ir->AddTriPoints6(19, 8.64707770295442768038e-01, 1.10922042803463405392e-01,
1596 7.48270055258283377231e-03);
1597 ir->AddTriPoints6(25, 6.23545995553675513889e-01, 3.08441760892117777804e-01,
1598 1.73206380704241866275e-02);
1599 ir->AddTriPoints6(31, 7.22357793124188019007e-01, 2.72515817773429591675e-01,
1600 4.79534050177163155559e-03);
1601 ir->SetOrder(13);
1602 TriangleIntRules[13] = ir;
1603 return ir;
1604
1605 case 14:
1606 ir = new IntegrationRule(42);
1607 ir->AddTriPoints3(0, 1.77205532412543442788e-01, 2.10812943684965080349e-02);
1608 ir->AddTriPoints3(3, 4.17644719340453940415e-01, 1.63941767720626740967e-02);
1609 ir->AddTriPoints3(6, 6.17998830908725871325e-02, 7.21684983488833382143e-03);
1610 ir->AddTriPoints3(9, 4.88963910362178677538e-01, 1.09417906847144447147e-02);
1611 ir->AddTriPoints3(12, 2.73477528308838646609e-01, 2.58870522536457925433e-02);
1612 ir->AddTriPoints3(15, 1.93909612487010996063e-02, 2.46170180120004094063e-03);
1613 ir->AddTriPoints6(18, 6.86980167808087793802e-01, 2.98372882136257788765e-01,
1614 7.21815405676692022074e-03);
1615 ir->AddTriPoints6(24, 7.70608554774996457049e-01, 1.72266687821355679588e-01,
1616 1.23328766062818367955e-02);
1617 ir->AddTriPoints6(30, 5.70222290846683188548e-01, 3.36861459796344964168e-01,
1618 1.92857553935303419057e-02);
1619 ir->AddTriPoints6(36, 8.79757171370171064950e-01, 1.18974497696956893478e-01,
1620 2.50511441925033596229e-03);
1621 ir->SetOrder(14);
1622 TriangleIntRules[14] = ir;
1623 return ir;
1624
1625 case 15:
1626 ir = new IntegrationRule(49);
1627 ir->AddTriMidPoint(0, 2.21676936910920364954e-02);
1628 ir->AddTriPoints3(1, 4.05362214133975495844e-01, 2.13568907857302828224e-02);
1629 ir->AddTriPoints3(4, 7.01735528999860580512e-02, 8.22236878131258133728e-03);
1630 ir->AddTriPoints3(7, 4.74170681438019769871e-01, 8.69807400038170690226e-03);
1631 ir->AddTriPoints3(10, 2.26378713420349653163e-01, 2.33916808643548149171e-02);
1632 ir->AddTriPoints3(13, 4.94996956769126195130e-01, 4.78692309123004283711e-03);
1633 ir->AddTriPoints3(16, 1.58117262509887002153e-02, 1.48038731895268772104e-03);
1634 ir->AddTriPoints6(19, 6.66975644801868106093e-01, 3.14648242812450851247e-01,
1635 7.80128641528798211224e-03);
1636 ir->AddTriPoints6(25, 9.19912157726236134891e-01, 7.09486052364554087291e-02,
1637 2.01492668600904969653e-03);
1638 ir->AddTriPoints6(31, 7.15222356931450642392e-01, 1.90535589476393929509e-01,
1639 1.43602934626006709801e-02);
1640 ir->AddTriPoints6(37, 8.13292641049419229304e-01, 1.68068645222414381202e-01,
1641 5.83631059078792285844e-03);
1642 ir->AddTriPoints6(43, 5.65252664877114230357e-01, 3.38950611475277163720e-01,
1643 1.56577381424846430458e-02);
1644 ir->SetOrder(15);
1645 TriangleIntRules[15] = ir;
1646 return ir;
1647
1648 case 16:
1649 ir = new IntegrationRule(55);
1650 ir->AddTriMidPoint(0, 2.26322830369093952463e-02);
1651 ir->AddTriPoints3(1, 2.45990070467141719313e-01, 2.05464615718494759966e-02);
1652 ir->AddTriPoints3(4, 4.15584896885420551627e-01, 2.03559166562126796218e-02);
1653 ir->AddTriPoints3(7, 8.53555665867003487968e-02, 7.39081734511220188322e-03);
1654 ir->AddTriPoints3(10, 1.61918644191271221544e-01, 1.47092048494940497855e-02);
1655 ir->AddTriPoints3(13, 5.00000000000000000000e-01, 2.20927315607528452004e-03);
1656 ir->AddTriPoints3(16, 4.75280727545942083268e-01, 1.29871666491385793357e-02);
1657 ir->AddTriPoints6(19, 7.54170061444767725334e-01, 1.91074763640529221576e-01,
1658 9.46913623220784969603e-03);
1659 ir->AddTriPoints6(25, 9.68244368030958701965e-01, 2.32034277688137335893e-02,
1660 8.27233357417524097638e-04);
1661 ir->AddTriPoints6(31, 6.49303698245446425652e-01, 3.31764523474147643434e-01,
1662 7.50430089214290316213e-03);
1663 ir->AddTriPoints6(37, 9.00273703270429548340e-01, 8.06961669858730079596e-02,
1664 3.97379696669624901673e-03);
1665 ir->AddTriPoints6(43, 5.89148840564247877616e-01, 3.08244969196354023921e-01,
1666 1.59918050396850343342e-02);
1667 ir->AddTriPoints6(49, 8.06621867499395683865e-01, 1.87441782483782071189e-01,
1668 2.69559355842440570919e-03);
1669 ir->SetOrder(16);
1670 TriangleIntRules[16] = ir;
1671 return ir;
1672
1673 case 17:
1674 ir = new IntegrationRule(60);
1675 ir->AddTriPoints3(0, 4.17103444361599295931e-01, 1.36554632640510532210e-02);
1676 ir->AddTriPoints3(3, 1.47554916607539610141e-02, 1.38694378881882109979e-03);
1677 ir->AddTriPoints3(6, 4.65597871618890324363e-01, 1.25097254752486782697e-02);
1678 ir->AddTriPoints3(9, 1.80358116266370605008e-01, 1.31563152940089925225e-02);
1679 ir->AddTriPoints3(12, 6.66540634795969033632e-02, 6.22950040115272107855e-03);
1680 ir->AddTriPoints3(15, 2.85706502436586629035e-01, 1.88581185763976415248e-02);
1681 ir->AddTriPoints6(18, 8.24790070165088096132e-01, 1.59192287472792681768e-01,
1682 3.98915010296479674579e-03);
1683 ir->AddTriPoints6(24, 6.26369030386452196879e-01, 3.06281591746186521164e-01,
1684 1.12438862733455335191e-02);
1685 ir->AddTriPoints6(30, 5.71294867944684092720e-01, 4.15475459295228999324e-01,
1686 5.19921997791976831654e-03);
1687 ir->AddTriPoints6(36, 7.53235145936458128091e-01, 1.68722513495259462957e-01,
1688 1.02789491602272593102e-02);
1689 ir->AddTriPoints6(42, 7.15072259110642427515e-01, 2.71791870055354878311e-01,
1690 4.34610725050059605590e-03);
1691 ir->AddTriPoints6(48, 9.15919353297816929427e-01, 7.25054707990024915887e-02,
1692 2.29217420086793351869e-03);
1693 ir->AddTriPoints6(54, 5.43275579596159796658e-01, 2.99218942476970228839e-01,
1694 1.30858129676684944304e-02);
1695 ir->SetOrder(17);
1696 TriangleIntRules[17] = ir;
1697 return ir;
1698
1699 case 18:
1700 ir = new IntegrationRule(67);
1701 ir->AddTriMidPoint(0, 1.81778676507133342410e-02);
1702 ir->AddTriPoints3(1, 3.99955628067576229867e-01, 1.66522350166950668104e-02);
1703 ir->AddTriPoints3(4, 4.87580301574869645620e-01, 6.02332381699985548729e-03);
1704 ir->AddTriPoints3(7, 4.61809506406449243876e-01, 9.47458575338943308208e-03);
1705 ir->AddTriPoints3(10, 2.42264702514271956790e-01, 1.82375447044718190515e-02);
1706 ir->AddTriPoints3(13, 3.88302560886856218403e-02, 3.56466300985948522304e-03);
1707 ir->AddTriPoints3(16, 9.19477421216432500017e-02, 8.27957997600162372287e-03);
1708 ir->AddTriPoints6(19, 7.70372376214675247397e-01, 1.83822707925463957324e-01,
1709 6.87980811747110256732e-03);
1710 ir->AddTriPoints6(25, 6.70953985194234547862e-01, 2.06349257433837918185e-01,
1711 1.18909554500764153007e-02);
1712 ir->AddTriPoints6(31, 6.00418954634256873959e-01, 3.95683434332269712286e-01,
1713 2.26526725112853252742e-03);
1714 ir->AddTriPoints6(37, 8.78342189467521738955e-01, 1.08195793791033278985e-01,
1715 3.42005505980359086893e-03);
1716 ir->AddTriPoints6(43, 6.39988092004714625993e-01, 3.19751624525377309283e-01,
1717 8.87374455101020212511e-03);
1718 ir->AddTriPoints6(49, 7.58929479855198430016e-01, 2.35772184958191743931e-01,
1719 2.50533043728986106261e-03);
1720 ir->AddTriPoints6(55, 9.72360728962795684005e-01, 2.70909109951620319379e-02,
1721 6.11474063480544911126e-04);
1722 ir->AddTriPoints6(61, 5.45918775386194599086e-01, 3.33493529449880754534e-01,
1723 1.27410876559122202695e-02);
1724 ir->SetOrder(18);
1725 TriangleIntRules[18] = ir;
1726 return ir;
1727
1728 case 19:
1729 ir = new IntegrationRule(73);
1730 ir->AddTriMidPoint(0, 1.72346988520061666916e-02);
1731 ir->AddTriPoints3(1, 5.25238903512089683190e-02, 3.55462829889906543543e-03);
1732 ir->AddTriPoints3(4, 4.92512675041336889237e-01, 5.16087757147214078873e-03);
1733 ir->AddTriPoints3(7, 1.11448873323021391268e-01, 7.61717554650914990128e-03);
1734 ir->AddTriPoints3(10, 4.59194201039543670184e-01, 1.14917950133708035576e-02);
1735 ir->AddTriPoints3(13, 4.03969722551901222474e-01, 1.57687674465774863020e-02);
1736 ir->AddTriPoints3(16, 1.78170104781764315760e-01, 1.23259574240954274116e-02);
1737 ir->AddTriPoints3(19, 1.16394611837894457196e-02, 8.82661388221423837477e-04);
1738 ir->AddTriPoints3(22, 2.55161632913607716588e-01, 1.58765096830015377261e-02);
1739 ir->AddTriPoints6(25, 8.30156464400275351245e-01, 1.30697676268032414448e-01,
1740 4.84774224342752330097e-03);
1741 ir->AddTriPoints6(31, 5.59369805720300927732e-01, 3.11317629809541251973e-01,
1742 1.31731609886953666272e-02);
1743 ir->AddTriPoints6(37, 6.33313293128784149388e-01, 3.64617780974611060962e-01,
1744 1.64103827591790965915e-03);
1745 ir->AddTriPoints6(43, 7.04004819966042139079e-01, 2.21434885432331141075e-01,
1746 9.05397246560622585843e-03);
1747 ir->AddTriPoints6(49, 8.52566954376889230005e-01, 1.42425757365756355810e-01,
1748 1.46315755173510018451e-03);
1749 ir->AddTriPoints6(55, 6.05083979068707922266e-01, 3.54028009735275261960e-01,
1750 8.05108138201205379703e-03);
1751 ir->AddTriPoints6(61, 7.43181368957436361278e-01, 2.41894578960579587079e-01,
1752 4.22794374976824798712e-03);
1753 ir->AddTriPoints6(67, 9.30137698876805085746e-01, 6.00862753223067036501e-02,
1754 1.66360068142969402642e-03);
1755 ir->SetOrder(19);
1756 TriangleIntRules[19] = ir;
1757 return ir;
1758
1759 case 20:
1760 ir = new IntegrationRule(79);
1761 ir->AddTriMidPoint(0, 1.39101107014531159140e-02);
1762 ir->AddTriPoints3(1, 2.54579267673339160183e-01, 1.40832013075202471669e-02);
1763 ir->AddTriPoints3(4, 1.09761410283977789426e-02, 7.98840791066619858654e-04);
1764 ir->AddTriPoints3(7, 1.09383596711714603522e-01, 7.83023077607453328597e-03);
1765 ir->AddTriPoints3(10, 1.86294997744540946627e-01, 9.17346297425291473671e-03);
1766 ir->AddTriPoints3(13, 4.45551056955924895675e-01, 9.45239993323244813428e-03);
1767 ir->AddTriPoints3(16, 3.73108805988847103130e-02, 2.16127541066557732688e-03);
1768 ir->AddTriPoints3(19, 3.93425347817099924086e-01, 1.37880506290704585304e-02);
1769 ir->AddTriPoints3(22, 4.76245611540499047543e-01, 7.10182530340844071076e-03);
1770 ir->AddTriPoints6(25, 8.33295511838236246938e-01, 1.59133707657067247077e-01,
1771 2.20289741855849742491e-03);
1772 ir->AddTriPoints6(31, 7.54921502863547422280e-01, 1.98518132228788335425e-01,
1773 5.98639857895469015836e-03);
1774 ir->AddTriPoints6(37, 9.31054476783942153162e-01, 6.40905856084340586065e-02,
1775 1.12986960212586558597e-03);
1776 ir->AddTriPoints6(43, 6.11877703547425655373e-01, 3.33134817309587605294e-01,
1777 8.66722556721933289070e-03);
1778 ir->AddTriPoints6(49, 8.61684018936486717521e-01, 9.99522962881386756173e-02,
1779 4.14571152761385782609e-03);
1780 ir->AddTriPoints6(55, 6.78165737889635522606e-01, 2.15607057390094447591e-01,
1781 7.72260782209923009323e-03);
1782 ir->AddTriPoints6(61, 5.70144692890973359134e-01, 4.20023758816224113133e-01,
1783 3.69568150025529782929e-03);
1784 ir->AddTriPoints6(67, 5.42331804172428100230e-01, 3.17860123835772001577e-01,
1785 1.16917457318277372147e-02);
1786 ir->AddTriPoints6(73, 7.08681375720323636358e-01, 2.80581411423665327831e-01,
1787 3.57820023845768515197e-03);
1788 ir->SetOrder(20);
1789 TriangleIntRules[20] = ir;
1790 return ir;
1791
1792 case 21:
1793 case 22:
1794 case 23:
1795 case 24:
1796 case 25:
1797 ir = new IntegrationRule(126);
1798 ir->AddTriPoints3b(0, 0.0279464830731742, 0.0040027909400102085);
1799 ir->AddTriPoints3b(3, 0.131178601327651467, 0.00797353841619525);
1800 ir->AddTriPoints3b(6, 0.220221729512072267, 0.006554570615397765);
1801 ir->AddTriPoints3 (9, 0.298443234019804467, 0.00979150048281781);
1802 ir->AddTriPoints3(12, 0.2340441723373718, 0.008235442720768635);
1803 ir->AddTriPoints3(15, 0.151468334609017567, 0.00427363953704605);
1804 ir->AddTriPoints3(18, 0.112733893545993667, 0.004080942928613246);
1805 ir->AddTriPoints3(21, 0.0777156920915263, 0.0030605732699918895);
1806 ir->AddTriPoints3(24, 0.034893093614297, 0.0014542491324683325);
1807 ir->AddTriPoints3(27, 0.00725818462093236667, 0.00034613762283099815);
1808 ir->AddTriPoints6(30, 0.0012923527044422, 0.227214452153364077,
1809 0.0006241445996386985);
1810 ir->AddTriPoints6(36, 0.0053997012721162, 0.435010554853571706,
1811 0.001702376454401511);
1812 ir->AddTriPoints6(42, 0.006384003033975, 0.320309599272204437,
1813 0.0016798271630320255);
1814 ir->AddTriPoints6(48, 0.00502821150199306667, 0.0917503222800051889,
1815 0.000858078269748377);
1816 ir->AddTriPoints6(54, 0.00682675862178186667, 0.0380108358587243835,
1817 0.000740428158357803);
1818 ir->AddTriPoints6(60, 0.0100161996399295333, 0.157425218485311668,
1819 0.0017556563053643425);
1820 ir->AddTriPoints6(66, 0.02575781317339, 0.239889659778533193,
1821 0.003696775074853242);
1822 ir->AddTriPoints6(72, 0.0302278981199158, 0.361943118126060531,
1823 0.003991543738688279);
1824 ir->AddTriPoints6(78, 0.0305049901071620667, 0.0835519609548285602,
1825 0.0021779813065790205);
1826 ir->AddTriPoints6(84, 0.0459565473625693333, 0.148443220732418205,
1827 0.003682528350708916);
1828 ir->AddTriPoints6(90, 0.0674428005402775333, 0.283739708727534955,
1829 0.005481786423209775);
1830 ir->AddTriPoints6(96, 0.0700450914159106, 0.406899375118787573,
1831 0.00587498087177056);
1832 ir->AddTriPoints6(102, 0.0839115246401166, 0.194113987024892542,
1833 0.005007800356899285);
1834 ir->AddTriPoints6(108, 0.120375535677152667, 0.32413434700070316,
1835 0.00665482039381434);
1836 ir->AddTriPoints6(114, 0.148066899157366667, 0.229277483555980969,
1837 0.00707722325261307);
1838 ir->AddTriPoints6(120, 0.191771865867325067, 0.325618122595983752,
1839 0.007440689780584005);
1840 ir->SetOrder(25);
1841 TriangleIntRules[21] =
1842 TriangleIntRules[22] =
1843 TriangleIntRules[23] =
1844 TriangleIntRules[24] =
1845 TriangleIntRules[25] = ir;
1846 return ir;
1847
1848 default:
1849 // Grundmann-Moller fallback for orders beyond tabulated rules
1850 int i = (Order / 2) * 2 + 1; // closest odd >= Order
1851 AllocIntRule(TriangleIntRules, i);
1852 ir = new IntegrationRule;
1853 ir->GrundmannMollerSimplexRule(i/2, 2);
1854 if (!TriangleIntRules[i-1]) { TriangleIntRules[i-1] = ir; }
1855 TriangleIntRules[i] = ir;
1856 return ir;
1857 }
1858}
1859
1860// Integration rules for unit square
1861IntegrationRule *IntegrationRules::SquareIntegrationRule(int Order)
1862{
1863 int RealOrder = GetSegmentRealOrder(Order);
1864 // Order is one of {RealOrder-1,RealOrder}
1865 if (!HaveIntRule(SegmentIntRules, RealOrder))
1866 {
1867 SegmentIntegrationRule(RealOrder);
1868 }
1869 AllocIntRule(SquareIntRules, RealOrder); // RealOrder >= Order
1870 SquareIntRules[RealOrder-1] =
1871 SquareIntRules[RealOrder] =
1872 new IntegrationRule(*SegmentIntRules[RealOrder],
1873 *SegmentIntRules[RealOrder]);
1874 return SquareIntRules[Order];
1875}
1876
1877// Tet rules d=0-13 from Witherden & Vincent [1], orbit data from PyFR, CC-BY 4.0.
1878// Tet rules d=14-20 from Chuluunbaatar et al. [2], supplementary data.
1879IntegrationRule *IntegrationRules::TetrahedronIntegrationRule(int Order)
1880{
1881 IntegrationRule *ir = NULL;
1882
1883 switch (Order)
1884 {
1885 case 0:
1886 case 1:
1887 ir = new IntegrationRule(1);
1888 ir->AddTetMidPoint(0, 1./6.);
1889 ir->SetOrder(1);
1890 TetrahedronIntRules[0] =
1891 TetrahedronIntRules[1] = ir;
1892 return ir;
1893
1894 case 2:
1895 ir = new IntegrationRule(4);
1896 ir->AddTetPoints4(0, 1.38196601125010531952e-01, 1./24.);
1897 ir->SetOrder(2);
1898 TetrahedronIntRules[2] = ir;
1899 return ir;
1900
1901 case 3:
1902 ir = new IntegrationRule(8);
1903 ir->AddTetPoints4(0, 3.28163302516381705232e-01, 2.27029737561812265667e-02);
1904 ir->AddTetPoints4(4, 1.08047249898428621151e-01, 1.89636929104854412564e-02);
1905 ir->SetOrder(3);
1906 TetrahedronIntRules[3] = ir;
1907 return ir;
1908
1909 case 4:
1910 case 5:
1911 ir = new IntegrationRule(14);
1912 ir->AddTetPoints4(0, 3.10885919263300669613e-01, 1.87813209530026427319e-02);
1913 ir->AddTetPoints4(4, 9.27352503108912484819e-02, 1.22488405193936587129e-02);
1914 ir->AddTetPoints6(8, 4.54496295874350364485e-01, 7.09100346284691120807e-03);
1915 ir->SetOrder(5);
1916 TetrahedronIntRules[4] =
1917 TetrahedronIntRules[5] = ir;
1918 return ir;
1919
1920 case 6:
1921 ir = new IntegrationRule(24);
1922 ir->AddTetPoints4(0, 4.06739585346113652342e-02, 1.67953517588677390775e-03);
1923 ir->AddTetPoints4(4, 3.22337890142275540484e-01, 9.22619692394245453915e-03);
1924 ir->AddTetPoints4(8, 2.14602871259152117034e-01, 6.65379170969458179352e-03);
1925 ir->AddTetPoints12(12, 6.36610018750174977420e-02, 6.03005664791649187428e-01,
1926 8.03571428571428492127e-03);
1927 ir->SetOrder(6);
1928 TetrahedronIntRules[6] = ir;
1929 return ir;
1930
1931 case 7:
1932 ir = new IntegrationRule(35);
1933 ir->AddTetMidPoint(0, 1.59142149106884754628e-02);
1934 ir->AddTetPoints4(1, 3.15701149778202794227e-01, 7.05493020166117132397e-03);
1935 ir->AddTetPoints6(5, 4.49510177401603649994e-01, 5.31615463880959638471e-03);
1936 ir->AddTetPoints12(11, 1.88833831026001153219e-01, 5.75171637586999962011e-01,
1937 6.20118845472243662709e-03);
1938 ir->AddTetPoints12(23, 2.12654725414832546093e-02, 8.10830241098548620826e-01,
1939 1.35179513831722359664e-03);
1940 ir->SetOrder(7);
1941 TetrahedronIntRules[7] = ir;
1942 return ir;
1943
1944 case 8:
1945 ir = new IntegrationRule(46);
1946 ir->AddTetPoints4(0, 1.07952724962210866444e-01, 4.40444181806813866292e-03);
1947 ir->AddTetPoints4(4, 1.85109487782586568105e-01, 8.67195792728975463348e-03);
1948 ir->AddTetPoints4(8, 4.23165436847673381848e-02, 1.25420935892336655841e-03);
1949 ir->AddTetPoints4(12, 3.14181709124039088010e-01, 6.96063047615581593358e-03);
1950 ir->AddTetPoints6(16, 4.35591328583830206256e-01, 6.04682171021813687217e-03);
1951 ir->AddTetPoints12(22, 2.14339301271305737728e-02, 7.17464063426308307214e-01,
1952 1.19281714847407210867e-03);
1953 ir->AddTetPoints12(34, 2.04139333876029116510e-01, 5.83797378302144398532e-01,
1954 2.57558102516005586052e-03);
1955 ir->SetOrder(8);
1956 TetrahedronIntRules[8] = ir;
1957 return ir;
1958
1959 case 9:
1960 ir = new IntegrationRule(59);
1961 ir->AddTetMidPoint(0, 9.66842481874670943431e-03);
1962 ir->AddTetPoints4(1, 6.19817086544571793638e-10, 1.07198802932093984424e-05);
1963 ir->AddTetPoints4(5, 1.60774535395261597426e-01, 3.86222307707090968185e-03);
1964 ir->AddTetPoints4(9, 3.22276521821420969260e-01, 4.92715205590488116577e-03);
1965 ir->AddTetPoints4(13, 4.51089183454135844720e-02, 1.34399666326936377374e-03);
1966 ir->AddTetPoints6(17, 3.87703453995623947836e-01, 6.35568001728374458448e-03);
1967 ir->AddTetPoints12(23, 4.58871448752459276665e-01, 7.97025232620401369310e-02,
1968 1.39740369971642539558e-03);
1969 ir->AddTetPoints12(35, 3.37758706853386048152e-02, 7.18350326442074527122e-01,
1970 1.70575989212422133613e-03);
1971 ir->AddTetPoints12(47, 1.83641369809927956780e-01, 5.98301349801968918030e-01,
1972 3.42081932799802312939e-03);
1973 ir->SetOrder(9);
1974 TetrahedronIntRules[9] = ir;
1975 return ir;
1976
1977 case 10:
1978 ir = new IntegrationRule(81);
1979 ir->AddTetMidPoint(0, 7.89996225933678984654e-03);
1980 ir->AddTetPoints4(1, 3.12250068695188676138e-01, 4.48950999871145037950e-03);
1981 ir->AddTetPoints4(5, 1.14309653857346149586e-01, 1.64485995279889710662e-03);
1982 ir->AddTetPoints12(9, 4.10430739218965501269e-01, 1.65486025619611065718e-01,
1983 1.89898020336587186781e-03);
1984 ir->AddTetPoints12(21, 6.13800882479076381770e-03, 9.42988767345204870196e-01,
1985 6.03240573898756009806e-05);
1986 ir->AddTetPoints12(33, 1.21050181145589408338e-01, 4.77190379904280370660e-01,
1987 4.28995533007601147213e-03);
1988 ir->AddTetPoints12(45, 3.27794682164426753879e-02, 5.94256269480006982242e-01,
1989 1.68931194662596552945e-03);
1990 ir->AddTetPoints12(57, 3.24852815648231096901e-02, 8.01177284658344368573e-01,
1991 1.09602454617265063913e-03);
1992 ir->AddTetPoints12(69, 1.74979342183939068356e-01, 6.28071845475365986289e-01,
1993 2.15117263314366490706e-03);
1994 ir->SetOrder(10);
1995 TetrahedronIntRules[10] = ir;
1996 return ir;
1997
1998 case 11:
1999 ir = new IntegrationRule(96);
2000 ir->AddTetPoints4(0, 2.71527207067321363354e-02, 3.30755017786941475644e-04);
2001 ir->AddTetPoints4(4, 7.29513610462571016058e-02, 1.27724462275054500421e-03);
2002 ir->AddTetPoints4(8, 1.16306248902001030388e-01, 2.22195840281977797376e-03);
2003 ir->AddTetPoints4(12, 1.79873804986097840519e-01, 3.55549424791121128006e-03);
2004 ir->AddTetPoints4(16, 2.90224794862315171873e-01, 4.27767411104971236741e-03);
2005 ir->AddTetPoints4(20, 3.25420936748619160639e-01, 2.29560465583227143668e-03);
2006 ir->AddTetPoints6(24, 4.99998725049884129579e-01, 1.95152894059845476377e-04);
2007 ir->AddTetPoints6(30, 3.94300142842090972639e-01, 4.13762713030314983886e-03);
2008 ir->AddTetPoints12(36, 1.53994139264412854828e-02, 8.20202176629804657892e-01,
2009 3.44113207868302869216e-04);
2010 ir->AddTetPoints12(48, 4.36843254717693696421e-02, 6.27516751622257062948e-01,
2011 2.00540889524405963051e-03);
2012 ir->AddTetPoints12(60, 1.32316796082697751835e-01, 7.35366407834604496330e-01,
2013 5.92160675031106853265e-04);
2014 ir->AddTetPoints12(72, 2.14430354900043917965e-01, 5.31595425719235903372e-01,
2015 3.02373698028425954079e-03);
2016 ir->AddTetPoints12(84, 4.39586615093850330283e-01, 1.15789732843376125260e-01,
2017 1.10416876556284249307e-03);
2018 ir->SetOrder(11);
2019 TetrahedronIntRules[11] = ir;
2020 return ir;
2021
2022 case 12:
2023 ir = new IntegrationRule(123);
2024 ir->AddTetMidPoint(0, 3.73841522662751247000e-03);
2025 ir->AddTetPoints4(1, 1.87550512633127830497e-02, 1.42695998696545141987e-04);
2026 ir->AddTetPoints4(5, 1.08129536920462676619e-01, 2.21101382522646480733e-03);
2027 ir->AddTetPoints4(9, 2.00131676822545012673e-01, 1.02716311841773611131e-03);
2028 ir->AddTetPoints4(13, 3.00854293538076578152e-01, 3.84627572131096594557e-03);
2029 ir->AddTetPoints4(17, 3.33333333333333259318e-01, 3.93263480259983290444e-04);
2030 ir->AddTetPoints6(21, 4.61659950214442116323e-01, 3.64372815936188636666e-04);
2031 ir->AddTetPoints12(27, 1.44707549187619299857e-02, 8.12825119403836504617e-01,
2032 2.78228183082975693598e-04);
2033 ir->AddTetPoints12(39, 1.93543398987769954545e-02, 6.01428742996530152354e-01,
2034 5.44744358748572190913e-04);
2035 ir->AddTetPoints12(51, 7.79277628532308863640e-02, 8.27642519452021385717e-01,
2036 4.96603607085240776955e-04);
2037 ir->AddTetPoints12(63, 1.22055870746741623734e-01, 4.77806520042316273944e-01,
2038 3.50252598711278933380e-03);
2039 ir->AddTetPoints12(75, 2.47870739372197945727e-01, 4.77761799116294072487e-01,
2040 1.92951947508030146987e-03);
2041 ir->AddTetPoints12(87, 4.29731509588804683197e-01, 1.17747435901101149547e-01,
2042 1.59458000732484511328e-03);
2043 ir->AddTetPoints24(99, 6.53037808968305988344e-01, 2.26776739658831050228e-01,
2044 9.77349816032284102185e-02, 1.25441443948160597475e-03);
2045 ir->SetOrder(12);
2046 TetrahedronIntRules[12] = ir;
2047 return ir;
2048
2049 case 13:
2050 ir = new IntegrationRule(145);
2051 ir->AddTetMidPoint(0, 4.65163625751287973520e-03);
2052 ir->AddTetPoints4(1, 1.83047574861928130652e-02, 1.11328544338301012079e-04);
2053 ir->AddTetPoints4(5, 1.79015082630022803745e-01, 3.21788310144650391634e-03);
2054 ir->AddTetPoints4(9, 3.29615853754448240309e-01, 1.11613482625956810662e-03);
2055 ir->AddTetPoints6(13, 4.84258919196047465938e-01, 4.22777636660235864308e-04);
2056 ir->AddTetPoints6(19, 4.37693799377281589358e-01, 1.42741910394635984974e-03);
2057 ir->AddTetPoints12(25, 1.68580250819503341120e-02, 7.16622722155387803511e-01,
2058 3.27226375772531215529e-04);
2059 ir->AddTetPoints12(37, 2.35257182448596058322e-02, 8.50600927605402956644e-01,
2060 4.21131904215649394228e-04);
2061 ir->AddTetPoints12(49, 6.94418950495464537553e-02, 7.08574314820604622689e-01,
2062 9.98940835257684659268e-04);
2063 ir->AddTetPoints12(61, 9.37005272821476720146e-02, 5.63456727822489344959e-01,
2064 1.88623398086488818989e-03);
2065 ir->AddTetPoints12(73, 1.25885360164042447995e-01, 7.40105985667665167149e-01,
2066 5.36847192210583730974e-04);
2067 ir->AddTetPoints12(85, 2.17955270547737667286e-01, 5.35290625276012344003e-01,
2068 1.79931440889047528954e-03);
2069 ir->AddTetPoints12(97, 3.54663455472783883948e-01, 2.00014910210617791186e-01,
2070 2.91862732938839245650e-03);
2071 ir->AddTetPoints12(109, 4.16689287657038387458e-01, 1.52054854976777675812e-01,
2072 9.62750257012783515476e-04);
2073 ir->AddTetPoints24(121, 6.06652560730350010054e-01, 3.04158433676372519372e-01,
2074 7.79465622318078477093e-02, 6.21649861415869242447e-04);
2075 ir->SetOrder(13);
2076 TetrahedronIntRules[13] = ir;
2077 return ir;
2078
2079 case 14:
2080 // Chuluunbaatar et al. 2022: 175 pts, 1xCent + 6xS31 + 1xS22 + 10xS211 + 1xS1111
2081 ir = new IntegrationRule(175);
2082 ir->AddTetMidPoint(0, 2.79630622899013732072e-03);
2083 ir->AddTetPoints4(1, 3.33328696010048830534e-01, 1.46917540892973303920e-04);
2084 ir->AddTetPoints4(5, 2.03700979179134489261e-01, 1.62781576883158380503e-03);
2085 ir->AddTetPoints4(9, 4.23119120487503441730e-02, 3.41825853298758448786e-04);
2086 ir->AddTetPoints4(13, 1.66911321524259963212e-02, 6.86936532495300726303e-05);
2087 ir->AddTetPoints4(17, 1.64429779556425403886e-01, 2.04589809259575743788e-03);
2088 ir->AddTetPoints4(21, 3.05243130480787605574e-01, 2.91353212326472864671e-03);
2089 ir->AddTetPoints6(25, 3.64287147870284933049e-01, 2.86344364876423311192e-03);
2090 ir->AddTetPoints12(31, 2.15024351638664623643e-01, 5.09377822427890203372e-01,
2091 1.86604702493200981690e-03);
2092 ir->AddTetPoints12(43, 4.08453557824531576781e-01, 2.80291884809145824820e-02,
2093 1.37079721642533879263e-03);
2094 ir->AddTetPoints12(55, 2.59921479331125596102e-02, 7.58920443676681433232e-01,
2095 5.79340182017268356431e-04);
2096 ir->AddTetPoints12(67, 1.49228115767079897586e-02, 6.12483481308898292106e-01,
2097 3.15838010189281473503e-04);
2098 ir->AddTetPoints12(79, 8.37923462693035414617e-02, 8.22678981568125355928e-01,
2099 3.37570057080462679680e-04);
2100 ir->AddTetPoints12(91, 2.67966909251860618824e-01, 1.21450733299050331326e-02,
2101 7.33968440516890967273e-04);
2102 ir->AddTetPoints12(103, 7.22614743275835913483e-02, 2.93829968686904419162e-01,
2103 1.73940500456261186446e-03);
2104 ir->AddTetPoints12(115, 4.61690356122462508548e-01, 6.24312988244191680032e-02,
2105 5.50156605537168688809e-04);
2106 ir->AddTetPoints12(127, 1.02556247843651599492e-05, 9.09652220362116237240e-01,
2107 3.74818592914694638193e-05);
2108 ir->AddTetPoints12(139, 1.30667193397036723868e-01, 6.88760930866849863108e-01,
2109 1.25403778742792012396e-03);
2110 ir->AddTetPoints24(151, 4.96082264783182565887e-03, 1.13153535288820022986e-01,
2111 2.55337379104889128367e-01, 5.28969173366363918341e-04);
2112 ir->SetOrder(14);
2113 TetrahedronIntRules[14] = ir;
2114 return ir;
2115
2116 case 15:
2117 // Chuluunbaatar et al. 2022: 209 pts, 1xCent + 4xS31 + 2xS22 + 11xS211 + 2xS1111
2118 ir = new IntegrationRule(209);
2119 ir->AddTetMidPoint(0, 1.41781886024826123995e-03);
2120 ir->AddTetPoints4(1, 3.28314281102506377863e-01, 8.78039594754075579386e-04);
2121 ir->AddTetPoints4(5, 5.95315181460130682378e-02, 6.49096346642090296988e-04);
2122 ir->AddTetPoints4(9, 1.79953296856689010097e-01, 2.51315014419990637520e-03);
2123 ir->AddTetPoints4(13, 2.87467267398706316506e-01, 1.49510722611222407301e-03);
2124 ir->AddTetPoints6(17, 1.63820429539269674102e-01, 1.59662635597863640340e-03);
2125 ir->AddTetPoints6(23, 4.49691037286174599696e-01, 5.56101982388976408267e-04);
2126 ir->AddTetPoints12(29, 4.00736540413628217205e-01, 1.44084693588290586180e-02,
2127 7.41098096825775301023e-04);
2128 ir->AddTetPoints12(41, 9.30917130105696349895e-02, 5.00389099764625755462e-01,
2129 1.48911776902807633377e-03);
2130 ir->AddTetPoints12(53, 8.58969713610300000806e-02, 6.54216648304909331735e-01,
2131 1.11933741359922559432e-03);
2132 ir->AddTetPoints12(65, 2.10555592437809635520e-01, 6.11819979966393701076e-02,
2133 1.62698522585349981094e-03);
2134 ir->AddTetPoints12(77, 8.52418251507089524965e-02, 9.51322614055337932581e-03,
2135 1.79269162929391381043e-04);
2136 ir->AddTetPoints12(89, 3.39062766530538045595e-02, 1.00939010271196565223e-03,
2137 6.94170071688395131987e-05);
2138 ir->AddTetPoints12(101, 3.61923170322900333851e-01, 6.94744848139675630350e-02,
2139 1.59447426536825733780e-03);
2140 ir->AddTetPoints12(113, 4.82786943073602314858e-01, 2.98248878093377127463e-02,
2141 1.85989656618890347554e-04);
2142 ir->AddTetPoints12(125, 1.67482762532157707092e-02, 8.28143120169573809797e-01,
2143 2.46974837616148544094e-04);
2144 ir->AddTetPoints12(137, 1.77918303634979659000e-02, 2.95058306317452390122e-01,
2145 3.64978786118624204133e-04);
2146 ir->AddTetPoints12(149, 2.22052218944333024098e-01, 5.47335431979886655185e-01,
2147 5.97708840203148013097e-04);
2148 ir->AddTetPoints24(161, 7.01737933129022994905e-01, 1.90468590405707266511e-01,
2149 9.00527571062145620884e-02, 6.09486799192013577881e-04);
2150 ir->AddTetPoints24(185, 9.30456155647334665071e-02, 3.39714197260826189506e-01,
2151 1.75628396157984228987e-02, 7.07458692200529210524e-04);
2152 ir->SetOrder(15);
2153 TetrahedronIntRules[15] = ir;
2154 return ir;
2155
2156 case 16:
2157 // Chuluunbaatar et al. 2022: 248 pts, 8xS31 + 2xS22 + 11xS211 + 3xS1111
2158 ir = new IntegrationRule(248);
2159 ir->AddTetPoints4(0, 3.27237393634992601577e-01, 1.02720766161859349518e-03);
2160 ir->AddTetPoints4(4, 1.70006239733430930539e-01, 1.65526299995553852033e-03);
2161 ir->AddTetPoints4(8, 1.15524594427552973475e-01, 9.38857005487496389280e-04);
2162 ir->AddTetPoints4(12, 2.91444830780401391290e-02, 6.51307095609853886316e-05);
2163 ir->AddTetPoints4(16, 2.99333264802760234957e-01, 1.67595204112568215392e-03);
2164 ir->AddTetPoints4(20, 3.08156348381425804206e-01, 5.31861976759345615219e-04);
2165 ir->AddTetPoints4(24, 1.50096498602994791322e-02, 5.70730781338430579624e-05);
2166 ir->AddTetPoints4(28, 2.15377318942399170743e-01, 1.98341225672248695419e-03);
2167 ir->AddTetPoints6(32, 4.31794349434656055120e-01, 1.33750640425309239717e-03);
2168 ir->AddTetPoints6(38, 3.51744151127164061954e-01, 1.76194827177588689456e-03);
2169 ir->AddTetPoints12(44, 8.29503118270854405969e-03, 1.02752005688054329213e-01,
2170 7.68034210054447698257e-05);
2171 ir->AddTetPoints12(56, 4.80211290069074772657e-02, 1.31255041819827861227e-01,
2172 6.11232548742599826781e-04);
2173 ir->AddTetPoints12(68, 1.58330800578366723275e-02, 7.34396180497698725098e-01,
2174 2.28071918651308634196e-04);
2175 ir->AddTetPoints12(80, 2.33860521976982954628e-01, 5.24417475091189966285e-01,
2176 5.40957583749601829924e-04);
2177 ir->AddTetPoints12(92, 4.03140399383019043533e-01, 1.61507733387133249614e-02,
2178 7.92724342585451077596e-04);
2179 ir->AddTetPoints12(104, 4.62664186044103586948e-01, 8.10608626417101511830e-03,
2180 2.79154547643383486085e-04);
2181 ir->AddTetPoints12(116, 9.54740058566225929804e-02, 2.29727696324949964835e-01,
2182 9.08138512826854073234e-04);
2183 ir->AddTetPoints12(128, 5.22644355194657739272e-02, 2.65023714835432855352e-01,
2184 5.22825831653034723938e-04);
2185 ir->AddTetPoints12(140, 1.54579380484822833525e-02, 3.89592797271225033118e-01,
2186 2.70158998322436651619e-04);
2187 ir->AddTetPoints12(152, 6.51049846146104782552e-02, 1.06703843590993385781e-02,
2188 1.88285026959176838299e-04);
2189 ir->AddTetPoints12(164, 1.54103896531334966236e-01, 6.61715834360067312048e-01,
2190 9.04088475565851504463e-04);
2191 ir->AddTetPoints24(176, 3.06401667521507548031e-01, 9.60517630472854377910e-02,
2192 5.82737849734082380415e-01, 5.64378019946093099565e-04);
2193 ir->AddTetPoints24(200, 7.52465510383990981991e-02, 7.45338308409307703783e-01,
2194 1.68928693209220324653e-04, 1.50966565378719797755e-04);
2195 ir->AddTetPoints24(224, 6.67856954025341370551e-02, 1.77429946613237937703e-01,
2196 4.69596074566060506239e-01, 1.47055596469915315222e-03);
2197 ir->SetOrder(16);
2198 TetrahedronIntRules[16] = ir;
2199 return ir;
2200
2201 case 17:
2202 // Chuluunbaatar et al. 2022: 284 pts, 8xS31 + 2xS22 + 14xS211 + 3xS1111
2203 ir = new IntegrationRule(284);
2204 ir->AddTetPoints4(0, 7.70317217555786387662e-02, 5.61182432136912863994e-04);
2205 ir->AddTetPoints4(4, 3.33178098937441047322e-01, 1.00689770519544758830e-04);
2206 ir->AddTetPoints4(8, 4.70791056455278841830e-02, 3.67647177915098600219e-05);
2207 ir->AddTetPoints4(12, 3.04818016813530989761e-01, 1.65889979279151768450e-03);
2208 ir->AddTetPoints4(16, 1.30944391509640850613e-01, 1.44088986921434188127e-03);
2209 ir->AddTetPoints4(20, 1.92535395691919936079e-01, 9.15395452245713805300e-04);
2210 ir->AddTetPoints4(24, 2.76657577444746005657e-01, 1.54901732083429399985e-03);
2211 ir->AddTetPoints4(28, 1.25812395975189866837e-02, 3.37712309004839736381e-05);
2212 ir->AddTetPoints6(32, 3.79480026881957605706e-03, 6.09736907157372445766e-05);
2213 ir->AddTetPoints6(38, 6.63574479091031538269e-02, 9.84476156008183339238e-04);
2214 ir->AddTetPoints12(44, 1.55274078991054307469e-02, 1.62632006416904367763e-01,
2215 1.72804764846827806904e-04);
2216 ir->AddTetPoints12(56, 1.50826606630984655366e-01, 2.85203367985520928052e-01,
2217 1.47139558752681400000e-03);
2218 ir->AddTetPoints12(68, 2.15452134252546806392e-01, 4.98848586166224794436e-01,
2219 1.39306363547645069810e-03);
2220 ir->AddTetPoints12(80, 8.76098177043343750992e-02, 5.57666868254345748923e-01,
2221 1.10287787958478406859e-03);
2222 ir->AddTetPoints12(92, 2.76970146665180327883e-01, 4.27355049241211759625e-01,
2223 7.68445912031412610432e-04);
2224 ir->AddTetPoints12(104, 7.84854004483451911378e-02, 8.28808438721931994841e-01,
2225 2.88969312852391376975e-04);
2226 ir->AddTetPoints12(116, 4.16031236751370603333e-01, 5.86692256093802096822e-03,
2227 3.64077087845785364682e-04);
2228 ir->AddTetPoints12(128, 3.11418578536613735799e-03, 2.87446864291519776913e-01,
2229 3.72979694270385682886e-05);
2230 ir->AddTetPoints12(140, 1.48006973486492082737e-01, 3.23952556344107162056e-02,
2231 8.00305827281323160088e-04);
2232 ir->AddTetPoints12(152, 1.43033359605475689225e-02, 6.71799737186767331742e-02,
2233 1.04156882366980408738e-04);
2234 ir->AddTetPoints12(164, 4.67432600299733047589e-01, 1.06651363448138844503e-02,
2235 3.28661937749209721524e-04);
2236 ir->AddTetPoints12(176, 3.84385292133539946402e-01, 1.72438767641856061097e-01,
2237 1.30629277435961670649e-03);
2238 ir->AddTetPoints12(188, 4.91933575124020999736e-02, 1.88887052205218147760e-01,
2239 6.32377286180225181393e-04);
2240 ir->AddTetPoints12(200, 2.12339226453523544080e-01, 4.66228370030305223209e-03,
2241 2.79290741478308349437e-04);
2242 ir->AddTetPoints24(212, 5.56903978599597615506e-01, 3.03486206973905936479e-01,
2243 1.18763501187465259079e-01, 6.89373805061415279201e-04);
2244 ir->AddTetPoints24(236, 7.72626757757003540528e-02, 7.24630018034681633310e-01,
2245 1.98007306189710574618e-01, 1.50128885728721429014e-04);
2246 ir->AddTetPoints24(260, 3.94151894733046209707e-02, 1.37686205384732439361e-02,
2247 3.27821577026260191356e-01, 2.69135394730690453036e-04);
2248 ir->SetOrder(17);
2249 TetrahedronIntRules[17] = ir;
2250 return ir;
2251
2252 case 18:
2253 // Chuluunbaatar et al. 2022: 343 pts, 1xCent + 6xS31 + 1xS22 + 18xS211 + 4xS1111
2254 ir = new IntegrationRule(343);
2255 ir->AddTetMidPoint(0, 1.50320520665968271855e-03);
2256 ir->AddTetPoints4(1, 1.48031283019549930735e-01, 1.29183701010426432026e-03);
2257 ir->AddTetPoints4(5, 9.18424577295562372115e-02, 5.65165600131921114398e-04);
2258 ir->AddTetPoints4(9, 1.21731006846268821620e-02, 2.96638661291863846498e-05);
2259 ir->AddTetPoints4(13, 2.96287086243479214076e-01, 1.68021599975901742008e-03);
2260 ir->AddTetPoints4(17, 3.26360945420223702573e-01, 5.68549421501223146459e-04);
2261 ir->AddTetPoints4(21, 2.16789137320780644913e-01, 5.55087845531530756776e-04);
2262 ir->AddTetPoints6(25, 4.02614199568341046831e-01, 9.23257682834909085973e-04);
2263 ir->AddTetPoints12(31, 4.40000294606430919497e-01, 2.67115252330815747261e-02,
2264 5.89236226881148018354e-04);
2265 ir->AddTetPoints12(43, 4.12210360146149590310e-01, 1.74700018752273367184e-01,
2266 2.20201645262970173086e-04);
2267 ir->AddTetPoints12(55, 3.72351275734651154803e-01, 2.01036053559202482210e-01,
2268 1.19114067751767893286e-03);
2269 ir->AddTetPoints12(67, 2.69242251358920825499e-01, 4.49869807112305730712e-01,
2270 4.91465288515259167076e-04);
2271 ir->AddTetPoints12(79, 9.76627002277863226487e-02, 5.25608170470769464622e-01,
2272 9.64486286268097844226e-04);
2273 ir->AddTetPoints12(91, 7.95369840699704060138e-03, 9.21057037109250575924e-01,
2274 3.50539800669945179434e-05);
2275 ir->AddTetPoints12(103, 1.87267495112264620305e-01, 6.22654876406694146596e-01,
2276 2.16974411183503681708e-04);
2277 ir->AddTetPoints12(115, 1.11072676172302167719e-01, 7.68063140393386190041e-01,
2278 2.34282910136374296871e-04);
2279 ir->AddTetPoints12(127, 7.28479245819699250397e-02, 6.49722949416110195919e-01,
2280 4.87753175028903700802e-04);
2281 ir->AddTetPoints12(139, 4.35242030819264283381e-02, 1.17645467635705727738e-01,
2282 3.42108745586317604826e-04);
2283 ir->AddTetPoints12(151, 4.75773867838972852606e-01, 4.07808063375027368691e-02,
2284 1.54370387724311262630e-04);
2285 ir->AddTetPoints12(163, 1.34493684207502642303e-02, 7.10473230757141527292e-01,
2286 1.53084245505138950502e-04);
2287 ir->AddTetPoints12(175, 1.55188126953707594691e-01, 4.80062353992693063853e-02,
2288 7.41762550201790354931e-04);
2289 ir->AddTetPoints12(187, 9.79636346189126545891e-03, 3.98937047199835026490e-01,
2290 9.70189072253606300464e-05);
2291 ir->AddTetPoints12(199, 2.22972555180978554423e-01, 4.76498622927509052349e-01,
2292 1.23606250864963739498e-03);
2293 ir->AddTetPoints12(211, 4.21260289724883496554e-02, 5.74400719147259319897e-01,
2294 5.42935360416797459064e-04);
2295 ir->AddTetPoints12(223, 5.33405089760383491204e-02, 8.80640211270697026436e-01,
2296 1.37609067910292992955e-04);
2297 ir->AddTetPoints12(235, 1.61516953402295604381e-01, 3.97825734805866804145e-01,
2298 1.38360407936932868454e-03);
2299 ir->AddTetPoints24(247, 1.45407574632878761056e-01, 2.91164813093958863011e-01,
2300 2.48113931665566757323e-02, 7.08660104525119741853e-04);
2301 ir->AddTetPoints24(271, 3.05950727633923398596e-03, 8.24555339410965038027e-01,
2302 2.68565028804892240444e-02, 7.44949831353088352858e-05);
2303 ir->AddTetPoints24(295, 6.97926614756394281258e-01, 2.13661027507205059095e-01,
2304 1.66604565123493510159e-02, 3.48774332060316084436e-04);
2305 ir->AddTetPoints24(319, 7.44110286479428006956e-02, 3.30529031579615995007e-01,
2306 5.94802303330229431566e-01, 1.27738536486342427233e-04);
2307 ir->SetOrder(18);
2308 TetrahedronIntRules[18] = ir;
2309 return ir;
2310
2311 case 19:
2312 // Chuluunbaatar et al. 2022: 383 pts, 1xCent + 7xS31 + 3xS22 + 18xS211 + 5xS1111
2313 ir = new IntegrationRule(383);
2314 ir->AddTetMidPoint(0, 1.63415516118113374362e-03);
2315 ir->AddTetPoints4(1, 1.99329047511150186933e-01, 1.40358969707281050661e-03);
2316 ir->AddTetPoints4(5, 3.19645815662209620278e-01, 7.59091701642911130359e-04);
2317 ir->AddTetPoints4(9, 1.28431938718745111000e-02, 3.39837309564992975973e-05);
2318 ir->AddTetPoints4(13, 4.48982322308715264825e-02, 2.64426237344559213801e-04);
2319 ir->AddTetPoints4(17, 1.36956642483832574664e-01, 7.02856031175181001670e-04);
2320 ir->AddTetPoints4(21, 2.90023140379987831583e-01, 1.36565197140369625796e-03);
2321 ir->AddTetPoints4(25, 9.74727471850612287030e-02, 5.49967641751253539552e-04);
2322 ir->AddTetPoints6(29, 9.71505706534206842084e-02, 8.76433367036966496331e-04);
2323 ir->AddTetPoints6(35, 3.43201766155373844125e-01, 1.42791869569969145752e-03);
2324 ir->AddTetPoints6(41, 4.81048682529186311108e-01, 2.14104659346860782621e-04);
2325 ir->AddTetPoints12(47, 1.65183633185142647593e-01, 6.20343271948313068620e-01,
2326 7.66624121398570487762e-04);
2327 ir->AddTetPoints12(59, 6.34076230480007801971e-02, 1.00712056526788096511e-06,
2328 5.83669782740338187726e-05);
2329 ir->AddTetPoints12(71, 1.14358224224068777061e-03, 4.00863727471189756901e-01,
2330 2.15179213304474853136e-05);
2331 ir->AddTetPoints12(83, 1.72841898844304682481e-02, 2.80974353964125900252e-01,
2332 2.11660243173845957895e-04);
2333 ir->AddTetPoints12(95, 3.72064110603054443160e-01, 1.99705629942815821032e-01,
2334 8.75485553265252145448e-04);
2335 ir->AddTetPoints12(107, 5.20242736384851911513e-02, 1.37531998164526964024e-01,
2336 2.41875978548309640689e-04);
2337 ir->AddTetPoints12(119, 1.60391938988630439189e-01, 6.93856268828658799552e-03,
2338 2.41421983084743403854e-04);
2339 ir->AddTetPoints12(131, 2.04009311788170112981e-03, 1.85612033720361502276e-01,
2340 2.06414634761428247161e-05);
2341 ir->AddTetPoints12(143, 5.27148535043930888122e-02, 3.66275984765305206992e-01,
2342 5.92721175866269185152e-04);
2343 ir->AddTetPoints12(155, 2.43716736043213727525e-01, 4.92302726125094514131e-01,
2344 5.87805221231469288319e-04);
2345 ir->AddTetPoints12(167, 2.35953750535251915998e-01, 4.36147999140300668408e-01,
2346 1.13870552683716466137e-03);
2347 ir->AddTetPoints12(179, 3.76396525093455058819e-01, 2.39487568074092604942e-01,
2348 3.83776606890474675932e-04);
2349 ir->AddTetPoints12(191, 1.01345934656195998946e-01, 7.75724008450901503231e-01,
2350 3.13399374751491786861e-04);
2351 ir->AddTetPoints12(203, 1.03978576485678226443e-02, 9.15876371248755760668e-01,
2352 5.00269118618190970684e-05);
2353 ir->AddTetPoints12(215, 4.34825905512194077485e-01, 1.54748703679767566493e-02,
2354 5.11025086732051357814e-04);
2355 ir->AddTetPoints12(227, 1.21014927057761692564e-01, 5.16611295841134299245e-01,
2356 1.01828426898903845119e-03);
2357 ir->AddTetPoints12(239, 2.02221519510974792611e-02, 1.24848861415461573343e-01,
2358 1.43839758373707761420e-04);
2359 ir->AddTetPoints12(251, 6.45349753497565792326e-02, 6.58797428082353198064e-01,
2360 5.65395165437599170333e-04);
2361 ir->AddTetPoints24(263, 5.41751356566992220420e-02, 1.84132753560833639650e-01,
2362 7.55314661874476711567e-01, 1.46482060260151955187e-04);
2363 ir->AddTetPoints24(287, 8.81662316742434920558e-02, 6.34269181940578685719e-01,
2364 1.71630199679625762565e-02, 3.35574461050504140036e-04);
2365 ir->AddTetPoints24(311, 2.99876324799488391815e-01, 5.12011805461436986242e-01,
2366 1.39945756017624101109e-01, 6.87105878169750922298e-04);
2367 ir->AddTetPoints24(335, 5.43033048543508201078e-01, 3.98941499659789464149e-03,
2368 2.96197429831241032527e-01, 1.95466436126630728823e-04);
2369 ir->AddTetPoints24(359, 5.64748804926985426000e-01, 5.04233375578317308263e-02,
2370 5.38328049657370907161e-03, 1.64230458281612438400e-04);
2371 ir->SetOrder(19);
2372 TetrahedronIntRules[19] = ir;
2373 return ir;
2374
2375 case 20:
2376 // Chuluunbaatar et al. 2022: 441 pts, 1xCent + 8xS31 + 4xS22 + 20xS211 + 6xS1111
2377 ir = new IntegrationRule(441);
2378 ir->AddTetMidPoint(0, 1.18189152746071531389e-03);
2379 ir->AddTetPoints4(1, 1.44398440418483348102e-01, 9.66793543666131616025e-04);
2380 ir->AddTetPoints4(5, 7.58537944731913719304e-03, 7.60496594911488061041e-06);
2381 ir->AddTetPoints4(9, 2.92814880923072839991e-01, 1.15590090717039508002e-03);
2382 ir->AddTetPoints4(13, 3.21283351882928780441e-01, 6.88636083704610908220e-04);
2383 ir->AddTetPoints4(17, 1.99126561548209762842e-01, 1.13432796616464034133e-03);
2384 ir->AddTetPoints4(21, 9.94395843777090698845e-02, 4.86016284904959409725e-04);
2385 ir->AddTetPoints4(25, 5.64411054542164752901e-02, 3.22610846546138882538e-04);
2386 ir->AddTetPoints4(29, 2.29655958568571322287e-02, 5.81298999656466752642e-05);
2387 ir->AddTetPoints6(33, 1.79141319969986889671e-01, 1.09529243625682828553e-03);
2388 ir->AddTetPoints6(39, 1.28302591207222288494e-01, 5.73999808941768881014e-04);
2389 ir->AddTetPoints6(45, 1.45390267831490144212e-02, 1.87025723866918939901e-04);
2390 ir->AddTetPoints6(51, 4.21353125034043096697e-01, 7.00971843927932197066e-04);
2391 ir->AddTetPoints12(57, 2.31009838674045342444e-01, 4.40089079468850674637e-01,
2392 9.76079610667369892280e-04);
2393 ir->AddTetPoints12(69, 5.34968850305569260106e-03, 1.93845423004036843118e-01,
2394 3.05362840831512903964e-05);
2395 ir->AddTetPoints12(81, 1.24450062776632008887e-01, 2.68040213994591769442e-01,
2396 8.86819612544235340128e-04);
2397 ir->AddTetPoints12(93, 2.04325810970697151203e-02, 2.58308114426872181824e-01,
2398 1.92969809694827680807e-04);
2399 ir->AddTetPoints12(105, 4.82828231821251577238e-02, 5.80396926577266859815e-03,
2400 6.19875387085781813859e-05);
2401 ir->AddTetPoints12(117, 2.89149787325270579696e-01, 4.18198665244226719384e-01,
2402 1.83280536557154684341e-04);
2403 ir->AddTetPoints12(129, 4.46052961749180063022e-02, 1.63432451082933805075e-01,
2404 3.33781952353497124181e-04);
2405 ir->AddTetPoints12(141, 2.70746696244779198881e-03, 9.47473449934223443947e-01,
2406 9.76902870004440518315e-06);
2407 ir->AddTetPoints12(153, 1.81599434536722420530e-01, 5.60679256816125279328e-02,
2408 7.16163033436471277611e-04);
2409 ir->AddTetPoints12(165, 7.98241847716316815786e-02, 2.24797220241435974364e-01,
2410 6.67198343081130593700e-04);
2411 ir->AddTetPoints12(177, 1.46751424308700709198e-02, 1.05996716787954137207e-01,
2412 1.02112432519835052438e-04);
2413 ir->AddTetPoints12(189, 1.47988480867858707146e-01, 6.98383249617804735543e-01,
2414 1.65331156535892409174e-04);
2415 ir->AddTetPoints12(201, 4.52421884404454466289e-01, 8.04532263339534647884e-02,
2416 3.75572061072812404120e-04);
2417 ir->AddTetPoints12(213, 4.82988925439242506449e-03, 3.56408995372303527560e-01,
2418 3.70372995907359520520e-05);
2419 ir->AddTetPoints12(225, 3.96075105354866952023e-01, 1.93643489260524576112e-01,
2420 4.20355142354041121707e-04);
2421 ir->AddTetPoints12(237, 2.11473197416018027228e-01, 5.66485319771568907044e-01,
2422 3.20737452814357003415e-04);
2423 ir->AddTetPoints12(249, 2.56953469781508958558e-01, 4.54914546979866607490e-01,
2424 5.44699807144207316482e-04);
2425 ir->AddTetPoints12(261, 3.63762446007509787638e-01, 7.07704644682126682298e-02,
2426 8.71724711789707298014e-04);
2427 ir->AddTetPoints12(273, 4.34084693566413395982e-02, 5.61826818484091217165e-01,
2428 4.66716966955154613419e-04);
2429 ir->AddTetPoints12(285, 1.26096840063810999855e-01, 4.15826803180920218095e-02,
2430 4.05374493922667372432e-04);
2431 ir->AddTetPoints24(297, 3.19830665436792060952e-01, 4.36032333155288651105e-02,
2432 5.02224495466759290885e-01, 7.04309544520175120040e-04);
2433 ir->AddTetPoints24(321, 6.93104765295092647634e-04, 7.61588104432530443866e-01,
2434 4.88127934219945436300e-02, 6.22004488693067759562e-05);
2435 ir->AddTetPoints24(345, 3.01059509765821443905e-03, 4.68001522754562040984e-02,
2436 5.92923309754523120141e-01, 1.11516752988944994277e-04);
2437 ir->AddTetPoints24(369, 8.05046770737637640281e-01, 1.15008082676269607347e-01,
2438 6.71446262920421810261e-02, 1.37946350993749402127e-04);
2439 ir->AddTetPoints24(393, 3.27837344763098725853e-01, 1.41845459805815643506e-01,
2440 3.73982332962941683638e-03, 1.75610557117139728066e-04);
2441 ir->AddTetPoints24(417, 1.69431918115453827856e-02, 9.30651836894259287813e-02,
2442 6.46141331822991715761e-01, 3.76832469454361519961e-04);
2443 ir->SetOrder(20);
2444 TetrahedronIntRules[20] = ir;
2445 return ir;
2446
2447 default:
2448 // Grundmann-Moller fallback for orders beyond tabulated rules
2449 int i = (Order / 2) * 2 + 1; // closest odd >= Order
2450 AllocIntRule(TetrahedronIntRules, i);
2451 ir = new IntegrationRule;
2452 ir->GrundmannMollerSimplexRule(i/2, 3);
2453 if (!TetrahedronIntRules[i-1]) { TetrahedronIntRules[i-1] = ir; }
2454 TetrahedronIntRules[i] = ir;
2455 return ir;
2456 }
2457}
2458
2459// Integration rules for reference pyramid
2460IntegrationRule *IntegrationRules::PyramidIntegrationRule(int Order)
2461{
2462 // This is a simple integration rule adapted from an integration
2463 // rule for a cube which seems to be adequate for now. We should continue
2464 // to search for a more appropriate integration rule designed specifically
2465 // for pyramid elements.
2466 const IntegrationRule &irc = Get(Geometry::CUBE, Order);
2467 int npts = irc.GetNPoints();
2468 AllocIntRule(PyramidIntRules, Order);
2469 PyramidIntRules[Order] = new IntegrationRule(npts);
2470 PyramidIntRules[Order]->SetOrder(Order);
2471
2472 if (npts == 1)
2473 {
2474 // We handle this as a special case because with only one integration
2475 // point we cannot accurately integrate the quadratic factor
2476 // pow(1.0 - ipc.z, 2) and the resulting weight does not match the volume
2477 // of the reference element.
2478 IntegrationPoint &ipp = PyramidIntRules[Order]->IntPoint(0);
2479 ipp.x = 0.375;
2480 ipp.y = 0.375;
2481 ipp.z = 0.25;
2482 ipp.weight = 1.0 / 3.0;
2483 }
2484 else
2485 {
2486 for (int k=0; k<npts; k++)
2487 {
2488 const IntegrationPoint &ipc = irc.IntPoint(k);
2489 IntegrationPoint &ipp = PyramidIntRules[Order]->IntPoint(k);
2490 ipp.x = ipc.x * (1.0 - ipc.z);
2491 ipp.y = ipc.y * (1.0 - ipc.z);
2492 ipp.z = ipc.z;
2493 ipp.weight = ipc.weight * pow(1.0 - ipc.z, 2);
2494 }
2495 }
2496 return PyramidIntRules[Order];
2497}
2498
2499// Integration rules for reference prism
2500IntegrationRule *IntegrationRules::PrismIntegrationRule(int Order)
2501{
2502 const IntegrationRule &irt = Get(Geometry::TRIANGLE, Order);
2503 const IntegrationRule &irs = Get(Geometry::SEGMENT, Order);
2504 int nt = irt.GetNPoints();
2505 int ns = irs.GetNPoints();
2506 AllocIntRule(PrismIntRules, Order);
2507 PrismIntRules[Order] = new IntegrationRule(nt * ns);
2508 PrismIntRules[Order]->SetOrder(std::min(irt.GetOrder(), irs.GetOrder()));
2509 while (Order < std::min(irt.GetOrder(), irs.GetOrder()))
2510 {
2511 AllocIntRule(PrismIntRules, ++Order);
2512 PrismIntRules[Order] = PrismIntRules[Order-1];
2513 }
2514
2515 for (int ks=0; ks<ns; ks++)
2516 {
2517 const IntegrationPoint &ips = irs.IntPoint(ks);
2518 for (int kt=0; kt<nt; kt++)
2519 {
2520 int kp = ks * nt + kt;
2521 const IntegrationPoint &ipt = irt.IntPoint(kt);
2522 IntegrationPoint &ipp = PrismIntRules[Order]->IntPoint(kp);
2523 ipp.x = ipt.x;
2524 ipp.y = ipt.y;
2525 ipp.z = ips.x;
2526 ipp.weight = ipt.weight * ips.weight;
2527 }
2528 }
2529 return PrismIntRules[Order];
2530}
2531
2532// Integration rules for reference cube
2533IntegrationRule *IntegrationRules::CubeIntegrationRule(int Order)
2534{
2535 int RealOrder = GetSegmentRealOrder(Order);
2536 if (!HaveIntRule(SegmentIntRules, RealOrder))
2537 {
2538 SegmentIntegrationRule(RealOrder);
2539 }
2540 AllocIntRule(CubeIntRules, RealOrder);
2541 CubeIntRules[RealOrder-1] =
2542 CubeIntRules[RealOrder] =
2543 new IntegrationRule(*SegmentIntRules[RealOrder],
2544 *SegmentIntRules[RealOrder],
2545 *SegmentIntRules[RealOrder]);
2546 return CubeIntRules[Order];
2547}
2548
2550
2552{
2553 const MemoryType h_mt = MemoryType::HOST;
2554 SquareStroudIntRules.SetSize(32, h_mt);
2555 SquareStroudIntRules = NULL;
2556
2557 TriangleStroudIntRules.SetSize(32, h_mt);
2558 TriangleStroudIntRules = NULL;
2559
2560 CubeStroudIntRules.SetSize(32, h_mt);
2561 CubeStroudIntRules = NULL;
2562
2563 TetrahedronStroudIntRules.SetSize(32, h_mt);
2564 TetrahedronStroudIntRules = NULL;
2565
2566#if defined(MFEM_THREAD_SAFE) && defined(MFEM_USE_OPENMP)
2567 IntRuleLocks.SetSize(Geometry::NUM_GEOMETRIES, h_mt);
2568 for (int i = 0; i < Geometry::NUM_GEOMETRIES; i++)
2569 {
2570 omp_init_lock(&IntRuleLocks[i]);
2571 }
2572#endif
2573}
2574
2575const IntegrationRule &StroudIntegrationRules::Get(int GeomType, int Order)
2576{
2577 Array<IntegrationRule *> *ir_array = NULL;
2578
2579 switch (GeomType)
2580 {
2581 case Geometry::TRIANGLE: ir_array = &TriangleStroudIntRules; break;
2582 case Geometry::TETRAHEDRON: ir_array = &TetrahedronStroudIntRules; break;
2583 case Geometry::INVALID:
2585 MFEM_ABORT("Unknown type of reference element!");
2586 default:
2587 MFEM_ABORT("Stroud rules only valid for triangular and tetrahedral elements!");
2588 }
2589
2590 if (Order < 0)
2591 {
2592 Order = 0;
2593 }
2594
2595#if defined(MFEM_THREAD_SAFE) && defined(MFEM_USE_OPENMP)
2596 omp_set_lock(&IntRuleLocks[GeomType]);
2597#endif
2598
2599 if (!HaveIntRule(*ir_array, Order))
2600 {
2601 IntegrationRule *ir = GenerateIntegrationRule(GeomType, Order);
2602#ifdef MFEM_DEBUG
2603 int RealOrder = Order;
2604 while (RealOrder+1 < ir_array->Size() && (*ir_array)[RealOrder+1] == ir)
2605 {
2606 RealOrder++;
2607 }
2608 MFEM_VERIFY(RealOrder == ir->GetOrder(), "internal error");
2609#else
2610 MFEM_CONTRACT_VAR(ir);
2611#endif
2612 }
2613
2614#if defined(MFEM_THREAD_SAFE) && defined(MFEM_USE_OPENMP)
2615 omp_unset_lock(&IntRuleLocks[GeomType]);
2616#endif
2617
2618 return *(*ir_array)[Order];
2619}
2620
2621void StroudIntegrationRules::DeleteIntRuleArray(
2622 Array<IntegrationRule *> &ir_array) const
2623{
2624 // Many of the intrules have multiple contiguous copies in the ir_array
2625 // so we have to be careful to not delete them twice.
2626 IntegrationRule *ir = NULL;
2627 for (int i = 0; i < ir_array.Size(); i++)
2628 {
2629 if (ir_array[i] != NULL && ir_array[i] != ir)
2630 {
2631 ir = ir_array[i];
2632 delete ir;
2633 }
2634 }
2635}
2636
2638{
2639#if defined(MFEM_THREAD_SAFE) && defined(MFEM_USE_OPENMP)
2640 for (int i = 0; i < Geometry::NUM_GEOMETRIES; i++)
2641 {
2642 omp_destroy_lock(&IntRuleLocks[i]);
2643 }
2644#endif
2645 DeleteIntRuleArray(SquareStroudIntRules);
2646 DeleteIntRuleArray(TriangleStroudIntRules);
2647 DeleteIntRuleArray(CubeStroudIntRules);
2648 DeleteIntRuleArray(TetrahedronStroudIntRules);
2649}
2650
2651
2652IntegrationRule *StroudIntegrationRules::GenerateIntegrationRule(int GeomType,
2653 int Order)
2654{
2655 switch (GeomType)
2656 {
2657 case Geometry::TRIANGLE:
2658 return TriangleStroudIntegrationRule(Order);
2660 return TetrahedronStroudIntegrationRule(Order);
2661 case Geometry::INVALID:
2663 MFEM_ABORT("Unknown type of reference element!");
2664 default:
2665 MFEM_ABORT("Stroud rules only valid for triangular and tetrahedral elements!");
2666 }
2667 return NULL;
2668}
2669
2670/* Integration rule in reference triangle according to tensor product Gauss-Jacobi rule.
2671 The nodes and weights are used in the original form defined on the reference
2672 square to evaluate the component 1D basis functions. Mapping to the reference
2673 triangle via IntegrationRule::DuffyTrans() occurs only in evaluation of coefficient
2674 vectors, see e.g. MassIntegrator::AssemblePASimplex. */
2675IntegrationRule *StroudIntegrationRules::TriangleStroudIntegrationRule(
2676 int Order)
2677{
2678 int RealOrder = GetSegmentRealOrder(Order);
2679 // Order is one of {RealOrder-1,RealOrder}
2680 // if (!HaveIntRule(SegmentIntRules, RealOrder))
2681 // {
2682 // SegmentIntegrationRule(RealOrder);
2683 // }
2684 IntegrationRule ir_0_0;
2685 // Gauss-Jacobi is exact for 2*n-1
2686 int n = RealOrder/2 + 1;
2687 QuadratureFunctions1D::GaussJacobi(n, 0.0, 0.0, &ir_0_0);
2688
2689 IntegrationRule ir_1_0;
2690 QuadratureFunctions1D::GaussJacobi(n, 1.0, 0.0, &ir_1_0);
2691
2692 AllocIntRule(TriangleStroudIntRules, RealOrder); // RealOrder >= Order
2693 // create rule in unit square
2694 TriangleStroudIntRules[RealOrder-1] =
2695 TriangleStroudIntRules[RealOrder] =
2696 new IntegrationRule(ir_1_0, ir_0_0);
2697 // map rule to reference triangle
2698 // TriangleStroudIntRules[RealOrder-1]->DuffyTrans(2);
2699 *TriangleStroudIntRules[RealOrder-1] =
2700 DuffyTrans(*TriangleStroudIntRules[RealOrder-1], 2);
2701 return TriangleStroudIntRules[Order];
2702}
2703
2704/* Integration rule in reference tetrahedron according to tensor product Gauss-Jacobi rule.
2705 The nodes and weights are used in the original form defined on the reference
2706 square to evaluate the component 1D basis functions. Mapping to the reference
2707 triangle via IntegrationRule::DuffyTrans() occurs only in evaluation of coefficient
2708 vectors, see e.g. MassIntegrator::AssemblePASimplex. */
2709IntegrationRule *StroudIntegrationRules::TetrahedronStroudIntegrationRule(
2710 int Order)
2711{
2712 int RealOrder = GetSegmentRealOrder(Order);
2713 // Order is one of {RealOrder-1,RealOrder}
2714
2715 IntegrationRule ir_0_0;
2716 int n = RealOrder/2 + 1;
2717 QuadratureFunctions1D::GaussJacobi(n, 0.0, 0.0, &ir_0_0);
2718
2719 IntegrationRule ir_1_0;
2720 QuadratureFunctions1D::GaussJacobi(n, 1.0, 0.0, &ir_1_0);
2721
2722 IntegrationRule ir_2_0;
2723 QuadratureFunctions1D::GaussJacobi(n, 2.0, 0.0, &ir_2_0);
2724
2725 AllocIntRule(TetrahedronStroudIntRules, RealOrder); // RealOrder >= Order
2726 // create rule in unit cube
2727 TetrahedronStroudIntRules[RealOrder-1] =
2728 TetrahedronStroudIntRules[RealOrder] =
2729 new IntegrationRule(ir_2_0, ir_1_0, ir_0_0);
2730 // map rule to reference tetrahedron
2731 // TetrahedronStroudIntRules[RealOrder-1]->DuffyTrans(3);
2732 *TetrahedronStroudIntRules[RealOrder-1] =
2733 DuffyTrans(*TetrahedronStroudIntRules[RealOrder-1], 3);
2734 return TetrahedronStroudIntRules[Order];
2735}
2736
2738 const int patch, const int *ijk,
2739 Array<const KnotVector*> const& kv) const
2740{
2741 // First check whether a rule has been assigned to element index elem.
2742 auto search = elementToRule.find(elem);
2743 if (search != elementToRule.end())
2744 {
2745 return *elementRule[search->second];
2746 }
2747
2748#ifndef MFEM_THREAD_SAFE
2749 // If no prescribed rule is given for the current element, a temporary one is
2750 // formed by restricting a tensor-product of 1D rules to the element. The
2751 // ownership model for this temporary rule is not thread-safe.
2752
2753 MFEM_VERIFY(patchRules1D.NumRows(),
2754 "Undefined rule in NURBSMeshRules::GetElementRule");
2755
2756 // Use a tensor product of rules on the patch.
2757 MFEM_VERIFY(kv.Size() == dim, "");
2758
2759 int np = 1;
2760 std::vector<std::vector<real_t>> el(dim);
2761
2762 std::vector<int> npd;
2763 npd.assign(3, 0);
2764
2765 for (int d=0; d<dim; ++d)
2766 {
2767 const int order = kv[d]->GetOrder();
2768
2769 const real_t kv0 = (*kv[d])[order + ijk[d]];
2770 const real_t kv1 = (*kv[d])[order + ijk[d] + 1];
2771
2772 const bool rightEnd = (order + ijk[d] + 1) == (kv[d]->Size() - 1);
2773
2774 for (int i=0; i<patchRules1D(patch,d)->Size(); ++i)
2775 {
2776 const IntegrationPoint& ip = (*patchRules1D(patch,d))[i];
2777 if (kv0 <= ip.x && (ip.x < kv1 || rightEnd))
2778 {
2779 const real_t x = (ip.x - kv0) / (kv1 - kv0);
2780 el[d].push_back(x);
2781 el[d].push_back(ip.weight);
2782 }
2783 }
2784
2785 npd[d] = static_cast<int>(el[d].size() / 2);
2786 np *= npd[d];
2787 }
2788
2789 temporaryElementRule.SetSize(np);
2790
2791 // Set temporaryElementRule[i + j*npd[0] + k*npd[0]*npd[1]] =
2792 // (el[0][2*i], el[1][2*j], el[2][2*k])
2793
2794 MFEM_VERIFY(npd[0] > 0 && npd[1] > 0, "Assuming 2D or 3D");
2795
2796 for (int i = 0; i < npd[0]; ++i)
2797 {
2798 for (int j = 0; j < npd[1]; ++j)
2799 {
2800 for (int k = 0; k < std::max(npd[2], 1); ++k)
2801 {
2802 const int id = i + j*npd[0] + k*npd[0]*npd[1];
2803 temporaryElementRule[id].x = el[0][2*i];
2804 temporaryElementRule[id].y = el[1][2*j];
2805
2806 temporaryElementRule[id].weight = el[0][(2*i)+1];
2807 temporaryElementRule[id].weight *= el[1][(2*j)+1];
2808
2809 if (npd[2] > 0)
2810 {
2811 temporaryElementRule[id].z = el[2][2*k];
2812 temporaryElementRule[id].weight *= el[2][(2*k)+1];
2813 }
2814 }
2815 }
2816 }
2817
2818 return temporaryElementRule;
2819#else
2820 MFEM_ABORT("Temporary integration rules on NURBS elements "
2821 "are not thread-safe.");
2822#endif
2823}
2824
2825void NURBSMeshRules::GetIntegrationPointFrom1D(const int patch, int i, int j,
2826 int k, IntegrationPoint & ip)
2827{
2828 MFEM_VERIFY(patchRules1D.NumRows() > 0,
2829 "Assuming patchRules1D is set.");
2830
2831 ip.weight = (*patchRules1D(patch,0))[i].weight;
2832 ip.x = (*patchRules1D(patch,0))[i].x;
2833
2834 if (dim > 1)
2835 {
2836 ip.weight *= (*patchRules1D(patch,1))[j].weight;
2837 ip.y = (*patchRules1D(patch,1))[j].x; // 1D rule only has x
2838 }
2839
2840 if (dim > 2)
2841 {
2842 ip.weight *= (*patchRules1D(patch,2))[k].weight;
2843 ip.z = (*patchRules1D(patch,2))[k].x; // 1D rule only has x
2844 }
2845}
2846
2848{
2849 if ((int) pointToElem.size() == npatches) { return; } // Already set
2850
2851 MFEM_VERIFY(elementToRule.empty() && patchRules1D.NumRows() > 0
2852 && npatches > 0, "Assuming patchRules1D is set.");
2853 MFEM_VERIFY(mesh.NURBSext, "");
2854 MFEM_VERIFY(mesh.Dimension() == dim, "");
2855
2856 pointToElem.resize(npatches);
2857 patchRules1D_KnotSpan.resize(npatches);
2858
2859 // First, find all the elements in each patch.
2860 std::vector<std::vector<int>> patchElements(npatches);
2861
2862 for (int e=0; e<mesh.GetNE(); ++e)
2863 {
2864 patchElements[mesh.NURBSext->GetElementPatch(e)].push_back(e);
2865 }
2866
2867 Array<int> ijk(3);
2868 Array<int> maxijk(3);
2869 Array<int> np(3); // Number of points in each dimension
2870 ijk = 0;
2871
2873
2874 for (int p=0; p<npatches; ++p)
2875 {
2876 patchRules1D_KnotSpan[p].resize(dim);
2877
2878 // For each patch, get the range of ijk.
2879 mesh.NURBSext->GetPatchKnotVectors(p, pkv);
2880 MFEM_VERIFY((int) pkv.Size() == dim, "");
2881
2882 maxijk = 1;
2883 np = 1;
2884 for (int d=0; d<dim; ++d)
2885 {
2886 maxijk[d] = pkv[d]->GetNKS();
2887 np[d] = patchRules1D(p,d)->Size();
2888 }
2889
2890 // For each patch, set a map from ijk to element index.
2891 Array3D<int> ijk2elem(maxijk[0], maxijk[1], maxijk[2]);
2892 ijk2elem = -1;
2893
2894 for (auto elem : patchElements[p])
2895 {
2896 mesh.NURBSext->GetElementIJK(elem, ijk);
2897 MFEM_VERIFY(ijk2elem(ijk[0], ijk[1], ijk[2]) == -1, "");
2898 ijk2elem(ijk[0], ijk[1], ijk[2]) = elem;
2899 }
2900
2901 // For each point, find its ijk and from that its element index.
2902 // It is assumed here that the NURBSFiniteElement kv the same as the
2903 // patch kv.
2904
2905 for (int d=0; d<dim; ++d)
2906 {
2907 patchRules1D_KnotSpan[p][d].SetSize(patchRules1D(p,d)->Size());
2908
2909 for (int r=0; r<patchRules1D(p,d)->Size(); ++r)
2910 {
2911 const IntegrationPoint& ip = (*patchRules1D(p,d))[r];
2912
2913 const int order = pkv[d]->GetOrder();
2914
2915 // Find ijk_d such that ip.x is in the corresponding knot-span.
2916 int ijk_d = 0;
2917 bool found = false;
2918 while (!found)
2919 {
2920 const real_t kv0 = (*pkv[d])[order + ijk_d];
2921 const real_t kv1 = (*pkv[d])[order + ijk_d + 1];
2922
2923 const bool rightEnd = (order + ijk_d + 1) == (pkv[d]->Size() - 1);
2924
2925 if (kv0 <= ip.x && (ip.x < kv1 || rightEnd))
2926 {
2927 found = true;
2928 }
2929 else
2930 {
2931 ijk_d++;
2932 }
2933 }
2934
2935 patchRules1D_KnotSpan[p][d][r] = ijk_d;
2936 }
2937 }
2938
2939 pointToElem[p].SetSize(np[0], np[1], np[2]);
2940 for (int i=0; i<np[0]; ++i)
2941 for (int j=0; j<np[1]; ++j)
2942 for (int k=0; k<np[2]; ++k)
2943 {
2944 const int elem = ijk2elem(patchRules1D_KnotSpan[p][0][i],
2945 patchRules1D_KnotSpan[p][1][j],
2946 patchRules1D_KnotSpan[p][2][k]);
2947 MFEM_VERIFY(elem >= 0, "");
2948 pointToElem[p](i,j,k) = elem;
2949 }
2950 } // Loop (p) over patches
2951}
2952
2954 std::vector<const IntegrationRule*> & ir1D)
2955{
2956 MFEM_VERIFY((int) ir1D.size() == dim, "Wrong dimension");
2957
2958 for (int i=0; i<dim; ++i)
2959 {
2960 patchRules1D(patch,i) = ir1D[i];
2961 }
2962}
2963
2965{
2966 for (int i=0; i<patchRules1D.NumRows(); ++i)
2967 for (int j=0; j<patchRules1D.NumCols(); ++j)
2968 {
2969 delete patchRules1D(i, j);
2970 }
2971}
2972
2973}
int Size() const
Return the logical size of the array.
Definition array.hpp:192
Class for integration point with weight.
Definition intrules.hpp:35
void Set1w(const real_t x1, const real_t w)
Definition intrules.hpp:50
void Set(const real_t x1, const real_t x2, const real_t x3, const real_t w)
Definition intrules.hpp:68
Class for an integration rule - an Array of IntegrationPoint.
Definition intrules.hpp:96
IntegrationRule Reorder(const Array< int > &ordering) const
Returns an integration rule such that the new IntegrationPoints are re-ordered based on ordering.
Definition intrules.cpp:239
int GetOrder() const
Returns the order of the integration rule.
Definition intrules.hpp:248
int GetNPoints() const
Returns the number of the points in the integration rule.
Definition intrules.hpp:255
IntegrationRule * ApplyToKnotIntervals(KnotVector const &kv) const
Return an integration rule for KnotVector kv, defined by applying this rule on each knot interval.
Definition intrules.cpp:193
const Array< real_t > & GetWeights() const
Return the quadrature weights in a contiguous array.
Definition intrules.cpp:98
void SetOrder(const int order)
Sets the order of the integration rule. This is only for keeping order information,...
Definition intrules.hpp:252
void SetPointIndices()
Sets the indices of each quadrature point on initialization.
Definition intrules.cpp:111
IntegrationPoint & IntPoint(int i)
Returns a reference to the i-th integration point.
Definition intrules.hpp:258
Container class for integration rules.
Definition intrules.hpp:430
const IntegrationRule & Get(int GeomType, int Order)
Returns an integration rule for given GeomType and Order.
IntegrationRules(int ref=0, int type=Quadrature1D::GaussLegendre)
void Set(int GeomType, int Order, IntegrationRule &IntRule)
~IntegrationRules()
Destroys an IntegrationRules object.
A vector of knots in one dimension, with B-spline basis functions of a prescribed order.
Definition nurbs.hpp:38
int Size() const
Return the number of knots, including multiplicities.
Definition nurbs.hpp:117
int GetNE() const
Return the number of elements, defined by distinct knots.
Definition nurbs.hpp:108
Mesh data type.
Definition mesh.hpp:67
NURBSExtension * NURBSext
Optional NURBS mesh extension.
Definition mesh.hpp:317
int GetNE() const
Returns number of elements.
Definition mesh.hpp:1390
int Dimension() const
Dimension of the reference space used within the elements.
Definition mesh.hpp:1314
void GetElementIJK(int elem, Array< int > &ijk)
Return Cartesian indices (i,j) in 2D or (i,j,k) in 3D of element elem, in the knot-span tensor produc...
Definition nurbs.cpp:5664
int GetElementPatch(int elem) const
Returns the index of the patch containing element elem.
Definition nurbs.hpp:1104
void GetPatchKnotVectors(int p, Array< KnotVector * > &kv)
Return KnotVectors in kv in each dimension for patch p.
Definition nurbs.cpp:4017
void Finalize(Mesh const &mesh)
Finalize() must be called before this class can be used for assembly. In particular,...
void SetPatchRules1D(const int patch, std::vector< const IntegrationRule * > &ir1D)
Set 1D integration rules to be used as a tensor product rule on the patch with index patch....
void GetIntegrationPointFrom1D(const int patch, int i, int j, int k, IntegrationPoint &ip)
For tensor product rules defined on each patch by SetPatchRules1D(), return the integration point wit...
IntegrationRule & GetElementRule(const int elem, const int patch, const int *ijk, Array< const KnotVector * > const &kv) const
Returns a rule for the element.
static int CheckOpen(int type)
If the Quadrature1D type is not open return Invalid; otherwise return type.
@ ClosedUniform
aka closed Newton-Cotes
Definition intrules.hpp:416
@ ClosedGL
aka closed Gauss Legendre
Definition intrules.hpp:418
@ OpenHalfUniform
aka "open half" Newton-Cotes
Definition intrules.hpp:417
@ OpenUniform
aka open Newton-Cotes
Definition intrules.hpp:415
static int CheckClosed(int type)
If the Quadrature1D type is not closed return Invalid; otherwise return type.
static void GaussLegendre(const int np, IntegrationRule *ir)
Definition intrules.cpp:620
static void ClosedUniform(const int np, IntegrationRule *ir)
Definition intrules.cpp:856
static void OpenUniform(const int np, IntegrationRule *ir)
Definition intrules.cpp:840
static void ClosedGL(const int np, IntegrationRule *ir)
Definition intrules.cpp:891
static void GaussJacobi(const int np, const real_t alpha, const real_t beta, IntegrationRule *ir)
Definition intrules.cpp:488
static void GivePolyPoints(const int np, real_t *pts, const int type)
Definition intrules.cpp:913
static void OpenHalfUniform(const int np, IntegrationRule *ir)
Definition intrules.cpp:876
static void GaussLobatto(const int np, IntegrationRule *ir)
Definition intrules.cpp:708
Container class for integration rules.
Definition intrules.hpp:501
~StroudIntegrationRules()
Destroys an StroudIntegrationRules object.
const IntegrationRule & Get(int GeomType, int Order)
Returns a Stroud integration rule for given GeomType and Order.
Vector data type.
Definition vector.hpp:82
const real_t alpha
Definition ex15.cpp:369
int dim
Definition ex24.cpp:53
real_t weight(const Vector &x)
mfem::real_t real_t
MFEM_HOST_DEVICE dual< value_type, gradient_type > pow(dual< value_type, gradient_type > a, dual< value_type, gradient_type > b)
implementation of a (dual) raised to the b (dual) power
Definition dual.hpp:374
StroudIntegrationRules StroudIntRules
A global object with all Stroud integration rules (defined in intrules.cpp)
IntegrationRule DuffyTrans(const IntegrationRule &ir, int dim)
Definition intrules.cpp:256
float real_t
Definition config.hpp:46
MemoryType
Memory types supported by MFEM.
@ HOST
Host memory; using new[] and delete[].
std::function< real_t(const Vector &)> f(real_t mass_coeff)
Definition lor_mms.hpp:30
IntegrationRules RefinedIntRules(1, Quadrature1D::GaussLegendre)
A global object with all refined integration rules.
Definition intrules.hpp:552
IntegrationRules IntRules(0, Quadrature1D::GaussLegendre)
A global object with all integration rules (defined in intrules.cpp)
Definition intrules.hpp:549
STL namespace.
real_t p(const Vector &x, real_t t)
MFEM_HOST_DEVICE Complex exp(const Complex &q)
void pts(int iphi, int t, real_t x[])