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 11111 for NEMO/branches/2019/dev_r11085_ASINTER-05_Brodeau_Advanced_Bulk/src/OCE/SBC/sbcblk_algo_coare.F90 – NEMO

Ignore:
Timestamp:
2019-06-14T15:55:28+02:00 (5 years ago)
Author:
laurent
Message:

LB: skin temperature now used by ECMWF bulk algorithm, and can be xios-ed ; new module "SBC/sbcblk_skin.F90" ; all physical constants defined in SBC now moved to "DOM/phycst.F90"; all air-properties and other ABL functions gathered in a new module: "SBC/sbcblk_phymbl.F90".

File:
1 edited

Legend:

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

    r10069 r11111  
    11MODULE sbcblk_algo_coare 
    22   !!====================================================================== 
    3    !!                       ***  MODULE  sbcblk_algo_coare  *** 
    4    !! Computes turbulent components of surface fluxes 
    5    !!         according to Fairall et al. 2003 (COARE v3) 
    6    !! 
     3   !!                   ***  MODULE  sbcblk_algo_coare  *** 
     4   !! Computes: 
    75   !!   * bulk transfer coefficients C_D, C_E and C_H 
    86   !!   * air temp. and spec. hum. adjusted from zt (2m) to zu (10m) if needed 
     
    108   !!   => all these are used in bulk formulas in sbcblk.F90 
    119   !! 
    12    !!    Using the bulk formulation/param. of COARE v3, Fairall et al. 2003 
    13    !! 
     10   !!    Using the bulk formulation/param. of COARE v3, Fairall et al., 2003 
    1411   !! 
    1512   !!       Routine turb_coare maintained and developed in AeroBulk 
    16    !!                     (http://aerobulk.sourceforge.net/) 
     13   !!                     (https://github.com/brodeau/aerobulk) 
    1714   !! 
    18    !!            Author: Laurent Brodeau, 2016, brodeau@gmail.com 
    19    !! 
    20    !!====================================================================== 
    21    !! History :  3.6  !  2016-02  (L.Brodeau)   Original code 
     15   !! ** Author: L. Brodeau, june 2016 / AeroBulk (https://github.com/brodeau/aerobulk) 
     16   !!---------------------------------------------------------------------- 
     17   !! History :  4.0  !  2016-02  (L.Brodeau)   Original code 
    2218   !!---------------------------------------------------------------------- 
    2319 
     
    2723   !!                   returns the effective bulk wind speed at 10m 
    2824   !!---------------------------------------------------------------------- 
    29    USE oce            ! ocean dynamics and tracers 
    30    USE dom_oce        ! ocean space and time domain 
    31    USE phycst         ! physical constants 
    32    USE sbc_oce        ! Surface boundary condition: ocean fields 
    33    USE sbcwave, ONLY  :  cdn_wave ! wave module 
     25   USE oce             ! ocean dynamics and tracers 
     26   USE dom_oce         ! ocean space and time domain 
     27   USE phycst          ! physical constants 
     28   USE sbc_oce         ! Surface boundary condition: ocean fields 
     29   USE sbcwave, ONLY   :  cdn_wave ! wave module 
    3430#if defined key_si3 || defined key_cice 
    35    USE sbc_ice        ! Surface boundary condition: ice fields 
     31   USE sbc_ice         ! Surface boundary condition: ice fields 
    3632#endif 
    37    ! 
     33   USE sbcblk_phymbl  !LB: all thermodynamics functions, rho_air, q_sat, etc... 
    3834   USE in_out_manager ! I/O manager 
    3935   USE iom            ! I/O manager library 
     
    5046   REAL(wp), PARAMETER ::   zi0     = 600._wp      ! scale height of the atmospheric boundary layer... 
    5147   REAL(wp), PARAMETER ::   Beta0   =   1.250_wp   ! gustiness parameter 
    52    REAL(wp), PARAMETER ::   rctv0   =   0.608_wp   ! constant to obtain virtual temperature... 
     48 
     49   INTEGER , PARAMETER ::   nb_itt = 5             ! number of itterations 
    5350 
    5451   !!---------------------------------------------------------------------- 
     
    6158      !!                      ***  ROUTINE  turb_coare  *** 
    6259      !! 
    63       !!            2015: L. Brodeau (brodeau@gmail.com) 
    64       !! 
    6560      !! ** Purpose :   Computes turbulent transfert coefficients of surface 
    6661      !!                fluxes according to Fairall et al. (2003) 
    6762      !!                If relevant (zt /= zu), adjust temperature and humidity from height zt to zu 
    68       !! 
    69       !! ** Method : Monin Obukhov Similarity Theory 
    70       !!---------------------------------------------------------------------- 
     63      !!                Returns the effective bulk wind speed at 10m to be used in the bulk formulas 
     64      !! 
    7165      !! 
    7266      !! INPUT : 
     
    8882      !!    *  t_zu   : pot. air temperature adjusted at wind height zu       [K] 
    8983      !!    *  q_zu   : specific humidity of air        //                    [kg/kg] 
    90       !!    *  U_blk  : bulk wind at 10m                                      [m/s] 
    91       !!---------------------------------------------------------------------- 
     84      !!    *  U_blk  : bulk wind speed at 10m                                [m/s] 
     85      !! 
     86      !! 
     87      !! ** Author: L. Brodeau, june 2016 / AeroBulk (https://github.com/brodeau/aerobulk) 
     88      !!---------------------------------------------------------------------------------- 
    9289      REAL(wp), INTENT(in   )                     ::   zt       ! height for t_zt and q_zt                    [m] 
    9390      REAL(wp), INTENT(in   )                     ::   zu       ! height for U_zu                             [m] 
     
    106103      ! 
    107104      INTEGER :: j_itt 
    108       LOGICAL ::   l_zt_equal_zu = .FALSE.      ! if q and t are given at same height as U 
    109       INTEGER , PARAMETER ::   nb_itt = 4       ! number of itterations 
     105      LOGICAL :: l_zt_equal_zu = .FALSE.      ! if q and t are given at same height as U 
    110106 
    111107      REAL(wp), DIMENSION(jpi,jpj) ::  & 
     
    125121 
    126122      !! First guess of temperature and humidity at height zu: 
    127       t_zu = MAX(t_zt , 0.0)    ! who knows what's given on masked-continental regions... 
    128       q_zu = MAX(q_zt , 1.e-6)  !               " 
     123      t_zu = MAX( t_zt , 199.0_wp )   ! who knows what's given on masked-continental regions... 
     124      q_zu = MAX( q_zt , 1.e-6_wp )   !               " 
    129125 
    130126      !! Pot. temp. difference (and we don't want it to be 0!) 
    131       dt_zu = t_zu - sst ;  dt_zu = SIGN( MAX(ABS(dt_zu),1.E-6), dt_zu ) 
    132       dq_zu = q_zu - ssq ;  dq_zu = SIGN( MAX(ABS(dq_zu),1.E-9), dq_zu ) 
    133  
    134       znu_a = visc_air(t_zt) ! Air viscosity (m^2/s) at zt given from temperature in (K) 
     127      dt_zu = t_zu - sst ;  dt_zu = SIGN( MAX(ABS(dt_zu),1.E-6_wp), dt_zu ) 
     128      dq_zu = q_zu - ssq ;  dq_zu = SIGN( MAX(ABS(dq_zu),1.E-9_wp), dq_zu ) 
     129 
     130      znu_a = visc_air(t_zu) ! Air viscosity (m^2/s) at zt given from temperature in (K) 
    135131 
    136132      ztmp2 = 0.5*0.5  ! initial guess for wind gustiness contribution 
     
    144140 
    145141      z0     = alfa_charn(U_blk)*u_star*u_star/grav + 0.11*znu_a/u_star 
    146       z0t    = 0.1*EXP(vkarmn/(0.00115/(vkarmn/ztmp1)))   !  WARNING: 1/z0t ! 
     142      z0     = MIN(ABS(z0), 0.001)  ! (prevent FPE from stupid values from masked region later on...) !#LOLO 
     143      z0t    = 1. / ( 0.1*EXP(vkarmn/(0.00115/(vkarmn/ztmp1))) ) 
     144      z0t    = MIN(ABS(z0t), 0.001)  ! (prevent FPE from stupid values from masked region later on...) !#LOLO 
    147145 
    148146      ztmp2  = vkarmn/ztmp0 
    149147      Cd     = ztmp2*ztmp2    ! first guess of Cd 
    150148 
    151       ztmp0 = vkarmn*vkarmn/LOG(zt*z0t)/Cd 
    152  
    153       !Ribcu = -zu/(zi0*0.004*Beta0**3) !! Saturation Rib, zi0 = tropicalbound. layer depth 
    154       ztmp2  = grav*zu*(dt_zu + rctv0*t_zu*dq_zu)/(t_zu*U_blk*U_blk)  !! Ribu Bulk Richardson number 
    155       ztmp1 = 0.5 + sign(0.5 , ztmp2) 
     149      ztmp0 = vkarmn*vkarmn/LOG(zt/z0t)/Cd 
     150 
     151      ztmp2  = grav*zu*(dt_zu + rctv0*t_zu*dq_zu)/(t_zu*U_blk*U_blk)  !! Ribu Bulk Richardson number ;       !Ribcu = -zu/(zi0*0.004*Beta0**3) !! Saturation Rib, zi0 = tropicalbound. layer depth 
     152 
     153      !! First estimate of zeta_u, depending on the stability, ie sign of Ribu (ztmp2): 
     154      ztmp1 = 0.5 + SIGN( 0.5_wp , ztmp2 ) 
    156155      ztmp0 = ztmp0*ztmp2 
    157       !!             Ribu < 0                                 Ribu > 0   Beta = 1.25 
    158       zeta_u = (1.-ztmp1) * (ztmp0/(1.+ztmp2/(-zu/(zi0*0.004*Beta0**3)))) & 
    159          &  +     ztmp1   * (ztmp0*(1. + 27./9.*ztmp2/ztmp0)) 
     156      zeta_u = (1.-ztmp1) * (ztmp0/(1.+ztmp2/(-zu/(zi0*0.004*Beta0**3)))) & !  Ribu < 0 
     157         &  +     ztmp1   * (ztmp0*(1. + 27./9.*ztmp2/ztmp0))               !  Ribu > 0 
     158      !#LOLO: should make sure that the "ztmp0" of "27./9.*ztmp2/ztmp0" is "ztmp0*ztmp2" and not "ztmp0==vkarmn*vkarmn/LOG(zt/z0t)/Cd" ! 
    160159 
    161160      !! First guess M-O stability dependent scaling params.(u*,t*,q*) to estimate z0 and z/L 
    162       ztmp0  =  vkarmn/(LOG(zu*z0t) - psi_h_coare(zeta_u)) 
     161      ztmp0  = vkarmn/(LOG(zu/z0t) - psi_h_coare(zeta_u)) 
    163162 
    164163      u_star = U_blk*vkarmn/(LOG(zu) - LOG(z0)  - psi_m_coare(zeta_u)) 
     
    168167      ! What's need to be done if zt /= zu: 
    169168      IF( .NOT. l_zt_equal_zu ) THEN 
    170  
     169         !! First update of values at zu (or zt for wind) 
    171170         zeta_t = zt*zeta_u/zu 
    172  
    173          !! First update of values at zu (or zt for wind) 
    174171         ztmp0 = psi_h_coare(zeta_u) - psi_h_coare(zeta_t) 
    175          ztmp1 = log(zt/zu) + ztmp0 
     172         ztmp1 = LOG(zt/zu) + ztmp0 
    176173         t_zu = t_zt - t_star/vkarmn*ztmp1 
    177174         q_zu = q_zt - q_star/vkarmn*ztmp1 
    178          q_zu = (0.5 + sign(0.5,q_zu))*q_zu !Makes it impossible to have negative humidity : 
    179  
    180          dt_zu = t_zu - sst  ; dt_zu = SIGN( MAX(ABS(dt_zu),1.E-6), dt_zu ) 
    181          dq_zu = q_zu - ssq  ; dq_zu = SIGN( MAX(ABS(dq_zu),1.E-9), dq_zu ) 
    182  
     175         q_zu = (0.5 + SIGN(0.5_wp,q_zu))*q_zu !Makes it impossible to have negative humidity : 
     176         ! 
     177         dt_zu = t_zu - sst  ; dt_zu = SIGN( MAX(ABS(dt_zu),1.E-6_wp), dt_zu ) 
     178         dq_zu = q_zu - ssq  ; dq_zu = SIGN( MAX(ABS(dq_zu),1.E-9_wp), dq_zu ) 
    183179      END IF 
    184180 
     
    188184         !!Inverse of Monin-Obukov length (1/L) : 
    189185         ztmp0 = One_on_L(t_zu, q_zu, u_star, t_star, q_star)  ! 1/L == 1/[Monin-Obukhov length] 
     186         ztmp0 = SIGN( MIN(ABS(ztmp0),200._wp), ztmp0 ) ! (prevents FPE from stupid values from masked region later on...) !#LOLO 
    190187 
    191188         ztmp1 = u_star*u_star   ! u*^2 
     
    193190         !! Update wind at 10m taking into acount convection-related wind gustiness: 
    194191         ! Ug = Beta*w*  (Beta = 1.25, Fairall et al. 2003, Eq.8): 
    195          ztmp2 = Beta0*Beta0*ztmp1*(MAX(-zi0*ztmp0/vkarmn,0.))**(2./3.)   ! => ztmp2 == Ug^2 
     192         ztmp2 = Beta0*Beta0*ztmp1*(MAX(-zi0*ztmp0/vkarmn,0._wp))**(2./3.)   ! => ztmp2 == Ug^2 
    196193         !!   ! Only true when unstable (L<0) => when ztmp0 < 0 => explains "-" before 600. 
    197          U_blk = MAX(sqrt(U_zu*U_zu + ztmp2), 0.2)        ! include gustiness in bulk wind speed 
     194         U_blk = MAX(sqrt(U_zu*U_zu + ztmp2), 0.2_wp)        ! include gustiness in bulk wind speed 
    198195         ! => 0.2 prevents U_blk to be 0 in stable case when U_zu=0. 
    199196 
     
    203200         !! Roughness lengthes z0, z0t (z0q = z0t) : 
    204201         z0   = ztmp2*ztmp1/grav + 0.11*znu_a/u_star ! Roughness length (eq.6) 
    205          ztmp1 = z0*u_star/znu_a                             ! Re_r: roughness Reynolds number 
    206          z0t  = min( 1.1E-4 , 5.5E-5*ztmp1**(-0.6) )        ! Scalar roughness for both theta and q (eq.28) 
     202         ztmp1 = z0*u_star/znu_a                           ! Re_r: roughness Reynolds number 
     203         z0t  = MIN( 1.1E-4_wp , 5.5E-5_wp*ztmp1**(-0.6_wp) ) ! Scalar roughness for both theta and q (eq.28) 
    207204 
    208205         !! Stability parameters: 
    209          zeta_u = zu*ztmp0 ; zeta_u = sign( min(abs(zeta_u),50.0), zeta_u ) 
     206         zeta_u = zu*ztmp0 
     207         zeta_u = SIGN( MIN(ABS(zeta_u),50.0_wp), zeta_u ) 
    210208         IF( .NOT. l_zt_equal_zu ) THEN 
    211             zeta_t = zt*ztmp0 ;  zeta_t = sign( min(abs(zeta_t),50.0), zeta_t ) 
     209            zeta_t = zt*ztmp0 
     210            zeta_t = SIGN( MIN(ABS(zeta_t),50.0_wp), zeta_t ) 
    212211         END IF 
    213212 
    214213         !! Turbulent scales at zu=10m : 
    215214         ztmp0   = psi_h_coare(zeta_u) 
    216          ztmp1   = vkarmn/(LOG(zu) -LOG(z0t) - ztmp0) 
     215         ztmp1   = vkarmn/(LOG(zu) - LOG(z0t) - ztmp0) 
    217216 
    218217         t_star = dt_zu*ztmp1 
    219218         q_star = dq_zu*ztmp1 
    220          u_star = U_blk*vkarmn/(LOG(zu) -LOG(z0) - psi_m_coare(zeta_u)) 
     219         u_star = U_blk*vkarmn/(LOG(zu) - LOG(z0) - psi_m_coare(zeta_u)) 
    221220 
    222221         IF( .NOT. l_zt_equal_zu ) THEN 
     
    259258      !! Wind greater than 18 m/s :  alfa = 0.018 
    260259      !! 
    261       !! Author: L. Brodeau, june 2016 / AeroBulk  (https://sourceforge.net/p/aerobulk) 
     260      !! Author: L. Brodeau, june 2016 / AeroBulk  (https://github.com/brodeau/aerobulk/) 
    262261      !!------------------------------------------------------------------- 
    263262      REAL(wp), DIMENSION(jpi,jpj) :: alfa_charn 
     
    274273            ! 
    275274            ! Charnock's constant, increases with the wind : 
    276             zgt10 = 0.5 + SIGN(0.5,(zw - 10.)) ! If zw<10. --> 0, else --> 1 
    277             zgt18 = 0.5 + SIGN(0.5,(zw - 18.)) ! If zw<18. --> 0, else --> 1 
     275            zgt10 = 0.5 + SIGN(0.5_wp,(zw - 10)) ! If zw<10. --> 0, else --> 1 
     276            zgt18 = 0.5 + SIGN(0.5_wp,(zw - 18.)) ! If zw<18. --> 0, else --> 1 
    278277            ! 
    279278            alfa_charn(ji,jj) =  (1. - zgt10)*0.011    &    ! wind is lower than 10 m/s 
     
    294293      !! 
    295294      !! Author: L. Brodeau, june 2016 / AeroBulk 
    296       !!         (https://sourceforge.net/p/aerobulk) 
     295      !!         (https://github.com/brodeau/aerobulk/) 
    297296      !!------------------------------------------------------------------------ 
    298297      REAL(wp), DIMENSION(jpi,jpj)             :: One_on_L         !: 1./(Monin Obukhov length) [m^-1] 
     
    330329      !!       form from Beljaars and Holtslag (1991) 
    331330      !! 
    332       !! ** Author: L. Brodeau, june 2016 / AeroBulk (https://sourceforge.net/p/aerobulk) 
     331      !! ** Author: L. Brodeau, june 2016 / AeroBulk (https://github.com/brodeau/aerobulk/) 
    333332      !!---------------------------------------------------------------------------------- 
    334333      REAL(wp), DIMENSION(jpi,jpj) :: psi_m_coare 
     
    356355            zf = zta*zta 
    357356            zf = zf/(1. + zf) 
    358             zc = MIN(50., 0.35*zta) 
    359             zstab = 0.5 + SIGN(0.5, zta) 
     357            zc = MIN(50._wp, 0.35_wp*zta) 
     358            zstab = 0.5 + SIGN(0.5_wp, zta) 
    360359            ! 
    361360            psi_m_coare(ji,jj) = (1. - zstab) * ( (1. - zf)*zpsi_k + zf*zpsi_c ) & ! (zta < 0) 
     
    383382      !! 
    384383      !! Author: L. Brodeau, june 2016 / AeroBulk 
    385       !!         (https://sourceforge.net/p/aerobulk) 
     384      !!         (https://github.com/brodeau/aerobulk/) 
    386385      !!---------------------------------------------------------------- 
    387386      !! 
     
    408407            zf = zta*zta 
    409408            zf = zf/(1. + zf) 
    410             zc = MIN(50.,0.35*zta) 
    411             zstab = 0.5 + SIGN(0.5, zta) 
     409            zc = MIN(50._wp,0.35_wp*zta) 
     410            zstab = 0.5 + SIGN(0.5_wp, zta) 
    412411            ! 
    413412            psi_h_coare(ji,jj) = (1. - zstab) * ( (1. - zf)*zpsi_k + zf*zpsi_c ) & 
     
    420419   END FUNCTION psi_h_coare 
    421420 
    422  
    423    FUNCTION visc_air( ptak ) 
    424       !!--------------------------------------------------------------------- 
    425       !! Air kinetic viscosity (m^2/s) given from temperature in degrees... 
    426       !! 
    427       !! Author: L. Brodeau, june 2016 / AeroBulk 
    428       !!         (https://sourceforge.net/p/aerobulk) 
    429       !!--------------------------------------------------------------------- 
    430       !! 
    431       REAL(wp), DIMENSION(jpi,jpj) :: visc_air 
    432       REAL(wp), DIMENSION(jpi,jpj), INTENT(in) :: ptak  ! air temperature in (K) 
    433       ! 
    434       INTEGER  ::   ji, jj         ! dummy loop indices 
    435       REAL(wp) ::   ztc, ztc2      ! local scalar 
    436       ! 
    437       DO jj = 1, jpj 
    438          DO ji = 1, jpi 
    439             ztc  = ptak(ji,jj) - rt0   ! air temp, in deg. C 
    440             ztc2 = ztc*ztc 
    441             visc_air(ji,jj) = 1.326E-5*(1. + 6.542E-3*ztc + 8.301E-6*ztc2 - 4.84E-9*ztc2*ztc) 
    442          END DO 
    443       END DO 
    444       ! 
    445    END FUNCTION visc_air 
    446  
    447  
     421   !!====================================================================== 
    448422END MODULE sbcblk_algo_coare 
Note: See TracChangeset for help on using the changeset viewer.