C $Header: /u/gcmpack/MITgcm/pkg/kpp/kpp_forcing_surf.F,v 1.10 2014/09/11 19:23:23 jmc Exp $ C $Name: $ #include "KPP_OPTIONS.h" #ifdef ALLOW_AUTODIFF # include "AUTODIFF_OPTIONS.h" #endif #ifdef ALLOW_SALT_PLUME #include "SALT_PLUME_OPTIONS.h" #endif CBOP C !ROUTINE: KPP_FORCING_SURF C !INTERFACE: ========================================================== SUBROUTINE KPP_FORCING_SURF( I rhoSurf, surfForcU, surfForcV, I surfForcT, surfForcS, surfForcTice, I Qsw, #ifdef ALLOW_SALT_PLUME I SPforcS,SPforcT, #endif /* ALLOW_SALT_PLUME */ I ttalpha, ssbeta, O ustar, bo, bosol, #ifdef ALLOW_SALT_PLUME O boplume, #endif /* ALLOW_SALT_PLUME */ O dVsq, I ikppkey, iMin, iMax, jMin, jMax, bi, bj, myTime, myThid ) C !DESCRIPTION: \bv C *==========================================================* C | SUBROUTINE KPP_FORCING_SURF | C | o Compute all surface related KPP fields: | C | - friction velocity ustar | C | - turbulent and radiative surface buoyancy forcing, | C | bo and bosol, and surface haline buoyancy forcing | C | boplume | C | - velocity shear relative to surface squared (this is | C | not really a surface affected quantity unless it is | C | computed with respect to some resolution independent | C | reference level, that is KPP_ESTIMATE_UREF defined ) | C *==========================================================* IMPLICIT NONE C \ev C !USES: =============================================================== #include "SIZE.h" #include "EEPARAMS.h" #include "PARAMS.h" #include "GRID.h" #include "DYNVARS.h" #include "KPP_PARAMS.h" C !INPUT PARAMETERS: =================================================== C Routine arguments C ikppkeyb - key for storing trajectory for adjoint (taf) C imin, imax, jmin, jmax - array computation indices C bi, bj - array indices on which to apply calculations C myTime - Current time in simulation C myThid - Current thread id C rhoSurf- density of surface layer (kg/m^3) C surfForcU units are r_unit.m/s^2 (=m^2/s^2 if r=z) C surfForcV units are r_unit.m/s^2 (=m^2/s^-2 if r=z) C surfForcS units are r_unit.psu/s (=psu.m/s if r=z) C - EmPmR * S_surf plus salinity relaxation*drF(1) C surfForcT units are r_unit.Kelvin/s (=Kelvin.m/s if r=z) C - Qnet (+Qsw) plus temp. relaxation*drF(1) C -> calculate -lambda*(T(model)-T(clim)) C Qnet assumed to be net heat flux including ShortWave rad. C surfForcTice C - equivalent Temperature flux in the top level that corresponds C to the melting or freezing of sea-ice. C Note that the surface level temperature is modified C directly by the sea-ice model in order to maintain C water temperature under sea-ice at the freezing C point. But we need to keep track of the C equivalent amount of heat that this surface-level C temperature change implies because it is used by C the KPP package (kpp_calc.F and kpp_transport_t.F). C Units are r_unit.K/s (=Kelvin.m/s if r=z) (>0 for ocean warming). C C Qsw - surface shortwave radiation (upwards positive) C saltPlumeFlux - salt rejected during freezing (downward = positive) C ttalpha - thermal expansion coefficient without 1/rho factor C d(rho{k,k})/d(T(k)) (kg/m^3/C) C ssbeta - salt expansion coefficient without 1/rho factor C d(rho{k,k})/d(S(k)) (kg/m^3/PSU) C !OUTPUT PARAMETERS: C ustar (nx,ny) - surface friction velocity (m/s) C bo (nx,ny) - surface turbulent buoyancy forcing (m^2/s^3) C bosol (nx,ny) - surface radiative buoyancy forcing (m^2/s^3) C boplume(nx,ny,Nr+1) - surface haline buoyancy forcing (m^2/s^3) C dVsq (nx,ny,Nr) - velocity shear re surface squared C at grid levels for bldepth (m^2/s^2) INTEGER ikppkey INTEGER iMin, iMax, jMin, jMax INTEGER bi, bj INTEGER myThid _RL myTime _RL rhoSurf (1-OLx:sNx+OLx,1-OLy:sNy+OLy) _RL surfForcU (1-OLx:sNx+OLx,1-OLy:sNy+OLy,nSx,nSy) _RL surfForcV (1-OLx:sNx+OLx,1-OLy:sNy+OLy,nSx,nSy) _RL surfForcT (1-OLx:sNx+OLx,1-OLy:sNy+OLy,nSx,nSy) _RL surfForcS (1-OLx:sNx+OLx,1-OLy:sNy+OLy,nSx,nSy) _RL surfForcTice(1-OLx:sNx+OLx,1-OLy:sNy+OLy,nSx,nSy) _RS Qsw (1-OLx:sNx+OLx,1-OLy:sNy+OLy,nSx,nSy) _RL TTALPHA (1-OLx:sNx+OLx,1-OLy:sNy+OLy,Nrp1) _RL SSBETA (1-OLx:sNx+OLx,1-OLy:sNy+OLy,Nrp1) _RL ustar ( 1-OLx:sNx+OLx, 1-OLy:sNy+OLy ) _RL bo ( 1-OLx:sNx+OLx, 1-OLy:sNy+OLy ) _RL bosol ( 1-OLx:sNx+OLx, 1-OLy:sNy+OLy ) #ifdef ALLOW_SALT_PLUME _RL SPforcS (1-OLx:sNx+OLx, 1-OLy:sNy+OLy, Nr ) _RL SPforcT (1-OLx:sNx+OLx, 1-OLy:sNy+OLy, Nr ) _RL boplume (1-OLx:sNx+OLx, 1-OLy:sNy+OLy, Nrp1 ) #endif /* ALLOW_SALT_PLUME */ _RL dVsq ( 1-OLx:sNx+OLx, 1-OLy:sNy+OLy, Nr ) C !LOCAL VARIABLES: ==================================================== C Local constants _RL p0 , p5 , p125 PARAMETER( p0=0.0, p5=0.5, p125=0.125 ) INTEGER i, j, k, im1, ip1, jm1, jp1 _RL tempvar2 _RL recip_Cp _RL work3 ( 1-OLx:sNx+OLx, 1-OLy:sNy+OLy ) #ifdef KPP_ESTIMATE_UREF _RL tempvar1, dBdz1, dBdz2, ustarX, ustarY _RL z0 ( 1-OLx:sNx+OLx, 1-OLy:sNy+OLy ) _RL zRef ( 1-OLx:sNx+OLx, 1-OLy:sNy+OLy ) _RL uRef ( 1-OLx:sNx+OLx, 1-OLy:sNy+OLy ) _RL vRef ( 1-OLx:sNx+OLx, 1-OLy:sNy+OLy ) #endif #ifdef ALLOW_SALT_PLUME #ifdef SALT_PLUME_VOLUME INTEGER kp1 _RL temparray (1-OLx:sNx+OLx, 1-OLy:sNy+OLy ) #endif /* SALT_PLUME_VOLUME */ #endif /* ALLOW_SALT_PLUME */ CEOP C------------------------------------------------------------------------ C friction velocity, turbulent and radiative surface buoyancy forcing C ------------------------------------------------------------------- C taux / rho = surfForcU (N/m^2) C tauy / rho = surfForcV (N/m^2) C ustar = sqrt( sqrt( taux^2 + tauy^2 ) / rho ) (m/s) C bo = - g * ( alpha*surfForcT + C beta *surfForcS ) / rho (m^2/s^3) C bosol = - g * alpha * Qsw * drF(1) / rho (m^2/s^3) C boplume =-g * ( beta *saltPlumeFlux/rhoConst )/rho (m^2/s^3) C =-g * ( beta *SPforcS /rhoConst )/rho (m^2/s^3) C -g * (alpha *SPforcT/Cp /rhoConst )/rho (m^2/s^3) C------------------------------------------------------------------------ recip_Cp = 1. _d 0 / HeatCapacity_Cp C initialize arrays to zero DO j = 1-OLy, sNy+OLy DO i = 1-OLx, sNx+OLx ustar(i,j) = p0 bo (I,J) = p0 bosol(I,J) = p0 #ifdef ALLOW_SALT_PLUME DO k = 1, Nr boplume(I,J,k) = p0 ENDDO boplume(I,J,Nrp1) = p0 #endif /* ALLOW_SALT_PLUME */ ENDDO ENDDO DO j = jmin, jmax jp1 = j + 1 DO i = imin, imax ip1 = i+1 work3(i,j) = & (surfForcU(i,j,bi,bj) + surfForcU(ip1,j,bi,bj)) * & (surfForcU(i,j,bi,bj) + surfForcU(ip1,j,bi,bj)) + & (surfForcV(i,j,bi,bj) + surfForcV(i,jp1,bi,bj)) * & (surfForcV(i,j,bi,bj) + surfForcV(i,jp1,bi,bj)) ENDDO ENDDO #ifdef ALLOW_AUTODIFF_TAMC CADJ store work3 = comlev1_kpp, key = ikppkey #endif DO j = jmin, jmax jp1 = j + 1 DO i = imin, imax ip1 = i+1 if ( work3(i,j) .lt. (phepsi*phepsi*drF(1)*drF(1)) ) then ustar(i,j) = SQRT( phepsi * p5 * drF(1) ) else tempVar2 = SQRT( work3(i,j) ) * p5 ustar(i,j) = SQRT( tempVar2 ) endif ENDDO ENDDO DO j = jmin, jmax jp1 = j + 1 DO i = imin, imax ip1 = i+1 bo(I,J) = - gravity * & ( TTALPHA(I,J,1) * (surfForcT(i,j,bi,bj)+ & surfForcTice(i,j,bi,bj)) + & SSBETA(I,J,1) * surfForcS(i,j,bi,bj) ) & / rhoSurf(I,J) bosol(I,J) = gravity * TTALPHA(I,J,1) * Qsw(i,j,bi,bj) * & recip_Cp*recip_rhoConst & / rhoSurf(I,J) ENDDO ENDDO #ifdef ALLOW_SALT_PLUME Catn: need check sign of SPforcT Cnote: on input, if notdef salt_plume_volume, SPforc[S,T](k>1)=!0 IF ( useSALT_PLUME ) THEN #ifdef SALT_PLUME_VOLUME DO j = jmin, jmax DO i = imin, imax DO k = 1, Nr kp1 = k+1 temparray(I,J) = - gravity * & ( SSBETA(I,J,k) * SPforcS(i,j,k) + & TTALPHA(I,J,k)* SPforcT(i,j,k) / HeatCapacity_Cp ) & * recip_rhoConst / rhoSurf(I,J) boplume(I,J,kp1) = boplume(I,J,k)+temparray(I,J) ENDDO ENDDO ENDDO #else /* SALT_PLUME_VOLUME */ DO j = jmin, jmax DO i = imin, imax DO k = 2, Nrp1 boplume(I,J,k) = 0. _d 0 ENDDO boplume(I,J,1) = - gravity * SSBETA(I,J,1) & * SPforcS(i,j,1) & * recip_rhoConst / rhoSurf(I,J) ENDDO ENDDO #endif /* SALT_PLUME_VOLUME */ ENDIF #endif /* ALLOW_SALT_PLUME */ #ifdef ALLOW_AUTODIFF_TAMC CADJ store ustar = comlev1_kpp, key = ikppkey #endif #ifdef ALLOW_DIAGNOSTICS IF ( useDiagnostics ) THEN CALL DIAGNOSTICS_FILL(bo ,'KPPbo ',0,1,2,bi,bj,myThid) CALL DIAGNOSTICS_FILL(bosol ,'KPPbosol',0,1,2,bi,bj,myThid) #ifdef ALLOW_SALT_PLUME CALL DIAGNOSTICS_FILL(boplume,'KPPboplm',0,Nr,2,bi,bj,myThid) #endif /* ALLOW_SALT_PLUME */ ENDIF #endif /* ALLOW_DIAGNOSTICS */ C------------------------------------------------------------------------ C velocity shear C -------------- C Get velocity shear squared, averaged from "u,v-grid" C onto "t-grid" (in (m/s)**2): C dVsq(k)=(Uref-U(k))**2+(Vref-V(k))**2 at grid levels C------------------------------------------------------------------------ C initialize arrays to zero DO k = 1, Nr DO j = 1-OLy, sNy+OLy DO i = 1-OLx, sNx+OLx dVsq(i,j,k) = p0 ENDDO ENDDO ENDDO C dVsq computation #ifdef KPP_ESTIMATE_UREF C Get rid of vertical resolution dependence of dVsq term by C estimating a surface velocity that is independent of first level C thickness in the model. First determine mixed layer depth hMix. C Second zRef = espilon * hMix. Third determine roughness length C scale z0. Third estimate reference velocity. DO j = jmin, jmax jp1 = j + 1 DO i = imin, imax ip1 = i + 1 C Determine mixed layer depth hMix as the shallowest depth at which C dB/dz exceeds 5.2e-5 s^-2. work1(i,j) = nzmax(i,j,bi,bj) DO k = 1, Nr IF ( k .LT. nzmax(i,j,bi,bj) .AND. & maskC(I,J,k,bi,bj) .GT. 0. .AND. & dbloc(i,j,k) / drC(k+1) .GT. dB_dz ) & work1(i,j) = k ENDDO C Linearly interpolate to find hMix. k = work1(i,j) IF ( k .EQ. 0 .OR. nzmax(i,j,bi,bj) .EQ. 1 ) THEN zRef(i,j) = p0 ELSEIF ( k .EQ. 1) THEN dBdz2 = dbloc(i,j,1) / drC(2) zRef(i,j) = drF(1) * dB_dz / dBdz2 ELSEIF ( k .LT. nzmax(i,j,bi,bj) ) THEN dBdz1 = dbloc(i,j,k-1) / drC(k ) dBdz2 = dbloc(i,j,k ) / drC(k+1) zRef(i,j) = rF(k) + drF(k) * (dB_dz - dBdz1) / & MAX ( phepsi, dBdz2 - dBdz1 ) ELSE zRef(i,j) = rF(k+1) ENDIF C Compute roughness length scale z0 subject to 0 < z0 tempVar1 = p5 * ( & (uVel(i, j, 1,bi,bj)-uVel(i, j, 2,bi,bj)) * & (uVel(i, j, 1,bi,bj)-uVel(i, j, 2,bi,bj)) + & (uVel(ip1,j, 1,bi,bj)-uVel(ip1,j, 2,bi,bj)) * & (uVel(ip1,j, 1,bi,bj)-uVel(ip1,j, 2,bi,bj)) + & (vVel(i, j, 1,bi,bj)-vVel(i, j, 2,bi,bj)) * & (vVel(i, j, 1,bi,bj)-vVel(i, j, 2,bi,bj)) + & (vVel(i, jp1,1,bi,bj)-vVel(i, jp1,2,bi,bj)) * & (vVel(i, jp1,1,bi,bj)-vVel(i, jp1,2,bi,bj)) ) IF ( tempVar1 .lt. (epsln*epsln) ) THEN tempVar2 = epsln ELSE tempVar2 = SQRT ( tempVar1 ) ENDIF z0(i,j) = rF(2) * & ( rF(3) * LOG ( rF(3) / rF(2) ) / & ( rF(3) - rF(2) ) - & tempVar2 * vonK / & MAX ( ustar(i,j), phepsi ) ) z0(i,j) = MAX ( z0(i,j), phepsi ) C zRef is set to 0.1 * hMix subject to z0 <= zRef <= drF(1) zRef(i,j) = MAX ( epsilon * zRef(i,j), z0(i,j) ) zRef(i,j) = MIN ( zRef(i,j), drF(1) ) C Estimate reference velocity uRef and vRef. uRef(i,j) = p5 * ( uVel(i,j,1,bi,bj) + uVel(ip1,j,1,bi,bj) ) vRef(i,j) = p5 * ( vVel(i,j,1,bi,bj) + vVel(i,jp1,1,bi,bj) ) IF ( zRef(i,j) .LT. drF(1) ) THEN ustarX = ( surfForcU(i, j,bi,bj) + & surfForcU(ip1,j,bi,bj) ) * p5 *recip_drF(1) ustarY = ( surfForcV(i,j, bi,bj) + & surfForcV(i,jp1,bi,bj) ) * p5 *recip_drF(1) tempVar1 = ustarX * ustarX + ustarY * ustarY if ( tempVar1 .lt. (epsln*epsln) ) then tempVar2 = epsln else tempVar2 = SQRT ( tempVar1 ) endif tempVar2 = ustar(i,j) * & ( LOG ( zRef(i,j) / rF(2) ) + & z0(i,j) / zRef(i,j) - z0(i,j) / rF(2) ) / & vonK / tempVar2 uRef(i,j) = uRef(i,j) + ustarX * tempVar2 vRef(i,j) = vRef(i,j) + ustarY * tempVar2 ENDIF ENDDO ENDDO DO k = 1, Nr DO j = jmin, jmax jm1 = j - 1 jp1 = j + 1 DO i = imin, imax im1 = i - 1 ip1 = i + 1 dVsq(i,j,k) = p5 * ( & (uRef(i,j) - uVel(i, j, k,bi,bj)) * & (uRef(i,j) - uVel(i, j, k,bi,bj)) + & (uRef(i,j) - uVel(ip1,j, k,bi,bj)) * & (uRef(i,j) - uVel(ip1,j, k,bi,bj)) + & (vRef(i,j) - vVel(i, j, k,bi,bj)) * & (vRef(i,j) - vVel(i, j, k,bi,bj)) + & (vRef(i,j) - vVel(i, jp1,k,bi,bj)) * & (vRef(i,j) - vVel(i, jp1,k,bi,bj)) ) #ifdef KPP_SMOOTH_DVSQ dVsq(i,j,k) = p5 * dVsq(i,j,k) + p125 * ( & (uRef(i,j) - uVel(i, jm1,k,bi,bj)) * & (uRef(i,j) - uVel(i, jm1,k,bi,bj)) + & (uRef(i,j) - uVel(ip1,jm1,k,bi,bj)) * & (uRef(i,j) - uVel(ip1,jm1,k,bi,bj)) + & (uRef(i,j) - uVel(i, jp1,k,bi,bj)) * & (uRef(i,j) - uVel(i, jp1,k,bi,bj)) + & (uRef(i,j) - uVel(ip1,jp1,k,bi,bj)) * & (uRef(i,j) - uVel(ip1,jp1,k,bi,bj)) + & (vRef(i,j) - vVel(im1,j, k,bi,bj)) * & (vRef(i,j) - vVel(im1,j, k,bi,bj)) + & (vRef(i,j) - vVel(im1,jp1,k,bi,bj)) * & (vRef(i,j) - vVel(im1,jp1,k,bi,bj)) + & (vRef(i,j) - vVel(ip1,j, k,bi,bj)) * & (vRef(i,j) - vVel(ip1,j, k,bi,bj)) + & (vRef(i,j) - vVel(ip1,jp1,k,bi,bj)) * & (vRef(i,j) - vVel(ip1,jp1,k,bi,bj)) ) #endif /* KPP_SMOOTH_DVSQ */ ENDDO ENDDO ENDDO #else /* KPP_ESTIMATE_UREF */ DO k = 1, Nr DO j = jmin, jmax jm1 = j - 1 jp1 = j + 1 DO i = imin, imax im1 = i - 1 ip1 = i + 1 dVsq(i,j,k) = p5 * ( & (uVel(i, j, 1,bi,bj)-uVel(i, j, k,bi,bj)) * & (uVel(i, j, 1,bi,bj)-uVel(i, j, k,bi,bj)) + & (uVel(ip1,j, 1,bi,bj)-uVel(ip1,j, k,bi,bj)) * & (uVel(ip1,j, 1,bi,bj)-uVel(ip1,j, k,bi,bj)) + & (vVel(i, j, 1,bi,bj)-vVel(i, j, k,bi,bj)) * & (vVel(i, j, 1,bi,bj)-vVel(i, j, k,bi,bj)) + & (vVel(i, jp1,1,bi,bj)-vVel(i, jp1,k,bi,bj)) * & (vVel(i, jp1,1,bi,bj)-vVel(i, jp1,k,bi,bj)) ) #ifdef KPP_SMOOTH_DVSQ dVsq(i,j,k) = p5 * dVsq(i,j,k) + p125 * ( & (uVel(i, jm1,1,bi,bj)-uVel(i, jm1,k,bi,bj)) * & (uVel(i, jm1,1,bi,bj)-uVel(i, jm1,k,bi,bj)) + & (uVel(ip1,jm1,1,bi,bj)-uVel(ip1,jm1,k,bi,bj)) * & (uVel(ip1,jm1,1,bi,bj)-uVel(ip1,jm1,k,bi,bj)) + & (uVel(i, jp1,1,bi,bj)-uVel(i, jp1,k,bi,bj)) * & (uVel(i, jp1,1,bi,bj)-uVel(i, jp1,k,bi,bj)) + & (uVel(ip1,jp1,1,bi,bj)-uVel(ip1,jp1,k,bi,bj)) * & (uVel(ip1,jp1,1,bi,bj)-uVel(ip1,jp1,k,bi,bj)) + & (vVel(im1,j, 1,bi,bj)-vVel(im1,j, k,bi,bj)) * & (vVel(im1,j, 1,bi,bj)-vVel(im1,j, k,bi,bj)) + & (vVel(im1,jp1,1,bi,bj)-vVel(im1,jp1,k,bi,bj)) * & (vVel(im1,jp1,1,bi,bj)-vVel(im1,jp1,k,bi,bj)) + & (vVel(ip1,j, 1,bi,bj)-vVel(ip1,j, k,bi,bj)) * & (vVel(ip1,j, 1,bi,bj)-vVel(ip1,j, k,bi,bj)) + & (vVel(ip1,jp1,1,bi,bj)-vVel(ip1,jp1,k,bi,bj)) * & (vVel(ip1,jp1,1,bi,bj)-vVel(ip1,jp1,k,bi,bj)) ) #endif /* KPP_SMOOTH_DVSQ */ ENDDO ENDDO ENDDO #endif /* KPP_ESTIMATE_UREF */ RETURN END