C $Header: /u/gcmpack/MITgcm/pkg/cd_code/cd_code_scheme.F,v 1.2 2004/11/10 01:55:01 jmc Exp $
C $Name:  $

#include "CD_CODE_OPTIONS.h"

CBOP
C !ROUTINE: CD_CODE_SCHEME

C !INTERFACE: ==========================================================
      SUBROUTINE CD_CODE_SCHEME( 
     I        bi,bj,k, dPhiHydX,dPhiHydY, guFld,gvFld,
     O        guCor,gvCor,
     I        myTime, myIter, myThid)

C !DESCRIPTION:
C The C-D scheme. The less said the better :-)

C !USES: ===============================================================
C     == Global variables ==
      IMPLICIT NONE
#include "SIZE.h"
#include "DYNVARS.h"
#ifdef ALLOW_CD_CODE
#include "CD_CODE_VARS.h"
#endif
#include "EEPARAMS.h"
#include "PARAMS.h"
#include "GRID.h"
#include "SURFACE.h"

C !INPUT PARAMETERS: ===================================================
C  bi,bj                :: tile indices
C  k                    :: vertical level
C     dPhiHydX,Y        :: Gradient (X & Y dir.) of Hydrostatic Potential
C  guFld,gvFld          :: Acceleration (U & V compon.) from the C grid
C  guCor,gvCor          :: Coriolis terms (2 compon.) computed on C grid
C  myTime               :: current time
C  myIter               :: current time-step number
C  myThid               :: thread number

      INTEGER bi,bj,k
      _RL dPhiHydX(1-Olx:sNx+Olx,1-Oly:sNy+Oly)
      _RL dPhiHydY(1-Olx:sNx+Olx,1-Oly:sNy+Oly)
      _RL    guFld(1-Olx:sNx+Olx,1-Oly:sNy+Oly)
      _RL    gvFld(1-Olx:sNx+Olx,1-Oly:sNy+Oly)
      _RL    guCor(1-Olx:sNx+Olx,1-Oly:sNy+Oly)
      _RL    gvCor(1-Olx:sNx+Olx,1-Oly:sNy+Oly)
      _RL     myTime
      INTEGER myIter
      INTEGER myThid


C !LOCAL VARIABLES: ====================================================
#ifdef ALLOW_CD_CODE
C  i,j                  :: loop indices
C  pF                   :: pressure gradient
C  vF                   :: work space
C  aF                   :: work space
      _RL pF(1-OLx:sNx+OLx,1-OLy:sNy+OLy)
      _RL vF(1-OLx:sNx+OLx,1-OLy:sNy+OLy)
      _RL aF(1-OLx:sNx+OLx,1-OLy:sNy+OLy)
      INTEGER i,j,iMin,iMax,jMin,jMax
      _RL ab15,ab05
      _RL phxFac, phyFac
CEOP

C     Compute ranges
      iMin=1-Olx+1
      iMax=sNx+Olx-1
      jMin=1-Oly+1
      jMax=sNy+Oly-1

C     Adams-Bashforth weighting factors
      ab15   =  1.5 + abEps
      ab05   = -0.5 - abEps

C-- stagger time stepping: grad Phi_Hyp is not in gU,gV and needs to be added:
      IF (staggerTimeStep) THEN
        phxFac = pfFacMom
        phyFac = pfFacMom
      ELSE
        phxFac = 0.
        phyFac = 0.
      ENDIF

C-    Initialize output (dummy) arrays:
c     DO j=1-Oly,sNy+Oly
c      DO i=1-Olx,sNx+Olx
c       guCor(i,j) = 0. _d 0
c       gvCor(i,j) = 0. _d 0
c      ENDDO
c     ENDDO

C     Pressure extrapolated forward in time
      DO j=1-Oly,sNy+Oly
       DO i=1-Olx,sNx+Olx
        pf(i,j) = 
     &   ab15*(  etaN(i,j,bi,bj)*Bo_surf(i,j,bi,bj) )
     &  +ab05*(etaNm1(i,j,bi,bj)*Bo_surf(i,j,bi,bj) )
       ENDDO
      ENDDO

C--   Zonal velocity coriolis term
C     Note. As coded here, coriolis will not work with "thin walls"
C--   Coriolis with CD scheme allowed
C     grady(p) + gV
      DO j=1-Oly+1,sNy+Oly
       DO i=1-Olx,sNx+Olx
        af(i,j) =
     &        (  gvFld(i,j)
     &          -( _recip_dyC(i,j,bi,bj)*(pf(i,j)-pf(i,j-1))
     &            +phyFac*dPhiHydY(i,j) )
     &        )*_maskS(i,j,k,bi,bj)
       ENDDO
      ENDDO
C     Average to Vd point and add coriolis
      DO j=jMin,jMax
       DO i=iMin,iMax
        vf(i,j) =      
     &    0.25*( af(i  ,j)+af(i  ,j+1)
     &          +af(i-1,j)+af(i-1,j+1)
     &         )*_maskW(i,j,k,bi,bj)
     &   -0.5*(_fCori(i,j,bi,bj)+
     &         _fCori(i-1,j,bi,bj))
     &         *uVel(i,j,k,bi,bj)
       ENDDO
      ENDDO
C     Step forward Vd
      DO j=jMin,jMax
       DO i=iMin,iMax
        vVelD(i,j,k,bi,bj) = vVelD(i,j,k,bi,bj) + deltaTmom*vf(i,j)
       ENDDO
      ENDDO
C     Relax D grid V to C grid V
      DO j=jMin,jMax
       DO i=iMin,iMax
         vVelD(i,j,k,bi,bj) = ( rCD*vVelD(i,j,k,bi,bj)
     &   +(1. - rCD)*(
     &            ab15*( 
     &                vVel(i  ,j  ,k,bi,bj)+vVel(i  ,j+1,k,bi,bj)
     &               +vVel(i-1,j  ,k,bi,bj)+vVel(i-1,j+1,k,bi,bj)
     &                 )*0.25
     &           +ab05*( 
     &                vNM1(i  ,j  ,k,bi,bj)+vNM1(i  ,j+1,k,bi,bj)
     &               +vNM1(i-1,j  ,k,bi,bj)+vNM1(i-1,j+1,k,bi,bj)
     &                 )*0.25
     &               )        )*_maskW(i,j,k,bi,bj)
       ENDDO
      ENDDO
C     Calculate coriolis force on U
      DO j=jMin,jMax
       DO i=iMin,iMax
        guCor(i,j) = 
     &    0.5*( _fCori(i  ,j,bi,bj) + 
     &          _fCori(i-1,j,bi,bj)  )
     &   *vVelD(i,j,k,bi,bj)*cfFacMom
       ENDDO
      ENDDO

C--   Meridional velocity coriolis term
C     gradx(p)+gU
      DO j=1-Oly,sNy+Oly
       DO i=1-Olx+1,sNx+Olx
        af(i,j) =
     &        (  guFld(i,j)
     &          -( _recip_dxC(i,j,bi,bj)*(pf(i,j)-pf(i-1,j))
     &            +phxFac*dPhiHydX(i,j) )
     &        )*_maskW(i,j,k,bi,bj)
       ENDDO
      ENDDO
C     Average to Ud point and add coriolis
      DO j=jMin,jMax
       DO i=iMin,iMax
        vf(i,j) =
     &    0.25*( af(i  ,j)+af(i  ,j-1)
     &          +af(i+1,j)+af(i+1,j-1)
     &         )*_maskS(i,j,k,bi,bj)
     &   +0.5*( _fCori(i,j,bi,bj)
     &         +_fCori(i,j-1,bi,bj))
     &         *vVel(i,j,k,bi,bj)
       ENDDO
      ENDDO
C     Step forward Ud
      DO j=jMin,jMax
       DO i=iMin,iMax
        uVelD(i,j,k,bi,bj) = uVelD(i,j,k,bi,bj) + deltaTmom*vf(i,j)
       ENDDO
      ENDDO
C     Relax D grid U to C grid U
      DO j=jMin,jMax
       DO i=iMin,iMax
         uVelD(i,j,k,bi,bj) = ( rCD*uVelD(i,j,k,bi,bj) 
     &   +(1. - rCD)*(
     &            ab15*( 
     &                uVel(i,j  ,k,bi,bj)+uVel(i+1,j  ,k,bi,bj)
     &               +uVel(i,j-1,k,bi,bj)+uVel(i+1,j-1,k,bi,bj)
     &                 )*0.25
     &           +ab05*( 
     &                uNM1(i,j  ,k,bi,bj)+uNM1(i+1,j  ,k,bi,bj)
     &               +uNM1(i,j-1,k,bi,bj)+uNM1(i+1,j-1,k,bi,bj)
     &                 )*0.25
     &               )        )*_maskS(i,j,k,bi,bj)
       ENDDO
      ENDDO
C     Calculate coriolis force on V
      DO j=jMin,jMax
       DO i=iMin,iMax
        gvCor(i,j) =
     &    -0.5*( _fCori(i  ,j,bi,bj) 
     &          +_fCori(i,j-1,bi,bj)  )
     &   *uVelD(i,j,k,bi,bj)*cfFacMom
       ENDDO
      ENDDO

C--   Save "previous time level" variables
      DO j=1-OLy,sNy+OLy
       DO i=1-OLx,sNx+OLx
         uNM1(i,j,k,bi,bj) =  uVel(i,j,k,bi,bj)
         vNM1(i,j,k,bi,bj) =  vVel(i,j,k,bi,bj)
       ENDDO
      ENDDO

#endif /* ALLOW_CD_CODE */

      RETURN
      END