!
!##################################################################
!##################################################################
!######                                                      ######
!######                 SUBROUTINE VA15AD                    ######
!######                                                      ######
!######     Center for Analysis and Prediction of Storms     ######
!######                University of Oklahoma                ######
!######                                                      ######
!##################################################################
!##################################################################
!
!-----------------------------------------------------------------------
!
!  PURPOSE:
!
!  minimization code.
!
!-----------------------------------------------------------------------
!
!  AUTHOR:
!
!  unknown, copied from Florida state University. 
!
!-----------------------------------------------------------------------
!
!
!  ----------------------------------------------------------------------
!
!  CALL VA15AD(Numctr,MGRA,ctrv,CFUN,grad,DIAGCO,DIAG,IPRINT,
!    :                  EPS,SWORK,YWORK,POINT,WORK,IFLAG,FTOL)
!
!


SUBROUTINE va15ad(n,m,x,f,g,diagco,diag,iprint,eps,s,y,                 & 1,3
           point,w,iflag,ftol)
!
!
  REAL :: x(n),g(n),s(m*n),y(m*n),diag(n),w(n+2*m)
  REAL :: ftol,gtol,xtol,stpmin,stpmax,stp,f,ys,sq,                     &
                yr,beta,one,zero,eps,xnorm,gnorm,yy,ddot,stp1
!
!
  INTEGER :: bound,lp,iter,nfun,nfev,iprint(2),point,cp,iflag
  LOGICAL :: finish,diagco
  COMMON /va15dd/mp,lp, gtol
  SAVE
  DATA one,zero/1.0E+0,0.0E+0/
!
!  ------------------------------------------------------------
!  INITIALIZE
!  ------------------------------------------------------------
!
  IF(iflag == 0) GO TO 1
  GO TO (72,10) iflag
  1  iter= 0
  IF(n <= 0.OR.m <= 0) GO TO 96
  IF(gtol <= 1.d-04) THEN
    IF(lp > 0) WRITE(lp,145)
    gtol=1.d-02
  END IF
  nfun= 1
  point= 0
  finish= .false.
  IF(diagco) THEN
    DO i=1,n
      IF (diag(i) <= zero) GO TO 95
    END DO
  ELSE
    DO i=1,n
      diag(i)= 1.0D0
    END DO
  END IF
  DO i=1,n
    s(i)= -g(i)*diag(i)
  END DO
  gnorm= SQRT(ddot(n,g,1,g,1))
  IF( gnorm > 0.0 ) THEN
    stp1= one/gnorm
  ELSE
   iflag=-13 
   return
  ENDIF
!
!  PARAMETERS FOR LINE SEARCH ROUTINE
!  ----------------------------------
  xtol= 1.0D-17
  stpmin= 1.0D-20
  stpmax= 1.0D+20
  maxfev= 20
!
  print*,'iprint=',iprint,iter,nfun,n,m,f,stp,finish
  CALL va15bd(iprint,iter,nfun,                                         &
                      n,m,x,f,g,stp,finish)
!
!    ------------------------------------------------------------
!  MAIN ITERATION LOOP
!    --------------------------------------------------------
!
  8    iter= iter+1
  info=0
  bound=iter-1
  IF (iter > m)bound=m
  IF(iter == 1) GO TO 65
!
!  ------------------------------------------------------------
!  COMPUTE -HG AND THE DIAGONAL SCALING MATRIX IN DIAG
!  ------------------------------------------------------------
!
  IF(.NOT.diagco) THEN
    DO i=1,n
      diag(i)= ys/yy
    END DO
  ELSE
    iflag=2
    RETURN
  END IF
  10  CONTINUE
  DO i=1,n
    IF (diag(i) <= zero) GO TO 95
  END DO
!
  cp= point
  IF (point == 0) cp=m
  w(n+cp)= one/ys
  DO i=1,n
    w(i)= -g(i)
  END DO
  cp= point
  DO ii= 1,bound
    cp=cp-1
    IF (cp == -1)cp=m-1
    sq= ddot(n,s(cp*n+1),1,w,1)
    w(n+m+cp+1)= w(n+cp+1)*sq
    DO k=1,n
      w(k)= w(k)-w(n+m+cp+1)*y(cp*n+k)
    END DO
  END DO
!
  DO i=1,n
    w(i)=diag(i)*w(i)
  END DO
  DO ii=1,bound
    yr= ddot(n,y(cp*n+1),1,w,1)
    beta= w(n+cp+1)*yr
    DO k=1,n
      w(k)= w(k)+s(cp*n+k)*(w(n+m+cp+1)-beta)
    END DO
    cp=cp+1
    IF (cp == m)cp=0
  END DO
!
!  ------------------------------------------------------------
!  STORE THE NEW DIRECTION IN S
!  ------------------------------------------------------------
!
  DO j=1,n
    s(point*n+j)= w(j)
  END DO
!
!  ------------------------------------------------------------
!  OBTAIN THE MINIMIZER OF THE FUNCTION ALONG THE
!  DIRECTION S BY USING THE LINE SEARCH ROUTINE OF VD05AD
!  ------------------------------------------------------------
  65  nfev=0
  stp=one
  IF (iter == 1) stp=stp1
  DO i=1,n
    w(i)=g(i)
  END DO
  72  CONTINUE
!
  CALL vd05ad(n,x,f,g,s(point*n+1),stp,ftol,gtol,                       &
              xtol,stpmin,stpmax,maxfev,info,nfev,diag)
!
  IF (info == -1) THEN
    iflag=1
    RETURN
  END IF
  IF (info /= 1) GO TO 90
  nfun= nfun + nfev
!
!  ------------------------------------------------------------
!  COMPUTE THE NEW S AND Y
!  ------------------------------------------------------------
!
  npt=point*n
  DO i=1,n
    s(npt+i)= stp*s(npt+i)
    y(npt+i)= g(i)-w(i)
  END DO
  ys= ddot(n,y(npt+1),1,s(npt+1),1)
  yy= ddot(n,y(npt+1),1,y(npt+1),1)
  point=point+1
  IF (point == m)point=0
!
!  ------------------------------------------------------------
!  CONVERGENCE CHECK
!  ------------------------------------------------------------
!
  gnorm= ddot(n,g,1,g,1)
  gnorm=SQRT(gnorm)
  xnorm= ddot(n,x,1,x,1)
  xnorm=SQRT(xnorm)
! xnorm= MAX1(1.0,xnorm)
  xnorm= MAX(1.0,xnorm)
!
  IF (gnorm/xnorm <= eps) finish=.true.
!
  CALL va15bd(iprint,iter,nfun,                                         &
                 n,m,x,f,g,stp,finish)
  IF (finish) THEN
    iflag=0
    RETURN
  END IF
  GO TO 8
!
!  ------------------------------------------------------------
!  END OF MAIN ITERATION LOOP. ERROR EXITS.
!  ------------------------------------------------------------
!
  90  IF(lp <= 0) RETURN
  IF (info == 0) THEN
    iflag= -1
    WRITE(lp,100)iflag
  ELSE IF (info == 2) THEN
    iflag= -2
    WRITE(lp,105)iflag
  ELSE IF (info == 3) THEN
    iflag= -3
    WRITE(lp,110)iflag
  ELSE IF (info == 4) THEN
    iflag= -4
    WRITE(lp,115)iflag
  ELSE IF (info == 5) THEN
    iflag= -5
    WRITE(lp,120)iflag
  ELSE IF (info == 6) THEN
    iflag= -6
    WRITE(lp,125)iflag
  END IF
  RETURN
!
  95  iflag= -7
  IF(lp > 0) WRITE(lp,135)iflag,i
  RETURN
  96  iflag= -8
  IF(lp > 0) WRITE(lp,140)iflag
!
!  ------------------------------------------------------------
!  FORMATS
!  ------------------------------------------------------------
!
  100  FORMAT(/' IFLAG= ',i2,/' IMPROPER INPUT PARAMETERS DURING',      &
              ' THE LINE SEARCH.')
  105  FORMAT(/' IFLAG= ',i2,/' RELATIVE WIDTH OF THE INTERVAL OF',     &
              ' UNCERTAINTY IN THE LINE SEARCH'                         &
              /'IS OF THE ORDER OF machine roundoff.')
  110  FORMAT(/' IFLAG= ',i2,/' NUMBER OF CALLS TO FUNCTION IN THE',    &
              ' LINE SEARCH HAS REACHED 20.')
  115  FORMAT(/' IFLAG= ',i2,/' THE STEP IN THE LINE SEARCH IS',        &
              ' TOO SMALL.')
  120  FORMAT(/' IFLAG= ',i2,/' THE STEP IN THE LINE SEARCH IS',        &
              ' TOO LARGE.')
  125  FORMAT(/' IFLAG= ',i2,/' ROUNDING ERRORS PREVENT FURTHER',       &
              ' PROGRESS IN THE LINE SEARCH.')
  135  FORMAT(/' IFLAG= ',i2,/' THE',i5,'-TH DIAGONAL ELEMENT OF THE',  &
              ' INVERSE HESSIAN APPROXIMATION IS NOT POSITIVE')
  140  FORMAT(/' IFLAG= ',i2,/' IMPROPER INPUT PARAMETERS (N OR M',     &
              ' ARE NOT POSITIVE)')
  145  FORMAT(/'  GTOL IS LESS THAN OR EQUAL TO 1.D-04',                &
              / 'IT HAS BEEN RESET TO 1.D-02')
  RETURN
END SUBROUTINE va15ad
!
!
!
!


SUBROUTINE va15bd(iprint,iter,nfun,                                     & 2
           n,m,x,f,g,stp,finish)
!
!  ---------------------------------------------------------------------
!  THIS ROUTINE PRINTS MONITORING INFORMATION. THE FREQUENCY AND AMOUNT
!  OF OUTPUT ARE SPECIFIED AS FOLLOWS:
!
!  IPRINT(1) < 0 : NO OUTPUT IS GENERATED
!  IPRINT(1) = 0 : OUTPUT ONLY AT FIRST AND LAST ITERATION
!  IPRINT(1) 0 : OUTPUT EVERY IPRINT(1) ITERATION
!  IPRINT(2) = 0 : ITERATION COUNT, FUNCTION VALUE, NORM OF THE GRADIENT
!                  ,NUMBER OF FUNCTION CALLS AND STEP LENGTH
!  IPRINT(2) = 1 : + VECTOR OF VARIABLES AND GRADIENT VECTOR AT THE
!                    INITIAL POINT
!  IPRINT(2) = 2 : + VECTOR OF VARIABLES
!  IPRINT(2) = 3 : + GRADIENT VECTOR
!  ---------------------------------------------------------------------
!
  REAL :: x(n),g(n),f,gnorm,stp,factor,ddot,gtol
  INTEGER :: iprint(2),iter,nfun,prob,lp
  LOGICAL :: finish
  COMMON /set/ factor,prob
  COMMON /va15dd/mp,lp, gtol
!
  IF (iprint(1) < 0)RETURN
  gnorm= ddot(n,g,1,g,1)
  gnorm= SQRT(gnorm)
  IF (iter == 0)THEN
    WRITE(mp,10)
    WRITE(mp,20) prob,n,m
    WRITE(mp,30)f,gnorm
    IF (iprint(2) >= 1)THEN
      WRITE(mp,40)
      WRITE(mp,50) (x(i),i=1,n)
      WRITE(mp,60)
      WRITE(mp,50) (g(i),i=1,n)
    END IF
    WRITE(mp,10)
    WRITE(mp,70)
  ELSE
    IF ((iprint(1) == 0).AND.(iter /= 1.AND..NOT.finish))RETURN
    IF (iprint(1) /= 0)THEN
      IF(MOD(iter-1,iprint(1)) == 0.OR.finish)THEN
        WRITE(mp,80)iter,nfun,f,gnorm,stp
      ELSE
        RETURN
      END IF
    ELSE
      WRITE(mp,80)iter,nfun,f,gnorm,stp
    END IF
    IF (iprint(2) == 2.OR.iprint(2) == 3)THEN
      IF (finish)THEN
        WRITE(mp,90)
      ELSE
        WRITE(mp,40)
      END IF
      WRITE(mp,50)(x(i),i=1,n)
      IF (iprint(2) == 3)THEN
        WRITE(mp,60)
        WRITE(mp,50)(g(i),i=1,n)
      END IF
    END IF
    IF (finish) WRITE(mp,100)
  END IF
!
  10   FORMAT('*************************************************')
  20   FORMAT(' PROB=',i3,'   N=',i9,'   NUMBER OF CORRECTIONS=',i2)
  30   FORMAT(' F= ',1PD10.3,'   GNORM= ',1PD10.3)
  40   FORMAT(' VECTOR X= ')
  50   FORMAT(6(2X,1PD10.3))
  60   FORMAT(' GRADIENT VECTOR G= ')
  70   FORMAT(/'   I   NFN',4X,'FUNC',8X,'GNORM',7X,'STEPLENGTH'/)
  80   FORMAT(2(i4,1X),3X,3(1PD10.3,2X))
  90   FORMAT(' FINAL POINT X= ')
  100  FORMAT(/' THE MINIMIZATION TERMINATED WITHOUT DETECTING ERRORS.', &
              /' IFLAG = 0')
!
  RETURN
END SUBROUTINE va15bd
!
!   ----------------------------------------------------------
!   DATA BLOCK
!   ----------------------------------------------------------
!
  BLOCK DATA va15cd
  COMMON /va15dd/mp,lp, gtol
  INTEGER :: lp
  REAL :: gtol
  DATA mp,lp,gtol/6,6,9.0E-01/
  END
!
!   -------------------------------------------------------------
!


SUBROUTINE vd05ad(n,x,f,g,s,stp,ftol,gtol,xtol,                         & 1,2
           stpmin,stpmax,maxfev,info,nfev,wa)
  INTEGER :: n,maxfev,info,nfev
  REAL :: f,stp,ftol,gtol,xtol,stpmin,stpmax
  REAL :: x(n),g(n),s(n),wa(n)
  SAVE
!  **********
!
!  SUBROUTINE VD05AD
!
!  THE PURPOSE OF VD05AD IS TO FIND A STEP WHICH SATISFIES
!  A SUFFICIENT DECREASE CONDITION AND A CURVATURE CONDITION.
!  THE USER MUST PROVIDE A SUBROUTINE WHICH CALCULATES THE
!  FUNCTION AND THE GRADIENT.
!
!  AT EACH STAGE THE SUBROUTINE UPDATES AN INTERVAL OF
!  UNCERTAINTY WITH ENDPOINTS STX AND STY. THE INTERVAL OF
!  UNCERTAINTY IS INITIALLY CHOSEN SO THAT IT CONTAINS A
!  MINIMIZER OF THE MODIFIED FUNCTION
!
!       F(X+STP*S) - F(X) - FTOL*STP*(GRADF(X)'S).
!
!  IF A STEP IS OBTAINED FOR WHICH THE MODIFIED FUNCTION
!  HAS A NONPOSITIVE FUNCTION VALUE AND NONNEGATIVE DERIVATIVE,
!  THEN THE INTERVAL OF UNCERTAINTY IS CHOSEN SO THAT IT
!  CONTAINS A MINIMIZER OF F(X+STP*S).
!
!  THE ALGORITHM IS DESIGNED TO FIND A STEP WHICH SATISFIES
!  THE SUFFICIENT DECREASE CONDITION
!
!        F(X+STP*S) .LE. F(X) + FTOL*STP*(GRADF(X)'S),
!
!  AND THE CURVATURE CONDITION
!
!        ABS(GRADF(X+STP*S)'S)) .LE. GTOL*ABS(GRADF(X)'S).
!
!  IF FTOL IS LESS THAN GTOL AND IF, FOR EXAMPLE, THE FUNCTION
!  IS BOUNDED BELOW, THEN THERE IS ALWAYS A STEP WHICH SATISFIES
!  BOTH CONDITIONS. IF NO STEP CAN BE FOUND WHICH SATISFIES BOTH
!  CONDITIONS, THEN THE ALGORITHM USUALLY STOPS WHEN ROUNDING
!  ERRORS PREVENT FURTHER PROGRESS. IN THIS CASE STP ONLY
!  SATISFIES THE SUFFICIENT DECREASE CONDITION.
!
!  THE SUBROUTINE STATEMENT IS
!
!     SUBROUTINE VD05AD(N,X,F,G,S,STP,FTOL,GTOL,XTOL,
!                       STPMIN,STPMAX,MAXFEV,INFO,NFEV,WA)
!  WHERE
!
!    N IS A POSITIVE INTEGER INPUT VARIABLE SET TO THE NUMBER
!      OF VARIABLES.
!
!    X IS AN ARRAY OF LENGTH N. ON INPUT IT MUST CONTAIN THE
!      BASE POINT FOR THE LINE SEARCH. ON OUTPUT IT CONTAINS
!      X + STP*S.
!
!    F IS A VARIABLE. ON INPUT IT MUST CONTAIN THE VALUE OF F
!      AT X. ON OUTPUT IT CONTAINS THE VALUE OF F AT X + STP*S.
!
!    G IS AN ARRAY OF LENGTH N. ON INPUT IT MUST CONTAIN THE
!      GRADIENT OF F AT X. ON OUTPUT IT CONTAINS THE GRADIENT
!      OF F AT X + STP*S.
!
!    S IS AN INPUT ARRAY OF LENGTH N WHICH SPECIFIES THE
!      SEARCH DIRECTION.
!
!    STP IS A NONNEGATIVE VARIABLE. ON INPUT STP CONTAINS AN
!      INITIAL ESTIMATE OF A SATISFACTORY STEP. ON OUTPUT
!      STP CONTAINS THE FINAL ESTIMATE.
!
!    FTOL AND GTOL ARE NONNEGATIVE INPUT VARIABLES. TERMINATION
!      OCCURS WHEN THE SUFFICIENT DECREASE CONDITION AND THE
!      DIRECTIONAL DERIVATIVE CONDITION ARE SATISFIED.
!
!    XTOL IS A NONNEGATIVE INPUT VARIABLE. TERMINATION OCCURS
!      WHEN THE RELATIVE WIDTH OF THE INTERVAL OF UNCERTAINTY
!      IS AT MOST XTOL.
!
!    STPMIN AND STPMAX ARE NONNEGATIVE INPUT VARIABLES WHICH
!      SPECIFY LOWER AND UPPER BOUNDS FOR THE STEP.
!
!    MAXFEV IS A POSITIVE INTEGER INPUT VARIABLE. TERMINATION
!      OCCURS WHEN THE NUMBER OF CALLS TO FCN IS AT LEAST
!      MAXFEV BY THE END OF AN ITERATION.
!
!    INFO IS AN INTEGER OUTPUT VARIABLE SET AS FOLLOWS:
!
!      INFO = 0  IMPROPER INPUT PARAMETERS.
!
!      INFO =-1  A RETURN IS MADE TO COMPUTE THE FUNCTION AND GRADIENT.
!
!      INFO = 1  THE SUFFICIENT DECREASE CONDITION AND THE
!                DIRECTIONAL DERIVATIVE CONDITION HOLD.
!
!      INFO = 2  RELATIVE WIDTH OF THE INTERVAL OF UNCERTAINTY
!                IS AT MOST XTOL.
!
!      INFO = 3  NUMBER OF CALLS TO FCN HAS REACHED MAXFEV.
!
!      INFO = 4  THE STEP IS AT THE LOWER BOUND STPMIN.
!
!      INFO = 5  THE STEP IS AT THE UPPER BOUND STPMAX.
!
!      INFO = 6  ROUNDING ERRORS PREVENT FURTHER PROGRESS.
!                THERE MAY NOT BE A STEP WHICH SATISFIES THE
!                SUFFICIENT DECREASE AND CURVATURE CONDITIONS.
!                TOLERANCES MAY BE TOO SMALL.
!
!    NFEV IS AN INTEGER OUTPUT VARIABLE SET TO THE NUMBER OF
!      CALLS TO FCN.
!
!    WA IS A WORK ARRAY OF LENGTH N.
!
!  SUBPROGRAMS CALLED
!
!    HARWELL-SUPPLIED...VD05BD
!
!    FORTRAN-SUPPLIED...ABS,MAX,MIN
!
!  ARGONNE NATIONAL LABORATORY. MINPACK PROJECT. JUNE 1983
!  JORGE J. MORE', DAVID J. THUENTE
!
!  **********
  INTEGER :: infoc,j
  LOGICAL :: brackt,stage1
  REAL :: dg,dgm,dginit,dgtest,dgx,dgxm,dgy,dgym,                       &
         finit,ftest1,fm,fx,fxm,fy,fym,p5,p66,stx,sty,                  &
         stmin,stmax,width,width1,xtrapf,zero
  DATA p5,p66,xtrapf,zero /0.5E0,0.66E0,4.0E0,0.0E0/
  IF(info == -1) GO TO 45
  infoc = 1
!
!  CHECK THE INPUT PARAMETERS FOR ERRORS.
!
  IF (n <= 0 .OR. stp <= zero .OR. ftol < zero .OR.                     &
      gtol < zero .OR. xtol < zero .OR. stpmin < zero                   &
      .OR. stpmax < stpmin .OR. maxfev <= 0) RETURN
!
!  COMPUTE THE INITIAL GRADIENT IN THE SEARCH DIRECTION
!  AND CHECK THAT S IS A DESCENT DIRECTION.
!
  dginit = zero
  DO j = 1, n
    dginit = dginit + g(j)*s(j)
  END DO
  IF (dginit >= zero) RETURN
!
!  INITIALIZE LOCAL VARIABLES.
!
  brackt = .false.
  stage1 = .true.
  nfev = 0
  finit = f
  dgtest = ftol*dginit
  width = stpmax - stpmin
  width1 = width/p5
  DO j = 1, n
    wa(j) = x(j)
  END DO
!
!  THE VARIABLES STX, FX, DGX CONTAIN THE VALUES OF THE STEP,
!  FUNCTION, AND DIRECTIONAL DERIVATIVE AT THE BEST STEP.
!  THE VARIABLES STY, FY, DGY CONTAIN THE VALUE OF THE STEP,
!  FUNCTION, AND DERIVATIVE AT THE OTHER ENDPOINT OF
!  THE INTERVAL OF UNCERTAINTY.
!  THE VARIABLES STP, F, DG CONTAIN THE VALUES OF THE STEP,
!  FUNCTION, AND DERIVATIVE AT THE CURRENT STEP.
!
  stx = zero
  fx = finit
  dgx = dginit
  sty = zero
  fy = finit
  dgy = dginit
!
!  START OF ITERATION.
!
  30 CONTINUE
!
!     SET THE MINIMUM AND MAXIMUM STEPS TO CORRESPOND
!     TO THE PRESENT INTERVAL OF UNCERTAINTY.
!
  IF (brackt) THEN
    stmin = MIN(stx,sty)
    stmax = MAX(stx,sty)
  ELSE
    stmin = stx
    stmax = stp + xtrapf*(stp - stx)
  END IF
!
!     FORCE THE STEP TO BE WITHIN THE BOUNDS STPMAX AND STPMIN.
!
  stp = MAX(stp,stpmin)
  stp = MIN(stp,stpmax)
!
   print*,'stp =================',stp
!
!     IF AN UNUSUAL TERMINATION IS TO OCCUR THEN LET
!     STP BE THE LOWEST POINT OBTAINED SO FAR.
!
  IF ((brackt .AND. (stp <= stmin .OR. stp >= stmax))                   &
      .OR. nfev >= maxfev-1 .OR. infoc == 0                             &
      .OR. (brackt .AND. stmax-stmin <= xtol*stmax)) stp = stx
!
!     EVALUATE THE FUNCTION AND GRADIENT AT STP
!     AND COMPUTE THE DIRECTIONAL DERIVATIVE.
!
  DO j = 1, n
    x(j) = wa(j) + stp*s(j)
  END DO
  info=-1
  RETURN
!
  45    info=0
  nfev = nfev + 1
  dg = zero
  DO j = 1, n
    dg = dg + g(j)*s(j)
  END DO
  ftest1 = finit + stp*dgtest
!
!     TEST FOR CONVERGENCE.
!
  IF ((brackt .AND. (stp <= stmin .OR. stp >= stmax)) .OR. infoc == 0) info = 6
  IF (stp == stpmax .AND. f <= ftest1 .AND. dg <= dgtest) info = 5
  IF (stp == stpmin .AND. (f > ftest1 .OR. dg >= dgtest)) info = 4
  IF (nfev >= maxfev) info = 3
  IF (brackt .AND. stmax-stmin <= xtol*stmax) info = 2
  IF (f <= ftest1 .AND. ABS(dg) <= gtol*(-dginit)) info = 1
!
!     CHECK FOR TERMINATION.
!
  IF (info /= 0) RETURN
!
!     IN THE FIRST STAGE WE SEEK A STEP FOR WHICH THE MODIFIED
!     FUNCTION HAS A NONPOSITIVE VALUE AND NONNEGATIVE DERIVATIVE.
!
  IF (stage1 .AND. f <= ftest1 .AND.                                    &
      dg >= MIN(ftol,gtol)*dginit) stage1 = .false.
!
!     A MODIFIED FUNCTION IS USED TO PREDICT THE STEP ONLY IF
!     WE HAVE NOT OBTAINED A STEP FOR WHICH THE MODIFIED
!     FUNCTION HAS A NONPOSITIVE FUNCTION VALUE AND NONNEGATIVE
!     DERIVATIVE, AND IF A LOWER FUNCTION VALUE HAS BEEN
!     OBTAINED BUT THE DECREASE IS NOT SUFFICIENT.
!
  IF (stage1 .AND. f <= fx .AND. f > ftest1) THEN
!
!        DEFINE THE MODIFIED FUNCTION AND DERIVATIVE VALUES.
!
    fm = f - stp*dgtest
    fxm = fx - stx*dgtest
    fym = fy - sty*dgtest
    dgm = dg - dgtest
    dgxm = dgx - dgtest
    dgym = dgy - dgtest
!
!        CALL CSTEP TO UPDATE THE INTERVAL OF UNCERTAINTY
!        AND TO COMPUTE THE NEW STEP.
!
    CALL vd05bd(stx,fxm,dgxm,sty,fym,dgym,stp,fm,dgm,                   &
               brackt,stmin,stmax,infoc)
!
!        RESET THE FUNCTION AND GRADIENT VALUES FOR F.
!
    fx = fxm + stx*dgtest
    fy = fym + sty*dgtest
    dgx = dgxm + dgtest
    dgy = dgym + dgtest
  ELSE
!
!        CALL VD05BD TO UPDATE THE INTERVAL OF UNCERTAINTY
!        AND TO COMPUTE THE NEW STEP.
!
    CALL vd05bd(stx,fx,dgx,sty,fy,dgy,stp,f,dg,                         &
               brackt,stmin,stmax,infoc)
  END IF
!
!     FORCE A SUFFICIENT DECREASE IN THE SIZE OF THE
!     INTERVAL OF UNCERTAINTY.
!
  IF (brackt) THEN
    IF (ABS(sty-stx) >= p66*width1) stp = stx + p5*(sty - stx)
    width1 = width
    width = ABS(sty-stx)
  END IF
!
!     END OF ITERATION.
!
  GO TO 30
!
!  LAST CARD OF SUBROUTINE VD05AD.
!
END SUBROUTINE vd05ad
!
!
!
!


SUBROUTINE vd05bd(stx,fx,dx,sty,fy,dy,stp,fp,dp,brackt,                 & 2
           stpmin,stpmax,info)
  INTEGER :: info
  REAL :: stx,fx,dx,sty,fy,dy,stp,fp,dp,stpmin,stpmax
  LOGICAL :: brackt,bound
!  **********
!
!  SUBROUTINE VD05BD
!
!  THE PURPOSE OF VD05BD IS TO COMPUTE A SAFEGUARDED STEP FOR
!  A LINESEARCH AND TO UPDATE AN INTERVAL OF UNCERTAINTY FOR
!  A MINIMIZER OF THE FUNCTION.
!
!  THE PARAMETER STX CONTAINS THE STEP WITH THE LEAST FUNCTION
!  VALUE. THE PARAMETER STP CONTAINS THE CURRENT STEP. IT IS
!  ASSUMED THAT THE DERIVATIVE AT STX IS NEGATIVE IN THE
!  DIRECTION OF THE STEP. IF BRACKT IS SET TRUE THEN A
!  MINIMIZER HAS BEEN BRACKETED IN AN INTERVAL OF UNCERTAINTY
!  WITH ENDPOINTS STX AND STY.
!
!  THE SUBROUTINE STATEMENT IS
!
!    SUBROUTINE VD05BD(STX,FX,DX,STY,FY,DY,STP,FP,DP,BRACKT,
!                     STPMIN,STPMAX,INFO)
!
!  WHERE
!
!    STX, FX, AND DX ARE VARIABLES WHICH SPECIFY THE STEP,
!      THE FUNCTION, AND THE DERIVATIVE AT THE BEST STEP OBTAINED
!      SO FAR. THE DERIVATIVE MUST BE NEGATIVE IN THE DIRECTION
!      OF THE STEP, THAT IS, DX AND STP-STX MUST HAVE OPPOSITE
!      SIGNS. ON OUTPUT THESE PARAMETERS ARE UPDATED APPROPRIATELY.
!
!    STY, FY, AND DY ARE VARIABLES WHICH SPECIFY THE STEP,
!      THE FUNCTION, AND THE DERIVATIVE AT THE OTHER ENDPOINT OF
!      THE INTERVAL OF UNCERTAINTY. ON OUTPUT THESE PARAMETERS ARE
!      UPDATED APPROPRIATELY.
!
!    STP, FP, AND DP ARE VARIABLES WHICH SPECIFY THE STEP,
!      THE FUNCTION, AND THE DERIVATIVE AT THE CURRENT STEP.
!      IF BRACKT IS SET TRUE THEN ON INPUT STP MUST BE
!      BETWEEN STX AND STY. ON OUTPUT STP IS SET TO THE NEW STEP.
!
!    BRACKT IS A LOGICAL VARIABLE WHICH SPECIFIES IF A MINIMIZER
!      HAS BEEN BRACKETED. IF THE MINIMIZER HAS NOT BEEN BRACKETED
!      THEN ON INPUT BRACKT MUST BE SET FALSE. IF THE MINIMIZER
!      IS BRACKETED THEN ON OUTPUT BRACKT IS SET TRUE.
!
!    STPMIN AND STPMAX ARE INPUT VARIABLES WHICH SPECIFY LOWER
!      AND UPPER BOUNDS FOR THE STEP.
!
!    INFO IS AN INTEGER OUTPUT VARIABLE SET AS FOLLOWS:
!      IF INFO = 1,2,3,4,5, THEN THE STEP HAS BEEN COMPUTED
!      ACCORDING TO ONE OF THE FIVE CASES BELOW. OTHERWISE
!      INFO = 0, AND THIS INDICATES IMPROPER INPUT PARAMETERS.
!
!  SUBPROGRAMS CALLED
!
!    FORTRAN-SUPPLIED ... ABS,MAX,MIN,SQRT
!
!  ARGONNE NATIONAL LABORATORY. MINPACK PROJECT. JUNE 1983
!  JORGE J. MORE', DAVID J. THUENTE
!
!  **********
  REAL :: gamma,p,q,r,s,sgnd,stpc,stpf,stpq,theta
  info = 0
!
!  CHECK THE INPUT PARAMETERS FOR ERRORS.
!
  IF ((brackt .AND. (stp <= MIN(stx,sty) .OR. stp >= MAX(stx,sty))) .OR. &
      dx*(stp-stx) >= 0.0 .OR. stpmax < stpmin) RETURN
!
!  DETERMINE IF THE DERIVATIVES HAVE OPPOSITE SIGN.
!
  sgnd = dp*(dx/ABS(dx))
!
!  FIRST CASE. A HIGHER FUNCTION VALUE.
!  THE MINIMUM IS BRACKETED. IF THE CUBIC STEP IS CLOSER
!  TO STX THAN THE QUADRATIC STEP, THE CUBIC STEP IS TAKEN,
!  ELSE THE AVERAGE OF THE CUBIC AND QUADRATIC STEPS IS TAKEN.
!
  IF (fp > fx) THEN
    info = 1
    bound = .true.
    theta = 3*(fx - fp)/(stp - stx) + dx + dp
    s = MAX(ABS(theta),ABS(dx),ABS(dp))
    gamma = s*SQRT((theta/s)**2 - (dx/s)*(dp/s))
    IF (stp < stx) gamma = -gamma
    p = (gamma - dx) + theta
    q = ((gamma - dx) + gamma) + dp
    r = p/q
    stpc = stx + r*(stp - stx)
    stpq = stx + ((dx/((fx-fp)/(stp-stx)+dx))/2)*(stp - stx)
    IF (ABS(stpc-stx) < ABS(stpq-stx)) THEN
      stpf = stpc
    ELSE
      stpf = stpc + (stpq - stpc)/2
    END IF
    brackt = .true.
!
!  SECOND CASE. A LOWER FUNCTION VALUE AND DERIVATIVES OF
!  OPPOSITE SIGN. THE MINIMUM IS BRACKETED. IF THE CUBIC
!  STEP IS CLOSER TO STX THAN THE QUADRATIC (SECANT) STEP,
!  THE CUBIC STEP IS TAKEN, ELSE THE QUADRATIC STEP IS TAKEN.
!
  ELSE IF (sgnd < 0.0) THEN
    info = 2
    bound = .false.
    theta = 3*(fx - fp)/(stp - stx) + dx + dp
    s = MAX(ABS(theta),ABS(dx),ABS(dp))
    gamma = s*SQRT((theta/s)**2 - (dx/s)*(dp/s))
    IF (stp > stx) gamma = -gamma
    p = (gamma - dp) + theta
    q = ((gamma - dp) + gamma) + dx
    r = p/q
    stpc = stp + r*(stx - stp)
    stpq = stp + (dp/(dp-dx))*(stx - stp)
    IF (ABS(stpc-stp) > ABS(stpq-stp)) THEN
      stpf = stpc
    ELSE
      stpf = stpq
    END IF
    brackt = .true.
!
!  THIRD CASE. A LOWER FUNCTION VALUE, DERIVATIVES OF THE
!  SAME SIGN, AND THE MAGNITUDE OF THE DERIVATIVE DECREASES.
!  THE CUBIC STEP IS ONLY USED IF THE CUBIC TENDS TO INFINITY
!  IN THE DIRECTION OF THE STEP OR IF THE MINIMUM OF THE CUBIC
!  IS BEYOND STP. OTHERWISE THE CUBIC STEP IS DEFINED TO BE
!  EITHER STPMIN OR STPMAX. THE QUADRATIC (SECANT) STEP IS ALSO
!  COMPUTED AND IF THE MINIMUM IS BRACKETED THEN THE THE STEP
!  CLOSEST TO STX IS TAKEN, ELSE THE STEP FARTHEST AWAY IS TAKEN.
!
  ELSE IF (ABS(dp) < ABS(dx)) THEN
    info = 3
    bound = .true.
    theta = 3*(fx - fp)/(stp - stx) + dx + dp
    s = MAX(ABS(theta),ABS(dx),ABS(dp))
!
!     THE CASE GAMMA = 0 ONLY ARISES IF THE CUBIC DOES NOT TEND
!     TO INFINITY IN THE DIRECTION OF THE STEP.
!
    gamma = s*SQRT(MAX(0.0,(theta/s)**2 - (dx/s)*(dp/s)))
    IF (stp > stx) gamma = -gamma
    p = (gamma - dp) + theta
    q = (gamma + (dx - dp)) + gamma
    r = p/q
    IF (r < 0.0 .AND. gamma /= 0.0) THEN
      stpc = stp + r*(stx - stp)
    ELSE IF (stp > stx) THEN
      stpc = stpmax
    ELSE
      stpc = stpmin
    END IF
    stpq = stp + (dp/(dp-dx))*(stx - stp)
    IF (brackt) THEN
      IF (ABS(stp-stpc) < ABS(stp-stpq)) THEN
        stpf = stpc
      ELSE
        stpf = stpq
      END IF
    ELSE
      IF (ABS(stp-stpc) > ABS(stp-stpq)) THEN
        stpf = stpc
      ELSE
        stpf = stpq
      END IF
    END IF
!
!  FOURTH CASE. A LOWER FUNCTION VALUE, DERIVATIVES OF THE
!  SAME SIGN, AND THE MAGNITUDE OF THE DERIVATIVE DOES
!  NOT DECREASE. IF THE MINIMUM IS NOT BRACKETED, THE STEP
!  IS EITHER STPMIN OR STPMAX, ELSE THE CUBIC STEP IS TAKEN.
!
  ELSE
    info = 4
    bound = .false.
    IF (brackt) THEN
      theta = 3*(fp - fy)/(sty - stp) + dy + dp
      s = MAX(ABS(theta),ABS(dy),ABS(dp))
      gamma = s*SQRT((theta/s)**2 - (dy/s)*(dp/s))
      IF (stp > sty) gamma = -gamma
      p = (gamma - dp) + theta
      q = ((gamma - dp) + gamma) + dy
      r = p/q
      stpc = stp + r*(sty - stp)
      stpf = stpc
    ELSE IF (stp > stx) THEN
      stpf = stpmax
    ELSE
      stpf = stpmin
    END IF
  END IF
!
!  UPDATE THE INTERVAL OF UNCERTAINTY. THIS UPDATE DOES NOT
!  DEPEND ON THE NEW STEP OR THE CASE ANALYSIS ABOVE.
!
  IF (fp > fx) THEN
    sty = stp
    fy = fp
    dy = dp
  ELSE
    IF (sgnd < 0.0) THEN
      sty = stx
      fy = fx
      dy = dx
    END IF
    stx = stp
    fx = fp
    dx = dp
  END IF
!
!  COMPUTE THE NEW STEP AND SAFEGUARD IT.
!
  stpf = MIN(stpmax,stpf)
  stpf = MAX(stpmin,stpf)
  stp = stpf
  IF (brackt .AND. bound) THEN
    IF (sty > stx) THEN
      stp = MIN(stx+0.66*(sty-stx),stp)
    ELSE
      stp = MAX(stx+0.66*(sty-stx),stp)
    END IF
  END IF
  RETURN
!
!  LAST CARD OF SUBROUTINE VD05BD.
!
END SUBROUTINE vd05bd
!
!
!
!


  FUNCTION ddot(n,d,i1,s,i2)
!
!   -------------------------------------------------------
!   THIS FUNCTION COMPUTES THE INNER PRODUCT OF TWO VECTORS
!   -------------------------------------------------------
!
  REAL :: d(n),s(n),prod
  INTEGER :: i1,i2
!
  prod=0.0E0
  DO i=1,n
    prod= prod+d(i)*s(i)
  END DO
!
  ddot= prod
!
  RETURN
  END FUNCTION ddot
!
!
!     ##################################################################
!     ##################################################################
!     ######                                                      ######
!     ######                SUBROUTINE ADWCONTRA                  ######
!     ######                                                      ######
!     ######                Copyright (c) 1994                    ######
!     ######  Center for the Analysis and Prediction of Storms    ######
!     ######    University of Oklahoma.  All rights reserved.     ######
!     ######                                                      ######
!     ##################################################################
!     ##################################################################
!

      SUBROUTINE ADWCONTRA(nx,ny,nz,u,v,w,mapfct,j1,j2,j3,aj3z,         & 1,1
                 rhostr,rhostru,rhostrv,rhostrw,wcont,ustr,vstr)

!
!#######################################################################
!
!     PURPOSE:
!
!     Perform the adjoint operations on WCONTRA. WCONTRA
!     calculates wcont, the contravariant vertical velocity (m/s)
!
!#######################################################################
!
!     AUTHOR:   Jidong Gao
!     5/20/96 converted to ARPS4.0.22
!
!#######################################################################
!
!     INPUT:
!
!       nx       Number of grid points in the x-direction (east/west)
!       ny       Number of grid points in the y-direction (north/south)
!       nz       Number of grid points in the vertical
!
!       u        x component of velocity at all time levels (m/s)
!       v        y component of velocity at all time levels (m/s)
!       w        Vertical component of Cartesian velocity
!                at all time levels (m/s)
!
!    mapfct   Map factors at scalar, u and v points
!
!       j1       Coordinate transform Jacobian -d(zp)/dx
!       j2       Coordinate transform Jacobian -d(zp)/dy
!       j3       Coordinate transform Jacobian  d(zp)/dz
!    aj3z     Avgz of the coordinate transformation Jacobian  d(zp)/dz
!
!       rhostr   j3 times base state density rhobar(kg/m**3).
!       rhostru  Average rhostr at u points (kg/m**3).
!       rhostrv  Average rhostr at v points (kg/m**3).
!       rhostrw  Average rhostr at w points (kg/m**3).
!
!     OUTPUT:
!
!       wcont    Vertical component of contravariant velocity in
!                computational coordinates (m/s)
!
!#######################################################################
!

!
!#######################################################################
!
!     Variable Declarations.
!
!#######################################################################
!
  IMPLICIT NONE

  INTEGER :: nx,ny,nz          ! The number of grid points in 3
                               ! directions

  REAL :: u     (nx,ny,nz)     ! Total u-velocity (m/s)
  REAL :: v     (nx,ny,nz)     ! Total v-velocity (m/s)
  REAL :: w     (nx,ny,nz)     ! Total w-velocity (m/s)

  REAL :: mapfct(nx,ny,8)      ! Map factors at scalar, u and v points

  REAL :: j1    (nx,ny,nz)     ! Coordinate transform Jacobian
                               ! defined as - d( zp )/d( x ).
  REAL :: j2    (nx,ny,nz)     ! Coordinate transform Jacobian
                               ! defined as - d( zp )/d( y ).
  REAL :: j3    (nx,ny,nz)     ! Coordinate transform Jacobian
                               ! defined as d( zp )/d( z ).
  REAL :: aj3z  (nx,ny,nz)     ! Coordinate transformation Jacobian defined
                               ! as d( zp )/d( z ) AVERAGED IN THE Z-DIR.

  REAL :: rhostr(nx,ny,nz)     ! j3 times base state density rhobar
                               ! (kg/m**3).
  REAL :: rhostru(nx,ny,nz)    ! Average rhostr at u points (kg/m**3).
  REAL :: rhostrv(nx,ny,nz)    ! Average rhostr at v points (kg/m**3).
  REAL :: rhostrw(nx,ny,nz)    ! Average rhostr at w points (kg/m**3).

  REAL :: wcont (nx,ny,nz)     ! Vertical velocity in computational
                               ! coordinates (m/s)

  REAL :: ustr  (nx,ny,nz)     ! temporary work array
  REAL :: vstr  (nx,ny,nz)     ! temporary work array
  real :: tem1  (nx,ny,nz)     ! temporary work array
  real :: tem2  (nx,ny,nz)     ! temporary work array
!
!
!#######################################################################
!
!     Include files:
!
!#######################################################################
!
  INCLUDE 'globcst.inc'
!
!-----------------------------------------------------------------------
!
!  Misc. local variables:
!
!-----------------------------------------------------------------------
!
  INTEGER :: i,j,k
  integer onvf
!
!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
!
!     Beginning of executable code...
!
!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
!
  CALL advbcwcont(nx,ny,nz,wcont)

  IF( crdtrns == 0 ) THEN  ! No coord. transformation case.

    DO k= 2,nz-1
      DO j= 1,ny-1
        DO i= 1,nx-1
          w(i,j,k)=w(i,j,k) + wcont(i,j,k)
          wcont(i,j,k)=0.0
        END DO
      END DO
    END DO

  ELSEIF( ternopt == 0) THEN

    DO k= 2,nz-1
      DO j= 1,ny-1
        DO i= 1,nx-1
          w(i,j,k)=w(i,j,k) + wcont(i,j,k)/aj3z(i,j,k)
          wcont(i,j,k)=0.0
        END DO
      END DO
    END DO

  ELSE

    DO k= 2,nz-1
      DO j= 1,ny-1
        DO i= 1,nx-1
!         wcont(i,j,k)= (                                               &
!             ((ustr(i  ,j,k)+ustr(i  ,j,k-1))*j1(i  ,j,k)              &
!             +(ustr(i+1,j,k)+ustr(i+1,j,k-1))*j1(i+1,j,k)              &
!             +(vstr(i  ,j,k)+vstr(i  ,j,k-1))*j2(i  ,j,k)              &
!             +(vstr(i,j+1,k)+vstr(i,j+1,k-1))*j2(i,j+1,k))             &
!             * mapfct(i,j,8)                                           &
!             / rhostrw(i,j,k) + w(i,j,k)                               &
!             ) /aj3z(i,j,k)
!
         ustr(i,j,k  )=ustr(i,j,k  ) + wcont(i,j,k)*j1(i,j,k)           &
            *mapfct(i,j,8)/rhostrw(i,j,k)/aj3z(i,j,k)
         ustr(i,j,k-1)=ustr(i,j,k-1) + wcont(i,j,k)*j1(i,j,k)           &
            *mapfct(i,j,8)/rhostrw(i,j,k)/aj3z(i,j,k)
         ustr(i+1,j,k  )=ustr(i+1,j,k  ) + wcont(i,j,k)*j1(i+1,j,k)     &
            *mapfct(i,j,8)/rhostrw(i,j,k)/aj3z(i,j,k)
         ustr(i+1,j,k-1)=ustr(i+1,j,k-1) + wcont(i,j,k)*j1(i+1,j,k)     &
            *mapfct(i,j,8)/rhostrw(i,j,k)/aj3z(i,j,k)
         vstr(i  ,j,k  )=vstr(i  ,j,k  ) + wcont(i,j,k)*j2(i,j  ,k)     &
            *mapfct(i,j,8)/rhostrw(i,j,k)/aj3z(i,j,k)
         vstr(i  ,j,k-1)=vstr(i  ,j,k-1) + wcont(i,j,k)*j2(i,j  ,k)     &
            *mapfct(i,j,8)/rhostrw(i,j,k)/aj3z(i,j,k)
         vstr(i,j+1,k  )=vstr(i,j+1,k  ) + wcont(i,j,k)*j2(i,j+1,k)     &
            *mapfct(i,j,8)/rhostrw(i,j,k)/aj3z(i,j,k)          
         vstr(i,j+1,k-1)=vstr(i,j+1,k-1) + wcont(i,j,k)*j2(i,j+1,k)     &
            *mapfct(i,j,8)/rhostrw(i,j,k)/aj3z(i,j,k)
         w(i,j,k)=w(i,j,k) + wcont(i,j,k)/aj3z(i,j,k)
         wcont(i,j,k) = 0.0
        END DO
      END DO
    END DO

    DO k= 1,nz-1
      DO j= 1,ny
        DO i= 1,nx-1
!         vstr(i,j,k)=v(i,j,k)*rhostrv(i,j,k)

          v(i,j,k)=v(i,j,k)+vstr(i,j,k)*rhostrv(i,j,k)
          vstr(i,j,k) = 0.0
        END DO
      END DO
    END DO

!
    DO k= 1,nz-1
      DO j= 1,ny-1
        DO i= 1,nx
!         ustr(i,j,k)=u(i,j,k)*rhostru(i,j,k)

          u(i,j,k)=u(i,j,k)+ustr(i,j,k)*rhostru(i,j,k)
          ustr(i,j,k)=0.0
        END DO
      END DO
    END DO
!
      ENDIF

      RETURN
      END
!
!
!     ##################################################################
!     ##################################################################
!     ######                                                      ######
!     ######                  SUBROUTINE ADVBCWCONT               ######
!     ######                                                      ######
!     ######                Copyright (c) 1992-1994               ######
!     ######  Center for the Analysis and Prediction of Storms    ######
!     ######    University of Oklahoma.  All rights reserved.     ######
!     ######                                                      ######
!     ##################################################################
!     ##################################################################
!

SUBROUTINE ADVBCWCONT(nx,ny,nz,wcont) 1,1
!
!-----------------------------------------------------------------------
!
!     PURPOSE:
!
!     Perform the adjoint of
!     Set the top and bottom boundary conditions for wcont.
!
!-----------------------------------------------------------------------
!
!     AUTHOR:
!     5/22/96 Jidong Gao
!
!     MODIFICATION HISTORY:
!
!-----------------------------------------------------------------------
!
!     INPUT :
!
!       nx       Number of grid points in the x-direction (east/west)
!       ny       Number of grid points in the y-direction (north/south)
!       nz       Number of grid points in the vertical
!
!       wcont    Contravariant vertical velocity (m/s)
!
!     OUTPUT:
!
!       wcont    Top and bottom values of wcont.
!
!-----------------------------------------------------------------------
!
!     Variable Declarations:
!
!-----------------------------------------------------------------------
!
      implicit none             ! Force explicit declarations

      integer nx,ny,nz          ! Number of grid points in x, y and z
                                ! directions

      real wcont (nx,ny,nz)     ! Contravariant vertical velocity (m/s)
!
!-----------------------------------------------------------------------
!
!     Misc. local variables:
!
!-----------------------------------------------------------------------
!
      integer i, j, k
!
!-----------------------------------------------------------------------
!
!     Include files:
!
!-----------------------------------------------------------------------
!
      include 'bndry.inc'
!
!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
!
!     Beginning of executable code...
!
!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
!
!
!-----------------------------------------------------------------------
!
!     Set the top boundary condition
!
!-----------------------------------------------------------------------
!
      IF(tbc == 1) THEN             ! Rigid lid boundary condition

        DO j=1,ny-1
        DO i=1,nx-1
!         wcont(i,j,nz)=-wcont(i,j,nz-2)
!         wcont(i,j,nz-1)=0.0

          wcont(i,j,nz-2)=wcont(i,j,nz-2)-wcont(i,j,nz)
          wcont(i,j,nz)=0.0
          wcont(i,j,nz-1)=0.0
        END DO
        END DO

      ELSEIF(tbc == 2) THEN         ! Periodic boundary condition.

        DO j=1,ny-1
        DO i=1,nx-1
!         wcont(i,j,nz)=wcont(i,j,3)

          wcont(i,j,3)=wcont(i,j,3)+wcont(i,j,nz)
          wcont(i,j,nz)=0.0
        END DO
        END DO

      ELSEIF(tbc == 3.OR.tbc == 4) THEN ! Zero normal gradient condition.

        DO j=1,ny-1
        DO i=1,nx-1
!         wcont(i,j,nz)=wcont(i,j,nz-1)

          wcont(i,j,nz-1)=wcont(i,j,nz-1)+wcont(i,j,nz)
          wcont(i,j,nz) = 0.0
        END DO
        END DO

      ELSE

        WRITE(6,900) 'VBCWCONT', tbc
        CALL arpsstop ("",1)
        stop

      ENDIF
!
!
!-----------------------------------------------------------------------
!
!     Set the bottom boundary condition
!
!-----------------------------------------------------------------------
!
      IF(bbc == 1) THEN             ! Non-penetrative ground condition

        DO j=1,ny-1
        DO i=1,nx-1
!         wcont(i,j,1)=-wcont(i,j,3)
!         wcont(i,j,2)=0.0

          wcont(i,j,3)=wcont(i,j,3)-wcont(i,j,1)
          wcont(i,j,1)=0.0
          wcont(i,j,2)=0.0
        END DO
        END DO

      ELSEIF(bbc == 2) THEN         ! Periodic boundary condition.

        DO j=1,ny-1
        DO i=1,nx-1
!         wcont(i,j,1)=wcont(i,j,nz-2)

          wcont(i,j,nz-2)=wcont(i,j,nz-2)+wcont(i,j,1)
          wcont(i,j,1) = 0.0 
        END DO
        END DO

      ELSEIF(bbc.eq.3) THEN         ! Zero normal gradient condition.

        DO j=1,ny-1
        DO i=1,nx-1
!         wcont(i,j,1)=wcont(i,j,2)

          wcont(i,j,2)=wcont(i,j,2)+wcont(i,j,1)
          wcont(i,j,1)= 0.0
        END DO
        END DO

      ELSE

        write(6,900) 'VBCWCONT', bbc
        STOP
      ENDIF

900   format(1x,'Invalid boundary condition option found in ',a,     &
             /1x,'The option was ',i3,' Job stopped.')

      RETURN
      END