!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! !! !! GNU General Public License !! !! !! !! This file is part of the Flexible Modeling System (FMS). !! !! !! !! FMS is free software; you can redistribute it and/or modify !! !! it and are expected to follow the terms of the GNU General Public !! !! License as published by the Free Software Foundation. !! !! !! !! FMS is distributed in the hope that it will be useful, !! !! but WITHOUT ANY WARRANTY; without even the implied warranty of !! !! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the !! !! GNU General Public License for more details. !! !! !! !! You should have received a copy of the GNU General Public License !! !! along with FMS; if not, write to: !! !! Free Software Foundation, Inc. !! !! 59 Temple Place, Suite 330 !! !! Boston, MA 02111-1307 USA !! !! or see: !! !! http://www.gnu.org/licenses/gpl.txt !! !! !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! module fft_mod ! ! Bruce Wyman ! ! ! ! Performs simultaneous fast Fourier transforms (FFTs) between ! real grid space and complex Fourier space. ! ! ! This routine computes multiple 1-dimensional FFTs and inverse FFTs. ! There are 2d and 3d versions between type real grid point space ! and type complex Fourier space. There are single (32-bit) and ! full (64-bit) versions. ! ! On Cray and SGI systems, vendor-specific scientific library ! routines are used, otherwise a user may choose a NAG library version ! or stand-alone version using Temperton's FFT. ! !----------------------------------------------------------------------- !these are used to determine hardware/OS/compiler #ifdef __sgi # ifdef _COMPILER_VERSION !the MIPSPro compiler defines _COMPILER_VERSION # define sgi_mipspro # else # define sgi_generic # endif #endif !fft uses the SCILIB on SGICRAY, and the NAG library otherwise #if defined(_CRAY) || defined(sgi_mipspro) # define SGICRAY #endif use platform_mod, only: R8_KIND, R4_KIND use fms_mod, only: write_version_number, & error_mesg, FATAL #ifndef SGICRAY #ifndef NAGFFT use fft99_mod, only: fft991, set99 #endif #endif implicit none private !----------------- interfaces -------------------- public :: fft_init, fft_end, fft_grid_to_fourier, fft_fourier_to_grid ! ! ! Given multiple sequences of real data values, this routine ! computes the complex Fourier transform for all sequences. ! ! ! Given multiple sequences of real data values, this routine ! computes the complex Fourier transform for all sequences. ! ! ! ! Multiple sequence of real data values. The first dimension ! must be n+1 (where n is the size of a single sequence). ! ! ! Multiple sequences of transformed data in complex Fourier space. ! The first dimension must equal n/2+1 (where n is the size ! of a single sequence). The remaining dimensions must be the ! same size as the input argument "grid". ! ! ! The complex Fourier components are passed in the following format. !
!        fourier (1)     = cmplx ( a(0), b(0) )
!        fourier (2)     = cmplx ( a(1), b(1) )
!            :              :
!            :              :
!        fourier (n/2+1) = cmplx ( a(n/2), b(n/2) )
!     
! where n = length of each real transform !
! ! The initialization routine fft_init must be called before routines ! fft_grid_to_fourier. ! ! ! The real grid point field must have a first dimension equal to n+1 ! (where n is the size of each real transform). This message occurs ! when using the SGI/Cray fft. ! ! ! The real grid point field must have a first dimension equal to n ! (where n is the size of each real transform). This message occurs ! when using the NAG or Temperton fft. ! ! ! 32-bit real data is not supported when using the NAG fft. You ! may try modifying this part of the code by uncommenting the ! calls to the NAG library or less consider using the Temperton fft. ! interface fft_grid_to_fourier module procedure fft_grid_to_fourier_float_2d, fft_grid_to_fourier_double_2d, & fft_grid_to_fourier_float_3d, fft_grid_to_fourier_double_3d end interface !
! ! ! Given multiple sequences of Fourier space transforms, ! this routine computes the inverse transform and returns ! the real data values for all sequences. ! ! ! Given multiple sequences of Fourier space transforms, ! this routine computes the inverse transform and returns ! the real data values for all sequences. ! ! ! ! Multiple sequence complex Fourier space transforms. ! The first dimension must equal n/2+1 (where n is the ! size of a single real data sequence). ! ! ! Multiple sequence of real data values. The first dimension ! must be n+1 (where n is the size of a single sequence). ! The remaining dimensions must be the same size as the input ! argument "fourier". ! ! ! The initialization routine fft_init must be called before routines fft_fourier_to_grid. ! ! ! The complex Fourier field must have a first dimension equal to ! n/2+1 (where n is the size of each real transform). This message ! occurs when using the SGI/Cray fft. ! ! ! The complex Fourier field must have a first dimension greater ! than or equal to n/2+1 (where n is the size of each real ! transform). This message occurs when using the NAG or Temperton fft. ! ! ! float kind not supported for nag fft ! 32-bit real data is not supported when using the NAG fft. You ! may try modifying this part of the code by uncommenting the ! calls to the NAG library or less consider using the Temperton fft. ! interface fft_fourier_to_grid module procedure fft_fourier_to_grid_float_2d, fft_fourier_to_grid_double_2d, & fft_fourier_to_grid_float_3d, fft_fourier_to_grid_double_3d end interface ! !---------------------- private data ----------------------------------- ! tables for trigonometric constants and factors ! (not all will be used) real(R8_KIND), allocatable, dimension(:) :: table8 real(R4_KIND), allocatable, dimension(:) :: table4 real , allocatable, dimension(:) :: table99 integer , allocatable, dimension(:) :: ifax logical :: do_log =.true. integer :: leng, leng1, leng2, lenc ! related to transform size logical :: module_is_initialized=.false. ! cvs version and tag name character(len=128) :: version = '$Id: fft.F90,v 13.0 2006/03/28 21:38:54 fms Exp $' character(len=128) :: tagname = '$Name: mom4p1_pubrel_dec2009_nnz $' !----------------------------------------------------------------------- ! ! WRAPPER FOR FFT ! ! Provides fast fourier transtorm (FFT) between real grid ! space and complex fourier space. ! ! The complex fourier components are passed in the following format. ! ! fourier (1) = cmplx ( a(0), b(0) ) ! fourier (2) = cmplx ( a(1), b(1) ) ! : : ! : : ! fourier (n/2+1) = cmplx ( a(n/2), b(n/2) ) ! ! where n = length of each real transform ! ! fft uses the SCILIB on SGICRAY, otherwise the NAG library or ! a standalone version of Temperton's fft is used ! SCFFTM and CSFFTM are used on Crays ! DZFFTM and ZDFFTM are used on SGIs ! The following NAG routines are used: c06fpf, c06gqf, c06fqf. ! These routine names may be slightly different on different ! platforms. ! !----------------------------------------------------------------------- contains !####################################################################### ! ! ! ! function fft_grid_to_fourier_float_2d (grid) result (fourier) !----------------------------------------------------------------------- real (R4_KIND), intent(in), dimension(:,:) :: grid complex(R4_KIND), dimension(lenc,size(grid,2)) :: fourier !----------------------------------------------------------------------- ! ! input ! ----- ! grid = Multiple transforms in grid point space, the first dimension ! must be n+1 (where n is the size of each real transform). ! ! returns ! ------- ! Multiple transforms in complex fourier space, the first dimension ! must equal n/2+1 (where n is the size of each real transform). ! The remaining dimensions must be the same size as the input ! argument "grid". ! !----------------------------------------------------------------------- #ifdef SGICRAY # ifdef _CRAY ! local storage for cray fft real(R4_KIND), dimension((2*leng+4)*size(grid,2)) :: work # else ! local storage for sgi fft real(R4_KIND), dimension(leng2) :: work # endif #else # ifdef NAGFFT ! local storage for nag fft real(R4_KIND), dimension(size(grid,2),leng) :: data, work # else ! local storage for temperton fft real, dimension(leng2,size(grid,2)) :: data real, dimension(leng1,size(grid,2)) :: work # endif #endif #if defined(SGICRAY) || defined(NAGFFT) real(R4_KIND) :: scale #endif integer :: j, k, num, len_grid !----------------------------------------------------------------------- if (.not.module_is_initialized) & call error_handler ('fft_grid_to_fourier', & 'fft_init must be called.') !----------------------------------------------------------------------- len_grid = size(grid,1) #ifdef SGICRAY if (len_grid /= leng1) call error_handler ('fft_grid_to_fourier', & 'size of first dimension of input data is wrong') #else if (len_grid < leng) call error_handler ('fft_grid_to_fourier', & 'length of input data too small.') #endif !----------------------------------------------------------------------- !----------------transform to fourier coefficients (+1)----------------- num = size(grid,2) ! number of transforms #ifdef SGICRAY ! Cray/SGI fft scale = 1./real(leng) # ifdef _CRAY call scfftm (-1,leng,num,scale, grid,leng1, fourier,lenc, & table4, work, 0) # else call scfftm (-1,leng,num,scale, grid,leng1, fourier,lenc, & table4, work, 0) # endif #else # ifdef NAGFFT ! NAG fft ! will not allow float kind for NAG call error_handler ('fft_grid_to_fourier', & 'float kind not supported for nag fft') do j=1,size(grid,2) data(j,1:leng) = grid(1:leng,j) enddo scale = 1./sqrt(float(leng)) data = data * scale fourier(1,:) = cmplx( data(:,1), 0. ) do k=2,lenc-1 fourier(k,:) = cmplx( data(:,k), data(:,leng-k+2) ) enddo fourier(lenc,:) = cmplx( data(:,lenc), 0. ) # else ! Temperton fft do j=1,num data(1:leng,j) = grid(1:leng,j) enddo call fft991 (data,work,table99,ifax,1,leng2,leng,num,-1) do j=1,size(grid,2) do k=1,lenc fourier(k,j) = cmplx( data(2*k-1,j), data(2*k,j) ) enddo enddo # endif #endif !----------------------------------------------------------------------- end function fft_grid_to_fourier_float_2d !####################################################################### ! ! ! ! function fft_fourier_to_grid_float_2d (fourier) result (grid) !----------------------------------------------------------------------- complex(R4_KIND), intent(in), dimension(:,:) :: fourier real (R4_KIND), dimension(leng1,size(fourier,2)) :: grid !----------------------------------------------------------------------- ! ! input ! ----- ! fourier = Multiple transforms in complex fourier space, the first ! dimension must equal n/2+1 (where n is the size of each ! real transform). ! ! returns ! ------- ! Multiple transforms in grid point space, the first dimension ! must be n+1 (where n is the size of each real transform). ! The remaining dimensions must be the same size as the input ! argument "fourier". ! !----------------------------------------------------------------------- #ifdef SGICRAY # ifdef _CRAY ! local storage for cray fft real(R4_KIND), dimension((2*leng+4)*size(fourier,2)) :: work # else ! local storage for sgi fft real(R4_KIND), dimension(leng2) :: work # endif #else # ifdef NAGFFT ! local storage for nag fft real(R4_KIND), dimension(size(fourier,2),leng) :: data, work # else ! local storage for temperton fft real, dimension(leng2,size(fourier,2)) :: data real, dimension(leng1,size(fourier,2)) :: work # endif #endif #if defined(SGICRAY) || defined(NAGFFT) real(R4_KIND) :: scale #endif integer :: j, k, num, len_fourier !----------------------------------------------------------------------- if (.not.module_is_initialized) & call error_handler ('fft_grid_to_fourier', & 'fft_init must be called.') !----------------------------------------------------------------------- len_fourier = size(fourier,1) num = size(fourier,2) ! number of transforms #ifdef SGICRAY if (len_fourier /= lenc) call error_handler ('fft_fourier_to_grid', & 'size of first dimension of input data is wrong') #else if (len_fourier < lenc) call error_handler ('fft_fourier_to_grid', & 'length of input data too small.') #endif !----------------------------------------------------------------------- !----------------inverse transform to real space (-1)------------------- #ifdef SGICRAY ! Cray/SGI fft scale = 1.0 # ifdef _CRAY call csfftm (+1,leng,num,scale, fourier,len_fourier, & grid,leng1, table4, work, 0) # else call csfftm (+1,leng,num,scale, fourier,len_fourier, & grid,leng1, table4, work, 0) # endif #else # ifdef NAGFFT ! NAG fft ! will not allow float kind for nag call error_handler ('fft_fourier_to_grid', & 'float kind not supported for nag fft') ! save input complex array in real format (herm.) do k=1,lenc data(:,k) = real(fourier(k,:)) enddo do k=2,lenc-1 data(:,leng-k+2) = aimag(fourier(k,:)) enddo ! scale and transpose data scale = sqrt(real(leng)) do j=1,num grid(1:leng,j) = data(j,1:leng)*scale enddo # else ! Temperton fft do j=1,num do k=1,lenc data(2*k-1,j) = real (fourier(k,j)) data(2*k ,j) = aimag(fourier(k,j)) enddo enddo call fft991 (data,work,table99,ifax,1,leng2,leng,num,+1) do j=1,num grid(1:leng,j) = data(1:leng,j) enddo # endif #endif !----------------------------------------------------------------------- end function fft_fourier_to_grid_float_2d !####################################################################### ! ! ! ! function fft_grid_to_fourier_double_2d (grid) result (fourier) !----------------------------------------------------------------------- real (R8_KIND), intent(in), dimension(:,:) :: grid complex(R8_KIND), dimension(lenc,size(grid,2)) :: fourier !----------------------------------------------------------------------- ! ! input ! ----- ! grid = Multiple transforms in grid point space, the first dimension ! must be n+1 (where n is the size of each real transform). ! ! returns ! ------- ! Multiple transforms in complex fourier space, the first dimension ! must equal n/2+1 (where n is the size of each real transform). ! The remaining dimensions must be the same size as the input ! argument "grid". ! !----------------------------------------------------------------------- #ifdef SGICRAY # ifdef _CRAY ! local storage for cray fft real(R8_KIND), dimension((2*leng+4)*size(grid,2)) :: work # else ! local storage for sgi fft real(R8_KIND), dimension(leng2) :: work # endif #else # ifdef NAGFFT ! local storage for nag fft real(R8_KIND), dimension(size(grid,2),leng) :: data, work # else ! local storage for temperton fft real, dimension(leng2,size(grid,2)) :: data real, dimension(leng1,size(grid,2)) :: work # endif #endif #if defined(SGICRAY) || defined(NAGFFT) real(R8_KIND) :: scale #endif integer :: j, k, num, len_grid #ifdef NAGFFT integer :: ifail #endif !----------------------------------------------------------------------- if (.not.module_is_initialized) & call error_handler ('fft_grid_to_fourier', & 'fft_init must be called.') !----------------------------------------------------------------------- len_grid = size(grid,1) #ifdef SGICRAY if (len_grid /= leng1) call error_handler ('fft_grid_to_fourier', & 'size of first dimension of input data is wrong') #else if (len_grid < leng) call error_handler ('fft_grid_to_fourier', & 'length of input data too small.') #endif !----------------------------------------------------------------------- !----------------transform to fourier coefficients (+1)----------------- num = size(grid,2) ! number of transforms #ifdef SGICRAY ! Cray/SGI fft scale = 1./float(leng) # ifdef _CRAY call scfftm (-1,leng,num,scale, grid,leng1, fourier,lenc, & table8, work, 0) # else call dzfftm (-1,leng,num,scale, grid,leng1, fourier,lenc, & table8, work, 0) # endif #else # ifdef NAGFFT ! NAG fft do j=1,size(grid,2) data(j,1:leng) = grid(1:leng,j) enddo call c06fpf ( num, leng, data, 's', table8, work, ifail ) scale = 1./sqrt(float(leng)) data = data * scale fourier(1,:) = cmplx( data(:,1), 0. ) do k=2,lenc-1 fourier(k,:) = cmplx( data(:,k), data(:,leng-k+2) ) enddo fourier(lenc,:) = cmplx( data(:,lenc), 0. ) # else ! Temperton fft do j=1,num data(1:leng,j) = grid(1:leng,j) enddo call fft991 (data,work,table99,ifax,1,leng2,leng,num,-1) do j=1,size(grid,2) do k=1,lenc fourier(k,j) = cmplx( data(2*k-1,j), data(2*k,j) ) enddo enddo # endif #endif !----------------------------------------------------------------------- end function fft_grid_to_fourier_double_2d !####################################################################### ! ! ! ! function fft_fourier_to_grid_double_2d (fourier) result (grid) !----------------------------------------------------------------------- complex(R8_KIND), intent(in), dimension(:,:) :: fourier real (R8_KIND), dimension(leng1,size(fourier,2)) :: grid !----------------------------------------------------------------------- ! ! input ! ----- ! fourier = Multiple transforms in complex fourier space, the first ! dimension must equal n/2+1 (where n is the size of each ! real transform). ! ! returns ! ------- ! Multiple transforms in grid point space, the first dimension ! must be n+1 (where n is the size of each real transform). ! The remaining dimensions must be the same size as the input ! argument "fourier". ! !----------------------------------------------------------------------- #ifdef SGICRAY # ifdef _CRAY ! local storage for cray fft real(R8_KIND), dimension((2*leng+4)*size(fourier,2)) :: work # else ! local storage for sgi fft real(R8_KIND), dimension(leng2) :: work # endif #else # ifdef NAGFFT ! local storage for nag fft real(R8_KIND), dimension(size(fourier,2),leng) :: data, work # else ! local storage for temperton fft real, dimension(leng2,size(fourier,2)) :: data real, dimension(leng1,size(fourier,2)) :: work # endif #endif #if defined(SGICRAY) || defined(NAGFFT) real(R8_KIND) :: scale #endif integer :: j, k, num, len_fourier #ifdef NAGFFT integer :: ifail #endif !----------------------------------------------------------------------- if (.not.module_is_initialized) & call error_handler ('fft_grid_to_fourier', & 'fft_init must be called.') !----------------------------------------------------------------------- len_fourier = size(fourier,1) num = size(fourier,2) ! number of transforms #ifdef SGICRAY if (len_fourier /= lenc) call error_handler ('fft_fourier_to_grid', & 'size of first dimension of input data is wrong') #else if (len_fourier < lenc) call error_handler ('fft_fourier_to_grid', & 'length of input data too small.') #endif !----------------------------------------------------------------------- !----------------inverse transform to real space (-1)------------------- #ifdef SGICRAY ! Cray/SGI fft scale = 1.0 # ifdef _CRAY call csfftm (+1,leng,num,scale, fourier,len_fourier, & grid,leng1, table8, work, 0) # else call zdfftm (+1,leng,num,scale, fourier,len_fourier, & grid,leng1, table8, work, 0) # endif #else # ifdef NAGFFT ! NAG fft ! save input complex array in real format (herm.) do k=1,lenc data(:,k) = real(fourier(k,:)) enddo do k=2,lenc-1 data(:,leng-k+2) = aimag(fourier(k,:)) enddo call c06gqf ( num, leng, data, ifail ) call c06fqf ( num, leng, data, 's', table8, work, ifail ) ! scale and transpose data scale = sqrt(real(leng)) do j=1,num grid(1:leng,j) = data(j,1:leng)*scale enddo # else ! Temperton fft do j=1,num do k=1,lenc data(2*k-1,j) = real (fourier(k,j)) data(2*k ,j) = aimag(fourier(k,j)) enddo enddo call fft991 (data,work,table99,ifax,1,leng2,leng,num,+1) do j=1,num grid(1:leng,j) = data(1:leng,j) enddo # endif #endif !----------------------------------------------------------------------- end function fft_fourier_to_grid_double_2d !####################################################################### ! interface overloads !####################################################################### ! ! ! ! function fft_grid_to_fourier_float_3d (grid) result (fourier) !----------------------------------------------------------------------- real (R4_KIND), intent(in), dimension(:,:,:) :: grid complex(R4_KIND), dimension(lenc,size(grid,2),size(grid,3)) :: fourier integer :: n !----------------------------------------------------------------------- do n = 1, size(grid,3) fourier(:,:,n) = fft_grid_to_fourier_float_2d (grid(:,:,n)) enddo !----------------------------------------------------------------------- end function fft_grid_to_fourier_float_3d !####################################################################### ! ! ! ! function fft_fourier_to_grid_float_3d (fourier) result (grid) !----------------------------------------------------------------------- complex(R4_KIND), intent(in), dimension(:,:,:) :: fourier real (R4_KIND), dimension(leng1,size(fourier,2),size(fourier,3)) :: grid integer :: n !----------------------------------------------------------------------- do n = 1, size(fourier,3) grid(:,:,n) = fft_fourier_to_grid_float_2d (fourier(:,:,n)) enddo !----------------------------------------------------------------------- end function fft_fourier_to_grid_float_3d !####################################################################### ! ! ! ! function fft_grid_to_fourier_double_3d (grid) result (fourier) !----------------------------------------------------------------------- real (R8_KIND), intent(in), dimension(:,:,:) :: grid complex(R8_KIND), dimension(lenc,size(grid,2),size(grid,3)) :: fourier integer :: n !----------------------------------------------------------------------- do n = 1, size(grid,3) fourier(:,:,n) = fft_grid_to_fourier_double_2d (grid(:,:,n)) enddo !----------------------------------------------------------------------- end function fft_grid_to_fourier_double_3d !####################################################################### ! ! ! ! function fft_fourier_to_grid_double_3d (fourier) result (grid) !----------------------------------------------------------------------- complex(R8_KIND), intent(in), dimension(:,:,:) :: fourier real (R8_KIND), dimension(leng1,size(fourier,2),size(fourier,3)) :: grid integer :: n !----------------------------------------------------------------------- do n = 1, size(fourier,3) grid(:,:,n) = fft_fourier_to_grid_double_2d (fourier(:,:,n)) enddo !----------------------------------------------------------------------- end function fft_fourier_to_grid_double_3d !####################################################################### ! ! ! This routine must be called to initialize the size of a ! single transform and setup trigonometric constants. ! ! ! This routine must be called once to initialize the size of a ! single transform. To change the size of the transform the ! routine fft_exit must be called before re-initialing with fft_init. ! ! ! ! The number of real values in a single sequence of data. ! The resulting transformed data will have n/2+1 pairs of ! complex values. ! subroutine fft_init (n) !----------------------------------------------------------------------- integer, intent(in) :: n !----------------------------------------------------------------------- ! ! n = size (length) of each transform ! !----------------------------------------------------------------------- #ifdef SGICRAY real (R4_KIND) :: dummy4(1) complex(R4_KIND) :: cdummy4(1) real (R8_KIND) :: dummy8(1) complex(R8_KIND) :: cdummy8(1) integer :: isys(0:1) #else # ifdef NAGFFT real(R8_KIND) :: data8(n), work8(n) real(R4_KIND) :: data4(n), work4(n) integer :: ifail4, ifail8 # endif #endif !----------------------------------------------------------------------- ! --- fourier transform initialization ---- ! ! You must call fft_exit before calling fft_init for a second time. ! if (module_is_initialized) & call error_handler ('fft_init', 'attempted to reinitialize fft') ! write version and tag name to log file if (do_log) then call write_version_number (version, tagname) do_log = .false. endif ! variables that save length of transform leng = n; leng1 = n+1; leng2 = n+2; lenc = n/2+1 #ifdef SGICRAY # ifdef _CRAY ! initialization for cray ! float kind may not apply for cray allocate (table4(100+2*leng), table8(100+2*leng)) ! size may be too large? call scfftm (0,leng,1,0.0, dummy4, 1, cdummy4, 1, table4, dummy4, 0) call scfftm (0,leng,1,0.0, dummy8, 1, cdummy8, 1, table8, dummy8, 0) # else ! initialization for sgi allocate (table4(leng+256), table8(leng+256)) isys(0) = 1 call scfftm (0,leng,1,0.0, dummy4, 1, cdummy4, 1, table4, dummy8, isys) call dzfftm (0,leng,1,0.0, dummy8, 1, cdummy8, 1, table8, dummy8, isys) # endif #else # ifdef NAGFFT ! initialization for nag fft ifail8 = 0 allocate (table8(100+2*leng)) ! size may be too large? call c06fpf ( 1, leng, data8, 'i', table8, work8, ifail8 ) ! will not allow float kind for nag ifail4 = 0 !!!!! allocate (table4(100+2*leng)) !!!!! call c06fpe ( 1, leng, data4, 'i', table4, work4, ifail4 ) if (ifail4 /= 0 .or. ifail8 /= 0) then call error_handler ('fft_init', 'nag fft initialization error') endif # else ! initialization for Temperton fft allocate (table99(3*leng/2+1)) allocate (ifax(10)) call set99 ( table99, ifax, leng ) # endif #endif module_is_initialized = .true. !----------------------------------------------------------------------- end subroutine fft_init ! !####################################################################### ! ! ! This routine is called to unset the transform size and deallocate memory. ! ! ! This routine is called to unset the transform size and ! deallocate memory. It can not be called unless fft_init ! has already been called. There are no arguments. ! ! ! ! You can not call fft_end unless fft_init has been called. ! subroutine fft_end !----------------------------------------------------------------------- ! ! unsets transform size and deallocates memory ! !----------------------------------------------------------------------- ! --- fourier transform un-initialization ---- if (.not.module_is_initialized) & call error_handler ('fft_end', & 'attempt to un-initialize fft that has not been initialized') leng = 0; leng1 = 0; leng2 = 0; lenc = 0 if (allocated(table4)) deallocate (table4) if (allocated(table8)) deallocate (table8) if (allocated(table99)) deallocate (table99) module_is_initialized = .false. !----------------------------------------------------------------------- end subroutine fft_end ! !####################################################################### ! wrapper for handling errors subroutine error_handler ( routine, message ) character(len=*), intent(in) :: routine, message call error_mesg ( routine, message, FATAL ) ! print *, 'ERROR: ',trim(routine) ! print *, 'ERROR: ',trim(message) ! stop 111 end subroutine error_handler !####################################################################### end module fft_mod #ifdef test_fft program test use fft_mod integer, parameter :: lot = 2 real , allocatable :: ain(:,:), aout(:,:) complex, allocatable :: four(:,:) integer :: i, j, m, n integer :: ntrans(2) = (/ 60, 90 /) ! test multiple transform lengths do m = 1,2 ! set up input data n = ntrans(m) allocate (ain(n+1,lot),aout(n+1,lot),four(n/2+1,lot)) call random_number (ain(1:n,:)) aout(1:n,:) = ain(1:n,:) call fft_init (n) ! transform grid to fourier and back four = fft_grid_to_fourier (aout) aout = fft_fourier_to_grid (four) ! print original and transformed do j=1,lot do i=1,n write (*,'(2i4,3(2x,f15.9))') j, i, ain(i,j), aout(i,j), aout(i,j)-ain(i,j) enddo enddo call fft_end deallocate (ain,aout,four) enddo end program test #endif ! ! ! For the SGI/Cray version refer to the manual pages for ! DZFFTM, ZDFFTM, SCFFTM, and CSFFTM. ! ! ! For the NAG version refer to the NAG documentation for ! routines C06FPF, C06FQF, and C06GQF. ! ! ! -D NAGFFT ! On non-Cray/SGI machines, set to use the NAG library FFT routines. ! Otherwise the Temperton FFT is used by default. ! ! ! Provides source code for a simple test program. ! The program generates several sequences of real data. ! This data is transformed to Fourier space and back to real data, ! then compared to the original real data. ! ! ! On SGI machines the scientific library needs to be loaded by ! linking with: ! ! ! If using the NAG library, the following loader options (or ! something similar) may be necessary: ! ! ! The routines are overloaded for 2d and 3d versions. ! The 2d versions copy data into 3d arrays then calls the 3d interface. ! ! On SGI/Cray machines: ! ! There are single (32-bit) and full (64-bit) versions. ! For Cray machines the single precision version does not apply. ! ! On non-SGI/CRAY machines: ! ! The NAG library option uses the "full" precision NAG ! routines (C06FPF,C06FQF,C06GQF). Users may have to specify ! a 64-bit real compiler option (e.g., -r8). ! ! The stand-alone Temperton FFT option works for the ! real precision specified at compile time. ! If you compiled with single (32-bit) real precision ! then FFT's cannot be computed at full (64-bit) precision. ! !