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.
sbcblk_algo_ecmwf.F90 in NEMO/trunk/src/OCE/SBC – NEMO

source: NEMO/trunk/src/OCE/SBC/sbcblk_algo_ecmwf.F90 @ 14072

Last change on this file since 14072 was 14072, checked in by laurent, 3 years ago

Merging branch "2020/dev_r13648_ASINTER-04_laurent_bulk_ice", ticket #2369

  • Property svn:keywords set to Id
File size: 24.7 KB
Line 
1MODULE sbcblk_algo_ecmwf
2   !!======================================================================
3   !!                   ***  MODULE  sbcblk_algo_ecmwf  ***
4   !! Computes:
5   !!   * bulk transfer coefficients C_D, C_E and C_H
6   !!   * air temp. and spec. hum. adjusted from zt (2m) to zu (10m) if needed
7   !!   * the effective bulk wind speed at 10m Ubzu
8   !!   => all these are used in bulk formulas in sbcblk.F90
9   !!
10   !!    Using the bulk formulation/param. of IFS of ECMWF (cycle 40r1)
11   !!         based on IFS doc (avaible online on the ECMWF's website)
12   !!
13   !!       Routine turb_ecmwf maintained and developed in AeroBulk
14   !!                     (https://github.com/brodeau/aerobulk)
15   !!
16   !! ** Author: L. Brodeau, June 2019 / AeroBulk (https://github.com/brodeau/aerobulk)
17   !!----------------------------------------------------------------------
18   !! History :  4.0  !  2016-02  (L.Brodeau)   Original code
19   !!            4.2  !  2020-12  (L. Brodeau) Introduction of various air-ice bulk parameterizations + improvements
20   !!----------------------------------------------------------------------
21
22   !!----------------------------------------------------------------------
23   !!   turb_ecmwf  : computes the bulk turbulent transfer coefficients
24   !!                   adjusts t_air and q_air from zt to zu m
25   !!                   returns the effective bulk wind speed at 10m
26   !!----------------------------------------------------------------------
27   USE dom_oce         ! ocean space and time domain
28   USE phycst          ! physical constants
29   USE lib_mpp,        ONLY: ctl_stop         ! distribued memory computing library
30   USE in_out_manager, ONLY: nit000  ! I/O manager
31   USE sbc_phy         ! Catalog of functions for physical/meteorological parameters in the marine boundary layer
32   USE sbcblk_skin_ecmwf ! cool-skin/warm layer scheme !LB
33
34   IMPLICIT NONE
35   PRIVATE
36
37   PUBLIC :: SBCBLK_ALGO_ECMWF_INIT, TURB_ECMWF
38
39   !! ECMWF own values for given constants, taken form IFS documentation...
40   REAL(wp), PARAMETER, PUBLIC :: charn0_ecmwf = 0.018_wp    ! Charnock constant (pretty high value here !!!
41   !                                          !    =>  Usually 0.011 for moderate winds)
42   REAL(wp), PARAMETER ::   zi0     = 1000.   ! scale height of the atmospheric boundary layer...1
43   REAL(wp), PARAMETER ::   Beta0    = 1.     ! gustiness parameter ( = 1.25 in COAREv3)
44   REAL(wp), PARAMETER ::   alpha_M = 0.11    ! For roughness length (smooth surface term)
45   REAL(wp), PARAMETER ::   alpha_H = 0.40    ! (Chapter 3, p.34, IFS doc Cy31r1)
46   REAL(wp), PARAMETER ::   alpha_Q = 0.62    !
47
48   !! * Substitutions
49#  include "do_loop_substitute.h90"
50
51   !!----------------------------------------------------------------------
52CONTAINS
53
54
55   SUBROUTINE sbcblk_algo_ecmwf_init(l_use_cs, l_use_wl)
56      !!---------------------------------------------------------------------
57      !!                  ***  FUNCTION sbcblk_algo_ecmwf_init  ***
58      !!
59      !! INPUT :
60      !! -------
61      !!    * l_use_cs : use the cool-skin parameterization
62      !!    * l_use_wl : use the warm-layer parameterization
63      !!---------------------------------------------------------------------
64      LOGICAL , INTENT(in) ::   l_use_cs ! use the cool-skin parameterization
65      LOGICAL , INTENT(in) ::   l_use_wl ! use the warm-layer parameterization
66      INTEGER :: ierr
67      !!---------------------------------------------------------------------
68      IF( l_use_wl ) THEN
69         ierr = 0
70         ALLOCATE ( dT_wl(jpi,jpj), Hz_wl(jpi,jpj), STAT=ierr )
71         IF( ierr > 0 ) CALL ctl_stop( ' SBCBLK_ALGO_ECMWF_INIT => allocation of dT_wl & Hz_wl failed!' )
72         dT_wl(:,:)  = 0._wp
73         Hz_wl(:,:)  = rd0 ! (rd0, constant, = 3m is default for Zeng & Beljaars)
74      ENDIF
75      IF( l_use_cs ) THEN
76         ierr = 0
77         ALLOCATE ( dT_cs(jpi,jpj), STAT=ierr )
78         IF( ierr > 0 ) CALL ctl_stop( ' SBCBLK_ALGO_ECMWF_INIT => allocation of dT_cs failed!' )
79         dT_cs(:,:) = -0.25_wp  ! First guess of skin correction
80      ENDIF
81   END SUBROUTINE sbcblk_algo_ecmwf_init
82
83
84
85   SUBROUTINE turb_ecmwf( kt, zt, zu, T_s, t_zt, q_s, q_zt, U_zu, l_use_cs, l_use_wl, &
86      &                      Cd, Ch, Ce, t_zu, q_zu, Ubzu,                            &
87      &                      nb_iter, Cdn, Chn, Cen,                                           & ! optional output
88      &                      Qsw, rad_lw, slp, pdT_cs,                                & ! optionals for cool-skin (and warm-layer)
89      &                      pdT_wl, pHz_wl )                                           ! optionals for warm-layer only
90      !!----------------------------------------------------------------------------------
91      !!                      ***  ROUTINE  turb_ecmwf  ***
92      !!
93      !! ** Purpose :   Computes turbulent transfert coefficients of surface
94      !!                fluxes according to IFS doc. (cycle 45r1)
95      !!                If relevant (zt /= zu), adjust temperature and humidity from height zt to zu
96      !!                Returns the effective bulk wind speed at zu to be used in the bulk formulas
97      !!
98      !!                Applies the cool-skin warm-layer correction of the SST to T_s
99      !!                if the net shortwave flux at the surface (Qsw), the downwelling longwave
100      !!                radiative fluxes at the surface (rad_lw), and the sea-leve pressure (slp)
101      !!                are provided as (optional) arguments!
102      !!
103      !! INPUT :
104      !! -------
105      !!    *  kt   : current time step (starts at 1)
106      !!    *  zt   : height for temperature and spec. hum. of air            [m]
107      !!    *  zu   : height for wind speed (usually 10m)                     [m]
108      !!    *  t_zt : potential air temperature at zt                         [K]
109      !!    *  q_zt : specific humidity of air at zt                          [kg/kg]
110      !!    *  U_zu : scalar wind speed at zu                                 [m/s]
111      !!    * l_use_cs : use the cool-skin parameterization
112      !!    * l_use_wl : use the warm-layer parameterization
113      !!
114      !! INPUT/OUTPUT:
115      !! -------------
116      !!    *  T_s  : always "bulk SST" as input                              [K]
117      !!              -> unchanged "bulk SST" as output if CSWL not used      [K]
118      !!              -> skin temperature as output if CSWL used              [K]
119      !!
120      !!    *  q_s  : SSQ aka saturation specific humidity at temp. T_s       [kg/kg]
121      !!              -> doesn't need to be given a value if skin temp computed (in case l_use_cs=True or l_use_wl=True)
122      !!              -> MUST be given the correct value if not computing skint temp. (in case l_use_cs=False or l_use_wl=False)
123      !!
124      !! OPTIONAL INPUT:
125      !! ---------------
126      !!    *  Qsw    : net solar flux (after albedo) at the surface (>0)     [W/m^2]
127      !!    *  rad_lw : downwelling longwave radiation at the surface  (>0)   [W/m^2]
128      !!    *  slp    : sea-level pressure                                    [Pa]
129      !!
130      !! OPTIONAL OUTPUT:
131      !! ----------------
132      !!    * pdT_cs  : SST increment "dT" for cool-skin correction           [K]
133      !!    * pdT_wl  : SST increment "dT" for warm-layer correction          [K]
134      !!    * pHz_wl  : thickness of warm-layer                               [m]
135      !!
136      !! OUTPUT :
137      !! --------
138      !!    *  Cd     : drag coefficient
139      !!    *  Ch     : sensible heat coefficient
140      !!    *  Ce     : evaporation coefficient
141      !!    *  t_zu   : pot. air temperature adjusted at wind height zu       [K]
142      !!    *  q_zu   : specific humidity of air        //                    [kg/kg]
143      !!    *  Ubzu   : bulk wind speed at zu                                 [m/s]
144      !!
145      !!
146      !! ** Author: L. Brodeau, June 2019 / AeroBulk (https://github.com/brodeau/aerobulk/)
147      !!----------------------------------------------------------------------------------
148      INTEGER,  INTENT(in   )                     ::   kt       ! current time step
149      REAL(wp), INTENT(in   )                     ::   zt       ! height for t_zt and q_zt                    [m]
150      REAL(wp), INTENT(in   )                     ::   zu       ! height for U_zu                             [m]
151      REAL(wp), INTENT(inout), DIMENSION(jpi,jpj) ::   T_s      ! sea surface temperature                [Kelvin]
152      REAL(wp), INTENT(in   ), DIMENSION(jpi,jpj) ::   t_zt     ! potential air temperature              [Kelvin]
153      REAL(wp), INTENT(inout), DIMENSION(jpi,jpj) ::   q_s      ! sea surface specific humidity           [kg/kg]
154      REAL(wp), INTENT(in   ), DIMENSION(jpi,jpj) ::   q_zt     ! specific air humidity at zt             [kg/kg]
155      REAL(wp), INTENT(in   ), DIMENSION(jpi,jpj) ::   U_zu     ! relative wind module at zu                [m/s]
156      LOGICAL , INTENT(in   )                     ::   l_use_cs ! use the cool-skin parameterization
157      LOGICAL , INTENT(in   )                     ::   l_use_wl ! use the warm-layer parameterization
158      REAL(wp), INTENT(  out), DIMENSION(jpi,jpj) ::   Cd       ! transfer coefficient for momentum         (tau)
159      REAL(wp), INTENT(  out), DIMENSION(jpi,jpj) ::   Ch       ! transfer coefficient for sensible heat (Q_sens)
160      REAL(wp), INTENT(  out), DIMENSION(jpi,jpj) ::   Ce       ! transfert coefficient for evaporation   (Q_lat)
161      REAL(wp), INTENT(  out), DIMENSION(jpi,jpj) ::   t_zu     ! pot. air temp. adjusted at zu               [K]
162      REAL(wp), INTENT(  out), DIMENSION(jpi,jpj) ::   q_zu     ! spec. humidity adjusted at zu           [kg/kg]
163      REAL(wp), INTENT(  out), DIMENSION(jpi,jpj) ::   Ubzu    ! bulk wind speed at zu                     [m/s]
164      !
165      INTEGER , INTENT(in   ), OPTIONAL                     :: nb_iter  ! number of iterations
166      REAL(wp), INTENT(  out), OPTIONAL, DIMENSION(jpi,jpj) ::   CdN
167      REAL(wp), INTENT(  out), OPTIONAL, DIMENSION(jpi,jpj) ::   ChN
168      REAL(wp), INTENT(  out), OPTIONAL, DIMENSION(jpi,jpj) ::   CeN
169      REAL(wp), INTENT(in   ), OPTIONAL, DIMENSION(jpi,jpj) ::   Qsw      !             [W/m^2]
170      REAL(wp), INTENT(in   ), OPTIONAL, DIMENSION(jpi,jpj) ::   rad_lw   !             [W/m^2]
171      REAL(wp), INTENT(in   ), OPTIONAL, DIMENSION(jpi,jpj) ::   slp      !             [Pa]
172      REAL(wp), INTENT(  out), OPTIONAL, DIMENSION(jpi,jpj) ::   pdT_cs
173      REAL(wp), INTENT(  out), OPTIONAL, DIMENSION(jpi,jpj) ::   pdT_wl   !             [K]
174      REAL(wp), INTENT(  out), OPTIONAL, DIMENSION(jpi,jpj) ::   pHz_wl   !             [m]
175      !
176      INTEGER :: nbit, jit
177      LOGICAL :: l_zt_equal_zu = .FALSE.      ! if q and t are given at same height as U
178      !
179      REAL(wp), DIMENSION(jpi,jpj) :: u_star, t_star, q_star
180      REAL(wp), DIMENSION(jpi,jpj) :: dt_zu, dq_zu
181      REAL(wp), DIMENSION(jpi,jpj) :: znu_a         !: Nu_air, Viscosity of air
182      REAL(wp), DIMENSION(jpi,jpj) :: Linv  !: 1/L (inverse of Monin Obukhov length...
183      REAL(wp), DIMENSION(jpi,jpj) :: z0, z0t, z0q
184      !
185      REAL(wp), DIMENSION(:,:), ALLOCATABLE :: zsst  ! to back up the initial bulk SST
186      !
187      REAL(wp), DIMENSION(jpi,jpj) :: func_m, func_h
188      REAL(wp), DIMENSION(jpi,jpj) :: ztmp0, ztmp1, ztmp2
189      CHARACTER(len=40), PARAMETER :: crtnm = 'turb_ecmwf@sbcblk_algo_ecmwf.F90'
190      !!----------------------------------------------------------------------------------
191      IF( kt == nit000 ) CALL SBCBLK_ALGO_ECMWF_INIT(l_use_cs, l_use_wl)
192
193      nbit = nb_iter0
194      IF( PRESENT(nb_iter) ) nbit = nb_iter
195
196      l_zt_equal_zu = ( ABS(zu - zt) < 0.01_wp ) ! testing "zu == zt" is risky with double precision
197
198      !! Initializations for cool skin and warm layer:
199      IF( l_use_cs .AND. (.NOT.(PRESENT(Qsw) .AND. PRESENT(rad_lw) .AND. PRESENT(slp))) ) &
200         &   CALL ctl_stop( '['//TRIM(crtnm)//'] => ' , 'you need to provide Qsw, rad_lw & slp to use cool-skin param!' )
201
202      IF( l_use_wl .AND. (.NOT.(PRESENT(Qsw) .AND. PRESENT(rad_lw) .AND. PRESENT(slp))) ) &
203         &   CALL ctl_stop( '['//TRIM(crtnm)//'] => ' , 'you need to provide Qsw, rad_lw & slp to use warm-layer param!' )
204
205      IF( l_use_cs .OR. l_use_wl ) THEN
206         ALLOCATE ( zsst(jpi,jpj) )
207         zsst = T_s ! backing up the bulk SST
208         IF( l_use_cs ) T_s = T_s - 0.25_wp   ! First guess of correction
209         q_s    = rdct_qsat_salt*q_sat(MAX(T_s, 200._wp), slp) ! First guess of q_s
210      ENDIF
211
212
213      ! Identical first gess as in COARE, with IFS parameter values though...
214      !
215      !! First guess of temperature and humidity at height zu:
216      t_zu = MAX( t_zt ,  180._wp )   ! who knows what's given on masked-continental regions...
217      q_zu = MAX( q_zt , 1.e-6_wp )   !               "
218
219      !! Pot. temp. difference (and we don't want it to be 0!)
220      dt_zu = t_zu - T_s ;   dt_zu = SIGN( MAX(ABS(dt_zu),1.E-6_wp), dt_zu )
221      dq_zu = q_zu - q_s ;   dq_zu = SIGN( MAX(ABS(dq_zu),1.E-9_wp), dq_zu )
222
223      znu_a = visc_air(t_zu) ! Air viscosity (m^2/s) at zt given from temperature in (K)
224
225      Ubzu = SQRT(U_zu*U_zu + 0.5_wp*0.5_wp) ! initial guess for wind gustiness contribution
226
227      ztmp0   = LOG(    zu*10000._wp) ! optimization: 10000. == 1/z0 (with z0 first guess == 0.0001)
228      ztmp1   = LOG(10._wp*10000._wp) !       "                    "               "
229      u_star = 0.035_wp*Ubzu*ztmp1/ztmp0       ! (u* = 0.035*Un10)
230
231      z0     = charn0_ecmwf*u_star*u_star/grav + 0.11_wp*znu_a/u_star
232      z0     = MIN( MAX(ABS(z0), 1.E-9) , 1._wp )                      ! (prevents FPE from stupid values from masked region later on)
233
234      z0t    = 1._wp / ( 0.1_wp*EXP(vkarmn/(0.00115/(vkarmn/ztmp1))) )
235      z0t    = MIN( MAX(ABS(z0t), 1.E-9) , 1._wp )                      ! (prevents FPE from stupid values from masked region later on)
236
237      Cd     = MAX( (vkarmn/ztmp0)**2 , Cx_min )   ! first guess of Cd
238
239      ztmp0 = vkarmn2/LOG(zt/z0t)/Cd
240
241      ztmp2 = Ri_bulk( zu, T_s, t_zu, q_s, q_zu, Ubzu ) ! Bulk Richardson Number (BRN)
242
243      !! First estimate of zeta_u, depending on the stability, ie sign of BRN (ztmp2):
244      ztmp1 = 0.5 + SIGN( 0.5_wp , ztmp2 )
245      func_h = (1._wp - ztmp1) *   ztmp0*ztmp2 / (1._wp - ztmp2*zi0*0.004_wp*Beta0**3/zu) & !  BRN < 0
246         &  +       ztmp1      * ( ztmp0*ztmp2 + 27._wp/9._wp*ztmp2*ztmp2 )                 !  BRN > 0
247
248      !! First guess M-O stability dependent scaling params.(u*,t*,q*) to estimate z0 and z/L
249      ztmp0  = vkarmn/(LOG(zu/z0t) - psi_h_ecmwf(func_h))
250
251      u_star = MAX ( Ubzu*vkarmn/(LOG(zu) - LOG(z0)  - psi_m_ecmwf(func_h)) , 1.E-9 )  !  (MAX => prevents FPE from stupid values from masked region later on)
252      t_star = dt_zu*ztmp0
253      q_star = dq_zu*ztmp0
254
255      ! What needs to be done if zt /= zu:
256      IF( .NOT. l_zt_equal_zu ) THEN
257         !! First update of values at zu (or zt for wind)
258         ztmp0 = psi_h_ecmwf(func_h) - psi_h_ecmwf(zt*func_h/zu)    ! zt*func_h/zu == zeta_t
259         ztmp1 = LOG(zt/zu) + ztmp0
260         t_zu = t_zt - t_star/vkarmn*ztmp1
261         q_zu = q_zt - q_star/vkarmn*ztmp1
262         q_zu = (0.5_wp + SIGN(0.5_wp,q_zu))*q_zu !Makes it impossible to have negative humidity :
263         !
264         dt_zu = t_zu - T_s  ; dt_zu = SIGN( MAX(ABS(dt_zu),1.E-6_wp), dt_zu )
265         dq_zu = q_zu - q_s  ; dq_zu = SIGN( MAX(ABS(dq_zu),1.E-9_wp), dq_zu )
266      ENDIF
267
268
269      !! => that was same first guess as in COARE...
270
271
272      !! First guess of inverse of Obukov length (1/L) :
273      Linv = One_on_L( t_zu, q_zu, u_star, t_star, q_star )
274
275      !! Functions such as  u* = Ubzu*vkarmn/func_m
276      ztmp0 = zu*Linv
277      func_m = LOG(zu) - LOG(z0)  - psi_m_ecmwf(ztmp0) + psi_m_ecmwf( z0*Linv)
278      func_h = LOG(zu) - LOG(z0t) - psi_h_ecmwf(ztmp0) + psi_h_ecmwf(z0t*Linv)
279
280      !! ITERATION BLOCK
281      DO jit = 1, nbit
282
283         !! Bulk Richardson Number at z=zu (Eq. 3.25)
284         ztmp0 = Ri_bulk( zu, T_s, t_zu, q_s, q_zu, Ubzu ) ! Bulk Richardson Number (BRN)
285
286         !! New estimate of the inverse of the Obukhon length (Linv == zeta/zu) :
287         Linv = ztmp0*func_m*func_m/func_h / zu     ! From Eq. 3.23, Chap.3.2.3, IFS doc - Cy40r1
288         !! Note: it is slightly different that the L we would get with the usual
289         Linv = SIGN( MIN(ABS(Linv),200._wp), Linv ) ! (prevent FPE from stupid values from masked region later on...)
290
291         !! Update func_m with new Linv:
292         func_m = LOG(zu) -LOG(z0) - psi_m_ecmwf(zu*Linv) + psi_m_ecmwf(z0*Linv) ! LB: should be "zu+z0" rather than "zu" alone, but z0 is tiny wrt zu!
293
294         !! Need to update roughness lengthes:
295         u_star = Ubzu*vkarmn/func_m
296         ztmp2  = u_star*u_star
297         ztmp1  = znu_a/u_star
298         z0     = MIN( ABS( alpha_M*ztmp1 + charn0_ecmwf*ztmp2/grav ) , 0.001_wp)
299         z0t    = MIN( ABS( alpha_H*ztmp1                           ) , 0.001_wp)   ! eq.3.26, Chap.3, p.34, IFS doc - Cy31r1
300         z0q    = MIN( ABS( alpha_Q*ztmp1                           ) , 0.001_wp)
301
302         !! 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)
303         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)
304         !!   ! Only true when unstable (L<0) => when ztmp0 < 0 => explains "-" before zi0
305         Ubzu = MAX(SQRT(U_zu*U_zu + ztmp2), 0.2_wp)        ! include gustiness in bulk wind speed
306         ! => 0.2 prevents Ubzu to be 0 in stable case when U_zu=0.
307
308
309         !! Need to update "theta" and "q" at zu in case they are given at different heights
310         !! as well the air-sea differences:
311         IF( .NOT. l_zt_equal_zu ) THEN
312            !! Arrays func_m and func_h are free for a while so using them as temporary arrays...
313            func_h = psi_h_ecmwf(zu*Linv) ! temporary array !!!
314            func_m = psi_h_ecmwf(zt*Linv) ! temporary array !!!
315
316            ztmp2  = psi_h_ecmwf(z0t*Linv)
317            ztmp0  = func_h - ztmp2
318            ztmp1  = vkarmn/(LOG(zu) - LOG(z0t) - ztmp0)
319            t_star = dt_zu*ztmp1
320            ztmp2  = ztmp0 - func_m + ztmp2
321            ztmp1  = LOG(zt/zu) + ztmp2
322            t_zu   = t_zt - t_star/vkarmn*ztmp1
323
324            ztmp2  = psi_h_ecmwf(z0q*Linv)
325            ztmp0  = func_h - ztmp2
326            ztmp1  = vkarmn/(LOG(zu) - LOG(z0q) - ztmp0)
327            q_star = dq_zu*ztmp1
328            ztmp2  = ztmp0 - func_m + ztmp2
329            ztmp1  = LOG(zt/zu) + ztmp2
330            q_zu   = q_zt - q_star/vkarmn*ztmp1
331         ENDIF
332
333         !! Updating because of updated z0 and z0t and new Linv...
334         ztmp0 = zu*Linv
335         func_m = log(zu) - LOG(z0 ) - psi_m_ecmwf(ztmp0) + psi_m_ecmwf(z0 *Linv)
336         func_h = log(zu) - LOG(z0t) - psi_h_ecmwf(ztmp0) + psi_h_ecmwf(z0t*Linv)
337
338
339         IF( l_use_cs ) THEN
340            !! Cool-skin contribution
341
342            CALL UPDATE_QNSOL_TAU( zu, T_s, q_s, t_zu, q_zu, u_star, t_star, q_star, U_zu, Ubzu, slp, rad_lw, &
343               &                   ztmp1, ztmp0,  Qlat=ztmp2)  ! Qnsol -> ztmp1 / Tau -> ztmp0
344
345            CALL CS_ECMWF( Qsw, ztmp1, u_star, zsst )  ! Qnsol -> ztmp1
346
347            T_s(:,:) = zsst(:,:) + dT_cs(:,:)*tmask(:,:,1)
348            IF( l_use_wl ) T_s(:,:) = T_s(:,:) + dT_wl(:,:)*tmask(:,:,1)
349            q_s(:,:) = rdct_qsat_salt*q_sat(MAX(T_s(:,:), 200._wp), slp(:,:))
350
351         ENDIF
352
353         IF( l_use_wl ) THEN
354            !! Warm-layer contribution
355            CALL UPDATE_QNSOL_TAU( zu, T_s, q_s, t_zu, q_zu, u_star, t_star, q_star, U_zu, Ubzu, slp, rad_lw, &
356               &                   ztmp1, ztmp2)  ! Qnsol -> ztmp1 / Tau -> ztmp2
357            CALL WL_ECMWF( Qsw, ztmp1, u_star, zsst )
358            !! Updating T_s and q_s !!!
359            T_s(:,:) = zsst(:,:) + dT_wl(:,:)*tmask(:,:,1) !
360            IF( l_use_cs ) T_s(:,:) = T_s(:,:) + dT_cs(:,:)*tmask(:,:,1)
361            q_s(:,:) = rdct_qsat_salt*q_sat(MAX(T_s(:,:), 200._wp), slp(:,:))
362         ENDIF
363
364         IF( l_use_cs .OR. l_use_wl .OR. (.NOT. l_zt_equal_zu) ) THEN
365            dt_zu = t_zu - T_s ;  dt_zu = SIGN( MAX(ABS(dt_zu),1.E-6_wp), dt_zu )
366            dq_zu = q_zu - q_s ;  dq_zu = SIGN( MAX(ABS(dq_zu),1.E-9_wp), dq_zu )
367         ENDIF
368
369      END DO !DO jit = 1, nbit
370
371      Cd = MAX( vkarmn2/(func_m*func_m) , Cx_min )
372      Ch = MAX( vkarmn2/(func_m*func_h) , Cx_min )
373      ztmp2 = LOG(zu/z0q) - psi_h_ecmwf(zu*Linv) + psi_h_ecmwf(z0q*Linv)   ! func_q
374      Ce = MAX( vkarmn2/(func_m*ztmp2)  , Cx_min )
375
376      IF(PRESENT(Cdn)) Cdn = MAX( vkarmn2 / (LOG(zu/z0 )*LOG(zu/z0 )) , Cx_min )
377      IF(PRESENT(Chn)) Chn = MAX( vkarmn2 / (LOG(zu/z0t)*LOG(zu/z0t)) , Cx_min )
378      IF(PRESENT(Cen)) Cen = MAX( vkarmn2 / (LOG(zu/z0q)*LOG(zu/z0q)) , Cx_min )
379
380      IF( l_use_cs .AND. PRESENT(pdT_cs) ) pdT_cs = dT_cs
381      IF( l_use_wl .AND. PRESENT(pdT_wl) ) pdT_wl = dT_wl
382      IF( l_use_wl .AND. PRESENT(pHz_wl) ) pHz_wl = Hz_wl
383
384      IF( l_use_cs .OR. l_use_wl ) DEALLOCATE ( zsst )
385
386   END SUBROUTINE turb_ecmwf
387
388
389   FUNCTION psi_m_ecmwf( pzeta )
390      !!----------------------------------------------------------------------------------
391      !! Universal profile stability function for momentum
392      !!     ECMWF / as in IFS cy31r1 documentation, available online
393      !!     at ecmwf.int
394      !!
395      !! pzeta : stability paramenter, z/L where z is altitude measurement
396      !!         and L is M-O length
397      !!
398      !! ** Author: L. Brodeau, June 2016 / AeroBulk (https://github.com/brodeau/aerobulk/)
399      !!----------------------------------------------------------------------------------
400      REAL(wp), DIMENSION(jpi,jpj) :: psi_m_ecmwf
401      REAL(wp), DIMENSION(jpi,jpj), INTENT(in) :: pzeta
402      !
403      INTEGER  ::   ji, jj    ! dummy loop indices
404      REAL(wp) :: zta, zx2, zx, ztmp, zpsi_unst, zpsi_stab, zstab, zc
405      !!----------------------------------------------------------------------------------
406      zc = 5._wp/0.35_wp
407      DO_2D( nn_hls, nn_hls, nn_hls, nn_hls )
408            !
409            zta = MIN( pzeta(ji,jj) , 5._wp ) !! Very stable conditions (L positif and big!):
410
411            ! *** Unstable (Paulson 1970)    [eq.3.20, Chap.3, p.33, IFS doc - Cy31r1] :
412            zx2 = SQRT( ABS(1._wp - 16._wp*zta) )  ! (1 - 16z)^0.5
413            zx  = SQRT(zx2)                          ! (1 - 16z)^0.25
414            ztmp = 1._wp + zx
415            zpsi_unst = LOG( 0.125_wp*ztmp*ztmp*(1._wp + zx2) ) - 2._wp*ATAN( zx ) + 0.5_wp*rpi
416
417            ! *** Stable                   [eq.3.22, Chap.3, p.33, IFS doc - Cy31r1] :
418            zpsi_stab = -2._wp/3._wp*(zta - zc)*EXP(-0.35_wp*zta) &
419               &       - zta - 2._wp/3._wp*zc
420            !
421            zstab = 0.5_wp + SIGN(0.5_wp, zta) ! zta > 0 => zstab = 1
422            !
423            psi_m_ecmwf(ji,jj) =         zstab  * zpsi_stab &  ! (zta > 0) Stable
424               &              + (1._wp - zstab) * zpsi_unst    ! (zta < 0) Unstable
425            !
426      END_2D
427   END FUNCTION psi_m_ecmwf
428
429
430   FUNCTION psi_h_ecmwf( pzeta )
431      !!----------------------------------------------------------------------------------
432      !! Universal profile stability function for temperature and humidity
433      !!     ECMWF / as in IFS cy31r1 documentation, available online
434      !!     at ecmwf.int
435      !!
436      !! pzeta : stability paramenter, z/L where z is altitude measurement
437      !!         and L is M-O length
438      !!
439      !! ** Author: L. Brodeau, June 2016 / AeroBulk (https://github.com/brodeau/aerobulk/)
440      !!----------------------------------------------------------------------------------
441      REAL(wp), DIMENSION(jpi,jpj) :: psi_h_ecmwf
442      REAL(wp), DIMENSION(jpi,jpj), INTENT(in) :: pzeta
443      !
444      INTEGER  ::   ji, jj     ! dummy loop indices
445      REAL(wp) ::  zta, zx2, zpsi_unst, zpsi_stab, zstab, zc
446      !!----------------------------------------------------------------------------------
447      zc = 5._wp/0.35_wp
448      !
449      DO_2D( nn_hls, nn_hls, nn_hls, nn_hls )
450            !
451            zta = MIN(pzeta(ji,jj) , 5._wp)   ! Very stable conditions (L positif and big!):
452            !
453            ! *** Unstable (Paulson 1970)   [eq.3.20, Chap.3, p.33, IFS doc - Cy31r1] :
454            zx2 = SQRT( ABS(1._wp - 16._wp*zta) )  ! (1 -16z)^0.5
455            zpsi_unst = 2._wp*LOG( 0.5_wp*(1._wp + zx2) )
456            !
457            ! *** Stable [eq.3.22, Chap.3, p.33, IFS doc - Cy31r1] :
458            zpsi_stab = -2._wp/3._wp*(zta - zc)*EXP(-0.35_wp*zta) &
459               &       - ABS(1._wp + 2._wp/3._wp*zta)**1.5_wp - 2._wp/3._wp*zc + 1._wp
460            !
461            ! LB: added ABS() to avoid NaN values when unstable, which contaminates the unstable solution...
462            !
463            zstab = 0.5_wp + SIGN(0.5_wp, zta) ! zta > 0 => zstab = 1
464            !
465            psi_h_ecmwf(ji,jj) =         zstab  * zpsi_stab &  ! (zta > 0) Stable
466               &              + (1._wp - zstab) * zpsi_unst    ! (zta < 0) Unstable
467            !
468      END_2D
469   END FUNCTION psi_h_ecmwf
470
471
472   !!======================================================================
473END MODULE sbcblk_algo_ecmwf
Note: See TracBrowser for help on using the repository browser.