sbcblk.F90 86 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525
  1. MODULE 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. !! 4.2 ! 2020-12 (L. Brodeau) Introduction of various air-ice bulk parameterizations + improvements
  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. !!----------------------------------------------------------------------
  33. USE oce ! ocean dynamics and tracers
  34. USE dom_oce ! ocean space and time domain
  35. USE phycst ! physical constants
  36. USE fldread ! read input fields
  37. USE sbc_oce ! Surface boundary condition: ocean fields
  38. USE trc_oce ! share SMS/Ocean variables
  39. USE cyclone ! Cyclone 10m wind form trac of cyclone centres
  40. USE sbcdcy ! surface boundary condition: diurnal cycle
  41. USE sbcwave , ONLY : cdn_wave ! wave module
  42. USE lib_fortran ! to use key_nosignedzero and glob_sum
  43. !
  44. #if defined key_si3
  45. USE sbc_ice ! Surface boundary condition: ice fields #LB? ok to be in '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. USE sbcblk_algo_ice_an05
  49. USE sbcblk_algo_ice_lu12
  50. USE sbcblk_algo_ice_lg15
  51. #endif
  52. USE sbcblk_algo_ncar ! => turb_ncar : NCAR - (formerly known as CORE, Large & Yeager, 2009)
  53. USE sbcblk_algo_coare3p0 ! => turb_coare3p0 : COAREv3.0 (Fairall et al. 2003)
  54. USE sbcblk_algo_coare3p6 ! => turb_coare3p6 : COAREv3.6 (Fairall et al. 2018 + Edson et al. 2013)
  55. USE sbcblk_algo_ecmwf ! => turb_ecmwf : ECMWF (IFS cycle 45r1)
  56. USE sbcblk_algo_andreas ! => turb_andreas : Andreas et al. 2015
  57. !
  58. USE iom ! I/O manager library
  59. USE in_out_manager ! I/O manager
  60. USE lib_mpp ! distribued memory computing library
  61. USE lbclnk ! ocean lateral boundary conditions (or mpp link)
  62. USE prtctl ! Print control
  63. USE sbc_phy ! Catalog of functions for physical/meteorological parameters in the marine boundary layer
  64. IMPLICIT NONE
  65. PRIVATE
  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. INTEGER , PUBLIC, PARAMETER :: jp_wndi = 1 ! index of 10m wind velocity (i-component) (m/s) at T-point
  76. INTEGER , PUBLIC, PARAMETER :: jp_wndj = 2 ! index of 10m wind velocity (j-component) (m/s) at T-point
  77. INTEGER , PUBLIC, PARAMETER :: jp_tair = 3 ! index of 10m air temperature (Kelvin)
  78. INTEGER , PUBLIC, PARAMETER :: jp_humi = 4 ! index of specific humidity (kg/kg)
  79. INTEGER , PUBLIC, PARAMETER :: jp_qsr = 5 ! index of solar heat (W/m2)
  80. INTEGER , PUBLIC, PARAMETER :: jp_qlw = 6 ! index of Long wave (W/m2)
  81. INTEGER , PUBLIC, PARAMETER :: jp_prec = 7 ! index of total precipitation (rain+snow) (Kg/m2/s)
  82. INTEGER , PUBLIC, PARAMETER :: jp_snow = 8 ! index of snow (solid prcipitation) (kg/m2/s)
  83. INTEGER , PUBLIC, PARAMETER :: jp_slp = 9 ! index of sea level pressure (Pa)
  84. INTEGER , PUBLIC, PARAMETER :: jp_uoatm = 10 ! index of surface current (i-component)
  85. ! ! seen by the atmospheric forcing (m/s) at T-point
  86. INTEGER , PUBLIC, PARAMETER :: jp_voatm = 11 ! index of surface current (j-component)
  87. ! ! seen by the atmospheric forcing (m/s) at T-point
  88. INTEGER , PUBLIC, PARAMETER :: jp_cc = 12 ! index of cloud cover (-) range:0-1
  89. INTEGER , PUBLIC, PARAMETER :: jp_hpgi = 13 ! index of ABL geostrophic wind or hpg (i-component) (m/s) at T-point
  90. INTEGER , PUBLIC, PARAMETER :: jp_hpgj = 14 ! index of ABL geostrophic wind or hpg (j-component) (m/s) at T-point
  91. #if defined key_drakkar
  92. LOGICAL :: ln_clim_forcing = .false. ! Logical flag for use of climatological forcing
  93. ! ( T= climatological, F=interannual)
  94. INTEGER , PUBLIC, PARAMETER :: jp_wmod =15 ! index of wind module (m/s)
  95. INTEGER , PUBLIC, PARAMETER :: jp_uw =16 ! index of zonal pseudo stress (m2/s2)
  96. INTEGER , PUBLIC, PARAMETER :: jp_vw =17 ! index of meridional pseudo stress (m2/s2)
  97. INTEGER , PUBLIC, PARAMETER :: jpfld = 17 ! maximum number of files to read
  98. #else
  99. INTEGER , PUBLIC, PARAMETER :: jpfld = 14 ! maximum number of files to read
  100. #endif
  101. ! Warning: keep this structure allocatable for Agrif...
  102. TYPE(FLD), PUBLIC, ALLOCATABLE, DIMENSION(:) :: sf ! structure of input atmospheric fields (file informations, fields read)
  103. ! !!* Namelist namsbc_blk : bulk parameters
  104. LOGICAL :: ln_NCAR ! "NCAR" algorithm (Large and Yeager 2008)
  105. LOGICAL :: ln_COARE_3p0 ! "COARE 3.0" algorithm (Fairall et al. 2003)
  106. LOGICAL :: ln_COARE_3p6 ! "COARE 3.6" algorithm (Edson et al. 2013)
  107. LOGICAL :: ln_ECMWF ! "ECMWF" algorithm (IFS cycle 45r1)
  108. LOGICAL :: ln_ANDREAS ! "ANDREAS" algorithm (Andreas et al. 2015)
  109. !
  110. !#LB:
  111. LOGICAL :: ln_Cx_ice_cst ! use constant air-ice bulk transfer coefficients (value given in namelist's rn_Cd_i, rn_Ce_i & rn_Ch_i)
  112. REAL(wp) :: rn_Cd_i, rn_Ce_i, rn_Ch_i ! values for " "
  113. LOGICAL :: ln_Cx_ice_AN05 ! air-ice bulk transfer coefficients based on Andreas et al., 2005
  114. LOGICAL :: ln_Cx_ice_LU12 ! air-ice bulk transfer coefficients based on Lupkes et al., 2012
  115. LOGICAL :: ln_Cx_ice_LG15 ! air-ice bulk transfer coefficients based on Lupkes & Gryanik, 2015
  116. !#LB.
  117. !
  118. LOGICAL :: ln_crt_fbk ! Add surface current feedback to the wind stress computation (Renault et al. 2020)
  119. REAL(wp) :: rn_stau_a ! Alpha and Beta coefficients of Renault et al. 2020, eq. 10: Stau = Alpha * Wnd + Beta
  120. REAL(wp) :: rn_stau_b !
  121. !
  122. REAL(wp) :: rn_pfac ! multiplication factor for precipitation
  123. REAL(wp), PUBLIC :: rn_efac ! multiplication factor for evaporation
  124. REAL(wp) :: rn_zqt ! z(q,t) : height of humidity and temperature measurements
  125. REAL(wp) :: rn_zu ! z(u) : height of wind measurements
  126. !
  127. INTEGER :: nn_iter_algo ! Number of iterations in bulk param. algo ("stable ABL + weak wind" requires more)
  128. REAL(wp), ALLOCATABLE, DIMENSION(:,:) :: theta_zu, q_zu ! air temp. and spec. hum. at wind speed height (L15 bulk scheme)
  129. #if defined key_si3
  130. REAL(wp), ALLOCATABLE, DIMENSION(:,:) :: Cd_ice , Ch_ice , Ce_ice !#LB transfert coefficients over ice
  131. REAL(wp), ALLOCATABLE, DIMENSION(:,:) :: theta_zu_i, q_zu_i !#LB fixme ! air temp. and spec. hum. over ice at wind speed height (L15 bulk scheme)
  132. #endif
  133. LOGICAL :: ln_skin_cs ! use the cool-skin (only available in ECMWF and COARE algorithms) !LB
  134. LOGICAL :: ln_skin_wl ! use the warm-layer parameterization (only available in ECMWF and COARE algorithms) !LB
  135. LOGICAL :: ln_humi_sph ! humidity read in files ("sn_humi") is specific humidity [kg/kg] if .true. !LB
  136. LOGICAL :: ln_humi_dpt ! humidity read in files ("sn_humi") is dew-point temperature [K] if .true. !LB
  137. LOGICAL :: ln_humi_rlh ! humidity read in files ("sn_humi") is relative humidity [%] if .true. !LB
  138. LOGICAL :: ln_tair_pot ! temperature read in files ("sn_tair") is already potential temperature (not absolute)
  139. !
  140. INTEGER :: nhumi ! choice of the bulk algorithm
  141. ! ! associated indices:
  142. INTEGER, PARAMETER :: np_humi_sph = 1
  143. INTEGER, PARAMETER :: np_humi_dpt = 2
  144. INTEGER, PARAMETER :: np_humi_rlh = 3
  145. INTEGER :: nblk ! choice of the bulk algorithm
  146. ! ! associated indices:
  147. INTEGER, PARAMETER :: np_NCAR = 1 ! "NCAR" algorithm (Large and Yeager 2008)
  148. INTEGER, PARAMETER :: np_COARE_3p0 = 2 ! "COARE 3.0" algorithm (Fairall et al. 2003)
  149. INTEGER, PARAMETER :: np_COARE_3p6 = 3 ! "COARE 3.6" algorithm (Edson et al. 2013)
  150. INTEGER, PARAMETER :: np_ECMWF = 4 ! "ECMWF" algorithm (IFS cycle 45r1)
  151. INTEGER, PARAMETER :: np_ANDREAS = 5 ! "ANDREAS" algorithm (Andreas et al. 2015)
  152. !#LB:
  153. #if defined key_si3
  154. ! Same, over sea-ice:
  155. INTEGER :: nblk_ice ! choice of the bulk algorithm
  156. ! ! associated indices:
  157. INTEGER, PARAMETER :: np_ice_cst = 1 ! constant transfer coefficients
  158. INTEGER, PARAMETER :: np_ice_an05 = 2 ! Andreas et al., 2005
  159. INTEGER, PARAMETER :: np_ice_lu12 = 3 ! Lupkes el al., 2012
  160. INTEGER, PARAMETER :: np_ice_lg15 = 4 ! Lupkes & Gryanik, 2015
  161. #endif
  162. !LB.
  163. !! * Substitutions
  164. # include "do_loop_substitute.h90"
  165. !!----------------------------------------------------------------------
  166. !! NEMO/OCE 4.0 , NEMO Consortium (2018)
  167. !! $Id: sbcblk.F90 15551 2021-11-28 20:19:36Z gsamson $
  168. !! Software governed by the CeCILL license (see ./LICENSE)
  169. !!----------------------------------------------------------------------
  170. CONTAINS
  171. INTEGER FUNCTION sbc_blk_alloc()
  172. !!-------------------------------------------------------------------
  173. !! *** ROUTINE sbc_blk_alloc ***
  174. !!-------------------------------------------------------------------
  175. ALLOCATE( theta_zu(jpi,jpj), q_zu(jpi,jpj), STAT=sbc_blk_alloc )
  176. CALL mpp_sum ( 'sbcblk', sbc_blk_alloc )
  177. IF( sbc_blk_alloc /= 0 ) CALL ctl_stop( 'STOP', 'sbc_blk_alloc: failed to allocate arrays' )
  178. END FUNCTION sbc_blk_alloc
  179. #if defined key_si3
  180. INTEGER FUNCTION sbc_blk_ice_alloc()
  181. !!-------------------------------------------------------------------
  182. !! *** ROUTINE sbc_blk_ice_alloc ***
  183. !!-------------------------------------------------------------------
  184. ALLOCATE( Cd_ice (jpi,jpj), Ch_ice (jpi,jpj), Ce_ice (jpi,jpj), &
  185. & theta_zu_i(jpi,jpj), q_zu_i(jpi,jpj), STAT=sbc_blk_ice_alloc )
  186. CALL mpp_sum ( 'sbcblk', sbc_blk_ice_alloc )
  187. IF( sbc_blk_ice_alloc /= 0 ) CALL ctl_stop( 'STOP', 'sbc_blk_ice_alloc: failed to allocate arrays' )
  188. END FUNCTION sbc_blk_ice_alloc
  189. #endif
  190. SUBROUTINE sbc_blk_init
  191. !!---------------------------------------------------------------------
  192. !! *** ROUTINE sbc_blk_init ***
  193. !!
  194. !! ** Purpose : choose and initialize a bulk formulae formulation
  195. !!
  196. !! ** Method :
  197. !!
  198. !!----------------------------------------------------------------------
  199. INTEGER :: jfpr ! dummy loop indice and argument
  200. INTEGER :: ios, ierror, ioptio ! Local integer
  201. !!
  202. CHARACTER(len=100) :: cn_dir ! Root directory for location of atmospheric forcing files
  203. TYPE(FLD_N), DIMENSION(jpfld) :: slf_i ! array of namelist informations on the fields to read
  204. TYPE(FLD_N) :: sn_wndi, sn_wndj , sn_humi, sn_qsr ! informations about the fields to be read
  205. TYPE(FLD_N) :: sn_qlw , sn_tair , sn_prec, sn_snow ! " "
  206. TYPE(FLD_N) :: sn_slp , sn_uoatm, sn_voatm ! " "
  207. TYPE(FLD_N) :: sn_cc, sn_hpgi, sn_hpgj ! " "
  208. INTEGER :: ipka ! number of levels in the atmospheric variable
  209. NAMELIST/namsbc_blk/ ln_NCAR, ln_COARE_3p0, ln_COARE_3p6, ln_ECMWF, ln_ANDREAS, & ! bulk algorithm
  210. & rn_zqt, rn_zu, nn_iter_algo, ln_skin_cs, ln_skin_wl, &
  211. & rn_pfac, rn_efac, &
  212. & ln_crt_fbk, rn_stau_a, rn_stau_b, & ! current feedback
  213. & ln_humi_sph, ln_humi_dpt, ln_humi_rlh, ln_tair_pot, &
  214. & ln_Cx_ice_cst, rn_Cd_i, rn_Ce_i, rn_Ch_i, &
  215. & ln_Cx_ice_AN05, ln_Cx_ice_LU12, ln_Cx_ice_LG15, &
  216. & cn_dir, &
  217. & sn_wndi, sn_wndj, sn_qsr, sn_qlw , & ! input fields
  218. & sn_tair, sn_humi, sn_prec, sn_snow, sn_slp, &
  219. & sn_uoatm, sn_voatm, sn_cc, sn_hpgi, sn_hpgj
  220. #if defined key_drakkar
  221. TYPE(FLD_N) :: sn_wmod, sn_uw, sn_vw
  222. NAMELIST/namsbc_blk_drk/ ln_clim_forcing,sn_wmod, sn_uw, sn_vw
  223. #endif
  224. ! cool-skin / warm-layer !LB
  225. !!---------------------------------------------------------------------
  226. !
  227. ! ! allocate sbc_blk_core array
  228. IF( sbc_blk_alloc() /= 0 ) CALL ctl_stop( 'STOP', 'sbc_blk : unable to allocate standard arrays' )
  229. !
  230. #if defined key_si3
  231. IF( sbc_blk_ice_alloc() /= 0 ) CALL ctl_stop( 'STOP', 'sbc_blk : unable to allocate standard ice arrays' )
  232. #endif
  233. !
  234. ! !** read bulk namelist
  235. READ ( numnam_ref, namsbc_blk, IOSTAT = ios, ERR = 901)
  236. 901 IF( ios /= 0 ) CALL ctl_nam ( ios , 'namsbc_blk in reference namelist' )
  237. !
  238. READ ( numnam_cfg, namsbc_blk, IOSTAT = ios, ERR = 902 )
  239. 902 IF( ios > 0 ) CALL ctl_nam ( ios , 'namsbc_blk in configuration namelist' )
  240. !
  241. IF(lwm) WRITE( numond, namsbc_blk )
  242. #if defined key_drakkar
  243. ! !** read bulk drakkar namelist
  244. READ ( numnam_ref, namsbc_blk_drk, IOSTAT = ios, ERR = 903)
  245. 903 IF( ios /= 0 ) CALL ctl_nam ( ios , 'namsbc_blk_drk in reference namelist' )
  246. !
  247. READ ( numnam_cfg, namsbc_blk_drk, IOSTAT = ios, ERR = 904 )
  248. 904 IF( ios > 0 ) CALL ctl_nam ( ios , 'namsbc_blk_drk in configuration namelist' )
  249. !
  250. IF(lwm) WRITE( numond, namsbc_blk_drk )
  251. #endif
  252. !
  253. ! !** initialization of the chosen bulk formulae (+ check)
  254. ! !* select the bulk chosen in the namelist and check the choice
  255. ioptio = 0
  256. IF( ln_NCAR ) THEN
  257. nblk = np_NCAR ; ioptio = ioptio + 1
  258. ENDIF
  259. IF( ln_COARE_3p0 ) THEN
  260. nblk = np_COARE_3p0 ; ioptio = ioptio + 1
  261. ENDIF
  262. IF( ln_COARE_3p6 ) THEN
  263. nblk = np_COARE_3p6 ; ioptio = ioptio + 1
  264. ENDIF
  265. IF( ln_ECMWF ) THEN
  266. nblk = np_ECMWF ; ioptio = ioptio + 1
  267. ENDIF
  268. IF( ln_ANDREAS ) THEN
  269. nblk = np_ANDREAS ; ioptio = ioptio + 1
  270. ENDIF
  271. IF( ioptio /= 1 ) CALL ctl_stop( 'sbc_blk_init: Choose one and only one bulk algorithm' )
  272. ! !** initialization of the cool-skin / warm-layer parametrization
  273. IF( ln_skin_cs .OR. ln_skin_wl ) THEN
  274. !! Some namelist sanity tests:
  275. IF( ln_NCAR ) &
  276. & CALL ctl_stop( 'sbc_blk_init: Cool-skin/warm-layer param. not compatible with NCAR algorithm' )
  277. IF( ln_ANDREAS ) &
  278. & CALL ctl_stop( 'sbc_blk_init: Cool-skin/warm-layer param. not compatible with ANDREAS algorithm' )
  279. !IF( nn_fsbc /= 1 ) &
  280. ! & CALL ctl_stop( 'sbc_blk_init: Please set "nn_fsbc" to 1 when using cool-skin/warm-layer param.')
  281. END IF
  282. IF( ln_skin_wl ) THEN
  283. !! Check if the frequency of downwelling solar flux input makes sense and if ln_dm2dc=T if it is daily!
  284. IF( (sn_qsr%freqh < 0.).OR.(sn_qsr%freqh > 24.) ) &
  285. & CALL ctl_stop( 'sbc_blk_init: Warm-layer param. (ln_skin_wl) not compatible with freq. of solar flux > daily' )
  286. IF( (sn_qsr%freqh == 24.).AND.(.NOT. ln_dm2dc) ) &
  287. & CALL ctl_stop( 'sbc_blk_init: Please set ln_dm2dc=T for warm-layer param. (ln_skin_wl) to work properly' )
  288. END IF
  289. ioptio = 0
  290. IF( ln_humi_sph ) THEN
  291. nhumi = np_humi_sph ; ioptio = ioptio + 1
  292. ENDIF
  293. IF( ln_humi_dpt ) THEN
  294. nhumi = np_humi_dpt ; ioptio = ioptio + 1
  295. ENDIF
  296. IF( ln_humi_rlh ) THEN
  297. nhumi = np_humi_rlh ; ioptio = ioptio + 1
  298. ENDIF
  299. IF( ioptio /= 1 ) CALL ctl_stop( 'sbc_blk_init: Choose one and only one type of air humidity' )
  300. !
  301. IF( ln_dm2dc ) THEN !* check: diurnal cycle on Qsr
  302. IF( sn_qsr%freqh /= 24. ) CALL ctl_stop( 'sbc_blk_init: ln_dm2dc=T only with daily short-wave input' )
  303. IF( sn_qsr%ln_tint ) THEN
  304. CALL ctl_warn( 'sbc_blk_init: ln_dm2dc=T daily qsr time interpolation done by sbcdcy module', &
  305. & ' ==> We force time interpolation = .false. for qsr' )
  306. sn_qsr%ln_tint = .false.
  307. ENDIF
  308. ENDIF
  309. #if defined key_si3
  310. ioptio = 0
  311. IF( ln_Cx_ice_cst ) THEN
  312. nblk_ice = np_ice_cst ; ioptio = ioptio + 1
  313. ENDIF
  314. IF( ln_Cx_ice_AN05 ) THEN
  315. nblk_ice = np_ice_an05 ; ioptio = ioptio + 1
  316. ENDIF
  317. IF( ln_Cx_ice_LU12 ) THEN
  318. nblk_ice = np_ice_lu12 ; ioptio = ioptio + 1
  319. ENDIF
  320. IF( ln_Cx_ice_LG15 ) THEN
  321. nblk_ice = np_ice_lg15 ; ioptio = ioptio + 1
  322. ENDIF
  323. IF( ioptio /= 1 ) CALL ctl_stop( 'sbc_blk_init: Choose one and only one ice-atm bulk algorithm' )
  324. #endif
  325. ! !* set the bulk structure
  326. ! !- store namelist information in an array
  327. !
  328. slf_i(jp_wndi ) = sn_wndi ; slf_i(jp_wndj ) = sn_wndj
  329. slf_i(jp_qsr ) = sn_qsr ; slf_i(jp_qlw ) = sn_qlw
  330. slf_i(jp_tair ) = sn_tair ; slf_i(jp_humi ) = sn_humi
  331. slf_i(jp_prec ) = sn_prec ; slf_i(jp_snow ) = sn_snow
  332. slf_i(jp_slp ) = sn_slp ; slf_i(jp_cc ) = sn_cc
  333. slf_i(jp_uoatm) = sn_uoatm ; slf_i(jp_voatm) = sn_voatm
  334. slf_i(jp_hpgi ) = sn_hpgi ; slf_i(jp_hpgj ) = sn_hpgj
  335. !
  336. IF( .NOT. ln_abl ) THEN ! force to not use jp_hpgi and jp_hpgj, should already be done in namelist_* but we never know...
  337. slf_i(jp_hpgi)%clname = 'NOT USED'
  338. slf_i(jp_hpgj)%clname = 'NOT USED'
  339. ENDIF
  340. #if defined key_drakkar
  341. slf_i(jp_wmod ) = sn_wmod ; slf_i(jp_uw ) = sn_uw ; slf_i(jp_vw ) = sn_vw
  342. IF( .NOT. ln_clim_forcing) THEN
  343. slf_i(jp_wmod)%clname = 'NOT USED'
  344. slf_i(jp_uw )%clname = 'NOT USED'
  345. slf_i(jp_vw )%clname = 'NOT USED'
  346. ELSE
  347. slf_i(jp_wndi)%clname = 'NOT USED'
  348. slf_i(jp_wndj)%clname = 'NOT USED'
  349. ENDIF
  350. #endif
  351. !
  352. ! !- allocate the bulk structure
  353. ALLOCATE( sf(jpfld), STAT=ierror )
  354. IF( ierror > 0 ) CALL ctl_stop( 'STOP', 'sbc_blk_init: unable to allocate sf structure' )
  355. !
  356. ! !- fill the bulk structure with namelist informations
  357. CALL fld_fill( sf, slf_i, cn_dir, 'sbc_blk_init', 'surface boundary condition -- bulk formulae', 'namsbc_blk' )
  358. sf(jp_wndi )%zsgn = -1._wp ; sf(jp_wndj )%zsgn = -1._wp ! vector field at T point: overwrite default definition of zsgn
  359. sf(jp_uoatm)%zsgn = -1._wp ; sf(jp_voatm)%zsgn = -1._wp ! vector field at T point: overwrite default definition of zsgn
  360. sf(jp_hpgi )%zsgn = -1._wp ; sf(jp_hpgj )%zsgn = -1._wp ! vector field at T point: overwrite default definition of zsgn
  361. !
  362. DO jfpr= 1, jpfld
  363. !
  364. IF( ln_abl .AND. &
  365. & ( jfpr == jp_wndi .OR. jfpr == jp_wndj .OR. jfpr == jp_humi .OR. &
  366. & jfpr == jp_hpgi .OR. jfpr == jp_hpgj .OR. jfpr == jp_tair ) ) THEN
  367. ipka = jpka ! ABL: some fields are 3D input
  368. ELSE
  369. ipka = 1
  370. ENDIF
  371. !
  372. ALLOCATE( sf(jfpr)%fnow(jpi,jpj,ipka) )
  373. !
  374. IF( TRIM(sf(jfpr)%clrootname) == 'NOT USED' ) THEN !-- not used field --! (only now allocated and set to default)
  375. IF( jfpr == jp_slp ) THEN
  376. sf(jfpr)%fnow(:,:,1:ipka) = 101325._wp ! use standard pressure in Pa
  377. ELSEIF( jfpr == jp_prec .OR. jfpr == jp_snow .OR. jfpr == jp_uoatm .OR. jfpr == jp_voatm ) THEN
  378. sf(jfpr)%fnow(:,:,1:ipka) = 0._wp ! no precip or no snow or no surface currents
  379. ELSEIF( jfpr == jp_hpgi .OR. jfpr == jp_hpgj ) THEN
  380. IF( .NOT. ln_abl ) THEN
  381. DEALLOCATE( sf(jfpr)%fnow ) ! deallocate as not used in this case
  382. ELSE
  383. sf(jfpr)%fnow(:,:,1:ipka) = 0._wp
  384. ENDIF
  385. ELSEIF( jfpr == jp_cc ) THEN
  386. sf(jp_cc)%fnow(:,:,1:ipka) = pp_cldf
  387. #if defined key_drakkar
  388. ELSEIF( jfpr == jp_wmod .OR. jfpr == jp_uw .OR. jfpr == jp_vw ) THEN
  389. sf(jfpr)%fnow(:,:,1:ipka) = 0._wp
  390. #endif
  391. ELSE
  392. WRITE(ctmp1,*) 'sbc_blk_init: no default value defined for field number', jfpr
  393. CALL ctl_stop( ctmp1 )
  394. ENDIF
  395. ELSE !-- used field --!
  396. IF( sf(jfpr)%ln_tint ) ALLOCATE( sf(jfpr)%fdta(jpi,jpj,ipka,2) ) ! allocate array for temporal interpolation
  397. !
  398. IF( sf(jfpr)%freqh > 0. .AND. MOD( NINT(3600. * sf(jfpr)%freqh), nn_fsbc * NINT(rn_Dt) ) /= 0 ) &
  399. & CALL ctl_warn( 'sbc_blk_init: sbcmod timestep rn_Dt*nn_fsbc is NOT a submultiple of atmospheric forcing frequency.', &
  400. & ' This is not ideal. You should consider changing either rn_Dt or nn_fsbc value...' )
  401. ENDIF
  402. END DO
  403. !
  404. IF( ln_abl ) THEN ! ABL: read 3D fields for wind, temperature, humidity and pressure gradient
  405. rn_zqt = ght_abl(2) ! set the bulk altitude to ABL first level
  406. rn_zu = ght_abl(2)
  407. IF(lwp) WRITE(numout,*)
  408. IF(lwp) WRITE(numout,*) ' ABL formulation: overwrite rn_zqt & rn_zu with ABL first level altitude'
  409. ENDIF
  410. !
  411. !
  412. IF(lwp) THEN !** Control print
  413. !
  414. WRITE(numout,*) !* namelist
  415. WRITE(numout,*) ' Namelist namsbc_blk (other than data information):'
  416. WRITE(numout,*) ' "NCAR" algorithm (Large and Yeager 2008) ln_NCAR = ', ln_NCAR
  417. WRITE(numout,*) ' "COARE 3.0" algorithm (Fairall et al. 2003) ln_COARE_3p0 = ', ln_COARE_3p0
  418. WRITE(numout,*) ' "COARE 3.6" algorithm (Fairall 2018 + Edson al 2013) ln_COARE_3p6 = ', ln_COARE_3p6
  419. WRITE(numout,*) ' "ECMWF" algorithm (IFS cycle 45r1) ln_ECMWF = ', ln_ECMWF
  420. WRITE(numout,*) ' "ANDREAS" algorithm (Andreas et al. 2015) ln_ANDREAS = ', ln_ANDREAS
  421. #if defined key_drakkar
  422. WRITE(numout,*) ' Use climatolofical forcing formulation ln_clim_forcing = ', ln_clim_forcing
  423. #endif
  424. WRITE(numout,*) ' Air temperature and humidity reference height (m) rn_zqt = ', rn_zqt
  425. WRITE(numout,*) ' Wind vector reference height (m) rn_zu = ', rn_zu
  426. WRITE(numout,*) ' factor applied on precipitation (total & snow) rn_pfac = ', rn_pfac
  427. WRITE(numout,*) ' factor applied on evaporation rn_efac = ', rn_efac
  428. WRITE(numout,*) ' (form absolute (=0) to relative winds(=1))'
  429. WRITE(numout,*) ' use surface current feedback on wind stress ln_crt_fbk = ', ln_crt_fbk
  430. IF(ln_crt_fbk) THEN
  431. WRITE(numout,*) ' Renault et al. 2020, eq. 10: Stau = Alpha * Wnd + Beta'
  432. WRITE(numout,*) ' Alpha rn_stau_a = ', rn_stau_a
  433. WRITE(numout,*) ' Beta rn_stau_b = ', rn_stau_b
  434. ENDIF
  435. !
  436. WRITE(numout,*)
  437. SELECT CASE( nblk ) !* Print the choice of bulk algorithm
  438. CASE( np_NCAR ) ; WRITE(numout,*) ' ==>>> "NCAR" algorithm (Large and Yeager 2008)'
  439. CASE( np_COARE_3p0 ) ; WRITE(numout,*) ' ==>>> "COARE 3.0" algorithm (Fairall et al. 2003)'
  440. CASE( np_COARE_3p6 ) ; WRITE(numout,*) ' ==>>> "COARE 3.6" algorithm (Fairall 2018+Edson et al. 2013)'
  441. CASE( np_ECMWF ) ; WRITE(numout,*) ' ==>>> "ECMWF" algorithm (IFS cycle 45r1)'
  442. CASE( np_ANDREAS ) ; WRITE(numout,*) ' ==>>> "ANDREAS" algorithm (Andreas et al. 2015)'
  443. END SELECT
  444. !
  445. WRITE(numout,*)
  446. WRITE(numout,*) ' use cool-skin parameterization (SSST) ln_skin_cs = ', ln_skin_cs
  447. WRITE(numout,*) ' use warm-layer parameterization (SSST) ln_skin_wl = ', ln_skin_wl
  448. !
  449. WRITE(numout,*)
  450. SELECT CASE( nhumi ) !* Print the choice of air humidity
  451. CASE( np_humi_sph ) ; WRITE(numout,*) ' ==>>> air humidity is SPECIFIC HUMIDITY [kg/kg]'
  452. CASE( np_humi_dpt ) ; WRITE(numout,*) ' ==>>> air humidity is DEW-POINT TEMPERATURE [K]'
  453. CASE( np_humi_rlh ) ; WRITE(numout,*) ' ==>>> air humidity is RELATIVE HUMIDITY [%]'
  454. END SELECT
  455. !
  456. !#LB:
  457. #if defined key_si3
  458. IF( nn_ice > 0 ) THEN
  459. WRITE(numout,*)
  460. WRITE(numout,*) ' use constant ice-atm bulk transfer coeff. ln_Cx_ice_cst = ', ln_Cx_ice_cst
  461. WRITE(numout,*) ' use ice-atm bulk coeff. from Andreas et al., 2005 ln_Cx_ice_AN05 = ', ln_Cx_ice_AN05
  462. WRITE(numout,*) ' use ice-atm bulk coeff. from Lupkes et al., 2012 ln_Cx_ice_LU12 = ', ln_Cx_ice_LU12
  463. WRITE(numout,*) ' use ice-atm bulk coeff. from Lupkes & Gryanik, 2015 ln_Cx_ice_LG15 = ', ln_Cx_ice_LG15
  464. ENDIF
  465. WRITE(numout,*)
  466. SELECT CASE( nblk_ice ) !* Print the choice of bulk algorithm
  467. CASE( np_ice_cst )
  468. WRITE(numout,*) ' ==>>> Constant bulk transfer coefficients over sea-ice:'
  469. WRITE(numout,*) ' => Cd_ice, Ce_ice, Ch_ice =', REAL(rn_Cd_i,4), REAL(rn_Ce_i,4), REAL(rn_Ch_i,4)
  470. IF( (rn_Cd_i<0._wp).OR.(rn_Cd_i>1.E-2_wp).OR.(rn_Ce_i<0._wp).OR.(rn_Ce_i>1.E-2_wp).OR.(rn_Ch_i<0._wp).OR.(rn_Ch_i>1.E-2_wp) ) &
  471. & CALL ctl_stop( 'Be realistic in your pick of Cd_ice, Ce_ice & Ch_ice ! (0 < Cx < 1.E-2)')
  472. CASE( np_ice_an05 ) ; WRITE(numout,*) ' ==>>> bulk algo over ice: Andreas et al, 2005'
  473. CASE( np_ice_lu12 ) ; WRITE(numout,*) ' ==>>> bulk algo over ice: Lupkes et al, 2012'
  474. CASE( np_ice_lg15 ) ; WRITE(numout,*) ' ==>>> bulk algo over ice: Lupkes & Gryanik, 2015'
  475. END SELECT
  476. #endif
  477. !#LB.
  478. !
  479. ENDIF
  480. !
  481. END SUBROUTINE sbc_blk_init
  482. SUBROUTINE sbc_blk( kt )
  483. !!---------------------------------------------------------------------
  484. !! *** ROUTINE sbc_blk ***
  485. !!
  486. !! ** Purpose : provide at each time step the surface ocean fluxes
  487. !! (momentum, heat, freshwater and runoff)
  488. !!
  489. !! ** Method :
  490. !! (1) READ each fluxes in NetCDF files:
  491. !! the wind velocity (i-component) at z=rn_zu (m/s) at T-point
  492. !! the wind velocity (j-component) at z=rn_zu (m/s) at T-point
  493. !! the specific humidity at z=rn_zqt (kg/kg)
  494. !! the air temperature at z=rn_zqt (Kelvin)
  495. !! the solar heat (W/m2)
  496. !! the Long wave (W/m2)
  497. !! the total precipitation (rain+snow) (Kg/m2/s)
  498. !! the snow (solid precipitation) (kg/m2/s)
  499. !! ABL dynamical forcing (i/j-components of either hpg or geostrophic winds)
  500. !! (2) CALL blk_oce_1 and blk_oce_2
  501. !!
  502. !! C A U T I O N : never mask the surface stress fields
  503. !! the stress is assumed to be in the (i,j) mesh referential
  504. !!
  505. !! ** Action : defined at each time-step at the air-sea interface
  506. !! - utau, vtau i- and j-component of the wind stress
  507. !! - taum wind stress module at T-point
  508. !! - wndm wind speed module at T-point over free ocean or leads in presence of sea-ice
  509. !! - qns, qsr non-solar and solar heat fluxes
  510. !! - emp upward mass flux (evapo. - precip.)
  511. !! - sfx salt flux due to freezing/melting (non-zero only if ice is present)
  512. !!
  513. !! ** References : Large & Yeager, 2004 / Large & Yeager, 2008
  514. !! Brodeau et al. Ocean Modelling 2010
  515. !!----------------------------------------------------------------------
  516. INTEGER, INTENT(in) :: kt ! ocean time step
  517. !!----------------------------------------------------------------------
  518. REAL(wp), DIMENSION(jpi,jpj) :: zssq, zcd_du, zsen, zlat, zevp, zpre, ztheta
  519. REAL(wp) :: ztst
  520. LOGICAL :: llerr
  521. !!----------------------------------------------------------------------
  522. !
  523. CALL fld_read( kt, nn_fsbc, sf ) ! input fields provided at the current time-step
  524. ! Sanity/consistence test on humidity at first time step to detect potential screw-up:
  525. IF( kt == nit000 ) THEN
  526. ! mean humidity over ocean on proc
  527. ztst = glob_sum( 'sbcblk', sf(jp_humi)%fnow(:,:,1) * e1e2t(:,:) * tmask(:,:,1) ) / glob_sum( 'sbcblk', e1e2t(:,:) * tmask(:,:,1) )
  528. llerr = .FALSE.
  529. SELECT CASE( nhumi )
  530. CASE( np_humi_sph ) ! specific humidity => expect: 0. <= something < 0.065 [kg/kg] (0.061 is saturation at 45degC !!!)
  531. IF( (ztst < 0._wp) .OR. (ztst > 0.065_wp) ) llerr = .TRUE.
  532. CASE( np_humi_dpt ) ! dew-point temperature => expect: 110. <= something < 320. [K]
  533. IF( (ztst < 110._wp) .OR. (ztst > 320._wp) ) llerr = .TRUE.
  534. CASE( np_humi_rlh ) ! relative humidity => expect: 0. <= something < 100. [%]
  535. IF( (ztst < 0._wp) .OR. (ztst > 100._wp) ) llerr = .TRUE.
  536. END SELECT
  537. IF(llerr) THEN
  538. WRITE(ctmp1,'(" Error on mean humidity value: ",f10.5)') ztst
  539. CALL ctl_stop( 'STOP', ctmp1, 'Something is wrong with air humidity!!!', &
  540. & ' ==> check the unit in your input files' , &
  541. & ' ==> check consistence of namelist choice: specific? relative? dew-point?', &
  542. & ' ==> ln_humi_sph -> [kg/kg] | ln_humi_rlh -> [%] | ln_humi_dpt -> [K] !!!' )
  543. ENDIF
  544. IF(lwp) THEN
  545. WRITE(numout,*) ''
  546. WRITE(numout,*) ' Global mean humidity at kt = nit000: ', ztst
  547. WRITE(numout,*) ' === Sanity/consistence test on air humidity sucessfuly passed! ==='
  548. WRITE(numout,*) ''
  549. ENDIF
  550. ENDIF !IF( kt == nit000 )
  551. ! ! compute the surface ocean fluxes using bulk formulea
  552. IF( MOD( kt - 1, nn_fsbc ) == 0 ) THEN
  553. ! Specific humidity of air at z=rn_zqt
  554. SELECT CASE( nhumi )
  555. CASE( np_humi_sph )
  556. q_air_zt(:,:) = sf(jp_humi )%fnow(:,:,1) ! what we read in file is already a spec. humidity!
  557. CASE( np_humi_dpt )
  558. IF((kt==nit000).AND.lwp) WRITE(numout,*) ' *** sbc_blk() => computing q_air out of dew-point and P !'
  559. q_air_zt(:,:) = q_sat( sf(jp_humi )%fnow(:,:,1), sf(jp_slp )%fnow(:,:,1) )
  560. CASE( np_humi_rlh )
  561. IF((kt==nit000).AND.lwp) WRITE(numout,*) ' *** sbc_blk() => computing q_air out of RH, t_air and slp !' !LBrm
  562. q_air_zt(:,:) = q_air_rh( 0.01_wp*sf(jp_humi )%fnow(:,:,1), &
  563. & sf(jp_tair )%fnow(:,:,1), sf(jp_slp )%fnow(:,:,1) ) !#LB: 0.01 => RH is % percent in file
  564. END SELECT
  565. ! Potential temperature of air at z=rn_zqt (most reanalysis products provide absolute temp., not potential temp.)
  566. IF( ln_tair_pot ) THEN
  567. ! temperature read into file is already potential temperature, do nothing...
  568. theta_air_zt(:,:) = sf(jp_tair )%fnow(:,:,1)
  569. ELSE
  570. ! temperature read into file is ABSOLUTE temperature (that's the case for ECMWF products for example...)
  571. IF((kt==nit000).AND.lwp) WRITE(numout,*) ' *** sbc_blk() => air temperature converted from ABSOLUTE to POTENTIAL!'
  572. zpre(:,:) = pres_temp( q_air_zt(:,:), sf(jp_slp)%fnow(:,:,1), rn_zu, pta=sf(jp_tair)%fnow(:,:,1) )
  573. theta_air_zt(:,:) = theta_exner( sf(jp_tair)%fnow(:,:,1), zpre(:,:) )
  574. ENDIF
  575. !
  576. CALL blk_oce_1( kt, sf(jp_wndi )%fnow(:,:,1), sf(jp_wndj )%fnow(:,:,1), & ! <<= in
  577. & theta_air_zt(:,:), q_air_zt(:,:), & ! <<= in
  578. & sf(jp_slp )%fnow(:,:,1), sst_m, ssu_m, ssv_m, & ! <<= in
  579. & sf(jp_uoatm)%fnow(:,:,1), sf(jp_voatm)%fnow(:,:,1), & ! <<= in
  580. & sf(jp_qsr )%fnow(:,:,1), sf(jp_qlw )%fnow(:,:,1), & ! <<= in (wl/cs)
  581. & tsk_m, zssq, zcd_du, zsen, zlat, zevp ) ! =>> out
  582. CALL blk_oce_2( theta_air_zt(:,:), & ! <<= in
  583. & sf(jp_qlw )%fnow(:,:,1), sf(jp_prec )%fnow(:,:,1), & ! <<= in
  584. & sf(jp_snow )%fnow(:,:,1), tsk_m, & ! <<= in
  585. & zsen, zlat, zevp ) ! <=> in out
  586. ENDIF
  587. !
  588. #if defined key_cice
  589. IF( MOD( kt - 1, nn_fsbc ) == 0 ) THEN
  590. qlw_ice(:,:,1) = sf(jp_qlw )%fnow(:,:,1)
  591. IF( ln_dm2dc ) THEN
  592. qsr_ice(:,:,1) = sbc_dcy( sf(jp_qsr)%fnow(:,:,1) )
  593. ELSE
  594. qsr_ice(:,:,1) = sf(jp_qsr)%fnow(:,:,1)
  595. ENDIF
  596. tatm_ice(:,:) = sf(jp_tair)%fnow(:,:,1) !#LB: should it be POTENTIAL temperature (theta_air_zt) instead ????
  597. qatm_ice(:,:) = q_air_zt(:,:)
  598. tprecip(:,:) = sf(jp_prec)%fnow(:,:,1) * rn_pfac
  599. sprecip(:,:) = sf(jp_snow)%fnow(:,:,1) * rn_pfac
  600. wndi_ice(:,:) = sf(jp_wndi)%fnow(:,:,1)
  601. wndj_ice(:,:) = sf(jp_wndj)%fnow(:,:,1)
  602. ENDIF
  603. #endif
  604. #if defined key_top
  605. IF( ln_trcdc2dm ) THEN ! diurnal cycle in TOP
  606. IF( MOD( kt - 1, nn_fsbc ) == 0 ) THEN
  607. IF( ln_dm2dc ) THEN
  608. qsr_mean(:,:) = ( 1. - albo ) * sf(jp_qsr)%fnow(:,:,1) * tmask(:,:,1)
  609. ELSE
  610. ncpl_qsr_freq = sf(jp_qsr)%freqh * 3600 ! qsr_mean will be computed in TOP
  611. ENDIF
  612. ENDIF
  613. ENDIF
  614. #endif
  615. !
  616. END SUBROUTINE sbc_blk
  617. SUBROUTINE blk_oce_1( kt, pwndi, pwndj, ptair, pqair, & ! inp
  618. & pslp , pst , pu , pv, & ! inp
  619. & puatm, pvatm, pdqsr , pdqlw , & ! inp
  620. & ptsk , pssq , pcd_du, psen, plat, pevp ) ! out
  621. !!---------------------------------------------------------------------
  622. !! *** ROUTINE blk_oce_1 ***
  623. !!
  624. !! ** Purpose : if ln_blk=T, computes surface momentum, heat and freshwater fluxes
  625. !! if ln_abl=T, computes Cd x |U|, Ch x |U|, Ce x |U| for ABL integration
  626. !!
  627. !! ** Method : bulk formulae using atmospheric fields from :
  628. !! if ln_blk=T, atmospheric fields read in sbc_read
  629. !! if ln_abl=T, the ABL model at previous time-step
  630. !!
  631. !! ** Outputs : - pssq : surface humidity used to compute latent heat flux (kg/kg)
  632. !! - pcd_du : Cd x |dU| at T-points (m/s)
  633. !! - psen : sensible heat flux (W/m^2)
  634. !! - plat : latent heat flux (W/m^2)
  635. !! - pevp : evaporation (mm/s) #lolo
  636. !!---------------------------------------------------------------------
  637. INTEGER , INTENT(in ) :: kt ! time step index
  638. REAL(wp), INTENT(in ), DIMENSION(:,:) :: pwndi ! atmospheric wind at T-point [m/s]
  639. REAL(wp), INTENT(in ), DIMENSION(:,:) :: pwndj ! atmospheric wind at T-point [m/s]
  640. REAL(wp), INTENT(in ), DIMENSION(:,:) :: pqair ! specific humidity at T-points [kg/kg]
  641. REAL(wp), INTENT(in ), DIMENSION(:,:) :: ptair ! potential temperature at T-points [Kelvin]
  642. REAL(wp), INTENT(in ), DIMENSION(:,:) :: pslp ! sea-level pressure [Pa]
  643. REAL(wp), INTENT(in ), DIMENSION(:,:) :: pst ! surface temperature [Celsius]
  644. REAL(wp), INTENT(in ), DIMENSION(:,:) :: pu ! surface current at U-point (i-component) [m/s]
  645. REAL(wp), INTENT(in ), DIMENSION(:,:) :: pv ! surface current at V-point (j-component) [m/s]
  646. REAL(wp), INTENT(in ), DIMENSION(:,:) :: puatm ! surface current seen by the atm at T-point (i-component) [m/s]
  647. REAL(wp), INTENT(in ), DIMENSION(:,:) :: pvatm ! surface current seen by the atm at T-point (j-component) [m/s]
  648. REAL(wp), INTENT(in ), DIMENSION(:,:) :: pdqsr ! downwelling solar (shortwave) radiation at surface [W/m^2]
  649. REAL(wp), INTENT(in ), DIMENSION(:,:) :: pdqlw ! downwelling longwave radiation at surface [W/m^2]
  650. REAL(wp), INTENT( out), DIMENSION(:,:) :: ptsk ! skin temp. (or SST if CS & WL not used) [Celsius]
  651. REAL(wp), INTENT( out), DIMENSION(:,:) :: pssq ! specific humidity at pst [kg/kg]
  652. REAL(wp), INTENT( out), DIMENSION(:,:) :: pcd_du
  653. REAL(wp), INTENT( out), DIMENSION(:,:) :: psen
  654. REAL(wp), INTENT( out), DIMENSION(:,:) :: plat
  655. REAL(wp), INTENT( out), DIMENSION(:,:) :: pevp
  656. !
  657. INTEGER :: ji, jj ! dummy loop indices
  658. REAL(wp) :: zztmp ! local variable
  659. REAL(wp) :: zstmax, zstau
  660. #if defined key_cyclone
  661. REAL(wp), DIMENSION(jpi,jpj) :: zwnd_i, zwnd_j ! wind speed components at T-point
  662. #endif
  663. REAL(wp), DIMENSION(jpi,jpj) :: ztau_i, ztau_j ! wind stress components at T-point
  664. REAL(wp), DIMENSION(jpi,jpj) :: zU_zu ! bulk wind speed at height zu [m/s]
  665. REAL(wp), DIMENSION(jpi,jpj) :: zcd_oce ! momentum transfert coefficient over ocean
  666. REAL(wp), DIMENSION(jpi,jpj) :: zch_oce ! sensible heat transfert coefficient over ocean
  667. REAL(wp), DIMENSION(jpi,jpj) :: zce_oce ! latent heat transfert coefficient over ocean
  668. REAL(wp), DIMENSION(jpi,jpj) :: zsspt ! potential sea-surface temperature [K]
  669. REAL(wp), DIMENSION(jpi,jpj) :: zpre, ztabs ! air pressure [Pa] & absolute temperature [K]
  670. REAL(wp), DIMENSION(jpi,jpj) :: zztmp1, zztmp2
  671. #if defined key_drakkar
  672. REAL(wp), DIMENSION(jpi,jpj) :: zwu, zwv
  673. #endif
  674. !!---------------------------------------------------------------------
  675. !
  676. ! local scalars ( place there for vector optimisation purposes)
  677. ! ! Temporary conversion from Celcius to Kelvin (and set minimum value far above 0 K)
  678. ptsk(:,:) = pst(:,:) + rt0 ! by default: skin temperature = "bulk SST" (will remain this way if NCAR algorithm used!)
  679. ! sea surface potential temperature [K]
  680. zsspt(:,:) = theta_exner( ptsk(:,:), pslp(:,:) )
  681. ! --- cloud cover --- !
  682. cloud_fra(:,:) = sf(jp_cc)%fnow(:,:,1)
  683. ! ----------------------------------------------------------------------------- !
  684. ! 0 Wind components and module at T-point relative to the moving ocean !
  685. ! ----------------------------------------------------------------------------- !
  686. ! ... components ( U10m - U_oce ) at T-point (unmasked)
  687. #if defined key_cyclone
  688. zwnd_i(:,:) = 0._wp
  689. zwnd_j(:,:) = 0._wp
  690. CALL wnd_cyc( kt, zwnd_i, zwnd_j ) ! add analytical tropical cyclone (Vincent et al. JGR 2012)
  691. DO_2D( nn_hls, nn_hls, nn_hls, nn_hls )
  692. zwnd_i(ji,jj) = pwndi(ji,jj) + zwnd_i(ji,jj)
  693. zwnd_j(ji,jj) = pwndj(ji,jj) + zwnd_j(ji,jj)
  694. ! ... scalar wind at T-point (not masked)
  695. wndm(ji,jj) = SQRT( zwnd_i(ji,jj) * zwnd_i(ji,jj) + zwnd_j(ji,jj) * zwnd_j(ji,jj) )
  696. END_2D
  697. #else
  698. #if defined key_drakkar
  699. IF (ln_clim_forcing) THEN
  700. wndm(:,:) = sf(jp_wmod)%fnow(:,:,1)
  701. ELSE
  702. #endif
  703. ! ... scalar wind module at T-point (not masked)
  704. DO_2D( nn_hls, nn_hls, nn_hls, nn_hls )
  705. wndm(ji,jj) = SQRT( pwndi(ji,jj) * pwndi(ji,jj) + pwndj(ji,jj) * pwndj(ji,jj) )
  706. END_2D
  707. #if defined key_drakkar
  708. ENDIF
  709. #endif
  710. #endif
  711. ! ----------------------------------------------------------------------------- !
  712. ! I Solar FLUX !
  713. ! ----------------------------------------------------------------------------- !
  714. ! ocean albedo assumed to be constant + modify now Qsr to include the diurnal cycle ! Short Wave
  715. zztmp = 1. - albo
  716. IF( ln_dm2dc ) THEN
  717. qsr(:,:) = zztmp * sbc_dcy( pdqsr(:,:) ) * tmask(:,:,1)
  718. ELSE
  719. qsr(:,:) = zztmp * pdqsr(:,:) * tmask(:,:,1)
  720. ENDIF
  721. ! ----------------------------------------------------------------------------- !
  722. ! II Turbulent FLUXES !
  723. ! ----------------------------------------------------------------------------- !
  724. ! specific humidity at SST
  725. pssq(:,:) = rdct_qsat_salt * q_sat( ptsk(:,:), pslp(:,:) )
  726. IF( ln_skin_cs .OR. ln_skin_wl ) THEN
  727. !! Backup "bulk SST" and associated spec. hum.
  728. zztmp1(:,:) = zsspt(:,:)
  729. zztmp2(:,:) = pssq(:,:)
  730. ENDIF
  731. !! Time to call the user-selected bulk parameterization for
  732. !! == transfer coefficients ==! Cd, Ch, Ce at T-point, and more...
  733. SELECT CASE( nblk )
  734. CASE( np_NCAR )
  735. CALL turb_ncar ( rn_zqt, rn_zu, zsspt, ptair, pssq, pqair, wndm, &
  736. & zcd_oce, zch_oce, zce_oce, theta_zu, q_zu, zU_zu , &
  737. & nb_iter=nn_iter_algo )
  738. !
  739. CASE( np_COARE_3p0 )
  740. CALL turb_coare3p0( kt, rn_zqt, rn_zu, zsspt, ptair, pssq, pqair, wndm, &
  741. & ln_skin_cs, ln_skin_wl, &
  742. & zcd_oce, zch_oce, zce_oce, theta_zu, q_zu, zU_zu, &
  743. & nb_iter=nn_iter_algo, &
  744. & Qsw=qsr(:,:), rad_lw=pdqlw(:,:), slp=pslp(:,:) )
  745. !
  746. CASE( np_COARE_3p6 )
  747. CALL turb_coare3p6( kt, rn_zqt, rn_zu, zsspt, ptair, pssq, pqair, wndm, &
  748. & ln_skin_cs, ln_skin_wl, &
  749. & zcd_oce, zch_oce, zce_oce, theta_zu, q_zu, zU_zu, &
  750. & nb_iter=nn_iter_algo, &
  751. & Qsw=qsr(:,:), rad_lw=pdqlw(:,:), slp=pslp(:,:) )
  752. !
  753. CASE( np_ECMWF )
  754. CALL turb_ecmwf ( kt, rn_zqt, rn_zu, zsspt, ptair, pssq, pqair, wndm, &
  755. & ln_skin_cs, ln_skin_wl, &
  756. & zcd_oce, zch_oce, zce_oce, theta_zu, q_zu, zU_zu, &
  757. & nb_iter=nn_iter_algo, &
  758. & Qsw=qsr(:,:), rad_lw=pdqlw(:,:), slp=pslp(:,:) )
  759. !
  760. CASE( np_ANDREAS )
  761. CALL turb_andreas ( rn_zqt, rn_zu, zsspt, ptair, pssq, pqair, wndm, &
  762. & zcd_oce, zch_oce, zce_oce, theta_zu, q_zu, zU_zu , &
  763. & nb_iter=nn_iter_algo )
  764. !
  765. CASE DEFAULT
  766. CALL ctl_stop( 'STOP', 'sbc_oce: non-existing bulk parameterizaton selected' )
  767. !
  768. END SELECT
  769. IF( iom_use('Cd_oce') ) CALL iom_put("Cd_oce", zcd_oce * tmask(:,:,1))
  770. IF( iom_use('Ce_oce') ) CALL iom_put("Ce_oce", zce_oce * tmask(:,:,1))
  771. IF( iom_use('Ch_oce') ) CALL iom_put("Ch_oce", zch_oce * tmask(:,:,1))
  772. !! LB: mainly here for debugging purpose:
  773. IF( iom_use('theta_zt') ) CALL iom_put("theta_zt", (ptair-rt0) * tmask(:,:,1)) ! potential temperature at z=zt
  774. IF( iom_use('q_zt') ) CALL iom_put("q_zt", pqair * tmask(:,:,1)) ! specific humidity "
  775. IF( iom_use('theta_zu') ) CALL iom_put("theta_zu", (theta_zu -rt0) * tmask(:,:,1)) ! potential temperature at z=zu
  776. IF( iom_use('q_zu') ) CALL iom_put("q_zu", q_zu * tmask(:,:,1)) ! specific humidity "
  777. IF( iom_use('ssq') ) CALL iom_put("ssq", pssq * tmask(:,:,1)) ! saturation specific humidity at z=0
  778. IF( iom_use('wspd_blk') ) CALL iom_put("wspd_blk", zU_zu * tmask(:,:,1)) ! bulk wind speed at z=zu
  779. IF( ln_skin_cs .OR. ln_skin_wl ) THEN
  780. !! In the presence of sea-ice we forget about the cool-skin/warm-layer update of zsspt, pssq & ptsk:
  781. WHERE ( fr_i(:,:) > 0.001_wp )
  782. ! sea-ice present, we forget about the update, using what we backed up before call to turb_*()
  783. zsspt(:,:) = zztmp1(:,:)
  784. pssq(:,:) = zztmp2(:,:)
  785. END WHERE
  786. ! apply potential temperature increment to abolute SST
  787. ptsk(:,:) = ptsk(:,:) + ( zsspt(:,:) - zztmp1(:,:) )
  788. END IF
  789. ! Turbulent fluxes over ocean => BULK_FORMULA @ sbc_phy.F90
  790. ! -------------------------------------------------------------
  791. IF( ln_abl ) THEN !== ABL formulation ==! multiplication by rho_air and turbulent fluxes computation done in ablstp
  792. DO_2D( nn_hls, nn_hls, nn_hls, nn_hls )
  793. zztmp = zU_zu(ji,jj)
  794. wndm(ji,jj) = zztmp ! Store zU_zu in wndm to compute ustar2 in ablmod
  795. pcd_du(ji,jj) = zztmp * zcd_oce(ji,jj)
  796. psen(ji,jj) = zztmp * zch_oce(ji,jj)
  797. pevp(ji,jj) = zztmp * zce_oce(ji,jj)
  798. zpre(ji,jj) = pres_temp( pqair(ji,jj), pslp(ji,jj), rn_zu, ptpot=ptair(ji,jj), pta=ztabs(ji,jj) )
  799. rhoa(ji,jj) = rho_air( ztabs(ji,jj), pqair(ji,jj), zpre(ji,jj) )
  800. END_2D
  801. ELSE !== BLK formulation ==! turbulent fluxes computation
  802. DO_2D( nn_hls, nn_hls, nn_hls, nn_hls )
  803. zpre(ji,jj) = pres_temp( q_zu(ji,jj), pslp(ji,jj), rn_zu, ptpot=theta_zu(ji,jj), pta=ztabs(ji,jj) )
  804. rhoa(ji,jj) = rho_air( ztabs(ji,jj), q_zu(ji,jj), zpre(ji,jj) )
  805. END_2D
  806. CALL BULK_FORMULA( rn_zu, zsspt(:,:), pssq(:,:), theta_zu(:,:), q_zu(:,:), &
  807. & zcd_oce(:,:), zch_oce(:,:), zce_oce(:,:), &
  808. & wndm(:,:), zU_zu(:,:), pslp(:,:), rhoa(:,:), &
  809. & taum(:,:), psen(:,:), plat(:,:), &
  810. & pEvap=pevp(:,:), pfact_evap=rn_efac )
  811. psen(:,:) = psen(:,:) * tmask(:,:,1)
  812. plat(:,:) = plat(:,:) * tmask(:,:,1)
  813. taum(:,:) = taum(:,:) * tmask(:,:,1)
  814. pevp(:,:) = pevp(:,:) * tmask(:,:,1)
  815. #if defined key_drakkar
  816. IF ( ln_clim_forcing ) THEN
  817. zwu(:,:) = sf(jp_uw)%fnow(:,:,1)
  818. zwv(:,:) = sf(jp_vw)%fnow(:,:,1)
  819. DO_2D( nn_hls, nn_hls, nn_hls, nn_hls )
  820. IF( wndm(ji,jj) > 0._wp ) THEN
  821. zztmp = taum(ji,jj) / wndm(ji,jj) / wndm(ji,jj)
  822. ! note that key_cyclone is not supported with climatological forcing
  823. ztau_i(ji,jj) = zztmp * zwu(ji,jj)
  824. ztau_j(ji,jj) = zztmp * zwv(ji,jj)
  825. ELSE
  826. ztau_i(ji,jj) = 0._wp
  827. ztau_j(ji,jj) = 0._wp
  828. ENDIF
  829. END_2D
  830. ELSE
  831. #endif
  832. DO_2D( nn_hls, nn_hls, nn_hls, nn_hls )
  833. IF( wndm(ji,jj) > 0._wp ) THEN
  834. zztmp = taum(ji,jj) / wndm(ji,jj)
  835. #if defined key_cyclone
  836. ztau_i(ji,jj) = zztmp * zwnd_i(ji,jj)
  837. ztau_j(ji,jj) = zztmp * zwnd_j(ji,jj)
  838. #else
  839. ztau_i(ji,jj) = zztmp * pwndi(ji,jj)
  840. ztau_j(ji,jj) = zztmp * pwndj(ji,jj)
  841. #endif
  842. ELSE
  843. ztau_i(ji,jj) = 0._wp
  844. ztau_j(ji,jj) = 0._wp
  845. ENDIF
  846. END_2D
  847. #if defined key_drakkar
  848. ENDIF
  849. #endif
  850. IF( ln_crt_fbk ) THEN ! aply eq. 10 and 11 of Renault et al. 2020 (doi: 10.1029/2019MS001715)
  851. 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)
  852. 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
  853. zstau = MIN( rn_stau_a * wndm(ji,jj) + rn_stau_b, zstmax ) ! stau (<0) must be smaller than zstmax
  854. ztau_i(ji,jj) = ztau_i(ji,jj) + zstau * ( 0.5_wp * ( pu(ji-1,jj ) + pu(ji,jj) ) - puatm(ji,jj) )
  855. ztau_j(ji,jj) = ztau_j(ji,jj) + zstau * ( 0.5_wp * ( pv(ji ,jj-1) + pv(ji,jj) ) - pvatm(ji,jj) )
  856. taum(ji,jj) = SQRT( ztau_i(ji,jj) * ztau_i(ji,jj) + ztau_j(ji,jj) * ztau_j(ji,jj) )
  857. END_2D
  858. ENDIF
  859. ! ... utau, vtau at U- and V_points, resp.
  860. ! Note the use of 0.5*(2-umask) in order to unmask the stress along coastlines
  861. ! Note that coastal wind stress is not used in the code... so this extra care has no effect
  862. DO_2D( 0, 0, 0, 0 ) ! start loop at 2, in case ln_crt_fbk = T
  863. utau(ji,jj) = 0.5 * ( 2. - umask(ji,jj,1) ) * ( ztau_i(ji,jj) + ztau_i(ji+1,jj ) ) &
  864. & * MAX(tmask(ji,jj,1),tmask(ji+1,jj,1))
  865. vtau(ji,jj) = 0.5 * ( 2. - vmask(ji,jj,1) ) * ( ztau_j(ji,jj) + ztau_j(ji ,jj+1) ) &
  866. & * MAX(tmask(ji,jj,1),tmask(ji,jj+1,1))
  867. END_2D
  868. IF( ln_crt_fbk ) THEN
  869. CALL lbc_lnk( 'sbcblk', utau, 'U', -1._wp, vtau, 'V', -1._wp, taum, 'T', 1._wp )
  870. ELSE
  871. CALL lbc_lnk( 'sbcblk', utau, 'U', -1._wp, vtau, 'V', -1._wp )
  872. ENDIF
  873. ! Saving open-ocean wind-stress (module and components) on T-points:
  874. CALL iom_put( "taum_oce", taum(:,:)*tmask(:,:,1) ) ! output wind stress module
  875. !#LB: These 2 lines below mostly here for 'STATION_ASF' test-case, otherwize "utau" (U-grid) and vtau" (V-grid) does the job in: [DYN/dynatf.F90])
  876. CALL iom_put( "utau_oce", ztau_i(:,:)*tmask(:,:,1) ) ! utau at T-points!
  877. CALL iom_put( "vtau_oce", ztau_j(:,:)*tmask(:,:,1) ) ! vtau at T-points!
  878. IF(sn_cfctl%l_prtctl) THEN
  879. CALL prt_ctl( tab2d_1=pssq , clinfo1=' blk_oce_1: pssq : ')
  880. CALL prt_ctl( tab2d_1=wndm , clinfo1=' blk_oce_1: wndm : ')
  881. CALL prt_ctl( tab2d_1=utau , clinfo1=' blk_oce_1: utau : ', mask1=umask, &
  882. & tab2d_2=vtau , clinfo2=' vtau : ', mask2=vmask )
  883. CALL prt_ctl( tab2d_1=zcd_oce, clinfo1=' blk_oce_1: Cd : ')
  884. ENDIF
  885. !
  886. ENDIF ! ln_blk / ln_abl
  887. ptsk(:,:) = ( ptsk(:,:) - rt0 ) * tmask(:,:,1) ! Back to Celsius
  888. IF( ln_skin_cs .OR. ln_skin_wl ) THEN
  889. CALL iom_put( "t_skin" , ptsk ) ! T_skin in Celsius
  890. CALL iom_put( "dt_skin" , ptsk - pst ) ! T_skin - SST temperature difference
  891. ENDIF
  892. !
  893. END SUBROUTINE blk_oce_1
  894. SUBROUTINE blk_oce_2( ptair, pdqlw, pprec, psnow, & ! <<= in
  895. & ptsk, psen, plat, pevp ) ! <<= in
  896. !!---------------------------------------------------------------------
  897. !! *** ROUTINE blk_oce_2 ***
  898. !!
  899. !! ** Purpose : finalize the momentum, heat and freshwater fluxes computation
  900. !! at the ocean surface at each time step knowing Cd, Ch, Ce and
  901. !! atmospheric variables (from ABL or external data)
  902. !!
  903. #if defined key_drakkar
  904. !! ** Outputs : - emp : evaporation minus precipitation (kg/m2/s)
  905. !! - qns : Non Solar heat flux over the ocean (W/m2)
  906. !! (include heat content of the precip, evap
  907. !! latent heat flux from melting snow )
  908. !! - qns_oce : Just the sensible, latent and LW (to be used in SI3)
  909. !! - qsr_oce : = qsr (to be used in SI3)
  910. #else
  911. !! ** Outputs : - utau : i-component of the stress at U-point (N/m2)
  912. !! - vtau : j-component of the stress at V-point (N/m2)
  913. !! - taum : Wind stress module at T-point (N/m2)
  914. !! - wndm : Wind speed module at T-point (m/s)
  915. !! - qsr : Solar heat flux over the ocean (W/m2)
  916. !! - qns : Non Solar heat flux over the ocean (W/m2)
  917. !! - emp : evaporation minus precipitation (kg/m2/s)
  918. !!---------------------------------------------------------------------
  919. #endif
  920. REAL(wp), INTENT(in), DIMENSION(:,:) :: ptair ! potential temperature of air #LB: confirm!
  921. REAL(wp), INTENT(in), DIMENSION(:,:) :: pdqlw ! downwelling longwave radiation at surface [W/m^2]
  922. REAL(wp), INTENT(in), DIMENSION(:,:) :: pprec
  923. REAL(wp), INTENT(in), DIMENSION(:,:) :: psnow
  924. REAL(wp), INTENT(in), DIMENSION(:,:) :: ptsk ! SKIN surface temperature [Celsius]
  925. REAL(wp), INTENT(in), DIMENSION(:,:) :: psen
  926. REAL(wp), INTENT(in), DIMENSION(:,:) :: plat
  927. REAL(wp), INTENT(in), DIMENSION(:,:) :: pevp
  928. !
  929. INTEGER :: ji, jj ! dummy loop indices
  930. REAL(wp) :: zztmp,zz1,zz2,zz3 ! local variable
  931. REAL(wp), DIMENSION(jpi,jpj) :: zqlw ! net long wave radiative heat flux
  932. REAL(wp), DIMENSION(jpi,jpj) :: zcptrain, zcptsnw, zcptn ! Heat content per unit mass (J/kg)
  933. !!---------------------------------------------------------------------
  934. !
  935. ! Heat content per unit mass (J/kg)
  936. zcptrain(:,:) = ( ptair - rt0 ) * rcp * tmask(:,:,1)
  937. zcptsnw (:,:) = ( MIN( ptair, rt0 ) - rt0 ) * rcpi * tmask(:,:,1)
  938. zcptn (:,:) = ptsk * rcp * tmask(:,:,1)
  939. !
  940. ! ----------------------------------------------------------------------------- !
  941. ! III Net longwave radiative FLUX !
  942. ! ----------------------------------------------------------------------------- !
  943. !! #LB: now moved after Turbulent fluxes because must use the skin temperature rather than bulk SST
  944. !! (ptsk is skin temperature if ln_skin_cs==.TRUE. .OR. ln_skin_wl==.TRUE.)
  945. zqlw(:,:) = qlw_net( pdqlw(:,:), ptsk(:,:)+rt0 )
  946. ! ----------------------------------------------------------------------------- !
  947. ! IV Total FLUXES !
  948. ! ----------------------------------------------------------------------------- !
  949. !
  950. emp (:,:) = ( pevp(:,:) - pprec(:,:) * rn_pfac ) * tmask(:,:,1) ! mass flux (evap. - precip.)
  951. !
  952. qns(:,:) = zqlw(:,:) + psen(:,:) + plat(:,:) & ! Downward Non Solar
  953. & - psnow(:,:) * rn_pfac * rLfus & ! remove latent melting heat for solid precip
  954. & - pevp(:,:) * zcptn(:,:) & ! remove evap heat content at SST
  955. & + ( pprec(:,:) - psnow(:,:) ) * rn_pfac * zcptrain(:,:) & ! add liquid precip heat content at Tair
  956. & + psnow(:,:) * rn_pfac * zcptsnw(:,:) ! add solid precip heat content at min(Tair,Tsnow)
  957. qns(:,:) = qns(:,:) * tmask(:,:,1)
  958. !
  959. #if defined key_si3
  960. qns_oce(:,:) = zqlw(:,:) + psen(:,:) + plat(:,:) ! non solar without emp (only needed by SI3)
  961. qsr_oce(:,:) = qsr(:,:)
  962. #endif
  963. !
  964. CALL iom_put( "rho_air" , rhoa*tmask(:,:,1) ) ! output air density [kg/m^3]
  965. CALL iom_put( "evap_oce" , pevp ) ! evaporation
  966. CALL iom_put( "qlw_oce" , zqlw ) ! output downward longwave heat over the ocean
  967. CALL iom_put( "qsb_oce" , psen ) ! output downward sensible heat over the ocean
  968. CALL iom_put( "qla_oce" , plat ) ! output downward latent heat over the ocean
  969. tprecip(:,:) = pprec(:,:) * rn_pfac * tmask(:,:,1) ! output total precipitation [kg/m2/s]
  970. sprecip(:,:) = psnow(:,:) * rn_pfac * tmask(:,:,1) ! output solid precipitation [kg/m2/s]
  971. CALL iom_put( 'snowpre', sprecip ) ! Snow
  972. CALL iom_put( 'precip' , tprecip ) ! Total precipitation
  973. !
  974. IF ( nn_ice == 0 ) THEN
  975. CALL iom_put( "qemp_oce" , qns-zqlw-psen-plat ) ! output downward heat content of E-P over the ocean
  976. CALL iom_put( "qns_oce" , qns ) ! output downward non solar heat over the ocean
  977. CALL iom_put( "qsr_oce" , qsr ) ! output downward solar heat over the ocean
  978. CALL iom_put( "qt_oce" , qns+qsr ) ! output total downward heat over the ocean
  979. ENDIF
  980. !
  981. IF(sn_cfctl%l_prtctl) THEN
  982. CALL prt_ctl(tab2d_1=zqlw , clinfo1=' blk_oce_2: zqlw : ')
  983. CALL prt_ctl(tab2d_1=psen , clinfo1=' blk_oce_2: psen : ' )
  984. CALL prt_ctl(tab2d_1=plat , clinfo1=' blk_oce_2: plat : ' )
  985. CALL prt_ctl(tab2d_1=qns , clinfo1=' blk_oce_2: qns : ' )
  986. CALL prt_ctl(tab2d_1=emp , clinfo1=' blk_oce_2: emp : ')
  987. ENDIF
  988. !
  989. END SUBROUTINE blk_oce_2
  990. #if defined key_si3
  991. !!----------------------------------------------------------------------
  992. !! 'key_si3' SI3 sea-ice model
  993. !!----------------------------------------------------------------------
  994. !! blk_ice_1 : provide the air-ice stress
  995. !! blk_ice_2 : provide the heat and mass fluxes at air-ice interface
  996. !! blk_ice_qcn : provide ice surface temperature and snow/ice conduction flux (emulating conduction flux)
  997. !!----------------------------------------------------------------------
  998. SUBROUTINE blk_ice_1( pwndi, pwndj, ptair, pqair, pslp , puice, pvice, ptsui, & ! inputs
  999. & putaui, pvtaui, pseni, pevpi, pssqi, pcd_dui ) ! optional outputs
  1000. !!---------------------------------------------------------------------
  1001. !! *** ROUTINE blk_ice_1 ***
  1002. !!
  1003. !! ** Purpose : provide the surface boundary condition over sea-ice
  1004. !!
  1005. !! ** Method : compute momentum using bulk formulation
  1006. !! formulea, ice variables and read atmospheric fields.
  1007. !! NB: ice drag coefficient is assumed to be a constant
  1008. !!---------------------------------------------------------------------
  1009. REAL(wp) , INTENT(in ), DIMENSION(:,: ) :: pslp ! sea-level pressure [Pa]
  1010. REAL(wp) , INTENT(in ), DIMENSION(:,: ) :: pwndi ! atmospheric wind at T-point [m/s]
  1011. REAL(wp) , INTENT(in ), DIMENSION(:,: ) :: pwndj ! atmospheric wind at T-point [m/s]
  1012. REAL(wp) , INTENT(in ), DIMENSION(:,: ) :: ptair ! atmospheric potential temperature at T-point [K]
  1013. REAL(wp) , INTENT(in ), DIMENSION(:,: ) :: pqair ! atmospheric specific humidity at T-point [kg/kg]
  1014. REAL(wp) , INTENT(in ), DIMENSION(:,: ) :: puice ! sea-ice velocity on I or C grid [m/s]
  1015. REAL(wp) , INTENT(in ), DIMENSION(:,: ) :: pvice ! "
  1016. REAL(wp) , INTENT(in ), DIMENSION(:,: ) :: ptsui ! sea-ice surface temperature [K]
  1017. REAL(wp) , INTENT( out), DIMENSION(:,: ), OPTIONAL :: putaui ! if ln_blk
  1018. REAL(wp) , INTENT( out), DIMENSION(:,: ), OPTIONAL :: pvtaui ! if ln_blk
  1019. REAL(wp) , INTENT( out), DIMENSION(:,: ), OPTIONAL :: pseni ! if ln_abl
  1020. REAL(wp) , INTENT( out), DIMENSION(:,: ), OPTIONAL :: pevpi ! if ln_abl
  1021. REAL(wp) , INTENT( out), DIMENSION(:,: ), OPTIONAL :: pssqi ! if ln_abl
  1022. REAL(wp) , INTENT( out), DIMENSION(:,: ), OPTIONAL :: pcd_dui ! if ln_abl
  1023. !
  1024. INTEGER :: ji, jj ! dummy loop indices
  1025. REAL(wp) :: zootm_su ! sea-ice surface mean temperature
  1026. REAL(wp) :: zztmp1, zztmp2 ! temporary scalars
  1027. REAL(wp), DIMENSION(jpi,jpj) :: ztmp, zsipt ! temporary array
  1028. #if defined key_drakkar
  1029. REAL(wp), DIMENSION(jpi,jpj) :: zwu, zwv ! temporary array
  1030. #endif
  1031. !!---------------------------------------------------------------------
  1032. !
  1033. ! ------------------------------------------------------------ !
  1034. ! Wind module relative to the moving ice ( U10m - U_ice ) !
  1035. ! ------------------------------------------------------------ !
  1036. ! C-grid ice dynamics : U & V-points (same as ocean)
  1037. #if defined key_drakkar
  1038. IF ( ln_clim_forcing) THEN
  1039. wndm_ice(:,:) = sf(jp_wmod)%fnow(:,:,1)
  1040. ELSE
  1041. #endif
  1042. DO_2D( nn_hls, nn_hls, nn_hls, nn_hls )
  1043. wndm_ice(ji,jj) = SQRT( pwndi(ji,jj) * pwndi(ji,jj) + pwndj(ji,jj) * pwndj(ji,jj) )
  1044. END_2D
  1045. #if defined key_drakkar
  1046. ENDIF
  1047. #endif
  1048. !
  1049. ! potential sea-ice surface temperature [K]
  1050. zsipt(:,:) = theta_exner( ptsui(:,:), pslp(:,:) )
  1051. ! sea-ice <-> atmosphere bulk transfer coefficients
  1052. SELECT CASE( nblk_ice )
  1053. CASE( np_ice_cst )
  1054. ! Constant bulk transfer coefficients over sea-ice:
  1055. Cd_ice(:,:) = rn_Cd_i
  1056. Ch_ice(:,:) = rn_Ch_i
  1057. Ce_ice(:,:) = rn_Ce_i
  1058. ! no height adjustment, keeping zt values:
  1059. theta_zu_i(:,:) = ptair(:,:)
  1060. q_zu_i(:,:) = pqair(:,:)
  1061. CASE( np_ice_an05 ) ! calculate new drag from Lupkes(2015) equations
  1062. ztmp(:,:) = q_sat( ptsui(:,:), pslp(:,:), l_ice=.TRUE. ) ! temporary array for SSQ
  1063. CALL turb_ice_an05( rn_zqt, rn_zu, zsipt, ptair, ztmp, pqair, wndm_ice, &
  1064. & Cd_ice, Ch_ice, Ce_ice, theta_zu_i, q_zu_i )
  1065. !!
  1066. CASE( np_ice_lu12 )
  1067. ztmp(:,:) = q_sat( ptsui(:,:), pslp(:,:), l_ice=.TRUE. ) ! temporary array for SSQ
  1068. CALL turb_ice_lu12( rn_zqt, rn_zu, zsipt, ptair, ztmp, pqair, wndm_ice, fr_i, &
  1069. & Cd_ice, Ch_ice, Ce_ice, theta_zu_i, q_zu_i )
  1070. !!
  1071. CASE( np_ice_lg15 ) ! calculate new drag from Lupkes(2015) equations
  1072. ztmp(:,:) = q_sat( ptsui(:,:), pslp(:,:), l_ice=.TRUE. ) ! temporary array for SSQ
  1073. CALL turb_ice_lg15( rn_zqt, rn_zu, zsipt, ptair, ztmp, pqair, wndm_ice, fr_i, &
  1074. & Cd_ice, Ch_ice, Ce_ice, theta_zu_i, q_zu_i )
  1075. !!
  1076. END SELECT
  1077. IF( iom_use('Cd_ice').OR.iom_use('Ce_ice').OR.iom_use('Ch_ice').OR.iom_use('taum_ice').OR.iom_use('utau_ice').OR.iom_use('vtau_ice') ) &
  1078. & ztmp(:,:) = ( 1._wp - MAX(0._wp, SIGN( 1._wp, 1.E-6_wp - fr_i )) )*tmask(:,:,1) ! mask for presence of ice !
  1079. IF( iom_use('Cd_ice') ) CALL iom_put("Cd_ice", Cd_ice*ztmp)
  1080. IF( iom_use('Ce_ice') ) CALL iom_put("Ce_ice", Ce_ice*ztmp)
  1081. IF( iom_use('Ch_ice') ) CALL iom_put("Ch_ice", Ch_ice*ztmp)
  1082. IF( ln_blk ) THEN
  1083. ! ---------------------------------------------------- !
  1084. ! Wind stress relative to nonmoving ice ( U10m ) !
  1085. ! ---------------------------------------------------- !
  1086. ! supress moving ice in wind stress computation as we don't know how to do it properly...
  1087. #if defined key_drakkar
  1088. IF ( ln_clim_forcing ) THEN
  1089. zwu(:,:) = sf(jp_uw)%fnow(:,:,1)
  1090. zwv(:,:) = sf(jp_vw)%fnow(:,:,1)
  1091. DO_2D( 0, 1, 0, 1 ) ! at T point
  1092. zztmp1 = rhoa(ji,jj) * Cd_ice(ji,jj)
  1093. putaui(ji,jj) = zztmp1 * zwu (ji,jj)
  1094. pvtaui(ji,jj) = zztmp1 * zwv (ji,jj)
  1095. END_2D
  1096. ELSE
  1097. #endif
  1098. DO_2D( 0, 1, 0, 1 ) ! at T point
  1099. zztmp1 = rhoa(ji,jj) * Cd_ice(ji,jj) * wndm_ice(ji,jj)
  1100. putaui(ji,jj) = zztmp1 * pwndi(ji,jj)
  1101. pvtaui(ji,jj) = zztmp1 * pwndj(ji,jj)
  1102. END_2D
  1103. #if defined key_drakkar
  1104. ENDIF
  1105. #endif
  1106. !#LB: saving the module, and x-y components, of the ai wind-stress at T-points: NOT weighted by the ice concentration !!!
  1107. IF(iom_use('taum_ice')) CALL iom_put('taum_ice', SQRT( putaui*putaui + pvtaui*pvtaui )*ztmp )
  1108. !#LB: These 2 lines below mostly here for 'STATION_ASF' test-case, otherwize "utau_oi" (U-grid) and vtau_oi" (V-grid) does the job in: [ICE/icedyn_rhg_evp.F90])
  1109. IF(iom_use('utau_ice')) CALL iom_put("utau_ice", putaui*ztmp) ! utau at T-points!
  1110. IF(iom_use('vtau_ice')) CALL iom_put("vtau_ice", pvtaui*ztmp) ! vtau at T-points!
  1111. !
  1112. DO_2D( 0, 0, 0, 0 ) ! U & V-points (same as ocean).
  1113. !#LB: QUESTION?? so SI3 expects wind stress vector to be provided at U & V points? Not at T-points ?
  1114. ! take care of the land-sea mask to avoid "pollution" of coastal stress. p[uv]taui used in frazil and rheology
  1115. zztmp1 = 0.5_wp * ( 2. - umask(ji,jj,1) ) * MAX( tmask(ji,jj,1),tmask(ji+1,jj ,1) )
  1116. zztmp2 = 0.5_wp * ( 2. - vmask(ji,jj,1) ) * MAX( tmask(ji,jj,1),tmask(ji ,jj+1,1) )
  1117. putaui(ji,jj) = zztmp1 * ( putaui(ji,jj) + putaui(ji+1,jj ) )
  1118. pvtaui(ji,jj) = zztmp2 * ( pvtaui(ji,jj) + pvtaui(ji ,jj+1) )
  1119. END_2D
  1120. CALL lbc_lnk( 'sbcblk', putaui, 'U', -1._wp, pvtaui, 'V', -1._wp )
  1121. !
  1122. IF(sn_cfctl%l_prtctl) CALL prt_ctl( tab2d_1=putaui , clinfo1=' blk_ice: putaui : ' &
  1123. & , tab2d_2=pvtaui , clinfo2=' pvtaui : ' )
  1124. ELSE ! ln_abl
  1125. DO_2D( nn_hls, nn_hls, nn_hls, nn_hls )
  1126. pcd_dui(ji,jj) = wndm_ice(ji,jj) * Cd_ice(ji,jj)
  1127. pseni (ji,jj) = wndm_ice(ji,jj) * Ch_ice(ji,jj)
  1128. pevpi (ji,jj) = wndm_ice(ji,jj) * Ce_ice(ji,jj)
  1129. END_2D
  1130. pssqi(:,:) = q_sat( ptsui(:,:), pslp(:,:), l_ice=.TRUE. ) ; ! more accurate way to obtain ssq !
  1131. ENDIF ! ln_blk / ln_abl
  1132. !
  1133. IF(sn_cfctl%l_prtctl) CALL prt_ctl(tab2d_1=wndm_ice , clinfo1=' blk_ice: wndm_ice : ')
  1134. !
  1135. END SUBROUTINE blk_ice_1
  1136. SUBROUTINE blk_ice_2( ptsu, phs, phi, palb, ptair, pqair, pslp, pdqlw, pprec, psnow )
  1137. !!---------------------------------------------------------------------
  1138. !! *** ROUTINE blk_ice_2 ***
  1139. !!
  1140. !! ** Purpose : provide the heat and mass fluxes at air-ice interface
  1141. !!
  1142. !! ** Method : compute heat and freshwater exchanged
  1143. !! between atmosphere and sea-ice using bulk formulation
  1144. !! formulea, ice variables and read atmmospheric fields.
  1145. !!
  1146. !! caution : the net upward water flux has with mm/day unit
  1147. !!---------------------------------------------------------------------
  1148. REAL(wp), DIMENSION(:,:,:), INTENT(in) :: ptsu ! sea ice surface temperature [K]
  1149. REAL(wp), DIMENSION(:,:,:), INTENT(in) :: phs ! snow thickness
  1150. REAL(wp), DIMENSION(:,:,:), INTENT(in) :: phi ! ice thickness
  1151. REAL(wp), DIMENSION(:,:,:), INTENT(in) :: palb ! ice albedo (all skies)
  1152. REAL(wp), DIMENSION(:,: ), INTENT(in) :: ptair ! potential temperature of air #LB: okay ???
  1153. REAL(wp), DIMENSION(:,: ), INTENT(in) :: pqair ! specific humidity of air
  1154. REAL(wp), DIMENSION(:,: ), INTENT(in) :: pslp
  1155. REAL(wp), DIMENSION(:,: ), INTENT(in) :: pdqlw
  1156. REAL(wp), DIMENSION(:,: ), INTENT(in) :: pprec
  1157. REAL(wp), DIMENSION(:,: ), INTENT(in) :: psnow
  1158. !!
  1159. INTEGER :: ji, jj, jl ! dummy loop indices
  1160. REAL(wp) :: zst, zst3, zsq, zsipt ! local variable
  1161. REAL(wp) :: zcoef_dqlw, zcoef_dqla ! - -
  1162. REAL(wp) :: zztmp, zzblk, zztmp1, z1_rLsub ! - -
  1163. REAL(wp), DIMENSION(jpi,jpj,jpl) :: z_qlw ! long wave heat flux over ice
  1164. REAL(wp), DIMENSION(jpi,jpj,jpl) :: z_qsb ! sensible heat flux over ice
  1165. REAL(wp), DIMENSION(jpi,jpj,jpl) :: z_dqlw ! long wave heat sensitivity over ice
  1166. REAL(wp), DIMENSION(jpi,jpj,jpl) :: z_dqsb ! sensible heat sensitivity over ice
  1167. REAL(wp), DIMENSION(jpi,jpj) :: zevap, zsnw ! evaporation and snw distribution after wind blowing (SI3)
  1168. REAL(wp), DIMENSION(jpi,jpj) :: ztmp, ztmp2
  1169. REAL(wp), DIMENSION(jpi,jpj) :: ztri
  1170. REAL(wp), DIMENSION(jpi,jpj) :: zcptrain, zcptsnw, zcptn ! Heat content per unit mass (J/kg)
  1171. !!---------------------------------------------------------------------
  1172. !
  1173. zcoef_dqlw = 4._wp * emiss_i * stefan ! local scalars
  1174. zztmp = 1. / ( 1. - albo )
  1175. dqla_ice(:,:,:) = 0._wp
  1176. ! Heat content per unit mass (J/kg)
  1177. zcptrain(:,:) = ( ptair - rt0 ) * rcp * tmask(:,:,1)
  1178. zcptsnw (:,:) = ( MIN( ptair, rt0 ) - rt0 ) * rcpi * tmask(:,:,1)
  1179. zcptn (:,:) = sst_m * rcp * tmask(:,:,1)
  1180. !
  1181. ! ! ========================== !
  1182. DO jl = 1, jpl ! Loop over ice categories !
  1183. ! ! ========================== !
  1184. DO_2D( nn_hls, nn_hls, nn_hls, nn_hls )
  1185. zst = ptsu(ji,jj,jl) ! surface temperature of sea-ice [K]
  1186. zsq = q_sat( zst, pslp(ji,jj), l_ice=.TRUE. ) ! surface saturation specific humidity when ice present
  1187. zsipt = theta_exner( zst, pslp(ji,jj) ) ! potential sea-ice surface temperature [K]
  1188. ! ----------------------------!
  1189. ! I Radiative FLUXES !
  1190. ! ----------------------------!
  1191. ! Short Wave (sw)
  1192. qsr_ice(ji,jj,jl) = zztmp * ( 1. - palb(ji,jj,jl) ) * qsr(ji,jj)
  1193. ! Long Wave (lw)
  1194. zst3 = zst * zst * zst
  1195. z_qlw(ji,jj,jl) = emiss_i * ( pdqlw(ji,jj) - stefan * zst * zst3 ) * tmask(ji,jj,1)
  1196. ! lw sensitivity
  1197. z_dqlw(ji,jj,jl) = zcoef_dqlw * zst3
  1198. ! ----------------------------!
  1199. ! II Turbulent FLUXES !
  1200. ! ----------------------------!
  1201. ! ... turbulent heat fluxes with Ch_ice recalculated in blk_ice_1
  1202. ! Common term in bulk F. equations...
  1203. zzblk = rhoa(ji,jj) * wndm_ice(ji,jj)
  1204. ! Sensible Heat
  1205. zztmp1 = zzblk * rCp_air * Ch_ice(ji,jj)
  1206. z_qsb (ji,jj,jl) = zztmp1 * (zsipt - theta_zu_i(ji,jj))
  1207. z_dqsb(ji,jj,jl) = zztmp1 ! ==> Qsens sensitivity (Dqsb_ice/Dtn_ice)
  1208. ! Latent Heat
  1209. zztmp1 = zzblk * rLsub * Ce_ice(ji,jj)
  1210. qla_ice(ji,jj,jl) = MAX( zztmp1 * (zsq - q_zu_i(ji,jj)) , 0._wp ) ! #LB: only sublimation (and not condensation) ???
  1211. IF(qla_ice(ji,jj,jl)>0._wp) dqla_ice(ji,jj,jl) = zztmp1*dq_sat_dt_ice(zst, pslp(ji,jj)) ! ==> Qlat sensitivity (dQlat/dT)
  1212. ! !#LB: dq_sat_dt_ice() in "sbc_phy.F90"
  1213. !#LB: without this unjustified "condensation sensure":
  1214. !qla_ice( ji,jj,jl) = zztmp1 * (zsq - q_zu_i(ji,jj))
  1215. !dqla_ice(ji,jj,jl) = zztmp1 * dq_sat_dt_ice(zst, pslp(ji,jj)) ! ==> Qlat sensitivity (dQlat/dT)
  1216. ! ----------------------------!
  1217. ! III Total FLUXES !
  1218. ! ----------------------------!
  1219. ! Downward Non Solar flux
  1220. qns_ice (ji,jj,jl) = z_qlw (ji,jj,jl) - z_qsb (ji,jj,jl) - qla_ice (ji,jj,jl)
  1221. ! Total non solar heat flux sensitivity for ice
  1222. dqns_ice(ji,jj,jl) = - ( z_dqlw(ji,jj,jl) + z_dqsb(ji,jj,jl) + dqla_ice(ji,jj,jl) ) !#LB: correct signs ????
  1223. END_2D
  1224. !
  1225. END DO
  1226. !
  1227. tprecip(:,:) = pprec(:,:) * rn_pfac * tmask(:,:,1) ! total precipitation [kg/m2/s]
  1228. sprecip(:,:) = psnow(:,:) * rn_pfac * tmask(:,:,1) ! solid precipitation [kg/m2/s]
  1229. CALL iom_put( 'snowpre', sprecip ) ! Snow precipitation
  1230. CALL iom_put( 'precip' , tprecip ) ! Total precipitation
  1231. ! --- evaporation --- !
  1232. z1_rLsub = 1._wp / rLsub
  1233. evap_ice (:,:,:) = rn_efac * qla_ice (:,:,:) * z1_rLsub ! sublimation
  1234. devap_ice(:,:,:) = rn_efac * dqla_ice(:,:,:) * z1_rLsub ! d(sublimation)/dT
  1235. zevap (:,:) = emp(:,:) + tprecip(:,:) ! evaporation over ocean !LB: removed rn_efac here, correct???
  1236. ! --- evaporation minus precipitation --- !
  1237. zsnw(:,:) = 0._wp
  1238. CALL ice_var_snwblow( (1.-at_i_b(:,:)), zsnw ) ! snow distribution over ice after wind blowing
  1239. emp_oce(:,:) = ( 1._wp - at_i_b(:,:) ) * zevap(:,:) - ( tprecip(:,:) - sprecip(:,:) ) - sprecip(:,:) * (1._wp - zsnw )
  1240. emp_ice(:,:) = SUM( a_i_b(:,:,:) * evap_ice(:,:,:), dim=3 ) - sprecip(:,:) * zsnw
  1241. emp_tot(:,:) = emp_oce(:,:) + emp_ice(:,:)
  1242. ! --- heat flux associated with emp --- !
  1243. qemp_oce(:,:) = - ( 1._wp - at_i_b(:,:) ) * zevap(:,:) * zcptn(:,:) & ! evap at sst
  1244. & + ( tprecip(:,:) - sprecip(:,:) ) * zcptrain(:,:) & ! liquid precip at Tair
  1245. & + sprecip(:,:) * ( 1._wp - zsnw ) * ( zcptsnw (:,:) - rLfus ) ! solid precip at min(Tair,Tsnow)
  1246. qemp_ice(:,:) = sprecip(:,:) * zsnw * ( zcptsnw (:,:) - rLfus ) ! solid precip (only)
  1247. ! --- total solar and non solar fluxes --- !
  1248. qns_tot(:,:) = ( 1._wp - at_i_b(:,:) ) * qns_oce(:,:) + SUM( a_i_b(:,:,:) * qns_ice(:,:,:), dim=3 ) &
  1249. & + qemp_ice(:,:) + qemp_oce(:,:)
  1250. qsr_tot(:,:) = ( 1._wp - at_i_b(:,:) ) * qsr_oce(:,:) + SUM( a_i_b(:,:,:) * qsr_ice(:,:,:), dim=3 )
  1251. ! --- heat content of precip over ice in J/m3 (to be used in 1D-thermo) --- !
  1252. qprec_ice(:,:) = rhos * ( zcptsnw(:,:) - rLfus )
  1253. ! --- heat content of evap over ice in W/m2 (to be used in 1D-thermo) ---
  1254. DO jl = 1, jpl
  1255. qevap_ice(:,:,jl) = 0._wp ! should be -evap_ice(:,:,jl)*( ( Tice - rt0 ) * rcpi * tmask(:,:,1) )
  1256. ! ! But we do not have Tice => consider it at 0degC => evap=0
  1257. END DO
  1258. ! --- shortwave radiation transmitted thru the surface scattering layer (W/m2) --- !
  1259. IF( nn_qtrice == 0 ) THEN
  1260. ! formulation derived from Grenfell and Maykut (1977), where transmission rate
  1261. ! 1) depends on cloudiness
  1262. ! 2) is 0 when there is any snow
  1263. ! 3) tends to 1 for thin ice
  1264. ztri(:,:) = 0.18 * ( 1.0 - cloud_fra(:,:) ) + 0.35 * cloud_fra(:,:) ! surface transmission when hi>10cm
  1265. DO jl = 1, jpl
  1266. WHERE ( phs(:,:,jl) <= 0._wp .AND. phi(:,:,jl) < 0.1_wp ) ! linear decrease from hi=0 to 10cm
  1267. qtr_ice_top(:,:,jl) = qsr_ice(:,:,jl) * ( ztri(:,:) + ( 1._wp - ztri(:,:) ) * ( 1._wp - phi(:,:,jl) * 10._wp ) )
  1268. ELSEWHERE( phs(:,:,jl) <= 0._wp .AND. phi(:,:,jl) >= 0.1_wp ) ! constant (ztri) when hi>10cm
  1269. qtr_ice_top(:,:,jl) = qsr_ice(:,:,jl) * ztri(:,:)
  1270. ELSEWHERE ! zero when hs>0
  1271. qtr_ice_top(:,:,jl) = 0._wp
  1272. END WHERE
  1273. ENDDO
  1274. ELSEIF( nn_qtrice == 1 ) THEN
  1275. ! formulation is derived from the thesis of M. Lebrun (2019).
  1276. ! It represents the best fit using several sets of observations
  1277. ! It comes with snow conductivities adapted to freezing/melting conditions (see icethd_zdf_bl99.F90)
  1278. qtr_ice_top(:,:,:) = 0.3_wp * qsr_ice(:,:,:)
  1279. ENDIF
  1280. !
  1281. IF( iom_use('evap_ao_cea') .OR. iom_use('hflx_evap_cea') ) THEN
  1282. CALL iom_put( 'evap_ao_cea' , zevap(:,:) * ( 1._wp - at_i_b(:,:) ) * tmask(:,:,1) ) ! ice-free oce evap (cell average)
  1283. CALL iom_put( 'hflx_evap_cea', zevap(:,:) * ( 1._wp - at_i_b(:,:) ) * tmask(:,:,1) * zcptn(:,:) ) ! heat flux from evap (cell average)
  1284. ENDIF
  1285. IF( iom_use('rain') .OR. iom_use('rain_ao_cea') .OR. iom_use('hflx_rain_cea') ) THEN
  1286. CALL iom_put( 'rain' , tprecip(:,:) - sprecip(:,:) ) ! liquid precipitation
  1287. CALL iom_put( 'rain_ao_cea' , ( tprecip(:,:) - sprecip(:,:) ) * ( 1._wp - at_i_b(:,:) ) ) ! liquid precipitation over ocean (cell average)
  1288. CALL iom_put( 'hflx_rain_cea', ( tprecip(:,:) - sprecip(:,:) ) * zcptrain(:,:) ) ! heat flux from rain (cell average)
  1289. ENDIF
  1290. IF( iom_use('snow_ao_cea') .OR. iom_use('snow_ai_cea') .OR. &
  1291. & iom_use('hflx_snow_cea') .OR. iom_use('hflx_snow_ao_cea') .OR. iom_use('hflx_snow_ai_cea') ) THEN
  1292. CALL iom_put( 'snow_ao_cea' , sprecip(:,:) * ( 1._wp - zsnw(:,:) ) ) ! Snow over ice-free ocean (cell average)
  1293. CALL iom_put( 'snow_ai_cea' , sprecip(:,:) * zsnw(:,:) ) ! Snow over sea-ice (cell average)
  1294. CALL iom_put( 'hflx_snow_cea' , sprecip(:,:) * ( zcptsnw(:,:) - rLfus ) ) ! heat flux from snow (cell average)
  1295. CALL iom_put( 'hflx_snow_ao_cea', sprecip(:,:) * ( zcptsnw(:,:) - rLfus ) * ( 1._wp - zsnw(:,:) ) ) ! heat flux from snow (over ocean)
  1296. CALL iom_put( 'hflx_snow_ai_cea', sprecip(:,:) * ( zcptsnw(:,:) - rLfus ) * zsnw(:,:) ) ! heat flux from snow (over ice)
  1297. ENDIF
  1298. IF( iom_use('hflx_prec_cea') ) THEN ! heat flux from precip (cell average)
  1299. CALL iom_put('hflx_prec_cea' , sprecip(:,:) * ( zcptsnw (:,:) - rLfus ) &
  1300. & + ( tprecip(:,:) - sprecip(:,:) ) * zcptrain(:,:) )
  1301. ENDIF
  1302. IF( iom_use('subl_ai_cea') .OR. iom_use('hflx_subl_cea') ) THEN
  1303. CALL iom_put( 'subl_ai_cea' , SUM( a_i_b(:,:,:) * evap_ice(:,:,:), dim=3 ) * tmask(:,:,1) ) ! Sublimation over sea-ice (cell average)
  1304. CALL iom_put( 'hflx_subl_cea', SUM( a_i_b(:,:,:) * qevap_ice(:,:,:), dim=3 ) * tmask(:,:,1) ) ! Heat flux from sublimation (cell average)
  1305. ENDIF
  1306. !
  1307. IF(sn_cfctl%l_prtctl) THEN
  1308. CALL prt_ctl(tab3d_1=qla_ice , clinfo1=' blk_ice: qla_ice : ', tab3d_2=z_qsb , clinfo2=' z_qsb : ', kdim=jpl)
  1309. CALL prt_ctl(tab3d_1=z_qlw , clinfo1=' blk_ice: z_qlw : ', tab3d_2=dqla_ice, clinfo2=' dqla_ice : ', kdim=jpl)
  1310. CALL prt_ctl(tab3d_1=z_dqsb , clinfo1=' blk_ice: z_dqsb : ', tab3d_2=z_dqlw , clinfo2=' z_dqlw : ', kdim=jpl)
  1311. CALL prt_ctl(tab3d_1=dqns_ice, clinfo1=' blk_ice: dqns_ice : ', tab3d_2=qsr_ice , clinfo2=' qsr_ice : ', kdim=jpl)
  1312. CALL prt_ctl(tab3d_1=ptsu , clinfo1=' blk_ice: ptsu : ', tab3d_2=qns_ice , clinfo2=' qns_ice : ', kdim=jpl)
  1313. CALL prt_ctl(tab2d_1=tprecip , clinfo1=' blk_ice: tprecip : ', tab2d_2=sprecip , clinfo2=' sprecip : ')
  1314. ENDIF
  1315. !#LB:
  1316. ! air-ice heat flux components that are not written from ice_stp()@icestp.F90:
  1317. IF( iom_use('qla_ice') ) CALL iom_put( 'qla_ice', SUM( - qla_ice * a_i_b, dim=3 ) ) !#LB: sign consistent with what's done for ocean
  1318. IF( iom_use('qsb_ice') ) CALL iom_put( 'qsb_ice', SUM( - z_qsb * a_i_b, dim=3 ) ) !#LB: ==> negative => loss of heat for sea-ice
  1319. IF( iom_use('qlw_ice') ) CALL iom_put( 'qlw_ice', SUM( z_qlw * a_i_b, dim=3 ) )
  1320. !#LB.
  1321. END SUBROUTINE blk_ice_2
  1322. SUBROUTINE blk_ice_qcn( ld_virtual_itd, ptsu, ptb, phs, phi )
  1323. !!---------------------------------------------------------------------
  1324. !! *** ROUTINE blk_ice_qcn ***
  1325. !!
  1326. !! ** Purpose : Compute surface temperature and snow/ice conduction flux
  1327. !! to force sea ice / snow thermodynamics
  1328. !! in the case conduction flux is emulated
  1329. !!
  1330. !! ** Method : compute surface energy balance assuming neglecting heat storage
  1331. !! following the 0-layer Semtner (1976) approach
  1332. !!
  1333. !! ** Outputs : - ptsu : sea-ice / snow surface temperature (K)
  1334. !! - qcn_ice : surface inner conduction flux (W/m2)
  1335. !!
  1336. !!---------------------------------------------------------------------
  1337. LOGICAL , INTENT(in ) :: ld_virtual_itd ! single-category option
  1338. REAL(wp), DIMENSION(:,:,:), INTENT(inout) :: ptsu ! sea ice / snow surface temperature
  1339. REAL(wp), DIMENSION(:,:) , INTENT(in ) :: ptb ! sea ice base temperature
  1340. REAL(wp), DIMENSION(:,:,:), INTENT(in ) :: phs ! snow thickness
  1341. REAL(wp), DIMENSION(:,:,:), INTENT(in ) :: phi ! sea ice thickness
  1342. !
  1343. INTEGER , PARAMETER :: nit = 10 ! number of iterations
  1344. REAL(wp), PARAMETER :: zepsilon = 0.1_wp ! characteristic thickness for enhanced conduction
  1345. !
  1346. INTEGER :: ji, jj, jl ! dummy loop indices
  1347. INTEGER :: iter ! local integer
  1348. REAL(wp) :: zfac, zfac2, zfac3 ! local scalars
  1349. REAL(wp) :: zkeff_h, ztsu, ztsu0 !
  1350. REAL(wp) :: zqc, zqnet !
  1351. REAL(wp) :: zhe, zqa0 !
  1352. REAL(wp), DIMENSION(jpi,jpj,jpl) :: zgfac ! enhanced conduction factor
  1353. !!---------------------------------------------------------------------
  1354. ! -------------------------------------!
  1355. ! I Enhanced conduction factor !
  1356. ! -------------------------------------!
  1357. ! Emulates the enhancement of conduction by unresolved thin ice (ld_virtual_itd = T)
  1358. ! Fichefet and Morales Maqueda, JGR 1997
  1359. !
  1360. zgfac(:,:,:) = 1._wp
  1361. IF( ld_virtual_itd ) THEN
  1362. !
  1363. zfac = 1._wp / ( rn_cnd_s + rcnd_i )
  1364. zfac2 = EXP(1._wp) * 0.5_wp * zepsilon
  1365. zfac3 = 2._wp / zepsilon
  1366. !
  1367. DO jl = 1, jpl
  1368. DO_2D( nn_hls, nn_hls, nn_hls, nn_hls )
  1369. zhe = ( rn_cnd_s * phi(ji,jj,jl) + rcnd_i * phs(ji,jj,jl) ) * zfac ! Effective thickness
  1370. IF( zhe >= zfac2 ) zgfac(ji,jj,jl) = MIN( 2._wp, 0.5_wp * ( 1._wp + LOG( zhe * zfac3 ) ) ) ! Enhanced conduction factor
  1371. END_2D
  1372. END DO
  1373. !
  1374. ENDIF
  1375. ! -------------------------------------------------------------!
  1376. ! II Surface temperature and conduction flux !
  1377. ! -------------------------------------------------------------!
  1378. !
  1379. zfac = rcnd_i * rn_cnd_s
  1380. !
  1381. DO jl = 1, jpl
  1382. DO_2D( nn_hls, nn_hls, nn_hls, nn_hls )
  1383. !
  1384. zkeff_h = zfac * zgfac(ji,jj,jl) / & ! Effective conductivity of the snow-ice system divided by thickness
  1385. & ( rcnd_i * phs(ji,jj,jl) + rn_cnd_s * MAX( 0.01, phi(ji,jj,jl) ) )
  1386. ztsu = ptsu(ji,jj,jl) ! Store current iteration temperature
  1387. ztsu0 = ptsu(ji,jj,jl) ! Store initial surface temperature
  1388. zqa0 = qsr_ice(ji,jj,jl) - qtr_ice_top(ji,jj,jl) + qns_ice(ji,jj,jl) ! Net initial atmospheric heat flux
  1389. !
  1390. DO iter = 1, nit ! --- Iterative loop
  1391. zqc = zkeff_h * ( ztsu - ptb(ji,jj) ) ! Conduction heat flux through snow-ice system (>0 downwards)
  1392. zqnet = zqa0 + dqns_ice(ji,jj,jl) * ( ztsu - ptsu(ji,jj,jl) ) - zqc ! Surface energy budget
  1393. ztsu = ztsu - zqnet / ( dqns_ice(ji,jj,jl) - zkeff_h ) ! Temperature update
  1394. END DO
  1395. !
  1396. ptsu (ji,jj,jl) = MIN( rt0, ztsu )
  1397. qcn_ice(ji,jj,jl) = zkeff_h * ( ptsu(ji,jj,jl) - ptb(ji,jj) )
  1398. qns_ice(ji,jj,jl) = qns_ice(ji,jj,jl) + dqns_ice(ji,jj,jl) * ( ptsu(ji,jj,jl) - ztsu0 )
  1399. 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) ) &
  1400. & * MAX( 0._wp , SIGN( 1._wp, ptsu(ji,jj,jl) - rt0 ) )
  1401. ! --- Diagnose the heat loss due to changing non-solar flux (as in icethd_zdf_bl99) --- !
  1402. 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)
  1403. END_2D
  1404. !
  1405. END DO
  1406. !
  1407. END SUBROUTINE blk_ice_qcn
  1408. #endif
  1409. !!======================================================================
  1410. END MODULE sbcblk