Abstract Interface for NFFTs
The package AbstractNFFTs provides the abstract interface for NFFT implementations. Defining an abstract interface has the advantage that different implementations can be used and exchanging requires  only small effort.
An overview about the current packages and their dependencies is shown in the following package tree:
If you are not an expert user, you likely do not require different NFFT implementations and we therefore recommend to just use NFFT.jl and not worry about the abstract interface. 
Implementations
Currently, there are four implementations of the AbstractNFFTs interface:
- NFFT.jl: This is the reference implementation running und the CPU.
- CuNFFT.jl: An implementation running on graphics hardware of Nvidia exploiting CUDA.jl
- NFFT3.jl: In the Wrapperdirectory ofNFFT.jlthere is a wrapper around theNFFT3.jlpackage following theAbstractNFFTsinterface.NFFT3.jlis itself a wrapper around the high performance C library NFFT3.
- FINUFFT.jl: In the Wrapperdirectory ofNFFT.jlthere is a wrapper around theFINUFFT.jlpackage.FINUFFT.jlis itself a wrapper around the high performance C++ library FINUFFT.
Right now one needs to install NFFT.jl and manually include the wrapper files. In the future we hope to integrate the wrappers in NFFT3.jl and FINUFFT.jl directly such that it is much more convenient to switch libraries.
Interface
An NFFT implementation needs to define a new type that is a subtype of AbstractNFFTPlan{T,D,R}. Here
- Tis the real-valued element type of the nodes, i.e. a transform operating on- Complex{Float64}values and- Float64nodes uses the type- T=Float64.
- Dis the size of the input vector
- Ris the size of the output vector. Usually this will be- R=1unless a directional NFFT is implemented.
For instance the CuNFFTPlan is defined like this
mutable struct CuNFFTPlan{T,D} <: AbstractNFFTPlan{T,D,1} 
  ...
endIn addition to the plan, the following functions need to be implemented:
size_out(p)
size_out(p)
mul!(fHat, p, f) -> fHat
mul!(f, p::Adjoint{Complex{T},<:AbstractNFFTPlan{T}}, fHat) -> f
nodes!(p, k) -> pAll these functions are exported from AbstractNFFTs and we recommend to implement them using the explicit AbstractNFFTs. prefix:
function AbstractNFFTs.size_out(p:MyNFFTPlan)
 ...
endWe next outline all of the aforementioned functions and describe their behavior:
    size_in(p)Size of the input array for an NFFT operation. The returned tuple has D entries.  Note that this will be the output array for an adjoint NFFT.
    size_out(p)Size of the output array for an NFFT operation. The returned tuple has R entries.  Note that this will be the input array for an adjoint NFFT.
    mul!(fHat, p, f) -> fHatInplace NFFT transforming the D dimensional array f to the R dimensional array fHat. The transformation is applied along D-R+1 dimensions specified in the plan p. Both f and fHat must be complex arrays of element type Complex{T}.
    mul!(f, p::Adjoint{Complex{T},<:AbstractNFFTPlan{T}}, fHat) -> fInplace adjoint NFFT transforming the R dimensional array fHat to the D dimensional array f. The transformation is applied along D-R+1 dimensions specified in the plan p. Both f and fHat must be complex arrays of element type Complex{T}.
    nodes!(p, k)Exchange the nodes k in the plan p and return the plan. The implementation of this function is optional.
Plan Interface
The constructor for a plan also has a defined interface. It should be implemented in this way:
function MyNFFTPlan(k::Matrix{T}, N::NTuple{D,Int}; kwargs...) where {T,D}
  ...
endAll parameters are put into keyword arguments that have to match as well. We describe the keyword arguments in more detail in the overview page. Using the same plan interface allows to load several NFFT libraries simultaneously and exchange the constructor dynamically by storing the constructor in a function object. This is how the unit tests of NFFT.jl run.
Additionally, to the type-specific constructor one can provide the factory
plan_nfft(Q::Type, k::Matrix{T}, N::NTuple{D,Int}; kargs...) where {D}where Q is the Array type, e.g. Array. The reason to require the array type is, that this allows for GPU implementations, which would use for instance CuArray here.
The package AbstractNFFTs provides a convenient constructor
plan_nfft(k::Matrix{T}, N::NTuple{D,Int}; kargs...) where {D}defaulting to the Array type.
Different packages implementing plan_nfft will conflict if the same Q is implemented. In case of NFFT.jl and CuNFFT.jl there is no conflict since the array type is different.
Derived Interface
Based on the core low-level interface that an AbstractNFFTPlan needs to provide, the package AbstractNFFT.jl also provides high-level functions like *, nfft, and nfft_adjoint, which internally use the low-level interface. Thus, the implementation of high-level function is shared among all AbstractNFFT.jl implementations.