#include <misc.h>
module pft_module 2
!BOP
!
! !MODULE: pft_module --- polar filters
!
!
! !PUBLIC MEMBER FUNCTIONS:
public pft2d, pft_cf, rfftmlt, fftfax
!
! !DESCRIPTION:
!
! This module provides fast-Fourier transforms
!
! \begin{tabular}{|l|l|} \hline \hline
! pft2d & \\ \hline
! pft\_cf & \\ \hline
! rfftmlt & \\ \hline
! fftfax & \\ \hline
! \hline
! \end{tabular}
!
! !REVISION HISTORY:
! 01.01.30 Lin Integrated into this module
! 01.03.26 Sawyer Added ProTeX documentation
!
!EOP
!-----------------------------------------------------------------------
CONTAINS
!-----------------------------------------------------------------------
!BOP
! !IROUTINE: pft2d --- Two-dimensional fast Fourier transform
!
! !INTERFACE:
subroutine pft2d(p, s, damp, im, jp, ifax, trigs, q1, q2) 10,3
! !USES:
use shr_kind_mod
, only: r8 => shr_kind_r8
implicit none
! !INPUT PARAMETERS:
integer im ! Total X dimension
integer jp ! Total Y dimension
integer ifax(13) ! FFT internal information
real(r8) s(jp) ! 3-point algebraic filter
real(r8) damp(im,jp) ! FFT damping coefficients
real(r8) trigs(3*im/2+1)
! !INPUT/OUTPUT PARAMETERS:
real(r8) q1( im+2, *) ! Work array
real(r8) q2(*) ! Work array
real(r8) p(im,jp) ! Array to be polar filtered
! !DESCRIPTION:
!
! Perform a two-dimensional fast Fourier transformation.
!
! !REVISION HISTORY:
! 01.01.30 Lin Put into this module
! 01.03.26 Sawyer Added ProTeX documentation
! 02.04.05 Sawyer Integrated newest FVGCM version
!
!EOP
!-----------------------------------------------------------------------
!BOC
!
! !LOCAL VARIABLES:
real(r8) rsc, bt
integer i, j, n, nj
!Local Auto arrays:
real(r8) ptmp(0:im+1)
!!! real(r8) q1( im+2, jp)
!!! real(r8) q2( (im+1)*jp )
integer jf(jp)
nj = 0
do 200 j=1,jp
#if defined ( ALT_PFT )
if(s(j) > 1.01) then
#else
if(s(j) > 1.01 .and. s(j) <= 4.) then
rsc = 1./s(j)
bt = 0.5*(s(j)-1.)
do i=1,im
ptmp(i) = p(i,j)
enddo
ptmp( 0) = p(im,j)
ptmp(im+1) = p(1 ,j)
do i=1,im
p(i,j) = rsc * ( ptmp(i) + bt*(ptmp(i-1)+ptmp(i+1)) )
enddo
elseif(s(j) > 4.) then
#endif
! Packing for FFT
nj = nj + 1
jf(nj) = j
do i=1,im
q1(i,nj) = p(i,j)
enddo
q1(im+1,nj) = 0.
q1(im+2,nj) = 0.
endif
200 continue
if( nj == 0) return
call rfftmlt
(q1, q2, trigs, ifax, 1, im+2, im, nj, -1)
do n=1,nj
do i=5,im+2
q1(i,n) = q1(i,n) * damp(i-2,jf(n))
enddo
enddo
call rfftmlt
(q1, q2, trigs, ifax, 1, im+2, im, nj, 1)
do n=1,nj
do i=1,im
p(i,jf(n)) = q1(i,n)
enddo
enddo
return
!EOC
end subroutine pft2d
!-----------------------------------------------------------------------
!-----------------------------------------------------------------------
!BOP
! !IROUTINE: pft_cf --- Calculate algebraic and FFT polar filters
!
! !INTERFACE:
subroutine pft_cf(im, jm, js2g0, jn2g0, jn1g1, sc, se, dc, de, & 1,1
cosp, cose, ycrit)
! !USES:
use shr_kind_mod
, only: r8 => shr_kind_r8
implicit none
! !INPUT PARAMETERS:
integer im ! Total X dimension
integer jm ! Total Y dimension
integer js2g0 ! j south limit ghosted 0 (SP: from 2)
integer jn2g0 ! j north limit ghosted 0 (NP: from jm-1)
integer jn1g1 ! j north limit ghosted 1 (starts jm)
real (r8) cosp(jm) ! cosine array
real (r8) cose(jm) ! cosine array
real (r8) ycrit ! critical value
! !OUTPUT PARAMETERS:
real (r8) sc(js2g0:jn2g0) ! Algebric filter at center
real (r8) se(js2g0:jn1g1) ! Algebric filter at edge
real (r8) dc(im,js2g0:jn2g0) ! FFT filter at center
real (r8) de(im,js2g0:jn1g1) ! FFT filter at edge
! !DESCRIPTION:
!
! Compute coefficients for the 3-point algebraic and the FFT
! polar filters.
!
! !REVISION HISTORY:
!
! 99.01.01 Lin Creation
! 99.08.20 Sawyer/Lin Changes for SPMD mode
! 01.01.30 Lin Put into this module
! 01.03.26 Sawyer Added ProTeX documentation
!
!EOP
!-----------------------------------------------------------------------
!BOC
!
! !LOCAL VARIABLES:
integer i, j
real (r8) dl, coszc, cutoff, phi, damp
real (r8) pi
pi = 4.d0 * datan(1.d0)
coszc = cos(ycrit*pi/180.)
! INIT fft polar coefficients:
dl = pi/dble(im)
cutoff = 1.e-20
do j=js2g0,jn2g0
do i=1,im
dc(i,j) = 1.
enddo
enddo
do j=js2g0,jn1g1
do i=1,im
de(i,j) = 1.
enddo
enddo
! write(6,*) '3-point polar filter coefficients:'
!************
! Cell center
!************
do j=js2g0,jn2g0
sc(j) = (coszc/cosp(j))**2
#if defined ( ALT_PFT )
if( sc(j) > 1. ) then
#else
if(sc(j) > 1. .and. sc(j) <= 2.0) then
sc(j) = 1. + (sc(j)-1.)/(sc(j)+1.)
elseif(sc(j) > 2. .and. sc(j) <= 4.) then
sc(j) = 1. + sc(j)/(8.-sc(j))
elseif(sc(j) > 4. ) then
#endif
! FFT filter
do i=1,im/2
phi = dl * i
damp = min((cosp(j)/coszc)/sin(phi), 1.)**2
if(damp < cutoff) damp = 0.
dc(2*i-1,j) = damp
dc(2*i ,j) = damp
enddo
endif
enddo
!************
! Cell edges
!************
do j=js2g0,jn1g1
se(j) = (coszc/cose(j))**2
#if defined ( ALT_PFT )
if( se(j) > 1. ) then
#else
if(se(j) > 1. .and. se(j) <= 2.0 ) then
se(j) = 1. + (se(j)-1.)/(se(j)+1.)
elseif(se(j) > 2. .and. se(j) <= 4.) then
se(j) = 1. + se(j)/(8.-se(j))
elseif(se(j) > 4. ) then
#endif
! FFT
do i=1,im/2
phi = dl * i
damp = min((cose(j)/coszc)/sin(phi), 1.)**2
if(damp < cutoff) damp = 0.
de(2*i-1,j) = damp
de(2*i ,j) = damp
enddo
endif
enddo
return
!EOC
end subroutine pft_cf
!-----------------------------------------------------------------------
!-----------------------------------------------------------------------
!BOP
! !IROUTINE: rfftmlt --- Apply fast Fourier transform
!
! !INTERFACE:
subroutine rfftmlt(a,work,trigs,ifax,inc,jump,n,lot,isign) 2,1
! !USES:
use shr_kind_mod
, only: r8 => shr_kind_r8
! !DESCRIPTION:
!
! Apply the fast Fourier transform. If CPP token SGI_FFT is
! set, SGI libraries will be used. Otherwise the Fortran code
! is inlined.
!
! !REVISION HISTORY:
!
! 99.11.24 Sawyer Added wrappers for SGI
! 01.03.26 Sawyer Added ProTeX documentation
!
!EOP
!-----------------------------------------------------------------------
!BOC
#if defined( SGI_FFT )
!
! WS 99.11.24 : Added SGI wrappers
!
implicit none
integer inc, jump, n, lot, isign
real(r8) a(jump,lot)
real(r8) trigs(1)
real(r8) work(1) ! Not used; here for plug reason
integer ifax(*)
! Local
integer*4 iisign,in,iinc,ijump,ilot
integer i, j
real(r8) scale
!-----convert to i4
iisign = isign
iinc = inc
ijump = jump
in = n
ilot = lot
if( iisign < 0 ) then
!-----forward
call dzfftm1du (iisign,in,ilot,a,iinc,ijump,trigs)
endif
if( iisign > 0 ) then
!-----backward
call zdfftm1du (iisign,in,ilot,a,iinc,ijump,trigs)
scale = 1.0/float(n)
do j=1,lot
do i=1,jump
a(i,j) = scale*a(i,j)
enddo
enddo
endif
#else
!
! Default f77 version
!
real(r8) a(jump*lot)
real(r8) work((n+1)*lot)
real(r8) trigs(3*n/2+1)
integer ifax(13)
! SUBROUTINE "FFT991" - MULTIPLE REAL/HALF-COMPLEX PERIODIC
! FAST FOURIER TRANSFORM
! SAME AS FFT99 EXCEPT THAT ORDERING OF DATA CORRESPONDS TO
! THAT IN MRFFT2
! PROCEDURE USED TO CONVERT TO HALF-LENGTH COMPLEX TRANSFORM
! IS GIVEN BY COOLEY, LEWIS AND WELCH (J. SOUND VIB., VOL. 12
! (1970), 315-337)
! A IS THE ARRAY CONTAINING INPUT AND OUTPUT DATA
! WORK IS AN AREA OF SIZE (N+1)*LOT
! TRIGS IS A PREVIOUSLY PREPARED LIST OF TRIG FUNCTION VALUES
! IFAX IS A PREVIOUSLY PREPARED LIST OF FACTORS OF N/2
! INC IS THE INCREMENT WITHIN EACH DATA 'VECTOR'
! (E.G. INC=1 FOR CONSECUTIVELY STORED DATA)
! JUMP IS THE INCREMENT BETWEEN THE START OF EACH DATA VECTOR
! N IS THE LENGTH OF THE DATA VECTORS
! LOT IS THE NUMBER OF DATA VECTORS
! ISIGN = +1 FOR TRANSFORM FROM SPECTRAL TO GRIDPOINT
! = -1 FOR TRANSFORM FROM GRIDPOINT TO SPECTRAL
! ORDERING OF COEFFICIENTS:
! A(0),B(0),A(1),B(1),A(2),B(2),...,A(N/2),B(N/2)
! WHERE B(0)=B(N/2)=0; (N+2) LOCATIONS REQUIRED
!
! ORDERING OF DATA:
! X(0),X(1),X(2),...,X(N-1)
!
! VECTORIZATION IS ACHIEVED ON CRAY BY DOING THE TRANSFORMS IN
! PARALLEL
! *** N.B. N IS ASSUMED TO BE AN EVEN NUMBER
!
! DEFINITION OF TRANSFORMS:
! -------------------------
! ISIGN=+1: X(J)=SUM(K=0,...,N-1)(C(K)*EXP(2*I*J*K*PI/N))
! WHERE C(K)=A(K)+I*B(K) AND C(N-K)=A(K)-I*B(K)
!
! ISIGN=-1: A(K)=(1/N)*SUM(J=0,...,N-1)(X(J)*COS(2*J*K*PI/N))
! B(K)=-(1/N)*SUM(J=0,...,N-1)(X(J)*SIN(2*J*K*PI/N))
nfax=ifax(1)
nx=n+1
nh=n/2
ink=inc+inc
if (isign==+1) go to 30
! IF NECESSARY, TRANSFER DATA TO WORK AREA
igo=50
if (mod(nfax,2)==1) goto 40
ibase=1
jbase=1
do 20 l=1,lot
i=ibase
j=jbase
!DIR$ IVDEP
do 10 m=1,n
work(j)=a(i)
i=i+inc
j=j+1
10 continue
ibase=ibase+jump
jbase=jbase+nx
20 continue
igo=60
go to 40
! PREPROCESSING (ISIGN=+1)
30 continue
call fft99a(a,work,trigs,inc,jump,n,lot)
igo=60
! COMPLEX TRANSFORM
40 continue
ia=1
la=1
do 80 k=1,nfax
if (igo==60) go to 60
50 continue
call vpassm(a(ia),a(ia+inc),work(1),work(2),trigs, &
ink,2,jump,nx,lot,nh,ifax(k+1),la)
igo=60
go to 70
60 continue
call vpassm(work(1),work(2),a(ia),a(ia+inc),trigs, &
2,ink,nx,jump,lot,nh,ifax(k+1),la)
igo=50
70 continue
la=la*ifax(k+1)
80 continue
if (isign==-1) go to 130
! IF NECESSARY, TRANSFER DATA FROM WORK AREA
if (mod(nfax,2)==1) go to 110
ibase=1
jbase=1
do 100 l=1,lot
i=ibase
j=jbase
!DIR$ IVDEP
do 90 m=1,n
a(j)=work(i)
i=i+1
j=j+inc
90 continue
ibase=ibase+nx
jbase=jbase+jump
100 continue
! FILL IN ZEROS AT END
110 continue
ib=n*inc+1
!DIR$ IVDEP
do 120 l=1,lot
a(ib)=0.0
a(ib+inc)=0.0
ib=ib+jump
120 continue
go to 140
! POSTPROCESSING (ISIGN=-1):
130 continue
call fft99b(work,a,trigs,inc,jump,n,lot)
140 continue
#endif
return
!EOC
end subroutine rfftmlt
!-----------------------------------------------------------------------
!-----------------------------------------------------------------------
!BOP
! !IROUTINE: fftfax --- Initialize FFT
!
! !INTERFACE:
subroutine fftfax (n, ifax, trigs) 1,1
! !USES:
use shr_kind_mod
, only: r8 => shr_kind_r8
! !DESCRIPTION:
!
! Initialize the fast Fourier transform. If CPP token SGI_FFT is
! set, SGI libraries will be used. Otherwise the Fortran code
! is inlined.
!
! !REVISION HISTORY:
!
! 99.11.24 Sawyer Added wrappers for SGI
! 01.03.26 Sawyer Added ProTeX documentation
!
!EOP
!-----------------------------------------------------------------------
!BOC
#if defined( SGI_FFT )
implicit none
real(r8) trigs(1)
integer ifax(*)
integer n
! local
integer*4 nn
nn=n
call dzfftm1dui (nn,trigs)
#else
integer ifax(13)
real(r8) trigs(3*n/2+1)
! MODE 3 IS USED FOR REAL/HALF-COMPLEX TRANSFORMS. IT IS POSSIBLE
! TO DO COMPLEX/COMPLEX TRANSFORMS WITH OTHER VALUES OF MODE, BUT
! DOCUMENTATION OF THE DETAILS WERE NOT AVAILABLE WHEN THIS ROUTINE
! WAS WRITTEN.
data mode /3/
call fax (ifax, n, mode)
i = ifax(1)
if (ifax(i+1) > 5 .or. n <= 4) ifax(1) = -99
if (ifax(1) <= 0 ) then
write(6,*) ' set99 -- invalid n'
stop 'set99'
endif
call fftrig (trigs, n, mode)
#endif
return
!EOC
end subroutine fftfax
!-----------------------------------------------------------------------
end module pft_module