PUMA  219
Portable University Model of the Atmosphere
/Users/home/WC/puma/src/fftmod.f90
Go to the documentation of this file.
00001 !     =============
00002 !     MODULE FFTMOD
00003 !     =============
00004 
00005       module fftmod
00006       parameter(NRES = 12)
00007       integer :: nallowed(NRES) = (/16,32,48,64,96,128,256,384,512,1024,2048,4096/)
00008 !     T3    - N16   : 8-2
00009 !     T10   - N32   : 8-2-2
00010 !     T15   - N48   : 8-3-2
00011 !     T21   - N64   : 8-4-2
00012 !     T31   - N96   : 8-4-3
00013 !     T42   - N128  : 8-4-4
00014 !     T85   - N256  : 8-4-4-2
00015 !     T127  - N384  : 8-4-4-3
00016 !     T170  - N512  : 8-4-4-4
00017 !     T341  - N1024 : 8-4-4-4-2
00018 !     T682  - N2048 : 8-4-4-4-4
00019 !     T1365 - N4096 : 8-4-4-4-4-2
00020 
00021       integer :: lastn = 0
00022       real,allocatable :: trigs(:)
00023       end module fftmod
00024 
00025 !     ================
00026 !     SUBROUTINE GP2FC
00027 !     ================
00028 
00029       subroutine gp2fc(a,n,lot)
00030       use fftmod
00031       real a(n,lot)
00032 
00033       if (n /= lastn) then
00034          if (allocated(trigs)) deallocate(trigs)
00035          allocate(trigs(n))
00036          lastn = n
00037          call fftini(n)
00038       endif
00039 
00040       call dfft8(a,a,n,lot)
00041       la = n / 8
00042       do while (la >= 4)
00043          call dfft4(a,trigs,n,lot,la)
00044       enddo
00045 
00046       if (la == 3) then
00047          do l = 1 , lot
00048             call dfft3(a(1,l),trigs,n)
00049          enddo
00050       endif
00051 
00052       if (la == 2) then
00053          do l = 1 , lot
00054             call dfft2(a(1,l),trigs,n)
00055          enddo
00056       endif
00057       return
00058       end subroutine gp2fc
00059 
00060 !     ================
00061 !     SUBROUTINE FC2GP
00062 !     ================
00063 
00064       subroutine fc2gp(a,n,lot)
00065       use fftmod
00066       real a(n,lot)
00067 
00068       if (n /= lastn) then
00069          if (allocated(trigs)) deallocate(trigs)
00070          allocate(trigs(n))
00071          lastn = n
00072          call fftini(n)
00073       endif
00074 
00075       nf = n/8
00076       do while (nf >= 4)
00077          nf = nf/4
00078       enddo
00079       la = 1
00080       if (nf == 2) call ifft2(a,trigs,n,lot,la)
00081       if (nf == 3) call ifft3(a,trigs,n,lot,la)
00082       do while (la < n/8)
00083          call ifft4(a,trigs,n,lot,la)
00084       enddo
00085       call ifft8(a,a,n,lot)
00086       return
00087       end subroutine fc2gp
00088 
00089 !     =================
00090 !     SUBROUTINE FFTINI
00091 !     =================
00092 
00093       subroutine fftini(n)
00094       use fftmod
00095       logical labort
00096 
00097 !     check for allowed values of n
00098 
00099       labort = .true.
00100       do j = 1 , NRES
00101          if (n == nallowed(j)) labort = .false.
00102       enddo
00103 
00104       if (labort) then
00105          write (*,*) '*** FFT does not support n = ',n,' ***'
00106          write (*,*) 'Following resolutions may be used:'
00107          write (*,*) '----------------------------------'
00108          do j = 1 , NRES
00109             write (*,1000) nallowed(j), nallowed(j)/2, nallowed(j)/3
00110          enddo
00111          stop
00112       endif
00113  1000 format(' NLON=',I5,'  NLAT=',I5,'  NTRU=',I5)
00114 
00115       del = 4.0 * asin(1.0) / n
00116       do k=0,n/2-1
00117         angle = k * del
00118         trigs(2*k+1) = cos(angle)
00119         trigs(2*k+2) = sin(angle)
00120       enddo
00121       return
00122       end subroutine fftini
00123 
00124 !     ================
00125 !     SUBROUTINE DFFT2
00126 !     ================
00127 
00128       subroutine dfft2(a,trigs,n)
00129       dimension a(n),c(n),trigs(n)
00130 
00131       c(1) = a(1) + a(2)
00132       c(2) = 0.0
00133 
00134       ja = 3
00135       jb = n - 1
00136 
00137       do i=3,n-5,4
00138          c1 = trigs(ja  )
00139          s1 = trigs(ja+1)
00140          a1p3 = c1 * a(i+1) + s1 * a(i+3)
00141          a3m1 = c1 * a(i+3) - s1 * a(i+1)
00142          c(ja  ) = a(i) + a1p3
00143          c(jb  ) = a(i) - a1p3
00144          c(ja+1) = a3m1 + a(i+2)
00145          c(jb+1) = a3m1 - a(i+2)
00146          ja = ja + 2
00147          jb = jb - 2
00148       enddo
00149 
00150       c(ja  ) =  a(n-1)
00151       c(ja+1) = -a(n  )
00152 
00153       a = c
00154       return
00155       end subroutine dfft2
00156 
00157 !     ================
00158 !     SUBROUTINE DFFT3
00159 !     ================
00160 
00161       subroutine dfft3(a,trigs,n)
00162       parameter(SIN60 = 0.866025403784438D0)
00163       dimension a(n),c(n),trigs(n)
00164 
00165       ja = 1              !  1
00166       jb = 2 * (n/3)  + 1 ! 65
00167       jc = jb             ! 65
00168 
00169       c(ja  ) = a(1) + a(2) + a(3)
00170       c(ja+1) = 0.0
00171       c(jb  ) = a(1) - 0.5 * (a(2) + a(3))
00172       c(jb+1) =      SIN60 * (a(3) - a(2))
00173 
00174       ja = 3         !  3, 5, 7, ... ,31
00175       jb = jb + 2    ! 67,69,71, ... ,95
00176       jc = jc - 2    ! 63,61,59, ... ,35
00177 
00178       do i = 4 , n-8 , 6 ! 88
00179          c1 = trigs(ja  )
00180          s1 = trigs(ja+1)
00181          c2 = trigs(ja+ja-1)
00182          s2 = trigs(ja+ja  )
00183          a1 = (c1*a(i+1)+s1*a(i+4))+(c2*a(i+2)+s2*a(i+5))
00184          b1 = (c1*a(i+4)-s1*a(i+1))+(c2*a(i+5)-s2*a(i+2))
00185          a2 = a(i  ) - 0.5 * a1
00186          b2 = a(i+3) - 0.5 * b1
00187          a3 = SIN60*((c1*a(i+1)+s1*a(i+4))-(c2*a(i+2)+s2*a(i+5)))
00188          b3 = SIN60*((c1*a(i+4)-s1*A(i+1))-(c2*a(i+5)-s2*a(i+2)))
00189          c(ja  ) = a(i  ) + a1
00190          c(ja+1) = a(i+3) + b1
00191          c(jb  ) = a2 + b3
00192          c(jb+1) = b2 - a3
00193          c(jc  ) = a2 - b3
00194          c(jc+1) =-b2 - a3
00195          ja = ja + 2
00196          jb = jb + 2
00197          jc = jc - 2
00198       enddo
00199 
00200       if (ja <= jc) then ! ja=33  jc=33
00201          c(ja  ) = a(n-2) + 0.5 * (a(n-1) - a(n)) ! 33
00202          c(ja+1) =       -SIN60 * (a(n-1) + a(n)) ! 34
00203       endif
00204       a(:) = c(:)
00205       return
00206       end subroutine dfft3
00207 
00208 !     ================
00209 !     SUBROUTINE DFFT4
00210 !     ================
00211 
00212       subroutine dfft4(a,trigs,n,lot,la)
00213       dimension a(n,lot),c(n,lot),trigs(n)
00214       la = la / 4
00215 
00216       i1 = la
00217       i2 = la + i1
00218       i3 = la + i2
00219       i4 = la + i3
00220       i5 = la + i4
00221       i6 = la + i5
00222       i7 = la + i6
00223 
00224       j1 = n/2 - la
00225       j2 = n - la
00226       j3 = j1
00227       j5 = j1 + la
00228 
00229       do i=1,la
00230          do l=1,lot
00231          a0p2 = a(i   ,l) + a(i2+i,l)
00232          a1p3 = a(i1+i,l) + a(i3+i,l)
00233          c(   i,l) = a0p2 + a1p3
00234          c(j2+i,l) = a0p2 - a1p3
00235          c(j1+i,l) = a(   i,l) - a(i2+i,l)
00236          c(j5+i,l) = a(i3+i,l) - a(i1+i,l)
00237          enddo
00238       enddo
00239 
00240       jink = 2 * la
00241       j0 = la
00242       j1 = j1 + jink
00243       j2 = j2 - jink
00244       j3 = j3 - jink
00245       j4 = j0 + la
00246       j5 = j1 + la
00247       j6 = j2 + la
00248       j7 = j3 + la
00249 
00250       ibase=4*la
00251 
00252       do 450 k=la,(n-4)/8,la
00253          kb=k+k
00254          kc=kb+kb
00255          kd=kc+kb
00256          c1=trigs(kb+1)
00257          s1=trigs(kb+2)
00258          c2=trigs(kc+1)
00259          s2=trigs(kc+2)
00260          c3=trigs(kd+1)
00261          s3=trigs(kd+2)
00262 
00263          i=ibase+1
00264          do j=1,la
00265             do l=1,lot
00266             a1p5 = c1 * a(i1+i,l) + s1 * a(i5+i,l)
00267             a2p6 = c2 * a(i2+i,l) + s2 * a(i6+i,l)
00268             a3p7 = c3 * a(i3+i,l) + s3 * a(i7+i,l)
00269             a5m1 = c1 * a(i5+i,l) - s1 * a(i1+i,l)
00270             a6m2 = c2 * a(i6+i,l) - s2 * a(i2+i,l)
00271             a7m3 = c3 * a(i7+i,l) - s3 * a(i3+i,l)
00272             a0 = a(i,l) + a2p6
00273             a2 = a(i,l) - a2p6
00274             a1 = a1p5 + a3p7
00275             a3 = a3p7 - a1p5
00276             b0 = a(i4+i,l) + a6m2
00277             b2 = a(i4+i,l) - a6m2
00278             b1 = a5m1 + a7m3
00279             b3 = a5m1 - a7m3
00280             c(j0+j,l) = a0+a1
00281             c(j2+j,l) = a0-a1
00282             c(j4+j,l) = b0+b1
00283             c(j6+j,l) = b1-b0
00284             c(j1+j,l) = a2+b3
00285             c(j3+j,l) = a2-b3
00286             c(j5+j,l) = a3+b2
00287             c(j7+j,l) = a3-b2
00288             enddo
00289             i=i+1
00290          enddo
00291 
00292         ibase=ibase+8*la
00293         j0 = j0 + jink
00294         j1 = j1 + jink
00295         j2 = j2 - jink
00296         j3 = j3 - jink
00297         j4 = j0 + la
00298         j5 = j1 + la
00299         j6 = j2 + la
00300         j7 = j3 + la
00301 450   continue
00302       if (j1 <= j2) then
00303          sin45=sqrt(0.5)
00304          i=ibase+1
00305          do j=1,la
00306             do l=1,lot
00307             a1p3 = sin45 * (a(i1+i,l) + a(i3+i,l))
00308             a1m3 = sin45 * (a(i1+i,l) - a(i3+i,l))
00309             c(j0+j,l) =  a(   i,l) + a1m3
00310             c(j1+j,l) =  a(   i,l) - a1m3
00311             c(j4+j,l) = -a(i2+i,l) - a1p3
00312             c(j5+j,l) =  a(i2+i,l) - a1p3
00313             enddo
00314             i=i+1
00315          enddo
00316       endif
00317       if (la == 1) then
00318          do l=1,lot
00319          a(1,l) = c(1,l)
00320          a(2,l) = 0.0
00321          a(3:n,l) = c(2:n-1,l)
00322          enddo
00323       else
00324          a = c
00325       endif
00326       return
00327       end subroutine dfft4
00328 
00329 !     ================
00330 !     SUBROUTINE DFFT8
00331 !     ================
00332 
00333       subroutine dfft8(a,c,n,lot)
00334       real a(n*lot),c(n*lot)
00335       la = n / 8
00336       z  = 1.0 / n
00337       zsin45 = z * sqrt(0.5)
00338 
00339       do i=0,la*lot-1
00340          i0 = (i/la) * n + mod(i,la) + 1
00341          i1 = i0 + la
00342          i2 = i1 + la
00343          i3 = i2 + la
00344          i4 = i3 + la
00345          i5 = i4 + la
00346          i6 = i5 + la
00347          i7 = i6 + la
00348 
00349          a0p4 =  a(i0) + a(i4)
00350          a1p5 =  a(i1) + a(i5)
00351          a2p6 =  a(i2) + a(i6)
00352          a3p7 =  a(i3) + a(i7)
00353          a5m1 =  a(i5) - a(i1)
00354          a7m3 =  a(i7) - a(i3)
00355          a0m4 = (a(i0) - a(i4)) * z
00356          a6m2 = (a(i6) - a(i2)) * z
00357 
00358          a0p4p2p6 = a0p4 + a2p6
00359          a1p5p3p7 = a1p5 + a3p7
00360          a7m3p5m1 = (a7m3 + a5m1) * zsin45
00361          a7m3m5m1 = (a7m3 - a5m1) * zsin45
00362 
00363          c(i0) = z * (a0p4p2p6 + a1p5p3p7)
00364          c(i7) = z * (a0p4p2p6 - a1p5p3p7)
00365          c(i3) = z * (a0p4 - a2p6)
00366          c(i4) = z * (a3p7 - a1p5)
00367          c(i1) = a0m4 + a7m3m5m1
00368          c(i5) = a0m4 - a7m3m5m1
00369          c(i2) = a7m3p5m1 + a6m2
00370          c(i6) = a7m3p5m1 - a6m2
00371       enddo
00372       return
00373       end subroutine dfft8
00374 
00375 !     ================
00376 !     SUBROUTINE IFFT4
00377 !     ================
00378 
00379       subroutine ifft4(c,trigs,n,lot,la)
00380       dimension a(n,lot),c(n,lot),trigs(n)
00381 
00382       if (la == 1) then
00383          a(1,:) = 0.5 * c(1,:)
00384          a(n,:) = 0.0
00385          a(2:n-1,:) = c(3:n,:)
00386       else
00387          a = c
00388       endif
00389 
00390       m=n/4
00391       kstop=(n-4)/8
00392 
00393       i1 = n/2 - la
00394       i2 = n   - la
00395       i5 = i1  + la
00396 
00397       j1 = la
00398       j2 = la+j1
00399       j3 = la+j2
00400       j4 = la+j3
00401       j5 = la+j4
00402       j6 = la+j5
00403       j7 = la+j6
00404 
00405       do i=1,la
00406       do l=1,lot
00407          c(   i,l) = a(i,l) + a(i2+i,l) + a(i1+i,l)
00408          c(j1+i,l) = a(i,l) - a(i2+i,l) - a(i5+i,l)
00409          c(j2+i,l) = a(i,l) + a(i2+i,l) - a(i1+i,l)
00410          c(j3+i,l) = a(i,l) - a(i2+i,l) + a(i5+i,l)
00411       enddo
00412       enddo
00413 
00414       iink  = 2 * la
00415       jbase = 4 * la + 1
00416       i0    = la
00417       i1    = i0 + n/2
00418       i2    = n - 3 * la
00419       i3    = i2 - n/2
00420       i4    = i0 + la
00421       i5    = i1 + la
00422       i6    = i2 + la
00423       i7    = i3 + la
00424 
00425       do 450 k=la,kstop,la
00426         kb=k+k
00427         kc=kb+kb
00428         kd=kc+kb
00429         c1=trigs(kb+1)
00430         s1=trigs(kb+2)
00431         c2=trigs(kc+1)
00432         s2=trigs(kc+2)
00433         c3=trigs(kd+1)
00434         s3=trigs(kd+2)
00435         do i = 1 , la
00436            j = jbase
00437            do l=1,lot
00438            a0p2 = a(i0+i,l) + a(i2+i,l)
00439            a0m2 = a(i0+i,l) - a(i2+i,l)
00440            a1p3 = a(i1+i,l) + a(i3+i,l)
00441            a1m3 = a(i1+i,l) - a(i3+i,l)
00442            a4p6 = a(i4+i,l) + a(i6+i,l)
00443            a4m6 = a(i4+i,l) - a(i6+i,l)
00444            a5p7 = a(i5+i,l) + a(i7+i,l)
00445            a5m7 = a(i5+i,l) - a(i7+i,l)
00446 
00447            a0p2m1p3 = a0p2 - a1p3
00448            a4m6m5m7 = a4m6 - a5m7
00449 
00450            c(   j,l) = a0p2 + a1p3
00451            c(j4+j,l) = a4m6 + a5m7
00452            c(j2+j,l) = c2 * a0p2m1p3 - s2 * a4m6m5m7
00453            c(j6+j,l) = s2 * a0p2m1p3 + c2 * a4m6m5m7
00454            c(j1+j,l) = c1*(a0m2-a5p7)-s1*(a4p6+a1m3)
00455            c(j5+j,l) = s1*(a0m2-a5p7)+c1*(a4p6+a1m3)
00456            c(j3+j,l) = c3*(a0m2+a5p7)-s3*(a4p6-a1m3)
00457            c(j7+j,l) = s3*(a0m2+a5p7)+c3*(a4p6-a1m3)
00458            enddo
00459            jbase=jbase+1
00460         enddo
00461         i0 = i0 + iink
00462         i1 = i1 + iink
00463         i2 = i2 - iink
00464         i3 = i3 - iink
00465         i4 = i4 + iink
00466         i5 = i5 + iink
00467         i6 = i6 - iink
00468         i7 = i7 - iink
00469         jbase=jbase+7*la
00470 450     continue
00471 
00472       if (i1 <= i2) then
00473          sin45=sqrt(0.5)
00474          do i=1,la
00475             j=jbase
00476             do l=1,lot
00477             c(   j,l)=a(i0+i,l)+a(i1+i,l)
00478             c(j1+j,l)=sin45*((a(i0+i,l)-a(i1+i,l))-(a(la+i0+i,l)+a(la+i1+i,l)))
00479             c(j2+j,l)=a(la+i1+i,l)-a(la+i0+i,l)
00480             c(j3+j,l)=-sin45*((a(i0+i,l)-a(i1+i,l))+(a(la+i0+i,l)+a(la+i1+i,l)))
00481             enddo
00482             jbase=jbase+1
00483          enddo
00484       endif
00485       la = la * 4
00486       return
00487       end subroutine ifft4
00488 
00489 !     ================
00490 !     SUBROUTINE IFFT2
00491 !     ================
00492 
00493       subroutine ifft2(a,trigs,n,lot,la)
00494       dimension a(n,lot),c(n,lot),trigs(n)
00495 
00496       c(1,:) = 0.5 * a(1,:)
00497       c(2,:) = c(1,:)
00498 
00499       ia    =   3
00500       ib    = n-1
00501 
00502       do j = 3 , n-5 , 4
00503          c1 = trigs(ia  )
00504          s1 = trigs(ia+1)
00505          do l=1,lot
00506          amb = a(ia  ,l) - a(ib  ,l)
00507          apb = a(ia+1,l) + a(ib+1,l)
00508          c(j  ,l) = a(ia  ,l) + a(ib  ,l)
00509          c(j+2,l) = a(ia+1,l) - a(ib+1,l)
00510          c(j+1,l) = c1 * amb - s1 * apb
00511          c(j+3,l) = s1 * amb + c1 * apb
00512          enddo
00513          ia = ia + 2
00514          ib = ib - 2
00515       enddo
00516       c(n-1,:) =  a(ia  ,:)
00517       c(n  ,:) = -a(ia+1,:)
00518 
00519       a(:,:) = c(:,:)
00520       la = 2
00521       return
00522       end subroutine ifft2
00523 
00524 !     ================
00525 !     SUBROUTINE IFFT3
00526 !     ================
00527 
00528       subroutine ifft3(a,trigs,n,lot,la)
00529       dimension a(n,lot),c(n,lot),trigs(n)
00530       parameter(SIN60 = 0.866025403784438D0)
00531 
00532       ib = 2 * (n/3) + 1
00533 
00534       c(1,:) = 0.5 * a(1,:) + a(ib,:)
00535       c(2,:) = 0.5 * a(1,:) - 0.5 * a(ib,:) - SIN60 * a(ib+1,:)
00536       c(3,:) = 0.5 * a(1,:) - 0.5 * a(ib,:) + SIN60 * a(ib+1,:)
00537 
00538       ia = 3
00539       ic = ib - 2
00540       ib = ib + 2
00541 
00542       do j = 4 , n-8 , 6
00543          c1 = trigs(ia  )
00544          s1 = trigs(ia+1)
00545          c2 = trigs(ia+ia-1)
00546          s2 = trigs(ia+ia  )
00547 
00548          do l = 1 , lot
00549             hbpc = a(ia  ,l) - 0.5 * (a(ib  ,l) + a(ic  ,l))
00550             hbmc = a(ia+1,l) - 0.5 * (a(ib+1,l) - a(ic+1,l))
00551             sbmc = SIN60 * (a(ib  ,l) - a(ic  ,l))
00552             sbpc = SIN60 * (a(ib+1,l) + a(ic+1,l))
00553 
00554             c(j  ,l) = a(ia  ,l) + a(ib  ,l) + a(ic  ,l)
00555             c(j+3,l) = a(ia+1,l) + a(ib+1,l) - a(ic+1,l)
00556             c(j+1,l) = c1 * (hbpc-sbpc) - s1 * (hbmc+sbmc)
00557             c(j+4,l) = s1 * (hbpc-sbpc) + c1 * (hbmc+sbmc)
00558             c(j+2,l) = c2 * (hbpc+sbpc) - s2 * (hbmc-sbmc)
00559             c(j+5,l) = s2 * (hbpc+sbpc) + c2 * (hbmc-sbmc)
00560          enddo
00561          ia = ia + 2
00562          ib = ib + 2
00563          ic = ic - 2
00564       enddo
00565 
00566       c(n-2,:) = a(ia,:)
00567       c(n-1,:) =   0.5 * a(ia,:) - SIN60 * a(ia+1,:)
00568       c(n  ,:) = - 0.5 * a(ia,:) - SIN60 * a(ia+1,:)
00569 
00570       a(:,:)  = c(:,:)
00571       la = 3
00572       return
00573       end subroutine ifft3
00574 
00575 !     ================
00576 !     SUBROUTINE IFFT8
00577 !     ================
00578 
00579       subroutine ifft8(a,c,n,lot)
00580       parameter(SQRT2 = 1.414213562373095D0)
00581       dimension a(n*lot),c(n*lot)
00582       la = n / 8
00583 
00584       do i=0,la*lot-1
00585          i0 = (i/la) * n + mod(i,la) + 1
00586          i1 = i0 + la
00587          i2 = i1 + la
00588          i3 = i2 + la
00589          i4 = i3 + la
00590          i5 = i4 + la
00591          i6 = i5 + la
00592          i7 = i6 + la
00593 
00594          a0p7 = a(i0) + a(i7)
00595          a0m7 = a(i0) - a(i7)
00596          a1p5 = a(i1) + a(i5)
00597          a1m5 = a(i1) - a(i5)
00598          a2p6 = a(i2) + a(i6)
00599          a2m6 = a(i2) - a(i6)
00600 
00601          a0p7p3   = a0p7 + a(i3)
00602          a0p7m3   = a0p7 - a(i3)
00603          a0m7p4   = 2.0 * (a0m7 + a(i4))
00604          a0m7m4   = 2.0 * (a0m7 - a(i4))
00605          a1m5p2p6 = SQRT2 * (a1m5 + a2p6)
00606          a1m5m2p6 = SQRT2 * (a1m5 - a2p6)
00607 
00608          c(i0)  = 2.0 * (a0p7p3 + a1p5)
00609          c(i2)  = 2.0 * (a0p7m3 - a2m6)
00610          c(i4)  = 2.0 * (a0p7p3 - a1p5)
00611          c(i6)  = 2.0 * (a0p7m3 + a2m6)
00612 
00613          c(i1)  = a0m7m4 + a1m5m2p6
00614          c(i3)  = a0m7p4 - a1m5p2p6
00615          c(i5)  = a0m7m4 - a1m5m2p6
00616          c(i7)  = a0m7p4 + a1m5p2p6
00617       enddo
00618       return
00619       end