Skip to content

Commit ac1dfb6

Browse files
authored
Add files via upload
1 parent b207ec0 commit ac1dfb6

File tree

1 file changed

+172
-0
lines changed

1 file changed

+172
-0
lines changed

src/helmholtzhodge.jl

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
include("gradient.jl")
2+
3+
using BandedMatrices
4+
5+
import BandedMatrices: BandedQ
6+
7+
# Store QR factorizations required to apply the Helmholtz-Hodge decomposition.
8+
struct HelmholtzHodge{T}
9+
Q::Vector{BandedQ{T}}
10+
R::Vector{BandedMatrix{T, Matrix{T}}}
11+
X::Vector{T}
12+
end
13+
14+
function HelmholtzHodge(::Type{T}, N::Int) where T
15+
Q = Vector{BandedQ{T}}(N)
16+
R = Vector{BandedMatrix{T, Matrix{T}}}(N)
17+
for m = 1:N
18+
Q[m], R[m] = qr(helmholtzhodgeconversion(T, N, m))
19+
end
20+
HelmholtzHodge(Q, R, zeros(T, 2N+2))
21+
end
22+
23+
function helmholtzhodgeconversion(::Type{T}, N::Int, m::Int) where T
24+
A = BandedMatrix(Zeros{T}(2N+4-2m, 2N+2-2m), (2, 2))
25+
for= 1:N+1-m
26+
A[2ℓ, 2-1] = m
27+
A[2-1, 2ℓ] = m
28+
cst = (m+-1)*sqrt(T(ℓ*(ℓ+2m))/T((2+2m-1)*(2+2m+1)))
29+
A[2+2, 2ℓ] = cst
30+
A[2+1, 2-1] = cst
31+
end
32+
for= 1:N-m
33+
cst = -(m++1)*sqrt(T(ℓ*(ℓ+2m))/T((2+2m-1)*(2+2m+1)))
34+
A[2-1, 2+1] = cst
35+
A[2ℓ, 2+2] = cst
36+
end
37+
A
38+
end
39+
40+
# This function works in-place on the data stored in the factorization.
41+
function solvehelmholtzhodge!(HH::HelmholtzHodge{T}, m::Int) where T
42+
Q = HH.Q[m]
43+
R = HH.R[m]
44+
X = HH.X
45+
46+
# Step 1: apply Q'
47+
48+
H=Q.H
49+
m=Q.m
50+
51+
M=size(H,1)
52+
x=pointer(X)
53+
h=pointer(H)
54+
st=stride(H,2)
55+
sz=sizeof(T)
56+
57+
for k=1:min(size(H,2),m-M+1)
58+
wp=h+sz*st*(k-1)
59+
xp=x+sz*(k-1)
60+
61+
dt=BandedMatrices.dot(M,wp,1,xp,1)
62+
BandedMatrices.axpy!(M,-2*dt,wp,1,xp,1)
63+
end
64+
65+
for k=m-M+2:size(H,2)
66+
p=k-m+M-1
67+
68+
wp=h+sz*st*(k-1)
69+
xp=x+sz*(k-1)
70+
71+
dt=BandedMatrices.dot(M-p,wp,1,xp,1)
72+
BandedMatrices.axpy!(M-p,-2*dt,wp,1,xp,1)
73+
end
74+
75+
# Step 2: backsolve with (square) R
76+
77+
BandedMatrices.tbsv!('U', 'N', 'N', size(R.data, 2), R.u, pointer(R.data), size(R.data, 1), pointer(X), 1)
78+
79+
X
80+
end
81+
82+
83+
function helmholtzhodge!(HH::HelmholtzHodge{T}, U1, U2, V1, V2) where T
84+
N, M = size(V1)
85+
86+
# U1 is for e_theta and U2 is for e_phi.
87+
# The first columns are easy.
88+
U1[1, 1] = 0
89+
U2[1, 1] = 0
90+
@inbounds @simd for= 1:N-1
91+
U1[ℓ+1, 1] = -V1[ℓ, 1]/sqrt(T(ℓ*(ℓ+1)))
92+
U2[ℓ+1, 1] = -V2[ℓ, 1]/sqrt(T(ℓ*(ℓ+1)))
93+
end
94+
95+
# First, we multiply by sin(θ), which can be done by incrementing the order P_ℓ^{m-1} ↗ P_ℓ^m.
96+
@inbounds for m = 1:M÷2
97+
@simd for= 1:N-1-m
98+
aℓ = sqrt(T((ℓ+2m-2)*(ℓ+2m-1))/T((2+2m-3)*(2+2m-1)))
99+
bℓ = -sqrt(T(ℓ*(ℓ+1))/T((2+2m-1)*(2+2m+1)))
100+
V1[ℓ, 2m] = aℓ*V1[ℓ, 2m] + bℓ*V1[ℓ+2, 2m]
101+
V1[ℓ, 2m+1] = aℓ*V1[ℓ, 2m+1] + bℓ*V1[ℓ+2, 2m+1]
102+
V2[ℓ, 2m] = aℓ*V2[ℓ, 2m] + bℓ*V2[ℓ+2, 2m]
103+
V2[ℓ, 2m+1] = aℓ*V2[ℓ, 2m+1] + bℓ*V2[ℓ+2, 2m+1]
104+
end
105+
= N-m
106+
if> 0
107+
aℓ = sqrt(T((ℓ+2m-2)*(ℓ+2m-1))/T((2+2m-3)*(2+2m-1)))
108+
V1[ℓ, 2m] = aℓ*V1[ℓ, 2m]
109+
V1[ℓ, 2m+1] = aℓ*V1[ℓ, 2m+1]
110+
V2[ℓ, 2m] = aℓ*V2[ℓ, 2m]
111+
V2[ℓ, 2m+1] = aℓ*V2[ℓ, 2m+1]
112+
end
113+
= N+1-m
114+
aℓ = sqrt(T((ℓ+2m-2)*(ℓ+2m-1))/T((2+2m-3)*(2+2m-1)))
115+
V1[ℓ, 2m] = aℓ*V1[ℓ, 2m]
116+
V1[ℓ, 2m+1] = aℓ*V1[ℓ, 2m+1]
117+
V2[ℓ, 2m] = aℓ*V2[ℓ, 2m]
118+
V2[ℓ, 2m+1] = aℓ*V2[ℓ, 2m+1]
119+
end
120+
121+
# Next, we solve the banded linear systems.
122+
for m = 1:M÷2
123+
readin1!(HH.X, V1, V2, N, m)
124+
solvehelmholtzhodge!(HH, m)
125+
writeout1!(HH.X, U1, U2, N, m)
126+
readin2!(HH.X, V1, V2, N, m)
127+
solvehelmholtzhodge!(HH, m)
128+
writeout2!(HH.X, U1, U2, N, m)
129+
end
130+
131+
U1
132+
end
133+
134+
function readin1!(X, V1, V2, N, m)
135+
X[1] = V1[1, 2m]
136+
X[2N+2-2m] = V2[N+1-m, 2m+1]
137+
@inbounds for= 1:N-m
138+
X[2ℓ] = V2[ℓ, 2m+1]
139+
X[2+1] = V1[ℓ+1, 2m]
140+
end
141+
X[2N+3-2m] = X[2N+4-2m] = 0
142+
end
143+
144+
function readin2!(X, V1, V2, N, m)
145+
X[1] = V1[1, 2m+1]
146+
X[2N+2-2m] = -V2[N+1-m, 2m]
147+
@inbounds for= 1:N-m
148+
X[2ℓ] = -V2[ℓ, 2m]
149+
X[2+1] = V1[ℓ+1, 2m+1]
150+
end
151+
X[2N+3-2m] = X[2N+4-2m] = 0
152+
end
153+
154+
function writeout1!(X, U1, U2, N, m)
155+
U1[1, 2m] = X[1]
156+
U2[1, 2m+1] = X[N+1-m]
157+
@inbounds for= 1:N-1-m
158+
U1[ℓ+1, 2m] = X[2+1]
159+
U2[ℓ, 2m+1] = X[2ℓ]
160+
end
161+
U2[N-m, 2m+1] = X[2N-2m]
162+
end
163+
164+
function writeout2!(X, U1, U2, N, m)
165+
U1[1, 2m+1] = X[1]
166+
U2[1, 2m] = X[N+1-m]
167+
@inbounds for= 1:N-1-m
168+
U1[ℓ+1, 2m+1] = X[2+1]
169+
U2[ℓ, 2m] = -X[2ℓ]
170+
end
171+
U2[N-m, 2m] = -X[2N-2m]
172+
end

0 commit comments

Comments
 (0)