*     F12AAF Example Program Text
*     Mark 21 Release. NAG Copyright 2004.
*     .. Parameters ..
      INTEGER          LICOMM, NIN, NOUT
      PARAMETER        (LICOMM=140,NIN=5,NOUT=6)
      INTEGER          MAXN, MAXNCV, LDV
      PARAMETER        (MAXN=256,MAXNCV=30,LDV=MAXN)
      INTEGER          LCOMM
      PARAMETER        (LCOMM=3*MAXN+3*MAXNCV*MAXNCV+6*MAXNCV+60)
      INTEGER          IMON, IPOINT
      PARAMETER        (IMON=0,IPOINT=0)
*     .. Local Scalars ..
      DOUBLE PRECISION SIGMAI, SIGMAR
      INTEGER          I, IFAIL, IFAIL1, IREVCM, N, NCONV, NCV, NEV,
     +                 NITER, NSHIFT, NX
*     .. Local Arrays ..
      DOUBLE PRECISION AX(MAXN), COMM(LCOMM), D(MAXNCV,3), MX(MAXN),
     +                 RESID(MAXN), V(LDV,MAXNCV), X(MAXN)
      INTEGER          ICOMM(LICOMM)
*     .. External Functions ..
      DOUBLE PRECISION DNRM2
      EXTERNAL         DNRM2
*     .. External Subroutines ..
      EXTERNAL         AV, DCOPY, F12AAF, F12ABF, F12ACF, F12ADF, F12AEF
*     .. Executable Statements ..
      WRITE (NOUT,*) 'F12AAF Example Program Results'
      WRITE (NOUT,*)
*     Skip heading in data file
      READ (NIN,*)
      READ (NIN,*) NX, NEV, NCV
      N = NX*NX
      IF (N.LT.1 .OR. N.GT.MAXN) THEN
         WRITE (NOUT,99999) 'N is out of range: N = ', N
      ELSE IF (NCV.GT.MAXNCV) THEN
         WRITE (NOUT,99999) 'NCV is out of range: NCV = ', NCV
      ELSE
         IFAIL = 0
         CALL F12AAF(N,NEV,NCV,ICOMM,LICOMM,COMM,LCOMM,IFAIL)
*        Set the region of the spectrum that is required.
         CALL F12ADF('SMALLEST MAG',ICOMM,COMM,IFAIL)
         IF (IPOINT.NE.0) THEN
*           Use pointers to workspace in calculating matrix vector products
*           rather than interfacing through the array X.
            CALL F12ADF('POINTERS=YES',ICOMM,COMM,IFAIL)
         END IF
*
         IREVCM = 0
         IFAIL = -1
   20    CONTINUE
         CALL F12ABF(IREVCM,RESID,V,LDV,X,MX,NSHIFT,COMM,ICOMM,IFAIL)
         IF (IREVCM.NE.5) THEN
            IF (IREVCM.EQ.-1 .OR. IREVCM.EQ.1) THEN
*              Perform matrix vector multiplication y <--- Op*x
               IF (IPOINT.EQ.0) THEN
                  CALL AV(NX,X,AX)
                  CALL DCOPY(N,AX,1,X,1)
               ELSE
                  CALL AV(NX,COMM(ICOMM(1)),COMM(ICOMM(2)))
               END IF
            ELSE IF (IREVCM.EQ.4 .AND. IMON.NE.0) THEN
*              Set IMON=1 to output monitoring information.
               CALL F12AEF(NITER,NCONV,D,D(1,2),D(1,3),ICOMM,COMM)
               WRITE (6,99998) NITER, NCONV, DNRM2(NEV,D(1,3),1)
            END IF
            GO TO 20
         END IF
         IF (IFAIL.EQ.0) THEN
*           Post-Process using F12ACF to compute eigenvalues and
*           (by default) the corresponding eigenvectors.
            IFAIL1 = 0
            CALL F12ACF(NCONV,D,D(1,2),V,LDV,SIGMAR,SIGMAI,RESID,V,LDV,
     +                  COMM,ICOMM,IFAIL1)
            WRITE (NOUT,99996) NCONV
            DO 40 I = 1, NCONV
               WRITE (NOUT,99995) I, D(I,1), D(I,2)
   40       CONTINUE
         ELSE
            WRITE (NOUT,99997) IFAIL
         END IF
      END IF
      STOP
*
99999 FORMAT (1X,A,I5)
99998 FORMAT (1X,'Iteration',1X,I3,', No. converged =',1X,I3,', norm o',
     +       'f estimates =',E16.8)
99997 FORMAT (1X,' NAG Routine F12ABF Returned with IFAIL = ',I6)
99996 FORMAT (1X,/' The ',I4,' Ritz values of smallest magnitude are:',
     +       /)
99995 FORMAT (1X,I8,5X,'( ',F12.4,' , ',F12.4,' )')
      END
*
      SUBROUTINE AV(NX,V,W)
*     .. Scalar Arguments ..
      INTEGER       NX
*     .. Array Arguments ..
      DOUBLE PRECISION V(NX*NX), W(NX*NX)
*     .. Local Scalars ..
      DOUBLE PRECISION NX2
      INTEGER       J, LO
*     .. External Subroutines ..
      EXTERNAL      DAXPY, TV
*     .. Intrinsic Functions ..
      INTRINSIC     DBLE
*     .. Executable Statements ..
      NX2 = -DBLE((NX+1)*(NX+1))
      CALL TV(NX,V(1),W(1))
      CALL DAXPY(NX,NX2,V(NX+1),1,W(1),1)
      DO 20 J = 2, NX - 1
         LO = (J-1)*NX
         CALL TV(NX,V(LO+1),W(LO+1))
         CALL DAXPY(NX,NX2,V(LO-NX+1),1,W(LO+1),1)
         CALL DAXPY(NX,NX2,V(LO+NX+1),1,W(LO+1),1)
   20 CONTINUE
      LO = (NX-1)*NX
      CALL TV(NX,V(LO+1),W(LO+1))
      CALL DAXPY(NX,NX2,V(LO-NX+1),1,W(LO+1),1)
      RETURN
      END
*
      SUBROUTINE TV(NX,X,Y)
*     Compute the matrix vector multiplication y<---T*x where T is a nx
*     by nx tridiagonal matrix with constant diagonals (DD, DL and DU).
*     .. Parameters ..
      DOUBLE PRECISION HALF, RHO
      PARAMETER     (HALF=0.5D0,RHO=1.0D2)
*     .. Scalar Arguments ..
      INTEGER       NX
*     .. Array Arguments ..
      DOUBLE PRECISION X(NX), Y(NX)
*     .. Local Scalars ..
      DOUBLE PRECISION DD, DL, DU, NX1, NX2
      INTEGER       J
*     .. Intrinsic Functions ..
      INTRINSIC     DBLE
*     .. Executable Statements ..
      NX1 = DBLE(NX+1)
      NX2 = NX1*NX1
      DD = 4.0D0*NX2
      DL = -NX2 - HALF*RHO*NX1
      DU = -NX2 + HALF*RHO*NX1
      Y(1) = DD*X(1) + DU*X(2)
      DO 20 J = 2, NX - 1
         Y(J) = DL*X(J-1) + DD*X(J) + DU*X(J+1)
   20 CONTINUE
      Y(NX) = DL*X(NX-1) + DD*X(NX)
      RETURN
      END
