SUBROUTINE fft99(a,work,trigs,ifax,inc,jump,n,lot,ISIGN),4
!
! PURPOSE PERFORMS MULTIPLE FAST FOURIER TRANSFORMS. THIS PACKAGE
! WILL PERFORM A NUMBER OF SIMULTANEOUS REAL/HALF-COMPLEX
! PERIODIC FOURIER TRANSFORMS OR CORRESPONDING INVERSE
! TRANSFORMS, I.E. GIVEN A SET OF REAL DATA VECTORS, THE
! PACKAGE RETURNS A SET OF 'HALF-COMPLEX' FOURIER
! COEFFICIENT VECTORS, OR VICE VERSA. THE LENGTH OF THE
! TRANSFORMS MUST BE AN EVEN NUMBER GREATER THAN 4 THAT HAS
! NO OTHER FACTORS EXCEPT POSSIBLY POWERS OF 2, 3, AND 5.
! THIS IS AN ALL FORTRAN VERSION OF THE CRAYLIB PACKAGE
! THAT IS MOSTLY WRITTEN IN CAL.
!
! THE PACKAGE FFT99F CONTAINS SEVERAL USER-LEVEL ROUTINES:
!
! SUBROUTINE SET99
! AN INITIALIZATION ROUTINE THAT MUST BE CALLED ONCE
! BEFORE A SEQUENCE OF CALLS TO THE FFT ROUTINES
! (PROVIDED THAT N IS NOT CHANGED).
!
! SUBROUTINES FFT99 AND FFT991
! TWO FFT ROUTINES THAT RETURN SLIGHTLY DIFFERENT
! ARRANGEMENTS OF THE DATA IN GRIDPOINT SPACE.
!
!
! ACCESS THIS FORTRAN VERSION MAY BE ACCESSED WITH
!
! *FORTRAN,P=XLIB,SN=FFT99F
!
! TO ACCESS THE CRAY OBJECT CODE, CALLING THE USER ENTRY
! POINTS FROM A CRAY PROGRAM IS SUFFICIENT. THE SOURCE
! FORTRAN AND CAL CODE FOR THE CRAYLIB VERSION MAY BE
! ACCESSED USING
!
! FETCH P=CRAYLIB,SN=FFT99
! FETCH P=CRAYLIB,SN=CAL99
!
! USAGE LET N BE OF THE FORM 2**P * 3**Q * 5**R, WHERE P .GE. 1,
! Q .GE. 0, AND R .GE. 0. THEN A TYPICAL SEQUENCE OF
! CALLS TO TRANSFORM A GIVEN SET OF REAL VECTORS OF LENGTH
! N TO A SET OF 'HALF-COMPLEX' FOURIER COEFFICIENT VECTORS
! OF LENGTH N IS
!
! DIMENSION IFAX(13),TRIGS(3*N/2+1),A(M*(N+2)),
! + WORK(M*(N+1))
!
! CALL SET99 (TRIGS, IFAX, N)
! CALL FFT99 (A,WORK,TRIGS,IFAX,INC,JUMP,N,M,ISIGN)
!
! SEE THE INDIVIDUAL WRITE-UPS FOR SET99, FFT99, AND
! FFT991 BELOW, FOR A DETAILED DESCRIPTION OF THE
! ARGUMENTS.
!
! HISTORY THE PACKAGE WAS WRITTEN BY CLIVE TEMPERTON AT ECMWF IN
! NOVEMBER, 1978. IT WAS MODIFIED, DOCUMENTED, AND TESTED
! FOR NCAR BY RUSS REW IN SEPTEMBER, 1980.
!
!-----------------------------------------------------------------------
!
! SUBROUTINE SET99 (TRIGS, IFAX, N)
!
! PURPOSE A SET-UP ROUTINE FOR FFT99 AND FFT991. IT NEED ONLY BE
! CALLED ONCE BEFORE A SEQUENCE OF CALLS TO THE FFT
! ROUTINES (PROVIDED THAT N IS NOT CHANGED).
!
! ARGUMENT IFAX(13),TRIGS(3*N/2+1)
! DIMENSIONS
!
! ARGUMENTS
!
! ON INPUT TRIGS
! A FLOATING POINT ARRAY OF DIMENSION 3*N/2 IF N/2 IS
! EVEN, OR 3*N/2+1 IF N/2 IS ODD.
!
! IFAX
! AN INTEGER ARRAY. THE NUMBER OF ELEMENTS ACTUALLY USED
! WILL DEPEND ON THE FACTORIZATION OF N. DIMENSIONING
! IFAX FOR 13 SUFFICES FOR ALL N LESS THAN A MILLION.
!
! N
! AN EVEN NUMBER GREATER THAN 4 THAT HAS NO PRIME FACTOR
! GREATER THAN 5. N IS THE LENGTH OF THE TRANSFORMS (SEE
! THE DOCUMENTATION FOR FFT99 AND FFT991 FOR THE
! DEFINITIONS OF THE TRANSFORMS).
!
! ON OUTPUT IFAX
! CONTAINS THE FACTORIZATION OF N/2. IFAX(1) IS THE
! NUMBER OF FACTORS, AND THE FACTORS THEMSELVES ARE STORED
! IN IFAX(2),IFAX(3),... IF SET99 IS CALLED WITH N ODD,
! OR IF N HAS ANY PRIME FACTORS GREATER THAN 5, IFAX(1)
! IS SET TO -99.
!
! TRIGS
! AN ARRAY OF TRIGNOMENTRIC FUNCTION VALUES SUBSEQUENTLY
! USED BY THE FFT ROUTINES.
!
!-----------------------------------------------------------------------
!
! SUBROUTINE FFT991 (A,WORK,TRIGS,IFAX,INC,JUMP,N,M,ISIGN)
! AND
! SUBROUTINE FFT99 (A,WORK,TRIGS,IFAX,INC,JUMP,N,M,ISIGN)
!
! PURPOSE PERFORM A NUMBER OF SIMULTANEOUS REAL/HALF-COMPLEX
! PERIODIC FOURIER TRANSFORMS OR CORRESPONDING INVERSE
! TRANSFORMS, USING ORDINARY SPATIAL ORDER OF GRIDPOINT
! VALUES (FFT991) OR EXPLICIT CYCLIC CONTINUITY IN THE
! GRIDPOINT VALUES (FFT99). GIVEN A SET
! OF REAL DATA VECTORS, THE PACKAGE RETURNS A SET OF
! 'HALF-COMPLEX' FOURIER COEFFICIENT VECTORS, OR VICE
! VERSA. THE LENGTH OF THE TRANSFORMS MUST BE AN EVEN
! NUMBER THAT HAS NO OTHER FACTORS EXCEPT POSSIBLY POWERS
! OF 2, 3, AND 5. THESE VERSION OF FFT991 AND FFT99 ARE
! OPTIMIZED FOR USE ON THE CRAY-1.
!
! ARGUMENT A(M*(N+2)), WORK(M*(N+1)), TRIGS(3*N/2+1), IFAX(13)
! DIMENSIONS
!
! ARGUMENTS
!
! ON INPUT A
! AN ARRAY OF LENGTH M*(N+2) CONTAINING THE INPUT DATA
! OR COEFFICIENT VECTORS. THIS ARRAY IS OVERWRITTEN BY
! THE RESULTS.
!
! WORK
! A WORK ARRAY OF DIMENSION M*(N+1)
!
! TRIGS
! AN ARRAY SET UP BY SET99, WHICH MUST BE CALLED FIRST.
!
! IFAX
! AN ARRAY SET UP BY SET99, WHICH MUST BE CALLED FIRST.
!
! INC
! THE INCREMENT (IN WORDS) BETWEEN SUCCESSIVE ELEMENTS OF
! EACH DATA OR COEFFICIENT VECTOR (E.G. INC=1 FOR
! CONSECUTIVELY STORED DATA).
!
! JUMP
! THE INCREMENT (IN WORDS) BETWEEN THE FIRST ELEMENTS OF
! SUCCESSIVE DATA OR COEFFICIENT VECTORS. ON THE CRAY-1,
! TRY TO ARRANGE DATA SO THAT JUMP IS NOT A MULTIPLE OF 8
! (TO AVOID MEMORY BANK CONFLICTS). FOR CLARIFICATION OF
! INC AND JUMP, SEE THE EXAMPLES BELOW.
!
! N
! THE LENGTH OF EACH TRANSFORM (SEE DEFINITION OF
! TRANSFORMS, BELOW).
!
! M
! THE NUMBER OF TRANSFORMS TO BE DONE SIMULTANEOUSLY.
!
! ISIGN
! = +1 FOR A TRANSFORM FROM FOURIER COEFFICIENTS TO
! GRIDPOINT VALUES.
! = -1 FOR A TRANSFORM FROM GRIDPOINT VALUES TO FOURIER
! COEFFICIENTS.
!
! ON OUTPUT A
! IF ISIGN = +1, AND M COEFFICIENT VECTORS ARE SUPPLIED
! EACH CONTAINING THE SEQUENCE:
!
! A(0),B(0),A(1),B(1),...,A(N/2),B(N/2) (N+2 VALUES)
!
! THEN THE RESULT CONSISTS OF M DATA VECTORS EACH
! CONTAINING THE CORRESPONDING N+2 GRIDPOINT VALUES:
!
! FOR FFT991, X(0), X(1), X(2),...,X(N-1),0,0.
! FOR FFT99, X(N-1),X(0),X(1),X(2),...,X(N-1),X(0).
! (EXPLICIT CYCLIC CONTINUITY)
!
! WHEN ISIGN = +1, THE TRANSFORM IS DEFINED BY:
! 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)
! AND I=SQRT (-1)
!
! IF ISIGN = -1, AND M DATA VECTORS ARE SUPPLIED EACH
! CONTAINING A SEQUENCE OF GRIDPOINT VALUES X(J) AS
! DEFINED ABOVE, THEN THE RESULT CONSISTS OF M VECTORS
! EACH CONTAINING THE CORRESPONDING FOURIER COFFICIENTS
! A(K), B(K), 0 .LE. K .LE N/2.
!
! WHEN ISIGN = -1, THE INVERSE TRANSFORM IS DEFINED BY:
! C(K)=(1/N)*SUM(J=0,...,N-1)(X(J)*EXP(-2*I*J*K*PI/N))
! WHERE C(K)=A(K)+I*B(K) AND I=SQRT(-1)
!
! A CALL WITH ISIGN=+1 FOLLOWED BY A CALL WITH ISIGN=-1
! (OR VICE VERSA) RETURNS THE ORIGINAL DATA.
!
! NOTE: THE FACT THAT THE GRIDPOINT VALUES X(J) ARE REAL
! IMPLIES THAT B(0)=B(N/2)=0. FOR A CALL WITH ISIGN=+1,
! IT IS NOT ACTUALLY NECESSARY TO SUPPLY THESE ZEROS.
!
! EXAMPLES GIVEN 19 DATA VECTORS EACH OF LENGTH 64 (+2 FOR EXPLICIT
! CYCLIC CONTINUITY), COMPUTE THE CORRESPONDING VECTORS OF
! FOURIER COEFFICIENTS. THE DATA MAY, FOR EXAMPLE, BE
! ARRANGED LIKE THIS:
!
! FIRST DATA A(1)= . . . A(66)= A(70)
! VECTOR X(63) X(0) X(1) X(2) ... X(63) X(0) (4 EMPTY LOCATIONS)
!
! SECOND DATA A(71)= . . . A(140)
! VECTOR X(63) X(0) X(1) X(2) ... X(63) X(0) (4 EMPTY LOCATIONS)
!
! AND SO ON. HERE INC=1, JUMP=70, N=64, M=19, ISIGN=-1,
! AND FFT99 SHOULD BE USED (BECAUSE OF THE EXPLICIT CYCLIC
! CONTINUITY).
!
! ALTERNATIVELY THE DATA MAY BE ARRANGED LIKE THIS:
!
! FIRST SECOND LAST
! DATA DATA DATA
! VECTOR VECTOR VECTOR
!
! A(1)= A(2)= A(19)=
!
! X(63) X(63) . . . X(63)
! A(20)= X(0) X(0) . . . X(0)
! A(39)= X(1) X(1) . . . X(1)
! . . .
! . . .
! . . .
!
! IN WHICH CASE WE HAVE INC=19, JUMP=1, AND THE REMAINING
! PARAMETERS ARE THE SAME AS BEFORE. IN EITHER CASE, EACH
! COEFFICIENT VECTOR OVERWRITES THE CORRESPONDING INPUT
! DATA VECTOR.
!
!-----------------------------------------------------------------------
DIMENSION a((n+2)*lot),work((n+1)*lot),trigs(3*n/2+1),ifax(13)
!
! SUBROUTINE "FFT99" - MULTIPLE FAST REAL PERIODIC TRANSFORM
! CORRESPONDING TO OLD SCALAR ROUTINE FFT9
! 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(N-1),X(0),X(1),X(2),...,X(N),X(0)
! I.E. EXPLICIT CYCLIC CONTINUITY; (N+2) LOCATIONS REQUIRED
!
! 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) GO TO 40
ibase=inc+1
jbase=1
DO l=1,lot
i=ibase
j=jbase
!DIR$ IVDEP
DO m=1,n
work(j)=a(i)
i=i+inc
j=j+1
END DO
ibase=ibase+jump
jbase=jbase+nx
END DO
!
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=inc+1
la=1
DO k=1,nfax
IF (igo == 60) GO TO 60
! 50 CONTINUE
CALL vpassm
( 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)
END DO
!
IF (ISIGN == -1) GO TO 130
!
! IF NECESSARY, TRANSFER DATA FROM WORK AREA
IF (MOD(nfax,2) == 1) GO TO 110
ibase=1
jbase=ia
DO l=1,lot
i=ibase
j=jbase
!DIR$ IVDEP
DO m=1,n
a(j)=work(i)
i=i+1
j=j+inc
END DO
ibase=ibase+nx
jbase=jbase+jump
END DO
!
! FILL IN CYCLIC BOUNDARY POINTS
110 CONTINUE
ia=1
ib=n*inc+1
!DIR$ IVDEP
DO l=1,lot
a(ia)=a(ib)
a(ib+inc)=a(ia+inc)
ia=ia+jump
ib=ib+jump
END DO
GO TO 140
!
! POSTPROCESSING (ISIGN=-1):
! --------------------------
!
130 CONTINUE
CALL fft99b
(work,a,trigs,inc,jump,n,lot)
!
140 CONTINUE
RETURN
END SUBROUTINE fft99
SUBROUTINE fft99a(a,work,trigs,inc,jump,n,lot) 2
DIMENSION a(n),work(n),trigs(n)
!
! SUBROUTINE FFT99A - PREPROCESSING STEP FOR FFT99, ISIGN=+1
! (SPECTRAL TO GRIDPOINT TRANSFORM)
!
nh=n/2
nx=n+1
ink=inc+inc
!
! A(0) AND A(N/2)
ia=1
ib=n*inc+1
ja=1
jb=2
!DIR$ IVDEP
DO l=1,lot
work(ja)=a(ia)+a(ib)
work(jb)=a(ia)-a(ib)
ia=ia+jump
ib=ib+jump
ja=ja+nx
jb=jb+nx
END DO
!
! REMAINING WAVENUMBERS
iabase=2*inc+1
ibbase=(n-2)*inc+1
jabase=3
jbbase=n-1
!
DO k=3,nh,2
ia=iabase
ib=ibbase
ja=jabase
jb=jbbase
c=trigs(n+k)
s=trigs(n+k+1)
!DIR$ IVDEP
DO l=1,lot
work(ja)=(a(ia)+a(ib))- &
(s*(a(ia)-a(ib))+c*(a(ia+inc)+a(ib+inc)))
work(jb)=(a(ia)+a(ib))+ &
(s*(a(ia)-a(ib))+c*(a(ia+inc)+a(ib+inc)))
work(ja+1)=(c*(a(ia)-a(ib))-s*(a(ia+inc)+a(ib+inc)))+ &
(a(ia+inc)-a(ib+inc))
work(jb+1)=(c*(a(ia)-a(ib))-s*(a(ia+inc)+a(ib+inc)))- &
(a(ia+inc)-a(ib+inc))
ia=ia+jump
ib=ib+jump
ja=ja+nx
jb=jb+nx
END DO
iabase=iabase+ink
ibbase=ibbase-ink
jabase=jabase+2
jbbase=jbbase-2
END DO
!
IF (iabase /= ibbase) GO TO 50
! WAVENUMBER N/4 (IF IT EXISTS)
ia=iabase
ja=jabase
!DIR$ IVDEP
DO l=1,lot
work(ja)=2.0*a(ia)
work(ja+1)=-2.0*a(ia+inc)
ia=ia+jump
ja=ja+nx
END DO
!
50 CONTINUE
RETURN
END SUBROUTINE fft99a
SUBROUTINE fft99b(work,a,trigs,inc,jump,n,lot) 2
DIMENSION work(n),a(n),trigs(n)
!
! SUBROUTINE FFT99B - POSTPROCESSING STEP FOR FFT99, ISIGN=-1
! (GRIDPOINT TO SPECTRAL TRANSFORM)
!
nh=n/2
nx=n+1
ink=inc+inc
!
! A(0) AND A(N/2)
scale=1.0/FLOAT(n)
ia=1
ib=2
ja=1
jb=n*inc+1
!DIR$ IVDEP
DO l=1,lot
a(ja)=scale*(work(ia)+work(ib))
a(jb)=scale*(work(ia)-work(ib))
a(ja+inc)=0.0
a(jb+inc)=0.0
ia=ia+nx
ib=ib+nx
ja=ja+jump
jb=jb+jump
END DO
!
! REMAINING WAVENUMBERS
scale=0.5*scale
iabase=3
ibbase=n-1
jabase=2*inc+1
jbbase=(n-2)*inc+1
!
DO k=3,nh,2
ia=iabase
ib=ibbase
ja=jabase
jb=jbbase
c=trigs(n+k)
s=trigs(n+k+1)
!DIR$ IVDEP
DO l=1,lot
a(ja)=scale*((work(ia)+work(ib)) &
+(c*(work(ia+1)+work(ib+1))+s*(work(ia)-work(ib))))
a(jb)=scale*((work(ia)+work(ib)) &
-(c*(work(ia+1)+work(ib+1))+s*(work(ia)-work(ib))))
a(ja+inc)=scale*((c*(work(ia)-work(ib))-s*(work(ia+1)+work(ib+1))) &
+(work(ib+1)-work(ia+1)))
a(jb+inc)=scale*((c*(work(ia)-work(ib))-s*(work(ia+1)+work(ib+1))) &
-(work(ib+1)-work(ia+1)))
ia=ia+nx
ib=ib+nx
ja=ja+jump
jb=jb+jump
END DO
iabase=iabase+2
ibbase=ibbase-2
jabase=jabase+ink
jbbase=jbbase-ink
END DO
!
IF (iabase /= ibbase) GO TO 50
! WAVENUMBER N/4 (IF IT EXISTS)
ia=iabase
ja=jabase
scale=2.0*scale
!DIR$ IVDEP
DO l=1,lot
a(ja)=scale*work(ia)
a(ja+inc)=-scale*work(ia+1)
ia=ia+nx
ja=ja+jump
END DO
!
50 CONTINUE
RETURN
END SUBROUTINE fft99b
SUBROUTINE fft991(a,work,trigs,ifax,inc,jump,n,lot,ISIGN) 8,4
DIMENSION a(n),work(n),trigs(n),ifax(1)
!
! 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) GO TO 40
ibase=1
jbase=1
DO l=1,lot
i=ibase
j=jbase
!DIR$ IVDEP
DO m=1,n
work(j)=a(i)
i=i+inc
j=j+1
END DO
ibase=ibase+jump
jbase=jbase+nx
END DO
!
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 k=1,nfax
IF (igo == 60) GO TO 60
! 50 CONTINUE
CALL vpassm
( 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)
END DO
!
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 l=1,lot
i=ibase
j=jbase
!DIR$ IVDEP
DO m=1,n
a(j)=work(i)
i=i+1
j=j+inc
END DO
ibase=ibase+nx
jbase=jbase+jump
END DO
!
! FILL IN ZEROS AT END
110 CONTINUE
ib=n*inc+1
!DIR$ IVDEP
DO l=1,lot
a(ib)=0.0
a(ib+inc)=0.0
ib=ib+jump
END DO
GO TO 140
!
! POSTPROCESSING (ISIGN=-1):
! --------------------------
!
130 CONTINUE
CALL fft99b
(work,a,trigs,inc,jump,n,lot)
!
140 CONTINUE
RETURN
END SUBROUTINE fft991
SUBROUTINE set99 (trigs, ifax, n) 8,3
DIMENSION ifax(13),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'
CALL arpsstop
('arpsstop called from SET99',1)
END IF
CALL fftrig
(trigs, n, mode)
RETURN
END SUBROUTINE set99
SUBROUTINE fax(ifax,n,mode) 1
DIMENSION ifax(10)
nn=n
IF (IABS(mode) == 1) GO TO 10
IF (IABS(mode) == 8) GO TO 10
nn=n/2
IF ((nn+nn) == n) GO TO 10
ifax(1)=-99
RETURN
10 k=1
! TEST FOR FACTORS OF 4
20 IF (MOD(nn,4) /= 0) GO TO 30
k=k+1
ifax(k)=4
nn=nn/4
IF (nn == 1) GO TO 80
GO TO 20
! TEST FOR EXTRA FACTOR OF 2
30 IF (MOD(nn,2) /= 0) GO TO 40
k=k+1
ifax(k)=2
nn=nn/2
IF (nn == 1) GO TO 80
! TEST FOR FACTORS OF 3
40 IF (MOD(nn,3) /= 0) GO TO 50
k=k+1
ifax(k)=3
nn=nn/3
IF (nn == 1) GO TO 80
GO TO 40
! NOW FIND REMAINING FACTORS
50 l=5
inc=2
! INC ALTERNATELY TAKES ON VALUES 2 AND 4
60 IF (MOD(nn,l) /= 0) GO TO 70
k=k+1
ifax(k)=l
nn=nn/l
IF (nn == 1) GO TO 80
GO TO 60
70 l=l+inc
inc=6-inc
GO TO 60
80 ifax(1)=k-1
! IFAX(1) CONTAINS NUMBER OF FACTORS
nfax=ifax(1)
! SORT FACTORS INTO ASCENDING ORDER
IF (nfax == 1) GO TO 110
DO ii=2,nfax
istop=nfax+2-ii
DO i=2,istop
IF (ifax(i+1) >= ifax(i)) CYCLE
item=ifax(i)
ifax(i)=ifax(i+1)
ifax(i+1)=item
END DO
END DO
110 CONTINUE
RETURN
END SUBROUTINE fax
SUBROUTINE fftrig(trigs,n,mode) 1
DIMENSION trigs(1)
pi=2.0*ASIN(1.0)
imode=IABS(mode)
nn=n
IF (imode > 1.AND.imode < 6) nn=n/2
del=(pi+pi)/FLOAT(nn)
l=nn+nn
DO i=1,l,2
angle=0.5*FLOAT(i-1)*del
trigs(i)=COS(angle)
trigs(i+1)=SIN(angle)
END DO
IF (imode == 1) RETURN
IF (imode == 8) RETURN
del=0.5*del
nh=(nn+1)/2
l=nh+nh
la=nn+nn
DO i=1,l,2
angle=0.5*FLOAT(i-1)*del
trigs(la+i)=COS(angle)
trigs(la+i+1)=SIN(angle)
END DO
IF (imode <= 3) RETURN
del=0.5*del
la=la+nn
IF (mode == 5) GO TO 40
DO i=2,nn
angle=FLOAT(i-1)*del
trigs(la+i)=2.0*SIN(angle)
END DO
RETURN
40 CONTINUE
del=0.5*del
DO i=2,n
angle=FLOAT(i-1)*del
trigs(la+i)=SIN(angle)
END DO
RETURN
END SUBROUTINE fftrig
SUBROUTINE vpassm(a,b,c,d,trigs,inc1,inc2,inc3,inc4,lot,n,ifac,la) 4
DIMENSION a(n),b(n),c(n),d(n),trigs(n)
!
! SUBROUTINE "VPASSM" - MULTIPLE VERSION OF "VPASSA"
! PERFORMS ONE PASS THROUGH DATA
! AS PART OF MULTIPLE COMPLEX FFT ROUTINE
! A IS FIRST REAL INPUT VECTOR
! B IS FIRST IMAGINARY INPUT VECTOR
! C IS FIRST REAL OUTPUT VECTOR
! D IS FIRST IMAGINARY OUTPUT VECTOR
! TRIGS IS PRECALCULATED TABLE OF SINES " COSINES
! INC1 IS ADDRESSING INCREMENT FOR A AND B
! INC2 IS ADDRESSING INCREMENT FOR C AND D
! INC3 IS ADDRESSING INCREMENT BETWEEN A"S & B"S
! INC4 IS ADDRESSING INCREMENT BETWEEN C"S & D"S
! LOT IS THE NUMBER OF VECTORS
! N IS LENGTH OF VECTORS
! IFAC IS CURRENT FACTOR OF N
! LA IS PRODUCT OF PREVIOUS FACTORS
!
DATA sin36/0.587785252292473/,cos36/0.809016994374947/, &
sin72/0.951056516295154/,cos72/0.309016994374947/, &
sin60/0.866025403784437/
!
m=n/ifac
iink=m*inc1
jink=la*inc2
jump=(ifac-1)*jink
ibase=0
jbase=0
igo=ifac-1
IF (igo > 4) RETURN
! GO TO (10,50,90,130),igo
!
! obsolescent feature correction temporarily by WYH.
!
SELECT CASE (igo)
CASE (1)
GO TO 10
CASE (2)
GO TO 50
CASE (3)
GO TO 90
CASE (4)
GO TO 130
CASE DEFAULT
! Do nothing
END SELECT
!
! end of correction by WYH.
!
!
! CODING FOR FACTOR 2
!
10 ia=1
ja=1
ib=ia+iink
jb=ja+jink
DO l=1,la
i=ibase
j=jbase
!DIR$ IVDEP
DO ijk=1,lot
c(ja+j)=a(ia+i)+a(ib+i)
d(ja+j)=b(ia+i)+b(ib+i)
c(jb+j)=a(ia+i)-a(ib+i)
d(jb+j)=b(ia+i)-b(ib+i)
i=i+inc3
j=j+inc4
END DO
ibase=ibase+inc1
jbase=jbase+inc2
END DO
IF (la == m) RETURN
la1=la+1
jbase=jbase+jump
DO k=la1,m,la
kb=k+k-2
c1=trigs(kb+1)
s1=trigs(kb+2)
DO l=1,la
i=ibase
j=jbase
!DIR$ IVDEP
DO ijk=1,lot
c(ja+j)=a(ia+i)+a(ib+i)
d(ja+j)=b(ia+i)+b(ib+i)
c(jb+j)=c1*(a(ia+i)-a(ib+i))-s1*(b(ia+i)-b(ib+i))
d(jb+j)=s1*(a(ia+i)-a(ib+i))+c1*(b(ia+i)-b(ib+i))
i=i+inc3
j=j+inc4
END DO
ibase=ibase+inc1
jbase=jbase+inc2
END DO
jbase=jbase+jump
END DO
RETURN
!
! CODING FOR FACTOR 3
!
50 ia=1
ja=1
ib=ia+iink
jb=ja+jink
ic=ib+iink
jc=jb+jink
DO l=1,la
i=ibase
j=jbase
!DIR$ IVDEP
DO ijk=1,lot
c(ja+j)=a(ia+i)+(a(ib+i)+a(ic+i))
d(ja+j)=b(ia+i)+(b(ib+i)+b(ic+i))
c(jb+j)=(a(ia+i)-0.5*(a(ib+i)+a(ic+i)))-(sin60*(b(ib+i)-b(ic+i)))
c(jc+j)=(a(ia+i)-0.5*(a(ib+i)+a(ic+i)))+(sin60*(b(ib+i)-b(ic+i)))
d(jb+j)=(b(ia+i)-0.5*(b(ib+i)+b(ic+i)))+(sin60*(a(ib+i)-a(ic+i)))
d(jc+j)=(b(ia+i)-0.5*(b(ib+i)+b(ic+i)))-(sin60*(a(ib+i)-a(ic+i)))
i=i+inc3
j=j+inc4
END DO
ibase=ibase+inc1
jbase=jbase+inc2
END DO
IF (la == m) RETURN
la1=la+1
jbase=jbase+jump
DO k=la1,m,la
kb=k+k-2
kc=kb+kb
c1=trigs(kb+1)
s1=trigs(kb+2)
c2=trigs(kc+1)
s2=trigs(kc+2)
DO l=1,la
i=ibase
j=jbase
!DIR$ IVDEP
DO ijk=1,lot
c(ja+j)=a(ia+i)+(a(ib+i)+a(ic+i))
d(ja+j)=b(ia+i)+(b(ib+i)+b(ic+i))
c(jb+j)= &
c1*((a(ia+i)-0.5*(a(ib+i)+a(ic+i)))-(sin60*(b(ib+i)-b(ic+i)))) &
-s1*((b(ia+i)-0.5*(b(ib+i)+b(ic+i)))+(sin60*(a(ib+i)-a(ic+i))))
d(jb+j)= &
s1*((a(ia+i)-0.5*(a(ib+i)+a(ic+i)))-(sin60*(b(ib+i)-b(ic+i)))) &
+c1*((b(ia+i)-0.5*(b(ib+i)+b(ic+i)))+(sin60*(a(ib+i)-a(ic+i))))
c(jc+j)= &
c2*((a(ia+i)-0.5*(a(ib+i)+a(ic+i)))+(sin60*(b(ib+i)-b(ic+i)))) &
-s2*((b(ia+i)-0.5*(b(ib+i)+b(ic+i)))-(sin60*(a(ib+i)-a(ic+i))))
d(jc+j)= &
s2*((a(ia+i)-0.5*(a(ib+i)+a(ic+i)))+(sin60*(b(ib+i)-b(ic+i)))) &
+c2*((b(ia+i)-0.5*(b(ib+i)+b(ic+i)))-(sin60*(a(ib+i)-a(ic+i))))
i=i+inc3
j=j+inc4
END DO
ibase=ibase+inc1
jbase=jbase+inc2
END DO
jbase=jbase+jump
END DO
RETURN
!
! CODING FOR FACTOR 4
!
90 ia=1
ja=1
ib=ia+iink
jb=ja+jink
ic=ib+iink
jc=jb+jink
id=ic+iink
jd=jc+jink
DO l=1,la
i=ibase
j=jbase
!DIR$ IVDEP
DO ijk=1,lot
c(ja+j)=(a(ia+i)+a(ic+i))+(a(ib+i)+a(id+i))
c(jc+j)=(a(ia+i)+a(ic+i))-(a(ib+i)+a(id+i))
d(ja+j)=(b(ia+i)+b(ic+i))+(b(ib+i)+b(id+i))
d(jc+j)=(b(ia+i)+b(ic+i))-(b(ib+i)+b(id+i))
c(jb+j)=(a(ia+i)-a(ic+i))-(b(ib+i)-b(id+i))
c(jd+j)=(a(ia+i)-a(ic+i))+(b(ib+i)-b(id+i))
d(jb+j)=(b(ia+i)-b(ic+i))+(a(ib+i)-a(id+i))
d(jd+j)=(b(ia+i)-b(ic+i))-(a(ib+i)-a(id+i))
i=i+inc3
j=j+inc4
END DO
ibase=ibase+inc1
jbase=jbase+inc2
END DO
IF (la == m) RETURN
la1=la+1
jbase=jbase+jump
DO k=la1,m,la
kb=k+k-2
kc=kb+kb
kd=kc+kb
c1=trigs(kb+1)
s1=trigs(kb+2)
c2=trigs(kc+1)
s2=trigs(kc+2)
c3=trigs(kd+1)
s3=trigs(kd+2)
DO l=1,la
i=ibase
j=jbase
!DIR$ IVDEP
DO ijk=1,lot
c(ja+j)=(a(ia+i)+a(ic+i))+(a(ib+i)+a(id+i))
d(ja+j)=(b(ia+i)+b(ic+i))+(b(ib+i)+b(id+i))
c(jc+j)= &
c2*((a(ia+i)+a(ic+i))-(a(ib+i)+a(id+i))) &
-s2*((b(ia+i)+b(ic+i))-(b(ib+i)+b(id+i)))
d(jc+j)= &
s2*((a(ia+i)+a(ic+i))-(a(ib+i)+a(id+i))) &
+c2*((b(ia+i)+b(ic+i))-(b(ib+i)+b(id+i)))
c(jb+j)= &
c1*((a(ia+i)-a(ic+i))-(b(ib+i)-b(id+i))) &
-s1*((b(ia+i)-b(ic+i))+(a(ib+i)-a(id+i)))
d(jb+j)= &
s1*((a(ia+i)-a(ic+i))-(b(ib+i)-b(id+i))) &
+c1*((b(ia+i)-b(ic+i))+(a(ib+i)-a(id+i)))
c(jd+j)= &
c3*((a(ia+i)-a(ic+i))+(b(ib+i)-b(id+i))) &
-s3*((b(ia+i)-b(ic+i))-(a(ib+i)-a(id+i)))
d(jd+j)= &
s3*((a(ia+i)-a(ic+i))+(b(ib+i)-b(id+i))) &
+c3*((b(ia+i)-b(ic+i))-(a(ib+i)-a(id+i)))
i=i+inc3
j=j+inc4
END DO
ibase=ibase+inc1
jbase=jbase+inc2
END DO
jbase=jbase+jump
END DO
RETURN
!
! CODING FOR FACTOR 5
!
130 ia=1
ja=1
ib=ia+iink
jb=ja+jink
ic=ib+iink
jc=jb+jink
id=ic+iink
jd=jc+jink
ie=id+iink
je=jd+jink
DO l=1,la
i=ibase
j=jbase
!DIR$ IVDEP
DO ijk=1,lot
c(ja+j)=a(ia+i)+(a(ib+i)+a(ie+i))+(a(ic+i)+a(id+i))
d(ja+j)=b(ia+i)+(b(ib+i)+b(ie+i))+(b(ic+i)+b(id+i))
c(jb+j)=(a(ia+i)+cos72*(a(ib+i)+a(ie+i))-cos36*(a(ic+i)+a(id+i))) &
-(sin72*(b(ib+i)-b(ie+i))+sin36*(b(ic+i)-b(id+i)))
c(je+j)=(a(ia+i)+cos72*(a(ib+i)+a(ie+i))-cos36*(a(ic+i)+a(id+i))) &
+(sin72*(b(ib+i)-b(ie+i))+sin36*(b(ic+i)-b(id+i)))
d(jb+j)=(b(ia+i)+cos72*(b(ib+i)+b(ie+i))-cos36*(b(ic+i)+b(id+i))) &
+(sin72*(a(ib+i)-a(ie+i))+sin36*(a(ic+i)-a(id+i)))
d(je+j)=(b(ia+i)+cos72*(b(ib+i)+b(ie+i))-cos36*(b(ic+i)+b(id+i))) &
-(sin72*(a(ib+i)-a(ie+i))+sin36*(a(ic+i)-a(id+i)))
c(jc+j)=(a(ia+i)-cos36*(a(ib+i)+a(ie+i))+cos72*(a(ic+i)+a(id+i))) &
-(sin36*(b(ib+i)-b(ie+i))-sin72*(b(ic+i)-b(id+i)))
c(jd+j)=(a(ia+i)-cos36*(a(ib+i)+a(ie+i))+cos72*(a(ic+i)+a(id+i))) &
+(sin36*(b(ib+i)-b(ie+i))-sin72*(b(ic+i)-b(id+i)))
d(jc+j)=(b(ia+i)-cos36*(b(ib+i)+b(ie+i))+cos72*(b(ic+i)+b(id+i))) &
+(sin36*(a(ib+i)-a(ie+i))-sin72*(a(ic+i)-a(id+i)))
d(jd+j)=(b(ia+i)-cos36*(b(ib+i)+b(ie+i))+cos72*(b(ic+i)+b(id+i))) &
-(sin36*(a(ib+i)-a(ie+i))-sin72*(a(ic+i)-a(id+i)))
i=i+inc3
j=j+inc4
END DO
ibase=ibase+inc1
jbase=jbase+inc2
END DO
IF (la == m) RETURN
la1=la+1
jbase=jbase+jump
DO k=la1,m,la
kb=k+k-2
kc=kb+kb
kd=kc+kb
ke=kd+kb
c1=trigs(kb+1)
s1=trigs(kb+2)
c2=trigs(kc+1)
s2=trigs(kc+2)
c3=trigs(kd+1)
s3=trigs(kd+2)
c4=trigs(ke+1)
s4=trigs(ke+2)
DO l=1,la
i=ibase
j=jbase
!DIR$ IVDEP
DO ijk=1,lot
c(ja+j)=a(ia+i)+(a(ib+i)+a(ie+i))+(a(ic+i)+a(id+i))
d(ja+j)=b(ia+i)+(b(ib+i)+b(ie+i))+(b(ic+i)+b(id+i))
c(jb+j)= &
c1*((a(ia+i)+cos72*(a(ib+i)+a(ie+i))-cos36*(a(ic+i)+a(id+i))) &
-(sin72*(b(ib+i)-b(ie+i))+sin36*(b(ic+i)-b(id+i)))) &
-s1*((b(ia+i)+cos72*(b(ib+i)+b(ie+i))-cos36*(b(ic+i)+b(id+i))) &
+(sin72*(a(ib+i)-a(ie+i))+sin36*(a(ic+i)-a(id+i))))
d(jb+j)= &
s1*((a(ia+i)+cos72*(a(ib+i)+a(ie+i))-cos36*(a(ic+i)+a(id+i))) &
-(sin72*(b(ib+i)-b(ie+i))+sin36*(b(ic+i)-b(id+i)))) &
+c1*((b(ia+i)+cos72*(b(ib+i)+b(ie+i))-cos36*(b(ic+i)+b(id+i))) &
+(sin72*(a(ib+i)-a(ie+i))+sin36*(a(ic+i)-a(id+i))))
c(je+j)= &
c4*((a(ia+i)+cos72*(a(ib+i)+a(ie+i))-cos36*(a(ic+i)+a(id+i))) &
+(sin72*(b(ib+i)-b(ie+i))+sin36*(b(ic+i)-b(id+i)))) &
-s4*((b(ia+i)+cos72*(b(ib+i)+b(ie+i))-cos36*(b(ic+i)+b(id+i))) &
-(sin72*(a(ib+i)-a(ie+i))+sin36*(a(ic+i)-a(id+i))))
d(je+j)= &
s4*((a(ia+i)+cos72*(a(ib+i)+a(ie+i))-cos36*(a(ic+i)+a(id+i))) &
+(sin72*(b(ib+i)-b(ie+i))+sin36*(b(ic+i)-b(id+i)))) &
+c4*((b(ia+i)+cos72*(b(ib+i)+b(ie+i))-cos36*(b(ic+i)+b(id+i))) &
-(sin72*(a(ib+i)-a(ie+i))+sin36*(a(ic+i)-a(id+i))))
c(jc+j)= &
c2*((a(ia+i)-cos36*(a(ib+i)+a(ie+i))+cos72*(a(ic+i)+a(id+i))) &
-(sin36*(b(ib+i)-b(ie+i))-sin72*(b(ic+i)-b(id+i)))) &
-s2*((b(ia+i)-cos36*(b(ib+i)+b(ie+i))+cos72*(b(ic+i)+b(id+i))) &
+(sin36*(a(ib+i)-a(ie+i))-sin72*(a(ic+i)-a(id+i))))
d(jc+j)= &
s2*((a(ia+i)-cos36*(a(ib+i)+a(ie+i))+cos72*(a(ic+i)+a(id+i))) &
-(sin36*(b(ib+i)-b(ie+i))-sin72*(b(ic+i)-b(id+i)))) &
+c2*((b(ia+i)-cos36*(b(ib+i)+b(ie+i))+cos72*(b(ic+i)+b(id+i))) &
+(sin36*(a(ib+i)-a(ie+i))-sin72*(a(ic+i)-a(id+i))))
c(jd+j)= &
c3*((a(ia+i)-cos36*(a(ib+i)+a(ie+i))+cos72*(a(ic+i)+a(id+i))) &
+(sin36*(b(ib+i)-b(ie+i))-sin72*(b(ic+i)-b(id+i)))) &
-s3*((b(ia+i)-cos36*(b(ib+i)+b(ie+i))+cos72*(b(ic+i)+b(id+i))) &
-(sin36*(a(ib+i)-a(ie+i))-sin72*(a(ic+i)-a(id+i))))
d(jd+j)= &
s3*((a(ia+i)-cos36*(a(ib+i)+a(ie+i))+cos72*(a(ic+i)+a(id+i))) &
+(sin36*(b(ib+i)-b(ie+i))-sin72*(b(ic+i)-b(id+i)))) &
+c3*((b(ia+i)-cos36*(b(ib+i)+b(ie+i))+cos72*(b(ic+i)+b(id+i))) &
-(sin36*(a(ib+i)-a(ie+i))-sin72*(a(ic+i)-a(id+i))))
i=i+inc3
j=j+inc4
END DO
ibase=ibase+inc1
jbase=jbase+inc2
END DO
jbase=jbase+jump
END DO
RETURN
END SUBROUTINE vpassm