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.F90 in NEMO/branches/2020/dev_r13296_HPC-07_mocavero_mpi3/src/OCE/SBC – NEMO

source: NEMO/branches/2020/dev_r13296_HPC-07_mocavero_mpi3/src/OCE/SBC/sbcblk.F90 @ 13630

Last change on this file since 13630 was 13630, checked in by mocavero, 4 years ago

Add neighborhood collectives calls in the NEMO src - ticket #2496

  • Property svn:keywords set to Id
File size: 85.3 KB
Line 
1MODULE sbcblk
2   !!======================================================================
3   !!                       ***  MODULE  sbcblk  ***
4   !! Ocean forcing:  momentum, heat and freshwater flux formulation
5   !!                         Aerodynamic Bulk Formulas
6   !!                        SUCCESSOR OF "sbcblk_core"
7   !!=====================================================================
8   !! History :  1.0  !  2004-08  (U. Schweckendiek)  Original CORE code
9   !!            2.0  !  2005-04  (L. Brodeau, A.M. Treguier)  improved CORE bulk and its user interface
10   !!            3.0  !  2006-06  (G. Madec)  sbc rewritting
11   !!             -   !  2006-12  (L. Brodeau)  Original code for turb_core
12   !!            3.2  !  2009-04  (B. Lemaire)  Introduce iom_put
13   !!            3.3  !  2010-10  (S. Masson)  add diurnal cycle
14   !!            3.4  !  2011-11  (C. Harris)  Fill arrays required by CICE
15   !!            3.7  !  2014-06  (L. Brodeau)  simplification and optimization of CORE bulk
16   !!            4.0  !  2016-06  (L. Brodeau)  sbcblk_core becomes sbcblk and is not restricted to the CORE algorithm anymore
17   !!                 !                        ==> based on AeroBulk (https://github.com/brodeau/aerobulk/)
18   !!            4.0  !  2016-10  (G. Madec)  introduce a sbc_blk_init routine
19   !!            4.0  !  2016-10  (M. Vancoppenolle)  Introduce conduction flux emulator (M. Vancoppenolle)
20   !!            4.0  !  2019-03  (F. Lemarié & G. Samson)  add ABL compatibility (ln_abl=TRUE)
21   !!----------------------------------------------------------------------
22
23   !!----------------------------------------------------------------------
24   !!   sbc_blk_init  : initialisation of the chosen bulk formulation as ocean surface boundary condition
25   !!   sbc_blk       : bulk formulation as ocean surface boundary condition
26   !!   blk_oce_1     : computes pieces of momentum, heat and freshwater fluxes over ocean for ABL model  (ln_abl=TRUE)
27   !!   blk_oce_2     : finalizes momentum, heat and freshwater fluxes computation over ocean after the ABL step  (ln_abl=TRUE)
28   !!             sea-ice case only :
29   !!   blk_ice_1   : provide the air-ice stress
30   !!   blk_ice_2   : provide the heat and mass fluxes at air-ice interface
31   !!   blk_ice_qcn   : provide ice surface temperature and snow/ice conduction flux (emulating conduction flux)
32   !!   Cdn10_Lupkes2012 : Lupkes et al. (2012) air-ice drag
33   !!   Cdn10_Lupkes2015 : Lupkes et al. (2015) air-ice drag
34   !!----------------------------------------------------------------------
35   USE oce            ! ocean dynamics and tracers
36   USE dom_oce        ! ocean space and time domain
37   USE phycst         ! physical constants
38   USE fldread        ! read input fields
39   USE sbc_oce        ! Surface boundary condition: ocean fields
40   USE cyclone        ! Cyclone 10m wind form trac of cyclone centres
41   USE sbcdcy         ! surface boundary condition: diurnal cycle
42   USE sbcwave , ONLY :   cdn_wave ! wave module
43   USE sbc_ice        ! Surface boundary condition: ice fields
44   USE lib_fortran    ! to use key_nosignedzero
45#if defined key_si3
46   USE ice     , ONLY :   u_ice, v_ice, jpl, a_i_b, at_i_b, t_su, rn_cnd_s, hfx_err_dif, nn_qtrice
47   USE icevar         ! for CALL ice_var_snwblow
48#endif
49   USE sbcblk_algo_ncar     ! => turb_ncar     : NCAR - CORE (Large & Yeager, 2009)
50   USE sbcblk_algo_coare3p0 ! => turb_coare3p0 : COAREv3.0 (Fairall et al. 2003)
51   USE sbcblk_algo_coare3p6 ! => turb_coare3p6 : COAREv3.6 (Fairall et al. 2018 + Edson et al. 2013)
52   USE sbcblk_algo_ecmwf    ! => turb_ecmwf    : ECMWF (IFS cycle 45r1)
53   !
54   USE iom            ! I/O manager library
55   USE in_out_manager ! I/O manager
56   USE lib_mpp        ! distribued memory computing library
57   USE lbclnk         ! ocean lateral boundary conditions (or mpp link)
58   USE prtctl         ! Print control
59
60   USE sbcblk_phy     ! a catalog of functions for physical/meteorological parameters in the marine boundary layer, rho_air, q_sat, etc...
61
62
63   IMPLICIT NONE
64   PRIVATE
65
66   PUBLIC   sbc_blk_init  ! called in sbcmod
67   PUBLIC   sbc_blk       ! called in sbcmod
68   PUBLIC   blk_oce_1     ! called in sbcabl
69   PUBLIC   blk_oce_2     ! called in sbcabl
70#if defined key_si3
71   PUBLIC   blk_ice_1     ! routine called in icesbc
72   PUBLIC   blk_ice_2     ! routine called in icesbc
73   PUBLIC   blk_ice_qcn   ! routine called in icesbc
74#endif
75
76   INTEGER , PUBLIC, PARAMETER ::   jp_wndi  =  1   ! index of 10m wind velocity (i-component) (m/s)    at T-point
77   INTEGER , PUBLIC, PARAMETER ::   jp_wndj  =  2   ! index of 10m wind velocity (j-component) (m/s)    at T-point
78   INTEGER , PUBLIC, PARAMETER ::   jp_tair  =  3   ! index of 10m air temperature             (Kelvin)
79   INTEGER , PUBLIC, PARAMETER ::   jp_humi  =  4   ! index of specific humidity               ( % )
80   INTEGER , PUBLIC, PARAMETER ::   jp_qsr   =  5   ! index of solar heat                      (W/m2)
81   INTEGER , PUBLIC, PARAMETER ::   jp_qlw   =  6   ! index of Long wave                       (W/m2)
82   INTEGER , PUBLIC, PARAMETER ::   jp_prec  =  7   ! index of total precipitation (rain+snow) (Kg/m2/s)
83   INTEGER , PUBLIC, PARAMETER ::   jp_snow  =  8   ! index of snow (solid prcipitation)       (kg/m2/s)
84   INTEGER , PUBLIC, PARAMETER ::   jp_slp   =  9   ! index of sea level pressure              (Pa)
85   INTEGER , PUBLIC, PARAMETER ::   jp_uoatm = 10   ! index of surface current (i-component)
86   !                                                !          seen by the atmospheric forcing (m/s) at T-point
87   INTEGER , PUBLIC, PARAMETER ::   jp_voatm = 11   ! index of surface current (j-component)
88   !                                                !          seen by the atmospheric forcing (m/s) at T-point
89   INTEGER , PUBLIC, PARAMETER ::   jp_cc    = 12   ! index of cloud cover                     (-)      range:0-1
90   INTEGER , PUBLIC, PARAMETER ::   jp_hpgi  = 13   ! index of ABL geostrophic wind or hpg (i-component) (m/s) at T-point
91   INTEGER , PUBLIC, PARAMETER ::   jp_hpgj  = 14   ! index of ABL geostrophic wind or hpg (j-component) (m/s) at T-point
92   INTEGER , PUBLIC, PARAMETER ::   jpfld    = 14   ! maximum number of files to read
93
94   ! Warning: keep this structure allocatable for Agrif...
95   TYPE(FLD), PUBLIC, ALLOCATABLE, DIMENSION(:) ::   sf   ! structure of input atmospheric fields (file informations, fields read)
96
97   !                           !!* Namelist namsbc_blk : bulk parameters
98   LOGICAL  ::   ln_NCAR        ! "NCAR"      algorithm   (Large and Yeager 2008)
99   LOGICAL  ::   ln_COARE_3p0   ! "COARE 3.0" algorithm   (Fairall et al. 2003)
100   LOGICAL  ::   ln_COARE_3p6   ! "COARE 3.6" algorithm   (Edson et al. 2013)
101   LOGICAL  ::   ln_ECMWF       ! "ECMWF"     algorithm   (IFS cycle 45r1)
102   !
103   LOGICAL  ::   ln_Cd_L12      ! ice-atm drag = F( ice concentration )                        (Lupkes et al. JGR2012)
104   LOGICAL  ::   ln_Cd_L15      ! ice-atm drag = F( ice concentration, atmospheric stability ) (Lupkes et al. JGR2015)
105   !
106   LOGICAL  ::   ln_crt_fbk     ! Add surface current feedback to the wind stress computation  (Renault et al. 2020)
107   REAL(wp) ::   rn_stau_a      ! Alpha and Beta coefficients of Renault et al. 2020, eq. 10: Stau = Alpha * Wnd + Beta
108   REAL(wp) ::   rn_stau_b      !
109   !
110   REAL(wp)         ::   rn_pfac   ! multiplication factor for precipitation
111   REAL(wp), PUBLIC ::   rn_efac   ! multiplication factor for evaporation
112   REAL(wp)         ::   rn_zqt    ! z(q,t) : height of humidity and temperature measurements
113   REAL(wp)         ::   rn_zu     ! z(u)   : height of wind measurements
114   !
115   REAL(wp), PUBLIC, ALLOCATABLE, DIMENSION(:,:) ::   Cdn_oce, Chn_oce, Cen_oce  ! neutral coeffs over ocean (L15 bulk scheme and ABL)
116   REAL(wp),         ALLOCATABLE, DIMENSION(:,:) ::   Cd_ice , Ch_ice , Ce_ice   ! transfert coefficients over ice
117   REAL(wp),         ALLOCATABLE, DIMENSION(:,:) ::   t_zu, q_zu                 ! air temp. and spec. hum. at wind speed height (L15 bulk scheme)
118
119   LOGICAL  ::   ln_skin_cs     ! use the cool-skin (only available in ECMWF and COARE algorithms) !LB
120   LOGICAL  ::   ln_skin_wl     ! use the warm-layer parameterization (only available in ECMWF and COARE algorithms) !LB
121   LOGICAL  ::   ln_humi_sph    ! humidity read in files ("sn_humi") is specific humidity [kg/kg] if .true. !LB
122   LOGICAL  ::   ln_humi_dpt    ! humidity read in files ("sn_humi") is dew-point temperature [K] if .true. !LB
123   LOGICAL  ::   ln_humi_rlh    ! humidity read in files ("sn_humi") is relative humidity     [%] if .true. !LB
124   LOGICAL  ::   ln_tpot        !!GS: flag to compute or not potential temperature
125   !
126   INTEGER  ::   nhumi          ! choice of the bulk algorithm
127   !                            ! associated indices:
128   INTEGER, PARAMETER :: np_humi_sph = 1
129   INTEGER, PARAMETER :: np_humi_dpt = 2
130   INTEGER, PARAMETER :: np_humi_rlh = 3
131
132   INTEGER  ::   nblk           ! choice of the bulk algorithm
133   !                            ! associated indices:
134   INTEGER, PARAMETER ::   np_NCAR      = 1   ! "NCAR" algorithm        (Large and Yeager 2008)
135   INTEGER, PARAMETER ::   np_COARE_3p0 = 2   ! "COARE 3.0" algorithm   (Fairall et al. 2003)
136   INTEGER, PARAMETER ::   np_COARE_3p6 = 3   ! "COARE 3.6" algorithm   (Edson et al. 2013)
137   INTEGER, PARAMETER ::   np_ECMWF     = 4   ! "ECMWF" algorithm       (IFS cycle 45r1)
138
139   !! * Substitutions
140#  include "do_loop_substitute.h90"
141   !!----------------------------------------------------------------------
142   !! NEMO/OCE 4.0 , NEMO Consortium (2018)
143   !! $Id$
144   !! Software governed by the CeCILL license (see ./LICENSE)
145   !!----------------------------------------------------------------------
146CONTAINS
147
148   INTEGER FUNCTION sbc_blk_alloc()
149      !!-------------------------------------------------------------------
150      !!             ***  ROUTINE sbc_blk_alloc ***
151      !!-------------------------------------------------------------------
152      ALLOCATE( t_zu(jpi,jpj)   , q_zu(jpi,jpj)   ,                                      &
153         &      Cdn_oce(jpi,jpj), Chn_oce(jpi,jpj), Cen_oce(jpi,jpj),                    &
154         &      Cd_ice (jpi,jpj), Ch_ice (jpi,jpj), Ce_ice (jpi,jpj), STAT=sbc_blk_alloc )
155      !
156      CALL mpp_sum ( 'sbcblk', sbc_blk_alloc )
157      IF( sbc_blk_alloc /= 0 )   CALL ctl_stop( 'STOP', 'sbc_blk_alloc: failed to allocate arrays' )
158   END FUNCTION sbc_blk_alloc
159
160
161   SUBROUTINE sbc_blk_init
162      !!---------------------------------------------------------------------
163      !!                    ***  ROUTINE sbc_blk_init  ***
164      !!
165      !! ** Purpose :   choose and initialize a bulk formulae formulation
166      !!
167      !! ** Method  :
168      !!
169      !!----------------------------------------------------------------------
170      INTEGER  ::   jfpr                  ! dummy loop indice and argument
171      INTEGER  ::   ios, ierror, ioptio   ! Local integer
172      !!
173      CHARACTER(len=100)            ::   cn_dir                ! Root directory for location of atmospheric forcing files
174      TYPE(FLD_N), DIMENSION(jpfld) ::   slf_i                 ! array of namelist informations on the fields to read
175      TYPE(FLD_N) ::   sn_wndi, sn_wndj , sn_humi, sn_qsr      ! informations about the fields to be read
176      TYPE(FLD_N) ::   sn_qlw , sn_tair , sn_prec, sn_snow     !       "                        "
177      TYPE(FLD_N) ::   sn_slp , sn_uoatm, sn_voatm             !       "                        "
178      TYPE(FLD_N) ::   sn_cc, sn_hpgi, sn_hpgj                 !       "                        "
179      INTEGER     ::   ipka                                    ! number of levels in the atmospheric variable
180      NAMELIST/namsbc_blk/ sn_wndi, sn_wndj, sn_humi, sn_qsr, sn_qlw ,                &   ! input fields
181         &                 sn_tair, sn_prec, sn_snow, sn_slp, sn_uoatm, sn_voatm,     &
182         &                 sn_cc, sn_hpgi, sn_hpgj,                                   &
183         &                 ln_NCAR, ln_COARE_3p0, ln_COARE_3p6, ln_ECMWF,             &   ! bulk algorithm
184         &                 cn_dir , rn_zqt, rn_zu,                                    &
185         &                 rn_pfac, rn_efac, ln_Cd_L12, ln_Cd_L15, ln_tpot,           &
186         &                 ln_crt_fbk, rn_stau_a, rn_stau_b,                          &   ! current feedback
187         &                 ln_skin_cs, ln_skin_wl, ln_humi_sph, ln_humi_dpt, ln_humi_rlh  ! cool-skin / warm-layer !LB
188      !!---------------------------------------------------------------------
189      !
190      !                                      ! allocate sbc_blk_core array
191      IF( sbc_blk_alloc() /= 0 )   CALL ctl_stop( 'STOP', 'sbc_blk : unable to allocate standard arrays' )
192      !
193      !                             !** read bulk namelist
194      READ  ( numnam_ref, namsbc_blk, IOSTAT = ios, ERR = 901)
195901   IF( ios /= 0 )   CALL ctl_nam ( ios , 'namsbc_blk in reference namelist' )
196      !
197      READ  ( numnam_cfg, namsbc_blk, IOSTAT = ios, ERR = 902 )
198902   IF( ios >  0 )   CALL ctl_nam ( ios , 'namsbc_blk in configuration namelist' )
199      !
200      IF(lwm) WRITE( numond, namsbc_blk )
201      !
202      !                             !** initialization of the chosen bulk formulae (+ check)
203      !                                   !* select the bulk chosen in the namelist and check the choice
204      ioptio = 0
205      IF( ln_NCAR      ) THEN
206         nblk =  np_NCAR        ;   ioptio = ioptio + 1
207      ENDIF
208      IF( ln_COARE_3p0 ) THEN
209         nblk =  np_COARE_3p0   ;   ioptio = ioptio + 1
210      ENDIF
211      IF( ln_COARE_3p6 ) THEN
212         nblk =  np_COARE_3p6   ;   ioptio = ioptio + 1
213      ENDIF
214      IF( ln_ECMWF     ) THEN
215         nblk =  np_ECMWF       ;   ioptio = ioptio + 1
216      ENDIF
217      IF( ioptio /= 1 )   CALL ctl_stop( 'sbc_blk_init: Choose one and only one bulk algorithm' )
218
219      !                             !** initialization of the cool-skin / warm-layer parametrization
220      IF( ln_skin_cs .OR. ln_skin_wl ) THEN
221         !! Some namelist sanity tests:
222         IF( ln_NCAR )      &
223            & CALL ctl_stop( 'sbc_blk_init: Cool-skin/warm-layer param. not compatible with NCAR algorithm' )
224         IF( nn_fsbc /= 1 ) &
225            & CALL ctl_stop( 'sbc_blk_init: Please set "nn_fsbc" to 1 when using cool-skin/warm-layer param.')
226      END IF
227
228      IF( ln_skin_wl ) THEN
229         !! Check if the frequency of downwelling solar flux input makes sense and if ln_dm2dc=T if it is daily!
230         IF( (sn_qsr%freqh  < 0.).OR.(sn_qsr%freqh  > 24.) ) &
231            & CALL ctl_stop( 'sbc_blk_init: Warm-layer param. (ln_skin_wl) not compatible with freq. of solar flux > daily' )
232         IF( (sn_qsr%freqh == 24.).AND.(.NOT. ln_dm2dc) ) &
233            & CALL ctl_stop( 'sbc_blk_init: Please set ln_dm2dc=T for warm-layer param. (ln_skin_wl) to work properly' )
234      END IF
235
236      ioptio = 0
237      IF( ln_humi_sph ) THEN
238         nhumi =  np_humi_sph    ;   ioptio = ioptio + 1
239      ENDIF
240      IF( ln_humi_dpt ) THEN
241         nhumi =  np_humi_dpt    ;   ioptio = ioptio + 1
242      ENDIF
243      IF( ln_humi_rlh ) THEN
244         nhumi =  np_humi_rlh    ;   ioptio = ioptio + 1
245      ENDIF
246      IF( ioptio /= 1 )   CALL ctl_stop( 'sbc_blk_init: Choose one and only one type of air humidity' )
247      !
248      IF( ln_dm2dc ) THEN                 !* check: diurnal cycle on Qsr
249         IF( sn_qsr%freqh /= 24. )   CALL ctl_stop( 'sbc_blk_init: ln_dm2dc=T only with daily short-wave input' )
250         IF( sn_qsr%ln_tint ) THEN
251            CALL ctl_warn( 'sbc_blk_init: ln_dm2dc=T daily qsr time interpolation done by sbcdcy module',   &
252               &           '              ==> We force time interpolation = .false. for qsr' )
253            sn_qsr%ln_tint = .false.
254         ENDIF
255      ENDIF
256      !                                   !* set the bulk structure
257      !                                      !- store namelist information in an array
258      !
259      slf_i(jp_wndi ) = sn_wndi    ;   slf_i(jp_wndj ) = sn_wndj
260      slf_i(jp_qsr  ) = sn_qsr     ;   slf_i(jp_qlw  ) = sn_qlw
261      slf_i(jp_tair ) = sn_tair    ;   slf_i(jp_humi ) = sn_humi
262      slf_i(jp_prec ) = sn_prec    ;   slf_i(jp_snow ) = sn_snow
263      slf_i(jp_slp  ) = sn_slp     ;   slf_i(jp_cc   ) = sn_cc
264      slf_i(jp_uoatm) = sn_uoatm   ;   slf_i(jp_voatm) = sn_voatm
265      slf_i(jp_hpgi ) = sn_hpgi    ;   slf_i(jp_hpgj ) = sn_hpgj
266      !
267      IF( .NOT. ln_abl ) THEN   ! force to not use jp_hpgi and jp_hpgj, should already be done in namelist_* but we never know...
268         slf_i(jp_hpgi)%clname = 'NOT USED'
269         slf_i(jp_hpgj)%clname = 'NOT USED'
270      ENDIF
271      !
272      !                                      !- allocate the bulk structure
273      ALLOCATE( sf(jpfld), STAT=ierror )
274      IF( ierror > 0 )   CALL ctl_stop( 'STOP', 'sbc_blk_init: unable to allocate sf structure' )
275      !
276      !                                      !- fill the bulk structure with namelist informations
277      CALL fld_fill( sf, slf_i, cn_dir, 'sbc_blk_init', 'surface boundary condition -- bulk formulae', 'namsbc_blk' )
278      !
279      DO jfpr= 1, jpfld
280         !
281         IF(   ln_abl    .AND.                                                      &
282            &    ( jfpr == jp_wndi .OR. jfpr == jp_wndj .OR. jfpr == jp_humi .OR.   &
283            &      jfpr == jp_hpgi .OR. jfpr == jp_hpgj .OR. jfpr == jp_tair     )  ) THEN
284            ipka = jpka   ! ABL: some fields are 3D input
285         ELSE
286            ipka = 1
287         ENDIF
288         !
289         ALLOCATE( sf(jfpr)%fnow(jpi,jpj,ipka) )
290         !
291         IF( TRIM(sf(jfpr)%clrootname) == 'NOT USED' ) THEN    !--  not used field  --!   (only now allocated and set to default)
292            IF(     jfpr == jp_slp ) THEN
293               sf(jfpr)%fnow(:,:,1:ipka) = 101325._wp   ! use standard pressure in Pa
294            ELSEIF( jfpr == jp_prec .OR. jfpr == jp_snow .OR. jfpr == jp_uoatm .OR. jfpr == jp_voatm ) THEN
295               sf(jfpr)%fnow(:,:,1:ipka) = 0._wp        ! no precip or no snow or no surface currents
296            ELSEIF( jfpr == jp_hpgi .OR. jfpr == jp_hpgj ) THEN
297               IF( .NOT. ln_abl ) THEN
298                  DEALLOCATE( sf(jfpr)%fnow )   ! deallocate as not used in this case
299               ELSE
300                  sf(jfpr)%fnow(:,:,1:ipka) = 0._wp
301               ENDIF
302            ELSEIF( jfpr == jp_cc  ) THEN
303               sf(jp_cc)%fnow(:,:,1:ipka) = pp_cldf
304            ELSE
305               WRITE(ctmp1,*) 'sbc_blk_init: no default value defined for field number', jfpr
306               CALL ctl_stop( ctmp1 )
307            ENDIF
308         ELSE                                                  !-- used field  --!
309            IF( sf(jfpr)%ln_tint )   ALLOCATE( sf(jfpr)%fdta(jpi,jpj,ipka,2) )   ! allocate array for temporal interpolation
310            !
311            IF( sf(jfpr)%freqh > 0. .AND. MOD( NINT(3600. * sf(jfpr)%freqh), nn_fsbc * NINT(rn_Dt) ) /= 0 )   &
312         &  CALL ctl_warn( 'sbc_blk_init: sbcmod timestep rn_Dt*nn_fsbc is NOT a submultiple of atmospheric forcing frequency.',   &
313         &                 '               This is not ideal. You should consider changing either rn_Dt or nn_fsbc value...' )
314         ENDIF
315      END DO
316      !
317      IF( ln_wave ) THEN
318         !Activated wave module but neither drag nor stokes drift activated
319         IF( .NOT.(ln_cdgw .OR. ln_sdw .OR. ln_tauwoc .OR. ln_stcor ) )   THEN
320            CALL ctl_stop( 'STOP',  'Ask for wave coupling but ln_cdgw=F, ln_sdw=F, ln_tauwoc=F, ln_stcor=F' )
321            !drag coefficient read from wave model definable only with mfs bulk formulae and core
322         ELSEIF(ln_cdgw .AND. .NOT. ln_NCAR )       THEN
323            CALL ctl_stop( 'drag coefficient read from wave model definable only with NCAR and CORE bulk formulae')
324         ELSEIF(ln_stcor .AND. .NOT. ln_sdw)                             THEN
325            CALL ctl_stop( 'Stokes-Coriolis term calculated only if activated Stokes Drift ln_sdw=T')
326         ENDIF
327      ELSE
328         IF( ln_cdgw .OR. ln_sdw .OR. ln_tauwoc .OR. ln_stcor )                &
329            &   CALL ctl_stop( 'Not Activated Wave Module (ln_wave=F) but asked coupling ',    &
330            &                  'with drag coefficient (ln_cdgw =T) '  ,                        &
331            &                  'or Stokes Drift (ln_sdw=T) ' ,                                 &
332            &                  'or ocean stress modification due to waves (ln_tauwoc=T) ',      &
333            &                  'or Stokes-Coriolis term (ln_stcori=T)'  )
334      ENDIF
335      !
336      IF( ln_abl ) THEN       ! ABL: read 3D fields for wind, temperature, humidity and pressure gradient
337         rn_zqt = ght_abl(2)          ! set the bulk altitude to ABL first level
338         rn_zu  = ght_abl(2)
339         IF(lwp) WRITE(numout,*)
340         IF(lwp) WRITE(numout,*) '   ABL formulation: overwrite rn_zqt & rn_zu with ABL first level altitude'
341      ENDIF
342      !
343      ! set transfer coefficients to default sea-ice values
344      Cd_ice(:,:) = rCd_ice
345      Ch_ice(:,:) = rCd_ice
346      Ce_ice(:,:) = rCd_ice
347      !
348      IF(lwp) THEN                     !** Control print
349         !
350         WRITE(numout,*)                  !* namelist
351         WRITE(numout,*) '   Namelist namsbc_blk (other than data information):'
352         WRITE(numout,*) '      "NCAR"      algorithm   (Large and Yeager 2008)     ln_NCAR      = ', ln_NCAR
353         WRITE(numout,*) '      "COARE 3.0" algorithm   (Fairall et al. 2003)       ln_COARE_3p0 = ', ln_COARE_3p0
354         WRITE(numout,*) '      "COARE 3.6" algorithm (Fairall 2018 + Edson al 2013)ln_COARE_3p6 = ', ln_COARE_3p6
355         WRITE(numout,*) '      "ECMWF"     algorithm   (IFS cycle 45r1)            ln_ECMWF     = ', ln_ECMWF
356         WRITE(numout,*) '      Air temperature and humidity reference height (m)   rn_zqt       = ', rn_zqt
357         WRITE(numout,*) '      Wind vector reference height (m)                    rn_zu        = ', rn_zu
358         WRITE(numout,*) '      factor applied on precipitation (total & snow)      rn_pfac      = ', rn_pfac
359         WRITE(numout,*) '      factor applied on evaporation                       rn_efac      = ', rn_efac
360         WRITE(numout,*) '         (form absolute (=0) to relative winds(=1))'
361         WRITE(numout,*) '      use ice-atm drag from Lupkes2012                    ln_Cd_L12    = ', ln_Cd_L12
362         WRITE(numout,*) '      use ice-atm drag from Lupkes2015                    ln_Cd_L15    = ', ln_Cd_L15
363         WRITE(numout,*) '      use surface current feedback on wind stress         ln_crt_fbk   = ', ln_crt_fbk
364         IF(ln_crt_fbk) THEN
365         WRITE(numout,*) '         Renault et al. 2020, eq. 10: Stau = Alpha * Wnd + Beta'
366         WRITE(numout,*) '            Alpha                                         rn_stau_a    = ', rn_stau_a
367         WRITE(numout,*) '            Beta                                          rn_stau_b    = ', rn_stau_b
368         ENDIF
369         !
370         WRITE(numout,*)
371         SELECT CASE( nblk )              !* Print the choice of bulk algorithm
372         CASE( np_NCAR      )   ;   WRITE(numout,*) '   ==>>>   "NCAR" algorithm        (Large and Yeager 2008)'
373         CASE( np_COARE_3p0 )   ;   WRITE(numout,*) '   ==>>>   "COARE 3.0" algorithm   (Fairall et al. 2003)'
374         CASE( np_COARE_3p6 )   ;   WRITE(numout,*) '   ==>>>   "COARE 3.6" algorithm (Fairall 2018+Edson et al. 2013)'
375         CASE( np_ECMWF     )   ;   WRITE(numout,*) '   ==>>>   "ECMWF" algorithm       (IFS cycle 45r1)'
376         END SELECT
377         !
378         WRITE(numout,*)
379         WRITE(numout,*) '      use cool-skin  parameterization (SSST)  ln_skin_cs  = ', ln_skin_cs
380         WRITE(numout,*) '      use warm-layer parameterization (SSST)  ln_skin_wl  = ', ln_skin_wl
381         !
382         WRITE(numout,*)
383         SELECT CASE( nhumi )              !* Print the choice of air humidity
384         CASE( np_humi_sph )   ;   WRITE(numout,*) '   ==>>>   air humidity is SPECIFIC HUMIDITY     [kg/kg]'
385         CASE( np_humi_dpt )   ;   WRITE(numout,*) '   ==>>>   air humidity is DEW-POINT TEMPERATURE [K]'
386         CASE( np_humi_rlh )   ;   WRITE(numout,*) '   ==>>>   air humidity is RELATIVE HUMIDITY     [%]'
387         END SELECT
388         !
389      ENDIF
390      !
391   END SUBROUTINE sbc_blk_init
392
393
394   SUBROUTINE sbc_blk( kt )
395      !!---------------------------------------------------------------------
396      !!                    ***  ROUTINE sbc_blk  ***
397      !!
398      !! ** Purpose :   provide at each time step the surface ocean fluxes
399      !!              (momentum, heat, freshwater and runoff)
400      !!
401      !! ** Method  :
402      !!              (1) READ each fluxes in NetCDF files:
403      !!      the wind velocity (i-component) at z=rn_zu  (m/s) at T-point
404      !!      the wind velocity (j-component) at z=rn_zu  (m/s) at T-point
405      !!      the specific humidity           at z=rn_zqt (kg/kg)
406      !!      the air temperature             at z=rn_zqt (Kelvin)
407      !!      the solar heat                              (W/m2)
408      !!      the Long wave                               (W/m2)
409      !!      the total precipitation (rain+snow)         (Kg/m2/s)
410      !!      the snow (solid precipitation)              (kg/m2/s)
411      !!      ABL dynamical forcing (i/j-components of either hpg or geostrophic winds)
412      !!              (2) CALL blk_oce_1 and blk_oce_2
413      !!
414      !!      C A U T I O N : never mask the surface stress fields
415      !!                      the stress is assumed to be in the (i,j) mesh referential
416      !!
417      !! ** Action  :   defined at each time-step at the air-sea interface
418      !!              - utau, vtau  i- and j-component of the wind stress
419      !!              - taum        wind stress module at T-point
420      !!              - wndm        wind speed  module at T-point over free ocean or leads in presence of sea-ice
421      !!              - qns, qsr    non-solar and solar heat fluxes
422      !!              - emp         upward mass flux (evapo. - precip.)
423      !!              - sfx         salt flux due to freezing/melting (non-zero only if ice is present)
424      !!
425      !! ** References :   Large & Yeager, 2004 / Large & Yeager, 2008
426      !!                   Brodeau et al. Ocean Modelling 2010
427      !!----------------------------------------------------------------------
428      INTEGER, INTENT(in) ::   kt   ! ocean time step
429      !!----------------------------------------------------------------------
430      REAL(wp), DIMENSION(jpi,jpj) ::   zssq, zcd_du, zsen, zevp
431      REAL(wp) :: ztmp
432      !!----------------------------------------------------------------------
433      !
434      CALL fld_read( kt, nn_fsbc, sf )             ! input fields provided at the current time-step
435
436      ! Sanity/consistence test on humidity at first time step to detect potential screw-up:
437      IF( kt == nit000 ) THEN
438         IF(lwp) WRITE(numout,*) ''
439#if defined key_agrif
440         IF(lwp) WRITE(numout,*) ' === AGRIF => Sanity/consistence test on air humidity SKIPPED! :( ==='
441#else
442         ztmp = SUM(tmask(:,:,1)) ! number of ocean points on local proc domain
443         IF( ztmp > 8._wp ) THEN ! test only on proc domains with at least 8 ocean points!
444            ztmp = SUM(sf(jp_humi)%fnow(:,:,1)*tmask(:,:,1))/ztmp ! mean humidity over ocean on proc
445            SELECT CASE( nhumi )
446            CASE( np_humi_sph ) ! specific humidity => expect: 0. <= something < 0.065 [kg/kg] (0.061 is saturation at 45degC !!!)
447               IF(  (ztmp < 0._wp) .OR. (ztmp > 0.065)  ) ztmp = -1._wp
448            CASE( np_humi_dpt ) ! dew-point temperature => expect: 110. <= something < 320. [K]
449               IF( (ztmp < 110._wp).OR.(ztmp > 320._wp) ) ztmp = -1._wp
450            CASE( np_humi_rlh ) ! relative humidity => expect: 0. <= something < 100. [%]
451               IF(  (ztmp < 0._wp) .OR.(ztmp > 100._wp) ) ztmp = -1._wp
452            END SELECT
453            IF(ztmp < 0._wp) THEN
454               IF (lwp) WRITE(numout,'("   Mean humidity value found on proc #",i6.6," is: ",f10.5)') narea, ztmp
455               CALL ctl_stop( 'STOP', 'Something is wrong with air humidity!!!', &
456                  &   ' ==> check the unit in your input files'       , &
457                  &   ' ==> check consistence of namelist choice: specific? relative? dew-point?', &
458                  &   ' ==> ln_humi_sph -> [kg/kg] | ln_humi_rlh -> [%] | ln_humi_dpt -> [K] !!!' )
459            END IF
460         END IF
461         IF(lwp) WRITE(numout,*) ' === Sanity/consistence test on air humidity sucessfuly passed! ==='
462#endif
463         IF(lwp) WRITE(numout,*) ''
464      END IF !IF( kt == nit000 )
465      !                                            ! compute the surface ocean fluxes using bulk formulea
466      IF( MOD( kt - 1, nn_fsbc ) == 0 ) THEN
467         CALL blk_oce_1( kt, sf(jp_wndi )%fnow(:,:,1), sf(jp_wndj )%fnow(:,:,1),   &   !   <<= in
468            &                sf(jp_tair )%fnow(:,:,1), sf(jp_humi )%fnow(:,:,1),   &   !   <<= in
469            &                sf(jp_slp  )%fnow(:,:,1), sst_m, ssu_m, ssv_m,        &   !   <<= in
470            &                sf(jp_uoatm)%fnow(:,:,1), sf(jp_voatm)%fnow(:,:,1),   &   !   <<= in
471            &                sf(jp_qsr  )%fnow(:,:,1), sf(jp_qlw  )%fnow(:,:,1),   &   !   <<= in (wl/cs)
472            &                tsk_m, zssq, zcd_du, zsen, zevp )                         !   =>> out
473
474         CALL blk_oce_2(     sf(jp_tair )%fnow(:,:,1), sf(jp_qsr  )%fnow(:,:,1),   &   !   <<= in
475            &                sf(jp_qlw  )%fnow(:,:,1), sf(jp_prec )%fnow(:,:,1),   &   !   <<= in
476            &                sf(jp_snow )%fnow(:,:,1), tsk_m,                      &   !   <<= in
477            &                zsen, zevp )                                              !   <=> in out
478      ENDIF
479      !
480#if defined key_cice
481      IF( MOD( kt - 1, nn_fsbc ) == 0 )   THEN
482         qlw_ice(:,:,1)   = sf(jp_qlw )%fnow(:,:,1)
483         IF( ln_dm2dc ) THEN
484            qsr_ice(:,:,1) = sbc_dcy( sf(jp_qsr)%fnow(:,:,1) )
485         ELSE
486            qsr_ice(:,:,1) =          sf(jp_qsr)%fnow(:,:,1)
487         ENDIF
488         tatm_ice(:,:)    = sf(jp_tair)%fnow(:,:,1)
489
490         SELECT CASE( nhumi )
491         CASE( np_humi_sph )
492            qatm_ice(:,:) =           sf(jp_humi)%fnow(:,:,1)
493         CASE( np_humi_dpt )
494            qatm_ice(:,:) = q_sat(    sf(jp_humi)%fnow(:,:,1), sf(jp_slp)%fnow(:,:,1) )
495         CASE( np_humi_rlh )
496            qatm_ice(:,:) = q_air_rh( 0.01_wp*sf(jp_humi)%fnow(:,:,1), sf(jp_tair)%fnow(:,:,1), sf(jp_slp)%fnow(:,:,1)) !LB: 0.01 => RH is % percent in file
497         END SELECT
498
499         tprecip(:,:)     = sf(jp_prec)%fnow(:,:,1) * rn_pfac
500         sprecip(:,:)     = sf(jp_snow)%fnow(:,:,1) * rn_pfac
501         wndi_ice(:,:)    = sf(jp_wndi)%fnow(:,:,1)
502         wndj_ice(:,:)    = sf(jp_wndj)%fnow(:,:,1)
503      ENDIF
504#endif
505      !
506   END SUBROUTINE sbc_blk
507
508
509   SUBROUTINE blk_oce_1( kt, pwndi, pwndj, ptair, phumi,         &  ! inp
510      &                      pslp , pst  , pu   , pv,            &  ! inp
511      &                      puatm, pvatm, pqsr , pqlw ,         &  ! inp
512      &                      ptsk , pssq , pcd_du, psen, pevp   )   ! out
513      !!---------------------------------------------------------------------
514      !!                     ***  ROUTINE blk_oce_1  ***
515      !!
516      !! ** Purpose :   if ln_blk=T, computes surface momentum, heat and freshwater fluxes
517      !!                if ln_abl=T, computes Cd x |U|, Ch x |U|, Ce x |U| for ABL integration
518      !!
519      !! ** Method  :   bulk formulae using atmospheric fields from :
520      !!                if ln_blk=T, atmospheric fields read in sbc_read
521      !!                if ln_abl=T, the ABL model at previous time-step
522      !!
523      !! ** Outputs : - pssq    : surface humidity used to compute latent heat flux (kg/kg)
524      !!              - pcd_du  : Cd x |dU| at T-points  (m/s)
525      !!              - psen    : Ch x |dU| at T-points  (m/s)
526      !!              - pevp    : Ce x |dU| at T-points  (m/s)
527      !!---------------------------------------------------------------------
528      INTEGER , INTENT(in   )                 ::   kt     ! time step index
529      REAL(wp), INTENT(in   ), DIMENSION(:,:) ::   pwndi  ! atmospheric wind at U-point              [m/s]
530      REAL(wp), INTENT(in   ), DIMENSION(:,:) ::   pwndj  ! atmospheric wind at V-point              [m/s]
531      REAL(wp), INTENT(in   ), DIMENSION(:,:) ::   phumi  ! specific humidity at T-points            [kg/kg]
532      REAL(wp), INTENT(in   ), DIMENSION(:,:) ::   ptair  ! potential temperature at T-points        [Kelvin]
533      REAL(wp), INTENT(in   ), DIMENSION(:,:) ::   pslp   ! sea-level pressure                       [Pa]
534      REAL(wp), INTENT(in   ), DIMENSION(:,:) ::   pst    ! surface temperature                      [Celsius]
535      REAL(wp), INTENT(in   ), DIMENSION(:,:) ::   pu     ! surface current at U-point (i-component) [m/s]
536      REAL(wp), INTENT(in   ), DIMENSION(:,:) ::   pv     ! surface current at V-point (j-component) [m/s]
537      REAL(wp), INTENT(in   ), DIMENSION(:,:) ::   puatm  ! surface current seen by the atm at T-point (i-component) [m/s]
538      REAL(wp), INTENT(in   ), DIMENSION(:,:) ::   pvatm  ! surface current seen by the atm at T-point (j-component) [m/s]
539      REAL(wp), INTENT(in   ), DIMENSION(:,:) ::   pqsr   !
540      REAL(wp), INTENT(in   ), DIMENSION(:,:) ::   pqlw   !
541      REAL(wp), INTENT(  out), DIMENSION(:,:) ::   ptsk   ! skin temp. (or SST if CS & WL not used)  [Celsius]
542      REAL(wp), INTENT(  out), DIMENSION(:,:) ::   pssq   ! specific humidity at pst                 [kg/kg]
543      REAL(wp), INTENT(  out), DIMENSION(:,:) ::   pcd_du ! Cd x |dU| at T-points                    [m/s]
544      REAL(wp), INTENT(  out), DIMENSION(:,:) ::   psen   ! Ch x |dU| at T-points                    [m/s]
545      REAL(wp), INTENT(  out), DIMENSION(:,:) ::   pevp   ! Ce x |dU| at T-points                    [m/s]
546      !
547      INTEGER  ::   ji, jj               ! dummy loop indices
548      REAL(wp) ::   zztmp                ! local variable
549      REAL(wp) ::   zstmax, zstau
550#if defined key_cyclone
551      REAL(wp), DIMENSION(jpi,jpj) ::   zwnd_i, zwnd_j    ! wind speed components at T-point
552#endif
553      REAL(wp), DIMENSION(jpi,jpj) ::   ztau_i, ztau_j    ! wind stress components at T-point
554      REAL(wp), DIMENSION(jpi,jpj) ::   zU_zu             ! bulk wind speed at height zu  [m/s]
555      REAL(wp), DIMENSION(jpi,jpj) ::   ztpot             ! potential temperature of air at z=rn_zqt [K]
556      REAL(wp), DIMENSION(jpi,jpj) ::   zqair             ! specific humidity     of air at z=rn_zqt [kg/kg]
557      REAL(wp), DIMENSION(jpi,jpj) ::   zcd_oce           ! momentum transfert coefficient over ocean
558      REAL(wp), DIMENSION(jpi,jpj) ::   zch_oce           ! sensible heat transfert coefficient over ocean
559      REAL(wp), DIMENSION(jpi,jpj) ::   zce_oce           ! latent   heat transfert coefficient over ocean
560      REAL(wp), DIMENSION(jpi,jpj) ::   zqla              ! latent heat flux
561      REAL(wp), DIMENSION(jpi,jpj) ::   zztmp1, zztmp2
562      !!---------------------------------------------------------------------
563      !
564      ! local scalars ( place there for vector optimisation purposes)
565      !                           ! Temporary conversion from Celcius to Kelvin (and set minimum value far above 0 K)
566      ptsk(:,:) = pst(:,:) + rt0  ! by default: skin temperature = "bulk SST" (will remain this way if NCAR algorithm used!)
567
568      ! --- cloud cover --- !
569      cloud_fra(:,:) = sf(jp_cc)%fnow(:,:,1)
570
571      ! ----------------------------------------------------------------------------- !
572      !      0   Wind components and module at T-point relative to the moving ocean   !
573      ! ----------------------------------------------------------------------------- !
574
575      ! ... components ( U10m - U_oce ) at T-point (unmasked)
576#if defined key_cyclone
577      zwnd_i(:,:) = 0._wp
578      zwnd_j(:,:) = 0._wp
579      CALL wnd_cyc( kt, zwnd_i, zwnd_j )    ! add analytical tropical cyclone (Vincent et al. JGR 2012)
580      DO_2D( nn_hls, nn_hls, nn_hls, nn_hls )
581         zwnd_i(ji,jj) = pwndi(ji,jj) + zwnd_i(ji,jj)
582         zwnd_j(ji,jj) = pwndj(ji,jj) + zwnd_j(ji,jj)
583         ! ... scalar wind at T-point (not masked)
584         wndm(ji,jj) = SQRT( zwnd_i(ji,jj) * zwnd_i(ji,jj) + zwnd_j(ji,jj) * zwnd_j(ji,jj) )
585      END_2D
586#else
587      ! ... scalar wind module at T-point (not masked)
588      DO_2D( nn_hls, nn_hls, nn_hls, nn_hls )
589         wndm(ji,jj) = SQRT(  pwndi(ji,jj) * pwndi(ji,jj) + pwndj(ji,jj) * pwndj(ji,jj)  )
590      END_2D
591#endif
592      ! ----------------------------------------------------------------------------- !
593      !      I   Solar FLUX                                                           !
594      ! ----------------------------------------------------------------------------- !
595
596      ! ocean albedo assumed to be constant + modify now Qsr to include the diurnal cycle                    ! Short Wave
597      zztmp = 1. - albo
598      IF( ln_dm2dc ) THEN
599         qsr(:,:) = zztmp * sbc_dcy( sf(jp_qsr)%fnow(:,:,1) ) * tmask(:,:,1)
600      ELSE
601         qsr(:,:) = zztmp *          sf(jp_qsr)%fnow(:,:,1)   * tmask(:,:,1)
602      ENDIF
603
604
605      ! ----------------------------------------------------------------------------- !
606      !     II   Turbulent FLUXES                                                     !
607      ! ----------------------------------------------------------------------------- !
608
609      ! specific humidity at SST
610      pssq(:,:) = rdct_qsat_salt * q_sat( ptsk(:,:), pslp(:,:) )
611
612      IF( ln_skin_cs .OR. ln_skin_wl ) THEN
613         !! Backup "bulk SST" and associated spec. hum.
614         zztmp1(:,:) = ptsk(:,:)
615         zztmp2(:,:) = pssq(:,:)
616      ENDIF
617
618      ! specific humidity of air at "rn_zqt" m above the sea
619      SELECT CASE( nhumi )
620      CASE( np_humi_sph )
621         zqair(:,:) = phumi(:,:)      ! what we read in file is already a spec. humidity!
622      CASE( np_humi_dpt )
623         !IF(lwp) WRITE(numout,*) ' *** blk_oce => computing q_air out of d_air and slp !' !LBrm
624         zqair(:,:) = q_sat( phumi(:,:), pslp(:,:) )
625      CASE( np_humi_rlh )
626         !IF(lwp) WRITE(numout,*) ' *** blk_oce => computing q_air out of RH, t_air and slp !' !LBrm
627         zqair(:,:) = q_air_rh( 0.01_wp*phumi(:,:), ptair(:,:), pslp(:,:) ) !LB: 0.01 => RH is % percent in file
628      END SELECT
629      !
630      ! potential temperature of air at "rn_zqt" m above the sea
631      IF( ln_abl ) THEN
632         ztpot = ptair(:,:)
633      ELSE
634         ! Estimate of potential temperature at z=rn_zqt, based on adiabatic lapse-rate
635         !    (see Josey, Gulev & Yu, 2013) / doi=10.1016/B978-0-12-391851-2.00005-2
636         !    (since reanalysis products provide T at z, not theta !)
637         !#LB: because AGRIF hates functions that return something else than a scalar, need to
638         !     use scalar version of gamma_moist() ...
639         IF( ln_tpot ) THEN
640            DO_2D( nn_hls, nn_hls, nn_hls, nn_hls )
641               ztpot(ji,jj) = ptair(ji,jj) + gamma_moist( ptair(ji,jj), zqair(ji,jj) ) * rn_zqt
642            END_2D
643         ELSE
644            ztpot = ptair(:,:)
645         ENDIF
646      ENDIF
647
648      !! Time to call the user-selected bulk parameterization for
649      !!  ==  transfer coefficients  ==!   Cd, Ch, Ce at T-point, and more...
650      SELECT CASE( nblk )
651
652      CASE( np_NCAR      )
653         CALL turb_ncar    ( rn_zqt, rn_zu, ptsk, ztpot, pssq, zqair, wndm,                              &
654            &                zcd_oce, zch_oce, zce_oce, t_zu, q_zu, zU_zu, cdn_oce, chn_oce, cen_oce )
655
656      CASE( np_COARE_3p0 )
657         CALL turb_coare3p0 ( kt, rn_zqt, rn_zu, ptsk, ztpot, pssq, zqair, wndm, ln_skin_cs, ln_skin_wl, &
658            &                zcd_oce, zch_oce, zce_oce, t_zu, q_zu, zU_zu, cdn_oce, chn_oce, cen_oce,   &
659            &                Qsw=qsr(:,:), rad_lw=pqlw(:,:), slp=pslp(:,:) )
660
661      CASE( np_COARE_3p6 )
662         CALL turb_coare3p6 ( kt, rn_zqt, rn_zu, ptsk, ztpot, pssq, zqair, wndm, ln_skin_cs, ln_skin_wl, &
663            &                zcd_oce, zch_oce, zce_oce, t_zu, q_zu, zU_zu, cdn_oce, chn_oce, cen_oce,   &
664            &                Qsw=qsr(:,:), rad_lw=pqlw(:,:), slp=pslp(:,:) )
665
666      CASE( np_ECMWF     )
667         CALL turb_ecmwf   ( kt, rn_zqt, rn_zu, ptsk, ztpot, pssq, zqair, wndm, ln_skin_cs, ln_skin_wl,  &
668            &                zcd_oce, zch_oce, zce_oce, t_zu, q_zu, zU_zu, cdn_oce, chn_oce, cen_oce,   &
669            &                Qsw=qsr(:,:), rad_lw=pqlw(:,:), slp=pslp(:,:) )
670
671      CASE DEFAULT
672         CALL ctl_stop( 'STOP', 'sbc_oce: non-existing bulk formula selected' )
673
674      END SELECT
675     
676      IF( iom_use('Cd_oce') )   CALL iom_put("Cd_oce",   zcd_oce * tmask(:,:,1))
677      IF( iom_use('Ce_oce') )   CALL iom_put("Ce_oce",   zce_oce * tmask(:,:,1))
678      IF( iom_use('Ch_oce') )   CALL iom_put("Ch_oce",   zch_oce * tmask(:,:,1))
679      !! LB: mainly here for debugging purpose:
680      IF( iom_use('theta_zt') ) CALL iom_put("theta_zt", (ztpot-rt0) * tmask(:,:,1)) ! potential temperature at z=zt
681      IF( iom_use('q_zt') )     CALL iom_put("q_zt",     zqair       * tmask(:,:,1)) ! specific humidity       "
682      IF( iom_use('theta_zu') ) CALL iom_put("theta_zu", (t_zu -rt0) * tmask(:,:,1)) ! potential temperature at z=zu
683      IF( iom_use('q_zu') )     CALL iom_put("q_zu",     q_zu        * tmask(:,:,1)) ! specific humidity       "
684      IF( iom_use('ssq') )      CALL iom_put("ssq",      pssq        * tmask(:,:,1)) ! saturation specific humidity at z=0
685      IF( iom_use('wspd_blk') ) CALL iom_put("wspd_blk", zU_zu       * tmask(:,:,1)) ! bulk wind speed at z=zu
686     
687      IF( ln_skin_cs .OR. ln_skin_wl ) THEN
688         !! ptsk and pssq have been updated!!!
689         !!
690         !! In the presence of sea-ice we forget about the cool-skin/warm-layer update of ptsk and pssq:
691         WHERE ( fr_i(:,:) > 0.001_wp )
692            ! sea-ice present, we forget about the update, using what we backed up before call to turb_*()
693            ptsk(:,:) = zztmp1(:,:)
694            pssq(:,:) = zztmp2(:,:)
695         END WHERE
696      END IF
697
698      !  Turbulent fluxes over ocean  => BULK_FORMULA @ sbcblk_phy.F90
699      ! -------------------------------------------------------------
700
701      IF( ln_abl ) THEN         !==  ABL formulation  ==!   multiplication by rho_air and turbulent fluxes computation done in ablstp
702         DO_2D( nn_hls, nn_hls, nn_hls, nn_hls )
703            zztmp = zU_zu(ji,jj)
704            wndm(ji,jj)   = zztmp                   ! Store zU_zu in wndm to compute ustar2 in ablmod
705            pcd_du(ji,jj) = zztmp * zcd_oce(ji,jj)
706            psen(ji,jj)   = zztmp * zch_oce(ji,jj)
707            pevp(ji,jj)   = zztmp * zce_oce(ji,jj)
708            rhoa(ji,jj)   = rho_air( ptair(ji,jj), phumi(ji,jj), pslp(ji,jj) )
709         END_2D
710      ELSE                      !==  BLK formulation  ==!   turbulent fluxes computation
711         CALL BULK_FORMULA( rn_zu, ptsk(:,:), pssq(:,:), t_zu(:,:), q_zu(:,:), &
712            &               zcd_oce(:,:), zch_oce(:,:), zce_oce(:,:),          &
713            &               wndm(:,:), zU_zu(:,:), pslp(:,:),                  &
714            &               taum(:,:), psen(:,:), zqla(:,:),                   &
715            &               pEvap=pevp(:,:), prhoa=rhoa(:,:), pfact_evap=rn_efac )
716
717         zqla(:,:) = zqla(:,:) * tmask(:,:,1)
718         psen(:,:) = psen(:,:) * tmask(:,:,1)
719         taum(:,:) = taum(:,:) * tmask(:,:,1)
720         pevp(:,:) = pevp(:,:) * tmask(:,:,1)
721
722         DO_2D( nn_hls, nn_hls, nn_hls, nn_hls )
723            IF( wndm(ji,jj) > 0._wp ) THEN
724               zztmp = taum(ji,jj) / wndm(ji,jj)
725#if defined key_cyclone
726               ztau_i(ji,jj) = zztmp * zwnd_i(ji,jj)
727               ztau_j(ji,jj) = zztmp * zwnd_j(ji,jj)
728#else
729               ztau_i(ji,jj) = zztmp * pwndi(ji,jj)
730               ztau_j(ji,jj) = zztmp * pwndj(ji,jj)
731#endif
732            ELSE
733               ztau_i(ji,jj) = 0._wp
734               ztau_j(ji,jj) = 0._wp                 
735            ENDIF
736         END_2D
737
738         IF( ln_crt_fbk ) THEN   ! aply eq. 10 and 11 of Renault et al. 2020 (doi: 10.1029/2019MS001715)
739            zstmax = MIN( rn_stau_a * 3._wp + rn_stau_b, 0._wp )   ! set the max value of Stau corresponding to a wind of 3 m/s (<0)
740            DO_2D( 0, 1, 0, 1 )   ! end at jpj and jpi, as ztau_j(ji,jj+1) ztau_i(ji+1,jj) used in the next loop
741               zstau = MIN( rn_stau_a * wndm(ji,jj) + rn_stau_b, zstmax )   ! stau (<0) must be smaller than zstmax
742               ztau_i(ji,jj) = ztau_i(ji,jj) + zstau * ( 0.5_wp * ( pu(ji-1,jj  ) + pu(ji,jj) ) - puatm(ji,jj) )
743               ztau_j(ji,jj) = ztau_j(ji,jj) + zstau * ( 0.5_wp * ( pv(ji  ,jj-1) + pv(ji,jj) ) - pvatm(ji,jj) )
744               taum(ji,jj) = SQRT( ztau_i(ji,jj) * ztau_i(ji,jj) + ztau_j(ji,jj) * ztau_j(ji,jj) )
745            END_2D
746         ENDIF
747
748         ! ... utau, vtau at U- and V_points, resp.
749         !     Note the use of 0.5*(2-umask) in order to unmask the stress along coastlines
750         !     Note that coastal wind stress is not used in the code... so this extra care has no effect
751         DO_2D( 0, 0, 0, 0 )              ! start loop at 2, in case ln_crt_fbk = T
752            utau(ji,jj) = 0.5 * ( 2. - umask(ji,jj,1) ) * ( ztau_i(ji,jj) + ztau_i(ji+1,jj  ) ) &
753               &              * MAX(tmask(ji,jj,1),tmask(ji+1,jj,1))
754            vtau(ji,jj) = 0.5 * ( 2. - vmask(ji,jj,1) ) * ( ztau_j(ji,jj) + ztau_j(ji  ,jj+1) ) &
755               &              * MAX(tmask(ji,jj,1),tmask(ji,jj+1,1))
756         END_2D
757
758         IF( ln_crt_fbk ) THEN
759#if defined key_mpi3
760            CALL lbc_lnk_nc_multi( 'sbcblk', utau, 'U', -1., vtau, 'V', -1., taum, 'T', -1. )
761#else
762            CALL lbc_lnk_multi( 'sbcblk', utau, 'U', -1., vtau, 'V', -1., taum, 'T', -1. )
763#endif
764         ELSE
765#if defined key_mpi3
766            CALL lbc_lnk_nc_multi( 'sbcblk', utau, 'U', -1., vtau, 'V', -1. )
767#else
768            CALL lbc_lnk_multi( 'sbcblk', utau, 'U', -1., vtau, 'V', -1. )
769#endif
770         ENDIF
771
772         CALL iom_put( "taum_oce", taum )   ! output wind stress module
773
774         IF(sn_cfctl%l_prtctl) THEN
775            CALL prt_ctl( tab2d_1=wndm  , clinfo1=' blk_oce_1: wndm   : ')
776            CALL prt_ctl( tab2d_1=utau  , clinfo1=' blk_oce_1: utau   : ', mask1=umask,   &
777               &          tab2d_2=vtau  , clinfo2='            vtau   : ', mask2=vmask )
778         ENDIF
779         !
780      ENDIF !IF( ln_abl )
781     
782      ptsk(:,:) = ( ptsk(:,:) - rt0 ) * tmask(:,:,1)  ! Back to Celsius
783           
784      IF( ln_skin_cs .OR. ln_skin_wl ) THEN
785         CALL iom_put( "t_skin" ,  ptsk        )  ! T_skin in Celsius
786         CALL iom_put( "dt_skin" , ptsk - pst  )  ! T_skin - SST temperature difference...
787      ENDIF
788
789      IF(sn_cfctl%l_prtctl) THEN
790         CALL prt_ctl( tab2d_1=pevp  , clinfo1=' blk_oce_1: pevp   : ' )
791         CALL prt_ctl( tab2d_1=psen  , clinfo1=' blk_oce_1: psen   : ' )
792         CALL prt_ctl( tab2d_1=pssq  , clinfo1=' blk_oce_1: pssq   : ' )
793      ENDIF
794      !
795   END SUBROUTINE blk_oce_1
796
797
798   SUBROUTINE blk_oce_2( ptair, pqsr, pqlw, pprec,   &   ! <<= in
799      &                  psnow, ptsk, psen, pevp     )   ! <<= in
800      !!---------------------------------------------------------------------
801      !!                     ***  ROUTINE blk_oce_2  ***
802      !!
803      !! ** Purpose :   finalize the momentum, heat and freshwater fluxes computation
804      !!                at the ocean surface at each time step knowing Cd, Ch, Ce and
805      !!                atmospheric variables (from ABL or external data)
806      !!
807      !! ** Outputs : - utau    : i-component of the stress at U-point  (N/m2)
808      !!              - vtau    : j-component of the stress at V-point  (N/m2)
809      !!              - taum    : Wind stress module at T-point         (N/m2)
810      !!              - wndm    : Wind speed module at T-point          (m/s)
811      !!              - qsr     : Solar heat flux over the ocean        (W/m2)
812      !!              - qns     : Non Solar heat flux over the ocean    (W/m2)
813      !!              - emp     : evaporation minus precipitation       (kg/m2/s)
814      !!---------------------------------------------------------------------
815      REAL(wp), INTENT(in), DIMENSION(:,:) ::   ptair
816      REAL(wp), INTENT(in), DIMENSION(:,:) ::   pqsr
817      REAL(wp), INTENT(in), DIMENSION(:,:) ::   pqlw
818      REAL(wp), INTENT(in), DIMENSION(:,:) ::   pprec
819      REAL(wp), INTENT(in), DIMENSION(:,:) ::   psnow
820      REAL(wp), INTENT(in), DIMENSION(:,:) ::   ptsk   ! SKIN surface temperature   [Celsius]
821      REAL(wp), INTENT(in), DIMENSION(:,:) ::   psen
822      REAL(wp), INTENT(in), DIMENSION(:,:) ::   pevp
823      !
824      INTEGER  ::   ji, jj               ! dummy loop indices
825      REAL(wp) ::   zztmp,zz1,zz2,zz3    ! local variable
826      REAL(wp), DIMENSION(jpi,jpj) ::   ztskk             ! skin temp. in Kelvin
827      REAL(wp), DIMENSION(jpi,jpj) ::   zqlw              ! long wave and sensible heat fluxes     
828      REAL(wp), DIMENSION(jpi,jpj) ::   zqla              ! latent heat fluxes and evaporation
829      !!---------------------------------------------------------------------
830      !
831      ! local scalars ( place there for vector optimisation purposes)
832
833
834      ztskk(:,:) = ptsk(:,:) + rt0  ! => ptsk in Kelvin rather than Celsius
835     
836      ! ----------------------------------------------------------------------------- !
837      !     III    Net longwave radiative FLUX                                        !
838      ! ----------------------------------------------------------------------------- !
839
840      !! LB: now moved after Turbulent fluxes because must use the skin temperature rather that the SST
841      !! (ztskk is skin temperature if ln_skin_cs==.TRUE. .OR. ln_skin_wl==.TRUE.)
842      zqlw(:,:) = emiss_w * ( pqlw(:,:) - stefan*ztskk(:,:)*ztskk(:,:)*ztskk(:,:)*ztskk(:,:) ) * tmask(:,:,1)   ! Net radiative longwave flux
843
844      !  Latent flux over ocean
845      ! -----------------------
846
847      ! use scalar version of L_vap() for AGRIF compatibility
848      DO_2D( nn_hls, nn_hls, nn_hls, nn_hls )
849         zqla(ji,jj) = - L_vap( ztskk(ji,jj) ) * pevp(ji,jj)    ! Latent Heat flux !!GS: possibility to add a global qla to avoid recomputation after abl update
850      END_2D
851
852      IF(sn_cfctl%l_prtctl) THEN
853         CALL prt_ctl( tab2d_1=zqla  , clinfo1=' blk_oce_2: zqla   : ' )
854         CALL prt_ctl( tab2d_1=zqlw  , clinfo1=' blk_oce_2: zqlw   : ', tab2d_2=qsr, clinfo2=' qsr : ' )
855
856      ENDIF
857
858      ! ----------------------------------------------------------------------------- !
859      !     IV    Total FLUXES                                                       !
860      ! ----------------------------------------------------------------------------- !
861      !
862      emp (:,:) = (  pevp(:,:)                                       &   ! mass flux (evap. - precip.)
863         &         - pprec(:,:) * rn_pfac  ) * tmask(:,:,1)
864      !
865      qns(:,:) = zqlw(:,:) + psen(:,:) + zqla(:,:)                   &   ! Downward Non Solar
866         &     - psnow(:,:) * rn_pfac * rLfus                        &   ! remove latent melting heat for solid precip
867         &     - pevp(:,:) * ptsk(:,:) * rcp                         &   ! remove evap heat content at SST
868         &     + ( pprec(:,:) - psnow(:,:) ) * rn_pfac               &   ! add liquid precip heat content at Tair
869         &     * ( ptair(:,:) - rt0 ) * rcp                          &
870         &     + psnow(:,:) * rn_pfac                                &   ! add solid  precip heat content at min(Tair,Tsnow)
871         &     * ( MIN( ptair(:,:), rt0 ) - rt0 ) * rcpi
872      qns(:,:) = qns(:,:) * tmask(:,:,1)
873      !
874#if defined key_si3
875      qns_oce(:,:) = zqlw(:,:) + psen(:,:) + zqla(:,:)                             ! non solar without emp (only needed by SI3)
876      qsr_oce(:,:) = qsr(:,:)
877#endif
878      !
879      CALL iom_put( "rho_air"  , rhoa*tmask(:,:,1) )       ! output air density [kg/m^3]
880      CALL iom_put( "evap_oce" , pevp )                    ! evaporation
881      CALL iom_put( "qlw_oce"  , zqlw )                    ! output downward longwave heat over the ocean
882      CALL iom_put( "qsb_oce"  , psen )                    ! output downward sensible heat over the ocean
883      CALL iom_put( "qla_oce"  , zqla )                    ! output downward latent   heat over the ocean
884      tprecip(:,:) = pprec(:,:) * rn_pfac * tmask(:,:,1)   ! output total precipitation [kg/m2/s]
885      sprecip(:,:) = psnow(:,:) * rn_pfac * tmask(:,:,1)   ! output solid precipitation [kg/m2/s]
886      CALL iom_put( 'snowpre', sprecip )                   ! Snow
887      CALL iom_put( 'precip' , tprecip )                   ! Total precipitation
888      !
889      IF ( nn_ice == 0 ) THEN
890         CALL iom_put( "qemp_oce" , qns-zqlw-psen-zqla )   ! output downward heat content of E-P over the ocean
891         CALL iom_put( "qns_oce"  ,   qns  )               ! output downward non solar heat over the ocean
892         CALL iom_put( "qsr_oce"  ,   qsr  )               ! output downward solar heat over the ocean
893         CALL iom_put( "qt_oce"   ,   qns+qsr )            ! output total downward heat over the ocean
894      ENDIF
895      !
896      IF(sn_cfctl%l_prtctl) THEN
897         CALL prt_ctl(tab2d_1=zqlw , clinfo1=' blk_oce_2: zqlw  : ')
898         CALL prt_ctl(tab2d_1=zqla , clinfo1=' blk_oce_2: zqla  : ', tab2d_2=qsr  , clinfo2=' qsr   : ')
899         CALL prt_ctl(tab2d_1=emp  , clinfo1=' blk_oce_2: emp   : ')
900      ENDIF
901      !
902   END SUBROUTINE blk_oce_2
903
904
905#if defined key_si3
906   !!----------------------------------------------------------------------
907   !!   'key_si3'                                       SI3 sea-ice model
908   !!----------------------------------------------------------------------
909   !!   blk_ice_1   : provide the air-ice stress
910   !!   blk_ice_2   : provide the heat and mass fluxes at air-ice interface
911   !!   blk_ice_qcn : provide ice surface temperature and snow/ice conduction flux (emulating conduction flux)
912   !!   Cdn10_Lupkes2012 : Lupkes et al. (2012) air-ice drag
913   !!   Cdn10_Lupkes2015 : Lupkes et al. (2015) air-ice drag
914   !!----------------------------------------------------------------------
915
916   SUBROUTINE blk_ice_1( pwndi, pwndj, ptair, phumi, pslp , puice, pvice, ptsui,  &   ! inputs
917      &                  putaui, pvtaui, pseni, pevpi, pssqi, pcd_dui             )   ! optional outputs
918      !!---------------------------------------------------------------------
919      !!                     ***  ROUTINE blk_ice_1  ***
920      !!
921      !! ** Purpose :   provide the surface boundary condition over sea-ice
922      !!
923      !! ** Method  :   compute momentum using bulk formulation
924      !!                formulea, ice variables and read atmospheric fields.
925      !!                NB: ice drag coefficient is assumed to be a constant
926      !!---------------------------------------------------------------------
927      REAL(wp) , INTENT(in   ), DIMENSION(:,:  ) ::   pslp    ! sea-level pressure [Pa]
928      REAL(wp) , INTENT(in   ), DIMENSION(:,:  ) ::   pwndi   ! atmospheric wind at T-point [m/s]
929      REAL(wp) , INTENT(in   ), DIMENSION(:,:  ) ::   pwndj   ! atmospheric wind at T-point [m/s]
930      REAL(wp) , INTENT(in   ), DIMENSION(:,:  ) ::   ptair   ! atmospheric wind at T-point [m/s]
931      REAL(wp) , INTENT(in   ), DIMENSION(:,:  ) ::   phumi   ! atmospheric wind at T-point [m/s]
932      REAL(wp) , INTENT(in   ), DIMENSION(:,:  ) ::   puice   ! sea-ice velocity on I or C grid [m/s]
933      REAL(wp) , INTENT(in   ), DIMENSION(:,:  ) ::   pvice   ! "
934      REAL(wp) , INTENT(in   ), DIMENSION(:,:  ) ::   ptsui   ! sea-ice surface temperature [K]
935      REAL(wp) , INTENT(  out), DIMENSION(:,:  ), OPTIONAL ::   putaui  ! if ln_blk
936      REAL(wp) , INTENT(  out), DIMENSION(:,:  ), OPTIONAL ::   pvtaui  ! if ln_blk
937      REAL(wp) , INTENT(  out), DIMENSION(:,:  ), OPTIONAL ::   pseni   ! if ln_abl
938      REAL(wp) , INTENT(  out), DIMENSION(:,:  ), OPTIONAL ::   pevpi   ! if ln_abl
939      REAL(wp) , INTENT(  out), DIMENSION(:,:  ), OPTIONAL ::   pssqi   ! if ln_abl
940      REAL(wp) , INTENT(  out), DIMENSION(:,:  ), OPTIONAL ::   pcd_dui ! if ln_abl
941      !
942      INTEGER  ::   ji, jj    ! dummy loop indices
943      REAL(wp) ::   zootm_su                      ! sea-ice surface mean temperature
944      REAL(wp) ::   zztmp1, zztmp2                ! temporary arrays
945      REAL(wp), DIMENSION(jpi,jpj) ::   zcd_dui   ! transfer coefficient for momentum      (tau)
946      !!---------------------------------------------------------------------
947      !
948
949      ! ------------------------------------------------------------ !
950      !    Wind module relative to the moving ice ( U10m - U_ice )   !
951      ! ------------------------------------------------------------ !
952      ! C-grid ice dynamics :   U & V-points (same as ocean)
953      DO_2D( nn_hls, nn_hls, nn_hls, nn_hls )
954         wndm_ice(ji,jj) = SQRT( pwndi(ji,jj) * pwndi(ji,jj) + pwndj(ji,jj) * pwndj(ji,jj) )
955      END_2D
956      !
957      ! Make ice-atm. drag dependent on ice concentration
958      IF    ( ln_Cd_L12 ) THEN   ! calculate new drag from Lupkes(2012) equations
959         CALL Cdn10_Lupkes2012( Cd_ice )
960         Ch_ice(:,:) = Cd_ice(:,:)       ! momentum and heat transfer coef. are considered identical
961         Ce_ice(:,:) = Cd_ice(:,:)
962      ELSEIF( ln_Cd_L15 ) THEN   ! calculate new drag from Lupkes(2015) equations
963         CALL Cdn10_Lupkes2015( ptsui, pslp, Cd_ice, Ch_ice )
964         Ce_ice(:,:) = Ch_ice(:,:)       ! sensible and latent heat transfer coef. are considered identical
965      ENDIF
966     
967      IF( iom_use('Cd_ice') ) CALL iom_put("Cd_ice", Cd_ice)
968      IF( iom_use('Ce_ice') ) CALL iom_put("Ce_ice", Ce_ice)
969      IF( iom_use('Ch_ice') ) CALL iom_put("Ch_ice", Ch_ice)
970     
971      ! local scalars ( place there for vector optimisation purposes)
972      zcd_dui(:,:) = wndm_ice(:,:) * Cd_ice(:,:)
973
974      IF( ln_blk ) THEN
975         ! ---------------------------------------------------- !
976         !    Wind stress relative to nonmoving ice ( U10m )    !
977         ! ---------------------------------------------------- !
978         ! supress moving ice in wind stress computation as we don't know how to do it properly...
979         DO_2D( 0, 1, 0, 1 )    ! at T point
980            putaui(ji,jj) = rhoa(ji,jj) * zcd_dui(ji,jj) * pwndi(ji,jj)
981            pvtaui(ji,jj) = rhoa(ji,jj) * zcd_dui(ji,jj) * pwndj(ji,jj)
982         END_2D
983         !
984         DO_2D( 0, 0, 0, 0 )    ! U & V-points (same as ocean).
985            ! take care of the land-sea mask to avoid "pollution" of coastal stress. p[uv]taui used in frazil and  rheology
986            zztmp1 = 0.5_wp * ( 2. - umask(ji,jj,1) ) * MAX( tmask(ji,jj,1),tmask(ji+1,jj  ,1) )
987            zztmp2 = 0.5_wp * ( 2. - vmask(ji,jj,1) ) * MAX( tmask(ji,jj,1),tmask(ji  ,jj+1,1) )
988            putaui(ji,jj) = zztmp1 * ( putaui(ji,jj) + putaui(ji+1,jj  ) )
989            pvtaui(ji,jj) = zztmp2 * ( pvtaui(ji,jj) + pvtaui(ji  ,jj+1) )
990         END_2D
991#if defined key_mpi3
992         CALL lbc_lnk_nc_multi( 'sbcblk', putaui, 'U', -1._wp, pvtaui, 'V', -1._wp )
993#else
994         CALL lbc_lnk_multi( 'sbcblk', putaui, 'U', -1._wp, pvtaui, 'V', -1._wp )
995#endif
996         !
997         IF(sn_cfctl%l_prtctl)  CALL prt_ctl( tab2d_1=putaui  , clinfo1=' blk_ice: putaui : '   &
998            &                               , tab2d_2=pvtaui  , clinfo2='          pvtaui : ' )
999      ELSE ! ln_abl
1000         zztmp1 = 11637800.0_wp
1001         zztmp2 =    -5897.8_wp
1002         DO_2D( nn_hls, nn_hls, nn_hls, nn_hls )
1003            pcd_dui(ji,jj) = zcd_dui (ji,jj)
1004            pseni  (ji,jj) = wndm_ice(ji,jj) * Ch_ice(ji,jj)
1005            pevpi  (ji,jj) = wndm_ice(ji,jj) * Ce_ice(ji,jj)
1006            zootm_su       = zztmp2 / ptsui(ji,jj)   ! ptsui is in K (it can't be zero ??)
1007            pssqi  (ji,jj) = zztmp1 * EXP( zootm_su ) / rhoa(ji,jj)
1008         END_2D
1009      ENDIF
1010      !
1011      IF(sn_cfctl%l_prtctl)  CALL prt_ctl(tab2d_1=wndm_ice  , clinfo1=' blk_ice: wndm_ice : ')
1012      !
1013   END SUBROUTINE blk_ice_1
1014
1015
1016   SUBROUTINE blk_ice_2( ptsu, phs, phi, palb, ptair, phumi, pslp, pqlw, pprec, psnow  )
1017      !!---------------------------------------------------------------------
1018      !!                     ***  ROUTINE blk_ice_2  ***
1019      !!
1020      !! ** Purpose :   provide the heat and mass fluxes at air-ice interface
1021      !!
1022      !! ** Method  :   compute heat and freshwater exchanged
1023      !!                between atmosphere and sea-ice using bulk formulation
1024      !!                formulea, ice variables and read atmmospheric fields.
1025      !!
1026      !! caution : the net upward water flux has with mm/day unit
1027      !!---------------------------------------------------------------------
1028      REAL(wp), DIMENSION(:,:,:), INTENT(in)  ::   ptsu   ! sea ice surface temperature [K]
1029      REAL(wp), DIMENSION(:,:,:), INTENT(in)  ::   phs    ! snow thickness
1030      REAL(wp), DIMENSION(:,:,:), INTENT(in)  ::   phi    ! ice thickness
1031      REAL(wp), DIMENSION(:,:,:), INTENT(in)  ::   palb   ! ice albedo (all skies)
1032      REAL(wp), DIMENSION(:,:  ), INTENT(in)  ::   ptair
1033      REAL(wp), DIMENSION(:,:  ), INTENT(in)  ::   phumi
1034      REAL(wp), DIMENSION(:,:  ), INTENT(in)  ::   pslp
1035      REAL(wp), DIMENSION(:,:  ), INTENT(in)  ::   pqlw
1036      REAL(wp), DIMENSION(:,:  ), INTENT(in)  ::   pprec
1037      REAL(wp), DIMENSION(:,:  ), INTENT(in)  ::   psnow
1038      !!
1039      INTEGER  ::   ji, jj, jl               ! dummy loop indices
1040      REAL(wp) ::   zst3                     ! local variable
1041      REAL(wp) ::   zcoef_dqlw, zcoef_dqla   !   -      -
1042      REAL(wp) ::   zztmp, zztmp2, z1_rLsub  !   -      -
1043      REAL(wp), DIMENSION(jpi,jpj,jpl) ::   z1_st         ! inverse of surface temperature
1044      REAL(wp), DIMENSION(jpi,jpj,jpl) ::   z_qlw         ! long wave heat flux over ice
1045      REAL(wp), DIMENSION(jpi,jpj,jpl) ::   z_qsb         ! sensible  heat flux over ice
1046      REAL(wp), DIMENSION(jpi,jpj,jpl) ::   z_dqlw        ! long wave heat sensitivity over ice
1047      REAL(wp), DIMENSION(jpi,jpj,jpl) ::   z_dqsb        ! sensible  heat sensitivity over ice
1048      REAL(wp), DIMENSION(jpi,jpj)     ::   zevap, zsnw   ! evaporation and snw distribution after wind blowing (SI3)
1049      REAL(wp), DIMENSION(jpi,jpj)     ::   zqair         ! specific humidity of air at z=rn_zqt [kg/kg] !LB
1050      REAL(wp), DIMENSION(jpi,jpj)     ::   ztmp, ztmp2
1051      REAL(wp), DIMENSION(jpi,jpj)     ::   ztri
1052      !!---------------------------------------------------------------------
1053      !
1054      zcoef_dqlw = 4._wp * 0.95_wp * stefan             ! local scalars
1055      zcoef_dqla = -rLsub * 11637800._wp * (-5897.8_wp) !LB: BAD!
1056      !
1057      SELECT CASE( nhumi )
1058      CASE( np_humi_sph )
1059         zqair(:,:) =  phumi(:,:)      ! what we read in file is already a spec. humidity!
1060      CASE( np_humi_dpt )
1061         zqair(:,:) = q_sat( phumi(:,:), pslp )
1062      CASE( np_humi_rlh )
1063         zqair(:,:) = q_air_rh( 0.01_wp*phumi(:,:), ptair(:,:), pslp(:,:) ) !LB: 0.01 => RH is % percent in file
1064      END SELECT
1065      !
1066      zztmp = 1. / ( 1. - albo )
1067      WHERE( ptsu(:,:,:) /= 0._wp )
1068         z1_st(:,:,:) = 1._wp / ptsu(:,:,:)
1069      ELSEWHERE
1070         z1_st(:,:,:) = 0._wp
1071      END WHERE
1072      !                                     ! ========================== !
1073      DO jl = 1, jpl                        !  Loop over ice categories  !
1074         !                                  ! ========================== !
1075         DO jj = 1 , jpj
1076            DO ji = 1, jpi
1077               ! ----------------------------!
1078               !      I   Radiative FLUXES   !
1079               ! ----------------------------!
1080               zst3 = ptsu(ji,jj,jl) * ptsu(ji,jj,jl) * ptsu(ji,jj,jl)
1081               ! Short Wave (sw)
1082               qsr_ice(ji,jj,jl) = zztmp * ( 1. - palb(ji,jj,jl) ) * qsr(ji,jj)
1083               ! Long  Wave (lw)
1084               z_qlw(ji,jj,jl) = 0.95 * ( pqlw(ji,jj) - stefan * ptsu(ji,jj,jl) * zst3 ) * tmask(ji,jj,1)
1085               ! lw sensitivity
1086               z_dqlw(ji,jj,jl) = zcoef_dqlw * zst3
1087
1088               ! ----------------------------!
1089               !     II    Turbulent FLUXES  !
1090               ! ----------------------------!
1091
1092               ! ... turbulent heat fluxes with Ch_ice recalculated in blk_ice_1
1093               ! Sensible Heat
1094               z_qsb(ji,jj,jl) = rhoa(ji,jj) * rCp_air * Ch_ice(ji,jj) * wndm_ice(ji,jj) * (ptsu(ji,jj,jl) - ptair(ji,jj))
1095               ! Latent Heat
1096               zztmp2 = EXP( -5897.8 * z1_st(ji,jj,jl) )
1097               qla_ice(ji,jj,jl) = rn_efac * MAX( 0.e0, rhoa(ji,jj) * rLsub  * Ce_ice(ji,jj) * wndm_ice(ji,jj) *  &
1098                  &                ( 11637800. * zztmp2 / rhoa(ji,jj) - zqair(ji,jj) ) )
1099               ! Latent heat sensitivity for ice (Dqla/Dt)
1100               IF( qla_ice(ji,jj,jl) > 0._wp ) THEN
1101                  dqla_ice(ji,jj,jl) = rn_efac * zcoef_dqla * Ce_ice(ji,jj) * wndm_ice(ji,jj) *  &
1102                     &                 z1_st(ji,jj,jl) * z1_st(ji,jj,jl) * zztmp2
1103               ELSE
1104                  dqla_ice(ji,jj,jl) = 0._wp
1105               ENDIF
1106
1107               ! Sensible heat sensitivity (Dqsb_ice/Dtn_ice)
1108               z_dqsb(ji,jj,jl) = rhoa(ji,jj) * rCp_air * Ch_ice(ji,jj) * wndm_ice(ji,jj)
1109
1110               ! ----------------------------!
1111               !     III    Total FLUXES     !
1112               ! ----------------------------!
1113               ! Downward Non Solar flux
1114               qns_ice (ji,jj,jl) =     z_qlw (ji,jj,jl) - z_qsb (ji,jj,jl) - qla_ice (ji,jj,jl)
1115               ! Total non solar heat flux sensitivity for ice
1116               dqns_ice(ji,jj,jl) = - ( z_dqlw(ji,jj,jl) + z_dqsb(ji,jj,jl) + dqla_ice(ji,jj,jl) )
1117            END DO
1118            !
1119         END DO
1120         !
1121      END DO
1122      !
1123      tprecip(:,:) = pprec(:,:) * rn_pfac * tmask(:,:,1)  ! total precipitation [kg/m2/s]
1124      sprecip(:,:) = psnow(:,:) * rn_pfac * tmask(:,:,1)  ! solid precipitation [kg/m2/s]
1125      CALL iom_put( 'snowpre', sprecip )                  ! Snow precipitation
1126      CALL iom_put( 'precip' , tprecip )                  ! Total precipitation
1127
1128      ! --- evaporation --- !
1129      z1_rLsub = 1._wp / rLsub
1130      evap_ice (:,:,:) = rn_efac * qla_ice (:,:,:) * z1_rLsub    ! sublimation
1131      devap_ice(:,:,:) = rn_efac * dqla_ice(:,:,:) * z1_rLsub    ! d(sublimation)/dT
1132      zevap    (:,:)   = emp(:,:) + tprecip(:,:)   ! evaporation over ocean  !LB: removed rn_efac here, correct???
1133
1134      ! --- evaporation minus precipitation --- !
1135      zsnw(:,:) = 0._wp
1136      CALL ice_var_snwblow( (1.-at_i_b(:,:)), zsnw )  ! snow distribution over ice after wind blowing
1137      emp_oce(:,:) = ( 1._wp - at_i_b(:,:) ) * zevap(:,:) - ( tprecip(:,:) - sprecip(:,:) ) - sprecip(:,:) * (1._wp - zsnw )
1138      emp_ice(:,:) = SUM( a_i_b(:,:,:) * evap_ice(:,:,:), dim=3 ) - sprecip(:,:) * zsnw
1139      emp_tot(:,:) = emp_oce(:,:) + emp_ice(:,:)
1140
1141      ! --- heat flux associated with emp --- !
1142      qemp_oce(:,:) = - ( 1._wp - at_i_b(:,:) ) * zevap(:,:) * sst_m(:,:) * rcp                  & ! evap at sst
1143         &          + ( tprecip(:,:) - sprecip(:,:) ) * ( ptair(:,:) - rt0 ) * rcp               & ! liquid precip at Tair
1144         &          +   sprecip(:,:) * ( 1._wp - zsnw ) *                                        & ! solid precip at min(Tair,Tsnow)
1145         &              ( ( MIN( ptair(:,:), rt0 ) - rt0 ) * rcpi * tmask(:,:,1) - rLfus )
1146      qemp_ice(:,:) =   sprecip(:,:) * zsnw *                                                    & ! solid precip (only)
1147         &              ( ( MIN( ptair(:,:), rt0 ) - rt0 ) * rcpi * tmask(:,:,1) - rLfus )
1148
1149      ! --- total solar and non solar fluxes --- !
1150      qns_tot(:,:) = ( 1._wp - at_i_b(:,:) ) * qns_oce(:,:) + SUM( a_i_b(:,:,:) * qns_ice(:,:,:), dim=3 )  &
1151         &           + qemp_ice(:,:) + qemp_oce(:,:)
1152      qsr_tot(:,:) = ( 1._wp - at_i_b(:,:) ) * qsr_oce(:,:) + SUM( a_i_b(:,:,:) * qsr_ice(:,:,:), dim=3 )
1153
1154      ! --- heat content of precip over ice in J/m3 (to be used in 1D-thermo) --- !
1155      qprec_ice(:,:) = rhos * ( ( MIN( ptair(:,:), rt0 ) - rt0 ) * rcpi * tmask(:,:,1) - rLfus )
1156
1157      ! --- heat content of evap over ice in W/m2 (to be used in 1D-thermo) ---
1158      DO jl = 1, jpl
1159         qevap_ice(:,:,jl) = 0._wp ! should be -evap_ice(:,:,jl)*( ( Tice - rt0 ) * rcpi * tmask(:,:,1) )
1160         !                         ! But we do not have Tice => consider it at 0degC => evap=0
1161      END DO
1162
1163      ! --- shortwave radiation transmitted thru the surface scattering layer (W/m2) --- !
1164      IF( nn_qtrice == 0 ) THEN
1165         ! formulation derived from Grenfell and Maykut (1977), where transmission rate
1166         !    1) depends on cloudiness
1167         !    2) is 0 when there is any snow
1168         !    3) tends to 1 for thin ice
1169         ztri(:,:) = 0.18 * ( 1.0 - cloud_fra(:,:) ) + 0.35 * cloud_fra(:,:)  ! surface transmission when hi>10cm
1170         DO jl = 1, jpl
1171            WHERE    ( phs(:,:,jl) <= 0._wp .AND. phi(:,:,jl) <  0.1_wp )     ! linear decrease from hi=0 to 10cm 
1172               qtr_ice_top(:,:,jl) = qsr_ice(:,:,jl) * ( ztri(:,:) + ( 1._wp - ztri(:,:) ) * ( 1._wp - phi(:,:,jl) * 10._wp ) )
1173            ELSEWHERE( phs(:,:,jl) <= 0._wp .AND. phi(:,:,jl) >= 0.1_wp )     ! constant (ztri) when hi>10cm
1174               qtr_ice_top(:,:,jl) = qsr_ice(:,:,jl) * ztri(:,:)
1175            ELSEWHERE                                                         ! zero when hs>0
1176               qtr_ice_top(:,:,jl) = 0._wp 
1177            END WHERE
1178         ENDDO
1179      ELSEIF( nn_qtrice == 1 ) THEN
1180         ! formulation is derived from the thesis of M. Lebrun (2019).
1181         !    It represents the best fit using several sets of observations
1182         !    It comes with snow conductivities adapted to freezing/melting conditions (see icethd_zdf_bl99.F90)
1183         qtr_ice_top(:,:,:) = 0.3_wp * qsr_ice(:,:,:)
1184      ENDIF
1185      !
1186      IF( iom_use('evap_ao_cea') .OR. iom_use('hflx_evap_cea') ) THEN
1187         ztmp(:,:) = zevap(:,:) * ( 1._wp - at_i_b(:,:) )
1188         IF( iom_use('evap_ao_cea'  ) )  CALL iom_put( 'evap_ao_cea'  , ztmp(:,:) * tmask(:,:,1) )   ! ice-free oce evap (cell average)
1189         IF( iom_use('hflx_evap_cea') )  CALL iom_put( 'hflx_evap_cea', ztmp(:,:) * sst_m(:,:) * rcp * tmask(:,:,1) )   ! heat flux from evap (cell average)
1190      ENDIF
1191      IF( iom_use('hflx_rain_cea') ) THEN
1192         ztmp(:,:) = rcp * ( SUM( (ptsu-rt0) * a_i_b, dim=3 ) + sst_m(:,:) * ( 1._wp - at_i_b(:,:) ) )
1193         IF( iom_use('hflx_rain_cea') )  CALL iom_put( 'hflx_rain_cea', ( tprecip(:,:) - sprecip(:,:) ) * ztmp(:,:) )   ! heat flux from rain (cell average)
1194      ENDIF
1195      IF( iom_use('hflx_snow_cea') .OR. iom_use('hflx_snow_ao_cea') .OR. iom_use('hflx_snow_ai_cea')  )  THEN
1196         WHERE( SUM( a_i_b, dim=3 ) > 1.e-10 )
1197            ztmp(:,:) = rcpi * SUM( (ptsu-rt0) * a_i_b, dim=3 ) / SUM( a_i_b, dim=3 )
1198         ELSEWHERE
1199            ztmp(:,:) = rcp * sst_m(:,:)
1200         ENDWHERE
1201         ztmp2(:,:) = sprecip(:,:) * ( ztmp(:,:) - rLfus )
1202         IF( iom_use('hflx_snow_cea')    ) CALL iom_put('hflx_snow_cea'   , ztmp2(:,:) ) ! heat flux from snow (cell average)
1203         IF( iom_use('hflx_snow_ao_cea') ) CALL iom_put('hflx_snow_ao_cea', ztmp2(:,:) * ( 1._wp - zsnw(:,:) ) ) ! heat flux from snow (over ocean)
1204         IF( iom_use('hflx_snow_ai_cea') ) CALL iom_put('hflx_snow_ai_cea', ztmp2(:,:) *           zsnw(:,:)   ) ! heat flux from snow (over ice)
1205      ENDIF
1206      !
1207      IF(sn_cfctl%l_prtctl) THEN
1208         CALL prt_ctl(tab3d_1=qla_ice , clinfo1=' blk_ice: qla_ice  : ', tab3d_2=z_qsb   , clinfo2=' z_qsb    : ', kdim=jpl)
1209         CALL prt_ctl(tab3d_1=z_qlw   , clinfo1=' blk_ice: z_qlw    : ', tab3d_2=dqla_ice, clinfo2=' dqla_ice : ', kdim=jpl)
1210         CALL prt_ctl(tab3d_1=z_dqsb  , clinfo1=' blk_ice: z_dqsb   : ', tab3d_2=z_dqlw  , clinfo2=' z_dqlw   : ', kdim=jpl)
1211         CALL prt_ctl(tab3d_1=dqns_ice, clinfo1=' blk_ice: dqns_ice : ', tab3d_2=qsr_ice , clinfo2=' qsr_ice  : ', kdim=jpl)
1212         CALL prt_ctl(tab3d_1=ptsu    , clinfo1=' blk_ice: ptsu     : ', tab3d_2=qns_ice , clinfo2=' qns_ice  : ', kdim=jpl)
1213         CALL prt_ctl(tab2d_1=tprecip , clinfo1=' blk_ice: tprecip  : ', tab2d_2=sprecip , clinfo2=' sprecip  : ')
1214      ENDIF
1215      !
1216   END SUBROUTINE blk_ice_2
1217
1218
1219   SUBROUTINE blk_ice_qcn( ld_virtual_itd, ptsu, ptb, phs, phi )
1220      !!---------------------------------------------------------------------
1221      !!                     ***  ROUTINE blk_ice_qcn  ***
1222      !!
1223      !! ** Purpose :   Compute surface temperature and snow/ice conduction flux
1224      !!                to force sea ice / snow thermodynamics
1225      !!                in the case conduction flux is emulated
1226      !!
1227      !! ** Method  :   compute surface energy balance assuming neglecting heat storage
1228      !!                following the 0-layer Semtner (1976) approach
1229      !!
1230      !! ** Outputs : - ptsu    : sea-ice / snow surface temperature (K)
1231      !!              - qcn_ice : surface inner conduction flux (W/m2)
1232      !!
1233      !!---------------------------------------------------------------------
1234      LOGICAL                   , INTENT(in   ) ::   ld_virtual_itd  ! single-category option
1235      REAL(wp), DIMENSION(:,:,:), INTENT(inout) ::   ptsu            ! sea ice / snow surface temperature
1236      REAL(wp), DIMENSION(:,:)  , INTENT(in   ) ::   ptb             ! sea ice base temperature
1237      REAL(wp), DIMENSION(:,:,:), INTENT(in   ) ::   phs             ! snow thickness
1238      REAL(wp), DIMENSION(:,:,:), INTENT(in   ) ::   phi             ! sea ice thickness
1239      !
1240      INTEGER , PARAMETER ::   nit = 10                  ! number of iterations
1241      REAL(wp), PARAMETER ::   zepsilon = 0.1_wp         ! characteristic thickness for enhanced conduction
1242      !
1243      INTEGER  ::   ji, jj, jl           ! dummy loop indices
1244      INTEGER  ::   iter                 ! local integer
1245      REAL(wp) ::   zfac, zfac2, zfac3   ! local scalars
1246      REAL(wp) ::   zkeff_h, ztsu, ztsu0 !
1247      REAL(wp) ::   zqc, zqnet           !
1248      REAL(wp) ::   zhe, zqa0            !
1249      REAL(wp), DIMENSION(jpi,jpj,jpl) ::   zgfac   ! enhanced conduction factor
1250      !!---------------------------------------------------------------------
1251
1252      ! -------------------------------------!
1253      !      I   Enhanced conduction factor  !
1254      ! -------------------------------------!
1255      ! Emulates the enhancement of conduction by unresolved thin ice (ld_virtual_itd = T)
1256      ! Fichefet and Morales Maqueda, JGR 1997
1257      !
1258      zgfac(:,:,:) = 1._wp
1259
1260      IF( ld_virtual_itd ) THEN
1261         !
1262         zfac  = 1._wp /  ( rn_cnd_s + rcnd_i )
1263         zfac2 = EXP(1._wp) * 0.5_wp * zepsilon
1264         zfac3 = 2._wp / zepsilon
1265         !
1266         DO jl = 1, jpl
1267            DO_2D( nn_hls, nn_hls, nn_hls, nn_hls )
1268               zhe = ( rn_cnd_s * phi(ji,jj,jl) + rcnd_i * phs(ji,jj,jl) ) * zfac                            ! Effective thickness
1269               IF( zhe >=  zfac2 )   zgfac(ji,jj,jl) = MIN( 2._wp, 0.5_wp * ( 1._wp + LOG( zhe * zfac3 ) ) ) ! Enhanced conduction factor
1270            END_2D
1271         END DO
1272         !
1273      ENDIF
1274
1275      ! -------------------------------------------------------------!
1276      !      II   Surface temperature and conduction flux            !
1277      ! -------------------------------------------------------------!
1278      !
1279      zfac = rcnd_i * rn_cnd_s
1280      !
1281      DO jl = 1, jpl
1282         DO_2D( nn_hls, nn_hls, nn_hls, nn_hls )
1283            !
1284            zkeff_h = zfac * zgfac(ji,jj,jl) / &                                    ! Effective conductivity of the snow-ice system divided by thickness
1285               &      ( rcnd_i * phs(ji,jj,jl) + rn_cnd_s * MAX( 0.01, phi(ji,jj,jl) ) )
1286            ztsu    = ptsu(ji,jj,jl)                                                ! Store current iteration temperature
1287            ztsu0   = ptsu(ji,jj,jl)                                                ! Store initial surface temperature
1288            zqa0    = qsr_ice(ji,jj,jl) - qtr_ice_top(ji,jj,jl) + qns_ice(ji,jj,jl) ! Net initial atmospheric heat flux
1289            !
1290            DO iter = 1, nit     ! --- Iterative loop
1291               zqc   = zkeff_h * ( ztsu - ptb(ji,jj) )                              ! Conduction heat flux through snow-ice system (>0 downwards)
1292               zqnet = zqa0 + dqns_ice(ji,jj,jl) * ( ztsu - ptsu(ji,jj,jl) ) - zqc  ! Surface energy budget
1293               ztsu  = ztsu - zqnet / ( dqns_ice(ji,jj,jl) - zkeff_h )              ! Temperature update
1294            END DO
1295            !
1296            ptsu   (ji,jj,jl) = MIN( rt0, ztsu )
1297            qcn_ice(ji,jj,jl) = zkeff_h * ( ptsu(ji,jj,jl) - ptb(ji,jj) )
1298            qns_ice(ji,jj,jl) = qns_ice(ji,jj,jl) + dqns_ice(ji,jj,jl) * ( ptsu(ji,jj,jl) - ztsu0 )
1299            qml_ice(ji,jj,jl) = ( qsr_ice(ji,jj,jl) - qtr_ice_top(ji,jj,jl) + qns_ice(ji,jj,jl) - qcn_ice(ji,jj,jl) )  &
1300               &   * MAX( 0._wp , SIGN( 1._wp, ptsu(ji,jj,jl) - rt0 ) )
1301
1302            ! --- Diagnose the heat loss due to changing non-solar flux (as in icethd_zdf_bl99) --- !
1303            hfx_err_dif(ji,jj) = hfx_err_dif(ji,jj) - ( dqns_ice(ji,jj,jl) * ( ptsu(ji,jj,jl) - ztsu0 ) ) * a_i_b(ji,jj,jl)
1304
1305         END_2D
1306         !
1307      END DO
1308      !
1309   END SUBROUTINE blk_ice_qcn
1310
1311
1312   SUBROUTINE Cdn10_Lupkes2012( pcd )
1313      !!----------------------------------------------------------------------
1314      !!                      ***  ROUTINE  Cdn10_Lupkes2012  ***
1315      !!
1316      !! ** Purpose :    Recompute the neutral air-ice drag referenced at 10m
1317      !!                 to make it dependent on edges at leads, melt ponds and flows.
1318      !!                 After some approximations, this can be resumed to a dependency
1319      !!                 on ice concentration.
1320      !!
1321      !! ** Method :     The parameterization is taken from Lupkes et al. (2012) eq.(50)
1322      !!                 with the highest level of approximation: level4, eq.(59)
1323      !!                 The generic drag over a cell partly covered by ice can be re-written as follows:
1324      !!
1325      !!                 Cd = Cdw * (1-A) + Cdi * A + Ce * (1-A)**(nu+1/(10*beta)) * A**mu
1326      !!
1327      !!                    Ce = 2.23e-3       , as suggested by Lupkes (eq. 59)
1328      !!                    nu = mu = beta = 1 , as suggested by Lupkes (eq. 59)
1329      !!                    A is the concentration of ice minus melt ponds (if any)
1330      !!
1331      !!                 This new drag has a parabolic shape (as a function of A) starting at
1332      !!                 Cdw(say 1.5e-3) for A=0, reaching 1.97e-3 for A~0.5
1333      !!                 and going down to Cdi(say 1.4e-3) for A=1
1334      !!
1335      !!                 It is theoretically applicable to all ice conditions (not only MIZ)
1336      !!                 => see Lupkes et al (2013)
1337      !!
1338      !! ** References : Lupkes et al. JGR 2012 (theory)
1339      !!                 Lupkes et al. GRL 2013 (application to GCM)
1340      !!
1341      !!----------------------------------------------------------------------
1342      REAL(wp), DIMENSION(:,:), INTENT(inout) ::   pcd
1343      REAL(wp), PARAMETER ::   zCe   = 2.23e-03_wp
1344      REAL(wp), PARAMETER ::   znu   = 1._wp
1345      REAL(wp), PARAMETER ::   zmu   = 1._wp
1346      REAL(wp), PARAMETER ::   zbeta = 1._wp
1347      REAL(wp)            ::   zcoef
1348      !!----------------------------------------------------------------------
1349      zcoef = znu + 1._wp / ( 10._wp * zbeta )
1350
1351      ! generic drag over a cell partly covered by ice
1352      !!Cd(:,:) = Cd_oce(:,:) * ( 1._wp - at_i_b(:,:) ) +  &                        ! pure ocean drag
1353      !!   &      Cd_ice      *           at_i_b(:,:)   +  &                        ! pure ice drag
1354      !!   &      zCe         * ( 1._wp - at_i_b(:,:) )**zcoef * at_i_b(:,:)**zmu   ! change due to sea-ice morphology
1355
1356      ! ice-atm drag
1357      pcd(:,:) = rCd_ice +  &                                                         ! pure ice drag
1358         &      zCe     * ( 1._wp - at_i_b(:,:) )**zcoef * at_i_b(:,:)**(zmu-1._wp)  ! change due to sea-ice morphology
1359
1360   END SUBROUTINE Cdn10_Lupkes2012
1361
1362
1363   SUBROUTINE Cdn10_Lupkes2015( ptm_su, pslp, pcd, pch )
1364      !!----------------------------------------------------------------------
1365      !!                      ***  ROUTINE  Cdn10_Lupkes2015  ***
1366      !!
1367      !! ** pUrpose :    Alternative turbulent transfert coefficients formulation
1368      !!                 between sea-ice and atmosphere with distinct momentum
1369      !!                 and heat coefficients depending on sea-ice concentration
1370      !!                 and atmospheric stability (no meltponds effect for now).
1371      !!
1372      !! ** Method :     The parameterization is adapted from Lupkes et al. (2015)
1373      !!                 and ECHAM6 atmospheric model. Compared to Lupkes2012 scheme,
1374      !!                 it considers specific skin and form drags (Andreas et al. 2010)
1375      !!                 to compute neutral transfert coefficients for both heat and
1376      !!                 momemtum fluxes. Atmospheric stability effect on transfert
1377      !!                 coefficient is also taken into account following Louis (1979).
1378      !!
1379      !! ** References : Lupkes et al. JGR 2015 (theory)
1380      !!                 Lupkes et al. ECHAM6 documentation 2015 (implementation)
1381      !!
1382      !!----------------------------------------------------------------------
1383      !
1384      REAL(wp), DIMENSION(:,:), INTENT(in   ) ::   ptm_su ! sea-ice surface temperature [K]
1385      REAL(wp), DIMENSION(:,:), INTENT(in   ) ::   pslp   ! sea-level pressure [Pa]
1386      REAL(wp), DIMENSION(:,:), INTENT(inout) ::   pcd    ! momentum transfert coefficient
1387      REAL(wp), DIMENSION(:,:), INTENT(inout) ::   pch    ! heat transfert coefficient
1388      REAL(wp), DIMENSION(jpi,jpj)            ::   zst, zqo_sat, zqi_sat
1389      !
1390      ! ECHAM6 constants
1391      REAL(wp), PARAMETER ::   z0_skin_ice  = 0.69e-3_wp  ! Eq. 43 [m]
1392      REAL(wp), PARAMETER ::   z0_form_ice  = 0.57e-3_wp  ! Eq. 42 [m]
1393      REAL(wp), PARAMETER ::   z0_ice       = 1.00e-3_wp  ! Eq. 15 [m]
1394      REAL(wp), PARAMETER ::   zce10        = 2.80e-3_wp  ! Eq. 41
1395      REAL(wp), PARAMETER ::   zbeta        = 1.1_wp      ! Eq. 41
1396      REAL(wp), PARAMETER ::   zc           = 5._wp       ! Eq. 13
1397      REAL(wp), PARAMETER ::   zc2          = zc * zc
1398      REAL(wp), PARAMETER ::   zam          = 2. * zc     ! Eq. 14
1399      REAL(wp), PARAMETER ::   zah          = 3. * zc     ! Eq. 30
1400      REAL(wp), PARAMETER ::   z1_alpha     = 1._wp / 0.2_wp  ! Eq. 51
1401      REAL(wp), PARAMETER ::   z1_alphaf    = z1_alpha    ! Eq. 56
1402      REAL(wp), PARAMETER ::   zbetah       = 1.e-3_wp    ! Eq. 26
1403      REAL(wp), PARAMETER ::   zgamma       = 1.25_wp     ! Eq. 26
1404      REAL(wp), PARAMETER ::   z1_gamma     = 1._wp / zgamma
1405      REAL(wp), PARAMETER ::   r1_3         = 1._wp / 3._wp
1406      !
1407      INTEGER  ::   ji, jj         ! dummy loop indices
1408      REAL(wp) ::   zthetav_os, zthetav_is, zthetav_zu
1409      REAL(wp) ::   zrib_o, zrib_i
1410      REAL(wp) ::   zCdn_skin_ice, zCdn_form_ice, zCdn_ice
1411      REAL(wp) ::   zChn_skin_ice, zChn_form_ice
1412      REAL(wp) ::   z0w, z0i, zfmi, zfmw, zfhi, zfhw
1413      REAL(wp) ::   zCdn_form_tmp
1414      !!----------------------------------------------------------------------
1415
1416      ! Momentum Neutral Transfert Coefficients (should be a constant)
1417      zCdn_form_tmp = zce10 * ( LOG( 10._wp / z0_form_ice + 1._wp ) / LOG( rn_zu / z0_form_ice + 1._wp ) )**2   ! Eq. 40
1418      zCdn_skin_ice = ( vkarmn                                      / LOG( rn_zu / z0_skin_ice + 1._wp ) )**2   ! Eq. 7
1419      zCdn_ice      = zCdn_skin_ice   ! Eq. 7
1420      !zCdn_ice     = 1.89e-3         ! old ECHAM5 value (cf Eq. 32)
1421
1422      ! Heat Neutral Transfert Coefficients
1423      zChn_skin_ice = vkarmn**2 / ( LOG( rn_zu / z0_ice + 1._wp ) * LOG( rn_zu * z1_alpha / z0_skin_ice + 1._wp ) )   ! Eq. 50 + Eq. 52
1424
1425      ! Atmospheric and Surface Variables
1426      zst(:,:)     = sst_m(:,:) + rt0                                        ! convert SST from Celcius to Kelvin
1427      zqo_sat(:,:) = rdct_qsat_salt * q_sat( zst(:,:)   , pslp(:,:) )   ! saturation humidity over ocean [kg/kg]
1428      zqi_sat(:,:) =                  q_sat( ptm_su(:,:), pslp(:,:) )   ! saturation humidity over ice   [kg/kg]
1429      !
1430      DO_2D( 0, 0, 0, 0 )
1431         ! Virtual potential temperature [K]
1432         zthetav_os = zst(ji,jj)    * ( 1._wp + rctv0 * zqo_sat(ji,jj) )   ! over ocean
1433         zthetav_is = ptm_su(ji,jj) * ( 1._wp + rctv0 * zqi_sat(ji,jj) )   ! ocean ice
1434         zthetav_zu = t_zu (ji,jj)  * ( 1._wp + rctv0 * q_zu(ji,jj)    )   ! at zu
1435
1436         ! Bulk Richardson Number (could use Ri_bulk function from aerobulk instead)
1437         zrib_o = grav / zthetav_os * ( zthetav_zu - zthetav_os ) * rn_zu / MAX( 0.5, wndm(ji,jj)     )**2   ! over ocean
1438         zrib_i = grav / zthetav_is * ( zthetav_zu - zthetav_is ) * rn_zu / MAX( 0.5, wndm_ice(ji,jj) )**2   ! over ice
1439
1440         ! Momentum and Heat Neutral Transfert Coefficients
1441         zCdn_form_ice = zCdn_form_tmp * at_i_b(ji,jj) * ( 1._wp - at_i_b(ji,jj) )**zbeta  ! Eq. 40
1442         zChn_form_ice = zCdn_form_ice / ( 1._wp + ( LOG( z1_alphaf ) / vkarmn ) * SQRT( zCdn_form_ice ) )               ! Eq. 53
1443
1444         ! Momentum and Heat Stability functions (possibility to use psi_m_ecmwf instead ?)
1445         z0w = rn_zu * EXP( -1._wp * vkarmn / SQRT( Cdn_oce(ji,jj) ) ) ! over water
1446         z0i = z0_skin_ice                                             ! over ice
1447         IF( zrib_o <= 0._wp ) THEN
1448            zfmw = 1._wp - zam * zrib_o / ( 1._wp + 3._wp * zc2 * Cdn_oce(ji,jj) * SQRT( -zrib_o * ( rn_zu / z0w + 1._wp ) ) )  ! Eq. 10
1449            zfhw = ( 1._wp + ( zbetah * ( zthetav_os - zthetav_zu )**r1_3 / ( Chn_oce(ji,jj) * MAX(0.01, wndm(ji,jj)) )   &     ! Eq. 26
1450               &             )**zgamma )**z1_gamma
1451         ELSE
1452            zfmw = 1._wp / ( 1._wp + zam * zrib_o / SQRT( 1._wp + zrib_o ) )   ! Eq. 12
1453            zfhw = 1._wp / ( 1._wp + zah * zrib_o / SQRT( 1._wp + zrib_o ) )   ! Eq. 28
1454         ENDIF
1455
1456         IF( zrib_i <= 0._wp ) THEN
1457            zfmi = 1._wp - zam * zrib_i / (1._wp + 3._wp * zc2 * zCdn_ice * SQRT( -zrib_i * ( rn_zu / z0i + 1._wp)))   ! Eq.  9
1458            zfhi = 1._wp - zah * zrib_i / (1._wp + 3._wp * zc2 * zCdn_ice * SQRT( -zrib_i * ( rn_zu / z0i + 1._wp)))   ! Eq. 25
1459         ELSE
1460            zfmi = 1._wp / ( 1._wp + zam * zrib_i / SQRT( 1._wp + zrib_i ) )   ! Eq. 11
1461            zfhi = 1._wp / ( 1._wp + zah * zrib_i / SQRT( 1._wp + zrib_i ) )   ! Eq. 27
1462         ENDIF
1463
1464         ! Momentum Transfert Coefficients (Eq. 38)
1465         pcd(ji,jj) = zCdn_skin_ice *   zfmi +  &
1466            &        zCdn_form_ice * ( zfmi * at_i_b(ji,jj) + zfmw * ( 1._wp - at_i_b(ji,jj) ) ) / MAX( 1.e-06, at_i_b(ji,jj) )
1467
1468         ! Heat Transfert Coefficients (Eq. 49)
1469         pch(ji,jj) = zChn_skin_ice *   zfhi +  &
1470            &        zChn_form_ice * ( zfhi * at_i_b(ji,jj) + zfhw * ( 1._wp - at_i_b(ji,jj) ) ) / MAX( 1.e-06, at_i_b(ji,jj) )
1471         !
1472      END_2D
1473#if defined key_mpi3
1474      CALL lbc_lnk_nc_multi( 'sbcblk', pcd, 'T',  1.0_wp, pch, 'T', 1.0_wp )
1475#else
1476      CALL lbc_lnk_multi( 'sbcblk', pcd, 'T',  1.0_wp, pch, 'T', 1.0_wp )
1477#endif
1478      !
1479   END SUBROUTINE Cdn10_Lupkes2015
1480
1481#endif
1482
1483   !!======================================================================
1484END MODULE sbcblk
Note: See TracBrowser for help on using the repository browser.