Skip to content

Commit 125d347

Browse files
authored
Support zero Dirichlet conditions (#37)
* save * Start Dirichlet * Support Dirichlet * tests pass * Work on ADI * Arrowhead Mul * Update adi_poisson.jl * Avoid accessing outside arrays * Doesn't error with p = 160 * Increase coverage
1 parent e2dcaec commit 125d347

11 files changed

+525
-237
lines changed

Project.toml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "PiecewiseOrthogonalPolynomials"
22
uuid = "4461d12d-4663-4550-8580-cb764c85e20f"
33
authors = ["Sheehan Olver <[email protected]>"]
4-
version = "0.1.0"
4+
version = "0.2.0"
55

66
[deps]
77
ArrayLayouts = "4c555306-a7a7-4459-81d9-ec55ddd5c99a"
@@ -21,16 +21,16 @@ QuasiArrays = "c4ea9172-b204-11e9-377d-29865faadc5c"
2121

2222
[compat]
2323
ArrayLayouts = "1.0.12"
24-
BandedMatrices = "0.17.30"
24+
BandedMatrices = "0.17.33"
2525
BlockArrays = "0.16.25"
26-
BlockBandedMatrices = "0.12"
26+
BlockBandedMatrices = "0.12.2"
2727
ClassicalOrthogonalPolynomials = "0.11"
2828
ContinuumArrays = "0.14"
2929
FillArrays = "1.0"
3030
InfiniteArrays = "0.12.6"
3131
InfiniteLinearAlgebra = "0.6.16"
3232
LazyArrays = "1.0"
33-
LazyBandedMatrices = "0.8.13"
33+
LazyBandedMatrices = "0.8.15"
3434
MatrixFactorizations = "2.0"
3535
QuasiArrays = "0.11"
3636
julia = "1.9"

examples/adi_poisson.jl

Lines changed: 41 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
using PiecewiseOrthogonalPolynomials, MatrixFactorizations
1+
using PiecewiseOrthogonalPolynomials, MatrixFactorizations, HypergeometricFunctions
22
using Elliptic
33
using ClassicalOrthogonalPolynomials, StaticArrays, LinearAlgebra
4+
using Base: oneto
45

56
"""
67
Solve the Poisson equation with zero Dirichlet boundary conditions on the square
@@ -16,34 +17,44 @@ function mobius(z, a, b, c, d, α)
1617
(t₁*z + t₂)/(t₃*z + t₄)
1718
end
1819

20+
ellipticK(z) = convert(eltype(α),π)/2*HypergeometricFunctions._₂F₁(one(α)/2,one(α)/2,1, z)
1921

20-
function ADI_shifts(J, a, b, c, d, tol)
22+
23+
function ADI_shifts(J, a, b, c, d, tol=1e-15)
2124
γ = (c-a)*(d-b)/((c-b)*(d-a))
2225
α = -1 + 2γ + 2Complex^2 - γ)
2326
α = Real(α)
2427

25-
K = Elliptic.K(1-1/α^2)
26-
dn = [Elliptic.Jacobi.dn((2*j + 1)*K/(2J), 1-1/α^2) for j = 0:J-1]
28+
# K = ellipticK(1-1/big(α)^2)
29+
if α < 1e7
30+
K = Elliptic.K(1-1/α^2)
31+
dn = Elliptic.Jacobi.dn.((2*(0:J-1) + 1)*K/(2J), 1-1/α^2)
32+
else
33+
K = 2log(2)+log(α) + (-1+2log(2)+log(α))/α^2/4
34+
m1 = 1/α^2
35+
u = (1/2:J-1/2) * K/J
36+
dn = @. sech(u) + m1/4 * (sinh(u)cosh(u) + u) * tanh(u) * sech(u)
37+
end
2738

2839
[mobius(-α*i, a, b, c, d, α) for i = dn], [mobius*i, a, b, c, d, α) for i = dn]
2940
end
3041

31-
function ADI(A, B, M, F, a, b, c, d, tol)
42+
function ADI(A, B, C, F, a, b, c, d, tol=1e-15)
3243
"ADI method for solving standard sylvester AX - XB = F"
3344
# Modified slightly by John to allow for the mass matrix
3445
n = size(A)[1]
35-
X = zeros((n, n))
46+
X = zeros(axes(A))
3647

3748
γ = (c-a)*(d-b)/((c-b)*(d-a))
3849
J = Int(ceil(log(16γ)*log(4/tol)/π^2))
3950
# J = 200
4051
p, q = ADI_shifts(J, a, b, c, d, tol)
4152

4253
for j = 1:J
43-
X = (F - (A - p[j]*M)*X)/(B - p[j]*M)
44-
X = (A - q[j]*M)\(F - X*(B - q[j]*M))
54+
X = ((A/p[j] - C)*X - F/p[j])/reversecholesky(Symmetric(C - B/p[j]))
55+
X = reversecholesky(Symmetric(C - A/q[j]))\(X*(B/q[j] - C) - F/q[j])
4556
end
46-
57+
4758
X
4859
end
4960

@@ -56,8 +67,8 @@ function analysis_2D(f, n, p)
5667

5768
for i = 0:n-1 # loop over cells in positive x direction
5869
for j = 0:n-1 # loop over cells in positive y direction
59-
local f_ = z -> ((x,y)= z; f((x + i*dx - 1, y + j*dx - 1))) # define f on reference cell
60-
F[i+1:n:n*p, j+1:n:n*p] = T * f_.(SVector.(z, z')) # interpolate f into 2D tensor Legendre polynomials on reference cell
70+
f_ = (x,y) -> f(x + i*dx - 1, y + j*dx - 1) # define f on reference cell
71+
F[i+1:n:n*p, j+1:n:n*p] = T * f_.(z, z') # interpolate f into 2D tensor Legendre polynomials on reference cell
6172
end
6273
end
6374

@@ -67,65 +78,42 @@ end
6778
r = range(-1, 1, 5)
6879
K = length(r)-1
6980

70-
C = ContinuousPolynomial{1}(r)
7181
P = ContinuousPolynomial{0}(r)
72-
D = Derivative(axes(C,1))
73-
Δ = -weaklaplacian(C)
74-
M = grammatrix(C)
75-
e1s, e2s = [], []
76-
p = 40 # truncation degree on each cell
77-
N = K+1 + K*(p+1) # amount of basis functions in C
78-
79-
# Truncated Laplacian + Dirichlet bcs
80-
81-
82+
Q = DirichletPolynomial(r)
83+
Δ = -weaklaplacian(Q)
84+
M = grammatrix(Q)
8285

86+
p = 300 # truncation degree on each cell
87+
KR = Block.(oneto(p))
88+
Δₙ = Δ[KR,KR]
89+
Mₙ = M[KR,KR]
8390

84-
= Matrix(Δ[Block.(1:p), Block.(1:p)]);
85-
pΔ[:,1] .=0; pΔ[1,:] .=0; pΔ[1,1] = 1.;
86-
pΔ[:,K+1] .=0; pΔ[K+1,:] .=0; pΔ[K+1,K+1] = 1.;
87-
88-
# Truncated mass + Dirichlet bcs
89-
pM = Matrix(M[Block.(1:p), Block.(1:p)]);
90-
pM[:,1] .=0; pM[1,:] .=0; pM[1,1] = 1.;
91-
pM[:,K+1] .=0; pM[K+1,:] .=0; pM[K+1,K+1] = 1.;
92-
93-
"""
94-
Via the standard route ADI
95-
"""
96-
# Reverse Cholesky
97-
rpΔ = pΔ[end:-1:1, end:-1:1]
98-
L = cholesky(Symmetric(rpΔ)).L
99-
L = L[end:-1:1, end:-1:1]
100-
L * L'
91+
U = reversecholesky(Symmetric(Δₙ)).U
10192

102-
# Compute spectrum
103-
A = (L \ (L \ pM)') # = L⁻¹ pΔ L⁻ᵀ
93+
A = (U \ (U \ Mₙ)') # = L⁻¹ pΔ L⁻ᵀ
10494
e1s, e2s = eigmin(A), eigmax(A)
10595

10696
z = SVector.(-1:0.01:1, (-1:0.01:1)')
10797

10898
# RHS
109-
f(z) = ((x,y)= z; -2 .*sin.(pi*x) .* (2pi*y .*cos.(pi*y) .+ (1-pi^2*y^2) .*sin.(pi*y)))
99+
f = (x,y) -> -2 .*sin.(pi*x) .* (2pi*y .*cos.(pi*y) .+ (1-pi^2*y^2) .*sin.(pi*y))
110100
fp = analysis_2D(f, K, p) # interpolate F into P⊗P
111-
Fa = P[first.(z)[:,1], Block.(1:p)] * fp * P[first.(z)[:,1], Block.(1:p)]'
112-
norm(f.(z) - Fa)
101+
Fa = P[first.(z)[:,1], KR] * fp * P[first.(z)[:,1], KR]'
102+
norm(splat(f).(z) - Fa)
113103

114104
# weak form for RHS
115-
F = (C'*P)[Block.(1:p), Block.(1:p)]*fp*((C'*P)[Block.(1:p), Block.(1:p)])' # RHS <f,v>
116-
F[1, :] .= 0; F[K+1, :] .= 0; F[:, 1] .= 0; F[:, K+1] .= 0 # Dirichlet bcs
105+
F = (Q'*P)[KR, KR]*fp*((Q'*P)[KR, KR])' # RHS <f,v>
117106

118-
tol = 1e-15 # ADI tolerance
119-
A, B, a, b, c, d = pM, -pM, e1s, e2s, -e2s, -e1s
120-
X = ADI(A, B, pΔ, F, a, b, c, d, tol)
107+
A, B, a, b, c, d = Mₙ, -Mₙ, e1s, e2s, -e2s, -e1s
108+
@time X = ADI(A, B, Δₙ, F, a, b, c, d)
121109

122110
# X = UΔ
123-
U = (L' \ (L \ X'))'
111+
Y = (U' \ (U \ X'))'
124112

125113
u_exact = z -> ((x,y)= z; sin.(π*x)*sin.(π*y)*y^2)
126-
Ua = C[first.(z)[:,1], Block.(1:p)] * U * C[first.(z)[:,1], Block.(1:p)]'
114+
Ua = Q[first.(z)[:,1], Block.(1:p)] * Y * Q[first.(z)[:,1], Block.(1:p)]'
127115

128-
norm(u_exact.(z) - Ua) # ℓ^∞ error.
116+
@test u_exact.(z) Ua # ℓ^∞ error.
129117

130118
"""
131119
Via (5.3) and (5.6) of Kars' thesis.
@@ -153,7 +141,7 @@ F = (C'*P)[Block.(1:p), Block.(1:p)]*fp*((C'*P)[Block.(1:p), Block.(1:p)])' # R
153141
F[1, :] .= 0; F[K+1, :] .= 0; F[:, 1] .= 0; F[:, K+1] .= 0 # Dirichlet bcs
154142

155143
tol = 1e-15 # ADI tolerance
156-
A, B, a, b, c, d = pΔ, -pΔ, e1s, e2s, -e2s, -e1s
144+
A, B, a, b, c, d = pΔ, -pΔ, e1s, e2s, -e2s, -e1s
157145
X = ADI(A, B, pM, F, a, b, c, d, tol)
158146

159147
# X = UM

src/PiecewiseOrthogonalPolynomials.jl

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
module PiecewiseOrthogonalPolynomials
22
using ClassicalOrthogonalPolynomials, LinearAlgebra, BlockArrays, BlockBandedMatrices, BandedMatrices, ContinuumArrays, QuasiArrays, LazyArrays, LazyBandedMatrices, FillArrays, MatrixFactorizations, ArrayLayouts
33

4-
import ArrayLayouts: sublayout, sub_materialize, symmetriclayout, transposelayout, SymmetricLayout, HermitianLayout, TriangularLayout, layout_getindex, materialize!, MatLdivVec, AbstractStridedLayout, triangulardata
4+
import ArrayLayouts: sublayout, sub_materialize, symmetriclayout, transposelayout, SymmetricLayout, HermitianLayout, TriangularLayout, layout_getindex, materialize!, MatLdivVec, AbstractStridedLayout, triangulardata, MatMulMatAdd, MatMulVecAdd, _fill_lmul!
55
import BandedMatrices: _BandedMatrix
66
import BlockArrays: BlockSlice, block, blockindex, blockvec
77
import BlockBandedMatrices: _BandedBlockBandedMatrix, AbstractBandedBlockBandedMatrix, subblockbandwidths, blockbandwidths, AbstractBandedBlockBandedLayout, layout_replace_in_print_matrix
@@ -13,11 +13,13 @@ import Base: axes, getindex, +, -, *, /, ==, \, OneTo, oneto, replace_in_print_m
1313
import LinearAlgebra: BlasInt
1414
import MatrixFactorizations: reversecholcopy
1515

16-
export PiecewisePolynomial, ContinuousPolynomial, Derivative, Block, weaklaplacian, grammatrix
16+
export PiecewisePolynomial, ContinuousPolynomial, DirichletPolynomial, Derivative, Block, weaklaplacian, grammatrix
1717

18+
include("arrowhead.jl")
1819
include("piecewisepolynomial.jl")
1920
include("continuouspolynomial.jl")
20-
include("arrowhead.jl")
21+
include("dirichlet.jl")
22+
2123

2224

2325
end # module

0 commit comments

Comments
 (0)