15 Build a pyramid quadrature rule via the Duffy transform:
16 x = xi*(1-zeta), y = eta*(1-zeta), z = zeta
18 A tensor product of n 1D Gauss-Legendre points (n = ceil((order+1)/2))
19 integrates the pulled-back polynomial stiffness integrand exactly for
20 pyramid basis degree p = order//2.
22 Returns (pts, weights) on the reference pyramid [0<=x,y<=1-z, 0<=z<=1].
28 t, w = np.polynomial.legendre.leggauss(n)
31 xi1d = (t + 1.0) / 2.0
39 xi, eta, zeta = xi1d[i], xi1d[j], xi1d[k]
41 y = eta * (1.0 - zeta)
43 w_total = w1d[i] * w1d[j] * w1d[k] * (1.0 - zeta)**2
45 weights.append(w_total)
48 weights = np.array(weights)
83 Verify Duffy integrates the actual pyramid rational basis products exactly.
84 Tests xy/(1-z), x^2*y/(1-z)^2, etc. that appear in stiffness integrals.
87 x, y, z = sympy.symbols(
'x y z')
89 for p
in range(1, max_p + 1):
94 for a
in range(p + 1):
95 for b
in range(p + 1):
96 for c
in range(p + 1):
99 f = x**a * y**b / (1 - z)**(a + b - c)
if (a+b-c) >= 0
else x**a * y**b * (1-z)**(c-a-b)
104 pts_x, pts_y, pts_z = pts[:,0], pts[:,1], pts[:,2]
106 approx = float(np.sum(weights * pts_x**a * pts_y**b
107 / (1 - pts_z)**(a+b-c)))
109 approx = float(np.sum(weights * pts_x**a * pts_y**b
110 * (1 - pts_z)**(c-a-b)))
111 max_err = max(max_err, abs(exact - approx))
112 print(f
"p={p}, order={order}, max rational error={max_err:.2e}")