      program mtmsvdspec
c
c     Copyright (C) 1995
c
c     Michael Mann
c
c     MTM-SVD -- evolutive/fixed window  LFV spectrum estimation
c
c     v1.0
c
c     uses  original  multitaper spectral code of Jeffrey Park (c) 
c
c   mmax     - maximum number of spatial dofs desired (ie, max # of time series)
c   ntapmax  - maximum number of spectral dofs desired
c   ifmax    - maximum padded DFT length (maximum=8192)
c   nscanmax - maximum length of time series
c
c
      parameter (mmax=25,
     $           nscanmax=1200,ntapmax=3,ifmax=4096)
c
      character*19 filename
      character*1 cfnum
      complex *8 AAA(mmax,ntapmax,ifmax)
      complex *16 AA(mmax,ntapmax),UU(mmax,mmax),VV(ntapmax,ntapmax)
      real*8 ell
      real *8 S(ntapmax),sum
      real *8 partsum(ntapmax)
      real ar,ai
      real weight(mmax),a(nscanmax,mmax),anew(nscanmax,mmax)
      real datave(mmax),sd(mmax)
      real var
      common/npiprol/anpi
      common/nnaamm/iwflag
      common/work/b1(8194)
      common/taperz/ta(4100,16,2),tai(4100,16,2),dcf(4100,16,2),
     $          amu(4100,4)
      common/stap2/tas(8192,16)
      common/envel1/ell(20)
c
c
      iwflag=0
      zero = 0.0
      one = 1.0
      two = 2.0
      pi=3.14159265358979

c
c     dt    = time interval spacing in units of years
c     nscan = length of time series in units of "dt"
c     iabv  = number of time series in analysis (ie, "spatial" array)
c
c     presently set for 25 records of 1 month resolution and 100 year
c     length (** make sure array dimensions are large enough:
c          "ifmax" must be greater than nscan **)
c     so nscan = 100*12 = 1200, iabv = 25
c
c     dt = 1/12 so that time units/frequencies will be in terms
c     of annual time units
c
c     **** THESE SETTINGS ARE DATASET DEPENDENT!!! ****
c
      dt = 0.083333
      nscan = 1200
      iabv = 25
c
c     set frequency range for DFT, frequency spacing, zero
c     padding, etc.
c     ** NOTE: maximum padded DFT length is npad=8192 **
c
c     f1 = minimum frequency for analysis = 0
c     f2 = maximum frequency  (in cyc/year -- this can be varied up to
c          the nyquist sampling frequency = 0.5/dt)
c
c     ( presently set for the range 0 to 0.5 cycle year, or, periods greater
c      than tau=2 years. This is a smaller fraction of the full Nyquist
c      interval f=0 to f=6.0 cycle/year for monthly sampling)
c
      f1 = 0.0
      f2 = 0.5

c     default settings
c 
      npi = 2
      anpi=float(npi)
      nwin=3
      itype = 0
      nbeg=1
      nend = nscan
      neval = nscan
      nmove = nscan
      ninterv = nscan

444   write (6,*) 'present settings'
      write (6,*) '1) use',nwin, ' x ',npi,' pi tapers'
      write (6,*) '2) data interval (',nbeg,' to ',nend,' )'
      if (itype.eq.0) then 
        write (6,*) '3) fixed window analysis'
      else
         write (6,*) '3) evolutive analysis'
         write (6,*) '    --',nmove,' unit moving window'
         write (6,*) '    --',ninterv,' unit time step'
      endif
c      write (6,*) '-----------------'
      write (6,*) 'item to change (0=continue)'
      read (5,*) icont
      if (icont.eq.1) then
         goto 1111
      else
        if (icont.eq.2) then
           goto 2222
        else
           if (icont.eq.3) then
              goto 3333
           else
              goto 9999
           endif
        endif
      endif


1111  write (6,*) 'time-frequency bandwidth product "p"'
      read (5,*) npinew
      if (ntapmax.lt.2*npinew-1) then
         write (6,*) 'sorry--exceeds maximum bandwidth'
      else
         write (6,*) 'number of tapers'
         read (5,*) nwinnew
         if (nwinnew.gt.2*npinew-1) then
           write (6,*) 'sorry--cannot exceed 2*p-1'
         else
           npi=npinew
           anpi = float(npi)
           nwin=nwinnew
         endif
      endif
      goto 444

2222  write (6,*) 'beginning time index'
      read (5,*) nbeg
      write (6,*) 'ending time index'
      read (5,*) nend
      nmove = nend-nbeg+1
      neval = nmove
      ninterv = nmove
      goto 444

3333  write (6,*) 'choose'
      write (6,*) '(0) fixed window'
      write (6,*) '(1) evolutive analysis'
      read (5,*) itype
      if (itype.eq.1) then
         write (6,*) 'window width (in samples--e.g., # months)'
         read (5,*) nmove
         write (6,*) 'interval between evaluations (in samples " )'
         read (5,*) ninterv
      endif
      goto 444
c
c     npad = zero padding (power of two--must be > nscan)
c
c
9999  npad=4096
c
c     calculate frequency spacing, etc.
c
      ddf=1./(npad*dt)
      eps=.1*ddf
      nf1=(f1+eps)/ddf
      nf2=(f2+eps)/ddf
      nf=nf2-nf1+1
      nfmax = nf-1
c
c     set spatial, spectral dimensions for SVD matrix
c
      M = iabv
      N = nwin
      NV = N
      NU = N
      IP = 0
c
c     read in data.
c
c     * THIS SECTION WILL HAVE TO MODIFIED DEPENDING ON THE DATA
c       ANALYZED *
c
      open (unit=9,file='synth1.dat',
     $         status='old')
c   
      open (unit=10,file='synth2.dat',
     $         status='old')
c
      open (unit=11,file='synth3.dat',
     $         status='old')
c
      open (unit=12,file='synth4.dat',
     $         status='old')
c
      open (unit=13,file='synth5.dat',
     $         status='old')
c
c    read in the iabv=25 gridpoints from the
c    five files of 5 gridpoint series/file
c
      do j=1,nscan
          read (9,*) adum,(a(j,jnode),jnode=1,5)
          read (10,*) adum,(a(j,jnode),jnode=6,10)
          read (11,*) adum,(a(j,jnode),jnode=11,15)
          read (12,*) adum,(a(j,jnode),jnode=16,20)
          read (13,*) adum,(a(j,jnode),jnode=21,25)
      end do
      close (unit=9)
      close (unit=10)
      close (unit=11)
      close (unit=12)
      close (unit=13)
c
c     set uniform weights on each of the gridpoints. This is where
c     we might normally want to set gridpoint dependent weights
c     e.g., cos(latitude) weighting to provide areal representivity
c     to the decomposition, etc. For simplicity, we set the weights
c     as uniform here.
c
      do j=1,iabv
         weight(j)=one
      end do
c
777   format (11f6.2)
c
c
c
      write (6,*) 'read in: '
      write (6,*) iabv, ' time series'
      write (6,*) nscan, ' sequential time snapshots of data...'
c
c     for each time series, subtract mean, normalize by standard 
c     deviation for each month,
c     also set weights for the different dataseries. 
c     ( for the the present case, all dataseries are equally weighted for
c       analysis)
c
c
      open (unit=15,file='svd-means.out',
     $     status='unknown')
      open (unit=16,file='svd-sigmas.out',
     $     status='unknown')
      do j=1,iabv
         sum=0.0
         var = 0.0
         do i=nbeg,nend
            sum=sum+a(i,j)
         end do
         datave(j)=sum/float(neval)
         inew = 0
         do i=nbeg,nend
           inew = inew+1
           anew(inew,j)=a(i,j)-datave(j)
           var =var + anew(inew,j)**2
         end do
         sd(j)=sqrt(var/float(neval))
         do i=1,neval
           anew(i,j)=weight(j)*anew(i,j)/sd(j)
         end do
         write (15,*) j,datave(j)
         write (16,*) j,sd(j)
      end do 
      close (unit=15)
      close (unit=16)
c            
c     open output files
c
      do i=1,nwin
        cfnum = char(48+i)
        filename = 'evals-'//cfnum//'.out'
        open (unit=13+i-1,file=filename,
     $     status='unknown')
      end do
c
c     construct tapers appropriate for window width
c
      npts = nmove
      call taper(npts,nwin,ell)
c
      write (6,*) 'nscan ',nscan
      write (6,*) 'neval ',neval
      write (6,*) 'nbeg ',nbeg
      write (6,*) 'nend ',nend
      write (6,*) 'dt    ',dt
      write (6,*) 'nmove ',nmove
      write (6,*) 'ninterv ',ninterv
      niter = (neval-nmove)/ninterv + 1
      write (6,*) 'beginning 1st of ',niter, ' iteration/s...'
c
c     begin moving time window loop
c
      do it = 1,niter
        n1 = 1+(it-1)*ninterv
        n2 = n1+npts-1
        ncent = (n1+n2-1)/2
c
c       calculate DFTs for each gridpoint
c
        do ii=1,iabv
c        demean gridpoint series locally
         sum = 0.
         do i=n1,n2
            sum = sum+anew(i,ii)
         end do
         sum = sum/float(n2-n1+1)
         do iwin=1,nwin
          do i=1,npad
             b1(i)=0.
          end do
          do i=n1,n2
            b1(i-n1+1)=(anew(i,ii)-sum)*tas(i+1-n1,iwin)
          end do
          call realft(b1,npad/2,1)
          b1(npad-1)=b1(2)
          b1(npad)=0.
          b1(2)=0.
          do iif=1,nfmax
           iwhere = 2*(nf1+iif)-1
           ar=b1(iwhere)
           ai=b1(iwhere+1)
           AAA(ii,iwin,iif)=cmplx(ar,ai)
          end do
         end do
c
c       terminate DFT calculation
c
        end do
c
c       perform SVD for given time and frequency
c
        do iif =1,nfmax
         do ii=1,iabv
           do iwin=1,nwin
              AA(ii,iwin)=1.d0*AAA(ii,iwin,iif)
           end do
         end do
c     
c        perform SVD 
c
         call CSVD(AA,mmax,nwin,M,N,IP,NU,NV,S,UU,VV)
c
c
c        determine local fractional variances 
c
         sum = 0.d0
         do i=1,nwin
          sum = sum + S(i)**2
          partsum(i)=0.0
          do j=i,nwin
            partsum(i)=partsum(i)+S(j)**2
          end do
         end do
         freq = (iif-1)*ddf+f1
         singval = real(S(1))
         fracvar = real(S(1)**2/sum)
         if (itype.eq.1) then
          write (13,6666) freq,float(ncent+nbeg-1)*dt,
     $       fracvar,singval,iif
         else
          write (13,7777) freq,fracvar,singval,iif
         endif
         do i=2,nwin
          singval = real(S(i))
          fracvar = real(S(i)**2/sum)
          partvar = real(S(i)**2/partsum(i))
          if (itype.eq.1) then
               write (13+i-1,888) freq,float(ncent+nbeg-1)*dt,
     $           partvar,fracvar,singval,iif
          else
            write (13+i-1,999) freq, partvar,fracvar,singval,iif
          endif
         end do
c
c       terminate frequency loop
c
        end do
c  
c       provide progress update
c
        open (unit=12,file='svdevals-synth.status',
     $         status='unknown')
        if ((niter.ge.10).and.(mod(it-1,niter/10).eq.0)) then
         write (12,*) it,' iterations of ',niter,' done...'
         write (6,*) it,' iterations of ',niter,' done...'
        endif
        close (unit=12)
c
c       terminate time loop
c
      end do
      write (6,*) 'done.'
c
c     done -- close files
c
      do i=1,nwin
         close (unit=13+i-1)
      end do 
      close (unit=33)
888   format (f9.4,f6.2,2f9.4,f12.4,i6)
999   format (f9.4,2f9.4,f12.4,i6)
6666  format (f9.4,f6.2,f9.4,f12.4,i6)
7777  format (f9.4,f9.4,f12.4,i6)
      stop
      end
c
c
c
      subroutine taper(n,nwin,el)
c
c  to generate slepian tapers
c  ta is a real*4 array
c
c         j. park
c
      real*8 el,a,z,pi,ww,cs,ai,an,eps,rlu,rlb
      real*8 dfac,drat,gamma,bh,ell
      common/nnaamm/iwflag
      common/npiprol/anpi
      common/tapsum/tapsum(20),ell(20)
      common/work/ip(8194)        
      common/taperzz/z(65536)  ! we use this common block for scratch space
      common/stap2/ta(8192,16)
      dimension a(8192,8),el(10)
      data iwflag/0/,pi/3.14159265358979d0/
      equivalence (a(1,1),ta(1,1))
      an=dfloat(n)
      ww=dble(anpi)/an
      cs=dcos(2.d0*pi*ww)
c initialize matrix for eispack subroutine
c      type *,'ww,cs,an',ww,cs,an
      do i=0,n-1
        ai=dfloat(i)
        a(i+1,1)=-cs*((an-1.d0)/2.d0-ai)**2
        a(i+1,2)=-ai*(an-ai)/2.d0
        a(i+1,3)=a(i+1,2)**2        ! required by eispack routine
      end do
      eps=1.e-13
      m11=1
      call tridib(n,eps,a(1,1),a(1,2),a(1,3),rlb,rlu,m11,nwin,el,ip,
     x       ierr,a(1,4),a(1,5))
c      type *,ierr,rlb,rlu
c      call tnou('eigenvalues for the eigentapers')
c      type *,(el(i),i=1,nwin)
      call tinvit(n,n,a(1,1),a(1,2),a(1,3),nwin,el,ip,z,ierr,
     x            a(1,4),a(1,5),a(1,6),a(1,7),a(1,8))      
c  we calculate the eigenvalues of the dirichlet-kernel problem
c  i.e. the bandwidth retention factors
c  from slepian 1978 asymptotic formula, gotten from thomson 1982 eq 2.5
c  supplemented by the asymptotic formula for k near 2n from slepian 1978 eq 61
      dfac=an*pi*ww
      drat=8.d0*dfac
      dfac=4.d0*dsqrt(pi*dfac)*dexp(-2.d0*dfac)
      do k=1,nwin
        el(k)=1.d0-dfac
        dfac=dfac*drat/k  ! is this correct formula? yes,but fails as k -> 2n
      end do
c      call tnou('eigenvalues for the eigentapers (small k)')
c      type *,(el(i),i=1,nwin)
      gamma=dlog(8.d0*an*dsin(2.d0*pi*ww))+0.5772156649d0
      do k=1,nwin
        bh=-2.d0*pi*(an*ww-dfloat(k-1)/2.d0-.25d0)/gamma
        ell(k)=1.d0/(1.d0+dexp(pi*bh))
      end do
c      call tnou('eigenvalues for the eigentapers (k near 2n)')
c      type *,(ell(i),i=1,nwin)
      do i=1,nwin
        el(i)=dmax1(ell(i),el(i))
      end do     
c      call tnou('composite asymptotics for taper eigenvalues')
c      type *,(el(i),i=1,nwin)  
c   normalize the eigentapers to preserve power for a white process
c   i.e. they have rms value unity
      do k=1,nwin
        kk=(k-1)*n
        tapsum(k)=0.
        tapsq=0.
        do i=1,n
          aa=z(kk+i)
          ta(i,k)=aa
          tapsum(k)=tapsum(k)+aa
          tapsq=tapsq+aa*aa
        end do
        aa=sqrt(tapsq/n)
        tapsum(k)=tapsum(k)/aa
        do i=1,n
          ta(i,k)=ta(i,k)/aa
        end do
      end do
c      type *,'tapsum',(tapsum(i),i=1,nwin)
c  refft preserves amplitudes with zeropadding
c  zum beispiel: a(i)=1.,i=1,100 will transform at zero freq to b(f=0.)=100
c  no matter how much zero padding is done
c  therefore we need not doctor the taper normalization,
c  but wait until the fft to force the desired units
      iwflag=1
      return
      end
c
c
c
      SUBROUTINE CSVD (A,MMAX,NMAX,M,N,IP,NU,NV,S,U,V)
C
C   Singular value decomposition of an  M by N  complex matrix  A,
C   where M .GT. N .  The singular values are stored in the vector
C   S. The first NU columns of the M by M unitary matrix U and the
C   first NV columns of the N by N unitary matrix V  that minimize
C   Det(A-USV*) are also computed.
C
C
C         P.A. Businger and G.H. Golub, "Singular Value Decomposition
C         of a Complex Matrix," Communications of the ACM, vol. 12,
C         pp. 564-565, October 1969.
C
C   This algorithm is reprinted by permission, Association for
C   Computing Machinery; copyright 1969.
C
      parameter (nwork=10000)
      COMPLEX *16 A(MMAX,NMAX),U(MMAX,MMAX),V(NMAX,NMAX),Q,R
      REAL *8 S(NMAX),B(nwork),C(nwork),T(nwork),zero,one,ETA,TOL,
     $        EPS
      ETA = 1.2d-7
      TOL = 2.4d-32
      zero = 0.d0
      one = 1.d0
      NP=N+IP
      N1=N+1
C   Householder reduction
      C(1)=zero
      K=1
10    K1=K+1
C   Elimination of A(I,K) , I=K+1,...,M
      Z=zero
      DO 20 I=K,M
20      Z=Z+REAL(A(I,K))**2+dIMAG(A(I,K))**2
      B(K)=zero
      IF (Z .LE. TOL)  GO TO 70
      Z=SQRT(Z)
      B(K)=Z
      W=CdABS(A(K,K))
      Q=dcmplx(one,zero)
      IF (W .NE. zero)  Q=A(K,K)/W
      A(K,K)=Q*(Z+W)
      IF (K .EQ. NP)  GO TO 70
      DO 50 J=K1,NP
        Q=dcmplx(zero,zero)
        DO 30 I=K,M
30        Q=Q+dCONJG(A(I,K))*A(I,J)
        Q=Q/(Z*(Z+W))
        DO 40 I=K,M
40        A(I,J)=A(I,J)-Q*A(I,K)
50      CONTINUE
C   Phase transformation
      Q=-dCONJG(A(K,K))/CdABS(A(K,K))
      DO 60 J=K1,NP
60      A(K,J)=Q*A(K,J)
C   Elimination of A(K,J) , J=K+2,...,N
70    IF (K .EQ. N)  GO TO 140
      Z=zero
      DO 80 J=K1,N
80      Z=Z+REAL(A(K,J))**2+dIMAG(A(K,J))**2
      C(K1)=zero
      IF (Z .LE. TOL)  GO TO 130
      Z=SQRT(Z)
      C(K1)=Z
      W=CdABS(A(K,K1))
      Q=dcmplx(one,zero)
      IF (W .NE. zero)  Q=A(K,K1)/W
      A(K,K1)=Q*(Z+W)
      DO 110 I=K1,M
        Q=dcmplx(zero,zero)
        DO 90 J=K1,N
90        Q=Q+dCONJG(A(K,J))*A(I,J)
        Q=Q/(Z*(Z+W))
        DO 100 J=K1,N
100       A(I,J)=A(I,J)-Q*A(K,J)
110     CONTINUE
C   Phase transformation
      Q=-dCONJG(A(K,K1))/CdABS(A(K,K1))
      DO 120 I=K1,M
120     A(I,K1)=A(I,K1)*Q
130   K=K1
      GO TO 10
C   Tolerance for negligible elements
140   EPS=zero
      DO 150 K=1,N
        S(K)=B(K)
        T(K)=C(K)
150   EPS=DMAX1(EPS,S(K)+T(K))
      EPS=EPS*ETA
C   Initialization of U and V
      IF (NU .EQ. 0)  GO TO 180
      DO 170 J=1,NU
        DO 160 I=1,M
160       U(I,J)=dcmplx(zero,zero)
170     U(J,J)=dcmplx(one,zero)
180   IF (NV .EQ. 0)  GO TO 210
      DO 200 J=1,NV
        DO 190 I=1,N
190       V(I,J)=dcmplx(zero,zero)
200     V(J,J)=dcmplx(one,zero)
C   QR diagonalization
210   DO 380 KK=1,N
        K=N1-KK
C   Test for split
220     DO 230 LL=1,K
          L=K+1-LL
          IF (ABS(T(L)) .LE. EPS)  GO TO 290
          IF (ABS(S(L-1)) .LE. EPS)  GO TO 240
230       CONTINUE
C   Cancellation of B(L)
240     CS=zero
        SN=one
        L1=L-1
        DO 280 I=L,K
          F=SN*T(I)
          T(I)=CS*T(I)
          IF (ABS(F) .LE. EPS)  GO TO 290
          H=S(I)
          W=SQRT(F*F+H*H)
          S(I)=W
          CS=H/W
          SN=-F/W
          IF (NU .EQ. 0)  GO TO 260
          DO 250 J=1,N
            X=REAL(U(J,L1))
            Y=REAL(U(J,I))
            U(J,L1)=dCMPLX(X*CS+Y*SN,0.)
250         U(J,I)=dCMPLX(Y*CS-X*SN,0.)
260       IF (NP .EQ. N)  GO TO 280
          DO 270 J=N1,NP
            Q=A(L1,J)
            R=A(I,J)
            A(L1,J)=Q*CS+R*SN
270         A(I,J)=R*CS-Q*SN
280       CONTINUE
C   Test for convergence
290     W=S(K)
        IF (L .EQ. K)  GO TO 360
C   Origin shift
        X=S(L)
        Y=S(K-1)
        G=T(K-1)
        H=T(K)
        F=((Y-W)*(Y+W)+(G-H)*(G+H))/(2.d0*H*Y)
        G=SQRT(F*F+one)
        IF (F .LT. zero)  G=-G
        F=((X-W)*(X+W)+(Y/(F+G)-H)*H)/X
C   QR step
        CS=one
        SN=one
        L1=L+1
        DO 350 I=L1,K
          G=T(I)
          Y=S(I)
          H=SN*G
          G=CS*G
          W=SQRT(H*H+F*F)
          T(I-1)=W
          CS=F/W
          SN=H/W
          F=X*CS+G*SN
          G=G*CS-X*SN
          H=Y*SN
          Y=Y*CS
          IF (NV .EQ. 0)  GO TO 310
          DO 300 J=1,N
            X=REAL(V(J,I-1))
            W=REAL(V(J,I))
            V(J,I-1)=dCMPLX(X*CS+W*SN,0.)
300         V(J,I)=dCMPLX(W*CS-X*SN,0.)
310       W=SQRT(H*H+F*F)
          S(I-1)=W
          CS=F/W
          SN=H/W
          F=CS*G+SN*Y
          X=CS*Y-SN*G
          IF (NU .EQ. 0)  GO TO 330
          DO 320 J=1,N
            Y=REAL(U(J,I-1))
            W=REAL(U(J,I))
            U(J,I-1)=dCMPLX(Y*CS+W*SN,0.)
320         U(J,I)=dCMPLX(W*CS-Y*SN,0.)
330       IF (N .EQ. NP)  GO TO 350
          DO 340 J=N1,NP
            Q=A(I-1,J)
            R=A(I,J)
            A(I-1,J)=Q*CS+R*SN
340         A(I,J)=R*CS-Q*SN
350       CONTINUE
        T(L)=zero
        T(K)=F
        S(K)=X
        GO TO 220
C   Convergence
360     IF (W .GE. zero)  GO TO 380
        S(K)=-W
        IF (NV .EQ. 0)  GO TO 380
        DO 370 J=1,N
370       V(J,K)=-V(J,K)
380     CONTINUE
C   Sort singular values
      DO 450 K=1,N
        G=-one
        J=K
        DO 390 I=K,N
          IF (S(I) .LE. G)  GO TO 390
          G=S(I)
          J=I
390       CONTINUE
        IF (J .EQ. K)  GO TO 450
        S(J)=S(K)
        S(K)=G
        IF (NV .EQ. 0)  GO TO 410
        DO 400 I=1,N
          Q=V(I,J)
          V(I,J)=V(I,K)
400       V(I,K)=Q
410     IF (NU .EQ. 0)  GO TO 430
        DO 420 I=1,N
          Q=U(I,J)
          U(I,J)=U(I,K)
420       U(I,K)=Q
430     IF (N .EQ. NP)  GO TO 450
        DO 440 I=N1,NP
          Q=A(J,I)
          A(J,I)=A(K,I)
440       A(K,I)=Q
450     CONTINUE
C   Back transformation
      IF (NU .EQ. 0)  GO TO 510
      DO 500 KK=1,N
        K=N1-KK
        IF (B(K) .EQ. zero)  GO TO 500
        Q=-A(K,K)/CdABS(A(K,K))
        DO 460 J=1,NU
460       U(K,J)=Q*U(K,J)
        DO 490 J=1,NU
          Q=dcmplx(zero,zero)
          DO 470 I=K,M
470         Q=Q+dCONJG(A(I,K))*U(I,J)
          Q=Q/(CdABS(A(K,K))*B(K))
          DO 480 I=K,M
480         U(I,J)=U(I,J)-Q*A(I,K)
490       CONTINUE
500     CONTINUE
510   IF (NV .EQ. 0)  GO TO 570
      IF (N .LT. 2)  GO TO 570
      DO 560 KK=2,N
        K=N1-KK
        K1=K+1
        IF (C(K1) .EQ. zero)  GO TO 560
        Q=-dCONJG(A(K,K1))/CdABS(A(K,K1))
        DO 520 J=1,NV
520       V(K1,J)=Q*V(K1,J)
        DO 550 J=1,NV
          Q=dcmplx(zero,zero)
          DO 530 I=K1,N
530         Q=Q+A(K,I)*V(I,J)
          Q=Q/(CdABS(A(K,K1))*C(K1))
          DO 540 I=K1,N
540         V(I,J)=V(I,J)-Q*dCONJG(A(K,I))
550       CONTINUE
560     CONTINUE
570   RETURN
      END
