C $Header: /u/gcmpack/MITgcm/model/src/ini_cg2d.F,v 1.51 2012/06/15 20:13:16 heimbach Exp $
C $Name:  $

#include "PACKAGES_CONFIG.h"
#include "CPP_OPTIONS.h"

CBOP
C     !ROUTINE: INI_CG2D
C     !INTERFACE:
      SUBROUTINE INI_CG2D( myThid )

C     !DESCRIPTION: \bv
C     *==========================================================*
C     | SUBROUTINE INI_CG2D
C     | o Initialise 2d conjugate gradient solver operators.
C     *==========================================================*
C     | These arrays are purely a function of the basin geom.
C     | We set then here once and them use then repeatedly.
C     *==========================================================*
C     \ev

C     !USES:
      IMPLICIT NONE
C     === Global variables ===
#include "SIZE.h"
#include "EEPARAMS.h"
#include "PARAMS.h"
#include "GRID.h"
#include "SURFACE.h"
#include "CG2D.h"

C     !INPUT/OUTPUT PARAMETERS:
C     === Routine arguments ===
C     myThid - Thread no. that called this routine.
      INTEGER myThid

C     !LOCAL VARIABLES:
C     === Local variables ===
C     bi,bj  :: tile indices
C     i,j,k  :: Loop counters
C     faceArea :: Temporary used to hold cell face areas.
C     myNorm   :: Work variable used in calculating normalisation factor
      CHARACTER*(MAX_LEN_MBUF) msgBuf
      INTEGER bi, bj
      INTEGER i, j, k, ks
      _RL     faceArea
      _RS     myNorm
      _RS     aC, aCw, aCs
CEOP

C--   Initialize arrays in common blocs (CG2D.h) ; not really necessary
C     but safer when EXCH do not fill all the overlap regions.
      DO bj=myByLo(myThid),myByHi(myThid)
       DO bi=myBxLo(myThid),myBxHi(myThid)
        DO j=1-OLy,sNy+OLy
         DO i=1-OLx,sNx+OLx
          aW2d(i,j,bi,bj) = 0. _d 0
          aS2d(i,j,bi,bj) = 0. _d 0
          aC2d(i,j,bi,bj) = 0. _d 0
          pW(i,j,bi,bj) = 0. _d 0
          pS(i,j,bi,bj) = 0. _d 0
          pC(i,j,bi,bj) = 0. _d 0
         ENDDO
        ENDDO
        DO j=1-1,sNy+1
         DO i=1-1,sNx+1
          cg2d_q(i,j,bi,bj) = 0. _d 0
          cg2d_r(i,j,bi,bj) = 0. _d 0
          cg2d_s(i,j,bi,bj) = 0. _d 0
#ifdef ALLOW_CG2D_NSA
          cg2d_z(i,j,bi,bj) = 0. _d 0
#endif /* ALLOW_CG2D_NSA */
#ifdef ALLOW_SRCG
          cg2d_y(i,j,bi,bj) = 0. _d 0
          cg2d_v(i,j,bi,bj) = 0. _d 0
#endif /*  ALLOW_SRCG */
         ENDDO
        ENDDO
       ENDDO
      ENDDO

C--   Init. scalars
      cg2dNorm = 0. _d 0
      cg2dNormaliseRHS = .FALSE.
      cg2dtolerance = 0. _d 0

C--   Initialise laplace operator
C     aW2d: integral in Z Ax/dX
C     aS2d: integral in Z Ay/dY
      myNorm = 0. _d 0
      DO bj=myByLo(myThid),myByHi(myThid)
       DO bi=myBxLo(myThid),myBxHi(myThid)
        DO j=1,sNy
         DO i=1,sNx
          aW2d(i,j,bi,bj) = 0. _d 0
          aS2d(i,j,bi,bj) = 0. _d 0
         ENDDO
        ENDDO
        DO k=1,Nr
         DO j=1,sNy
          DO i=1,sNx
C  deep-model: *deepFacC (faceArea), /deepFacC (recip_dx,y): => no net effect
           faceArea = _dyG(i,j,bi,bj)*drF(k)
     &               *_hFacW(i,j,k,bi,bj)
           aW2d(i,j,bi,bj) = aW2d(i,j,bi,bj)
     &              + implicSurfPress*implicDiv2DFlow
     &               *faceArea*recip_dxC(i,j,bi,bj)
           faceArea = _dxG(i,j,bi,bj)*drF(k)
     &               *_hFacS(i,j,k,bi,bj)
           aS2d(i,j,bi,bj) = aS2d(i,j,bi,bj)
     &              + implicSurfPress*implicDiv2DFlow
     &               *faceArea*recip_dyC(i,j,bi,bj)
          ENDDO
         ENDDO
        ENDDO
        DO j=1,sNy
         DO i=1,sNx
#ifdef ALLOW_OBCS
           aW2d(i,j,bi,bj) = aW2d(i,j,bi,bj)
     &                   *maskInC(i,j,bi,bj)*maskInC(i-1,j,bi,bj)
           aS2d(i,j,bi,bj) = aS2d(i,j,bi,bj)
     &                   *maskInC(i,j,bi,bj)*maskInC(i,j-1,bi,bj)
#endif /* ALLOW_OBCS */
           myNorm = MAX(ABS(aW2d(i,j,bi,bj)),myNorm)
           myNorm = MAX(ABS(aS2d(i,j,bi,bj)),myNorm)
         ENDDO
        ENDDO
       ENDDO
      ENDDO
      _GLOBAL_MAX_RS( myNorm, myThid )
      IF ( myNorm .NE. 0. _d 0 ) THEN
       myNorm = 1. _d 0/myNorm
      ELSE
       myNorm = 1. _d 0
      ENDIF
      DO bj=myByLo(myThid),myByHi(myThid)
       DO bi=myBxLo(myThid),myBxHi(myThid)
        DO j=1,sNy
         DO i=1,sNx
          aW2d(i,j,bi,bj) = aW2d(i,j,bi,bj)*myNorm
          aS2d(i,j,bi,bj) = aS2d(i,j,bi,bj)*myNorm
         ENDDO
        ENDDO
       ENDDO
      ENDDO

C--   Update overlap regions
CcnhDebugStarts
C     CALL PLOT_FIELD_XYRS( aW2d, 'AW2D INI_CG2D.1' , 1, myThid )
C     CALL PLOT_FIELD_XYRS( aS2d, 'AS2D INI_CG2D.1' , 1, myThid )
CcnhDebugEnds
      CALL EXCH_UV_XY_RS( aW2d, aS2d, .FALSE., myThid )
CcnhDebugStarts
C     CALL PLOT_FIELD_XYRS( aW2d, 'AW2D INI_CG2D.2' , 1, myThid )
C     CALL PLOT_FIELD_XYRS( aS2d, 'AS2D INI_CG2D.2' , 1, myThid )
CcnhDebugEnds

      _BEGIN_MASTER(myThid)
C-- set global parameter in common block:
      cg2dNorm = myNorm
C-- Define the solver tolerance in the appropriate Unit :
      cg2dNormaliseRHS = cg2dTargetResWunit.LE.0.
      IF (cg2dNormaliseRHS) THEN
C-  when using a normalisation of RHS, tolerance has no unit => no conversion
        cg2dTolerance = cg2dTargetResidual
      ELSE
C-  convert Target-Residual (in W unit) to cg2d-solver residual unit [m^2/s^2]
        cg2dTolerance = cg2dNorm * cg2dTargetResWunit
     &                           * globalArea / deltaTmom
      ENDIF
      _END_MASTER(myThid)

CcnhDebugStarts
      _BEGIN_MASTER( myThid )
       WRITE(msgBuf,'(2A,1PE23.16)') 'INI_CG2D: ',
     &      'CG2D normalisation factor = ', cg2dNorm
       CALL PRINT_MESSAGE( msgBuf,standardMessageUnit,SQUEEZE_RIGHT,1)
       IF (.NOT.cg2dNormaliseRHS) THEN
        WRITE(msgBuf,'(2A,1PE22.15,A,1PE16.10,A)') 'INI_CG2D: ',
     &      'cg2dTolerance =', cg2dTolerance, ' (Area=',globalArea,')'
        CALL PRINT_MESSAGE(msgBuf,standardMessageUnit,SQUEEZE_RIGHT,1)
       ENDIF
       WRITE(msgBuf,*) ' '
       CALL PRINT_MESSAGE( msgBuf,standardMessageUnit,SQUEEZE_RIGHT,1)
      _END_MASTER( myThid )
CcnhDebugEnds

C--   Initialise preconditioner
C     Note. 20th May 1998
C           I made a weird discovery! In the model paper we argue
C           for the form of the preconditioner used here ( see
C           A Finite-volume, Incompressible Navier-Stokes Model
C           ...., Marshall et. al ). The algebra gives a simple
C           0.5 factor for the averaging of ac and aCw to get a
C           symmettric pre-conditioner. By using a factor of 0.51
C           i.e. scaling the off-diagonal terms in the
C           preconditioner down slightly I managed to get the
C           number of iterations for convergence in a test case to
C           drop form 192 -> 134! Need to investigate this further!
C           For now I have introduced a parameter cg2dpcOffDFac which
C           defaults to 0.51 but can be set at runtime.
      DO bj=myByLo(myThid),myByHi(myThid)
       DO bi=myBxLo(myThid),myBxHi(myThid)
C-    calculate and store solver main diagonal :
        DO j=0,sNy+1
         DO i=0,sNx+1
           ks = ksurfC(i,j,bi,bj)
           aC2d(i,j,bi,bj) = -(
     &       aW2d(i,j,bi,bj) + aW2d(i+1,j, bi,bj)
     &      +aS2d(i,j,bi,bj) + aS2d( i,j+1,bi,bj)
     &      +freeSurfFac*myNorm*recip_Bo(i,j,bi,bj)*deepFac2F(ks)
     &                  *rA(i,j,bi,bj)/deltaTMom/deltaTfreesurf
     &                        )
         ENDDO
        ENDDO
        DO j=1,sNy
         DO i=1,sNx
           aC  = aC2d( i, j, bi,bj)
           aCs = aC2d( i,j-1,bi,bj)
           aCw = aC2d(i-1,j, bi,bj)
           IF ( aC .EQ. 0. ) THEN
            pC(i,j,bi,bj) = 1. _d 0
           ELSE
            pC(i,j,bi,bj) =  1. _d 0 / aC
           ENDIF
           IF ( aC + aCw .EQ. 0. ) THEN
            pW(i,j,bi,bj) = 0.
           ELSE
            pW(i,j,bi,bj) =
     &         -aW2d(i,j,bi,bj)/((cg2dpcOffDFac *(aCw+aC))**2 )
           ENDIF
           IF ( aC + aCs .EQ. 0. ) THEN
            pS(i,j,bi,bj) = 0.
           ELSE
            pS(i,j,bi,bj) =
     &         -aS2d(i,j,bi,bj)/((cg2dpcOffDFac *(aCs+aC))**2 )
           ENDIF
C          pC(i,j,bi,bj) = 1.
C          pW(i,j,bi,bj) = 0.
C          pS(i,j,bi,bj) = 0.
         ENDDO
        ENDDO
       ENDDO
      ENDDO
C--   Update overlap regions
      CALL EXCH_XY_RS( pC, myThid )
      CALL EXCH_UV_XY_RS( pW, pS, .FALSE., myThid )
CcnhDebugStarts
C     CALL PLOT_FIELD_XYRS( pC, 'pC   INI_CG2D.2' , 1, myThid )
C     CALL PLOT_FIELD_XYRS( pW, 'pW   INI_CG2D.2' , 1, myThid )
C     CALL PLOT_FIELD_XYRS( pS, 'pS   INI_CG2D.2' , 1, myThid )
CcnhDebugEnds

      RETURN
      END