New URL for NEMO forge!   http://forge.nemo-ocean.eu

Since March 2022 along with NEMO 4.2 release, the code development moved to a self-hosted GitLab.
This present forge is now archived and remained online for history.
Changeset 11615 for NEMO/branches/2019/dev_r11085_ASINTER-05_Brodeau_Advanced_Bulk/src/OCE/SBC/sbcblk_algo_ecmwf.F90 – NEMO

Ignore:
Timestamp:
2019-09-30T15:18:21+02:00 (5 years ago)
Author:
laurent
Message:

LB: new cool-skin and warm-layer parameterizations for ECMWF and COARE3.6, COARE3.0 uses same CSWL param as for COARE3.6.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • NEMO/branches/2019/dev_r11085_ASINTER-05_Brodeau_Advanced_Bulk/src/OCE/SBC/sbcblk_algo_ecmwf.F90

    r11329 r11615  
    3939   USE sbc_oce         ! Surface boundary condition: ocean fields 
    4040   USE sbcblk_phy      ! all thermodynamics functions, rho_air, q_sat, etc... !LB 
    41    USE sbcblk_skin     ! cool-skin/warm layer scheme (CSWL_ECMWF) !LB 
     41   USE sbcblk_skin_ecmwf ! cool-skin/warm layer scheme !LB 
    4242 
    4343   IMPLICIT NONE 
     
    6060CONTAINS 
    6161 
    62    SUBROUTINE turb_ecmwf( zt, zu, T_s, t_zt, q_s, q_zt, U_zu, & 
     62   SUBROUTINE turb_ecmwf( zt, zu, T_s, t_zt, q_s, q_zt, U_zu, l_use_cs, l_use_wl, & 
    6363      &                      Cd, Ch, Ce, t_zu, q_zu, U_blk,      & 
    6464      &                      Cdn, Chn, Cen,                      & 
    65       &                      Qsw, rad_lw, slp,                   & 
    66       &                      Tsk_b ) 
     65      &                      Qsw, rad_lw, slp, pdT_cs,           & ! optionals for cool-skin (and warm-layer) 
     66      &                      pdT_wl )                              ! optionals for warm-layer only 
    6767      !!---------------------------------------------------------------------- 
    68        !!                      ***  ROUTINE  turb_ecmwf  *** 
     68      !!                      ***  ROUTINE  turb_ecmwf  *** 
    6969      !! 
    7070      !! ** Purpose :   Computes turbulent transfert coefficients of surface 
    71       !!                fluxes according to IFS doc. (cycle 40) 
     71      !!                fluxes according to IFS doc. (cycle 45r1) 
    7272      !!                If relevant (zt /= zu), adjust temperature and humidity from height zt to zu 
    7373      !!                Returns the effective bulk wind speed at zu to be used in the bulk formulas 
     
    8282      !!    *  zt   : height for temperature and spec. hum. of air            [m] 
    8383      !!    *  zu   : height for wind speed (usually 10m)                     [m] 
    84       !!    *  U_zu : scalar wind speed at zu                                 [m/s] 
    8584      !!    *  t_zt : potential air temperature at zt                         [K] 
    8685      !!    *  q_zt : specific humidity of air at zt                          [kg/kg] 
     86      !!    *  U_zu : scalar wind speed at zu                                 [m/s] 
     87      !!    * l_use_cs : use the cool-skin parameterization 
     88      !!    * l_use_wl : use the warm-layer parameterization 
    8789      !! 
    8890      !! INPUT/OUTPUT: 
     
    101103      !!    *  rad_lw : downwelling longwave radiation at the surface  (>0)   [W/m^2] 
    102104      !!    *  slp    : sea-level pressure                                    [Pa] 
    103       !!    *  Tsk_b  : estimate of skin temperature at previous time-step    [K] 
     105      !!    * pdT_cs  : SST increment "dT" for cool-skin correction           [K] 
     106      !!    * pdT_wl  : SST increment "dT" for warm-layer correction          [K] 
    104107      !! 
    105108      !! OUTPUT : 
     
    122125      REAL(wp), INTENT(in   ), DIMENSION(jpi,jpj) ::   q_zt     ! specific air humidity at zt             [kg/kg] 
    123126      REAL(wp), INTENT(in   ), DIMENSION(jpi,jpj) ::   U_zu     ! relative wind module at zu                [m/s] 
     127      LOGICAL , INTENT(in   )                     ::   l_use_cs ! use the cool-skin parameterization 
     128      LOGICAL , INTENT(in   )                     ::   l_use_wl ! use the warm-layer parameterization 
    124129      REAL(wp), INTENT(  out), DIMENSION(jpi,jpj) ::   Cd       ! transfer coefficient for momentum         (tau) 
    125130      REAL(wp), INTENT(  out), DIMENSION(jpi,jpj) ::   Ch       ! transfer coefficient for sensible heat (Q_sens) 
     
    133138      REAL(wp), INTENT(in   ), OPTIONAL, DIMENSION(jpi,jpj) ::   rad_lw   !             [W/m^2] 
    134139      REAL(wp), INTENT(in   ), OPTIONAL, DIMENSION(jpi,jpj) ::   slp      !             [Pa] 
    135       REAL(wp), INTENT(in   ), OPTIONAL, DIMENSION(jpi,jpj) ::   Tsk_b    !             [Pa] 
     140      REAL(wp), INTENT(  out), OPTIONAL, DIMENSION(jpi,jpj) ::   pdT_cs 
     141      ! 
     142      REAL(wp), INTENT(  out), OPTIONAL, DIMENSION(jpi,jpj) ::   pdT_wl   !             [K] 
    136143      ! 
    137144      INTEGER :: j_itt 
     
    145152         &  z0, z0t, z0q 
    146153      ! 
    147       ! Cool skin: 
    148       LOGICAL :: l_use_skin = .FALSE. 
    149       REAL(wp), DIMENSION(jpi,jpj) :: zsst    ! to back up the initial bulk SST 
     154      REAL(wp), DIMENSION(:,:), ALLOCATABLE :: & 
     155         &                zsst,   &  ! to back up the initial bulk SST 
     156         &                pdTc,   &  ! SST increment "dT" for cool-skin correction           [K] 
     157         &                pdTw       ! SST increment "dT" for warm layer correction          [K] 
    150158      ! 
    151159      REAL(wp), DIMENSION(jpi,jpj) ::   func_m, func_h 
    152160      REAL(wp), DIMENSION(jpi,jpj) ::   ztmp0, ztmp1, ztmp2 
    153       !!---------------------------------------------------------------------------------- 
    154  
    155       ! Cool skin ? 
    156       IF( PRESENT(Qsw) .AND. PRESENT(rad_lw) .AND. PRESENT(slp) ) THEN 
    157          l_use_skin = .TRUE. 
    158       END IF 
    159       IF (lwp) PRINT *, ' *** LOLO(sbcblk_algo_ecmwf.F90) => l_use_skin =', l_use_skin 
    160  
    161       ! Identical first gess as in COARE, with IFS parameter values though... 
    162       ! 
     161      CHARACTER(len=40), PARAMETER :: crtnm = 'turb_ecmwf@sbcblk_algo_ecmwf.F90' 
     162      !!---------------------------------------------------------------------------------- 
     163 
    163164      l_zt_equal_zu = .FALSE. 
    164165      IF( ABS(zu - zt) < 0.01_wp )   l_zt_equal_zu = .TRUE.    ! testing "zu == zt" is risky with double precision 
    165166 
    166       !! Initialization for cool skin: 
    167       zsst   = T_s    ! save the bulk SST 
    168       IF( l_use_skin ) THEN 
    169          ! First guess for skin temperature: 
    170          IF( PRESENT(Tsk_b) ) THEN 
    171             T_s = Tsk_b 
    172          ELSE 
    173             T_s = T_s - 0.25     ! sst - 0.25 
    174          END IF 
    175          q_s    = rdct_qsat_salt*q_sat(MAX(T_s, 200._wp), slp) ! First guess of q_s 
     167      !! Initializations for cool skin and warm layer: 
     168      IF ( l_use_cs ) THEN 
     169         IF( .NOT.(PRESENT(Qsw) .AND. PRESENT(rad_lw) .AND. PRESENT(slp)) ) THEN 
     170            PRINT *, ' * PROBLEM ('//trim(crtnm)//'): you need to provide Qsw, rad_lw & slp to use cool-skin param!' 
     171            STOP 
     172         END IF 
     173         ALLOCATE ( pdTc(jpi,jpj) ) 
     174         pdTc(:,:) = -0.25_wp  ! First guess of skin correction 
    176175      END IF 
    177176 
     177      IF ( l_use_wl ) THEN 
     178         IF(.NOT.(PRESENT(Qsw) .AND. PRESENT(rad_lw) .AND. PRESENT(slp))) THEN 
     179            PRINT *, ' * PROBLEM ('//trim(crtnm)//'): you need to provide Qsw, rad_lw & slp to use warm-layer param!' 
     180            STOP 
     181         END IF 
     182         ALLOCATE ( pdTw(jpi,jpj) ) 
     183         pdTw(:,:) = 0._wp 
     184      END IF 
     185 
     186      IF ( l_use_cs .OR. l_use_wl ) THEN 
     187         ALLOCATE ( zsst(jpi,jpj) ) 
     188         zsst = T_s ! backing up the bulk SST 
     189         IF( l_use_cs ) T_s = T_s - 0.25_wp   ! First guess of correction 
     190         q_s    = rdct_qsat_salt*q_sat(MAX(T_s, 200._wp), slp) ! First guess of q_s !LOLO WL too!!! 
     191      END IF 
     192 
     193 
     194      ! Identical first gess as in COARE, with IFS parameter values though... 
     195      ! 
    178196      !! First guess of temperature and humidity at height zu: 
    179197      t_zu = MAX( t_zt ,  180._wp )   ! who knows what's given on masked-continental regions... 
     
    197215      z0t    = MIN(ABS(z0t), 0.001_wp)  ! (prevent FPE from stupid values from masked region later on...) !#LOLO 
    198216 
    199       ztmp2  = vkarmn/ztmp0 
    200       Cd     = ztmp2*ztmp2    ! first guess of Cd 
     217      Cd     = (vkarmn/ztmp0)**2    ! first guess of Cd 
    201218 
    202219      ztmp0 = vkarmn*vkarmn/LOG(zt/z0t)/Cd 
     
    265282         z0q    = MIN( ABS( alpha_Q*ztmp1                     ) , 0.001_wp) 
    266283 
    267          !! Update wind at 10m taking into acount convection-related wind gustiness: 
    268          !! => Chap. 3.2, IFS doc - Cy40r1, Eq.3.17 and Eq.3.18 + Eq.3.8 
    269          ! Only true when unstable (L<0) => when ztmp0 < 0 => - !!! 
    270          ztmp2 = ztmp2 * ( MAX(-zi0*Linv/vkarmn , 0._wp))**(2._wp/3._wp) ! => w*^2  (combining Eq. 3.8 and 3.18, hap.3, IFS doc - Cy31r1) 
    271          !! => equivalent using Beta=1 (gustiness parameter, 1.25 for COARE, also zi0=600 in COARE..) 
    272          U_blk = MAX( SQRT(U_zu*U_zu + ztmp2) , 0.2_wp )              ! eq.3.17, Chap.3, p.32, IFS doc - Cy31r1 
     284         !! Update wind at zu with convection-related wind gustiness in unstable conditions (Chap. 3.2, IFS doc - Cy40r1, Eq.3.17 and Eq.3.18 + Eq.3.8) 
     285         ztmp2 = Beta0*Beta0*ztmp2*(MAX(-zi0*Linv/vkarmn,0._wp))**(2._wp/3._wp) ! square of wind gustiness contribution  (combining Eq. 3.8 and 3.18, hap.3, IFS doc - Cy31r1) 
     286         !!   ! Only true when unstable (L<0) => when ztmp0 < 0 => explains "-" before zi0 
     287         U_blk = MAX(SQRT(U_zu*U_zu + ztmp2), 0.2_wp)        ! include gustiness in bulk wind speed 
    273288         ! => 0.2 prevents U_blk to be 0 in stable case when U_zu=0. 
    274289 
     
    303318         func_h = log(zu) - LOG(z0t) - psi_h_ecmwf(ztmp0) + psi_h_ecmwf(z0t*Linv) 
    304319 
    305          !! SKIN related part 
    306          !! ----------------- 
    307          IF( l_use_skin ) THEN 
    308             !! compute transfer coefficients at zu : lolo: verifier... 
    309             Ch = vkarmn*vkarmn/(func_m*func_h) 
    310             ztmp1 = LOG(zu) - LOG(z0q) - psi_h_ecmwf(ztmp0) + psi_h_ecmwf(z0q*Linv)   ! func_q 
    311             Ce = vkarmn*vkarmn/(func_m*ztmp1) 
    312             ! Non-Solar heat flux to the ocean: 
    313             ztmp1 = U_blk*MAX(rho_air(t_zu, q_zu, slp), 1._wp)     ! rho*U10 
    314             ztmp2 = T_s*T_s 
    315             ztmp1 = ztmp1 * ( Ce*L_vap(T_s)*(q_zu - q_s) + Ch*cp_air(q_zu)*(t_zu - T_s) ) & ! Total turb. heat flux 
    316                &       +      emiss_w*(rad_lw - stefan*ztmp2*ztmp2)                         ! Net longwave flux 
    317             !!         => "ztmp1" is the net non-solar surface heat flux ! 
    318             !! Updating the values of the skin temperature T_s and q_s : 
    319             CALL CSWL_ECMWF( Qsw, ztmp1, u_star, zsst, T_s ) 
    320             q_s = rdct_qsat_salt*q_sat(MAX(T_s, 200._wp), slp)  ! 200 -> just to avoid numerics problem on masked regions if silly values are given 
    321          END IF 
    322  
    323          IF( (l_use_skin).OR.(.NOT. l_zt_equal_zu) ) THEN 
     320 
     321         IF( l_use_cs ) THEN 
     322            !! Cool-skin contribution 
     323 
     324            CALL UPDATE_QNSOL_TAU( T_s, q_s, t_zu, q_zu, u_star, t_star, q_star, U_blk, slp, rad_lw, & 
     325               &                   ztmp1, ztmp0,  Qlat=ztmp2)  ! Qnsol -> ztmp1 / Tau -> ztmp0 
     326 
     327            CALL CS_ECMWF( Qsw, ztmp1, u_star, zsst, pdTc )  ! Qnsol -> ztmp1 
     328 
     329            T_s(:,:) = zsst(:,:) + pdTc(:,:) 
     330            IF( l_use_wl ) T_s(:,:) = T_s(:,:) + pdTw(:,:) 
     331            q_s(:,:) = rdct_qsat_salt*q_sat(MAX(T_s(:,:), 200._wp), slp(:,:)) 
     332 
     333         END IF 
     334 
     335         IF( l_use_wl ) THEN 
     336            !! Warm-layer contribution 
     337            CALL UPDATE_QNSOL_TAU( T_s, q_s, t_zu, q_zu, u_star, t_star, q_star, U_blk, slp, rad_lw, & 
     338               &                   ztmp1, ztmp2)  ! Qnsol -> ztmp1 / Tau -> ztmp2 
     339            CALL WL_ECMWF( Qsw, ztmp1, u_star, zsst, pdTw ) 
     340            !! Updating T_s and q_s !!! 
     341            T_s(:,:) = zsst(:,:) + pdTw(:,:) 
     342            IF( l_use_cs ) T_s(:,:) = T_s(:,:) + pdTc(:,:) 
     343            q_s(:,:) = rdct_qsat_salt*q_sat(MAX(T_s(:,:), 200._wp), slp(:,:)) 
     344         END IF 
     345 
     346 
     347         IF( l_use_cs .OR. l_use_wl .OR. (.NOT. l_zt_equal_zu) ) THEN 
    324348            dt_zu = t_zu - T_s ;  dt_zu = SIGN( MAX(ABS(dt_zu),1.E-6_wp), dt_zu ) 
    325349            dq_zu = q_zu - q_s ;  dq_zu = SIGN( MAX(ABS(dq_zu),1.E-9_wp), dq_zu ) 
     
    337361      Cen = vkarmn*vkarmn / (log(zu/z0q)*log(zu/z0q)) 
    338362 
    339    END SUBROUTINE TURB_ECMWF 
     363      IF ( l_use_cs .AND. PRESENT(pdT_cs) ) pdT_cs = pdTc 
     364      IF ( l_use_wl .AND. PRESENT(pdT_wl) ) pdT_wl = pdTw 
     365 
     366      IF ( l_use_cs .OR. l_use_wl ) DEALLOCATE ( zsst ) 
     367      IF (          l_use_cs      ) DEALLOCATE ( pdTc ) 
     368      IF (          l_use_wl      ) DEALLOCATE ( pdTw ) 
     369 
     370   END SUBROUTINE turb_ecmwf 
    340371 
    341372 
     
    433464 
    434465 
    435  
    436  
    437  
    438466   !!====================================================================== 
    439467END MODULE sbcblk_algo_ecmwf 
Note: See TracChangeset for help on using the changeset viewer.