[Search for users] [Overall Top Noters] [List of all Conferences] [Download this site]

Conference turris::fortran

Title:Digital Fortran
Notice:Read notes 1.* for important information
Moderator:QUARK::LIONEL
Created:Thu Jun 01 1995
Last Modified:Fri Jun 06 1997
Last Successful Update:Fri Jun 06 1997
Number of topics:1333
Total number of notes:6734

1246.0. "fft again ..." by RTOMS::PARETIJ () Sun Mar 30 1997 16:46

      The following code does some sort of fft; there
      are 2 routines fft_ce and FFT_se calling cosft1 (sinft1) and
      realft calling four1. There are no comments, which strains
      my imagination. I am again looking for a way to use dxml.
      May be putting the code out to the forum will generate some
      questions I could refer to the customer.


	subroutine fft_ce(A,Re_,Im_,nx,ny,isign)
	implicit none
	integer nx,ny,isign
	real*8 A(0:nx,0:ny-1),Re_(0:nx,0:ny/2),Im_(0:nx,0:ny/2)
	integer i,j
	real*8 vec_x(0:nx), vec_y(0:ny-1)

	if(isign.eq.1)then

	do j=0,ny-1
	  do i=0,nx
	    vec_x(i)=A(i,j)
	  enddo
	  call cosft1(vec_x,nx)
	  A(0,j)=vec_x(0)/nx
	  do i=1,nx-1
	    A(i,j)=vec_x(i)*2/nx
	  enddo
	  A(nx,j)=vec_x(nx)/nx
	enddo
	do i=0,nx
	   do j=0,ny-1
	    vec_y(j)=A(i,j)
	   enddo
	   call realft(vec_y,ny,isign)
	   Re_(i,0)=vec_y(0)/ny
	   Im_(i,0)=0
	   do j=1,ny/2-1
	      Re_(i,j)=vec_y(2*j)/ny
	      Im_(i,j)=-vec_y(2*j+1)/ny
	   enddo
       Re_(i,ny/2)=0.5*vec_y(1)/ny
	   Im_(i,ny/2)=0
	enddo

	else

	do i=0,nx
		vec_y(0)=2*Re_(i,0)
		vec_y(1)=4*Re_(i,ny/2)
		do j=1,ny/2-1
			vec_y(2*j)=2*Re_(i,j)
			vec_y(2*j+1)=-2*Im_(i,j)
		enddo
		call realft(vec_y,ny,isign)
	    do j=0,ny-1
 			A(i,j)=vec_y(j)
	    enddo
	enddo
	do j=0,ny-1
	  vec_x(0)=2*A(0,j)
	  do i=1,nx-1
	    vec_x(i)=A(i,j)
	  enddo
	  vec_x(nx)=2*A(nx,j)
	  call cosft1(vec_x,nx)
	  do i=0,nx
	    A(i,j)=vec_x(i)
	  enddo
	enddo

	endif

	end
	
	
	
	subroutine fft_se(A,Re_,Im_,nx,ny,isign)
	implicit none
	integer nx,ny,isign
	real*8 A(0:nx,0:ny-1),Re_(0:nx,0:ny/2),Im_(0:nx,0:ny/2)
	integer i,j
	real*8 vec_x(0:nx-1), vec_y(0:ny-1)

	if(isign.eq.1)then

	do j=0,ny-1
	  vec_x(0)=0
	  do i=1,nx-1
	    vec_x(i)=A(i,j)
	  enddo
	  call sinft(vec_x,nx)
	  do i=0,nx-1
	    A(i,j)=vec_x(i)*2/nx
	  enddo
	enddo
	do i=1,nx-1
	   do j=0,ny-1
	    vec_y(j)=A(i,j)
	   enddo
	   call realft(vec_y,ny,isign)
	   Re_(i,0)=vec_y(0)/ny
	   Im_(i,0)=0
	   do j=1,ny/2-1
	      Re_(i,j)=vec_y(2*j)/ny
	      Im_(i,j)=-vec_y(2*j+1)/ny
	   enddo
       Re_(i,ny/2)=0.5*vec_y(1)/ny
	   Im_(i,ny/2)=0
	enddo
	do j=0,ny/2
		Re_(0,j)=0
		Im_(0,j)=0
		Re_(nx,j)=0
		Im_(nx,j)=0
	enddo

	else

	do i=1,nx-1
		vec_y(0)=2*Re_(i,0)
		vec_y(1)=4*Re_(i,ny/2)
		do j=1,ny/2-1
			vec_y(2*j)=2*Re_(i,j)
			vec_y(2*j+1)=-2*Im_(i,j)
		enddo
		call realft(vec_y,ny,isign)
	    do j=0,ny-1
 			A(i,j)=vec_y(j)
	    enddo
	enddo
	do j=0,ny-1
	  vec_x(0)=0
	  do i=1,nx-1
	    vec_x(i)=A(i,j)
	  enddo
	  call sinft(vec_x,nx)
	  do i=0,nx-1
	    A(i,j)=vec_x(i)
	  enddo
	enddo
	do j=0,ny-1
		A(nx,j)=0
	enddo

	endif

	end
	
	
      SUBROUTINE four1(data,nn,isign)
      INTEGER isign,nn
      real*8 data(2*nn)
      INTEGER i,istep,j,m,mmax,n
      real*8 tempi,tempr
      DOUBLE PRECISION theta,wi,wpi,wpr,wr,wtemp
      n=2*nn
      j=1
      do 11 i=1,n,2
        if(j.gt.i)then
          tempr=data(j)
          tempi=data(j+1)
          data(j)=data(i)
          data(j+1)=data(i+1)
          data(i)=tempr
          data(i+1)=tempi
        endif
        m=n/2
1       if ((m.ge.2).and.(j.gt.m)) then
          j=j-m
          m=m/2
        goto 1
        endif
        j=j+m
11    continue
      mmax=2
2     if (n.gt.mmax) then
        istep=2*mmax
        theta=6.28318530717959d0/(isign*mmax)
        wpr=-2.d0*dsin(0.5d0*theta)**2
        wpi=dsin(theta)
        wr=1.d0
        wi=0.d0
        do 13 m=1,mmax,2
          do 12 i=m,n,istep
            j=i+mmax
            tempr=(wr)*data(j)-(wi)*data(j+1)
            tempi=(wr)*data(j+1)+(wi)*data(j)
            data(j)=data(i)-tempr
            data(j+1)=data(i+1)-tempi
            data(i)=data(i)+tempr
            data(i+1)=data(i+1)+tempi
12        continue
          wtemp=wr
          wr=wr*wpr-wi*wpi+wr
          wi=wi*wpr+wtemp*wpi+wi
13      continue
        mmax=istep
      goto 2
      endif
      return
      END
      
      
	SUBROUTINE realft(data,n,isign)
      INTEGER isign,n
      real*8 data(n)
CU    USES four1
      INTEGER i,i1,i2,i3,i4,n2p3
      real*8 c1,c2,h1i,h1r,h2i,h2r,wis,wrs
      DOUBLE PRECISION theta,wi,wpi,wpr,wr,wtemp
      theta=3.141592653589793d0/dble(n/2)
      c1=0.5
      if (isign.eq.1) then
        c2=-0.5
        call four1(data,n/2,+1)
      else
        c2=0.5
        theta=-theta
      endif
      wpr=-2.0d0*dsin(0.5d0*theta)**2
      wpi=dsin(theta)
      wr=1.0d0+wpr
      wi=wpi
      n2p3=n+3
      do 11 i=2,n/4
        i1=2*i-1
        i2=i1+1
        i3=n2p3-i2
        i4=i3+1
        wrs=(wr)
        wis=(wi)
        h1r=c1*(data(i1)+data(i3))
        h1i=c1*(data(i2)-data(i4))
        h2r=-c2*(data(i2)+data(i4))
        h2i=c2*(data(i1)-data(i3))
        data(i1)=h1r+wrs*h2r-wis*h2i
        data(i2)=h1i+wrs*h2i+wis*h2r
        data(i3)=h1r-wrs*h2r+wis*h2i
        data(i4)=-h1i+wrs*h2i+wis*h2r
        wtemp=wr
        wr=wr*wpr-wi*wpi+wr
        wi=wi*wpr+wtemp*wpi+wi
11    continue
      if (isign.eq.1) then
        h1r=data(1)
        data(1)=h1r+data(2)
        data(2)=h1r-data(2)
      else
        h1r=data(1)
        data(1)=c1*(h1r+data(2))
        data(2)=c1*(h1r-data(2))
        call four1(data,n/2,-1)
      endif
      return
      END


	SUBROUTINE sinft(y,n)
      INTEGER n
      real*8 y(n)
CU    USES realft
      INTEGER j
      real*8 sum,y1,y2
      DOUBLE PRECISION theta,wi,wpi,wpr,wr,wtemp
      theta=3.141592653589793d0/dble(n)
      wr=1.0d0
      wi=0.0d0
      wpr=-2.0d0*dsin(0.5d0*theta)**2
      wpi=dsin(theta)
      y(1)=0.0
      do 11 j=1,n/2
        wtemp=wr
        wr=wr*wpr-wi*wpi+wr
        wi=wi*wpr+wtemp*wpi+wi
        y1=wi*(y(j+1)+y(n-j+1))
        y2=0.5*(y(j+1)-y(n-j+1))
        y(j+1)=y1+y2
        y(n-j+1)=y1-y2
11    continue
      call realft(y,n,+1)
      sum=0.0
      y(1)=0.5*y(1)
      y(2)=0.0
      do 12 j=1,n-1,2
        sum=sum+y(j)
        y(j)=y(j+1)
        y(j+1)=sum
12    continue
      return
      END

     
	SUBROUTINE cosft1(y,n)
      INTEGER n
      real*8 y(n+1)
CU    USES realft
      INTEGER j
      real*8 sum,y1,y2
      DOUBLE PRECISION theta,wi,wpi,wpr,wr,wtemp
      theta=3.141592653589793d0/n
      wr=1.0d0
      wi=0.0d0
      wpr=-2.0d0*dsin(0.5d0*theta)**2
      wpi=dsin(theta)
      sum=0.5*(y(1)-y(n+1))
      y(1)=0.5*(y(1)+y(n+1))
      do 11 j=1,n/2-1
        wtemp=wr
        wr=wr*wpr-wi*wpi+wr
        wi=wi*wpr+wtemp*wpi+wi
        y1=0.5*(y(j+1)+y(n-j+1))
        y2=(y(j+1)-y(n-j+1))
        y(j+1)=y1-wi*y2
        y(n-j+1)=y1+wi*y2
        sum=sum+wr*y2
11    continue
      call realft(y,n,+1)
      y(n+1)=y(2)
      y(2)=sum
      do 12 j=4,n,2
        sum=sum+y(j)
        y(j)=sum
12    continue
      return
      END
T.RTitleUserPersonal
Name
DateLines
1246.1RTL::HANEKMon Mar 31 1997 11:4629
First off, it would be best to move this discussion to the (NICCTR::)DXML
notes file.

It appears to me that the routines cosft1, sinft1, realft and four1 are
performing text book implementations of cosine, sine, real Fourier and
complex Fourier transforms.  four1( data, nn, isign ) is a standard
Cooley-Tukey in-place complex Fourier transform of length nn, with isign
indicating the direction of the transform (forward or backward).  The same
calling convention extends to the other routines. Each of the routines cosft1,
sinf1, realft and four1 have direct counter parts in the DXML, so you should be
able to replace them with calls into the DXML.  There may be some issues with
scaling the results by a constant depending on how the DXML routines are
implemented 

There seems to be lots of opportunities for performance improvements here beyond
simply using the DXML. Two in particular seem worth mentioning:

All fft codes use "tables" of sin and cos values.  The user code presentd in .-1
generates these tables on the fly which can be very inefficient if the length of
the fft remains constant over several invocations of the fft routines.  The DXML
provides  routines that can either generate the table on the fly, or pre-compute
it. Perhaps you should look into pre-computing the table.

Second, the fft_ce routine appears to be performing a kind of 2-dimensional
cosine tranform by transforming each of the columns and then each of the
rows.  It seems to me that this operation can be implemented using a
2-dimensional real fft (which the DXML supports) by either pre-conditioning the
input data or "fixing up" the result of the 2-dimensional.