Skip to content

Commit 012dc4c

Browse files
authored
Merge pull request #19 from JuliaImageRecon/nh/nonuniformFFTs
Adapt NFFTOp to work with NonuniformFFTs.jl
2 parents 687f0fe + 774bed8 commit 012dc4c

File tree

6 files changed

+76
-16
lines changed

6 files changed

+76
-16
lines changed

Project.toml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ Reexport = "189a3867-3050-52da-a836-e630ba90ab69"
1414
[extras]
1515
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
1616
JLArrays = "27aeb0d3-9eb9-45fb-866b-73c2ecf80fcb"
17+
NonuniformFFTs = "cd96f58b-6017-4a02-bb9e-f4d81626177f"
1718
NFFT = "efe261a4-0d2b-5849-be55-fc731d526b0d"
1819
Wavelets = "29a6e085-ba6d-5f35-a997-948ac2efa89a"
1920
FFTW = "7a1cc6ca-52ef-59f5-83cd-3a7055c09341"
@@ -26,6 +27,8 @@ KernelAbstractions = "0.9"
2627
JLArrays = "0.2"
2728
AbstractNFFTs = "0.9"
2829
LinearOperators = "2"
30+
NonuniformFFTs = "0.9"
31+
NFFT = "0.14"
2932
RadonKA = "0.6"
3033
Wavelets = "0.9, 0.10"
3134
Reexport = "1.0"
@@ -36,15 +39,17 @@ AbstractNFFTs = "7f219486-4aa7-41d6-80a7-e08ef20ceed7"
3639
GPUArrays = "0c68f7d7-f131-5f86-a1c3-88cf8149b2d7"
3740
KernelAbstractions = "63c18a36-062a-441e-b654-da1e3ab1ce7c"
3841
NFFT = "efe261a4-0d2b-5849-be55-fc731d526b0d"
42+
NonuniformFFTs = "cd96f58b-6017-4a02-bb9e-f4d81626177f"
3943
Wavelets = "29a6e085-ba6d-5f35-a997-948ac2efa89a"
4044
FFTW = "7a1cc6ca-52ef-59f5-83cd-3a7055c09341"
4145
RadonKA = "86de8297-835b-47df-b249-c04e8db91db5"
4246

4347
[targets]
44-
test = ["Test", "FFTW", "Wavelets", "NFFT", "JLArrays", "RadonKA"]
48+
test = ["Test", "FFTW", "Wavelets", "NFFT", "NonuniformFFTs", "JLArrays", "RadonKA"]
4549

4650
[extensions]
4751
LinearOperatorNFFTExt = ["AbstractNFFTs", "FFTW"]
52+
LinearOperatorNonuniformFFTsExt = ["AbstractNFFTs", "NonuniformFFTs", "FFTW"]
4853
LinearOperatorFFTWExt = "FFTW"
4954
LinearOperatorWaveletExt = "Wavelets"
5055
LinearOperatorGPUArraysExt = "GPUArrays"

ext/LinearOperatorNFFTExt/NFFTOp.jl

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ function LinearOperatorCollection.NFFTOp(::Type{T};
1919
return NFFTOpImpl(shape, nodes; toeplitz, oversamplingFactor, kernelSize, kargs... )
2020
end
2121

22-
mutable struct NFFTOpImpl{T, vecT, P <: AbstractNFFTPlan} <: NFFTOp{T}
22+
mutable struct NFFTOpImpl{T, vecT, P} <: NFFTOp{T, P}
2323
nrow :: Int
2424
ncol :: Int
2525
symmetric :: Bool
@@ -56,17 +56,17 @@ function NFFTOpImpl(shape::Tuple, tr::AbstractMatrix{T}; toeplitz, oversamplingF
5656
end
5757

5858
function produ!(y::AbstractVector, plan::AbstractNFFTPlan, x::AbstractVector)
59-
mul!(y, plan, reshape(x,plan.N))
59+
mul!(y, plan, reshape(x,size_in(plan)))
6060
end
6161

6262
function ctprodu!(x::AbstractVector, plan::AbstractNFFTPlan, y::AbstractVector)
63-
mul!(reshape(x, plan.N), adjoint(plan), y)
63+
mul!(reshape(x, size_in(plan)), adjoint(plan), y)
6464
end
6565

6666

6767
function Base.copy(S::NFFTOpImpl{T, vecT, P}) where {T, vecT, P}
6868
plan = copy(S.plan)
69-
return NFFTOpImpl{T, vecT, P}(size(plan.k,2), prod(plan.N), false, false
69+
return NFFTOpImpl{T, vecT, P}(size(plan.k,2), prod(size_in(plan)), false, false
7070
, (res,x) -> produ!(res,plan,x)
7171
, nothing
7272
, (res,y) -> ctprodu!(res,plan,y)
@@ -107,7 +107,7 @@ end
107107

108108
LinearOperators.storage_type(op::NFFTToeplitzNormalOp) = typeof(op.Mv5)
109109

110-
function NFFTToeplitzNormalOp(shape, W, fftplan, ifftplan, λ, xL1::matT, xL2::matT) where {T, D, matT <: AbstractArray{T, D}}
110+
function LinearOperatorCollection.NFFTToeplitzNormalOp(shape, W, fftplan, ifftplan, λ, xL1::matT, xL2::matT) where {T, D, matT <: AbstractArray{T, D}}
111111

112112
function produ!(y, shape, fftplan, ifftplan, λ, xL1, xL2, x)
113113
xL1 .= 0
@@ -130,8 +130,8 @@ function NFFTToeplitzNormalOp(shape, W, fftplan, ifftplan, λ, xL1::matT, xL2::m
130130
, shape, W, fftplan, ifftplan, λ, xL1, xL2)
131131
end
132132

133-
function NFFTToeplitzNormalOp(nfft::NFFTOp{T}, W=nothing; kwargs...) where {T}
134-
shape = nfft.plan.N
133+
function LinearOperatorCollection.NFFTToeplitzNormalOp(nfft::NFFTOp{T}, W=nothing; kwargs...) where {T}
134+
shape = size_in(nfft.plan)
135135

136136
tmpVec = similar(nfft.Mv5, (2 .* shape)...)
137137
tmpVec .= zero(T)
@@ -161,12 +161,12 @@ function NFFTToeplitzNormalOp(nfft::NFFTOp{T}, W=nothing; kwargs...) where {T}
161161
xL1 = tmpVec
162162
xL2 = similar(xL1)
163163

164-
return NFFTToeplitzNormalOp(shape, W, fftplan, ifftplan, λ, xL1, xL2)
164+
return LinearOperatorCollection.NFFTToeplitzNormalOp(shape, W, fftplan, ifftplan, λ, xL1, xL2)
165165
end
166166

167167
function LinearOperatorCollection.normalOperator(S::NFFTOpImpl{T}, W = nothing; copyOpsFn = copy, kwargs...) where T
168168
if S.toeplitz
169-
return NFFTToeplitzNormalOp(S,W; kwargs...)
169+
return LinearOperatorCollection.NFFTToeplitzNormalOp(S,W; kwargs...)
170170
else
171171
return NormalOp(eltype(S); parent = S, weights = W)
172172
end
@@ -175,5 +175,5 @@ end
175175
function Base.copy(A::NFFTToeplitzNormalOp{T,D,W}) where {T,D,W}
176176
fftplan = plan_fft( zeros(T, 2 .* A.shape); flags=FFTW.MEASURE)
177177
ifftplan = plan_ifft(zeros(T, 2 .* A.shape); flags=FFTW.MEASURE)
178-
return NFFTToeplitzNormalOp(A.shape, A.weights, fftplan, ifftplan, A.λ, copy(A.xL1), copy(A.xL2))
178+
return LinearOperatorCollection.NFFTToeplitzNormalOp(A.shape, A.weights, fftplan, ifftplan, A.λ, copy(A.xL1), copy(A.xL2))
179179
end
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
module LinearOperatorNonuniformFFTsExt
2+
3+
using LinearOperatorCollection, AbstractNFFTs, NonuniformFFTs, NonuniformFFTs.Kernels, FFTW
4+
5+
function LinearOperatorCollection.NFFTToeplitzNormalOp(nfft::NFFTOp{T, P}, W=nothing; kwargs...) where {T, vecT, P <: NonuniformFFTs.NFFTPlan}
6+
shape = size_in(nfft.plan)
7+
8+
tmpVec = similar(nfft.Mv5, (2 .* shape)...)
9+
tmpVec .= zero(T)
10+
11+
# plan the FFTs
12+
fftplan = plan_fft(tmpVec; kwargs...)
13+
ifftplan = plan_ifft(tmpVec; kwargs...)
14+
15+
# TODO extend the following function by weights
16+
# λ = calculateToeplitzKernel(shape, nfft.plan.k; m = nfft.plan.params.m, σ = nfft.plan.params.σ, window = nfft.plan.params.window, LUTSize = nfft.plan.params.LUTSize, fftplan = fftplan)
17+
18+
shape_os = 2 .* shape
19+
baseArrayType = Base.typename(typeof(tmpVec)).wrapper # https://github.com/JuliaLang/julia/issues/35543
20+
21+
nufft = nfft.plan.p
22+
σ = nufft.σ
23+
m = Kernels.half_support(first(nufft.kernels))
24+
k = stack(nufft.points, dims = 1)
25+
26+
p = plan_nfft(baseArrayType, k, shape_os; m = m, σ = σ,
27+
precompute=AbstractNFFTs.POLYNOMIAL, fftflags=FFTW.ESTIMATE, blocking=true)
28+
tmpOnes = similar(tmpVec, size(k, 2))
29+
tmpOnes .= one(T)
30+
31+
if !isnothing(W)
32+
eigMat = adjoint(p) * ( W * tmpOnes)
33+
else
34+
eigMat = adjoint(p) * (tmpOnes)
35+
end
36+
37+
λ = fftplan * fftshift(eigMat)
38+
39+
xL1 = tmpVec
40+
xL2 = similar(xL1)
41+
42+
return LinearOperatorCollection.NFFTToeplitzNormalOp(shape, W, fftplan, ifftplan, λ, xL1, xL2)
43+
end
44+
45+
46+
end

src/LinearOperatorCollection.jl

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,20 +30,22 @@ end
3030

3131
export linearOperatorList, createLinearOperator
3232
export AbstractLinearOperatorFromCollection, WaveletOp, FFTOp, DCTOp, DSTOp, NFFTOp,
33-
SamplingOp, NormalOp, WeightingOp, GradientOp, RadonOp
33+
SamplingOp, NormalOp, WeightingOp, GradientOp, RadonOp, NFFTToeplitzNormalOp
3434

3535
abstract type AbstractLinearOperatorFromCollection{T} <: AbstractLinearOperator{T} end
3636
abstract type WaveletOp{T} <: AbstractLinearOperatorFromCollection{T} end
3737
abstract type FFTOp{T} <: AbstractLinearOperatorFromCollection{T} end
3838
abstract type DCTOp{T} <: AbstractLinearOperatorFromCollection{T} end
3939
abstract type DSTOp{T} <: AbstractLinearOperatorFromCollection{T} end
40-
abstract type NFFTOp{T} <: AbstractLinearOperatorFromCollection{T} end
40+
abstract type NFFTOp{T, P} <: AbstractLinearOperatorFromCollection{T} end
4141
abstract type SamplingOp{T} <: AbstractLinearOperatorFromCollection{T} end
4242
abstract type NormalOp{T,S} <: AbstractLinearOperatorFromCollection{T} end
4343
abstract type GradientOp{T} <: AbstractLinearOperatorFromCollection{T} end
4444
abstract type RadonOp{T} <: AbstractLinearOperatorFromCollection{T} end
4545

4646

47+
function NFFTToeplitzNormalOp end
48+
4749
"""
4850
returns a list of currently implemented `LinearOperator`s
4951
"""

test/runtests.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ using Random
44
using LinearAlgebra
55
using FFTW
66
using Wavelets
7+
using NonuniformFFTs
78
using NFFT
89
using RadonKA
910
using JLArrays

test/testOperators.jl

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -440,9 +440,15 @@ end
440440
@info "test WaveletOp: $arrayType"
441441
@testset testWavelet(64,64;arrayType)
442442
@testset testWavelet(64,60;arrayType)
443-
@info "test NFFTOp: $arrayType"
444-
arrayType == JLArray || @testset testNFFT2d(;arrayType) # JLArray does not have a NFFTPlan
445-
arrayType == JLArray || @testset testNFFT3d(;arrayType) # JLArray does not have a NFFTPlan
443+
for backend in [NFFT.backend(), NonuniformFFTs.backend()]
444+
@info "test NFFTOp with $(string(typeof(backend))): $arrayType"
445+
@testset "NFFTOp with $(string(typeof(backend)))" begin
446+
with(nfft_backend => backend) do
447+
arrayType == JLArray || @testset testNFFT2d(;arrayType) # JLArray does not have a NFFTPlan
448+
arrayType == JLArray || @testset testNFFT3d(;arrayType) # JLArray does not have a NFFTPlan
449+
end
450+
end
451+
end
446452
@info "test DiagOp: $arrayType"
447453
@testset testDiagOp(;arrayType)
448454
@info "test RadonOp: $arrayType"

0 commit comments

Comments
 (0)