!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
module cubemain_fft_utils
  use cube_types
  use cubetools_parameters
  use cubemain_image_cplx
  !
  interface cubemain_fft_nan2zero
     module procedure cubemain_fft_image_nan2zero
     module procedure cubemain_fft_spectrum_nan2zero
  end interface cubemain_fft_nan2zero
  !
  public :: code_rdata,code_cdata
  public :: code_dire,code_inve
  public :: cubemain_fft_nextpow2,cubemain_fft_nan2zero
  public :: cubemain_fft_plunge,cubemain_fft_deplunge
  private
  !
  ! FFT codes
  integer(kind=code_k), parameter :: code_rdata =  0
  integer(kind=code_k), parameter :: code_cdata =  1
  integer(kind=code_k), parameter :: code_dire  = -1
  integer(kind=code_k), parameter :: code_inve  = +1
  !
contains
  !
  function cubemain_fft_nextpow2(input)
    !----------------------------------------------------------------------
    ! Computes next largest power 2
    !----------------------------------------------------------------------
    integer(kind=pixe_k), intent(in) :: input
    !
    integer(kind=pixe_k) :: cubemain_fft_nextpow2
    !
    cubemain_fft_nextpow2 = 2**(ceiling(log(1.0*input)/log(2.0)))
  end function cubemain_fft_nextpow2
  !
  subroutine cubemain_fft_image_nan2zero(nx,ny,image,error)
    use cubetools_nan
    use cubemain_image_real
    !----------------------------------------------------------------------
    ! This is costly but necessary
    !----------------------------------------------------------------------
    integer(kind=pixe_k), intent(in)    :: nx
    integer(kind=pixe_k), intent(in)    :: ny
    type(image_t),        intent(inout) :: image
    logical,              intent(inout) :: error
    !
    integer(kind=pixe_k) :: ix,iy
    !
    do iy=1,ny
       do ix=1,nx
          if (ieee_is_nan(image%z(ix,iy))) image%z(ix,iy) = 0.0
       enddo
    enddo
  end subroutine cubemain_fft_image_nan2zero
  !
  subroutine cubemain_fft_spectrum_nan2zero(nc,spectrum,error)
    use cubetools_nan
    use cubemain_spectrum_real
    !----------------------------------------------------------------------
    ! This is costly but necessary
    !----------------------------------------------------------------------
    integer(kind=chan_k), intent(in)    :: nc
    type(spectrum_t),     intent(inout) :: spectrum
    logical,              intent(inout) :: error
    !
    integer(kind=chan_k) :: ic
    !
    do ic=1,nc
       if (ieee_is_nan(spectrum%t(ic))) spectrum%t(ic) = 0.0
    enddo
  end subroutine cubemain_fft_spectrum_nan2zero
  !
  subroutine cubemain_fft_plunge(inx,iny,image,onx,ony,cimage,error)
    use cubetools_nan
    use cubemain_image_real
    !----------------------------------------------------------------------
    ! Plunges a real image into a previous allocated complex image twice
    ! the size to avoid aliasing. Flips nans into zeros on the fly
    ! ----------------------------------------------------------------------
    integer(kind=pixe_k), intent(in)    :: inx
    integer(kind=pixe_k), intent(in)    :: iny
    type(image_t),        intent(in)    :: image
    integer(kind=pixe_k), intent(in)    :: onx
    integer(kind=pixe_k), intent(in)    :: ony
    type(image_cplx_t),   intent(inout) :: cimage
    logical,              intent(inout) :: error
    !
    integer(kind=pixe_k) :: ix,iy,ix0,iy0
    !
    cimage%z = cmplx(0.0,0.0)
    !
    ix0 = onx/2-inx/2
    iy0 = ony/2-iny/2
    !
    do iy=1,iny
       do ix=1,inx
          if (ieee_is_nan(image%z(ix,iy))) then
             cimage%z(ix+ix0,iy+iy0) = cmplx(0.0,0.0)
          else
             cimage%z(ix+ix0,iy+iy0) = cmplx(image%z(ix,iy),0.)
          endif
       enddo
    enddo
  end subroutine cubemain_fft_plunge
  !
  subroutine cubemain_fft_deplunge(inx,iny,cimage,onx,ony,image,error)
    use cubemain_image_real
    !----------------------------------------------------------------------
    ! Deplunges and normalizes a real image from a complex image twice
    ! its size (reverse operation of cubemain_fft_plunge)
    ! ----------------------------------------------------------------------
    integer(kind=pixe_k), intent(in)    :: inx
    integer(kind=pixe_k), intent(in)    :: iny
    type(image_cplx_t),   intent(in)    :: cimage
    integer(kind=pixe_k), intent(in)    :: onx
    integer(kind=pixe_k), intent(in)    :: ony
    type(image_t),        intent(inout) :: image
    logical,              intent(inout) :: error
    !
    integer(kind=pixe_k) :: ix,iy,ix0,iy0
    real(kind=sign_k) :: weight
    !
    weight = 1.0/(inx*iny)
    ix0 = inx/2-onx/2
    iy0 = iny/2-ony/2
    !
    do iy=1,ony
       do ix=1,onx
          image%z(ix,iy) = real(cimage%z(ix+ix0,iy+iy0))*weight
       enddo
    enddo
  end subroutine cubemain_fft_deplunge
end module cubemain_fft_utils
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
