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/releases/r4.0/r4.0-HEAD/src/OCE/SBC – NEMO

source: NEMO/releases/r4.0/r4.0-HEAD/src/OCE/SBC/sbcblk.F90

Last change on this file was 15813, checked in by clem, 13 months ago

SI3: change heat budget to avoid supercooling. The rest: cosmetics

  • Property svn:keywords set to Id
File size: 75.4 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 (http://aerobulk.sourceforge.net/)
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   !!----------------------------------------------------------------------
21
22   !!----------------------------------------------------------------------
23   !!   sbc_blk_init  : initialisation of the chosen bulk formulation as ocean surface boundary condition
24   !!   sbc_blk       : bulk formulation as ocean surface boundary condition
25   !!   blk_oce       : computes momentum, heat and freshwater fluxes over ocean
26   !!   rho_air       : density of (moist) air (depends on T_air, q_air and SLP
27   !!   cp_air        : specific heat of (moist) air (depends spec. hum. q_air)
28   !!   q_sat         : saturation humidity as a function of SLP and temperature
29   !!   L_vap         : latent heat of vaporization of water as a function of temperature
30   !!             sea-ice case only :
31   !!   blk_ice_tau   : provide the air-ice stress
32   !!   blk_ice_flx   : provide the heat and mass fluxes at air-ice interface
33   !!   blk_ice_qcn   : provide ice surface temperature and snow/ice conduction flux (emulating conduction flux)
34   !!   Cdn10_Lupkes2012 : Lupkes et al. (2012) air-ice drag
35   !!   Cdn10_Lupkes2015 : Lupkes et al. (2015) air-ice drag
36   !!----------------------------------------------------------------------
37   USE oce            ! ocean dynamics and tracers
38   USE dom_oce        ! ocean space and time domain
39   USE phycst         ! physical constants
40   USE fldread        ! read input fields
41   USE sbc_oce        ! Surface boundary condition: ocean fields
42   USE trc_oce         ! share SMS/Ocean variables
43   USE cyclone        ! Cyclone 10m wind form trac of cyclone centres
44   USE sbcdcy         ! surface boundary condition: diurnal cycle
45   USE sbcwave , ONLY :   cdn_wave ! wave module
46   USE sbc_ice        ! Surface boundary condition: ice fields
47   USE lib_fortran    ! to use key_nosignedzero
48#if defined key_si3
49   USE ice     , ONLY :   u_ice, v_ice, jpl, a_i_b, at_i_b, t_su, rn_cnd_s, hfx_err_dif, nn_qtrice
50   USE icevar         ! for CALL ice_var_snwblow
51#endif
52   USE sbcblk_algo_ncar     ! => turb_ncar     : NCAR - CORE (Large & Yeager, 2009)
53   USE sbcblk_algo_coare    ! => turb_coare    : COAREv3.0 (Fairall et al. 2003)
54   USE sbcblk_algo_coare3p5 ! => turb_coare3p5 : COAREv3.5 (Edson et al. 2013)
55   USE sbcblk_algo_ecmwf    ! => turb_ecmwf    : ECMWF (IFS cycle 31)
56   !
57   USE iom            ! I/O manager library
58   USE in_out_manager ! I/O manager
59   USE lib_mpp        ! distribued memory computing library
60   USE lbclnk         ! ocean lateral boundary conditions (or mpp link)
61   USE prtctl         ! Print control
62
63   IMPLICIT NONE
64   PRIVATE
65
66   PUBLIC   sbc_blk_init  ! called in sbcmod
67   PUBLIC   sbc_blk       ! called in sbcmod
68#if defined key_si3
69   PUBLIC   blk_ice_tau   ! routine called in icesbc
70   PUBLIC   blk_ice_flx   ! routine called in icesbc
71   PUBLIC   blk_ice_qcn   ! routine called in icesbc
72#endif 
73
74!!Lolo: should ultimately be moved in the module with all physical constants ?
75!!gm  : In principle, yes.
76   REAL(wp), PARAMETER ::   Cp_dry = 1005.0       !: Specic heat of dry air, constant pressure      [J/K/kg]
77   REAL(wp), PARAMETER ::   Cp_vap = 1860.0       !: Specic heat of water vapor, constant pressure  [J/K/kg]
78   REAL(wp), PARAMETER ::   R_dry = 287.05_wp     !: Specific gas constant for dry air              [J/K/kg]
79   REAL(wp), PARAMETER ::   R_vap = 461.495_wp    !: Specific gas constant for water vapor          [J/K/kg]
80   REAL(wp), PARAMETER ::   reps0 = R_dry/R_vap   !: ratio of gas constant for dry air and water vapor => ~ 0.622
81   REAL(wp), PARAMETER ::   rctv0 = R_vap/R_dry - 1._wp !: for virtual temperature (== (1-eps)/eps) => ~ 0.608
82
83   INTEGER , PARAMETER ::   jpfld   =11           ! maximum number of files to read
84   INTEGER , PARAMETER ::   jp_wndi = 1           ! index of 10m wind velocity (i-component) (m/s)    at T-point
85   INTEGER , PARAMETER ::   jp_wndj = 2           ! index of 10m wind velocity (j-component) (m/s)    at T-point
86   INTEGER , PARAMETER ::   jp_tair = 3           ! index of 10m air temperature             (Kelvin)
87   INTEGER , PARAMETER ::   jp_humi = 4           ! index of specific humidity               ( % )
88   INTEGER , PARAMETER ::   jp_qsr  = 5           ! index of solar heat                      (W/m2)
89   INTEGER , PARAMETER ::   jp_qlw  = 6           ! index of Long wave                       (W/m2)
90   INTEGER , PARAMETER ::   jp_prec = 7           ! index of total precipitation (rain+snow) (Kg/m2/s)
91   INTEGER , PARAMETER ::   jp_snow = 8           ! index of snow (solid prcipitation)       (kg/m2/s)
92   INTEGER , PARAMETER ::   jp_slp  = 9           ! index of sea level pressure              (Pa)
93   INTEGER , PARAMETER ::   jp_cc   =10           ! index of cloud cover                     (-)      range:0-1
94   INTEGER , PARAMETER ::   jp_tdif =11           ! index of tau diff associated to HF tau   (N/m2)   at T-point
95
96   TYPE(FLD), ALLOCATABLE, DIMENSION(:) ::   sf   ! structure of input fields (file informations, fields read)
97
98   !                                             !!! Bulk parameters
99   REAL(wp), PARAMETER ::   cpa    = 1000.5         ! specific heat of air (only used for ice fluxes now...)
100   REAL(wp), PARAMETER ::   Ls     =    2.839e6     ! latent heat of sublimation
101   REAL(wp), PARAMETER ::   Stef   =    5.67e-8     ! Stefan Boltzmann constant
102   REAL(wp), PARAMETER ::   Cd_ice =    1.4e-3      ! transfer coefficient over ice
103   REAL(wp), PARAMETER ::   albo   =    0.066       ! ocean albedo assumed to be constant
104   !
105   !                           !!* Namelist namsbc_blk : bulk parameters
106   LOGICAL  ::   ln_NCAR        ! "NCAR"      algorithm   (Large and Yeager 2008)
107   LOGICAL  ::   ln_COARE_3p0   ! "COARE 3.0" algorithm   (Fairall et al. 2003)
108   LOGICAL  ::   ln_COARE_3p5   ! "COARE 3.5" algorithm   (Edson et al. 2013)
109   LOGICAL  ::   ln_ECMWF       ! "ECMWF"     algorithm   (IFS cycle 31)
110   !
111   LOGICAL  ::   ln_taudif      ! logical flag to use the "mean of stress module - module of mean stress" data
112   REAL(wp) ::   rn_pfac        ! multiplication factor for precipitation
113   REAL(wp) ::   rn_efac        ! multiplication factor for evaporation
114   REAL(wp) ::   rn_vfac        ! multiplication factor for ice/ocean velocity in the calculation of wind stress
115   REAL(wp) ::   rn_zqt         ! z(q,t) : height of humidity and temperature measurements
116   REAL(wp) ::   rn_zu          ! z(u)   : height of wind measurements
117!!gm ref namelist initialize it so remove the setting to false below
118   LOGICAL  ::   ln_Cd_L12 = .FALSE. !  Modify the drag ice-atm depending on ice concentration (from Lupkes et al. JGR2012)
119   LOGICAL  ::   ln_Cd_L15 = .FALSE. !  Modify the drag ice-atm depending on ice concentration (from Lupkes et al. JGR2015)
120   !
121   REAL(wp), ALLOCATABLE, SAVE, DIMENSION(:,:) ::   Cd_atm                    ! transfer coefficient for momentum      (tau)
122   REAL(wp), ALLOCATABLE, SAVE, DIMENSION(:,:) ::   Ch_atm                    ! transfer coefficient for sensible heat (Q_sens)
123   REAL(wp), ALLOCATABLE, SAVE, DIMENSION(:,:) ::   Ce_atm                    ! tansfert coefficient for evaporation   (Q_lat)
124   REAL(wp), ALLOCATABLE, SAVE, DIMENSION(:,:) ::   t_zu                      ! air temperature at wind speed height (needed by Lupkes 2015 bulk scheme)
125   REAL(wp), ALLOCATABLE, SAVE, DIMENSION(:,:) ::   q_zu                      ! air spec. hum.  at wind speed height (needed by Lupkes 2015 bulk scheme)
126   REAL(wp), ALLOCATABLE, SAVE, DIMENSION(:,:) ::   cdn_oce, chn_oce, cen_oce ! needed by Lupkes 2015 bulk scheme
127
128   INTEGER  ::   nblk           ! choice of the bulk algorithm
129   !                            ! associated indices:
130   INTEGER, PARAMETER ::   np_NCAR      = 1   ! "NCAR" algorithm        (Large and Yeager 2008)
131   INTEGER, PARAMETER ::   np_COARE_3p0 = 2   ! "COARE 3.0" algorithm   (Fairall et al. 2003)
132   INTEGER, PARAMETER ::   np_COARE_3p5 = 3   ! "COARE 3.5" algorithm   (Edson et al. 2013)
133   INTEGER, PARAMETER ::   np_ECMWF     = 4   ! "ECMWF" algorithm       (IFS cycle 31)
134
135   !! * Substitutions
136#  include "vectopt_loop_substitute.h90"
137   !!----------------------------------------------------------------------
138   !! NEMO/OCE 4.0 , NEMO Consortium (2018)
139   !! $Id$
140   !! Software governed by the CeCILL license (see ./LICENSE)
141   !!----------------------------------------------------------------------
142CONTAINS
143
144   INTEGER FUNCTION sbc_blk_alloc()
145      !!-------------------------------------------------------------------
146      !!             ***  ROUTINE sbc_blk_alloc ***
147      !!-------------------------------------------------------------------
148      ALLOCATE( Cd_atm (jpi,jpj), Ch_atm (jpi,jpj), Ce_atm (jpi,jpj), t_zu(jpi,jpj), q_zu(jpi,jpj), &
149         &      cdn_oce(jpi,jpj), chn_oce(jpi,jpj), cen_oce(jpi,jpj), STAT=sbc_blk_alloc )
150      !
151      CALL mpp_sum ( 'sbcblk', sbc_blk_alloc )
152      IF( sbc_blk_alloc /= 0 )   CALL ctl_stop( 'STOP', 'sbc_blk_alloc: failed to allocate arrays' )
153   END FUNCTION sbc_blk_alloc
154
155
156   SUBROUTINE sbc_blk_init
157      !!---------------------------------------------------------------------
158      !!                    ***  ROUTINE sbc_blk_init  ***
159      !!
160      !! ** Purpose :   choose and initialize a bulk formulae formulation
161      !!
162      !! ** Method  :
163      !!
164      !!----------------------------------------------------------------------
165      INTEGER  ::   jfpr, jfld            ! dummy loop indice and argument
166      INTEGER  ::   ios, ierror, ioptio   ! Local integer
167      !!
168      CHARACTER(len=100)            ::   cn_dir                ! Root directory for location of atmospheric forcing files
169      TYPE(FLD_N), DIMENSION(jpfld) ::   slf_i                 ! array of namelist informations on the fields to read
170      TYPE(FLD_N) ::   sn_wndi, sn_wndj, sn_humi, sn_qsr       ! informations about the fields to be read
171      TYPE(FLD_N) ::   sn_qlw , sn_tair, sn_prec, sn_snow      !       "                        "
172      TYPE(FLD_N) ::   sn_slp , sn_tdif, sn_cc                 !       "                        "
173      NAMELIST/namsbc_blk/ sn_wndi, sn_wndj, sn_humi, sn_qsr, sn_qlw ,                &   ! input fields
174         &                 sn_tair, sn_prec, sn_snow, sn_slp, sn_tdif, sn_cc,         &
175         &                 ln_NCAR, ln_COARE_3p0, ln_COARE_3p5, ln_ECMWF,             &   ! bulk algorithm
176         &                 cn_dir , ln_taudif, rn_zqt, rn_zu,                         & 
177         &                 rn_pfac, rn_efac, rn_vfac, ln_Cd_L12, ln_Cd_L15
178      !!---------------------------------------------------------------------
179      !
180      !                                      ! allocate sbc_blk_core array
181      IF( sbc_blk_alloc() /= 0 )   CALL ctl_stop( 'STOP', 'sbc_blk : unable to allocate standard arrays' )
182      !
183      !                             !** read bulk namelist 
184      REWIND( numnam_ref )                !* Namelist namsbc_blk in reference namelist : bulk parameters
185      READ  ( numnam_ref, namsbc_blk, IOSTAT = ios, ERR = 901)
186901   IF( ios /= 0 )   CALL ctl_nam ( ios , 'namsbc_blk in reference namelist' )
187      !
188      REWIND( numnam_cfg )                !* Namelist namsbc_blk in configuration namelist : bulk parameters
189      READ  ( numnam_cfg, namsbc_blk, IOSTAT = ios, ERR = 902 )
190902   IF( ios >  0 )   CALL ctl_nam ( ios , 'namsbc_blk in configuration namelist' )
191      !
192      IF(lwm) WRITE( numond, namsbc_blk )
193      !
194      !                             !** initialization of the chosen bulk formulae (+ check)
195      !                                   !* select the bulk chosen in the namelist and check the choice
196                                                               ioptio = 0
197      IF( ln_NCAR      ) THEN   ;   nblk =  np_NCAR        ;   ioptio = ioptio + 1   ;   ENDIF
198      IF( ln_COARE_3p0 ) THEN   ;   nblk =  np_COARE_3p0   ;   ioptio = ioptio + 1   ;   ENDIF
199      IF( ln_COARE_3p5 ) THEN   ;   nblk =  np_COARE_3p5   ;   ioptio = ioptio + 1   ;   ENDIF
200      IF( ln_ECMWF     ) THEN   ;   nblk =  np_ECMWF       ;   ioptio = ioptio + 1   ;   ENDIF
201      !
202      IF( ioptio /= 1 )   CALL ctl_stop( 'sbc_blk_init: Choose one and only one bulk algorithm' )
203      !
204      IF( ln_dm2dc ) THEN                 !* check: diurnal cycle on Qsr
205         IF( sn_qsr%freqh /= 24. )   CALL ctl_stop( 'sbc_blk_init: ln_dm2dc=T only with daily short-wave input' )
206         IF( sn_qsr%ln_tint ) THEN
207            CALL ctl_warn( 'sbc_blk_init: ln_dm2dc=T daily qsr time interpolation done by sbcdcy module',   &
208               &           '              ==> We force time interpolation = .false. for qsr' )
209            sn_qsr%ln_tint = .false.
210         ENDIF
211      ENDIF
212      !                                   !* set the bulk structure
213      !                                      !- store namelist information in an array
214      slf_i(jp_wndi) = sn_wndi   ;   slf_i(jp_wndj) = sn_wndj
215      slf_i(jp_qsr ) = sn_qsr    ;   slf_i(jp_qlw ) = sn_qlw
216      slf_i(jp_tair) = sn_tair   ;   slf_i(jp_humi) = sn_humi
217      slf_i(jp_prec) = sn_prec   ;   slf_i(jp_snow) = sn_snow
218      slf_i(jp_slp)  = sn_slp    ;   slf_i(jp_cc)   = sn_cc
219      slf_i(jp_tdif) = sn_tdif
220      !
221      lhftau = ln_taudif                     !- add an extra field if HF stress is used
222      jfld = jpfld - COUNT( (/.NOT.lhftau/) )
223      !
224      !                                      !- allocate the bulk structure
225      ALLOCATE( sf(jfld), STAT=ierror )
226      IF( ierror > 0 )   CALL ctl_stop( 'STOP', 'sbc_blk_init: unable to allocate sf structure' )
227
228      !                                      !- fill the bulk structure with namelist informations
229      CALL fld_fill( sf, slf_i, cn_dir, 'sbc_blk_init', 'surface boundary condition -- bulk formulae', 'namsbc_blk' )
230      !
231      DO jfpr = 1, jfld
232         !
233         IF( TRIM(sf(jfpr)%clrootname) == 'NOT USED' ) THEN    !--  not used field  --!   (only now allocated and set to zero)
234            ALLOCATE( sf(jfpr)%fnow(jpi,jpj,1) )
235            sf(jfpr)%fnow(:,:,1) = 0._wp
236         ELSE                                                  !-- used field --!
237            ALLOCATE( sf(jfpr)%fnow(jpi,jpj,1) )
238            IF( slf_i(jfpr)%ln_tint )   ALLOCATE( sf(jfpr)%fdta(jpi,jpj,1,2) )
239            IF( slf_i(jfpr)%freqh > 0. .AND. MOD( NINT(3600. * slf_i(jfpr)%freqh), nn_fsbc * NINT(rdt) ) /= 0 )                      &
240               &  CALL ctl_warn( 'sbc_blk_init: sbcmod timestep rdt*nn_fsbc is NOT a submultiple of atmospheric forcing frequency.', &
241               &                 '               This is not ideal. You should consider changing either rdt or nn_fsbc value...' )
242         ENDIF
243      ENDDO
244      ! fill cloud cover array with constant value if "not used"
245      IF( TRIM(sf(jp_cc)%clrootname) == 'NOT USED' )   sf(jp_cc)%fnow(:,:,1) = pp_cldf
246         
247      IF ( ln_wave ) THEN
248      !Activated wave module but neither drag nor stokes drift activated
249         IF ( .NOT.(ln_cdgw .OR. ln_sdw .OR. ln_tauwoc .OR. ln_stcor ) )   THEN
250            CALL ctl_stop( 'STOP',  'Ask for wave coupling but ln_cdgw=F, ln_sdw=F, ln_tauwoc=F, ln_stcor=F' )
251      !drag coefficient read from wave model definable only with mfs bulk formulae and core
252         ELSEIF (ln_cdgw .AND. .NOT. ln_NCAR )       THEN       
253             CALL ctl_stop( 'drag coefficient read from wave model definable only with NCAR and CORE bulk formulae')
254         ELSEIF (ln_stcor .AND. .NOT. ln_sdw)                             THEN
255             CALL ctl_stop( 'Stokes-Coriolis term calculated only if activated Stokes Drift ln_sdw=T')
256         ENDIF
257      ELSE
258      IF ( ln_cdgw .OR. ln_sdw .OR. ln_tauwoc .OR. ln_stcor )                & 
259         &   CALL ctl_stop( 'Not Activated Wave Module (ln_wave=F) but asked coupling ',    &
260         &                  'with drag coefficient (ln_cdgw =T) '  ,                        &
261         &                  'or Stokes Drift (ln_sdw=T) ' ,                                 &
262         &                  'or ocean stress modification due to waves (ln_tauwoc=T) ',      & 
263         &                  'or Stokes-Coriolis term (ln_stcori=T)'  )
264      ENDIF 
265      !
266      !           
267      IF(lwp) THEN                     !** Control print
268         !
269         WRITE(numout,*)                  !* namelist
270         WRITE(numout,*) '   Namelist namsbc_blk (other than data information):'
271         WRITE(numout,*) '      "NCAR"      algorithm   (Large and Yeager 2008)     ln_NCAR      = ', ln_NCAR
272         WRITE(numout,*) '      "COARE 3.0" algorithm   (Fairall et al. 2003)       ln_COARE_3p0 = ', ln_COARE_3p0
273         WRITE(numout,*) '      "COARE 3.5" algorithm   (Edson et al. 2013)         ln_COARE_3p5 = ', ln_COARE_3p5
274         WRITE(numout,*) '      "ECMWF"     algorithm   (IFS cycle 31)              ln_ECMWF     = ', ln_ECMWF
275         WRITE(numout,*) '      add High freq.contribution to the stress module     ln_taudif    = ', ln_taudif
276         WRITE(numout,*) '      Air temperature and humidity reference height (m)   rn_zqt       = ', rn_zqt
277         WRITE(numout,*) '      Wind vector reference height (m)                    rn_zu        = ', rn_zu
278         WRITE(numout,*) '      factor applied on precipitation (total & snow)      rn_pfac      = ', rn_pfac
279         WRITE(numout,*) '      factor applied on evaporation                       rn_efac      = ', rn_efac
280         WRITE(numout,*) '      factor applied on ocean/ice velocity                rn_vfac      = ', rn_vfac
281         WRITE(numout,*) '         (form absolute (=0) to relative winds(=1))'
282         WRITE(numout,*) '      use ice-atm drag from Lupkes2012                    ln_Cd_L12    = ', ln_Cd_L12
283         WRITE(numout,*) '      use ice-atm drag from Lupkes2015                    ln_Cd_L15    = ', ln_Cd_L15
284         !
285         WRITE(numout,*)
286         SELECT CASE( nblk )              !* Print the choice of bulk algorithm
287         CASE( np_NCAR      )   ;   WRITE(numout,*) '   ==>>>   "NCAR" algorithm        (Large and Yeager 2008)'
288         CASE( np_COARE_3p0 )   ;   WRITE(numout,*) '   ==>>>   "COARE 3.0" algorithm   (Fairall et al. 2003)'
289         CASE( np_COARE_3p5 )   ;   WRITE(numout,*) '   ==>>>   "COARE 3.5" algorithm   (Edson et al. 2013)'
290         CASE( np_ECMWF     )   ;   WRITE(numout,*) '   ==>>>   "ECMWF" algorithm       (IFS cycle 31)'
291         END SELECT
292         !
293      ENDIF
294      !
295   END SUBROUTINE sbc_blk_init
296
297
298   SUBROUTINE sbc_blk( kt )
299      !!---------------------------------------------------------------------
300      !!                    ***  ROUTINE sbc_blk  ***
301      !!
302      !! ** Purpose :   provide at each time step the surface ocean fluxes
303      !!              (momentum, heat, freshwater and runoff)
304      !!
305      !! ** Method  : (1) READ each fluxes in NetCDF files:
306      !!      the 10m wind velocity (i-component) (m/s)    at T-point
307      !!      the 10m wind velocity (j-component) (m/s)    at T-point
308      !!      the 10m or 2m specific humidity     ( % )
309      !!      the solar heat                      (W/m2)
310      !!      the Long wave                       (W/m2)
311      !!      the 10m or 2m air temperature       (Kelvin)
312      !!      the total precipitation (rain+snow) (Kg/m2/s)
313      !!      the snow (solid prcipitation)       (kg/m2/s)
314      !!      the tau diff associated to HF tau   (N/m2)   at T-point   (ln_taudif=T)
315      !!              (2) CALL blk_oce
316      !!
317      !!      C A U T I O N : never mask the surface stress fields
318      !!                      the stress is assumed to be in the (i,j) mesh referential
319      !!
320      !! ** Action  :   defined at each time-step at the air-sea interface
321      !!              - utau, vtau  i- and j-component of the wind stress
322      !!              - taum        wind stress module at T-point
323      !!              - wndm        wind speed  module at T-point over free ocean or leads in presence of sea-ice
324      !!              - qns, qsr    non-solar and solar heat fluxes
325      !!              - emp         upward mass flux (evapo. - precip.)
326      !!              - sfx         salt flux due to freezing/melting (non-zero only if ice is present)
327      !!
328      !! ** References :   Large & Yeager, 2004 / Large & Yeager, 2008
329      !!                   Brodeau et al. Ocean Modelling 2010
330      !!----------------------------------------------------------------------
331      INTEGER, INTENT(in) ::   kt   ! ocean time step
332      !!---------------------------------------------------------------------
333      !
334      CALL fld_read( kt, nn_fsbc, sf )             ! input fields provided at the current time-step
335      !
336      !                                            ! compute the surface ocean fluxes using bulk formulea
337      IF( MOD( kt - 1, nn_fsbc ) == 0 )   CALL blk_oce( kt, sf, sst_m, ssu_m, ssv_m )
338
339#if defined key_cice
340      IF( MOD( kt - 1, nn_fsbc ) == 0 )   THEN
341         qlw_ice(:,:,1)   = sf(jp_qlw )%fnow(:,:,1)
342         IF( ln_dm2dc ) THEN ; qsr_ice(:,:,1) = sbc_dcy( sf(jp_qsr)%fnow(:,:,1) )
343         ELSE                ; qsr_ice(:,:,1) =          sf(jp_qsr)%fnow(:,:,1) 
344         ENDIF
345         tatm_ice(:,:)    = sf(jp_tair)%fnow(:,:,1)
346         qatm_ice(:,:)    = sf(jp_humi)%fnow(:,:,1)
347         tprecip(:,:)     = sf(jp_prec)%fnow(:,:,1) * rn_pfac
348         sprecip(:,:)     = sf(jp_snow)%fnow(:,:,1) * rn_pfac
349         wndi_ice(:,:)    = sf(jp_wndi)%fnow(:,:,1)
350         wndj_ice(:,:)    = sf(jp_wndj)%fnow(:,:,1)
351      ENDIF
352#endif
353      !
354   END SUBROUTINE sbc_blk
355
356
357   SUBROUTINE blk_oce( kt, sf, pst, pu, pv )
358      !!---------------------------------------------------------------------
359      !!                     ***  ROUTINE blk_oce  ***
360      !!
361      !! ** Purpose :   provide the momentum, heat and freshwater fluxes at
362      !!      the ocean surface at each time step
363      !!
364      !! ** Method  :   bulk formulea for the ocean using atmospheric
365      !!      fields read in sbc_read
366      !!
367      !! ** Outputs : - utau    : i-component of the stress at U-point  (N/m2)
368      !!              - vtau    : j-component of the stress at V-point  (N/m2)
369      !!              - taum    : Wind stress module at T-point         (N/m2)
370      !!              - wndm    : Wind speed module at T-point          (m/s)
371      !!              - qsr     : Solar heat flux over the ocean        (W/m2)
372      !!              - qns     : Non Solar heat flux over the ocean    (W/m2)
373      !!              - emp     : evaporation minus precipitation       (kg/m2/s)
374      !!
375      !!  ** Nota  :   sf has to be a dummy argument for AGRIF on NEC
376      !!---------------------------------------------------------------------
377      INTEGER  , INTENT(in   )                 ::   kt    ! time step index
378      TYPE(fld), INTENT(inout), DIMENSION(:)   ::   sf    ! input data
379      REAL(wp) , INTENT(in)   , DIMENSION(:,:) ::   pst   ! surface temperature                      [Celcius]
380      REAL(wp) , INTENT(in)   , DIMENSION(:,:) ::   pu    ! surface current at U-point (i-component) [m/s]
381      REAL(wp) , INTENT(in)   , DIMENSION(:,:) ::   pv    ! surface current at V-point (j-component) [m/s]
382      !
383      INTEGER  ::   ji, jj               ! dummy loop indices
384      REAL(wp) ::   zztmp                ! local variable
385      REAL(wp), DIMENSION(jpi,jpj) ::   zwnd_i, zwnd_j    ! wind speed components at T-point
386      REAL(wp), DIMENSION(jpi,jpj) ::   zsq               ! specific humidity at pst
387      REAL(wp), DIMENSION(jpi,jpj) ::   zqlw, zqsb        ! long wave and sensible heat fluxes
388      REAL(wp), DIMENSION(jpi,jpj) ::   zqla, zevap       ! latent heat fluxes and evaporation
389      REAL(wp), DIMENSION(jpi,jpj) ::   zst               ! surface temperature in Kelvin
390      REAL(wp), DIMENSION(jpi,jpj) ::   zU_zu             ! bulk wind speed at height zu  [m/s]
391      REAL(wp), DIMENSION(jpi,jpj) ::   ztpot             ! potential temperature of air at z=rn_zqt [K]
392      REAL(wp), DIMENSION(jpi,jpj) ::   zrhoa             ! density of air   [kg/m^3]
393      REAL(wp), DIMENSION(jpi,jpj) ::   zcptrain, zcptsnw, zcptn ! Heat content per unit mass (J/kg)
394      !!---------------------------------------------------------------------
395      !
396      ! Heat content per unit mass (J/kg)
397      zcptrain(:,:) = (      sf(jp_tair)%fnow(:,:,1)        - rt0 ) * rcp  * tmask(:,:,1)
398      zcptsnw (:,:) = ( MIN( sf(jp_tair)%fnow(:,:,1), rt0 ) - rt0 ) * rcpi * tmask(:,:,1)
399      zcptn   (:,:) =        pst(:,:)                               * rcp  * tmask(:,:,1)
400      !
401      ! local scalars ( place there for vector optimisation purposes)
402      zst(:,:) = pst(:,:) + rt0      ! convert SST from Celcius to Kelvin (and set minimum value far above 0 K)
403
404      ! --- cloud cover --- !
405      cloud_fra(:,:) = sf(jp_cc)%fnow(:,:,1)
406
407      ! ----------------------------------------------------------------------------- !
408      !      0   Wind components and module at T-point relative to the moving ocean   !
409      ! ----------------------------------------------------------------------------- !
410
411      ! ... components ( U10m - U_oce ) at T-point (unmasked)
412!!gm    move zwnd_i (_j) set to zero  inside the key_cyclone ???
413      zwnd_i(:,:) = 0._wp
414      zwnd_j(:,:) = 0._wp
415#if defined key_cyclone
416      CALL wnd_cyc( kt, zwnd_i, zwnd_j )    ! add analytical tropical cyclone (Vincent et al. JGR 2012)
417      DO jj = 2, jpjm1
418         DO ji = fs_2, fs_jpim1   ! vect. opt.
419            sf(jp_wndi)%fnow(ji,jj,1) = sf(jp_wndi)%fnow(ji,jj,1) + zwnd_i(ji,jj)
420            sf(jp_wndj)%fnow(ji,jj,1) = sf(jp_wndj)%fnow(ji,jj,1) + zwnd_j(ji,jj)
421         END DO
422      END DO
423#endif
424      ! mask the wind in case it is not masked in the input file otherwise we end up with twice the stress at the coast
425      ! (see calculation of utau/vtau below)
426      DO jj = 2, jpjm1
427         DO ji = fs_2, fs_jpim1   ! vect. opt.
428            zwnd_i(ji,jj) = (  sf(jp_wndi)%fnow(ji,jj,1) - rn_vfac * 0.5 * ( pu(ji-1,jj  ) + pu(ji,jj) )  ) * tmask(ji,jj,1)
429            zwnd_j(ji,jj) = (  sf(jp_wndj)%fnow(ji,jj,1) - rn_vfac * 0.5 * ( pv(ji  ,jj-1) + pv(ji,jj) )  ) * tmask(ji,jj,1)
430         END DO
431      END DO
432      CALL lbc_lnk_multi( 'sbcblk', zwnd_i, 'T', -1., zwnd_j, 'T', -1. )
433      ! ... scalar wind ( = | U10m - U_oce | ) at T-point (masked)
434      wndm(:,:) = SQRT(  zwnd_i(:,:) * zwnd_i(:,:)   &
435         &             + zwnd_j(:,:) * zwnd_j(:,:)  )
436
437      ! ----------------------------------------------------------------------------- !
438      !      I   Radiative FLUXES                                                     !
439      ! ----------------------------------------------------------------------------- !
440
441      ! ocean albedo assumed to be constant + modify now Qsr to include the diurnal cycle                    ! Short Wave
442      zztmp = 1. - albo
443      IF( ln_dm2dc ) THEN   ;   qsr(:,:) = zztmp * sbc_dcy( sf(jp_qsr)%fnow(:,:,1) ) * tmask(:,:,1)
444      ELSE                  ;   qsr(:,:) = zztmp *          sf(jp_qsr)%fnow(:,:,1)   * tmask(:,:,1)
445      ENDIF
446
447#if defined key_top
448      IF( ln_trcdc2dm )  THEN      !  diurnal cycle in TOP
449         IF( ln_dm2dc )  THEN  ;  qsr_mean(:,:) = zztmp * sf(jp_qsr)%fnow(:,:,1)  * tmask(:,:,1)
450         ELSE                  ;  ncpl_qsr_freq = sf(jp_qsr)%freqh * 3600 !   qsr_mean will be computed in TOP
451         ENDIF
452      ENDIF
453#endif
454
455      zqlw(:,:) = (  sf(jp_qlw)%fnow(:,:,1) - Stef * zst(:,:)*zst(:,:)*zst(:,:)*zst(:,:)  ) * tmask(:,:,1)   ! Long  Wave
456
457      ! ----------------------------------------------------------------------------- !
458      !     II    Turbulent FLUXES                                                    !
459      ! ----------------------------------------------------------------------------- !
460
461      ! ... specific humidity at SST and IST tmask(
462      zsq(:,:) = 0.98 * q_sat( zst(:,:), sf(jp_slp)%fnow(:,:,1) )
463      !!
464      !! Estimate of potential temperature at z=rn_zqt, based on adiabatic lapse-rate
465      !!    (see Josey, Gulev & Yu, 2013) / doi=10.1016/B978-0-12-391851-2.00005-2
466      !!    (since reanalysis products provide T at z, not theta !)
467      ztpot = sf(jp_tair)%fnow(:,:,1) + gamma_moist( sf(jp_tair)%fnow(:,:,1), sf(jp_humi)%fnow(:,:,1) ) * rn_zqt
468
469      SELECT CASE( nblk )        !==  transfer coefficients  ==!   Cd, Ch, Ce at T-point
470      !
471      CASE( np_NCAR      )   ;   CALL turb_ncar    ( rn_zqt, rn_zu, zst, ztpot, zsq, sf(jp_humi)%fnow, wndm,   &  ! NCAR-COREv2
472         &                                           Cd_atm, Ch_atm, Ce_atm, t_zu, q_zu, zU_zu, cdn_oce, chn_oce, cen_oce )
473      CASE( np_COARE_3p0 )   ;   CALL turb_coare   ( rn_zqt, rn_zu, zst, ztpot, zsq, sf(jp_humi)%fnow, wndm,   &  ! COARE v3.0
474         &                                           Cd_atm, Ch_atm, Ce_atm, t_zu, q_zu, zU_zu, cdn_oce, chn_oce, cen_oce )
475      CASE( np_COARE_3p5 )   ;   CALL turb_coare3p5( rn_zqt, rn_zu, zst, ztpot, zsq, sf(jp_humi)%fnow, wndm,   &  ! COARE v3.5
476         &                                           Cd_atm, Ch_atm, Ce_atm, t_zu, q_zu, zU_zu, cdn_oce, chn_oce, cen_oce )
477      CASE( np_ECMWF     )   ;   CALL turb_ecmwf   ( rn_zqt, rn_zu, zst, ztpot, zsq, sf(jp_humi)%fnow, wndm,   &  ! ECMWF
478         &                                           Cd_atm, Ch_atm, Ce_atm, t_zu, q_zu, zU_zu, cdn_oce, chn_oce, cen_oce )
479      CASE DEFAULT
480         CALL ctl_stop( 'STOP', 'sbc_oce: non-existing bulk formula selected' )
481      END SELECT
482
483      !                          ! Compute true air density :
484      IF( ABS(rn_zu - rn_zqt) > 0.01 ) THEN     ! At zu: (probably useless to remove zrho*grav*rn_zu from SLP...)
485         zrhoa(:,:) = rho_air( t_zu(:,:)              , q_zu(:,:)              , sf(jp_slp)%fnow(:,:,1) )
486      ELSE                                      ! At zt:
487         zrhoa(:,:) = rho_air( sf(jp_tair)%fnow(:,:,1), sf(jp_humi)%fnow(:,:,1), sf(jp_slp)%fnow(:,:,1) )
488      END IF
489
490!!      CALL iom_put( "Cd_oce", Cd_atm)  ! output value of pure ocean-atm. transfer coef.
491!!      CALL iom_put( "Ch_oce", Ch_atm)  ! output value of pure ocean-atm. transfer coef.
492
493      DO jj = 1, jpj             ! tau module, i and j component
494         DO ji = 1, jpi
495            zztmp = zrhoa(ji,jj)  * zU_zu(ji,jj) * Cd_atm(ji,jj)   ! using bulk wind speed
496            taum  (ji,jj) = zztmp * wndm  (ji,jj)
497            zwnd_i(ji,jj) = zztmp * zwnd_i(ji,jj)
498            zwnd_j(ji,jj) = zztmp * zwnd_j(ji,jj)
499         END DO
500      END DO
501
502      !                          ! add the HF tau contribution to the wind stress module
503      IF( lhftau )   taum(:,:) = taum(:,:) + sf(jp_tdif)%fnow(:,:,1)
504
505      CALL iom_put( "taum_oce", taum )   ! output wind stress module
506
507      ! ... utau, vtau at U- and V_points, resp.
508      !     Note the use of 0.5*(2-umask) in order to unmask the stress along coastlines
509      !     Note the use of MAX(tmask(i,j),tmask(i+1,j) is to mask tau over ice shelves
510      DO jj = 1, jpjm1
511         DO ji = 1, fs_jpim1
512            utau(ji,jj) = 0.5 * ( 2. - umask(ji,jj,1) ) * ( zwnd_i(ji,jj) + zwnd_i(ji+1,jj  ) ) &
513               &          * MAX(tmask(ji,jj,1),tmask(ji+1,jj,1))
514            vtau(ji,jj) = 0.5 * ( 2. - vmask(ji,jj,1) ) * ( zwnd_j(ji,jj) + zwnd_j(ji  ,jj+1) ) &
515               &          * MAX(tmask(ji,jj,1),tmask(ji,jj+1,1))
516         END DO
517      END DO
518      CALL lbc_lnk_multi( 'sbcblk', utau, 'U', -1., vtau, 'V', -1. )
519
520      !  Turbulent fluxes over ocean
521      ! -----------------------------
522
523      ! zqla used as temporary array, for rho*U (common term of bulk formulae):
524      zqla(:,:) = zrhoa(:,:) * zU_zu(:,:) * tmask(:,:,1)
525
526      IF( ABS( rn_zu - rn_zqt) < 0.01_wp ) THEN
527         !! q_air and t_air are given at 10m (wind reference height)
528         zevap(:,:) = rn_efac*MAX( 0._wp,             zqla(:,:)*Ce_atm(:,:)*(zsq(:,:) - sf(jp_humi)%fnow(:,:,1)) ) ! Evaporation, using bulk wind speed
529         zqsb (:,:) = cp_air(sf(jp_humi)%fnow(:,:,1))*zqla(:,:)*Ch_atm(:,:)*(zst(:,:) - ztpot(:,:)             )   ! Sensible Heat, using bulk wind speed
530      ELSE
531         !! q_air and t_air are not given at 10m (wind reference height)
532         ! Values of temp. and hum. adjusted to height of wind during bulk algorithm iteration must be used!!!
533         zevap(:,:) = rn_efac*MAX( 0._wp,             zqla(:,:)*Ce_atm(:,:)*(zsq(:,:) - q_zu(:,:) ) ) ! Evaporation, using bulk wind speed
534         zqsb (:,:) = cp_air(sf(jp_humi)%fnow(:,:,1))*zqla(:,:)*Ch_atm(:,:)*(zst(:,:) - t_zu(:,:) )   ! Sensible Heat, using bulk wind speed
535      ENDIF
536
537      zqla(:,:) = L_vap(zst(:,:)) * zevap(:,:)     ! Latent Heat flux
538
539
540      IF(ln_ctl) THEN
541         CALL prt_ctl( tab2d_1=zqla  , clinfo1=' blk_oce: zqla   : ', tab2d_2=Ce_atm , clinfo2=' Ce_oce  : ' )
542         CALL prt_ctl( tab2d_1=zqsb  , clinfo1=' blk_oce: zqsb   : ', tab2d_2=Ch_atm , clinfo2=' Ch_oce  : ' )
543         CALL prt_ctl( tab2d_1=zqlw  , clinfo1=' blk_oce: zqlw   : ', tab2d_2=qsr, clinfo2=' qsr : ' )
544         CALL prt_ctl( tab2d_1=zsq   , clinfo1=' blk_oce: zsq    : ', tab2d_2=zst, clinfo2=' zst : ' )
545         CALL prt_ctl( tab2d_1=utau  , clinfo1=' blk_oce: utau   : ', mask1=umask,   &
546            &          tab2d_2=vtau  , clinfo2=           ' vtau : ', mask2=vmask )
547         CALL prt_ctl( tab2d_1=wndm  , clinfo1=' blk_oce: wndm   : ')
548         CALL prt_ctl( tab2d_1=zst   , clinfo1=' blk_oce: zst    : ')
549      ENDIF
550
551      ! ----------------------------------------------------------------------------- !
552      !     III    Total FLUXES                                                       !
553      ! ----------------------------------------------------------------------------- !
554      !
555      emp (:,:) = (  zevap(:,:)                                          &   ! mass flux (evap. - precip.)
556         &         - sf(jp_prec)%fnow(:,:,1) * rn_pfac  ) * tmask(:,:,1)
557      !
558      qns(:,:) = zqlw(:,:) - zqsb(:,:) - zqla(:,:)                                &   ! Downward Non Solar
559         &     - sf(jp_snow)%fnow(:,:,1) * rn_pfac * rLfus                        &   ! remove latent melting heat for solid precip
560         &     - zevap(:,:) * zcptn(:,:)                                          &   ! remove evap heat content at SST
561         &     + ( sf(jp_prec)%fnow(:,:,1) - sf(jp_snow)%fnow(:,:,1) ) * rn_pfac  &   ! add liquid precip heat content at Tair
562         &     * zcptrain(:,:)                                                    &
563         &     + sf(jp_snow)%fnow(:,:,1) * rn_pfac                                &   ! add solid  precip heat content at min(Tair,Tsnow)
564         &     * zcptsnw(:,:)
565      qns(:,:) = qns(:,:) * tmask(:,:,1)
566      !
567#if defined key_si3
568      qns_oce(:,:) = zqlw(:,:) - zqsb(:,:) - zqla(:,:)                                ! non solar without emp (only needed by SI3)
569      qsr_oce(:,:) = qsr(:,:)
570#endif
571      !
572      IF ( nn_ice == 0 ) THEN
573         CALL iom_put( "qlw_oce" ,   zqlw )                 ! output downward longwave heat over the ocean
574         CALL iom_put( "qsb_oce" , - zqsb )                 ! output downward sensible heat over the ocean
575         CALL iom_put( "qla_oce" , - zqla )                 ! output downward latent   heat over the ocean
576         CALL iom_put( "qemp_oce",   qns-zqlw+zqsb+zqla )   ! output downward heat content of E-P over the ocean
577         CALL iom_put( "qns_oce" ,   qns  )                 ! output downward non solar heat over the ocean
578         CALL iom_put( "qsr_oce" ,   qsr  )                 ! output downward solar heat over the ocean
579         CALL iom_put( "qt_oce"  ,   qns+qsr )              ! output total downward heat over the ocean
580         tprecip(:,:) = sf(jp_prec)%fnow(:,:,1) * rn_pfac * tmask(:,:,1) ! output total precipitation [kg/m2/s]
581         sprecip(:,:) = sf(jp_snow)%fnow(:,:,1) * rn_pfac * tmask(:,:,1) ! output solid precipitation [kg/m2/s]
582         CALL iom_put( 'snowpre', sprecip )                 ! Snow
583         CALL iom_put( 'precip' , tprecip )                 ! Total precipitation
584      ENDIF
585      !
586      IF(ln_ctl) THEN
587         CALL prt_ctl(tab2d_1=zqsb , clinfo1=' blk_oce: zqsb   : ', tab2d_2=zqlw , clinfo2=' zqlw  : ')
588         CALL prt_ctl(tab2d_1=zqla , clinfo1=' blk_oce: zqla   : ', tab2d_2=qsr  , clinfo2=' qsr   : ')
589         CALL prt_ctl(tab2d_1=pst  , clinfo1=' blk_oce: pst    : ', tab2d_2=emp  , clinfo2=' emp   : ')
590         CALL prt_ctl(tab2d_1=utau , clinfo1=' blk_oce: utau   : ', mask1=umask,   &
591            &         tab2d_2=vtau , clinfo2=              ' vtau  : ' , mask2=vmask )
592      ENDIF
593      !
594   END SUBROUTINE blk_oce
595
596
597
598   FUNCTION rho_air( ptak, pqa, pslp )
599      !!-------------------------------------------------------------------------------
600      !!                           ***  FUNCTION rho_air  ***
601      !!
602      !! ** Purpose : compute density of (moist) air using the eq. of state of the atmosphere
603      !!
604      !! ** Author: L. Brodeau, june 2016 / AeroBulk (https://sourceforge.net/p/aerobulk)
605      !!-------------------------------------------------------------------------------
606      REAL(wp), DIMENSION(jpi,jpj), INTENT(in) ::   ptak      ! air temperature             [K]
607      REAL(wp), DIMENSION(jpi,jpj), INTENT(in) ::   pqa       ! air specific humidity   [kg/kg]
608      REAL(wp), DIMENSION(jpi,jpj), INTENT(in) ::   pslp      ! pressure in                [Pa]
609      REAL(wp), DIMENSION(jpi,jpj)             ::   rho_air   ! density of moist air   [kg/m^3]
610      !!-------------------------------------------------------------------------------
611      !
612      rho_air = pslp / (  R_dry*ptak * ( 1._wp + rctv0*pqa )  )
613      !
614   END FUNCTION rho_air
615
616
617   FUNCTION cp_air( pqa )
618      !!-------------------------------------------------------------------------------
619      !!                           ***  FUNCTION cp_air  ***
620      !!
621      !! ** Purpose : Compute specific heat (Cp) of moist air
622      !!
623      !! ** Author: L. Brodeau, june 2016 / AeroBulk (https://sourceforge.net/p/aerobulk)
624      !!-------------------------------------------------------------------------------
625      REAL(wp), DIMENSION(jpi,jpj), INTENT(in) ::   pqa      ! air specific humidity         [kg/kg]
626      REAL(wp), DIMENSION(jpi,jpj)             ::   cp_air   ! specific heat of moist air   [J/K/kg]
627      !!-------------------------------------------------------------------------------
628      !
629      Cp_air = Cp_dry + Cp_vap * pqa
630      !
631   END FUNCTION cp_air
632
633
634   FUNCTION q_sat( ptak, pslp )
635      !!----------------------------------------------------------------------------------
636      !!                           ***  FUNCTION q_sat  ***
637      !!
638      !! ** Purpose : Specific humidity at saturation in [kg/kg]
639      !!              Based on accurate estimate of "e_sat"
640      !!              aka saturation water vapor (Goff, 1957)
641      !!
642      !! ** Author: L. Brodeau, june 2016 / AeroBulk (https://sourceforge.net/p/aerobulk)
643      !!----------------------------------------------------------------------------------
644      REAL(wp), DIMENSION(jpi,jpj), INTENT(in) ::   ptak    ! air temperature                       [K]
645      REAL(wp), DIMENSION(jpi,jpj), INTENT(in) ::   pslp    ! sea level atmospheric pressure       [Pa]
646      REAL(wp), DIMENSION(jpi,jpj)             ::   q_sat   ! Specific humidity at saturation   [kg/kg]
647      !
648      INTEGER  ::   ji, jj         ! dummy loop indices
649      REAL(wp) ::   ze_sat, ztmp   ! local scalar
650      !!----------------------------------------------------------------------------------
651      !
652      DO jj = 1, jpj
653         DO ji = 1, jpi
654            !
655            ztmp = rt0 / ptak(ji,jj)
656            !
657            ! Vapour pressure at saturation [hPa] : WMO, (Goff, 1957)
658            ze_sat = 10.**( 10.79574*(1. - ztmp) - 5.028*LOG10(ptak(ji,jj)/rt0)        &
659               &    + 1.50475*10.**(-4)*(1. - 10.**(-8.2969*(ptak(ji,jj)/rt0 - 1.)) )  &
660               &    + 0.42873*10.**(-3)*(10.**(4.76955*(1. - ztmp)) - 1.) + 0.78614  )
661               !
662            q_sat(ji,jj) = reps0 * ze_sat/( 0.01_wp*pslp(ji,jj) - (1._wp - reps0)*ze_sat )   ! 0.01 because SLP is in [Pa]
663            !
664         END DO
665      END DO
666      !
667   END FUNCTION q_sat
668
669
670   FUNCTION gamma_moist( ptak, pqa )
671      !!----------------------------------------------------------------------------------
672      !!                           ***  FUNCTION gamma_moist  ***
673      !!
674      !! ** Purpose : Compute the moist adiabatic lapse-rate.
675      !!     => http://glossary.ametsoc.org/wiki/Moist-adiabatic_lapse_rate
676      !!     => http://www.geog.ucsb.edu/~joel/g266_s10/lecture_notes/chapt03/oh10_3_01/oh10_3_01.html
677      !!
678      !! ** Author: L. Brodeau, june 2016 / AeroBulk (https://sourceforge.net/p/aerobulk)
679      !!----------------------------------------------------------------------------------
680      REAL(wp), DIMENSION(jpi,jpj), INTENT(in) ::   ptak          ! air temperature       [K]
681      REAL(wp), DIMENSION(jpi,jpj), INTENT(in) ::   pqa           ! specific humidity [kg/kg]
682      REAL(wp), DIMENSION(jpi,jpj)             ::   gamma_moist   ! moist adiabatic lapse-rate
683      !
684      INTEGER  ::   ji, jj         ! dummy loop indices
685      REAL(wp) :: zrv, ziRT        ! local scalar
686      !!----------------------------------------------------------------------------------
687      !
688      DO jj = 1, jpj
689         DO ji = 1, jpi
690            zrv = pqa(ji,jj) / (1. - pqa(ji,jj))
691            ziRT = 1. / (R_dry*ptak(ji,jj))    ! 1/RT
692            gamma_moist(ji,jj) = grav * ( 1. + rLevap*zrv*ziRT ) / ( Cp_dry + rLevap*rLevap*zrv*reps0*ziRT/ptak(ji,jj) )
693         END DO
694      END DO
695      !
696   END FUNCTION gamma_moist
697
698
699   FUNCTION L_vap( psst )
700      !!---------------------------------------------------------------------------------
701      !!                           ***  FUNCTION L_vap  ***
702      !!
703      !! ** Purpose : Compute the latent heat of vaporization of water from temperature
704      !!
705      !! ** Author: L. Brodeau, june 2016 / AeroBulk (https://sourceforge.net/p/aerobulk)
706      !!----------------------------------------------------------------------------------
707      REAL(wp), DIMENSION(jpi,jpj)             ::   L_vap   ! latent heat of vaporization   [J/kg]
708      REAL(wp), DIMENSION(jpi,jpj), INTENT(in) ::   psst   ! water temperature                [K]
709      !!----------------------------------------------------------------------------------
710      !
711      L_vap = (  2.501 - 0.00237 * ( psst(:,:) - rt0)  ) * 1.e6
712      !
713   END FUNCTION L_vap
714
715#if defined key_si3
716   !!----------------------------------------------------------------------
717   !!   'key_si3'                                       SI3 sea-ice model
718   !!----------------------------------------------------------------------
719   !!   blk_ice_tau : provide the air-ice stress
720   !!   blk_ice_flx : provide the heat and mass fluxes at air-ice interface
721   !!   blk_ice_qcn : provide ice surface temperature and snow/ice conduction flux (emulating conduction flux)
722   !!   Cdn10_Lupkes2012 : Lupkes et al. (2012) air-ice drag
723   !!   Cdn10_Lupkes2015 : Lupkes et al. (2015) air-ice drag
724   !!----------------------------------------------------------------------
725
726   SUBROUTINE blk_ice_tau
727      !!---------------------------------------------------------------------
728      !!                     ***  ROUTINE blk_ice_tau  ***
729      !!
730      !! ** Purpose :   provide the surface boundary condition over sea-ice
731      !!
732      !! ** Method  :   compute momentum using bulk formulation
733      !!                formulea, ice variables and read atmospheric fields.
734      !!                NB: ice drag coefficient is assumed to be a constant
735      !!---------------------------------------------------------------------
736      INTEGER  ::   ji, jj    ! dummy loop indices
737      REAL(wp) ::   zwndi_f , zwndj_f, zwnorm_f   ! relative wind module and components at F-point
738      REAL(wp) ::   zwndi_t , zwndj_t             ! relative wind components at T-point
739      REAL(wp) ::   zztmp1  , zztmp2              ! temporary values
740      REAL(wp), DIMENSION(jpi,jpj) ::   zrhoa     ! transfer coefficient for momentum      (tau)
741      !!---------------------------------------------------------------------
742      !
743      ! set transfer coefficients to default sea-ice values
744      Cd_atm(:,:) = Cd_ice
745      Ch_atm(:,:) = Cd_ice
746      Ce_atm(:,:) = Cd_ice
747
748      wndm_ice(:,:) = 0._wp      !!gm brutal....
749
750      ! ------------------------------------------------------------ !
751      !    Wind module relative to the moving ice ( U10m - U_ice )   !
752      ! ------------------------------------------------------------ !
753      ! C-grid ice dynamics :   U & V-points (same as ocean)
754      DO jj = 2, jpjm1
755         DO ji = fs_2, fs_jpim1   ! vect. opt.
756            zwndi_t = (  sf(jp_wndi)%fnow(ji,jj,1) - rn_vfac * 0.5 * ( u_ice(ji-1,jj  ) + u_ice(ji,jj) )  )
757            zwndj_t = (  sf(jp_wndj)%fnow(ji,jj,1) - rn_vfac * 0.5 * ( v_ice(ji  ,jj-1) + v_ice(ji,jj) )  )
758            wndm_ice(ji,jj) = SQRT( zwndi_t * zwndi_t + zwndj_t * zwndj_t ) * tmask(ji,jj,1)
759         END DO
760      END DO
761      CALL lbc_lnk( 'sbcblk', wndm_ice, 'T',  1. )
762      !
763      ! Make ice-atm. drag dependent on ice concentration
764      IF    ( ln_Cd_L12 ) THEN   ! calculate new drag from Lupkes(2012) equations
765         CALL Cdn10_Lupkes2012( Cd_atm )
766         Ch_atm(:,:) = Cd_atm(:,:)       ! momentum and heat transfer coef. are considered identical
767      ELSEIF( ln_Cd_L15 ) THEN   ! calculate new drag from Lupkes(2015) equations
768         CALL Cdn10_Lupkes2015( Cd_atm, Ch_atm ) 
769      ENDIF
770
771!!      CALL iom_put( "Cd_ice", Cd_atm)  ! output value of pure ice-atm. transfer coef.
772!!      CALL iom_put( "Ch_ice", Ch_atm)  ! output value of pure ice-atm. transfer coef.
773
774      ! local scalars ( place there for vector optimisation purposes)
775      ! Computing density of air! Way denser that 1.2 over sea-ice !!!
776      zrhoa (:,:) =  rho_air(sf(jp_tair)%fnow(:,:,1), sf(jp_humi)%fnow(:,:,1), sf(jp_slp)%fnow(:,:,1))
777
778      ! ------------------------------------------------------------ !
779      !    Wind stress relative to the moving ice ( U10m - U_ice )   !
780      ! ------------------------------------------------------------ !
781      zztmp1 = rn_vfac * 0.5_wp
782      DO jj = 2, jpj    ! at T point
783         DO ji = 2, jpi
784            zztmp2 = zrhoa(ji,jj) * Cd_atm(ji,jj) * wndm_ice(ji,jj)
785            utau_ice(ji,jj) = zztmp2 * ( sf(jp_wndi)%fnow(ji,jj,1) - zztmp1 * ( u_ice(ji-1,jj  ) + u_ice(ji,jj) ) )
786            vtau_ice(ji,jj) = zztmp2 * ( sf(jp_wndj)%fnow(ji,jj,1) - zztmp1 * ( v_ice(ji  ,jj-1) + v_ice(ji,jj) ) )
787         END DO
788      END DO
789      !
790      DO jj = 2, jpjm1  ! U & V-points (same as ocean).
791         DO ji = fs_2, fs_jpim1   ! vect. opt.
792            ! take care of the land-sea mask to avoid "pollution" of coastal stress. p[uv]taui used in frazil and  rheology
793            zztmp1 = 0.5_wp * ( 2. - umask(ji,jj,1) ) * MAX( tmask(ji,jj,1),tmask(ji+1,jj  ,1) )
794            zztmp2 = 0.5_wp * ( 2. - vmask(ji,jj,1) ) * MAX( tmask(ji,jj,1),tmask(ji  ,jj+1,1) )
795            utau_ice(ji,jj) = zztmp1 * ( utau_ice(ji,jj) + utau_ice(ji+1,jj  ) )
796            vtau_ice(ji,jj) = zztmp2 * ( vtau_ice(ji,jj) + vtau_ice(ji  ,jj+1) )
797         END DO
798      END DO
799      CALL lbc_lnk_multi( 'sbcblk', utau_ice, 'U', -1., vtau_ice, 'V', -1. )
800      !
801      !
802      IF(ln_ctl) THEN
803         CALL prt_ctl(tab2d_1=utau_ice  , clinfo1=' blk_ice: utau_ice : ', tab2d_2=vtau_ice  , clinfo2=' vtau_ice : ')
804         CALL prt_ctl(tab2d_1=wndm_ice  , clinfo1=' blk_ice: wndm_ice : ')
805      ENDIF
806      !
807   END SUBROUTINE blk_ice_tau
808
809
810   SUBROUTINE blk_ice_flx( ptsu, phs, phi, palb )
811      !!---------------------------------------------------------------------
812      !!                     ***  ROUTINE blk_ice_flx  ***
813      !!
814      !! ** Purpose :   provide the heat and mass fluxes at air-ice interface
815      !!
816      !! ** Method  :   compute heat and freshwater exchanged
817      !!                between atmosphere and sea-ice using bulk formulation
818      !!                formulea, ice variables and read atmmospheric fields.
819      !!
820      !! caution : the net upward water flux has with mm/day unit
821      !!---------------------------------------------------------------------
822      REAL(wp), DIMENSION(:,:,:), INTENT(in)  ::   ptsu   ! sea ice surface temperature
823      REAL(wp), DIMENSION(:,:,:), INTENT(in)  ::   phs    ! snow thickness
824      REAL(wp), DIMENSION(:,:,:), INTENT(in)  ::   phi    ! ice thickness
825      REAL(wp), DIMENSION(:,:,:), INTENT(in)  ::   palb   ! ice albedo (all skies)
826      !!
827      INTEGER  ::   ji, jj, jl               ! dummy loop indices
828      REAL(wp) ::   zst3                     ! local variable
829      REAL(wp) ::   zcoef_dqlw, zcoef_dqla   !   -      -
830      REAL(wp) ::   zztmp, z1_rLsub          !   -      -
831      REAL(wp), DIMENSION(jpi,jpj,jpl) ::   z1_st         ! inverse of surface temperature
832      REAL(wp), DIMENSION(jpi,jpj,jpl) ::   z_qlw         ! long wave heat flux over ice
833      REAL(wp), DIMENSION(jpi,jpj,jpl) ::   z_qsb         ! sensible  heat flux over ice
834      REAL(wp), DIMENSION(jpi,jpj,jpl) ::   z_dqlw        ! long wave heat sensitivity over ice
835      REAL(wp), DIMENSION(jpi,jpj,jpl) ::   z_dqsb        ! sensible  heat sensitivity over ice
836      REAL(wp), DIMENSION(jpi,jpj)     ::   zevap, zsnw   ! evaporation and snw distribution after wind blowing (SI3)
837      REAL(wp), DIMENSION(jpi,jpj)     ::   zrhoa
838      REAL(wp), DIMENSION(jpi,jpj)     ::   ztri
839      REAL(wp), DIMENSION(jpi,jpj)     ::   zcptrain, zcptsnw, zcptn ! Heat content per unit mass (J/kg)
840      !!---------------------------------------------------------------------
841      !
842      zcoef_dqlw = 4.0 * 0.95 * Stef             ! local scalars
843      zcoef_dqla = -Ls * 11637800. * (-5897.8)
844      !
845      zrhoa(:,:) = rho_air( sf(jp_tair)%fnow(:,:,1), sf(jp_humi)%fnow(:,:,1), sf(jp_slp)%fnow(:,:,1) )
846      !
847      ! Heat content per unit mass (J/kg)
848      zcptrain(:,:) = (      sf(jp_tair)%fnow(:,:,1)        - rt0 ) * rcp  * tmask(:,:,1)
849      zcptsnw (:,:) = ( MIN( sf(jp_tair)%fnow(:,:,1), rt0 ) - rt0 ) * rcpi * tmask(:,:,1)
850      zcptn   (:,:) =        sst_m(:,:)                             * rcp  * tmask(:,:,1)
851      !
852      zztmp = 1. / ( 1. - albo )
853      WHERE( ptsu(:,:,:) /= 0._wp )   ;   z1_st(:,:,:) = 1._wp / ptsu(:,:,:)
854      ELSEWHERE                       ;   z1_st(:,:,:) = 0._wp
855      END WHERE
856      !                                     ! ========================== !
857      DO jl = 1, jpl                        !  Loop over ice categories  !
858         !                                  ! ========================== !
859         DO jj = 1 , jpj
860            DO ji = 1, jpi
861               ! ----------------------------!
862               !      I   Radiative FLUXES   !
863               ! ----------------------------!
864               zst3 = ptsu(ji,jj,jl) * ptsu(ji,jj,jl) * ptsu(ji,jj,jl)
865               ! Short Wave (sw)
866               qsr_ice(ji,jj,jl) = zztmp * ( 1. - palb(ji,jj,jl) ) * qsr(ji,jj)
867               ! Long  Wave (lw)
868               z_qlw(ji,jj,jl) = 0.95 * ( sf(jp_qlw)%fnow(ji,jj,1) - Stef * ptsu(ji,jj,jl) * zst3 ) * tmask(ji,jj,1)
869               ! lw sensitivity
870               z_dqlw(ji,jj,jl) = zcoef_dqlw * zst3
871
872               ! ----------------------------!
873               !     II    Turbulent FLUXES  !
874               ! ----------------------------!
875
876               ! ... turbulent heat fluxes with Ch_atm recalculated in blk_ice_tau
877               ! Sensible Heat
878               z_qsb(ji,jj,jl) = zrhoa(ji,jj) * cpa * Ch_atm(ji,jj) * wndm_ice(ji,jj) * (ptsu(ji,jj,jl) - sf(jp_tair)%fnow(ji,jj,1))
879               ! Latent Heat
880               qla_ice(ji,jj,jl) = rn_efac * MAX( 0.e0, zrhoa(ji,jj) * Ls  * Ch_atm(ji,jj) * wndm_ice(ji,jj) *  &
881                  &                ( 11637800. * EXP( -5897.8 * z1_st(ji,jj,jl) ) / zrhoa(ji,jj) - sf(jp_humi)%fnow(ji,jj,1) ) )
882               ! Latent heat sensitivity for ice (Dqla/Dt)
883               IF( qla_ice(ji,jj,jl) > 0._wp ) THEN
884                  dqla_ice(ji,jj,jl) = rn_efac * zcoef_dqla * Ch_atm(ji,jj) * wndm_ice(ji,jj) *  &
885                     &                 z1_st(ji,jj,jl)*z1_st(ji,jj,jl) * EXP(-5897.8 * z1_st(ji,jj,jl))
886               ELSE
887                  dqla_ice(ji,jj,jl) = 0._wp
888               ENDIF
889
890               ! Sensible heat sensitivity (Dqsb_ice/Dtn_ice)
891               z_dqsb(ji,jj,jl) = zrhoa(ji,jj) * cpa * Ch_atm(ji,jj) * wndm_ice(ji,jj)
892
893               ! ----------------------------!
894               !     III    Total FLUXES     !
895               ! ----------------------------!
896               ! Downward Non Solar flux
897               qns_ice (ji,jj,jl) =     z_qlw (ji,jj,jl) - z_qsb (ji,jj,jl) - qla_ice (ji,jj,jl)
898               ! Total non solar heat flux sensitivity for ice
899               dqns_ice(ji,jj,jl) = - ( z_dqlw(ji,jj,jl) + z_dqsb(ji,jj,jl) + dqla_ice(ji,jj,jl) )
900            END DO
901            !
902         END DO
903         !
904      END DO
905      !
906      tprecip(:,:) = sf(jp_prec)%fnow(:,:,1) * rn_pfac * tmask(:,:,1)  ! total precipitation [kg/m2/s]
907      sprecip(:,:) = sf(jp_snow)%fnow(:,:,1) * rn_pfac * tmask(:,:,1)  ! solid precipitation [kg/m2/s]
908      CALL iom_put( 'snowpre', sprecip )                    ! Snow precipitation
909      CALL iom_put( 'precip' , tprecip )                    ! Total precipitation
910
911      ! --- evaporation --- !
912      z1_rLsub = 1._wp / rLsub
913      evap_ice (:,:,:) = rn_efac * qla_ice (:,:,:) * z1_rLsub    ! sublimation
914      devap_ice(:,:,:) = rn_efac * dqla_ice(:,:,:) * z1_rLsub    ! d(sublimation)/dT
915      zevap    (:,:)   = rn_efac * ( emp(:,:) + tprecip(:,:) )   ! evaporation over ocean
916
917      ! --- evaporation minus precipitation --- !
918      zsnw(:,:) = 0._wp
919      CALL ice_var_snwblow( (1.-at_i_b(:,:)), zsnw )  ! snow distribution over ice after wind blowing
920      emp_oce(:,:) = ( 1._wp - at_i_b(:,:) ) * zevap(:,:) - ( tprecip(:,:) - sprecip(:,:) ) - sprecip(:,:) * (1._wp - zsnw )
921      emp_ice(:,:) = SUM( a_i_b(:,:,:) * evap_ice(:,:,:), dim=3 ) - sprecip(:,:) * zsnw
922      emp_tot(:,:) = emp_oce(:,:) + emp_ice(:,:)
923
924      ! --- heat flux associated with emp --- !
925      qemp_oce(:,:) = - ( 1._wp - at_i_b(:,:) ) * zevap(:,:) * zcptn(:,:)         & ! evap at sst
926         &          + ( tprecip(:,:) - sprecip(:,:) )   *   zcptrain(:,:)         & ! liquid precip at Tair
927         &          +   sprecip(:,:) * ( 1._wp - zsnw ) * ( zcptsnw (:,:) - rLfus ) ! solid precip at min(Tair,Tsnow)
928      qemp_ice(:,:) =   sprecip(:,:) *           zsnw   * ( zcptsnw (:,:) - rLfus ) ! solid precip (only)
929
930      ! --- total solar and non solar fluxes --- !
931      qns_tot(:,:) = ( 1._wp - at_i_b(:,:) ) * qns_oce(:,:) + SUM( a_i_b(:,:,:) * qns_ice(:,:,:), dim=3 )  &
932         &           + qemp_ice(:,:) + qemp_oce(:,:)
933      qsr_tot(:,:) = ( 1._wp - at_i_b(:,:) ) * qsr_oce(:,:) + SUM( a_i_b(:,:,:) * qsr_ice(:,:,:), dim=3 )
934
935      ! --- heat content of precip over ice in J/m3 (to be used in 1D-thermo) --- !
936      qprec_ice(:,:) = rhos * ( zcptsnw(:,:) - rLfus )
937
938      ! --- heat content of evap over ice in W/m2 (to be used in 1D-thermo) ---
939      DO jl = 1, jpl
940         qevap_ice(:,:,jl) = 0._wp ! should be -evap_ice(:,:,jl)*( ( Tice - rt0 ) * rcpi * tmask(:,:,1) )
941         !                         ! But we do not have Tice => consider it at 0degC => evap=0
942      END DO
943
944      ! --- shortwave radiation transmitted thru the surface scattering layer (W/m2) --- !
945      IF( nn_qtrice == 0 ) THEN
946         ! formulation derived from Grenfell and Maykut (1977), where transmission rate
947         !    1) depends on cloudiness
948         !    2) is 0 when there is any snow
949         !    3) tends to 1 for thin ice
950         ztri(:,:) = 0.18 * ( 1.0 - cloud_fra(:,:) ) + 0.35 * cloud_fra(:,:)  ! surface transmission when hi>10cm
951         DO jl = 1, jpl
952            WHERE    ( phs(:,:,jl) <= 0._wp .AND. phi(:,:,jl) <  0.1_wp )     ! linear decrease from hi=0 to 10cm 
953               qtr_ice_top(:,:,jl) = qsr_ice(:,:,jl) * ( ztri(:,:) + ( 1._wp - ztri(:,:) ) * ( 1._wp - phi(:,:,jl) * 10._wp ) )
954            ELSEWHERE( phs(:,:,jl) <= 0._wp .AND. phi(:,:,jl) >= 0.1_wp )     ! constant (ztri) when hi>10cm
955               qtr_ice_top(:,:,jl) = qsr_ice(:,:,jl) * ztri(:,:)
956            ELSEWHERE                                                         ! zero when hs>0
957               qtr_ice_top(:,:,jl) = 0._wp 
958            END WHERE
959         ENDDO
960      ELSEIF( nn_qtrice == 1 ) THEN
961         ! formulation is derived from the thesis of M. Lebrun (2019).
962         !    It represents the best fit using several sets of observations
963         !    It comes with snow conductivities adapted to freezing/melting conditions (see icethd_zdf_bl99.F90)
964         qtr_ice_top(:,:,:) = 0.3_wp * qsr_ice(:,:,:)
965      ENDIF
966      !
967
968      IF( iom_use('evap_ao_cea') .OR. iom_use('hflx_evap_cea') ) THEN
969         CALL iom_put( 'evap_ao_cea'  , zevap(:,:) * ( 1._wp - at_i_b(:,:) ) * tmask(:,:,1)              )   ! ice-free oce evap (cell average)
970         CALL iom_put( 'hflx_evap_cea', zevap(:,:) * ( 1._wp - at_i_b(:,:) ) * tmask(:,:,1) * zcptn(:,:) )   ! heat flux from evap (cell average)
971      ENDIF
972      IF( iom_use('rain') .OR. iom_use('rain_ao_cea') .OR. iom_use('hflx_rain_cea') ) THEN
973         CALL iom_put( 'rain'         ,   tprecip(:,:) - sprecip(:,:)                             )          ! liquid precipitation
974         CALL iom_put( 'rain_ao_cea'  , ( tprecip(:,:) - sprecip(:,:) ) * ( 1._wp - at_i_b(:,:) ) )          ! liquid precipitation over ocean (cell average)
975         CALL iom_put( 'hflx_rain_cea', ( tprecip(:,:) - sprecip(:,:) ) * zcptrain(:,:) )                    ! heat flux from rain (cell average)
976      ENDIF
977      IF(  iom_use('snow_ao_cea')   .OR. iom_use('snow_ai_cea')      .OR. &
978         & iom_use('hflx_snow_cea') .OR. iom_use('hflx_snow_ao_cea') .OR. iom_use('hflx_snow_ai_cea')  )  THEN
979         CALL iom_put( 'snow_ao_cea'     , sprecip(:,:)                            * ( 1._wp - zsnw(:,:) ) ) ! Snow over ice-free ocean  (cell average)
980         CALL iom_put( 'snow_ai_cea'     , sprecip(:,:)                            *           zsnw(:,:)   ) ! Snow over sea-ice         (cell average)
981         CALL iom_put( 'hflx_snow_cea'   , sprecip(:,:) * ( zcptsnw(:,:) - rLfus ) )                         ! heat flux from snow (cell average)
982         CALL iom_put( 'hflx_snow_ao_cea', sprecip(:,:) * ( zcptsnw(:,:) - rLfus ) * ( 1._wp - zsnw(:,:) ) ) ! heat flux from snow (over ocean)
983         CALL iom_put( 'hflx_snow_ai_cea', sprecip(:,:) * ( zcptsnw(:,:) - rLfus ) *           zsnw(:,:)   ) ! heat flux from snow (over ice)
984      ENDIF
985      IF( iom_use('hflx_prec_cea') ) THEN                                                                    ! heat flux from precip (cell average)
986         CALL iom_put('hflx_prec_cea' ,    sprecip(:,:)                  * ( zcptsnw (:,:) - rLfus )  &
987            &                          + ( tprecip(:,:) - sprecip(:,:) ) *   zcptrain(:,:) )
988      ENDIF
989      !
990      IF( iom_use('subl_ai_cea') .OR. iom_use('hflx_subl_cea') ) THEN
991         CALL iom_put( 'subl_ai_cea'  , SUM( a_i_b(:,:,:) *  evap_ice(:,:,:), dim=3 ) * tmask(:,:,1) ) ! Sublimation over sea-ice (cell average)
992         CALL iom_put( 'hflx_subl_cea', SUM( a_i_b(:,:,:) * qevap_ice(:,:,:), dim=3 ) * tmask(:,:,1) ) ! Heat flux from sublimation (cell average)
993      ENDIF
994     
995      IF(ln_ctl) THEN
996         CALL prt_ctl(tab3d_1=qla_ice , clinfo1=' blk_ice: qla_ice  : ', tab3d_2=z_qsb   , clinfo2=' z_qsb    : ', kdim=jpl)
997         CALL prt_ctl(tab3d_1=z_qlw   , clinfo1=' blk_ice: z_qlw    : ', tab3d_2=dqla_ice, clinfo2=' dqla_ice : ', kdim=jpl)
998         CALL prt_ctl(tab3d_1=z_dqsb  , clinfo1=' blk_ice: z_dqsb   : ', tab3d_2=z_dqlw  , clinfo2=' z_dqlw   : ', kdim=jpl)
999         CALL prt_ctl(tab3d_1=dqns_ice, clinfo1=' blk_ice: dqns_ice : ', tab3d_2=qsr_ice , clinfo2=' qsr_ice  : ', kdim=jpl)
1000         CALL prt_ctl(tab3d_1=ptsu    , clinfo1=' blk_ice: ptsu     : ', tab3d_2=qns_ice , clinfo2=' qns_ice  : ', kdim=jpl)
1001         CALL prt_ctl(tab2d_1=tprecip , clinfo1=' blk_ice: tprecip  : ', tab2d_2=sprecip , clinfo2=' sprecip  : ')
1002      ENDIF
1003      !
1004   END SUBROUTINE blk_ice_flx
1005   
1006
1007   SUBROUTINE blk_ice_qcn( ld_virtual_itd, ptsu, ptb, phs, phi )
1008      !!---------------------------------------------------------------------
1009      !!                     ***  ROUTINE blk_ice_qcn  ***
1010      !!
1011      !! ** Purpose :   Compute surface temperature and snow/ice conduction flux
1012      !!                to force sea ice / snow thermodynamics
1013      !!                in the case conduction flux is emulated
1014      !!               
1015      !! ** Method  :   compute surface energy balance assuming neglecting heat storage
1016      !!                following the 0-layer Semtner (1976) approach
1017      !!
1018      !! ** Outputs : - ptsu    : sea-ice / snow surface temperature (K)
1019      !!              - qcn_ice : surface inner conduction flux (W/m2)
1020      !!
1021      !!---------------------------------------------------------------------
1022      LOGICAL                   , INTENT(in   ) ::   ld_virtual_itd  ! single-category option
1023      REAL(wp), DIMENSION(:,:,:), INTENT(inout) ::   ptsu            ! sea ice / snow surface temperature
1024      REAL(wp), DIMENSION(:,:)  , INTENT(in   ) ::   ptb             ! sea ice base temperature
1025      REAL(wp), DIMENSION(:,:,:), INTENT(in   ) ::   phs             ! snow thickness
1026      REAL(wp), DIMENSION(:,:,:), INTENT(in   ) ::   phi             ! sea ice thickness
1027      !
1028      INTEGER , PARAMETER ::   nit = 10                  ! number of iterations
1029      REAL(wp), PARAMETER ::   zepsilon = 0.1_wp         ! characteristic thickness for enhanced conduction
1030      !
1031      INTEGER  ::   ji, jj, jl           ! dummy loop indices
1032      INTEGER  ::   iter                 ! local integer
1033      REAL(wp) ::   zfac, zfac2, zfac3   ! local scalars
1034      REAL(wp) ::   zkeff_h, ztsu, ztsu0 !
1035      REAL(wp) ::   zqc, zqnet           !
1036      REAL(wp) ::   zhe, zqa0            !
1037      REAL(wp), DIMENSION(jpi,jpj,jpl) ::   zgfac   ! enhanced conduction factor
1038      !!---------------------------------------------------------------------
1039     
1040      ! -------------------------------------!
1041      !      I   Enhanced conduction factor  !
1042      ! -------------------------------------!
1043      ! Emulates the enhancement of conduction by unresolved thin ice (ld_virtual_itd = T)
1044      ! Fichefet and Morales Maqueda, JGR 1997
1045      !
1046      zgfac(:,:,:) = 1._wp
1047     
1048      IF( ld_virtual_itd ) THEN
1049         !
1050         zfac  = 1._wp /  ( rn_cnd_s + rcnd_i )
1051         zfac2 = EXP(1._wp) * 0.5_wp * zepsilon
1052         zfac3 = 2._wp / zepsilon
1053         !   
1054         DO jl = 1, jpl               
1055            DO jj = 1 , jpj
1056               DO ji = 1, jpi
1057                  zhe = ( rn_cnd_s * phi(ji,jj,jl) + rcnd_i * phs(ji,jj,jl) ) * zfac                            ! Effective thickness
1058                  IF( zhe >=  zfac2 )   zgfac(ji,jj,jl) = MIN( 2._wp, 0.5_wp * ( 1._wp + LOG( zhe * zfac3 ) ) ) ! Enhanced conduction factor
1059               END DO
1060            END DO
1061         END DO
1062         !     
1063      ENDIF
1064     
1065      ! -------------------------------------------------------------!
1066      !      II   Surface temperature and conduction flux            !
1067      ! -------------------------------------------------------------!
1068      !
1069      zfac = rcnd_i * rn_cnd_s
1070      !
1071      DO jl = 1, jpl
1072         DO jj = 1 , jpj
1073            DO ji = 1, jpi
1074               !                   
1075               zkeff_h = zfac * zgfac(ji,jj,jl) / &                                    ! Effective conductivity of the snow-ice system divided by thickness
1076                  &      ( rcnd_i * phs(ji,jj,jl) + rn_cnd_s * MAX( 0.01, phi(ji,jj,jl) ) )
1077               ztsu    = ptsu(ji,jj,jl)                                                ! Store current iteration temperature
1078               ztsu0   = ptsu(ji,jj,jl)                                                ! Store initial surface temperature
1079               zqa0    = qsr_ice(ji,jj,jl) - qtr_ice_top(ji,jj,jl) + qns_ice(ji,jj,jl) ! Net initial atmospheric heat flux
1080               !
1081               DO iter = 1, nit     ! --- Iterative loop
1082                  zqc   = zkeff_h * ( ztsu - ptb(ji,jj) )                              ! Conduction heat flux through snow-ice system (>0 downwards)
1083                  zqnet = zqa0 + dqns_ice(ji,jj,jl) * ( ztsu - ptsu(ji,jj,jl) ) - zqc  ! Surface energy budget
1084                  ztsu  = ztsu - zqnet / ( dqns_ice(ji,jj,jl) - zkeff_h )              ! Temperature update
1085               END DO
1086               !
1087               ptsu   (ji,jj,jl) = MIN( rt0, ztsu )
1088               qcn_ice(ji,jj,jl) = zkeff_h * ( ptsu(ji,jj,jl) - ptb(ji,jj) )
1089               qns_ice(ji,jj,jl) = qns_ice(ji,jj,jl) + dqns_ice(ji,jj,jl) * ( ptsu(ji,jj,jl) - ztsu0 )
1090               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) )  &
1091                             &   * MAX( 0._wp , SIGN( 1._wp, ptsu(ji,jj,jl) - rt0 ) )
1092
1093               ! --- Diagnose the heat loss due to changing non-solar flux (as in icethd_zdf_bl99) --- !
1094               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) 
1095
1096            END DO
1097         END DO
1098         !
1099      END DO 
1100      !     
1101   END SUBROUTINE blk_ice_qcn
1102   
1103
1104   SUBROUTINE Cdn10_Lupkes2012( Cd )
1105      !!----------------------------------------------------------------------
1106      !!                      ***  ROUTINE  Cdn10_Lupkes2012  ***
1107      !!
1108      !! ** Purpose :    Recompute the neutral air-ice drag referenced at 10m
1109      !!                 to make it dependent on edges at leads, melt ponds and flows.
1110      !!                 After some approximations, this can be resumed to a dependency
1111      !!                 on ice concentration.
1112      !!               
1113      !! ** Method :     The parameterization is taken from Lupkes et al. (2012) eq.(50)
1114      !!                 with the highest level of approximation: level4, eq.(59)
1115      !!                 The generic drag over a cell partly covered by ice can be re-written as follows:
1116      !!
1117      !!                 Cd = Cdw * (1-A) + Cdi * A + Ce * (1-A)**(nu+1/(10*beta)) * A**mu
1118      !!
1119      !!                    Ce = 2.23e-3       , as suggested by Lupkes (eq. 59)
1120      !!                    nu = mu = beta = 1 , as suggested by Lupkes (eq. 59)
1121      !!                    A is the concentration of ice minus melt ponds (if any)
1122      !!
1123      !!                 This new drag has a parabolic shape (as a function of A) starting at
1124      !!                 Cdw(say 1.5e-3) for A=0, reaching 1.97e-3 for A~0.5
1125      !!                 and going down to Cdi(say 1.4e-3) for A=1
1126      !!
1127      !!                 It is theoretically applicable to all ice conditions (not only MIZ)
1128      !!                 => see Lupkes et al (2013)
1129      !!
1130      !! ** References : Lupkes et al. JGR 2012 (theory)
1131      !!                 Lupkes et al. GRL 2013 (application to GCM)
1132      !!
1133      !!----------------------------------------------------------------------
1134      REAL(wp), DIMENSION(:,:), INTENT(inout) ::   Cd
1135      REAL(wp), PARAMETER ::   zCe   = 2.23e-03_wp
1136      REAL(wp), PARAMETER ::   znu   = 1._wp
1137      REAL(wp), PARAMETER ::   zmu   = 1._wp
1138      REAL(wp), PARAMETER ::   zbeta = 1._wp
1139      REAL(wp)            ::   zcoef
1140      !!----------------------------------------------------------------------
1141      zcoef = znu + 1._wp / ( 10._wp * zbeta )
1142
1143      ! generic drag over a cell partly covered by ice
1144      !!Cd(:,:) = Cd_oce(:,:) * ( 1._wp - at_i_b(:,:) ) +  &                        ! pure ocean drag
1145      !!   &      Cd_ice      *           at_i_b(:,:)   +  &                        ! pure ice drag
1146      !!   &      zCe         * ( 1._wp - at_i_b(:,:) )**zcoef * at_i_b(:,:)**zmu   ! change due to sea-ice morphology
1147
1148      ! ice-atm drag
1149      Cd(:,:) = Cd_ice +  &                                                         ! pure ice drag
1150         &      zCe    * ( 1._wp - at_i_b(:,:) )**zcoef * at_i_b(:,:)**(zmu-1._wp)  ! change due to sea-ice morphology
1151     
1152   END SUBROUTINE Cdn10_Lupkes2012
1153
1154
1155   SUBROUTINE Cdn10_Lupkes2015( Cd, Ch )
1156      !!----------------------------------------------------------------------
1157      !!                      ***  ROUTINE  Cdn10_Lupkes2015  ***
1158      !!
1159      !! ** pUrpose :    Alternative turbulent transfert coefficients formulation
1160      !!                 between sea-ice and atmosphere with distinct momentum
1161      !!                 and heat coefficients depending on sea-ice concentration
1162      !!                 and atmospheric stability (no meltponds effect for now).
1163      !!               
1164      !! ** Method :     The parameterization is adapted from Lupkes et al. (2015)
1165      !!                 and ECHAM6 atmospheric model. Compared to Lupkes2012 scheme,
1166      !!                 it considers specific skin and form drags (Andreas et al. 2010)
1167      !!                 to compute neutral transfert coefficients for both heat and
1168      !!                 momemtum fluxes. Atmospheric stability effect on transfert
1169      !!                 coefficient is also taken into account following Louis (1979).
1170      !!
1171      !! ** References : Lupkes et al. JGR 2015 (theory)
1172      !!                 Lupkes et al. ECHAM6 documentation 2015 (implementation)
1173      !!
1174      !!----------------------------------------------------------------------
1175      !
1176      REAL(wp), DIMENSION(:,:), INTENT(inout) ::   Cd
1177      REAL(wp), DIMENSION(:,:), INTENT(inout) ::   Ch
1178      REAL(wp), DIMENSION(jpi,jpj)            ::   ztm_su, zst, zqo_sat, zqi_sat
1179      !
1180      ! ECHAM6 constants
1181      REAL(wp), PARAMETER ::   z0_skin_ice  = 0.69e-3_wp  ! Eq. 43 [m]
1182      REAL(wp), PARAMETER ::   z0_form_ice  = 0.57e-3_wp  ! Eq. 42 [m]
1183      REAL(wp), PARAMETER ::   z0_ice       = 1.00e-3_wp  ! Eq. 15 [m]
1184      REAL(wp), PARAMETER ::   zce10        = 2.80e-3_wp  ! Eq. 41
1185      REAL(wp), PARAMETER ::   zbeta        = 1.1_wp      ! Eq. 41
1186      REAL(wp), PARAMETER ::   zc           = 5._wp       ! Eq. 13
1187      REAL(wp), PARAMETER ::   zc2          = zc * zc
1188      REAL(wp), PARAMETER ::   zam          = 2. * zc     ! Eq. 14
1189      REAL(wp), PARAMETER ::   zah          = 3. * zc     ! Eq. 30
1190      REAL(wp), PARAMETER ::   z1_alpha     = 1._wp / 0.2_wp  ! Eq. 51
1191      REAL(wp), PARAMETER ::   z1_alphaf    = z1_alpha    ! Eq. 56
1192      REAL(wp), PARAMETER ::   zbetah       = 1.e-3_wp    ! Eq. 26
1193      REAL(wp), PARAMETER ::   zgamma       = 1.25_wp     ! Eq. 26
1194      REAL(wp), PARAMETER ::   z1_gamma     = 1._wp / zgamma
1195      REAL(wp), PARAMETER ::   r1_3         = 1._wp / 3._wp
1196      !
1197      INTEGER  ::   ji, jj         ! dummy loop indices
1198      REAL(wp) ::   zthetav_os, zthetav_is, zthetav_zu
1199      REAL(wp) ::   zrib_o, zrib_i
1200      REAL(wp) ::   zCdn_skin_ice, zCdn_form_ice, zCdn_ice
1201      REAL(wp) ::   zChn_skin_ice, zChn_form_ice
1202      REAL(wp) ::   z0w, z0i, zfmi, zfmw, zfhi, zfhw
1203      REAL(wp) ::   zCdn_form_tmp
1204      !!----------------------------------------------------------------------
1205
1206      ! mean temperature
1207      WHERE( at_i_b(:,:) > 1.e-20 )   ;   ztm_su(:,:) = SUM( t_su(:,:,:) * a_i_b(:,:,:) , dim=3 ) / at_i_b(:,:)
1208      ELSEWHERE                       ;   ztm_su(:,:) = rt0
1209      ENDWHERE
1210     
1211      ! Momentum Neutral Transfert Coefficients (should be a constant)
1212      zCdn_form_tmp = zce10 * ( LOG( 10._wp / z0_form_ice + 1._wp ) / LOG( rn_zu / z0_form_ice + 1._wp ) )**2   ! Eq. 40
1213      zCdn_skin_ice = ( vkarmn                                      / LOG( rn_zu / z0_skin_ice + 1._wp ) )**2   ! Eq. 7
1214      zCdn_ice      = zCdn_skin_ice   ! Eq. 7 (cf Lupkes email for details)
1215      !zCdn_ice     = 1.89e-3         ! old ECHAM5 value (cf Eq. 32)
1216
1217      ! Heat Neutral Transfert Coefficients
1218      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 (cf Lupkes email for details)
1219     
1220      ! Atmospheric and Surface Variables
1221      zst(:,:)     = sst_m(:,:) + rt0                                        ! convert SST from Celcius to Kelvin
1222      zqo_sat(:,:) = 0.98_wp * q_sat( zst(:,:)   , sf(jp_slp)%fnow(:,:,1) )  ! saturation humidity over ocean [kg/kg]
1223      zqi_sat(:,:) = 0.98_wp * q_sat( ztm_su(:,:), sf(jp_slp)%fnow(:,:,1) )  ! saturation humidity over ice   [kg/kg]
1224      !
1225      DO jj = 2, jpjm1           ! reduced loop is necessary for reproducibility
1226         DO ji = fs_2, fs_jpim1
1227            ! Virtual potential temperature [K]
1228            zthetav_os = zst(ji,jj)    * ( 1._wp + rctv0 * zqo_sat(ji,jj) )   ! over ocean
1229            zthetav_is = ztm_su(ji,jj) * ( 1._wp + rctv0 * zqi_sat(ji,jj) )   ! ocean ice
1230            zthetav_zu = t_zu (ji,jj)  * ( 1._wp + rctv0 * q_zu(ji,jj)    )   ! at zu
1231           
1232            ! Bulk Richardson Number (could use Ri_bulk function from aerobulk instead)
1233            zrib_o = grav / zthetav_os * ( zthetav_zu - zthetav_os ) * rn_zu / MAX( 0.5, wndm(ji,jj)     )**2   ! over ocean
1234            zrib_i = grav / zthetav_is * ( zthetav_zu - zthetav_is ) * rn_zu / MAX( 0.5, wndm_ice(ji,jj) )**2   ! over ice
1235           
1236            ! Momentum and Heat Neutral Transfert Coefficients
1237            zCdn_form_ice = zCdn_form_tmp * at_i_b(ji,jj) * ( 1._wp - at_i_b(ji,jj) )**zbeta  ! Eq. 40
1238            zChn_form_ice = zCdn_form_ice / ( 1._wp + ( LOG( z1_alphaf ) / vkarmn ) * SQRT( zCdn_form_ice ) )               ! Eq. 53
1239                       
1240            ! Momentum and Heat Stability functions (possibility to use psi_m_ecmwf instead)
1241            z0w = rn_zu * EXP( -1._wp * vkarmn / SQRT( Cdn_oce(ji,jj) ) ) ! over water
1242            z0i = z0_skin_ice                                             ! over ice (cf Lupkes email for details)
1243            IF( zrib_o <= 0._wp ) THEN
1244               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
1245               zfhw = ( 1._wp + ( zbetah * ( zthetav_os - zthetav_zu )**r1_3 / ( Chn_oce(ji,jj) * MAX(0.01, wndm(ji,jj)) )   &     ! Eq. 26
1246                  &             )**zgamma )**z1_gamma
1247            ELSE
1248               zfmw = 1._wp / ( 1._wp + zam * zrib_o / SQRT( 1._wp + zrib_o ) )   ! Eq. 12
1249               zfhw = 1._wp / ( 1._wp + zah * zrib_o / SQRT( 1._wp + zrib_o ) )   ! Eq. 28
1250            ENDIF
1251           
1252            IF( zrib_i <= 0._wp ) THEN
1253               zfmi = 1._wp - zam * zrib_i / (1._wp + 3._wp * zc2 * zCdn_ice * SQRT( -zrib_i * ( rn_zu / z0i + 1._wp)))   ! Eq.  9
1254               zfhi = 1._wp - zah * zrib_i / (1._wp + 3._wp * zc2 * zCdn_ice * SQRT( -zrib_i * ( rn_zu / z0i + 1._wp)))   ! Eq. 25
1255            ELSE
1256               zfmi = 1._wp / ( 1._wp + zam * zrib_i / SQRT( 1._wp + zrib_i ) )   ! Eq. 11
1257               zfhi = 1._wp / ( 1._wp + zah * zrib_i / SQRT( 1._wp + zrib_i ) )   ! Eq. 27
1258            ENDIF
1259           
1260            ! Momentum Transfert Coefficients (Eq. 38)
1261            Cd(ji,jj) = zCdn_skin_ice *   zfmi +  &
1262               &        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) )
1263           
1264            ! Heat Transfert Coefficients (Eq. 49)
1265            Ch(ji,jj) = zChn_skin_ice *   zfhi +  &
1266               &        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) )
1267            !
1268         END DO
1269      END DO
1270      CALL lbc_lnk_multi( 'sbcblk', Cd, 'T',  1., Ch, 'T', 1. )
1271      !
1272   END SUBROUTINE Cdn10_Lupkes2015
1273
1274#endif
1275
1276   !!======================================================================
1277END MODULE sbcblk
Note: See TracBrowser for help on using the repository browser.