Skip to content

Commit e2dcaec

Browse files
authored
reorg package (#36)
1 parent 6c0c3c0 commit e2dcaec

File tree

4 files changed

+487
-316
lines changed

4 files changed

+487
-316
lines changed

examples/adi_poisson.jl

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
using PiecewiseOrthogonalPolynomials, MatrixFactorizations
2+
using Elliptic
3+
using ClassicalOrthogonalPolynomials, StaticArrays, LinearAlgebra
4+
5+
"""
6+
Solve the Poisson equation with zero Dirichlet boundary conditions on the square
7+
"""
8+
9+
# These 4 routines from ADI were lifted from Kars' M4R repo.
10+
function mobius(z, a, b, c, d, α)
11+
t₁ = a*(-α*b + b + α*c + c) - 2b*c
12+
t₂ = a**(b+c) - b + c) - 2α*b*c
13+
t₃ = 2a -+1)*b +-1)*c
14+
t₄ = -α*(-2a+b+c) - b + c
15+
16+
(t₁*z + t₂)/(t₃*z + t₄)
17+
end
18+
19+
20+
function ADI_shifts(J, a, b, c, d, tol)
21+
γ = (c-a)*(d-b)/((c-b)*(d-a))
22+
α = -1 + 2γ + 2Complex^2 - γ)
23+
α = Real(α)
24+
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]
27+
28+
[mobius(-α*i, a, b, c, d, α) for i = dn], [mobius*i, a, b, c, d, α) for i = dn]
29+
end
30+
31+
function ADI(A, B, M, F, a, b, c, d, tol)
32+
"ADI method for solving standard sylvester AX - XB = F"
33+
# Modified slightly by John to allow for the mass matrix
34+
n = size(A)[1]
35+
X = zeros((n, n))
36+
37+
γ = (c-a)*(d-b)/((c-b)*(d-a))
38+
J = Int(ceil(log(16γ)*log(4/tol)/π^2))
39+
# J = 200
40+
p, q = ADI_shifts(J, a, b, c, d, tol)
41+
42+
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))
45+
end
46+
47+
X
48+
end
49+
50+
function analysis_2D(f, n, p)
51+
dx = 2/n
52+
53+
P₀ = legendre(0..dx) # Legendre mapped to the reference cell
54+
z,T = ClassicalOrthogonalPolynomials.plan_grid_transform(P₀, (p, p))
55+
F = zeros(n*p, n*p) # initialise F
56+
57+
for i = 0:n-1 # loop over cells in positive x direction
58+
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
61+
end
62+
end
63+
64+
F
65+
end
66+
67+
r = range(-1, 1, 5)
68+
K = length(r)-1
69+
70+
C = ContinuousPolynomial{1}(r)
71+
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+
83+
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'
101+
102+
# Compute spectrum
103+
A = (L \ (L \ pM)') # = L⁻¹ pΔ L⁻ᵀ
104+
e1s, e2s = eigmin(A), eigmax(A)
105+
106+
z = SVector.(-1:0.01:1, (-1:0.01:1)')
107+
108+
# RHS
109+
f(z) = ((x,y)= z; -2 .*sin.(pi*x) .* (2pi*y .*cos.(pi*y) .+ (1-pi^2*y^2) .*sin.(pi*y)))
110+
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)
113+
114+
# 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
117+
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)
121+
122+
# X = UΔ
123+
U = (L' \ (L \ X'))'
124+
125+
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)]'
127+
128+
norm(u_exact.(z) - Ua) # ℓ^∞ error.
129+
130+
"""
131+
Via (5.3) and (5.6) of Kars' thesis.
132+
"""
133+
# Reverse Cholesky
134+
rpM = pM[end:-1:1, end:-1:1]
135+
L = cholesky(Symmetric(rpM)).L
136+
L = L[end:-1:1, end:-1:1]
137+
L * L' pM
138+
139+
# Compute spectrum
140+
A = (L \ (L \ pΔ)') # = L⁻¹ pΔ L⁻ᵀ
141+
e1s, e2s = eigmin(A), eigmax(A)
142+
143+
z = SVector.(-1:0.01:1, (-1:0.01:1)')
144+
145+
# RHS
146+
f(z) = ((x,y)= z; -2 .*sin.(pi*x) .* (2pi*y .*cos.(pi*y) .+ (1-pi^2*y^2) .*sin.(pi*y)))
147+
fp = analysis_2D(f, K, p) # interpolate F into P⊗P
148+
Fa = P[first.(z)[:,1], Block.(1:p)] * fp * P[first.(z)[:,1], Block.(1:p)]'
149+
norm(f.(z) - Fa)
150+
151+
# weak form for RHS
152+
F = (C'*P)[Block.(1:p), Block.(1:p)]*fp*((C'*P)[Block.(1:p), Block.(1:p)])' # RHS <f,v>
153+
F[1, :] .= 0; F[K+1, :] .= 0; F[:, 1] .= 0; F[:, K+1] .= 0 # Dirichlet bcs
154+
155+
tol = 1e-15 # ADI tolerance
156+
A, B, a, b, c, d = pΔ, -pΔ, e1s, e2s, -e2s, -e1s
157+
X = ADI(A, B, pM, F, a, b, c, d, tol)
158+
159+
# X = UM
160+
U = (L' \ (L \ X'))'
161+
162+
u_exact = z -> ((x,y)= z; sin.(π*x)*sin.(π*y)*y^2)
163+
Ua = C[first.(z)[:,1], Block.(1:p)] * U * C[first.(z)[:,1], Block.(1:p)]'
164+
165+
norm(u_exact.(z) - Ua) # ℓ^∞ error.
166+

0 commit comments

Comments
 (0)