feat: Consolidate FEMQuad.jl into JuliaFEM (quadrature rules)

Consolidated entire FEMQuad.jl package (436 lines) into src/quadrature/:
- quaddata.jl: Quadrature data definitions
- glquad.jl: 2D quadrilateral Gauss-Legendre rules
- gltri.jl: 2D triangle Gauss-Legendre rules (131 lines)
- gltet.jl: 3D tetrahedron Gauss-Legendre rules
- glwed.jl: 3D wedge Gauss-Legendre rules
- glpyr.jl: 3D pyramid Gauss-Legendre rules

Changes:
- Created src/quadrature.jl as main include file
- Removed 'import FEMQuad' from JuliaFEM.jl
- Updated integrate.jl: FEMQuad.get_quadrature_points → get_quadrature_points
- Added export add_element! (was missing)

Result:
- ✅ JuliaFEM loads successfully
- ✅ Integration points work correctly
- ✅ 5 tests still passing (no regression)
- ✅ One less vendor package dependency

Next: Continue consolidating vendor packages
This commit is contained in:
Jukka Aho
2025-11-08 10:49:28 +02:00
parent a8d4f7e504
commit 315c319963
10 changed files with 505 additions and 4 deletions
+48
View File
@@ -0,0 +1,48 @@
# This file is a part of JuliaFEM.
# License is MIT: see https://github.com/JuliaFEM/FEMQuad.jl/blob/master/LICENSE
module FEMQuad
# Gaussian-Legendre quadratures
include("quaddata.jl")
include("glquad.jl")
# Gaussian-Legendre quadratures in 2d triangles
include("gltri.jl")
# Gaussian-Legendre quadratures in 3d hexahedrons
include("gltet.jl")
# Gaussian-Legendre quadratures in 3d wedges
include("glwed.jl")
# Gaussian-Legendre quadratures in 3d pyramid
include("glpyr.jl")
function get_rule(order::Int, rules::Vararg{Symbol})
for rule in rules
if get_order(Val{rule}) >= order
return rule
end
end
@warn("No accurate rule enough found, picking last.", order, rules)
return rules[end]
end
function integrate_1d(f::Function, rule::Symbol)
points = get_quadrature_points(Val{rule})
result = sum(w*f(ip) for (w, ip) in points)
return result
end
function integrate_2d(f::Function, rule::Symbol)
points = get_quadrature_points(Val{rule})
result = sum(w*f(ip) for (w, ip) in points)
return result
end
function integrate_3d(f::Function, rule::Symbol)
points = get_quadrature_points(Val{rule})
result = sum(w*f(ip) for (w, ip) in points)
return result
end
export get_quadrature_points
end
+45
View File
@@ -0,0 +1,45 @@
# This file is a part of JuliaFEM.
# License is MIT: see https://github.com/JuliaFEM/FEMQuad.jl/blob/master/LICENSE
### Gauss quadrature rules for pyramid elements
""" Gauss-Legendre quadrature, 5 point rule on pyramid. """
function get_quadrature_points(::Type{Val{:GLPYR5}})
g1 = 0.5842373946721771876874344
g2 = -2.0/3.0
g3 = 2.0/5.0
w1 = 81.0/100.0
w2 = 125.0/27.0
weights = (w1, w1, w1, w1, w2)
points = (
(-g1, -g1, g2),
( g1, -g1, g2),
( g1, g1, g2),
(-g1, g1, g2),
(0.0, 0.0, g3))
return zip(weights, points)
end
function get_order(::Type{Val{:GLPYR5}})
return 1
end
""" Gauss-Legendre quadrature, 5 point rule on pyramid. """
function get_quadrature_points(::Type{Val{:GLPYR5B}})
a = 2.0/15.0
h1 = 0.1531754163448146
h2 = 0.6372983346207416
weights = (a, a, a, a, a)
points = (
(0.5, 0.0, h1),
(0.0, 0.5, h1),
(-0.5, 0.0, h1),
(0.0, -0.5, h1),
(0.0, 0.0, h2)
)
return zip(weights, points)
end
function get_order(::Type{Val{:GLPYR5B}})
return 1
end
+40
View File
@@ -0,0 +1,40 @@
# This file is a part of JuliaFEM.
# License is MIT: see https://github.com/JuliaFEM/FEMQuad.jl/blob/master/LICENSE
# Tensorial quadrature rules in 1, 2, 3 dimensions
function tensor_product(w::Tuple, p::Tuple, dim::Int)
@assert length(w) == length(p)
N = length(w)
weights = Float64[]
points = NTuple{dim, Float64}[]
for i in CartesianIndices(ntuple(i -> 1:N, dim))
push!(weights, prod(w[k] for k in Tuple(i)))
push!(points, ntuple(k -> p[i[k]], dim))
end
return zip(Tuple(weights), Tuple(points))
end
names = [:GLSEG, :GLQUAD, :GLHEX]
names2 = ["segment", "quadrilateral", "hexahedron"]
for n in 1:length(QUAD_DATA)
points, weights = QUAD_DATA[n]
order = 2(n-1)+1
for dim in (1, 2, 3)
n_points = length(points)^dim
quadname = QuoteNode(Symbol(string(names[dim], n_points)))
z = tensor_product(weights, points, dim)
@eval begin
@doc """
get_quadrature_points(::Type{Val{:$($(quadname))})
Gauss-Legendre quadrature, $($(n_points)) point rule on $($(names2[dim]))."""
get_quadrature_points(::Type{Val{$(quadname)}}) = $z
end
@eval get_order(::Type{Val{$(quadname)}}) = $order
end
end
+67
View File
@@ -0,0 +1,67 @@
# This file is a part of JuliaFEM.
# License is MIT: see https://github.com/JuliaFEM/FEMQuad.jl/blob/master/LICENSE
### Gauss quadrature rules for tetrahedrons
""" Gauss-Legendre quadrature, 1 point rule on tetrahedron. """
function get_quadrature_points(::Type{Val{:GLTET1}})
weights = (1.0/6.0, )
points = ((1.0/4.0, 1.0/4.0, 1.0/4.0), )
return zip(weights, points)
end
function get_order(::Type{Val{:GLTET1}})
return 1
end
""" Gauss-Legendre quadrature, 4 point rule on tetrahedron. """
function get_quadrature_points(::Type{Val{:GLTET4}})
a = (5.0+3.0*sqrt(5.0))/20.0
b = (5.0-sqrt(5.0))/20.0
w = 1.0/24.0
weights = (w, w, w, w)
points = ((a, b, b), (b, a, b), (b, b, a), (b, b, b))
return zip(weights, points)
end
function get_order(::Type{Val{:GLTET4}})
return 2
end
""" Gauss-Legendre quadrature, 5 point rule on tetrahedron. """
function get_quadrature_points(::Type{Val{:GLTET5}})
a = 1.0/4.0
b = 1.0/6.0
c = 1.0/2.0
weights = (-2.0/15.0, 3.0/40.0, 3.0/40.0, 3.0/40.0, 3.0/40.0)
points = ((a, a, a), (b, b, b), (b, b, c), (b, c, b), (c, b, b))
return zip(weights, points)
end
function get_order(::Type{Val{:GLTET5}})
return 3
end
""" Gauss-Legendre quadrature, 15 point rule on tetrahedron. """
function get_quadrature_points(::Type{Val{:GLTET15}})
a = 1.0/4.0
b1 = 1.0/34.0*(7.0 + sqrt(15.0))
b2 = 1.0/34.0*(7.0 - sqrt(15.0))
c1 = 1.0/34.0*(13.0 - 3.0*sqrt(15.0))
c2 = 1.0/34.0*(13.0 + 3.0*sqrt(15.0))
d = 1.0/20.0*(5.0 - sqrt(15.0))
f = 1.0/20.0*(5.0 + sqrt(15.0))
w1 = 8.0/405.0
w2 = (2665.0 - 14.0*sqrt(15.0))/226800.0
w3 = (2665.0 + 14.0*sqrt(15.0))/226800.0
w4 = 5.0/567.0
weights = (w1, w2, w2, w2, w2, w3, w3, w3, w3, w4, w4, w4, w4, w4, w4)
points = ((a, a, a), (b1, b1, b1), (b1, b1, c1), (b1, c1, b1), (c1, b1, b1),
(b2, b2, b2), (b2, b2, c2), (b2, c2, b2), (c2, b2, b2), (d, d, f),
(d, f, d), (f, d, d), (d, f, f), (f, d, f), (f, f, d))
return zip(weights, points)
end
function get_order(::Type{Val{:GLTET15}})
return 4
end
+131
View File
@@ -0,0 +1,131 @@
# This file is a part of JuliaFEM.
# License is MIT: see https://github.com/JuliaFEM/FEMQuad.jl/blob/master/LICENSE
### Gauss quadrature rules for triangular elements
""" Gauss-Legendre quadrature, 1 point rule on triangle. """
function get_quadrature_points(::Type{Val{:GLTRI1}})
weights = (0.5, )
points = ((1.0/3.0, 1.0/3.0), )
return zip(weights, points)
end
function get_order(::Type{Val{:GLTRI1}})
return 1
end
""" Gauss-Legendre quadrature, 3 point rule on triangle. """
function get_quadrature_points(::Type{Val{:GLTRI3}})
weights = (1.0/6.0, 1.0/6.0, 1.0/6.0)
points = (
(2.0/3.0, 1.0/6.0),
(1.0/6.0, 2.0/3.0),
(1.0/6.0, 1.0/6.0)
)
return zip(weights, points)
end
function get_order(::Type{Val{:GLTRI3}})
return 2
end
""" Gauss-Legendre quadrature, 3 point rule on triangle. """
function get_quadrature_points(::Type{Val{:GLTRI3B}})
weights = (1.0/6.0, 1.0/6.0, 1.0/6.0)
points = (
(0.0, 1.0/2.0),
(1.0/2.0, 0.0),
(1.0/2.0, 1.0/2.0)
)
return zip(weights, points)
end
function get_order(::Type{Val{:GLTRI3B}})
return 2
end
""" Gauss-Legendre quadrature, 4 point rule on triangle. """
function get_quadrature_points(::Type{Val{:GLTRI4}})
weights = (
1.5902069087198858469718450103758e-01,
9.0979309128011415302815498962418e-02,
1.5902069087198858469718450103758e-01,
9.0979309128011415302815498962418e-02)
points = (
(1.5505102572168219018027159252941e-01, 1.7855872826361642311703513337422e-01),
(6.4494897427831780981972840747059e-01, 7.5031110222608118177475598324603e-02),
(1.5505102572168219018027159252941e-01, 6.6639024601470138670269327409637e-01),
(6.4494897427831780981972840747059e-01, 2.8001991549907407200279599420481e-01))
return zip(weights, points)
end
function get_order(::Type{Val{:GLTRI4}})
return 3
end
""" Gauss-Legendre quadrature, 4 point rule on triangle. """
function get_quadrature_points(::Type{Val{:GLTRI4B}})
weights = (-27.0/96.0, 25.0/96.0, 25.0/96.0, 25.0/96.0)
points = (
(1.0/3.0, 1.0/3.0),
(1.0/5.0, 1.0/5.0),
(1.0/5.0, 3.0/5.0),
(3.0/5.0, 1.0/5.0))
return zip(weights, points)
end
function get_order(::Type{Val{:GLTRI4B}})
return 3
end
""" Gauss-Legendre quadrature, 6 point rule on triangle. """
function get_quadrature_points(::Type{Val{:GLTRI6}})
P1 = 0.11169079483905
P2 = 0.0549758718227661
A = 0.445948490915965
B = 0.091576213509771
weights = (P2, P2, P2, P1, P1, P1)
points = ((B, B), (1.0-2.0*B, B), (B, 1.0-2.0*B),
(A, 1.0-2*A), (A, A), (1.0 - 2.0*A, A))
return zip(weights, points)
end
function get_order(::Type{Val{:GLTRI6}})
return 4
end
""" Gauss-Legendre quadrature, 7 point rule on triangle. """
function get_quadrature_points(::Type{Val{:GLTRI7}})
A = 0.470142064105115
B = 0.101286507323456
P1 = 0.066197076394253
P2 = 0.062969590272413
weights = (9/80, P1, P1, P1, P2, P2, P2)
points = ((1/3, 1/3), (A, A), (1.0-2.0*A, A), (A, 1.0-2.0*A),
(B, B), (1.0-2.0*B, B), (B, 1.0-2.0*B))
return zip(weights, points)
end
function get_order(::Type{Val{:GLTRI7}})
return 5
end
""" Gauss-Legendre quadrature, 12 point rule on triangle. """
function get_quadrature_points(::Type{Val{:GLTRI12}})
A = 0.063089014491502
B = 0.249286745170910
C = 0.310352451033785
D = 0.053145049844816
P1 = 0.025422453185103
P2 = 0.058393137863189
P3 = 0.041425537809187
weights = (P1, P1, P1, P2, P2, P2, P3, P3, P3, P3, P3, P3)
points = ((A, A), (1.0-2.0*A, A), (A, 1.0-2.0*A), (B, B), (1.0-2.0*B, B),
(B, 1.0-2.0*B), (C, D), (D, C), (1.0-C-D, C), (1.0-C-D, D),
(C, 1.0-C-D), (D, 1.0-C-D))
return zip(weights, points)
end
function get_order(::Type{Val{:GLTRI12}})
return 6
end
+93
View File
@@ -0,0 +1,93 @@
# This file is a part of JuliaFEM.
# License is MIT: see https://github.com/JuliaFEM/FEMQuad.jl/blob/master/LICENSE
### Gauss quadrature rules for prismatic elements (wedge)
""" Gauss-Legendre quadrature, 6 point rule on wedge. """
function get_quadrature_points(::Type{Val{:GLWED6}})
w = 1.0/6.0
a = sqrt(1.0/3.0)
weights = (w, w, w, w, w, w)
points = ((0.5, 0.0, -a), (0.0, 0.5, -a), (0.5, 0.5, -a),
(0.5, 0.0, a), (0.0, 0.5, a), (0.5, 0.5, a))
return zip(weights, points)
end
function get_order(::Type{Val{:GLWED6}})
return 1
end
""" Gauss-Legendre quadrature, 6 point rule on wedge. """
function get_quadrature_points(::Type{Val{:GLWED6B}})
w = 1.0/6.0
a = sqrt(1.0/3.0)
weights = (w, w, w, w, w, w)
points = ((2.0/3.0, 1.0/6.0, -a), (1.0/6.0, 2.0/3.0, -a), (1.0/6.0, 1.0/6.0, -a),
(2.0/3.0, 1.0/6.0, a), (1.0/6.0, 2.0/3.0, a), (1.0/6.0, 1.0/6.0, a))
return zip(weights, points)
end
function get_order(::Type{Val{:GLWED6B}})
return 1
end
""" Gauss-Legendre quadrature, 21 point rule on wedge. """
function get_quadrature_points(::Type{Val{:GLWED21}})
alpha = sqrt(3/5)
c1 = 5/9
c2 = 8/9
a = (6+sqrt(15))/21
b = (6-sqrt(15))/21
weights = (
c1*9/80,
c1*((155+sqrt(15))/2400),
c1*((155+sqrt(15))/2400),
c1*((155+sqrt(15))/2400),
c1*((155-sqrt(15))/2400),
c1*((155-sqrt(15))/2400),
c1*((155-sqrt(15))/2400),
c2*9/80,
c2*((155+sqrt(15))/2400),
c2*((155+sqrt(15))/2400),
c2*((155+sqrt(15))/2400),
c2*((155-sqrt(15))/2400),
c2*((155-sqrt(15))/2400),
c2*((155-sqrt(15))/2400),
c1*9/80,
c1*((155+sqrt(15))/2400),
c1*((155+sqrt(15))/2400),
c1*((155+sqrt(15))/2400),
c1*((155-sqrt(15))/2400),
c1*((155-sqrt(15))/2400),
c1*((155-sqrt(15))/2400))
points = (
(1/3, 1/3, -alpha),
(a, a, -alpha),
(1-2a, a, -alpha),
(a, 1-2a, -alpha),
(b, b, -alpha),
(1-2b, b, -alpha),
(b, 1-2b, -alpha),
(1/3, 1/3, 0),
(a, a, 0),
(1-2a, a, 0),
(a, 1-2a, 0),
(b, b, 0),
(1-2b, b, 0),
(b, 1-2b, 0),
(1/3, 1/3, alpha),
(a, a, alpha),
(1-2a, a, alpha),
(a, 1-2a, alpha),
(b, b, alpha),
(1-2b, b, alpha),
(b, 1-2b, alpha))
return zip(weights, points)
end
function get_order(::Type{Val{:GLWED21}})
return 5
end
+12
View File
@@ -0,0 +1,12 @@
const QUAD_DATA = [
[(0.0,),
(2.0,)],
[(-0.5773502691896258, 0.5773502691896258,),
(1.0, 1.0,)],
[(-0.7745966692414834, 0.0, 0.7745966692414834,),
(0.5555555555555556, 0.8888888888888888, 0.5555555555555556,)],
[(-0.8611363115940526, -0.3399810435848563, 0.3399810435848563, 0.8611363115940526,),
(0.34785484513745385, 0.6521451548625462, 0.6521451548625462, 0.34785484513745385,)],
[(-0.906179845938664, -0.5384693101056831, 0.0, 0.5384693101056831, 0.906179845938664,),
(0.23692688505618908, 0.47862867049936647, 0.5688888888888889, 0.47862867049936647, 0.23692688505618908,)],
]