Skip to content

Commit 0c28b08

Browse files
authored
Merge pull request #58 from jeremylt/jeremy/fast-gauss
Use FastGaussQuadrature
2 parents df51ae4 + f05c917 commit 0c28b08

File tree

7 files changed

+41
-270
lines changed

7 files changed

+41
-270
lines changed

Project.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ authors = ["Jeremy L Thompson <[email protected]>"]
44
version = "0.5.0"
55

66
[deps]
7+
FastGaussQuadrature = "442a2c76-b920-505d-bb47-c5924d526838"
78
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
89
Polynomials = "f27b6e38-b328-58d1-80ce-0feddd5e7a45"
910
Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7"

docs/Project.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
[deps]
22
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
33
DocumenterTools = "35a29f4d-8980-5a13-9543-d66fff28ecb8"
4+
FastGaussQuadrature = "442a2c76-b920-505d-bb47-c5924d526838"
45
LFAToolkit = "3f92b583-c0aa-4596-8bdf-f02f6c0a52df"
56

67
[compat]

docs/src/private/basis.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22

33
```@docs
44
LFAToolkit.AbstractBasis
5-
LFAToolkit.gaussquadrature
6-
LFAToolkit.gausslobattoquadrature
75
LFAToolkit.transformquadrature
86
LFAToolkit.sausage_transformation
97
LFAToolkit.kosloff_talezer_transformation

src/Basis/Constructors.jl

Lines changed: 24 additions & 256 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ Conformal mapping of Gauss ellipses to sausage_transformations using a truncated
2222
# Example:
2323
```jldoctest
2424
# sausage_transformation conformal map
25-
g, gprime = LFAToolkit.sausage_transformation(9)
25+
g, gprime = LFAToolkit.sausage_transformation(9);
2626
2727
# verify
2828
@assert g.(LinRange(-1,1,5)) ≈ [-0.9999999999999999, -0.39765215163451934, 0.0, 0.39765215163451934, 0.9999999999999999]
@@ -35,12 +35,12 @@ function sausage_transformation(d)
3535
c = zeros(d + 1)
3636
c[2:2:end] = [1, cumprod(1:2:d-2) ./ cumprod(2:2:d-1)...] ./ (1:2:d)
3737
c /= sum(c)
38-
pg = Polynomial(c)
39-
pgprime = derivative(pg)
38+
gp = Polynomial(c)
39+
gprimep = derivative(gp)
4040

41-
# Lower from Polynomial to Function
42-
g(x) = pg(x)
43-
gprime(x) = pgprime(x)
41+
# lower from Polynomial to Function
42+
g(x) = gp(x)
43+
gprime(x) = gprimep(x)
4444
g, gprime
4545
end
4646

@@ -58,7 +58,6 @@ The Kosloff and Tal-Ezer conformal map derived from the inverse sine function.
5858
# Example:
5959
```jldoctest
6060
# kosloff_talezer_transformation conformal map
61-
numberquadraturepoints = 5;
6261
g, gprime = LFAToolkit.kosloff_talezer_transformation(0.95);
6362
6463
# verify
@@ -102,11 +101,11 @@ function hale_trefethen_strip_transformation(ρ)
102101
d = 0.5 + 1 / (exp* π) + 1)
103102
π2 = π / 2
104103

105-
# Unscaled functions of u
104+
# unscaled functions of u
106105
gu(u) = log(1 + exp(-τ * (π2 + u))) - log(1 + exp(-τ * (π2 - u))) + d * τ * u
107106
gprimeu(u) = 1 / (exp* (π2 + u)) + 1) + 1 / (exp* (π2 - u)) + 1) - d
108107

109-
# Normalizing factor and scaled functions of s
108+
# normalizing factor and scaled functions of s
110109
C = 1 / gu/ 2)
111110
g(s) = C * gu(asin(s))
112111
gprime(s) = -τ * C / sqrt(1 - s^2) * gprimeu(asin(s))
@@ -128,14 +127,16 @@ Transformed quadrature by applying a smooth mapping = (g, gprime) from the origi
128127
129128
# Example:
130129
```jldoctest
130+
using FastGaussQuadrature;
131+
131132
# generate transformed quadrature points, weights with choice of conformal map
132-
points, weights = LFAToolkit.gaussquadrature(5)
133-
mapping = sausage_transformation(9)
134-
mpoints, mweights = transformquadrature(points, weights, mapping)
133+
points, weights = gausslegendre(5);
134+
mapping = sausage_transformation(9);
135+
mappedpoints, mappedweights = transformquadrature(points, weights, mapping);
135136
136137
# verify:
137-
wsum = sum(mweights);
138-
@assert wsum ≈ 2.0
138+
weightsum = sum(mappedweights);
139+
@assert weightsum ≈ 2.0
139140
140141
# output
141142
@@ -167,240 +168,6 @@ end
167168
# utility functions for generating polynomial bases
168169
# ------------------------------------------------------------------------------
169170

170-
"""
171-
```julia
172-
gaussquadrature(q, mapping)
173-
```
174-
175-
Construct a Gauss-Legendre quadrature with the option of applying conformal maps
176-
177-
# Arguments:
178-
- `q`: number of quadrature points
179-
- `mapping`: choice of conformal map
180-
181-
# Returns:
182-
- Gauss-Legendre quadrature points and weights, with conformal mapping applied to the points, if provided
183-
184-
# Example:
185-
```jldoctest
186-
# generate Gauss-Legendre points and weights
187-
quadraturepoints, quadratureweights = LFAToolkit.gaussquadrature(5);
188-
189-
# verify
190-
truepoints = [
191-
-√(5 + 2*√(10/7))/3,
192-
-√(5 - 2*√(10/7))/3,
193-
0.0,
194-
√(5 - 2*√(10/7))/3,
195-
√(5 + 2*√(10/7))/3
196-
];
197-
@assert truepoints ≈ quadraturepoints
198-
199-
trueweights = [
200-
(322-13*√70)/900,
201-
(322+13*√70)/900,
202-
128/225,
203-
(322+13*√70)/900,
204-
(322-13*√70)/900
205-
];
206-
@assert trueweights ≈ quadratureweights
207-
208-
# generate Gauss-Legendre points and weights
209-
mapping = hale_trefethen_strip_transformation(1.4);
210-
quadraturepoints, quadratureweights = LFAToolkit.gaussquadrature(5, mapping = mapping);
211-
212-
# verify
213-
@assert quadraturepoints ≈ [-0.7948688880827978, -0.3997698842865811, 0.0, 0.3997698842865811, 0.7948688880827978]
214-
@assert quadratureweights ≈ [0.3807611340604039, 0.3992835637032222, 0.3999715882806566, 0.3992835637032222, 0.3807611340604039]
215-
216-
# Accuracy test see Hale and Trefethen Fig 3.4
217-
f(x) = exp(-40*x^2)
218-
x, w = LFAToolkit.gaussquadrature(40);
219-
ref = w' * f.(x);
220-
x, w = LFAToolkit.gaussquadrature(20);
221-
xm, wm = LFAToolkit.gaussquadrature(20, mapping=hale_trefethen_strip_transformation(1.4))
222-
223-
# verify
224-
@assert isapprox(w' * f.(x) - ref, -2.879622518375813e-5, rtol=1e-10)
225-
@assert isapprox(wm' * f.(xm) - ref, -3.26498938996167e-10, rtol=1e-5)
226-
227-
# output
228-
229-
```
230-
"""
231-
function gaussquadrature(q::Int; mapping::Union{Tuple{Function,Function},Nothing} = nothing)
232-
quadraturepoints = zeros(Float64, q)
233-
quadratureweights = zeros(Float64, q)
234-
235-
if q < 1
236-
throw(DomainError(q, "q must be greater than or equal to 1")) # COV_EXCL_LINE
237-
end
238-
239-
# build qref1d, qweight1d
240-
for i = 0:floor(Int, q / 2)
241-
# guess
242-
xi = cos* (2 * i + 1.0) / (2 * q))
243-
244-
# Pn(xi)
245-
p0 = 1.0
246-
p1 = xi
247-
p2 = 0.0
248-
for j = 2:q
249-
p2 = ((2 * j - 1.0) * xi * p1 - (j - 1.0) * p0) / j
250-
p0 = p1
251-
p1 = p2
252-
end
253-
254-
# first Newton step
255-
dp2 = (xi * p2 - p0) * q / (xi * xi - 1.0)
256-
xi = xi - p2 / dp2
257-
258-
# Newton to convergence
259-
iter = 0
260-
maxiter = q^2 * 100
261-
while iter < maxiter && abs(p2) > 1e-15
262-
p0 = 1.0
263-
p1 = xi
264-
for j = 2:q
265-
p2 = ((2 * j - 1.0) * xi * p1 - (j - 1.0) * p0) / j
266-
p0 = p1
267-
p1 = p2
268-
end
269-
dp2 = (xi * p2 - p0) * q / (xi * xi - 1.0)
270-
xi = xi - p2 / dp2
271-
iter += 1
272-
end
273-
274-
# save xi, wi
275-
quadraturepoints[i+1] = -xi
276-
quadraturepoints[q-i] = xi
277-
wi = 2.0 / ((1.0 - xi * xi) * dp2 * dp2)
278-
quadratureweights[i+1] = wi
279-
quadratureweights[q-i] = wi
280-
end
281-
quadraturepoints[abs.(quadraturepoints).<10*eps()] .= 0
282-
283-
return transformquadrature(quadraturepoints, quadratureweights, mapping)
284-
end
285-
286-
"""
287-
```julia
288-
gausslobattoquadrature(q, weights, mapping)
289-
```
290-
291-
Construct a Gauss-Legendre-Lobatto quadrature with the option of applying conformal maps
292-
293-
# Arguments:
294-
- `q`: number of Gauss-Legendre-Lobatto points
295-
- `weights`: boolean flag indicating if quadrature weights are desired
296-
- `mapping`: choice of conformal map
297-
298-
# Returns:
299-
- Gauss-Legendre-Lobatto quadrature points or points and weights, with conformal mapping applied to the points, if provided
300-
301-
# Example:
302-
```jldoctest
303-
# generate Gauss-Legendre-Lobatto points and weights
304-
quadraturepoints, quadratureweights = LFAToolkit.gausslobattoquadrature(5, true);
305-
306-
# verify
307-
truepoints = [-1.0, -√(3/7), 0.0, √(3/7), 1.0];
308-
@assert truepoints ≈ quadraturepoints
309-
310-
# verify
311-
trueweights = [1/10, 49/90, 32/45, 49/90, 1/10];
312-
@assert trueweights ≈ quadratureweights
313-
314-
# generate Gauss-Legendre-Lobatto points and weights
315-
mapping = sausage_transformation(9);
316-
quadraturepoints, quadratureweights = LFAToolkit.gausslobattoquadrature(5, true, mapping=mapping)
317-
318-
# verify
319-
@assert quadraturepoints ≈ [-0.9999999999999999, -0.5418159129215785, 0.0, 0.5418159129215785, 0.9999999999999999]
320-
@assert quadratureweights ≈ [0.18690312494113656, 0.5445666710618016, 0.5400742149974571, 0.5445666710618016, 0.18690312494113656]
321-
322-
# output
323-
324-
```
325-
"""
326-
function gausslobattoquadrature(
327-
q::Int,
328-
weights::Bool;
329-
mapping::Union{Tuple{Function,Function},Nothing} = nothing,
330-
)
331-
quadraturepoints = zeros(Float64, q)
332-
quadratureweights = zeros(Float64, q)
333-
334-
if q < 2
335-
throw(DomainError(q, "q must be greater than or equal to 2")) # COV_EXCL_LINE
336-
end
337-
338-
# endpoints
339-
quadraturepoints[1] = -1.0
340-
quadraturepoints[q] = 1.0
341-
if weights
342-
wi = 2.0 / (q * (q - 1.0))
343-
quadratureweights[1] = wi
344-
quadratureweights[q] = wi
345-
end
346-
347-
# build qref1d, qweight1d
348-
for i = 1:floor(Int, (q - 1) / 2)
349-
# guess
350-
xi = cos* i / (q - 1.0))
351-
352-
# Pn(xi)
353-
p0 = 1.0
354-
p1 = xi
355-
p2 = 0.0
356-
for j = 2:q-1
357-
p2 = ((2 * j - 1.0) * xi * p1 - (j - 1.0) * p0) / j
358-
p0 = p1
359-
p1 = p2
360-
end
361-
362-
# first Newton step
363-
dp2 = (xi * p2 - p0) * q / (xi * xi - 1.0)
364-
d2p2 = (2 * xi * dp2 - q * (q - 1.0) * p2) / (1.0 - xi * xi)
365-
xi = xi - dp2 / d2p2
366-
367-
# Newton to convergence
368-
iter = 0
369-
maxiter = q^2 * 100
370-
while iter < maxiter && abs(dp2) > 1e-15
371-
p0 = 1.0
372-
p1 = xi
373-
for j = 2:q-1
374-
p2 = ((2 * j - 1.0) * xi * p1 - (j - 1.0) * p0) / j
375-
p0 = p1
376-
p1 = p2
377-
end
378-
dp2 = (xi * p2 - p0) * q / (xi * xi - 1.0)
379-
d2p2 = (2 * xi * dp2 - q * (q - 1.0) * p2) / (1.0 - xi * xi)
380-
xi = xi - dp2 / d2p2
381-
iter += 1
382-
end
383-
384-
# save xi, wi
385-
quadraturepoints[i+1] = -xi
386-
quadraturepoints[q-i] = xi
387-
if weights
388-
wi = 2.0 / (q * (q - 1.0) * p2 * p2)
389-
quadratureweights[i+1] = wi
390-
quadratureweights[q-i] = wi
391-
end
392-
end
393-
quadraturepoints[abs.(quadraturepoints).<10*eps()] .= 0
394-
395-
396-
# return
397-
if weights
398-
return transformquadrature(quadraturepoints, quadratureweights, mapping)
399-
else
400-
return transformquadrature(quadraturepoints, mapping)
401-
end
402-
end
403-
404171
"""
405172
```julia
406173
buildinterpolationandgradient(
@@ -420,11 +187,13 @@ Build one dimensional interpolation and gradient matrices, from Fornberg 1998
420187
421188
# Example:
422189
```jldoctest
190+
using FastGaussQuadrature
191+
423192
# get nodes, quadrature points, and weights
424193
numbernodes = 3;
425194
numberquadraturepoints = 4;
426-
nodes = LFAToolkit.gausslobattoquadrature(numbernodes, false);
427-
quadraturepoints, quadratureweights1d = LFAToolkit.gaussquadrature(numberquadraturepoints);
195+
nodes, = gausslobatto(numbernodes);
196+
quadraturepoints, quadratureweights1d = gausslegendre(numberquadraturepoints);
428197
429198
# build interpolation, gradient matrices
430199
interpolation, gradient = LFAToolkit.buildinterpolationandgradient(nodes, quadraturepoints);
@@ -584,14 +353,13 @@ function TensorH1LagrangeBasis(
584353
end
585354

586355
# get nodes, quadrature points, and weights
587-
nodes1d = gausslobattoquadrature(numbernodes1d, false)
356+
nodes1d, = gausslobatto(numbernodes1d)
588357
quadraturepoints1d = []
589358
quadratureweights1d = []
590359
if collocatedquadrature
591-
quadraturepoints1d, quadratureweights1d =
592-
gausslobattoquadrature(numberquadraturepoints1d, true)
360+
quadraturepoints1d, quadratureweights1d = gausslobatto(numberquadraturepoints1d)
593361
else
594-
quadraturepoints1d, quadratureweights1d = gaussquadrature(numberquadraturepoints1d)
362+
quadraturepoints1d, quadratureweights1d = gausslegendre(numberquadraturepoints1d)
595363
end
596364

597365
# build interpolation, gradient matrices
@@ -682,7 +450,7 @@ function TensorH1UniformBasis(
682450

683451
# get nodes, quadrature points, and weights
684452
nodes1d = [-1.0:(2.0/(numbernodes1d-1)):1.0...]
685-
quadraturepoints1d, quadratureweights1d = gaussquadrature(numberquadraturepoints1d)
453+
quadraturepoints1d, quadratureweights1d = gausslegendre(numberquadraturepoints1d)
686454

687455
# build interpolation, gradient matrices
688456
interpolation1d, gradient1d = buildinterpolationandgradient(nodes1d, quadraturepoints1d)
@@ -1103,7 +871,7 @@ function TensorH1LagrangeHProlongationBasis(
1103871
numberfineelements1d::Int,
1104872
)
1105873
# generate nodes
1106-
nodescoarse1d = gausslobattoquadrature(numbernodes1d, false)
874+
nodescoarse1d, = gausslobatto(numbernodes1d)
1107875
nodesfine1d = zeros((numbernodes1d - 1) * numberfineelements1d + 1)
1108876
for i = 1:numberfineelements1d
1109877
nodesfine1d[(i-1)*numbernodes1d-i+2:i*numbernodes1d-i+1] =

src/LFAToolkit.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ module LFAToolkit
88
# standard libraries
99
# ------------------------------------------------------------------------------
1010

11+
using FastGaussQuadrature
1112
using LinearAlgebra
1213
using Printf
1314
using SparseArrays

0 commit comments

Comments
 (0)