-
Notifications
You must be signed in to change notification settings - Fork 27
Expand file tree
/
Copy pathclassical.jl
More file actions
183 lines (161 loc) · 5.29 KB
/
classical.jl
File metadata and controls
183 lines (161 loc) · 5.29 KB
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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
function ruge_stuben(_A::Union{TA, Symmetric{Ti, TA}, Hermitian{Ti, TA}},
::Type{Val{bs}}=Val{1};
strength = Classical(0.25),
CF = RS(),
presmoother = GaussSeidel(),
postsmoother = GaussSeidel(),
max_levels = 10,
max_coarse = 10,
coarse_solver = BackslashSolver, kwargs...) where {Ti,Tv,bs,TA<:SparseMatrixCSC{Ti,Tv}}
# fails if near null space `B` is provided
haskey(kwargs, :B) && kwargs[:B] !== nothing && error("near null space `B` is only supported for smoothed aggregation AMG, not Ruge-Stüben AMG.")
if _A isa Symmetric && Ti <: Real || _A isa Hermitian
A = _A.data
symmetric = true
levels = Vector{Level{TA, Adjoint{Ti, TA}, TA}}()
else
symmetric = false
A = _A
levels = Vector{Level{TA, Adjoint{Ti, TA}, TA}}()
end
w = MultiLevelWorkspace(Val{bs}, eltype(A))
residual!(w, size(A, 1))
while length(levels) + 1 < max_levels && size(A, 1) > max_coarse
A = extend_heirarchy!(levels, strength, CF, A, symmetric)
coarse_x!(w, size(A, 1))
coarse_b!(w, size(A, 1))
residual!(w, size(A, 1))
end
MultiLevel(levels, A, coarse_solver(A), presmoother, postsmoother, w)
end
function extend_heirarchy!(levels, strength, CF, A::SparseMatrixCSC{Ti,Tv}, symmetric) where {Ti,Tv}
if symmetric
At = A
else
At = adjoint(A)
end
S, T = strength(At)
splitting = CF(S)
P, R = direct_interpolation(At, T, splitting)
push!(levels, Level(A, P, R))
return R * A * P
end
function direct_interpolation(At, T, splitting)
T = typeof(At)(T)
fill!(T.nzval, eltype(At)(1))
T .= At .* T
Pp = rs_direct_interpolation_pass1(T, splitting)
Px, Pj, Pp = rs_direct_interpolation_pass2(At, T, splitting, Pp)
R = SparseMatrixCSC(isempty(Pj) ? 0 : maximum(Pj), size(At, 1), Pp, Pj, Px)
P = R'
P, R
end
# calculates the number of nonzeros in each column of the interpolation matrix
function rs_direct_interpolation_pass1(T, splitting)
n = size(T, 2)
Bp = ones(Int, n+1)
nnzplus1 = 1
for i = 1:n
if splitting[i] == C_NODE
nnzplus1 += 1
else
for j in nzrange(T, i)
row = T.rowval[j]
if splitting[row] == C_NODE
nnzplus1 += 1
end
end
end
Bp[i+1] = nnzplus1
end
Bp
end
function rs_direct_interpolation_pass2(At::SparseMatrixCSC{Tv,Ti},
T::SparseMatrixCSC{Tv, Ti},
splitting::Vector{Ti},
Bp::Vector{Ti}) where {Tv,Ti}
Bx = zeros(Tv, Bp[end] - 1)
Bj = zeros(Ti, Bp[end] - 1)
n = size(At, 1)
for i = 1:n
if splitting[i] == C_NODE
Bj[Bp[i]] = i
Bx[Bp[i]] = 1
else
sum_strong_pos = zero(Tv)
sum_strong_neg = zero(Tv)
for j in nzrange(T, i)
row = T.rowval[j]
sval = T.nzval[j]
if splitting[row] == C_NODE
if real(sval) < 0
sum_strong_neg += sval
else
sum_strong_pos += sval
end
end
end
sum_all_pos = zero(Tv)
sum_all_neg = zero(Tv)
diag = zero(Tv)
for j in nzrange(At, i)
row = At.rowval[j]
aval = At.nzval[j]
if row == i
diag += aval
else
if real(aval) < 0
sum_all_neg += aval
else
sum_all_pos += aval
end
end
end
if sum_strong_pos == 0
beta = zero(diag)
if real(diag) >= 0
diag += sum_all_pos
end
else
beta = sum_all_pos / sum_strong_pos
end
if sum_strong_neg == 0
alpha = zero(diag)
if real(diag) < 0
diag += sum_all_neg
end
else
alpha = sum_all_neg / sum_strong_neg
end
if isapprox(real(diag), 0, atol=eps(real(Tv)))
neg_coeff = Tv(0)
pos_coeff = Tv(0)
else
neg_coeff = alpha / diag
pos_coeff = beta / diag
end
nnz = Bp[i]
for j in nzrange(T, i)
row = T.rowval[j]
sval = T.nzval[j]
if splitting[row] == C_NODE
Bj[nnz] = row
if real(sval) < 0
Bx[nnz] = abs(neg_coeff * sval)
else
Bx[nnz] = abs(pos_coeff * sval)
end
nnz += 1
end
end
end
end
m = zeros(Ti, n)
sum = zero(Ti)
for i = 1:n
m[i] = sum
sum += splitting[i]
end
Bj .= m[Bj] .+ 1
Bx, Bj, Bp
end