Integrated Computational Materials Engineering (ICME)

Postprocessing Codes - Evfit

Save the code as a file named

evfit.f

Compile with either gfortran or ifort. For gfortran executing

gfortran -O2 evfit.f -o evfit.x

will produce the executable evfit.x. For ifort executing

ifort -O3 evfit.f -o evfit.x

will produce the executable evfit.x.

Code

      program ev
*
*      Paolo Giannozzi e Stefano de Gironcoli
*      fit of E(V) to an equation of state
*      Unit: a0 (Angstrom), etot (eV); bulk modulus in Kbar
*            1 Kbar = 0.1 GPa
*
      implicit none
      integer nmaxpar, nmaxpt, nseek/1000/, npar, npt, istat
      parameter( nmaxpar=4, nmaxpt=40)
      character bravais*3, filin*40
      real*8 par(nmaxpar), Deltapar(nmaxpar), parmin(nmaxpar),
     &       parmax(nmaxpar), v0(nmaxpt), etot(nmaxpt), efit(nmaxpt), 
     &       fac, emin, c_su_a, chisq, a
      common v0, etot, efit, fac, emin, istat 
      external eqstate
C
      PRINT '(''$ UNIT CELL: FCC,BCC,SC,GENeric  > '')'
      READ '(A)',BRAVAIS
C
      IF(BRAVAIS.EQ.'FCC'.OR.BRAVAIS.EQ.'fcc') THEN
         FAC = 0.25
      ELSE IF(BRAVAIS.EQ.'BCC'.OR.BRAVAIS.EQ.'bcc') THEN
         FAC = 0.50
      ELSE IF(BRAVAIS.EQ.'SC'.OR.BRAVAIS.EQ.'sc') THEN
         FAC = 1.0
      ELSE IF(BRAVAIS.EQ.'GEN'.OR.BRAVAIS.EQ.'gen') THEN
         WRITE(*,*) 'write scaling factor (V=scalfac*a_0^3)'
         READ(*,*) FAC
      ELSE
         PRINT '(''$    Wurtzite lattice assumed. c/a > '')'
         read *, c_su_a
         fac = c_su_a*sqrt(3d0)/2d0
      ENDIF
C
      PRINT '(''     ENTER TYPE OF EQUATION OF STATE :''//
     &        ''$  1=BIRCH1, 2=BIRCH2, 3=KEANE, 4=MURNAGHAN  > '')'
      READ *,ISTAT
      if(istat.eq.1 .or. istat.eq.4) then
         npar=3
      else
         npar=4
      end if
      if(istat.eq.3) print '(''  possibly wrong...'')'
C     PRINT '(''$ INPUT FILE (Bohr, Ry) > '')'
      PRINT '(''$ INPUT FILE (Angstrom, eV) > '')'
      READ '(A)',FILIN
      OPEN(UNIT=2,FILE=FILIN,STATUS='OLD',FORM='FORMATTED')
  10  continue
      emin=1d10
      DO NPT=1,NMAXPT
          READ(2,*,ERR=10,END=20) a, etot(npt) 
C         unit conversion
          a=a/0.529177
          etot(npt)=etot(npt)/13.6058
          if(etot(npt).lt.emin) then
             par(1) = a
             emin = etot(npt)
          end if
          V0  (NPT) = FAC*a**3
      ENDDO     

      NPT = NMAXPT+1
  20  NPT = NPT-1
c
      par(2) = 500.0          
      par(3) = 5.0
      par(4) = -0.01
c
      parmin(1) = 0.0
      parmin(2) = 0.0
      parmin(3) = 1.0
      parmin(4) = -1.0
c
      parmax(1) = 100.0
      parmax(2) = 100000.
      parmax(3) = 15.0
      parmax(4) = 0.0
c
      Deltapar(1) = 0.1
      Deltapar(2) = 100.
      Deltapar(3) = 1.0
      Deltapar(4) = 0.01
c
      call minimize(eqstate,npt,npar,par,Deltapar,parmin,parmax,nseek,
     &              chisq)
C
      call write_results(npt,fac,v0,etot,efit,istat,par,npar,emin,chisq)
c
      STOP
      END   
C
C-----------------------------------------------------------------------
      SUBROUTINE EQSTATE(PAR,NPT,NPAR,DELTAE)
C-----------------------------------------------------------------------
C
      IMPLICIT NONE
      integer nmaxpt, npt, npar, i, istat
      PARAMETER( NMAXPT=40 )
      REAL*8 par(npar), deltae(npt), a0, k0, dk0, d2k0, c0, c1, x,
     &       vol0, fac, v0(nmaxpt), etot(nmaxpt), efit(nmaxpt),
     &       ddk, emin, conv_atomic_unit
      common v0, etot, efit, fac, emin, istat 
      parameter ( conv_atomic_unit=6.79777E-6 )
C                      
      A0   = PAR(1)
      VOL0 = FAC*A0**3
      K0   = PAR(2)*conv_atomic_UNIT ! converte k0 in unita' atomiche
      DK0  = PAR(3)
      D2K0 = PAR(4)/conv_atomic_UNIT ! e d2K0/dP2 in unita' atomiche**(-1)
C
      IF(ISTAT.EQ.1.OR.ISTAT.EQ.2) THEN
         IF(ISTAT.EQ.1) THEN
            C0 = 0.0
         ELSE
            C0 = ( 9.0*K0*D2K0 + 9.0*DK0**2 - 63.0*DK0 + 143.0 ) / 48.0
         ENDIF
         C1 = 3.0*(DK0-4.0)/8.0
         DO I=1,NPT
            X = VOL0/V0(I)
            EFIT(I) = 9.0*K0*VOL0*( (-0.5+  C1-  C0)*X**(2d0/3d0)/2.0
     &                             +( 0.5-2*C1+3*C0)*X**(4d0/3d0)/4.0
     &                             +(       C1-3*C0)*X**(6d0/3d0)/6.0
     &                             +(            C0)*X**(8d0/3d0)/8.0
     &                             -(-1D0/8.0+C1/6.0-C0/8.0) )
         ENDDO
      ELSE
         IF(ISTAT.EQ.3) THEN
            DDK = DK0 + K0*D2K0/DK0
         ELSE
            DDK = DK0
         ENDIF
         DO I=1,NPT
            EFIT(I) = - K0*DK0/DDK*VOL0/(DDK-1.0)
     &      + V0(I)*K0*DK0/DDK**2*( (VOL0/V0(I))**DDK/(DDK-1.0) + 1.0 )
     &      - K0*(DK0-DDK)/DDK*( V0(I)*LOG(VOL0/V0(I)) + V0(I)-VOL0 )
         ENDDO
      ENDIF
C
c      emin = energia all'equilibrio, ottenuta minimizzando chi**2
c
      emin = 0.0
      do i=1, npt
         emin = emin + etot(i)-efit(i)
      enddo
      emin = emin/npt
c
      DO I=1,NPT
          efit(i)=efit(i)+emin
          deltae(i)= etot(i)-efit(i)
      ENDDO
C
      RETURN
      END
c
c
      subroutine write_results
     &      (npt,fac,v0,etot,efit,istat,par,npar,emin,chisq)
      implicit none
      integer npt, istat, npar, i, iun
      character filout*40
      real*8 v0(npt), etot(npt), efit(npt), fac, par(npar), emin, chisq
c
      PRINT '(/''$ OUTPUT FILE > '')'
      READ '(A)',FILOUT
      IF(FILOUT.NE.' ') THEN
         iun=8
c         OPEN(UNIT=iun,FILE=FILOUT,FORM='FORMATTED',STATUS='NEW')
         OPEN(UNIT=iun,FILE=FILOUT,FORM='FORMATTED',STATUS='UNKNOWN')
      else
         iun=6
      end if
      if(istat.eq.1) write(iun,'('' Equation of state: '',
     &   ''Birch 1st order.  CHISQ = '',D10.4)') CHISQ
      if(istat.eq.2) write(iun,'('' Equation of state: '',
     &   ''Birch 2nd order.  CHISQ = '',D10.4)') CHISQ
      if(istat.eq.3) write(iun,'('' Equation of state: '',
     &   ''Keane.            CHISQ = '',D10.4)') CHISQ
      if(istat.eq.4) write(iun,'('' Equation of state: '',
     &   ''Murnaghan.        CHISQ = '',D10.4)') CHISQ
      if(istat.eq.1 .or. istat.eq.4) par(4) = 0.0
      WRITE(iun,'('' A0='',F10.7,'' K0='',f13.6,'' Kbar DK0='',
     & F12.7,'' D2K0='',F12.7,/,'' Emin='',f15.8/)')
     & par(1)*.529177, par(2), par(3), par(4), Emin*13.6058
      WRITE(iun,'(F10.6,2F20.12,3X,f13.6)') 
     & ( ((V0(I)/FAC)**(1d0/3d0))*.529177, ETOT(I)*13.6058, 
     & EFIT(I)*13.6058, (ETOT(I)-EFIT(I))*13.6058, I=1,NPT )
c      WRITE(iun,'('' A0='',F10.7,'' K0='',f13.6,'' Kbar DK0='',
c     & F12.7,'' D2K0='',F12.7,/,'' Emin='',f15.8/)')
c     & par(1), par(2), par(3), par(4), Emin
c      WRITE(iun,'(F7.3,2F13.6,3X,f13.6)') 
c     & ( ((V0(I)/FAC)**(1d0/3d0)), ETOT(I),
c     & EFIT(I), (ETOT(I)-EFIT(I)), I=1,NPT )

      IF(FILOUT.NE.' ') close(unit=iun)
      return
      end
c
c-----------------------------------------------------------------------
      subroutine minimize(func,npt,npar,par,Deltapar,parmin,parmax,
     &                    nseek,chisq)
c-----------------------------------------------------------------------
c
c      minimization through random seek followed by ZXSSQ (imsl). Input:
c      func, called by ZXSSQ, produces a vector Deltaf(npt)
c      The function to minimize is chisq=sum(i=1,npt) Deltaf(i)**2
c      par(npar) is the starting point for parameters, and contains
c      the final result. Deltapar(npar) is the radius
c      for the random search, with limits parmin(npar), parmax(npar) 
c      nseek is the number of random search. Can be <=0 (no random search)
c
      implicit none
      integer nmaxpar, nmaxpt, nbid
      parameter( nmaxpar=10, nmaxpt=500, nbid=nmaxpt*(nmaxpar+1)/2 )
      integer nseek, npar, npt, n, i, infer, ier
      integer*4 seed
      real*8 par(npar), Deltapar(npar), parmin(npar), parmax(npar), 
     &       parnew(nmaxpar), Deltaf(nmaxpt), xjac(nmaxpt,nmaxpar), 
     &       xjtj(nbid), work(5*nmaxpar+2*nmaxpt+nbid), parm(4), 
     &       chisq, chinew, random, bidon
      external func, random

      seed=321
c
      if(npar.gt.nmaxpar) then
          write(6,'('' too many parameters: npar='',i4,
     &      '' > nmaxpar='',i4)') npar, nmaxpar
          stop
      end if
      if(npt.gt.nmaxpt) then
          write(6,'('' too many points: npt='',i4,'' > nmaxpt='',i4)')
     &      npt, nmaxpt
          stop
      end if
      chisq = 1.0e30
      call set_random(seed)
c
      do i=1,nseek
         do n=1,npar
  10        parnew(n) = par(n) + (0.5 - random(seed))*Deltapar(n)
            if(parnew(n).gt.parmax(n) .or. parnew(n).lt.parmin(n)) 
     &      go to 10    
         enddo
c
         call func(parnew,npt,npar,Deltaf)
         chinew=0.0
         do n=1, npt
            chinew=chinew+Deltaf(n)**2
         end do
         if(chinew.lt.chisq) then
            do n=1,npar
               par(n) = parnew(n)
            enddo
            chisq = chinew
         endif
      enddo
      write (6,'('' chi2 = '',d10.4,''  after the random seek'')') chisq
c
      call zxssq2(func,npt,npar,4,0.0,0.0,10000,0,bidon,par,chisq,
     &            Deltaf,xjac,nmaxpt,xjtj,work,infer,ier)
      call func(par,npt,npar,Deltaf)
c
      return
      end
*
      subroutine set_random(seed)
      integer seed
      return
      end
*
      function random(seed)
      integer*4 seed
      real*8 random
      random=rand(seed)
      return
      end
*
C   IMSL ROUTINE NAME   - ZXSSQ
C
C-----------------------------------------------------------------------
c   Modified to:
c   a) Increase the maximum value of the Marquardt scal. param. to 10**5
c   b) Increase the value of the parameter at which it switches from
c      forward to central differencing from a tenth to 10**10
c      Cyrus
c   21 Feb 1987
c   c) Got rid of forward differences entirely because it cause problems
c      if the starting values of the parameters are at a minimum of the
c      function.
c   d) Have another subroutine parameter icusp2.  If icusp2.eq.1 then
c      the cusp conditions ae imposed by doing another minimization
c      within the usaual minimization. If the new parameters are not
c      accepted, then the cusp cond parameters are reset to their old
c      values by calling rsetab.
c      Actually instead of having icusp2 here, use it in rsetab itself
c-----------------------------------------------------------------------
C
C   COMPUTER            - IBM/DOUBLE
C
C   LATEST REVISION     - JANUARY 1, 1978
C
C   PURPOSE             - MINIMUM OF THE SUM OF SQUARES OF M FUNCTIONS
C                           IN N VARIABLES USING A FINITE DIFFERENCE
C                           LEVENBERG-MARQUARDT ALGORITHM
C
C   USAGE               - CALL ZXSSQ(FUNC,M,N,NSIG,EPS,DELTA,MAXFN,IOPT,
C                           PARM,X,SSQ,F,XJAC,IXJAC,XJTJ,WORK,INFER,IER)
C
C   ARGUMENTS    FUNC   - A USER SUPPLIED SUBROUTINE WHICH CALCULATES
C                           THE RESIDUAL VECTOR F(1),F(2),...,F(M) FOR
C                           GIVEN PARAMETER VALUES X(1),X(2),...,X(N).
C                           THE CALLING SEQUENCE HAS THE FOLLOWING FORM
C                             CALL FUNC(X,M,N,F)
C                             WHERE X IS A VECTOR OF LENGTH N AND F IS
C                               A VECTOR OF LENGTH M.
C                             FUNC MUST APPEAR IN AN EXTERNAL STATEMENT
C                               IN THE CALLING PROGRAM.
C                             FUNC MUST NOT ALTER THE VALUES OF
C                               X(I),I=1,...,N, M, OR N.
C                M      - THE NUMBER OF RESIDUALS OR OBSERVATIONS
C                           (INPUT)
C                N      - THE NUMBER OF UNKNOWN PARAMETERS (INPUT).
C                NSIG   - FIRST CONVERGENCE CRITERION. (INPUT)
C                           CONVERGENCE CONDITION SATISFIED IF ON TWO
C                           SUCCESSIVE ITERATIONS, THE PARAMETER
C                           ESTIMATES AGREE, COMPONENT BY COMPONENT,
C                           TO NSIG DIGITS.
C                EPS    - SECOND CONVERGENCE CRITERION. (INPUT)
C                           CONVERGENCE CONDITION SATISFIED IF, ON TWO
C                           SUCCESSIVE ITERATIONS THE RESIDUAL SUM
C                           OF SQUARES ESTIMATES HAVE RELATIVE
C                           DIFFERENCE LESS THAN OR EQUAL TO EPS. EPS
C                           MAY BE SET TO ZERO.
C                DELTA  - THIRD CONVERGENCE CRITERION. (INPUT)
C                           CONVERGENCE CONDITION SATISFIED IF THE
C                           (EUCLIDEAN) NORM OF THE APPROXIMATE
C                           GRADIENT IS LESS THAN OR EQUAL TO DELTA.
C                           DELTA MAY BE SET TO ZERO.
C                             NOTE, THE ITERATION IS TERMINATED, AND
C                             CONVERGENCE IS CONSIDERED ACHIEVED, IF
C                             ANY ONE OF THE THREE CONDITIONS IS
C                             SATISFIED.
C                MAXFN  - INPUT MAXIMUM NUMBER OF FUNCTION EVALUATIONS
C                           (I.E., CALLS TO SUBROUTINE FUNC) ALLOWED.
C                           THE ACTUAL NUMBER OF CALLS TO FUNC MAY
C                           EXCEED MAXFN SLIGHTLY.
C                IOPT   - INPUT OPTIONS PARAMETER.
C                         IOPT=0 IMPLIES BROWN'S ALGORITHM WITHOUT
C                           STRICT DESCENT IS DESIRED.
C                         IOPT=1 IMPLIES STRICT DESCENT AND DEFAULT
C                           VALUES FOR INPUT VECTOR PARM ARE DESIRED.
C                         IOPT=2 IMPLIES STRICT DESCENT IS DESIRED WITH
C                           USER PARAMETER CHOICES IN INPUT VECTOR PARM.
C                PARM   - INPUT VECTOR OF LENGTH 4 REQUIRED ONLY FOR
C                         IOPT EQUAL TWO.  PARM(I) CONTAINS, WHEN
C                           I=1, THE INITIAL VALUE OF THE MARQUARDT
C                             PARAMETER USED TO SCALE THE DIAGONAL OF
C                             THE APPROXIMATE HESSIAN MATRIX, XJTJ,
C                             BY THE FACTOR (1.0 + PARM(1)).  A SMALL
C                             VALUE GIVES A NEWTON STEP, WHILE A LARGE
C                             VALUE GIVES A STEEPEST DESCENT STEP.
C                             THE DEFAULT VALUE FOR PARM(1) IS 0.01.
C                           I=2, THE SCALING FACTOR USED TO MODIFY THE
C                             MARQUARDT PARAMETER, WHICH IS DECREASED
C                             BY PARM(2) AFTER AN IMMEDIATELY SUCCESSFUL
C                             DESCENT DIRECTION, AND INCREASED BY THE
C                             SQUARE OF PARM(2) IF NOT.  PARM(2) MUST
C                             BE GREATER THAN ONE, AND TWO IS DEFAULT.
C                           I=3, AN UPPER BOUND FOR INCREASING THE
C                             MARQUARDT PARAMETER.  THE SEARCH FOR A
C                             DESCENT POINT IS ABANDONED IF PARM(3) IS
C                             EXCEEDED.  PARM(3) GREATER THAN 100.0 IS
C                             RECOMMENDED.  DEFAULT IS 120.0.
C                           I=4, VALUE FOR INDICATING WHEN CENTRAL
C                             RATHER THAN FORWARD DIFFERENCING IS TO BE
C                             USED FOR CALCULATING THE JACOBIAN.  THE
C                             SWITCH IS MADE WHEN THE NORM OF THE
C                             GRADIENT OF THE SUM OF SQUARES FUNCTION
C                             BECOMES SMALLER THAN PARM(4).  CENTRAL
C                             DIFFERENCING IS GOOD IN THE VICINITY
C                             OF THE SOLUTION, SO PARM(4) SHOULD BE
C                             SMALL.  THE DEFAULT VALUE IS 0.10.
C                X      - VECTOR OF LENGTH N CONTAINING PARAMETER
C                           VALUES.
C                         ON INPUT, X SHOULD CONTAIN THE INITIAL
C                           ESTIMATE OF THE LOCATION OF THE MINIMUM.
C                         ON OUTPUT, X CONTAINS THE FINAL ESTIMATE
C                           OF THE LOCATION OF THE MINIMUM.
C                SSQ    - OUTPUT SCALAR WHICH IS SET TO THE RESIDUAL
C                           SUMS OF SQUARES, F(1)**2+...+F(M)**2, FOR
C                           THE FINAL PARAMETER ESTIMATES.
C                F      - OUTPUT VECTOR OF LENGTH M CONTAINING THE
C                           RESIDUALS FOR THE FINAL PARAMETER ESTIMATES.
C                XJAC   - OUTPUT M BY N MATRIX CONTAINING THE
C                           APPROXIMATE JACOBIAN AT THE OUTPUT VECTOR X.
C                IXJAC  - INPUT ROW DIMENSION OF MATRIX XJAC EXACTLY
C                           AS SPECIFIED IN THE DIMENSION STATEMENT
C                           IN THE CALLING PROGRAM.
C                XJTJ   - OUTPUT VECTOR OF LENGTH (N+1)*N/2 CONTAINING
C                           THE N BY N MATRIX (XJAC-TRANSPOSED) * (XJAC)
C                           IN SYMMETRIC STORAGE MODE.
C                WORK   - WORK VECTOR OF LENGTH 5*N + 2*M + (N+1)*N/2.
C                         ON OUTPUT, WORK(I) CONTAINS FOR
C                           I=1, THE NORM OF THE GRADIENT DESCRIBED
C                             UNDER INPUT PARAMETERS DELTA AND PARM(4).
C                           I=2, THE NUMBER OF FUNCTION EVALUATIONS
C                             REQUIRED DURING THE WORK(5) ITERATIONS.
C                           I=3, THE ESTIMATED NUMBER OF SIGNIFICANT
C                             DIGITS IN OUTPUT VECTOR X.
C                           I=4, THE FINAL VALUE OF THE MARQUARDT
C                             SCALING PARAMETER DESCRIBED UNDER PARM(1).
C                           I=5, THE NUMBER OF ITERATIONS (I.E., CHANGES
C                             TO THE X VECTOR) PERFORMED.
C                           SEE PROGRAMMING NOTES FOR DESCRIPTION OF
C                             THE LATTER ELEMENTS OF WORK.
C                INFER  - AN INTEGER THAT IS SET, ON OUTPUT, TO
C                           INDICATE WHICH CONVERGENCE CRITERION WAS
C                           SATISFIED.
C                         INFER = 0 INDICATES THAT CONVERGENCE FAILED.
C                           IER GIVES FURTHER EXPLANATION.
C                         INFER = 1 INDICATES THAT THE FIRST CRITERION
C                           WAS SATISFIED.
C                         INFER = 2 INDICATES THAT THE SECOND CRITERION
C                           WAS SATISFIED.
C                         INFER = 4 INDICATES THAT THE THIRD CRITERION
C                           WAS SATISFIED.
C                         IF MORE THAN ONE OF THE CONVERGENCE CRITERIA
C                           WERE SATISFIED ON THE FINAL ITERATION,
C                           INFER CONTAINS THE CORRESPONDING SUM.
C                           (E.G., INFER = 3 IMPLIES FIRST AND SECOND
C                           CRITERIA SATISFIED SIMULTANEOUSLY).
C                IER    - ERROR PARAMETER (OUTPUT)
C                         TERMINAL ERROR
C                           IER=129 IMPLIES A SINGULARITY WAS DETECTED
C                             IN THE JACOBIAN AND RECOVERY FAILED.
C                           IER=130 IMPLIES AT LEAST ONE OF M, N, IOPT,
C                             PARM(1), OR PARM(2) WAS SPECIFIED
C                             INCORRECTLY.
C                           IER=131 IMPLIES THAT THE MARQUARDT
C                             PARAMETER EXCEEDED PARM(3).
C                           IER=132 IMPLIES THAT AFTER A SUCCESSFUL
C                             RECOVERY FROM A SINGULAR JACOBIAN, THE
C                             VECTOR X HAS CYCLED BACK TO THE
C                             FIRST SINGULARITY.
C                           IER=133 IMPLIES THAT MAXFN WAS EXCEEDED.
C                         WARNING ERROR
C                           IER=38 IMPLIES THAT THE JACOBIAN IS ZERO.
C                             THE SOLUTION X IS A STATIONARY POINT.
C
C   PRECISION/HARDWARE  - SINGLE AND DOUBLE/H32
C                       - SINGLE/H36,H48,H60
C
C   REQD. IMSL ROUTINES - LEQT1P,LUDECP,LUELMP,UERSET,UERTST,UGETIO
C
C   NOTATION            - INFORMATION ON SPECIAL NOTATION AND
C                           CONVENTIONS IS AVAILABLE IN THE MANUAL
C                           INTRODUCTION OR THROUGH IMSL ROUTINE UHELP
C
C   COPYRIGHT           - 1978 BY IMSL, INC. ALL RIGHTS RESERVED.
C
C   WARRANTY            - IMSL WARRANTS ONLY THAT IMSL TESTING HAS BEEN
C                           APPLIED TO THIS CODE. NO OTHER WARRANTY,
C                           EXPRESSED OR IMPLIED, IS APPLICABLE.
C
C-----------------------------------------------------------------------
C
      SUBROUTINE ZXSSQ2 (FUNC,M,N,NSIG,EPS,DELTA,MAXFN,IOPT,PARM,
     *                   X,SSQ,F,XJAC,IXJAC,XJTJ,WORK,INFER,IER)
C                                  SPECIFICATIONS FOR ARGUMENTS
      external func  ! avoids a warning on silicon graphics
      INTEGER            M,N,NSIG,MAXFN,IOPT,IXJAC,INFER,IER
      DOUBLE PRECISION   EPS,DELTA,PARM(1),X(N),SSQ,F(M),XJAC(1),
     *                   XJTJ(1),WORK(1)
C                                  XJAC USED INTERNALLY IN PACKED FORM
C                                  SPECIFICATIONS FOR LOCAL VARIABLES
      INTEGER            IMJC,IGRAD1,IGRADL,IGRADU,IDELX1,IDELXL,
     *                   IDELXU,ISCAL1,ISCALL,ISCALU,IXNEW1,IXNEWL,
     *                   IXBAD1,IFPL1,IFPL,IFPU,IFML1,IFML,IEVAL,
     *                   IBAD,ISW,ITER,J,IJAC,I,K,L,IS,JS,LI,LJ,ICOUNT,
     *                   IZERO,LEVEL,LEVOLD
      DOUBLE PRECISION   AL,CONS2,DNORM,DSQ,
     *                   ERL2,ERL2X,F0,F0SQ,F0SQS4,G,HALF,
     *                   HH,ONE,ONEP10,ONEP5,ONESF0,AX,
     *                   PREC,REL,RHH,SIG,SQDIF,SSQOLD,SUM,TEN,
     *                   TENTH,XDIF,XHOLD,UP,ZERO,
     *                   XDABS,RELCON,P01,TWO,HUNTW,DELTA2
      DATA               SIG/16.0D0/
c     DATA               AX/0.1D0/
      DATA               AX/0.001D0/
      DATA               P01,TENTH,HALF,ZERO,ONE,ONEP5,TWO,
     *                   TEN,HUNTW,ONEP10,d1p5/0.01D0,0.1D0,0.5D0,0.0D0,
     *                   1.D0,1.5D0,2.D0,10.0D0,1.2D2,1.D10,1.d5/
      data               d2b3,d1b12/.6666666666666667d0,
     *                   .08333333333333333d0/
C                                  ERROR CHECKS
C                                  FIRST EXECUTABLE STATEMENT
      IER = 0
      LEVEL = 0
      CALL UERSET (LEVEL,LEVOLD)
      IF (M.LE.0.OR.M.GT.IXJAC.OR.N.LE.0.OR.IOPT.LT.0.OR.IOPT.GT.2)
     *   GO TO 305
      IMJC = IXJAC-M
      IF (IOPT.NE.2) GO TO 5
      IF (PARM(2).LE.ONE.OR.PARM(1).LE.ZERO) GO TO 305
C                                  MACHINE DEPENDENT CONSTANTS
    5 PREC = TEN**(-SIG-ONE)
      REL = TEN**(-SIG*HALF*HALF)
c     REL = TEN**(-SIG*HALF*half*half)
      RELCON = TEN**(-NSIG)
C                                  WORK VECTOR IS CONCATENATION OF
C                                  SCALED HESSIAN,GRADIENT,DELX,SCALE,
C                                  XNEW,XBAD,F(X+DEL),F(X-DEL)
      IGRAD1 = ((N+1)*N)/2
      IGRADL = IGRAD1+1
      IGRADU = IGRAD1+N
      IDELX1 = IGRADU
      IDELXL = IDELX1+1
      IDELXU = IDELX1+N
      ISCAL1 = IDELXU
      ISCALL = ISCAL1+1
      ISCALU = ISCAL1+N
      IXNEW1 = ISCALU
      IXNEWL = IXNEW1+1
      IXBAD1 = IXNEW1+N
      IFPL1 = IXBAD1+N
      IFPL = IFPL1+1
      IFPU = IFPL1+M
      IFML1 = IFPU
      IFML = IFML1+1
      ifmu = ifpu+m
      ifpl2 = ifmu+1
      ifpu2 = ifmu+m
      ifml2 = ifpu2+1
      ifmu2 = ifpu2+m
      IMJC = IXJAC - M
C                                  INITIALIZE VARIABLES
      AL = ONE
c     cons3 = huntw
c     CONS2 = TENTH
      cons3 = tenth
      cons2 = onep10
      IF (IOPT.EQ.0) GO TO 20
      IF (IOPT.EQ.1) GO TO 10
      AL = PARM(1)
      F0 = PARM(2)
      UP = PARM(3)
      CONS2 = PARM(4)*HALF
      GO TO 15
   10 AL = P01
      F0 = TWO
c     UP = HUNTW
      up = d1p5
   15 ONESF0 = ONE/F0
      F0SQ = F0*F0
      F0SQS4 = F0SQ**4
   20 IEVAL = 0
      DELTA2 = DELTA*HALF
      ERL2 = ONEP10
      IBAD = -99
c     ISW = 1
      ISW = 2
      ITER = -1
      INFER = 0
      IER = 0
      DO 25 J=IDELXL,IDELXU
         WORK(J) = ZERO
   25 CONTINUE
      GO TO 165
C                                  MAIN LOOP
   30 SSQOLD = SSQ
C                                  CALCULATE JACOBIAN
      IF (INFER.GT.0.OR.IJAC.GE.N.OR.IOPT.EQ.0.OR.ICOUNT.GT.0) GO TO 55
C                                  RANK ONE UPDATE TO JACOBIAN
      IJAC = IJAC+1
      DSQ = ZERO
      DO 35 J=IDELXL,IDELXU
         DSQ = DSQ+WORK(J)*WORK(J)
   35 CONTINUE
      IF (DSQ.LE.ZERO) GO TO 55
      DO 50 I=1,M
         G = F(I)-WORK(IFML1+I)
         K = I
         DO 40 J=IDELXL,IDELXU
            G = G+XJAC(K)*WORK(J)
            K = K+IXJAC
   40    CONTINUE
         G = G/DSQ
         K = I
         DO 45 J=IDELXL,IDELXU
c           next line should probably have a 2* before the G but it doesn't
c           make much of a diff.
            XJAC(K) = XJAC(K)-G*WORK(J)
            K = K+IXJAC
   45    CONTINUE
   50 CONTINUE
      GO TO 80
C                                  JACOBIAN BY INCREMENTING X
   55 IJAC = 0
      K = -IMJC
      DO 75 J=1,N
         K = K+IMJC
         XDABS = DABS(X(J))
         HH = REL*(DMAX1(XDABS,AX))
         XHOLD = X(J)
         X(J) = X(J)+HH
         CALL FUNC (X,M,N,WORK(IFPL))
         IEVAL = IEVAL+1
         X(J) = XHOLD
c        IF (ISW.EQ.1) GO TO 65
         if (isw.eq.2) go to 58
C                                  5 point CENTRAL DIFFERENCES
         X(J) = XHOLD-HH
         CALL FUNC (X,M,N,WORK(IFML))

         X(J) = XHOLD+2*HH
         CALL FUNC (X,M,N,WORK(IFpl2))

         X(J) = XHOLD-2*HH
         CALL FUNC (X,M,N,WORK(IFml2))
         IEVAL = IEVAL+3
         X(J) = XHOLD

         m2=2*m
         m3=3*m
         RHH = one/HH
         DO 57 I=IFPL,IFPU
            K = K+1
            XJAC(K) = (d2b3*(WORK(I)-WORK(I+M))
     1              - d1b12*(work(i+m2)-work(i+m3)))*RHH
   57    CONTINUE
         GO TO 75
C                                  3-point CENTRAL DIFFERENCES
   58      X(J) = XHOLD-HH
         CALL FUNC (X,M,N,WORK(IFML))
         IEVAL = IEVAL+1
         X(J) = XHOLD
         RHH = HALF/HH
         DO 60 I=IFPL,IFPU
            K = K+1
            XJAC(K) = (WORK(I)-WORK(I+M))*RHH
   60    CONTINUE
         GO TO 75
C                                  FORWARD DIFFERENCES
c  65    RHH = ONE/HH
cc       write(6,*) 'forward diff'
c        DO 70 I=1,M
c           K = K+1
c           XJAC(K) = (WORK(IFPL1+I)-F(I))*RHH
c  70    CONTINUE
   75 CONTINUE
C                                  CALCULATE GRADIENT
   80 ERL2X = ERL2
      ERL2 = ZERO
      K = -IMJC
      DO 90 J=IGRADL,IGRADU
         K = K+IMJC
         SUM = ZERO
         DO 85 I=1,M
            K = K+1
            SUM = SUM+XJAC(K)*F(I)
   85    CONTINUE
         WORK(J) = SUM
c        if(sum.gt.one) write(6,'(''iparm,grad'',i5,d12.4)')j-igradl+1,
c    1   sum
         ERL2 = ERL2+SUM*SUM
   90 CONTINUE
      ERL2 = DSQRT(ERL2)
c      if(isw.eq.3) write(6,'(''5 point central diff'',d12.4)') erl2
c      if(isw.eq.2) write(6,'(''3 point central diff'',d12.4)') erl2
c      if(isw.eq.1) write(6,'(''forward diff'',d12.4)') erl2
C                                  CONVERGENCE TEST FOR NORM OF GRADIENT
      IF (IJAC.GT.0) GO TO 95
      IF (ERL2.LE.DELTA2) INFER = INFER+4
      IF (isw.eq.1 .and. ERL2.LE.CONS2) ISW = 2
      if (isw.eq.2 .and. erl2.le.cons3) isw = 3
C                                  CALCULATE THE LOWER SUPER TRIANGE OF
C                                  JACOBIAN (TRANSPOSED) * JACOBIAN
   95 L = 0
      IS = -IXJAC
      DO 110 I=1,N
         IS = IS+IXJAC
         JS = -IXJAC
         DO 105 J=1,I
            JS = JS+IXJAC
            L = L+1
            SUM = ZERO
            DO 100 K=1,M
               LI = IS+K
               LJ = JS+K
               SUM = SUM+XJAC(LI)*XJAC(LJ)
  100       CONTINUE
            XJTJ(L) = SUM
  105    CONTINUE
  110 CONTINUE
C                                  CONVERGENCE CHECKS
      IF (INFER.GT.0) GO TO 315
      IF (IEVAL.GE.MAXFN) GO TO 290
C                                  COMPUTE SCALING VECTOR
      IF (IOPT.EQ.0) GO TO 120
      K = 0
      DO 115 J=1,N
         K = K+J
         WORK(ISCAL1+J) = XJTJ(K)
  115 CONTINUE
      GO TO 135
C                                  COMPUTE SCALING VECTOR AND NORM
  120 DNORM = ZERO
      K = 0
      DO 125 J=1,N
         K = K+J
         WORK(ISCAL1+J) = DSQRT(XJTJ(K))
         DNORM = DNORM+XJTJ(K)*XJTJ(K)
  125 CONTINUE
      DNORM = ONE/DSQRT(DNORM)
C                                  NORMALIZE SCALING VECTOR
      DO 130 J=ISCALL,ISCALU
         WORK(J) = WORK(J)*DNORM*ERL2
  130 CONTINUE
C                                  ADD L-M FACTOR TO DIAGONAL
  135 ICOUNT = 0
  140 K = 0
      DO 150 I=1,N
         DO 145 J=1,I
            K = K+1
            WORK(K) = XJTJ(K)
  145    CONTINUE
         WORK(K) = WORK(K)+WORK(ISCAL1+I)*AL
         WORK(IDELX1+I) = WORK(IGRAD1+I)
  150 CONTINUE
C                                  CHOLESKY DECOMPOSITION
  155 CALL LEQT1P (WORK,1,N,WORK(IDELXL),N,0,G,XHOLD,IER)
      IF (IER.EQ.0) GO TO 160
      IER = 0
      IF (IJAC.GT.0) GO TO 55
      IF (IBAD.LE.0) GO TO 240
      IF (IBAD.GE.2) GO TO 310
      GO TO 190
  160 IF (IBAD.NE.-99) IBAD = 0
C                                  CALCULATE SUM OF SQUARES
  165 DO 170 J=1,N
c     temporary change to see if min is more nearly quartic than quadratic
         WORK(IXNEW1+J) = X(J)-WORK(IDELX1+J)
c        WORK(IXNEW1+J) = X(J)-3*WORK(IDELX1+J)
  170 CONTINUE
      CALL FUNC (WORK(IXNEWL),M,N,WORK(IFPL))
      IEVAL = IEVAL+1
      SSQ = ZERO
      DO 175 I=IFPL,IFPU
         SSQ = SSQ+WORK(I)*WORK(I)
  175 CONTINUE
c      write(6,'(''iter,icount,ijac,ibad,ssq,al='',4i5,2d12.4)')
c     1iter,icount,ijac,ibad,ssq,al
c      if(ssq.le.ssqold) then
c        write(6,'(''new parms'',9f10.6)')(work(i),i=ixnewl,ixnewl+n-1)
c       else
c        write(6,'(''bad parms'',9f10.6)')(work(i),i=ixnewl,ixnewl+n-1)
c      endif
      IF (ITER.GE.0) GO TO 185
C                                  SSQ FOR INITIAL ESTIMATES OF X
      ITER = 0
      SSQOLD = SSQ
      DO 180 I=1,M
         F(I) = WORK(IFPL1+I)
  180 CONTINUE
      GO TO 55
  185 IF (IOPT.EQ.0) GO TO 215
C                                  CHECK DESCENT PROPERTY
      IF (SSQ.LE.SSQOLD) GO TO 205
C                                  INCREASE PARAMETER AND TRY AGAIN
  190 ICOUNT = ICOUNT+1
      AL = AL*F0SQ
      IF (IJAC.EQ.0) GO TO 195
      IF (ICOUNT.GE.4.OR.AL.GT.UP) GO TO 200
  195 IF (AL.LE.UP) GO TO 140
      IF (IBAD.EQ.1) GO TO 310
      GO TO 300
  200 AL = AL/F0SQS4
      GO TO 55
C                                  ADJUST MARQUARDT PARAMETER
  205 IF (ICOUNT.EQ.0) AL = AL/F0
      IF (ERL2X.LE.ZERO) GO TO 210
      G = ERL2/ERL2X
      IF (ERL2.LT.ERL2X) AL = AL*DMAX1(ONESF0,G)
      IF (ERL2.GT.ERL2X) AL = AL*DMIN1(F0,G)
  210 AL = DMAX1(AL,PREC)
C                                  ONE ITERATION CYCLE COMPLETED
  215 ITER = ITER+1
      DO 220 J=1,N
         X(J) = WORK(IXNEW1+J)
  220 CONTINUE
      DO 225 I=1,M
         WORK(IFML1+I) = F(I)
         F(I) = WORK(IFPL1+I)
  225 CONTINUE
C                                  RELATIVE CONVERGENCE TEST FOR X
      IF (ICOUNT.GT.0.OR.IJAC.GT.0) GO TO 30
      DO 230 J=1,N
         XDIF = DABS(WORK(IDELX1+J))/DMAX1(DABS(X(J)),AX)
         IF (XDIF.GT.RELCON) GO TO 235
  230 CONTINUE
      INFER = 1
C                                  RELATIVE CONVERGENCE TEST FOR SSQ
  235 SQDIF = DABS(SSQ-SSQOLD)/DMAX1(SSQOLD,AX)
      IF (SQDIF.LE.EPS) INFER = INFER+2
      GO TO 30
C                                  SINGULAR DECOMPOSITION
  240 IF (IBAD) 255,245,265
C                                  CHECK TO SEE IF CURRENT
C                                  ITERATE HAS CYCLED BACK TO
C                                  THE LAST SINGULAR POINT
  245 DO 250 J=1,N
         XHOLD = WORK(IXBAD1+J)
         IF (DABS(X(J)-XHOLD).GT.RELCON*DMAX1(AX,DABS(XHOLD))) GO TO 255
  250 CONTINUE
      GO TO 295
C                                  UPDATE THE BAD X VALUES
  255 DO 260 J=1,N
         WORK(IXBAD1+J) = X(J)
  260 CONTINUE
      IBAD = 1
C                                  INCREASE DIAGONAL OF HESSIAN
  265 IF (IOPT.NE.0) GO TO 280
      K = 0
      DO 275 I=1,N
         DO 270 J=1,I
            K = K+1
            WORK(K) = XJTJ(K)
  270    CONTINUE
         WORK(K) = ONEP5*(XJTJ(K)+AL*ERL2*WORK(ISCAL1+I))+REL
  275 CONTINUE
      IBAD = 2
      GO TO 155
C                                  REPLACE ZEROES ON HESSIAN DIAGONAL
  280 IZERO = 0
      DO 285 J=ISCALL,ISCALU
         IF (WORK(J).GT.ZERO) GO TO 285
         IZERO = IZERO+1
         WORK(J) = ONE
  285 CONTINUE
      IF (IZERO.LT.N) GO TO 140
      IER = 38
      GO TO 315
C                                  TERMINAL ERROR
  290 IER = IER+1
  295 IER = IER+1
  300 IER = IER+1
  305 IER = IER+1
  310 IER = IER+129
      IF (IER.EQ.130) GO TO 335
C                                  OUTPUT ERL2,IEVAL,NSIG,AL, AND ITER
  315 G = SIG
      DO 320 J=1,N
         XHOLD = DABS(WORK(IDELX1+J))
         IF (XHOLD.LE.ZERO) GO TO 320
         G = DMIN1(G,-DLOG10(XHOLD/DMAX1(AX,DABS(X(J)))))
  320 CONTINUE
      IF(N.GT.2) GO TO 330
      DO 325 J = 1,N
  325 WORK(J+5) = WORK(J+IGRAD1)
  330 WORK(1) = ERL2+ERL2
      WORK(2) = IEVAL
      SSQ = SSQOLD
      WORK(3) = G
      WORK(4) = AL
      WORK(5) = ITER
  335 CALL UERSET(LEVOLD,LEVOLD)
      IF (IER.EQ.0) GO TO 9005
 9000 CONTINUE
      CALL UERTST (IER,6HZXSSQ )
 9005 RETURN
      END
C
C   IMSL ROUTINE NAME   - UERTST
C
C-----------------------------------------------------------------------
C
C   COMPUTER            - IBM/SINGLE
C
C   LATEST REVISION     - JANUARY 1, 1978
C
C   PURPOSE             - PRINT A MESSAGE REFLECTING AN ERROR CONDITION
C
C   USAGE               - CALL UERTST (IER,NAME)
C
C   ARGUMENTS    IER    - ERROR PARAMETER. (INPUT)
C                           IER = I+J WHERE
C                             I = 128 IMPLIES TERMINAL ERROR,
C                             I =  64 IMPLIES WARNING WITH FIX, AND
C                             I =  32 IMPLIES WARNING.
C                             J = ERROR CODE RELEVANT TO CALLING
C                                 ROUTINE.
C                NAME   - A SIX CHARACTER LITERAL STRING GIVING THE
C                           NAME OF THE CALLING ROUTINE. (INPUT)
C
C   PRECISION/HARDWARE  - SINGLE/ALL
C
C   REQD. IMSL ROUTINES - UGETIO
C
C   NOTATION            - INFORMATION ON SPECIAL NOTATION AND
C                           CONVENTIONS IS AVAILABLE IN THE MANUAL
C                           INTRODUCTION OR THROUGH IMSL ROUTINE UHELP
C
C   REMARKS      THE ERROR MESSAGE PRODUCED BY UERTST IS WRITTEN
C                ONTO THE STANDARD OUTPUT UNIT. THE OUTPUT UNIT
C                NUMBER CAN BE DETERMINED BY CALLING UGETIO AS
C                FOLLOWS..   CALL UGETIO(1,NIN,NOUT).
C                THE OUTPUT UNIT NUMBER CAN BE CHANGED BY CALLING
C                UGETIO AS FOLLOWS..
C                                NIN = 0
C                                NOUT = NEW OUTPUT UNIT NUMBER
C                                CALL UGETIO(3,NIN,NOUT)
C                SEE THE UGETIO DOCUMENT FOR MORE DETAILS.
C
C   COPYRIGHT           - 1978 BY IMSL, INC. ALL RIGHTS RESERVED.
C
C   WARRANTY            - IMSL WARRANTS ONLY THAT IMSL TESTING HAS BEEN
C                           APPLIED TO THIS CODE. NO OTHER WARRANTY,
C                           EXPRESSED OR IMPLIED, IS APPLICABLE.
C
C-----------------------------------------------------------------------
C
      SUBROUTINE UERTST (IER,NAME)
C                                  SPECIFICATIONS FOR ARGUMENTS
      INTEGER            IER
      INTEGER*2          NAME(3)
C                                  SPECIFICATIONS FOR LOCAL VARIABLES
      INTEGER*2          NAMSET(3),NAMEQ(3)
      DATA               NAMSET/2HUE,2HRS,2HET/
      DATA               NAMEQ/2H  ,2H  ,2H  /
C                                  FIRST EXECUTABLE STATEMENT
      DATA               LEVEL/4/,IEQDF/0/,IEQ/1H=/
      IF (IER.GT.999) GO TO 25
      IF (IER.LT.-32) GO TO 55
      IF (IER.LE.128) GO TO 5
      IF (LEVEL.LT.1) GO TO 30
C                                  PRINT TERMINAL MESSAGE
      CALL UGETIO(1,NIN,IOUNIT)
      IF (IEQDF.EQ.1) WRITE(IOUNIT,35) IER,NAMEQ,IEQ,NAME
      IF (IEQDF.EQ.0) WRITE(IOUNIT,35) IER,NAME
      GO TO 30
    5 IF (IER.LE.64) GO TO 10
      IF (LEVEL.LT.2) GO TO 30
C                                  PRINT WARNING WITH FIX MESSAGE
      CALL UGETIO(1,NIN,IOUNIT)
      IF (IEQDF.EQ.1) WRITE(IOUNIT,40) IER,NAMEQ,IEQ,NAME
      IF (IEQDF.EQ.0) WRITE(IOUNIT,40) IER,NAME
      GO TO 30
   10 IF (IER.LE.32) GO TO 15
C                                  PRINT WARNING MESSAGE
      IF (LEVEL.LT.3) GO TO 30
      CALL UGETIO(1,NIN,IOUNIT)
      IF (IEQDF.EQ.1) WRITE(IOUNIT,45) IER,NAMEQ,IEQ,NAME
      IF (IEQDF.EQ.0) WRITE(IOUNIT,45) IER,NAME
      GO TO 30
   15 CONTINUE
C                                  CHECK FOR UERSET CALL
      DO 20 I=1,3
         IF (NAME(I).NE.NAMSET(I)) GO TO 25
   20 CONTINUE
      LEVOLD = LEVEL
      LEVEL = IER
      IER = LEVOLD
      IF (LEVEL.LT.0) LEVEL = 4
      IF (LEVEL.GT.4) LEVEL = 4
      GO TO 30
   25 CONTINUE
      IF (LEVEL.LT.4) GO TO 30
C                                  PRINT NON-DEFINED MESSAGE
      CALL UGETIO(1,NIN,IOUNIT)
      IF (IEQDF.EQ.1) WRITE(IOUNIT,50) IER,NAMEQ,IEQ,NAME
      IF (IEQDF.EQ.0) WRITE(IOUNIT,50) IER,NAME
   30 IEQDF = 0
      RETURN
   35 FORMAT(19H *** TERMINAL ERROR,10X,7H(IER = ,I3,
     1       20H) FROM IMSL ROUTINE ,3A2,A1,3A2)
   40 FORMAT(36H *** WARNING WITH FIX ERROR  (IER = ,I3,
     1       20H) FROM IMSL ROUTINE ,3A2,A1,3A2)
   45 FORMAT(18H *** WARNING ERROR,11X,7H(IER = ,I3,
     1       20H) FROM IMSL ROUTINE ,3A2,A1,3A2)
   50 FORMAT(20H *** UNDEFINED ERROR,9X,7H(IER = ,I5,
     1       20H) FROM IMSL ROUTINE ,3A2,A1,3A2)
C                                  SAVE P FOR P = R CASE
C                                    P IS THE PAGE NAME
C                                    R IS THE ROUTINE NAME
   55 IEQDF = 1
      DO 60 I=1,3
   60 NAMEQ(I) = NAME(I)
   65 RETURN
      END
C
C   IMSL ROUTINE NAME   - UERSET
C
C-----------------------------------------------------------------------
C
C   COMPUTER            - IBM/SINGLE
C
C   LATEST REVISION     - JANUARY 1, 1978
C
C   PURPOSE             - SET MESSAGE LEVEL FOR IMSL ROUTINE UERTST
C
C   USAGE               - CALL UERSET (LEVEL,LEVOLD)
C
C   ARGUMENTS    LEVEL  - NEW VALUE FOR MESSAGE LEVEL. (INPUT)
C                           OUTPUT FROM IMSL ROUTINE UERTST IS
C                           CONTROLLED SELECTIVELY AS FOLLOWS,
C                             LEVEL = 4 CAUSES ALL MESSAGES TO BE
C                                       PRINTED,
C                             LEVEL = 3 MESSAGES ARE PRINTED IF IER IS
C                                       GREATER THAN 32,
C                             LEVEL = 2 MESSAGES ARE PRINTED IF IER IS
C                                       GREATER THAN 64,
C                             LEVEL = 1 MESSAGES ARE PRINTED IF IER IS
C                                       GREATER THAN 128,
C                             LEVEL = 0 ALL MESSAGE PRINTING IS
C                                       SUPPRESSED.
C                LEVOLD - PREVIOUS MESSAGE LEVEL. (OUTPUT)
C
C   PRECISION/HARDWARE  - SINGLE/ALL
C
C   REQD. IMSL ROUTINES - UERTST,UGETIO
C
C   NOTATION            - INFORMATION ON SPECIAL NOTATION AND
C                           CONVENTIONS IS AVAILABLE IN THE MANUAL
C                           INTRODUCTION OR THROUGH IMSL ROUTINE UHELP
C
C   COPYRIGHT           - 1978 BY IMSL, INC. ALL RIGHTS RESERVED.
C
C   WARRANTY            - IMSL WARRANTS ONLY THAT IMSL TESTING HAS BEEN
C                           APPLIED TO THIS CODE. NO OTHER WARRANTY,
C                           EXPRESSED OR IMPLIED, IS APPLICABLE.
C
C-----------------------------------------------------------------------
C
      SUBROUTINE UERSET (LEVEL,LEVOLD)
C                                  SPECIFICATIONS FOR ARGUMENTS
      INTEGER            LEVEL,LEVOLD
C                                  FIRST EXECUTABLE STATEMENT
      LEVOLD = LEVEL
      CALL UERTST (LEVOLD,6HUERSET)
      RETURN
      END
C   IMSL ROUTINE NAME   - LEQT1P
C
C-----------------------------------------------------------------------
C
C   COMPUTER            - IBM/DOUBLE
C
C   LATEST REVISION     - JANUARY 1, 1978
C
C   PURPOSE             - LINEAR EQUATION SOLUTION - POSITIVE DEFINITE
C                           MATRIX - SYMMETRIC STORAGE MODE - SPACE
C                           ECONOMIZER SOLUTION
C
C   USAGE               - CALL LEQT1P (A,M,N,B,IB,IDGT,D1,D2,IER)
C
C   ARGUMENTS    A      - INPUT VECTOR OF LENGTH N(N+1)/2 CONTAINING THE
C                           N BY N COEFFICIENT MATRIX OF THE EQUATION
C                           AX = B. A IS A POSITIVE DEFINITE SYMMETRIC
C                           MATRIX STORED IN SYMMETRIC STORAGE MODE.
C                         ON OUTPUT, A IS REPLACED BY THE LOWER
C                           TRIANGULAR MATRIX L WHERE A = L*L-TRANSPOSE.
C                           L IS STORED IN SYMMETRIC STORAGE MODE WITH
C                           THE DIAGONAL ELEMENTS OF L IN RECIPROCAL
C                           FORM.
C                M      - NUMBER OF RIGHT HAND SIDES (COLUMNS IN B).
C                           (INPUT)
C                N      - ORDER OF A AND NUMBER OF ROWS IN B. (INPUT)
C                B      - INPUT MATRIX OF DIMENSION N BY M CONTAINING
C                           THE RIGHT-HAND SIDES OF THE EQUATION
C                           AX = B.
C                         ON OUTPUT, THE N BY M SOLUTION MATRIX X
C                           REPLACES B.
C                IB     - ROW DIMENSION OF B EXACTLY AS SPECIFIED IN
C                           THE DIMENSION STATEMENT IN THE CALLING
C                           PROGRAM. (INPUT)
C                IDGT   - THE ELEMENTS OF A ARE ASSUMED TO BE CORRECT
C                           TO IDGT DECIMAL DIGITS. (CURRENTLY NOT USED)
C                D1,D2  - COMPONENTS OF THE DETERMINANT OF A.
C                           DETERMINANT(A) = D1*2.**D2. (OUTPUT)
C                IER    - ERROR PARAMETER. (OUTPUT)
C                         TERMINAL ERROR
C                           IER = 129 INDICATES THAT THE INPUT MATRIX
C                             A IS ALGORITHMICALLY NOT POSITIVE
C                             DEFINITE. (SEE THE CHAPTER L PRELUDE).
C
C   PRECISION/HARDWARE  - SINGLE AND DOUBLE/H32
C                       - SINGLE/H36,H48,H60
C
C   REQD. IMSL ROUTINES - LUDECP,LUELMP,UERTST,UGETIO
C
C   NOTATION            - INFORMATION ON SPECIAL NOTATION AND
C                           CONVENTIONS IS AVAILABLE IN THE MANUAL
C                           INTRODUCTION OR THROUGH IMSL ROUTINE UHELP
C
C   COPYRIGHT           - 1978 BY IMSL, INC. ALL RIGHTS RESERVED.
C
C   WARRANTY            - IMSL WARRANTS ONLY THAT IMSL TESTING HAS BEEN
C                           APPLIED TO THIS CODE. NO OTHER WARRANTY,
C                           EXPRESSED OR IMPLIED, IS APPLICABLE.
C
C-----------------------------------------------------------------------
C
      SUBROUTINE LEQT1P (A,M,N,B,IB,IDGT,D1,D2,IER)
C
      DIMENSION          A(1),B(IB,1)
      DOUBLE PRECISION   A,B,D1,D2
C                                  FIRST EXECUTABLE STATEMENT
C                                  INITIALIZE IER
      IER = 0
C                                  DECOMPOSE A
      CALL LUDECP (A,A,N,D1,D2,IER)
      IF (IER.NE.0) GO TO 9000
C                                  PERFORM ELIMINATION
      DO 5 I = 1,M
         CALL LUELMP (A,B(1,I),N,B(1,I))
    5 CONTINUE
      GO TO 9005
 9000 CONTINUE
      CALL UERTST(IER,6HLEQT1P)
 9005 RETURN
      END
C   IMSL ROUTINE NAME   - LUDECP
C
C-----------------------------------------------------------------------
C
C   COMPUTER            - IBM/DOUBLE
C
C   LATEST REVISION     - JANUARY 1, 1978
C
C   PURPOSE             - DECOMPOSITION OF A POSITIVE DEFINITE MATRIX -
C                           SYMMETRIC STORAGE MODE
C
C   USAGE               - CALL LUDECP (A,UL,N,D1,D2,IER)
C
C   ARGUMENTS    A      - INPUT VECTOR OF LENGTH N(N+1)/2 CONTAINING
C                           THE N BY N POSITIVE DEFINITE SYMMETRIC
C                           MATRIX STORED IN SYMMETRIC STORAGE MODE.
C                UL     - OUTPUT VECTOR OF LENGTH N(N+1)/2 CONTAINING
C                           THE DECOMPOSED MATRIX L SUCH THAT A = L*
C                           L-TRANSPOSE. L IS STORED IN SYMMETRIC
C                           STORAGE MODE. THE DIAGONAL OF L CONTAINS THE
C                           RECIPROCALS OF THE ACTUAL DIAGONAL ELEMENTS.
C                N      - ORDER OF A. (INPUT)
C                D1,D2  - COMPONENTS OF THE DETERMINANT OF A.
C                           DETERMINANT(A) = D1*2.**D2. (OUTPUT)
C                IER    - ERROR PARAMETER. (OUTPUT)
C                         TERMINAL ERROR
C                           IER = 129 INDICATES THAT MATRIX A IS
C                             ALGORITHMICALLY NOT POSITIVE DEFINITE.
C                             (SEE THE CHAPTER L PRELUDE).
C
C   PRECISION/HARDWARE  - SINGLE AND DOUBLE/H32
C                       - SINGLE/H36,H48,H60
C
C   REQD. IMSL ROUTINES - UERTST,UGETIO
C
C   NOTATION            - INFORMATION ON SPECIAL NOTATION AND
C                           CONVENTIONS IS AVAILABLE IN THE MANUAL
C                           INTRODUCTION OR THROUGH IMSL ROUTINE UHELP
C
C   COPYRIGHT           - 1978 BY IMSL, INC. ALL RIGHTS RESERVED.
C
C   WARRANTY            - IMSL WARRANTS ONLY THAT IMSL TESTING HAS BEEN
C                           APPLIED TO THIS CODE. NO OTHER WARRANTY,
C                           EXPRESSED OR IMPLIED, IS APPLICABLE.
C
C-----------------------------------------------------------------------
C
      SUBROUTINE LUDECP (A,UL,N,D1,D2,IER)
C
      DIMENSION          A(1),UL(1)
      DOUBLE PRECISION   A,UL,D1,D2,ZERO,ONE,FOUR,SIXTN,SIXTH,X,RN
      DATA               ZERO,ONE,FOUR,SIXTN,SIXTH/
     *                   0.0D0,1.D0,4.D0,16.D0,.0625D0/
C                                  FIRST EXECUTABLE STATEMENT
      D1=ONE
      D2=ZERO
      RN = ONE/(N*SIXTN)
      IP = 1
      IER=0
      DO 45 I = 1,N
         IQ = IP
         IR = 1
         DO 40 J = 1,I
            X = A(IP)
            IF (J .EQ. 1) GO TO 10
            DO 5  K=IQ,IP1
               X = X - UL(K) * UL(IR)
               IR = IR+1
    5       CONTINUE
   10       IF (I.NE.J) GO TO 30
            D1 = D1*X
            IF (A(IP) + X*RN .LE. A(IP)) GO TO 50
   15       IF (DABS(D1).LE.ONE) GO TO 20
            D1 = D1 * SIXTH
            D2 = D2 + FOUR
            GO TO 15
   20       IF (DABS(D1) .GE. SIXTH) GO TO 25
            D1 = D1 * SIXTN
            D2 = D2 - FOUR
            GO TO 20
   25       UL(IP) = ONE/DSQRT(X)
            GO TO 35
   30       UL(IP) = X * UL(IR)
   35       IP1 = IP
            IP = IP+1
            IR = IR+1
   40    CONTINUE
   45 CONTINUE
      GO TO 9005
   50 IER = 129
 9000 CONTINUE
      CALL UERTST(IER,6HLUDECP)
 9005 RETURN
      END
C   IMSL ROUTINE NAME   - LUELMP
C
C-----------------------------------------------------------------------
C
C   COMPUTER            - IBM/DOUBLE
C
C   LATEST REVISION     - JANUARY 1, 1978
C
C   PURPOSE             - ELIMINATION PART OF THE SOLUTION OF AX=B -
C                           POSITIVE DEFINITE MATRIX - SYMMETRIC
C                           STORAGE MODE
C
C   USAGE               - CALL LUELMP (A,B,N,X)
C
C   ARGUMENTS    A      - INPUT VECTOR OF LENGTH N(N+1)/2 CONTAINING
C                           THE N BY N MATRIX L WHERE A = L*L-TRANSPOSE.
C                           L IS A LOWER TRIANGULAR MATRIX STORED IN
C                           SYMMETRIC STORAGE MODE. THE MAIN DIAGONAL
C                           ELEMENTS OF L ARE STORED IN RECIPROCAL
C                           FORM. MATRIX L MAY BE OBTAINED FROM IMSL
C                           ROUTINE LUDECP.
C                B      - VECTOR OF LENGTH N CONTAINING THE RIGHT HAND
C                           SIDE OF THE EQUATION AX = B. (INPUT)
C                N      - ORDER OF A AND THE LENGTH OF B AND X. (INPUT)
C                X      - VECTOR OF LENGTH N CONTAINING THE SOLUTION TO
C                           THE EQUATION AX = B. (OUTPUT)
C
C   PRECISION/HARDWARE  - SINGLE AND DOUBLE/H32
C                       - SINGLE/H36,H48,H60
C
C   REQD. IMSL ROUTINES - NONE REQUIRED
C
C   NOTATION            - INFORMATION ON SPECIAL NOTATION AND
C                           CONVENTIONS IS AVAILABLE IN THE MANUAL
C                           INTRODUCTION OR THROUGH IMSL ROUTINE UHELP
C
C   COPYRIGHT           - 1978 BY IMSL, INC. ALL RIGHTS RESERVED.
C
C   WARRANTY            - IMSL WARRANTS ONLY THAT IMSL TESTING HAS BEEN
C                           APPLIED TO THIS CODE. NO OTHER WARRANTY,
C                           EXPRESSED OR IMPLIED, IS APPLICABLE.
C
C-----------------------------------------------------------------------
C
      SUBROUTINE LUELMP (A,B,N,X)
C
      DIMENSION          A(1),B(1),X(1)
      DOUBLE PRECISION   A,B,X,T,ZERO
      DATA               ZERO/0.0D0/
C                                  FIRST EXECUTABLE STATEMENT
C                                  SOLUTION OF LY = B
      IP=1
      IW = 0
      DO 15 I=1,N
         T=B(I)
         IM1 = I-1
         IF (IW .EQ. 0) GO TO 9
         IP=IP+IW-1
         DO 5 K=IW,IM1
            T = T-A(IP)*X(K)
            IP=IP+1
    5    CONTINUE
         GO TO 10
    9    IF (T .NE. ZERO) IW = I
         IP = IP+IM1
   10    X(I)=T*A(IP)
         IP=IP+1
   15 CONTINUE
C                                  SOLUTION OF UX = Y
      N1 = N+1
      DO 30 I = 1,N
         II = N1-I
         IP=IP-1
         IS=IP
         IQ=II+1
         T=X(II)
         IF (N.LT.IQ) GO TO 25
         KK = N
         DO 20 K=IQ,N
            T = T - A(IS) * X(KK)
            KK = KK-1
            IS = IS-KK
   20    CONTINUE
   25    X(II)=T*A(IS)
   30 CONTINUE
      RETURN
      END
C   IMSL ROUTINE NAME   - UGETIO
C
C-----------------------------------------------------------------------
C
C   COMPUTER            - IBM/SINGLE
C
C   LATEST REVISION     - JANUARY 1, 1978
C
C   PURPOSE             - TO RETRIEVE CURRENT VALUES AND TO SET NEW
C                           VALUES FOR INPUT AND OUTPUT UNIT
C                           IDENTIFIERS.
C
C   USAGE               - CALL UGETIO(IOPT,NIN,NOUT)
C
C   ARGUMENTS    IOPT   - OPTION PARAMETER. (INPUT)
C                           IF IOPT=1, THE CURRENT INPUT AND OUTPUT
C                           UNIT IDENTIFIER VALUES ARE RETURNED IN NIN
C                           AND NOUT, RESPECTIVELY.
C                           IF IOPT=2 (3) THE INTERNAL VALUE OF
C                           NIN (NOUT) IS RESET FOR SUBSEQUENT USE.
C                NIN    - INPUT UNIT IDENTIFIER.
C                           OUTPUT IF IOPT=1, INPUT IF IOPT=2.
C                NOUT   - OUTPUT UNIT IDENTIFIER.
C                           OUTPUT IF IOPT=1, INPUT IF IOPT=3.
C
C   PRECISION/HARDWARE  - SINGLE/ALL
C
C   REQD. IMSL ROUTINES - NONE REQUIRED
C
C   NOTATION            - INFORMATION ON SPECIAL NOTATION AND
C                           CONVENTIONS IS AVAILABLE IN THE MANUAL
C                           INTRODUCTION OR THROUGH IMSL ROUTINE UHELP
C
C   REMARKS      EACH IMSL ROUTINE THAT PERFORMS INPUT AND/OR OUTPUT
C                OPERATIONS CALLS UGETIO TO OBTAIN THE CURRENT UNIT
C                IDENTIFIER VALUES. IF UGETIO IS CALLED WITH IOPT=2 OR 3
C                NEW UNIT IDENTIFIER VALUES ARE ESTABLISHED. SUBSEQUENT
C                INPUT/OUTPUT IS PERFORMED ON THE NEW UNITS.
C
C   COPYRIGHT           - 1978 BY IMSL, INC. ALL RIGHTS RESERVED.
C
C   WARRANTY            - IMSL WARRANTS ONLY THAT IMSL TESTING HAS BEEN
C                           APPLIED TO THIS CODE. NO OTHER WARRANTY,
C                           EXPRESSED OR IMPLIED, IS APPLICABLE.
C
C-----------------------------------------------------------------------
C
      SUBROUTINE UGETIO(IOPT,NIN,NOUT)
C                                  SPECIFICATIONS FOR ARGUMENTS
      INTEGER            IOPT,NIN,NOUT
C                                  SPECIFICATIONS FOR LOCAL VARIABLES
      INTEGER            NIND,NOUTD
      DATA               NIND/5/,NOUTD/6/
C                                  FIRST EXECUTABLE STATEMENT
      IF (IOPT.EQ.3) GO TO 10
      IF (IOPT.EQ.2) GO TO 5
      IF (IOPT.NE.1) GO TO 9005
      NIN = NIND
      NOUT = NOUTD
      GO TO 9005
    5 NIND = NIN
      GO TO 9005
   10 NOUTD = NOUT
 9005 RETURN
      END
      FUNCTION RANF(IDUM)
      PARAMETER (M=714025,IA=1366,IC=150889,RM=1.0/M)
      DIMENSION IR(97)
      DATA IFF /0/
      IF(IDUM.LT.0.OR.IFF.EQ.0) THEN
        IFF=1
        IDUM=MOD(IC-IDUM,M)
        DO 11 J=1,97
           IDUM=MOD(IA*IDUM+IC,M)
           IR(J)=IDUM
  11    CONTINUE
        IDUM=MOD(IA*IDUM+IC,M)
        IY=IDUM
      ENDIF
      J=1+(97*IY)/M
      IF(J.GT.97.OR.J.LT.1) THEN
      PRINT *,' RANF: J=',J
      STOP
      ENDIF
      IY=IR(J)
      RANF=IY*RM
      IDUM=MOD(IA*IDUM+IC,M)
      IR(J)=IDUM
      RETURN
      END