-
Notifications
You must be signed in to change notification settings - Fork 5
/
midterm.jl
133 lines (106 loc) · 3.21 KB
/
midterm.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
using PyPlot
using LinearAlgebra
using SparseArrays
using IterativeSolvers
function laplacian(D)
n = length(D)
return (n+1)^2 .* spdiagm(
-1 => D[2:end-1],
0 => .-(D[1:end-1] .+ D[2:end]),
1 => D[2:end-1],
)
end
function example()
# Specify the problem parameters
n = 100
D = x -> ifelse(x < 0.5, 0.1, 1.0)
f = x -> 1.0
# Assemble the linear system
x = LinRange(0,1,n+2)[2:end-1]
m = LinRange(0,1,2n+3)[2:2:end-1]
Δ = laplacian(D.(m))
u = -Δ\f.(x)
# Plot the solution
clf()
plot([0;x;1], [0;u;0])
xlabel(L"x")
ylabel(L"u(x)")
display(gcf())
end
function n_iterations()
D = x -> ifelse(x < 0.5, 0.1, 1.0)
f = x -> 1.0
n = round.(Int, 10.0.^LinRange(0,4,10))
error = [begin
x = LinRange(0,1,n+2)[2:end-1]
m = LinRange(0,1,2n+3)[2:2:end-1]
Δ = laplacian(D.(m))
_,hist = cg(-Δ,f.(x), log=true)
hist.iters
end for n in n]
clf()
loglog(n, error, "-o", label="# CG iterations")
loglog(n, 1.5e0.*n, "k--", label=L"O(n)")
xlabel(L"# grid points $n$")
# ylabel("# CG iterations")
legend()
display(gcf())
end
###############################################################################
# WARNING: The following code uses advanced Julia features. You are not
# expected to understand the details of how this code works, but you are
# welcome to ask me questions in case you would like to know more.
struct FourierPreconditioner{DST,Diag,iDST}
V::DST
iD::Diag
Vt::iDST
end
using FFTW
function FourierPreconditioner(n)
# Eigenector matrix and its inverse == transpose
u = zeros(n)
V = FFTW.plan_r2r(u, FFTW.RODFT00)
Vt = inv(V)
# Inverse of eigenvalue matrix
iD = Diagonal(@.( inv(2*(n+1)^2*(1 - cos(π*(1:n)/(n+1))))))
# Assemble `FourierPreconditioner` object
return FourierPreconditioner(V,iD,Vt)
end
function LinearAlgebra.ldiv!(v,P::FourierPreconditioner,u)
# Extract matrices from `FourierPreconditioner` object
V = P.V
iD = P.iD
Vt = P.Vt
# Apply preconditioner to `u` and store result in `v`
return v .= V*(iD*(Vt*u))
end
# End of advanced Julia code
###############################################################################
function fourier_preconditioning()
fig = figure(figsize=(8,6))
for (i,ε) in enumerate(10.0.^.-(0:3))
# Specify the problem parameters
n = 50
D = x -> 1-4*(1-ε)*x*(1-x)
f = x -> x^2 #1.0 #(x-0.5)^2
# Assemble the linear system
x = LinRange(0,1,n+2)[2:end-1]
m = LinRange(0,1,2n+3)[2:2:end-1]
A = -laplacian(D.(m))
b = f.(x)
# Plot convergence histories
subplot(2,2,i)
_,hist = cg(A,b, log=true)
semilogy([norm(b); hist[:resnorm]], label="no preconditioning")
_,hist = cg(A,b, Pl=FourierPreconditioner(n), log=true)
semilogy([norm(b); hist[:resnorm]], label="Fourier preconditioning")
title(latexstring("\\varepsilon = $ε"))
xlabel("Number of iterations")
ylabel("CG residual")
ylim(1e-6,1e2)
if i == 4; legend(loc="lower right"); end
end
tight_layout(pad=3.0)
display(gcf())
close(fig)
end