|
| 1 | +module RFFT |
| 2 | + |
| 3 | +using FFTW, LinearAlgebra |
| 4 | + |
| 5 | +export RCpair, plan_rfft!, plan_irfft!, rfft!, irfft!, normalization |
| 6 | + |
| 7 | +import Base: real, complex, copy, copy! |
| 8 | + |
| 9 | +mutable struct RCpair{T<:AbstractFloat,N,RType<:AbstractArray{T,N},CType<:AbstractArray{Complex{T},N}} |
| 10 | + R::RType |
| 11 | + C::CType |
| 12 | + region::Vector{Int} |
| 13 | +end |
| 14 | + |
| 15 | +function RCpair{T}(::UndefInitializer, realsize::Dims{N}, region=1:length(realsize)) where {T<:AbstractFloat,N} |
| 16 | + sz = [realsize...] |
| 17 | + firstdim = region[1] |
| 18 | + sz[firstdim] = realsize[firstdim]>>1 + 1 |
| 19 | + sz2 = copy(sz) |
| 20 | + sz2[firstdim] *= 2 |
| 21 | + R = Array{T,N}(undef, (sz2...,)::Dims{N}) |
| 22 | + C = unsafe_wrap(Array, convert(Ptr{Complex{T}}, pointer(R)), (sz...,)::Dims{N}) # work around performance problems of reinterpretarray |
| 23 | + RCpair(view(R, map(n->1:n, realsize)...), C, [region...]) |
| 24 | +end |
| 25 | + |
| 26 | +RCpair(A::Array{T}, region=1:ndims(A)) where {T<:AbstractFloat} = copy!(RCpair{T}(undef, size(A), region), A) |
| 27 | + |
| 28 | +real(RC::RCpair) = RC.R |
| 29 | +complex(RC::RCpair) = RC.C |
| 30 | + |
| 31 | +copy!(RC::RCpair, A::AbstractArray{T}) where {T<:Real} = (copy!(RC.R, A); RC) |
| 32 | +function copy(RC::RCpair{T,N}) where {T,N} |
| 33 | + C = copy(RC.C) |
| 34 | + R = reshape(reinterpret(T, C), size(parent(RC.R))) |
| 35 | + RCpair(view(R, RC.R.indices...), C, copy(RC.region)) |
| 36 | +end |
| 37 | + |
| 38 | +# New API |
| 39 | +rplan_fwd(R, C, region, flags, tlim) = |
| 40 | + FFTW.rFFTWPlan{eltype(R),FFTW.FORWARD,true,ndims(R)}(R, C, region, flags, tlim) |
| 41 | +rplan_inv(R, C, region, flags, tlim) = |
| 42 | + FFTW.rFFTWPlan{eltype(R),FFTW.BACKWARD,true,ndims(R)}(R, C, region, flags, tlim) |
| 43 | +function plan_rfft!(RC::RCpair{T}; flags::Integer = FFTW.ESTIMATE, timelimit::Real = FFTW.NO_TIMELIMIT) where T |
| 44 | + p = rplan_fwd(RC.R, RC.C, RC.region, flags, timelimit) |
| 45 | + return Z::RCpair -> begin |
| 46 | + FFTW.assert_applicable(p, Z.R, Z.C) |
| 47 | + FFTW.unsafe_execute!(p, Z.R, Z.C) |
| 48 | + return Z |
| 49 | + end |
| 50 | +end |
| 51 | +function plan_irfft!(RC::RCpair{T}; flags::Integer = FFTW.ESTIMATE, timelimit::Real = FFTW.NO_TIMELIMIT) where T |
| 52 | + p = rplan_inv(RC.C, RC.R, RC.region, flags, timelimit) |
| 53 | + return Z::RCpair -> begin |
| 54 | + FFTW.assert_applicable(p, Z.C, Z.R) |
| 55 | + FFTW.unsafe_execute!(p, Z.C, Z.R) |
| 56 | + rmul!(Z.R, 1 / prod(size(Z.R)[Z.region])) |
| 57 | + return Z |
| 58 | + end |
| 59 | +end |
| 60 | +function rfft!(RC::RCpair{T}) where T |
| 61 | + p = rplan_fwd(RC.R, RC.C, RC.region, FFTW.ESTIMATE, FFTW.NO_TIMELIMIT) |
| 62 | + FFTW.unsafe_execute!(p, RC.R, RC.C) |
| 63 | + return RC |
| 64 | +end |
| 65 | +function irfft!(RC::RCpair{T}) where T |
| 66 | + p = rplan_inv(RC.C, RC.R, RC.region, FFTW.ESTIMATE, FFTW.NO_TIMELIMIT) |
| 67 | + FFTW.unsafe_execute!(p, RC.C, RC.R) |
| 68 | + rmul!(RC.R, 1 / prod(size(RC.R)[RC.region])) |
| 69 | + return RC |
| 70 | +end |
| 71 | + |
| 72 | +@deprecate RCpair(realtype::Type{T}, realsize, region=1:length(realsize)) where T<:AbstractFloat RCpair{T}(undef, realsize, region) |
| 73 | + |
| 74 | +end |
0 commit comments