module pft_module 4 !BOP ! ! !MODULE: pft_module --- polar filters ! ! !USES: use shr_kind_mod, only: r8 => shr_kind_r8 use fv_control_mod, only: fft_flt #ifdef NO_R16 integer,parameter :: r16= selected_real_kind(12) ! 8 byte real #else integer,parameter :: r16= selected_real_kind(24) ! 16 byte real #endif ! ! !PUBLIC MEMBER FUNCTIONS: public pft2d, pft_cf, fftfax, pftinit, fftrans ! ! !DESCRIPTION: ! ! This module provides fast-Fourier transforms ! ! \begin{tabular}{|l|l|} \hline \hline ! pftinit & \\ \hline ! pft2d & \\ \hline ! pft\_cf & \\ \hline ! fftfax & \\ \hline ! fftrans & \\ \hline ! \hline ! \end{tabular} ! ! !REVISION HISTORY: ! 01.01.30 Lin Integrated into this module ! 01.03.26 Sawyer Added ProTeX documentation ! 05.05.25 Sawyer Merged CAM and GEOS5 versions (CAM vectorization) ! 05.07.26 Worley Revised module using for Cray X1 version ! 06.09.08 Sawyer Magic numbers isolated in F90 parameters ! !EOP !----------------------------------------------------------------------- private real(r8), parameter :: D0_0 = 0.0_r8 real(r8), parameter :: D1EM20 = 1.0e-20_r8 real(r8), parameter :: D0_5 = 0.5_r8 real(r8), parameter :: D1_0 = 1.0_r8 real(r8), parameter :: D1_01 = 1.01_r8 real(r8), parameter :: D2_0 = 2.0_r8 real(r8), parameter :: D4_0 = 4.0_r8 real(r8), parameter :: D8_0 = 8.0_r8 real(r8), parameter :: D180_0 =180.0_r8 integer, save :: ifax(13) !ECMWF fft real(r8), allocatable, save :: trigs(:) ! reentrant code?? CONTAINS !----------------------------------------------------------------------- !BOP ! !IROUTINE: pftinit --- Two-dimensional FFT initialization ! ! !INTERFACE: subroutine pftinit(im) 1,1 ! !USES: implicit none ! !INPUT PARAMETERS: integer im ! Total X dimension ! !DESCRIPTION: ! ! Perform a two-dimensional FFT initialization ! ! !REVISION HISTORY: ! 05.05.15 Mirin Put into this module ! !EOP !----------------------------------------------------------------------- !BOC ! ! !LOCAL VARIABLES: integer icffta real(r8) rcffta #if defined( LIBSCI_FFT ) allocate( trigs(2*im+100) ) icffta = 0 rcffta = D0_0 call dzfftm(0, im, icffta, rcffta, rcffta, icffta, & rcffta, icffta, trigs, rcffta, icffta) #else allocate( trigs(3*im/2+1) ) call fftfax(im, ifax, trigs) #endif return !EOC end subroutine pftinit !----------------------------------------------------------------------- !----------------------------------------------------------------------- !BOP ! !IROUTINE: pft2d --- Two-dimensional fast Fourier transform ! ! !INTERFACE: subroutine pft2d(p, s, damp, im, jp, q1, q2) 14,1 ! !USES: implicit none ! !INPUT PARAMETERS: integer im ! Total X dimension integer jp ! Total Y dimension real(r8) s(jp) ! 3-point algebraic filter real(r8) damp(im,jp) ! FFT damping coefficients ! !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 ! 05.05.17 Sawyer Merged CAM and GEOS-5 ! 05.07.26 Worley Removed ifax, trigs from arg list ! !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(s(j) > D1_01 ) then if(fft_flt .eq. 0 .and. s(j) <= D4_0) then rsc = D1_0/s(j) bt = D0_5*(s(j)-D1_0) 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 else ! Packing for FFT nj = nj + 1 jf(nj) = j do i=1,im q1(i,nj) = p(i,j) enddo q1(im+1,nj) = D0_0 q1(im+2,nj) = D0_0 endif endif 200 continue if( nj == 0) return call fftrans(damp, im, jp, nj, jf, q1, q2) do n=1,nj do i=1,im p(i,jf(n)) = q1(i,n) enddo enddo return !EOC end subroutine pft2d !----------------------------------------------------------------------- !----------------------------------------------------------------------- !BOP ! !IROUTINE: fftrans --- Two-dimensional fast Fourier transform ! ! !INTERFACE: subroutine fftrans(damp, im, jp, nj, jf, q1, q2) 1,2 ! !USES: implicit none ! !INPUT PARAMETERS: integer im ! Total X dimension integer jp ! Total Y dimension integer nj ! Number of transforms integer jf(jp) ! J index versus transform number real(r8) damp(im,jp) ! FFT damping coefficients ! !INPUT/OUTPUT PARAMETERS: real(r8) q1( im+2, *) ! Work array real(r8) q2(*) ! Work array ! !DESCRIPTION: ! ! Perform a two-dimensional fast Fourier transformation. ! ! !REVISION HISTORY: ! 05.05.15 Mirin Initial combined version ! !EOP !----------------------------------------------------------------------- !BOC ! ! !LOCAL VARIABLES: integer i, n real (r8) ooim !Local Auto arrays: #if defined( LIBSCI_FFT ) real (r8) qwk(2*im+4, jp) complex(r8) cqf(im/2+1, jp) integer imo2p #elif defined( SGI_FFT ) integer*4 im_4, nj_4, imp2_4 #endif #if defined( LIBSCI_FFT ) imo2p = im/2 + 1 ooim = D1_0/real(im,r8) call dzfftm(-1, im, nj, D1_0, q1, im+2, cqf, imo2p, & trigs, qwk, 0) do n=1,nj do i=3,imo2p cqf(i,n) = cqf(i,n) * damp(2*i-2,jf(n)) enddo enddo call zdfftm( 1, im, nj, ooim, cqf, imo2p, q1, im+2, & trigs, qwk, 0) #elif defined( SGI_FFT ) im_4 = im nj_4 = nj imp2_4 = im+2 call dzfftm1du (-1, im_4, nj_4, q1, 1, imp2_4, trigs) do n=1,nj do i=5,im+2 q1(i,n) = q1(i,n) * damp(i-2,jf(n)) enddo enddo call dzfftm1du (1, im_4, nj_4, q1, 1, imp2_4, trigs) ooim = D1_0/real(im,r8) do n=1,nj do i=1,im+2 q1(i,n) = ooim*q1(i,n) enddo enddo #else call fft991 (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 fft991 (q1, q2, trigs, ifax, 1, im+2, im, nj, 1) #endif return !EOC end subroutine fftrans !----------------------------------------------------------------------- !----------------------------------------------------------------------- !BOP ! !IROUTINE: pft_cf --- Calculate algebraic and FFT polar filters ! ! !INTERFACE: subroutine pft_cf(im, jm, js2g0, jn2g0, jn1g1, sc, se, dc, de, & 2 cosp, cose, ycrit) ! !USES: 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: real (r8), parameter :: pi = 3.14159265358979323846_R8 integer i, j real (r8) dl, coszc, cutoff, phi, damp coszc = cos(ycrit*pi/D180_0) ! INIT fft polar coefficients: dl = pi/real(im,r8) cutoff = D1EM20 do j=js2g0,jn2g0 do i=1,im dc(i,j) = D1_0 enddo enddo do j=js2g0,jn1g1 do i=1,im de(i,j) = D1_0 enddo enddo ! write(iulog,*) '3-point polar filter coefficients:' !************ ! Cell center !************ do j=js2g0,jn2g0 sc(j) = (coszc/cosp(j))**2 if(sc(j) > D1_0 ) then if(fft_flt .eq. 0 .and. sc(j) <= D2_0) then sc(j) = D1_0 + (sc(j)-D1_0)/(sc(j)+D1_0) elseif(fft_flt .eq. 0 .and. sc(j) <= D4_0) then sc(j) = D1_0 + sc(j)/(D8_0-sc(j)) else ! FFT filter do i=1,im/2 phi = dl * i damp = min((cosp(j)/coszc)/sin(phi),D1_0)**2 if(damp < cutoff) damp = D0_0 dc(2*i-1,j) = damp dc(2*i ,j) = damp enddo endif endif enddo !************ ! Cell edges !************ do j=js2g0,jn1g1 se(j) = (coszc/cose(j))**2 if(se(j) > D1_0 ) then if(fft_flt .eq. 0 .and. se(j) <= D2_0) then se(j) = D1_0 + (se(j)-D1_0)/(se(j)+D1_0) elseif(fft_flt .eq. 0 .and. se(j) <= D4_0) then se(j) = D1_0 + se(j)/(D8_0-se(j)) else ! FFT do i=1,im/2 phi = dl * i damp = min((cose(j)/coszc)/sin(phi), D1_0)**2 if(damp < cutoff) damp = D0_0 de(2*i-1,j) = damp de(2*i ,j) = damp enddo endif endif enddo return !EOC end subroutine pft_cf !----------------------------------------------------------------------- !----------------------------------------------------------------------- !BOP ! !IROUTINE: fftfax --- Initialize FFT ! ! !INTERFACE: subroutine fftfax (n, ifaxx, trigss) 1,1 ! !USES: implicit none ! !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 ! 05.07.26 Worley Modified version for Cray X1 ! !EOP !----------------------------------------------------------------------- !BOC integer n #if defined( SGI_FFT ) real(r8) trigss(1) integer ifaxx(*) ! local integer*4 nn nn=n call dzfftm1dui (nn,trigss) #else integer ifaxx(13) real(r8) trigss(3*n/2+1) call set99(trigss,ifaxx,n) #endif return !EOC end subroutine fftfax !----------------------------------------------------------------------- end module pft_module