C $Header: /home/ubuntu/mnt/e9_copy/MITgcm/pkg/generic_advdiff/gad_advection.F,v 1.27 2004/09/17 23:02:01 heimbach Exp $ C $Name: $ #include "GAD_OPTIONS.h" C---+----1----+----2----+----3----+----4----+----5----+----6----+----7-|--+----| CBOP C !ROUTINE: GAD_ADVECTION C !INTERFACE: ========================================================== SUBROUTINE GAD_ADVECTION( I implicitAdvection, advectionScheme, vertAdvecScheme, I tracerIdentity, I uVel, vVel, wVel, tracer, O gTracer, I bi,bj, myTime,myIter,myThid) C !DESCRIPTION: C Calculates the tendancy of a tracer due to advection. C It uses the multi-dimensional method given in \ref{sect:multiDimAdvection} C and can only be used for the non-linear advection schemes such as the C direct-space-time method and flux-limiters. C C The algorithm is as follows: C \begin{itemize} C \item{$\theta^{(n+1/3)} = \theta^{(n)} C - \Delta t \partial_x (u\theta^{(n)}) + \theta^{(n)} \partial_x u$} C \item{$\theta^{(n+2/3)} = \theta^{(n+1/3)} C - \Delta t \partial_y (v\theta^{(n+1/3)}) + \theta^{(n)} \partial_y v$} C \item{$\theta^{(n+3/3)} = \theta^{(n+2/3)} C - \Delta t \partial_r (w\theta^{(n+2/3)}) + \theta^{(n)} \partial_r w$} C \item{$G_\theta = ( \theta^{(n+3/3)} - \theta^{(n)} )/\Delta t$} C \end{itemize} C C The tendancy (output) is over-written by this routine. C !USES: =============================================================== IMPLICIT NONE #include "SIZE.h" #include "EEPARAMS.h" #include "PARAMS.h" #include "GRID.h" #include "GAD.h" #ifdef ALLOW_AUTODIFF_TAMC # include "tamc.h" # include "tamc_keys.h" # ifdef ALLOW_PTRACERS # include "PTRACERS_SIZE.h" # endif #endif #ifdef ALLOW_EXCH2 #include "W2_EXCH2_TOPOLOGY.h" #include "W2_EXCH2_PARAMS.h" #endif /* ALLOW_EXCH2 */ C !INPUT PARAMETERS: =================================================== C implicitAdvection :: implicit vertical advection (later on) C advectionScheme :: advection scheme to use (Horizontal plane) C vertAdvecScheme :: advection scheme to use (vertical direction) C tracerIdentity :: tracer identifier (required only for OBCS) C uVel :: velocity, zonal component C vVel :: velocity, meridional component C wVel :: velocity, vertical component C tracer :: tracer field C bi,bj :: tile indices C myTime :: current time C myIter :: iteration number C myThid :: thread number LOGICAL implicitAdvection INTEGER advectionScheme, vertAdvecScheme INTEGER tracerIdentity _RL uVel (1-Olx:sNx+Olx,1-Oly:sNy+Oly,Nr,nSx,nSy) _RL vVel (1-Olx:sNx+Olx,1-Oly:sNy+Oly,Nr,nSx,nSy) _RL wVel (1-Olx:sNx+Olx,1-Oly:sNy+Oly,Nr,nSx,nSy) _RL tracer(1-Olx:sNx+Olx,1-Oly:sNy+Oly,Nr,nSx,nSy) INTEGER bi,bj _RL myTime INTEGER myIter INTEGER myThid C !OUTPUT PARAMETERS: ================================================== C gTracer :: tendancy array _RL gTracer(1-Olx:sNx+Olx,1-Oly:sNy+Oly,Nr,nSx,nSy) C !LOCAL VARIABLES: ==================================================== C maskUp :: 2-D array for mask at W points C iMin,iMax, :: loop range for called routines C jMin,jMax :: loop range for called routines C i,j,k :: loop indices C kup :: index into 2 1/2D array, toggles between 1 and 2 C kdown :: index into 2 1/2D array, toggles between 2 and 1 C kp1 :: =k+1 for k maxcube. check tamc.h' ENDIF #endif /* ALLOW_AUTODIFF_TAMC */ IF (nipass.EQ.3) THEN calc_fluxes_X=.FALSE. calc_fluxes_Y=.FALSE. IF (ipass.EQ.1 .AND. (nCFace.EQ.1 .OR. nCFace.EQ.2) ) THEN calc_fluxes_X=.TRUE. ELSEIF (ipass.EQ.1 .AND. (nCFace.EQ.4 .OR. nCFace.EQ.5) ) THEN calc_fluxes_Y=.TRUE. ELSEIF (ipass.EQ.2 .AND. (nCFace.EQ.1 .OR. nCFace.EQ.6) ) THEN calc_fluxes_Y=.TRUE. ELSEIF (ipass.EQ.2 .AND. (nCFace.EQ.3 .OR. nCFace.EQ.4) ) THEN calc_fluxes_X=.TRUE. ELSEIF (ipass.EQ.3 .AND. (nCFace.EQ.2 .OR. nCFace.EQ.3) ) THEN calc_fluxes_Y=.TRUE. ELSEIF (ipass.EQ.3 .AND. (nCFace.EQ.5 .OR. nCFace.EQ.6) ) THEN calc_fluxes_X=.TRUE. ENDIF ELSE calc_fluxes_X=.TRUE. calc_fluxes_Y=.TRUE. ENDIF C-- X direction IF (calc_fluxes_X) THEN C-- Internal exchange for calculations in X IF (useCubedSphereExchange) THEN C-- For cube face corners we need to duplicate the C-- i-1 and i+1 values into the null space as follows: C C C o NW corner: copy T( 0,sNy ) into T( 0,sNy+1) e.g. C | C x T(0,sNy+1) | C /\ | C --||------------|----------- C || | C x T(0,sNy) | x T(1,sNy) C | C C o SW corner: copy T(0,1) into T(0,0) e.g. C | C x T(0,1) | x T(1,1) C || | C --||------------|----------- C \/ | C x T(0,0) | C | C C o NE corner: copy T(sNx+1,sNy ) into T(sNx+1,sNy+1) e.g. C | C | x T(sNx+1,sNy+1) C | /\ C ----------------|--||------- C | || C x T(sNx,sNy) | x T(sNx+1,sNy ) C | C o SE corner: copy T(sNx+1,1 ) into T(sNx+1,0 ) e.g. C | C x T(sNx,1) | x T(sNx+1, 1) C | || C ----------------|--||------- C | \/ C | x T(sNx+1, 0) IF ( southWestCorner ) THEN DO J=1,OLy DO I=1,OLx localTij(1-I, 1-J )= localTij(1-J ,1 ) ENDDO ENDDO ENDIF IF ( southEastCorner ) THEN DO J=1,OLy DO I=1,OLx localTij(sNx+I, 1-J )=localTij(sNx+J, I ) ENDDO ENDDO ENDIF IF ( northWestCorner ) THEN DO J=1,OLy DO I=1,OLx localTij( 1-I ,sNy+J)=localTij( 1-J , sNy+1-I ) ENDDO ENDDO ENDIF IF ( northEastCorner ) THEN DO J=1,OLy DO I=1,OLx localTij(sNx+I,sNy+J)=localTij(sNx+J, sNy+1-I ) ENDDO ENDDO ENDIF ENDIF C- Advective flux in X DO j=1-Oly,sNy+Oly DO i=1-Olx,sNx+Olx af(i,j) = 0. ENDDO ENDDO #ifdef ALLOW_AUTODIFF_TAMC #ifndef DISABLE_MULTIDIM_ADVECTION CADJ STORE localTij(:,:) = CADJ & comlev1_bibj_k_gad_pass, key=passkey, byte=isbyte #endif #endif /* ALLOW_AUTODIFF_TAMC */ IF (advectionScheme.EQ.ENUM_FLUX_LIMIT) THEN CALL GAD_FLUXLIMIT_ADV_X( & bi,bj,k,deltaTtracer,uTrans,uVel,localTij,af,myThid) ELSEIF (advectionScheme.EQ.ENUM_DST3 ) THEN CALL GAD_DST3_ADV_X( & bi,bj,k,deltaTtracer,uTrans,uVel,localTij,af,myThid) ELSEIF (advectionScheme.EQ.ENUM_DST3_FLUX_LIMIT ) THEN CALL GAD_DST3FL_ADV_X( & bi,bj,k,deltaTtracer,uTrans,uVel,localTij,af,myThid) ELSE STOP 'GAD_ADVECTION: adv. scheme incompatibale with multi-dim' ENDIF DO j=1-Oly,sNy+Oly DO i=1-Olx,sNx+Olx-1 localTij(i,j)=localTij(i,j)-deltaTtracer* & _recip_hFacC(i,j,k,bi,bj)*recip_drF(k) & *recip_rA(i,j,bi,bj) & *( af(i+1,j)-af(i,j) & -tracer(i,j,k,bi,bj)*(uTrans(i+1,j)-uTrans(i,j)) & ) ENDDO ENDDO #ifdef ALLOW_OBCS C-- Apply open boundary conditions IF (useOBCS) THEN IF (tracerIdentity.EQ.GAD_TEMPERATURE) THEN CALL OBCS_APPLY_TLOC( bi, bj, k, localTij, myThid ) ELSEIF (tracerIdentity.EQ.GAD_SALINITY) THEN CALL OBCS_APPLY_SLOC( bi, bj, k, localTij, myThid ) END IF END IF #endif /* ALLOW_OBCS */ C-- End of X direction ENDIF C-- Y direction IF (calc_fluxes_Y) THEN IF (useCubedSphereExchange) THEN C-- Internal exchange for calculations in Y C-- For cube face corners we need to duplicate the C-- j-1 and j+1 values into the null space as follows: C C o SW corner: copy T(0,1) into T(0,0) e.g. C | C | x T(1,1) C | C ----------------|----------- C | C x T(0,0)<====== x T(1,0) C | C C o NW corner: copy T( 0,sNy ) into T( 0,sNy+1) e.g. C | C x T(0,sNy+1)<=== x T(1,sNy+1) C | C ----------------|----------- C | C | x T(1,sNy) C | C C o NE corner: copy T(sNx+1,sNy ) into T(sNx+1,sNy+1) e.g. C | C x T(sNx,sNy+1)=====>x T(sNx+1,sNy+1) C | C ----------------|----------- C | C x T(sNx,sNy) | C | C o SE corner: copy T(sNx+1,1 ) into T(sNx+1,0 ) e.g. C | C x T(sNx,1) | C | C ----------------|----------- C | C x T(sNx,0) =====>x T(sNx+1, 0) IF ( southWestCorner ) THEN DO J=1,Oly DO I=1,Olx localTij( 1-i , 1-j ) = localTij(j , 1-i ) ENDDO ENDDO ENDIF IF ( southEastCorner ) THEN DO J=1,Oly DO I=1,Olx localTij(sNx+i, 1-j ) = localTij(sNx+1-j, 1-i ) ENDDO ENDDO ENDIF IF ( northWestCorner ) THEN DO J=1,Oly DO I=1,Olx localTij( 1-i ,sNy+j) = localTij(j ,sNy+i) ENDDO ENDDO ENDIF IF ( northEastCorner ) THEN DO J=1,Oly DO I=1,Olx localTij(sNx+i,sNy+j) = localTij(sNx+1-j,sNy+i) ENDDO ENDDO ENDIF ENDIF C- Advective flux in Y DO j=1-Oly,sNy+Oly DO i=1-Olx,sNx+Olx af(i,j) = 0. ENDDO ENDDO #ifdef ALLOW_AUTODIFF_TAMC #ifndef DISABLE_MULTIDIM_ADVECTION CADJ STORE localTij(:,:) = CADJ & comlev1_bibj_k_gad_pass, key=passkey, byte=isbyte #endif #endif /* ALLOW_AUTODIFF_TAMC */ IF (advectionScheme.EQ.ENUM_FLUX_LIMIT) THEN CALL GAD_FLUXLIMIT_ADV_Y( & bi,bj,k,deltaTtracer,vTrans,vVel,localTij,af,myThid) ELSEIF (advectionScheme.EQ.ENUM_DST3 ) THEN CALL GAD_DST3_ADV_Y( & bi,bj,k,deltaTtracer,vTrans,vVel,localTij,af,myThid) ELSEIF (advectionScheme.EQ.ENUM_DST3_FLUX_LIMIT ) THEN CALL GAD_DST3FL_ADV_Y( & bi,bj,k,deltaTtracer,vTrans,vVel,localTij,af,myThid) ELSE STOP 'GAD_ADVECTION: adv. scheme incompatibale with mutli-dim' ENDIF DO j=1-Oly,sNy+Oly-1 DO i=1-Olx,sNx+Olx localTij(i,j)=localTij(i,j)-deltaTtracer* & _recip_hFacC(i,j,k,bi,bj)*recip_drF(k) & *recip_rA(i,j,bi,bj) & *( af(i,j+1)-af(i,j) & -tracer(i,j,k,bi,bj)*(vTrans(i,j+1)-vTrans(i,j)) & ) ENDDO ENDDO #ifdef ALLOW_OBCS C-- Apply open boundary conditions IF (useOBCS) THEN IF (tracerIdentity.EQ.GAD_TEMPERATURE) THEN CALL OBCS_APPLY_TLOC( bi, bj, k, localTij, myThid ) ELSEIF (tracerIdentity.EQ.GAD_SALINITY) THEN CALL OBCS_APPLY_SLOC( bi, bj, k, localTij, myThid ) END IF END IF #endif /* ALLOW_OBCS */ C-- End of Y direction ENDIF C-- End of ipass loop ENDDO IF ( implicitAdvection ) THEN C- explicit advection is done ; store tendency in gTracer: DO j=1-Oly,sNy+Oly DO i=1-Olx,sNx+Olx gTracer(i,j,k,bi,bj)= & (localTij(i,j)-tracer(i,j,k,bi,bj))/deltaTtracer ENDDO ENDDO ELSE C- horizontal advection done; store intermediate result in 3D array: DO j=1-Oly,sNy+Oly DO i=1-Olx,sNx+Olx localTijk(i,j,k)=localTij(i,j) ENDDO ENDDO ENDIF C-- End of K loop for horizontal fluxes ENDDO IF ( .NOT.implicitAdvection ) THEN C-- Start of k loop for vertical flux DO k=Nr,1,-1 #ifdef ALLOW_AUTODIFF_TAMC kkey = (igadkey-1)*Nr + k #endif /* ALLOW_AUTODIFF_TAMC */ C-- kup Cycles through 1,2 to point to w-layer above C-- kDown Cycles through 2,1 to point to w-layer below kup = 1+MOD(k+1,2) kDown= 1+MOD(k,2) c kp1=min(Nr,k+1) kp1Msk=1. if (k.EQ.Nr) kp1Msk=0. C-- Compute Vertical transport #ifdef ALLOW_AIM C- a hack to prevent Water-Vapor vert.transport into the stratospheric level Nr IF ( k.EQ.1 .OR. & (useAIM .AND. tracerIdentity.EQ.GAD_SALINITY .AND. k.EQ.Nr) & ) THEN #else IF ( k.EQ.1 ) THEN #endif C- Surface interface : DO j=1-Oly,sNy+Oly DO i=1-Olx,sNx+Olx rTransKp1(i,j) = kp1Msk*rTrans(i,j) rTrans(i,j) = 0. fVerT(i,j,kUp) = 0. af(i,j) = 0. ENDDO ENDDO ELSE C- Interior interface : DO j=1-Oly,sNy+Oly DO i=1-Olx,sNx+Olx rTransKp1(i,j) = kp1Msk*rTrans(i,j) rTrans(i,j) = wVel(i,j,k,bi,bj)*rA(i,j,bi,bj) & *maskC(i,j,k-1,bi,bj) af(i,j) = 0. ENDDO ENDDO #ifdef ALLOW_GMREDI C-- Residual transp = Bolus transp + Eulerian transp IF (useGMRedi) & CALL GMREDI_CALC_WFLOW( & rTrans, bi, bj, k, myThid) #endif /* ALLOW_GMREDI */ #ifdef ALLOW_AUTODIFF_TAMC CADJ STORE localTijk(:,:,k) CADJ & = comlev1_bibj_k_gad, key=kkey, byte=isbyte CADJ STORE rTrans(:,:) CADJ & = comlev1_bibj_k_gad, key=kkey, byte=isbyte #endif /* ALLOW_AUTODIFF_TAMC */ C- Compute vertical advective flux in the interior: IF (vertAdvecScheme.EQ.ENUM_FLUX_LIMIT) THEN CALL GAD_FLUXLIMIT_ADV_R( & bi,bj,k,deltaTtracer,rTrans,wVel,localTijk,af,myThid) ELSEIF (vertAdvecScheme.EQ.ENUM_DST3 ) THEN CALL GAD_DST3_ADV_R( & bi,bj,k,deltaTtracer,rTrans,wVel,localTijk,af,myThid) ELSEIF (vertAdvecScheme.EQ.ENUM_DST3_FLUX_LIMIT ) THEN CALL GAD_DST3FL_ADV_R( & bi,bj,k,deltaTtracer,rTrans,wVel,localTijk,af,myThid) ELSE STOP 'GAD_ADVECTION: adv. scheme incompatibale with mutli-dim' ENDIF C- add the advective flux to fVerT DO j=1-Oly,sNy+Oly DO i=1-Olx,sNx+Olx fVerT(i,j,kUp) = af(i,j) ENDDO ENDDO C- end Surface/Interior if bloc ENDIF #ifdef ALLOW_AUTODIFF_TAMC CADJ STORE rTrans(:,:) CADJ & = comlev1_bibj_k_gad, key=kkey, byte=isbyte CADJ STORE rTranskp1(:,:) CADJ & = comlev1_bibj_k_gad, key=kkey, byte=isbyte #endif /* ALLOW_AUTODIFF_TAMC */ C-- Divergence of vertical fluxes DO j=1-Oly,sNy+Oly DO i=1-Olx,sNx+Olx localTij(i,j)=localTijk(i,j,k)-deltaTtracer* & _recip_hFacC(i,j,k,bi,bj)*recip_drF(k) & *recip_rA(i,j,bi,bj) & *( fVerT(i,j,kUp)-fVerT(i,j,kDown) & -tracer(i,j,k,bi,bj)*(rTrans(i,j)-rTransKp1(i,j)) & )*rkFac gTracer(i,j,k,bi,bj)= & (localTij(i,j)-tracer(i,j,k,bi,bj))/deltaTtracer ENDDO ENDDO C-- End of K loop for vertical flux ENDDO C-- end of if not.implicitAdvection block ENDIF RETURN END