C $Header: /u/gcmpack/MITgcm/model/src/ini_vertical_grid.F,v 1.23 2016/04/04 21:29:00 jmc Exp $ C $Name: $ #include "CPP_OPTIONS.h" CBOP C !ROUTINE: INI_VERTICAL_GRID C !INTERFACE: SUBROUTINE INI_VERTICAL_GRID( myThid ) C !DESCRIPTION: \bv C *==========================================================* C | SUBROUTINE INI_VERTICAL_GRID C | o Initialise vertical gridding arrays C *==========================================================* C \ev C !USES: IMPLICIT NONE C === Global variables === #include "SIZE.h" #include "EEPARAMS.h" #include "PARAMS.h" #include "GRID.h" C !INPUT/OUTPUT PARAMETERS: C == Routine arguments == C myThid :: my Thread Id number INTEGER myThid C !LOCAL VARIABLES: C == Local variables == C k :: loop index C msgBuf :: Informational/error message buffer INTEGER k _RL tmpRatio, checkRatio1, checkRatio2 CHARACTER*(MAX_LEN_MBUF) msgBuf _RL maxErrC, maxErrF, epsil, tmpError _RL rFullDepth, recip_fullDepth _RS rSigBndRS, tmpRS CEOP _BEGIN_MASTER(myThid) WRITE(msgBuf,'(A,2(A,L5))') 'Enter INI_VERTICAL_GRID:', & ' setInterFDr=', setInterFDr, & ' ; setCenterDr=', setCenterDr CALL PRINT_MESSAGE( msgBuf, standardMessageUnit, & SQUEEZE_RIGHT, myThid ) C-- Set factors required for mixing pressure and meters as vertical coordinate. C rkSign is a "sign" parameter which is used where the orientation of the vertical C coordinate (pressure or meters) relative to the vertical index (k) is important. C rkSign = -1 applies when k and the coordinate are in the opposite sense. C rkSign = 1 applies when k and the coordinate are in the same sense. rkSign = -1. _d 0 gravitySign = -1. _d 0 IF ( usingPCoords ) THEN gravitySign = 1. _d 0 ENDIF IF ( .NOT.(setInterFDr.OR.setCenterDr) ) THEN WRITE(msgBuf,'(A)') & 'S/R INI_VERTICAL_GRID: neither delR nor delRc are defined' CALL PRINT_ERROR( msgBuf, myThid ) WRITE(msgBuf,'(A)') & 'S/R INI_VERTICAL_GRID: Need at least 1 of the 2 (delR,delRc)' CALL PRINT_ERROR( msgBuf, myThid ) STOP 'ABNORMAL END: S/R INI_VERTICAL_GRID' ENDIF C--- Set Level r-thickness (drF) and Center r-distances (drC) IF (setInterFDr) THEN C-- Interface r-distances are defined: DO k=1,Nr drF(k) = delR(k) ENDDO C- Check that all thickness are > 0 : DO k=1,Nr IF (delR(k).LE.0.) THEN WRITE(msgBuf,'(A,I4,A,E16.8)') & 'S/R INI_VERTICAL_GRID: delR(k=',k,' )=',delR(k) CALL PRINT_ERROR( msgBuf, myThid ) WRITE(msgBuf,'(A)') & 'S/R INI_VERTICAL_GRID: Vert. grid spacing MUST BE > 0' CALL PRINT_ERROR( msgBuf, myThid ) STOP 'ABNORMAL END: S/R INI_VERTICAL_GRID' ENDIF ENDDO ELSE C-- Interface r-distances undefined: C assume Interface at middle between 2 Center drF(1) = delRc(1) DO k=2,Nr c drF(k-1) = 0.5 _d 0 *delRc(k) + drF(k-1) c drF( k ) = 0.5 _d 0 *delRc(k) C- note: change the order to prevent some compilers to produce wrong code C when trying to optimise this loop : drF( k ) = 0.5 _d 0 *delRc(k) drF(k-1) = 0.5 _d 0 *delRc(k) + drF(k-1) ENDDO drF(Nr) = delRc(Nr+1) + drF(Nr) ENDIF IF (setCenterDr) THEN C-- Cell Center r-distances are defined: DO k=1,Nr+1 drC(k) = delRc(k) ENDDO C- Check that all thickness are > 0 : DO k=1,Nr+1 IF (delRc(k).LE.0.) THEN WRITE(msgBuf,'(A,I4,A,E16.8)') & 'S/R INI_VERTICAL_GRID: delRc(k=',k,' )=',delRc(k) CALL PRINT_ERROR( msgBuf, myThid ) WRITE(msgBuf,'(A)') & 'S/R INI_VERTICAL_GRID: Vert. grid spacing MUST BE > 0' CALL PRINT_ERROR( msgBuf, myThid ) STOP 'ABNORMAL END: S/R INI_VERTICAL_GRID' ENDIF ENDDO ELSE C-- Cell Center r-distances undefined: C assume Center at middle between 2 Interfaces drC(1) = 0.5 _d 0 *delR(1) DO k=2,Nr drC(k) = 0.5 _d 0 *(delR(k-1)+delR(k)) ENDDO drC(Nr+1) = 0.5 _d 0 *delR(Nr) ENDIF C--- Set r-position of interFace (rF) and cell-Center (rC): C -- Use top_Pres or seaLev_Z to set vertical axis position: C OCN in Z: top_Pres(Ref) (= rhoConst*PhiRef(1)), seaLev_Z (=rF(1), @ the top) C ATM in Z: top_Pres(Ref) (= rhoConst*PhiRef(1)), seaLev_Z (=rF(Nr+1), @ bottom) C OCN in P: top_Pres (=rF(Nr+1)), seaLev_Z (<-> PhiRef(Nr+1)/g, @ the top) C ATM in P: top_Pres (=rF(Nr+1)), seaLev_Z (<-> PhiRef(1)/g, @ the bottom) IF ( rF(1).EQ.UNSET_RS .AND. & usingZCoords.AND.fluidIsWater ) THEN rF(1) = seaLev_Z ENDIF IF ( rF(1).NE.UNSET_RS ) THEN DO k=1,Nr rF(k+1) = rF(k) + rkSign*drF(k) ENDDO rC(1) = rF(1) + rkSign*drC(1) DO k=2,Nr rC(k) = rC(k-1) + rkSign*drC(k) ENDDO c IF ( usingPCoords ) THEN c top_Pres = rF(Nr+1) c ELSEIF ( fluidIsWater ) THEN c seaLev_Z = rF(1) c ELSE c seaLev_Z = rF(Nr+1) c ENDIF ELSE IF ( usingPCoords ) THEN rF(Nr+1) = top_Pres ELSE rF(Nr+1) = seaLev_Z ENDIF DO k=Nr,1,-1 rF(k) = rF(k+1) - rkSign*drF(k) ENDDO rC(Nr) = rF(Nr+1) - rkSign*drC(Nr+1) DO k=Nr,2,-1 rC(k-1) = rC(k) - rkSign*drC(k) ENDDO ENDIF C--- Check vertical discretization : checkRatio2 = 100. checkRatio1 = 1. _d 0 / checkRatio2 DO k=1,Nr tmpRatio = 0. IF ( (rC(k)-rF(k+1)) .NE. 0. ) & tmpRatio = (rF(k)-rC(k)) / (rC(k)-rF(k+1)) IF ( tmpRatio.LT.checkRatio1 .OR. tmpRatio.GT.checkRatio2 ) THEN c write(0,*) 'drF=',drF c write(0,*) 'drC=',drC c write(0,*) 'rF=',rF c write(0,*) 'rC=',rC WRITE(msgBuf,'(A,I4,A,E16.8)') & 'S/R INI_VERTICAL_GRID: Invalid relative position, level k=', & k, ' :', tmpRatio CALL PRINT_ERROR( msgBuf, myThid ) WRITE(msgBuf,'(A,1PE14.6,A,2E14.6)') & 'S/R INI_VERTICAL_GRID: rC=', rC(k), & ' , rF(k,k+1)=',rF(k),rF(k+1) CALL PRINT_ERROR( msgBuf, myThid ) STOP 'ABNORMAL END: S/R INI_VERTICAL_GRID' ENDIF ENDDO C- Calculate reciprol vertical grid spacing : DO k=1,Nr+1 recip_drC(k) = 1. _d 0/drC(k) ENDDO DO k=1,Nr recip_drF(k) = 1. _d 0/drF(k) ENDDO C--- Hybrid-Sigma vertical coordinate: IF ( selectSigmaCoord .EQ. 0 ) THEN DO k=1,Nr+1 aHybSigmF(k) = 0. _d 0 bHybSigmF(k) = 0. _d 0 dAHybSigC(k) = 0. _d 0 dAHybSigC(k) = 0. _d 0 ENDDO DO k=1,Nr aHybSigmC(k) = 0. _d 0 bHybSigmC(k) = 0. _d 0 dAHybSigF(k) = 0. _d 0 dAHybSigF(k) = 0. _d 0 ENDDO ELSE rFullDepth = rF(1) - rF(Nr+1) recip_fullDepth = 0. _d 0 IF ( rFullDepth.GT.0. ) recip_fullDepth = 1. _d 0 / rFullDepth rSigBndRS = rSigmaBnd IF ( hybSigmFile.EQ.' ' .AND. rSigmaBnd.EQ.UNSET_RL ) THEN C- Default is pure sigma: IF ( usingPCoords ) rSigBndRS = rF(Nr+1) IF ( usingZCoords ) rSigBndRS = rF(1) ENDIF c IF ( hybSigmFile.EQ.' ' .AND. rSigmaBnd.EQ.UNSET_RL ) THEN C- compute coeff as pure sigma coordinate c DO k=1,Nr+1 c aHybSigmF(k) = 0. c bHybSigmF(k) = (rF(k)-rF(Nr+1))*recip_fullDepth c ENDDO c DO k=1,Nr c aHybSigmC(k) = 0. c bHybSigmC(k) = (rC(k)-rF(Nr+1))*recip_fullDepth c ENDDO c ELSEIF ( hybSigmFile.EQ.' ' ) THEN IF ( hybSigmFile.EQ.' ' ) THEN C-- compute coeff assuming fixed r-coord above rSigmaBnd and pure sigma below IF ( usingPCoords .AND. setInterFDr ) THEN C- Alternative method : p = pTop + A*DeltaFullP + B*(eta+Pr_surf - rSigmaBnd) c aHybSigmF(k) = ( MIN(rF(k),rSigmaBnd) - rF(Nr+1) ) c & *recip_fullDepth c bHybSigmF(k) = ( MAX(rF(k),rSigmaBnd) - rSigmaBnd ) c & /( rF(1) - rSigmaBnd ) C- Standard method : p = pTop + A*DeltaFullP + B*(eta+Ro_surf - pTop) C sigma part goes from 0 @ rSigmaBnd (and above) to 1 @ surface DO k=1,Nr+1 C- separate the 2 cases: c IF ( rF(k).LE.rSigmaBnd ) THEN c bHybSigmF(k) = 0. c aHybSigmF(k) = ( rF(k) - rF(Nr+1) )*recip_fullDepth c ELSE c bHybSigmF(k) = (rF(k)-rSigmaBnd)/(rF(1)-rSigmaBnd) c aHybSigmF(k) = (1. _d 0 - bHybSigmF(k)) c & *(rSigmaBnd-rF(Nr+1) )*recip_fullDepth c ENDIF C- unique formula using min fct: tmpRS = MIN( rF(k), rSigBndRS ) bHybSigmF(k) = ( rF(k) - tmpRS )/(rF(1)-rSigBndRS) aHybSigmF(k) = (1. _d 0 - bHybSigmF(k)) & *( tmpRS -rF(Nr+1) )*recip_fullDepth ENDDO ENDIF IF ( usingPCoords .AND. setCenterDr ) THEN DO k=1,Nr C- separate the 2 cases: c IF ( rC(k).LE.rSigmaBnd ) THEN c bHybSigmC(k) = 0. c aHybSigmC(k) = ( rC(k) - rF(Nr+1) )*recip_fullDepth c ELSE c bHybSigmC(k) = (rC(k)-rSigmaBnd)/(rF(1)-rSigmaBnd) c aHybSigmC(k) = (1. _d 0 - bHybSigmC(k)) c & *(rSigmaBnd-rF(Nr+1) )*recip_fullDepth c ENDIF C- unique formula using min fct: tmpRS = MIN( rC(k), rSigBndRS ) bHybSigmC(k) = ( rC(k) - tmpRS )/(rF(1)-rSigBndRS) aHybSigmC(k) = (1. _d 0 - bHybSigmC(k)) & *( tmpRS -rF(Nr+1) )*recip_fullDepth ENDDO ENDIF IF ( usingZCoords .AND. setInterFDr ) THEN C- Standard method : z = zBot + A*DeltaFullZ + B*(eta+Ro_surf - zBot) C sigma part goes from 1 @ rSigmaBnd (and above) to 0 @ bottom DO k=1,Nr+1 C- separate the 2 cases: c IF ( rF(k).GE.rSigmaBnd ) THEN c bHybSigmF(k) = 1. c aHybSigmF(k) = ( rF(k)-rF(1) )*recip_fullDepth c ELSE c bHybSigmF(k) = ( rF(k)-rF(Nr+1) )/( rSigmaBnd-rF(Nr+1) ) c aHybSigmF(k) = bHybSigmF(k)*(rSigmaBnd-rF(1))*recip_fullDepth c ENDIF C- unique formula using max fct: tmpRS = MAX( rF(k), rSigBndRS ) bHybSigmF(k) = ( rF(k)-rF(Nr+1) )/( tmpRS-rF(Nr+1) ) aHybSigmF(k) = bHybSigmF(k)*( tmpRS-rF(1) )*recip_fullDepth ENDDO ENDIF IF ( usingZCoords .AND. setCenterDr ) THEN DO k=1,Nr C- separate the 2 cases: c IF ( rC(k).GE.rSigmaBnd ) THEN c bHybSigmC(k) = 1. c aHybSigmC(k) = ( rC(k)-rF(1) )*recip_fullDepth c ELSE c bHybSigmC(k) = ( rC(k)-rF(Nr+1) )/( rSigmaBnd-rF(Nr+1) ) c aHybSigmC(k) = bHybSigmC(k)*(rSigmaBnd-rF(1))*recip_fullDepth c ENDIF C- unique formula using max fct: tmpRS = MAX( rC(k), rSigBndRS ) bHybSigmC(k) = ( rC(k)-rF(Nr+1) )/( tmpRS-rF(Nr+1) ) aHybSigmC(k) = bHybSigmC(k)*( tmpRS-rF(1) )*recip_fullDepth ENDDO ENDIF ELSE C-- Coeff at interface are read from file IF (setCenterDr) THEN STOP 'ABNORMAL END: S/R INI_VERTICAL_GRID: Missing Code' ENDIF ENDIF C-- Finish setting (if not done) using simple averaging IF ( .NOT.setInterFDr ) THEN C- Interface position at the middle between 2 centers bHybSigmF(1) = 1. _d 0 aHybSigmF(1) = 0. _d 0 bHybSigmF(Nr+1) = 0. _d 0 aHybSigmF(Nr+1) = 0. _d 0 DO k=2,Nr bHybSigmF(k) = ( bHybSigmC(k) + bHybSigmC(k-1) )*0.5 _d 0 aHybSigmF(k) = ( aHybSigmC(k) + aHybSigmC(k-1) )*0.5 _d 0 ENDDO ENDIF IF ( .NOT.setCenterDr ) THEN C- Center position at the middle between 2 interfaces DO k=1,Nr bHybSigmC(k) = ( bHybSigmF(k) + bHybSigmF(k+1) )*0.5 _d 0 aHybSigmC(k) = ( aHybSigmF(k) + aHybSigmF(k+1) )*0.5 _d 0 ENDDO ENDIF C-- Vertical increment: DO k=1,Nr dAHybSigF(k) = ( aHybSigmF(k+1) - aHybSigmF(k) )*rkSign dBHybSigF(k) = ( bHybSigmF(k+1) - bHybSigmF(k) )*rkSign ENDDO DO k=2,Nr dAHybSigC(k) = ( aHybSigmC(k) - aHybSigmC(k-1) )*rkSign dBHybSigC(k) = ( bHybSigmC(k) - bHybSigmC(k-1) )*rkSign ENDDO dAHybSigC(1) = ( aHybSigmC(1) - aHybSigmF(1) )*rkSign dBHybSigC(1) = ( bHybSigmC(1) - bHybSigmF(1) )*rkSign dAHybSigC(Nr+1) = ( aHybSigmF(Nr+1) - aHybSigmC(Nr) )*rkSign dBHybSigC(Nr+1) = ( bHybSigmF(Nr+1) - bHybSigmC(Nr) )*rkSign C-- Check for miss-match between vertical discretization : maxErrC = 0. maxErrF = 0. epsil = 1. _d -9 DO k=1,Nr tmpError = ( rC(k)-rF(Nr+1) )*recip_fullDepth & - ( aHybSigmC(k)+bHybSigmC(k) ) IF ( ABS(tmpError).GT.epsil ) THEN IF ( maxErrC.LE.epsil ) THEN WRITE(msgBuf,'(2A)') 'S/R INI_VERTICAL_GRID:', & ' rC and Hybrid-Sigma Coeff miss-match' CALL PRINT_ERROR( msgBuf, myThid ) ENDIF WRITE(msgBuf,'(A,I4,2(A,1PE14.6),A,1P2E14.6)') & ' k=', k,' , err=', tmpError, ' ; rC=', rC(k), & ' , a & b=', aHybSigmC(k), bHybSigmC(k) CALL PRINT_ERROR( msgBuf, myThid ) ENDIF maxErrC = MAX( maxErrC, ABS(tmpError) ) ENDDO DO k=1,Nr+1 tmpError = ( rF(k)-rF(Nr+1) )*recip_fullDepth & - ( aHybSigmF(k)+bHybSigmF(k) ) IF ( ABS(tmpError).GT.epsil ) THEN IF ( maxErrF.LE.epsil ) THEN WRITE(msgBuf,'(2A)') 'S/R INI_VERTICAL_GRID:', & ' rF and Hybrid-Sigma Coeff miss-match' CALL PRINT_ERROR( msgBuf, myThid ) ENDIF WRITE(msgBuf,'(A,I4,2(A,1PE14.6),A,1P2E14.6)') & ' k=', k,' , err=', tmpError, ' ; rF=', rF(k), & ' , a & b=', aHybSigmF(k), bHybSigmF(k) CALL PRINT_ERROR( msgBuf, myThid ) ENDIF maxErrF = MAX( maxErrF, ABS(tmpError) ) ENDDO WRITE(msgBuf,'(2A,1PE14.6)') 'S/R INI_VERTICAL_GRID:', & ' matching of aHybSigmC & rC :', maxErrC CALL PRINT_MESSAGE( msgBuf, standardMessageUnit, & SQUEEZE_RIGHT, myThid ) WRITE(msgBuf,'(2A,1PE14.6)') 'S/R INI_VERTICAL_GRID:', & ' matching of aHybSigmF & rF :', maxErrF CALL PRINT_MESSAGE( msgBuf, standardMessageUnit, & SQUEEZE_RIGHT, myThid ) IF ( maxErrC.GT.epsil .OR. maxErrF.GT.epsil ) THEN WRITE(msgBuf,'(2A)') 'S/R INI_VERTICAL_GRID:', & ' rC,rF and Hybrid-Sigma Coeff miss-match' CALL PRINT_ERROR( msgBuf, myThid ) STOP 'ABNORMAL END: S/R INI_VERTICAL_GRID' ENDIF C--- End setting-up Hybrid-Sigma vertical coordinate: ENDIF _END_MASTER(myThid) _BARRIER RETURN END