zdfddm.F90 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. MODULE zdfddm
  2. !!======================================================================
  3. !! *** MODULE zdfddm ***
  4. !! Ocean physics : double diffusion mixing parameterization
  5. !!======================================================================
  6. !! History : OPA ! 2000-08 (G. Madec) double diffusive mixing
  7. !! NEMO 1.0 ! 2002-06 (G. Madec) F90: Free form and module
  8. !! 3.3 ! 2010-10 (C. Ethe, G. Madec) reorganisation of initialisation phase
  9. !! 3.6 ! 2013-04 (G. Madec, F. Roquet) zrau compute locally using interpolation of alpha & beta
  10. !!----------------------------------------------------------------------
  11. #if defined key_zdfddm || defined key_esopa
  12. !!----------------------------------------------------------------------
  13. !! 'key_zdfddm' : double diffusion
  14. !!----------------------------------------------------------------------
  15. !! zdf_ddm : compute the Ks for salinity
  16. !! zdf_ddm_init : read namelist and control the parameters
  17. !!----------------------------------------------------------------------
  18. USE oce ! ocean dynamics and tracers variables
  19. USE dom_oce ! ocean space and time domain variables
  20. USE zdf_oce ! ocean vertical physics variables
  21. USE eosbn2 ! equation of state
  22. !
  23. USE in_out_manager ! I/O manager
  24. USE lbclnk ! ocean lateral boundary conditions (or mpp link)
  25. USE prtctl ! Print control
  26. USE lib_mpp ! MPP library
  27. USE wrk_nemo ! work arrays
  28. USE timing ! Timing
  29. IMPLICIT NONE
  30. PRIVATE
  31. PUBLIC zdf_ddm ! called by step.F90
  32. PUBLIC zdf_ddm_init ! called by opa.F90
  33. PUBLIC zdf_ddm_alloc ! called by nemogcm.F90
  34. LOGICAL , PUBLIC, PARAMETER :: lk_zdfddm = .TRUE. !: double diffusive mixing flag
  35. REAL(wp), PUBLIC, SAVE, ALLOCATABLE, DIMENSION(:,:,:) :: avs !: salinity vertical diffusivity coeff. at w-point
  36. ! !!* Namelist namzdf_ddm : double diffusive mixing *
  37. REAL(wp) :: rn_avts ! maximum value of avs for salt fingering
  38. REAL(wp) :: rn_hsbfr ! heat/salt buoyancy flux ratio
  39. !! * Substitutions
  40. # include "domzgr_substitute.h90"
  41. # include "vectopt_loop_substitute.h90"
  42. !!----------------------------------------------------------------------
  43. !! NEMO/OPA 3.7 , NEMO Consortium (2014)
  44. !! $Id: zdfddm.F90 4990 2014-12-15 16:42:49Z timgraham $
  45. !! Software governed by the CeCILL licence (NEMOGCM/NEMO_CeCILL.txt)
  46. !!----------------------------------------------------------------------
  47. CONTAINS
  48. INTEGER FUNCTION zdf_ddm_alloc()
  49. !!----------------------------------------------------------------------
  50. !! *** ROUTINE zdf_ddm_alloc ***
  51. !!----------------------------------------------------------------------
  52. ALLOCATE( avs(jpi,jpj,jpk) , STAT= zdf_ddm_alloc )
  53. IF( lk_mpp ) CALL mpp_sum ( zdf_ddm_alloc )
  54. IF( zdf_ddm_alloc /= 0 ) CALL ctl_warn('zdf_ddm_alloc: failed to allocate arrays')
  55. END FUNCTION zdf_ddm_alloc
  56. SUBROUTINE zdf_ddm( kt )
  57. !!----------------------------------------------------------------------
  58. !! *** ROUTINE zdf_ddm ***
  59. !!
  60. !! ** Purpose : Add to the vertical eddy diffusivity coefficient the
  61. !! effect of salt fingering and diffusive convection.
  62. !!
  63. !! ** Method : Diapycnal mixing is increased in case of double
  64. !! diffusive mixing (i.e. salt fingering and diffusive layering)
  65. !! following Merryfield et al. (1999). The rate of double diffusive
  66. !! mixing depend on the buoyancy ratio (R=alpha/beta dk[T]/dk[S]):
  67. !! * salt fingering (Schmitt 1981):
  68. !! for R > 1 and rn2 > 0 : zavfs = rn_avts / ( 1 + (R/rn_hsbfr)^6 )
  69. !! for R > 1 and rn2 > 0 : zavfs = O
  70. !! otherwise : zavft = 0.7 zavs / R
  71. !! * diffusive layering (Federov 1988):
  72. !! for 0< R < 1 and N^2 > 0 : zavdt = 1.3635e-6 * exp( 4.6 exp(-0.54 (1/R-1) ) )
  73. !! otherwise : zavdt = 0
  74. !! for .5 < R < 1 and N^2 > 0 : zavds = zavdt (1.885 R -0.85)
  75. !! for 0 < R <.5 and N^2 > 0 : zavds = zavdt 0.15 R
  76. !! otherwise : zavds = 0
  77. !! * update the eddy diffusivity:
  78. !! avt = avt + zavft + zavdt
  79. !! avs = avs + zavfs + zavds
  80. !! avmu, avmv are required to remain at least above avt and avs.
  81. !!
  82. !! ** Action : avt, avs : updated vertical eddy diffusivity coef. for T & S
  83. !!
  84. !! References : Merryfield et al., JPO, 29, 1124-1142, 1999.
  85. !!----------------------------------------------------------------------
  86. INTEGER, INTENT(in) :: kt ! ocean time-step indexocean time step
  87. !
  88. INTEGER :: ji, jj , jk ! dummy loop indices
  89. REAL(wp) :: zaw, zbw, zrw ! local scalars
  90. REAL(wp) :: zdt, zds
  91. REAL(wp) :: zinr, zrr ! - -
  92. REAL(wp) :: zavft, zavfs ! - -
  93. REAL(wp) :: zavdt, zavds ! - -
  94. REAL(wp), POINTER, DIMENSION(:,:) :: zrau, zmsks, zmskf, zmskd1, zmskd2, zmskd3
  95. !!----------------------------------------------------------------------
  96. !
  97. IF( nn_timing == 1 ) CALL timing_start('zdf_ddm')
  98. !
  99. CALL wrk_alloc( jpi,jpj, zrau, zmsks, zmskf, zmskd1, zmskd2, zmskd3 )
  100. !
  101. ! ! ===============
  102. DO jk = 2, jpkm1 ! Horizontal slab
  103. ! ! ===============
  104. ! Define the mask
  105. ! ---------------
  106. DO jj = 1, jpj ! R=zrau = (alpha / beta) (dk[t] / dk[s])
  107. DO ji = 1, jpi
  108. zrw = ( fsdepw(ji,jj,jk ) - fsdept(ji,jj,jk) ) &
  109. & / ( fsdept(ji,jj,jk-1) - fsdept(ji,jj,jk) )
  110. !
  111. zaw = ( rab_n(ji,jj,jk,jp_tem) * (1. - zrw) + rab_n(ji,jj,jk-1,jp_tem) * zrw ) &
  112. & * tmask(ji,jj,jk) * tmask(ji,jj,jk-1)
  113. zbw = ( rab_n(ji,jj,jk,jp_sal) * (1. - zrw) + rab_n(ji,jj,jk-1,jp_sal) * zrw ) &
  114. & * tmask(ji,jj,jk) * tmask(ji,jj,jk-1)
  115. !
  116. zdt = zaw * ( tsn(ji,jj,jk-1,jp_tem) - tsn(ji,jj,jk,jp_tem) )
  117. zds = zbw * ( tsn(ji,jj,jk-1,jp_sal) - tsn(ji,jj,jk,jp_sal) )
  118. IF( ABS( zds) <= 1.e-20_wp ) zds = 1.e-20_wp
  119. zrau(ji,jj) = MAX( 1.e-20, zdt / zds ) ! only retains positive value of zrau
  120. END DO
  121. END DO
  122. DO jj = 1, jpj ! indicators:
  123. DO ji = 1, jpi
  124. ! stability indicator: msks=1 if rn2>0; 0 elsewhere
  125. IF( rn2(ji,jj,jk) + 1.e-12 <= 0. ) THEN ; zmsks(ji,jj) = 0._wp
  126. ELSE ; zmsks(ji,jj) = 1._wp
  127. ENDIF
  128. ! salt fingering indicator: msksf=1 if R>1; 0 elsewhere
  129. IF( zrau(ji,jj) <= 1. ) THEN ; zmskf(ji,jj) = 0._wp
  130. ELSE ; zmskf(ji,jj) = 1._wp
  131. ENDIF
  132. ! diffusive layering indicators:
  133. ! ! mskdl1=1 if 0< R <1; 0 elsewhere
  134. IF( zrau(ji,jj) >= 1. ) THEN ; zmskd1(ji,jj) = 0._wp
  135. ELSE ; zmskd1(ji,jj) = 1._wp
  136. ENDIF
  137. ! ! mskdl2=1 if 0< R <0.5; 0 elsewhere
  138. IF( zrau(ji,jj) >= 0.5 ) THEN ; zmskd2(ji,jj) = 0._wp
  139. ELSE ; zmskd2(ji,jj) = 1._wp
  140. ENDIF
  141. ! mskdl3=1 if 0.5< R <1; 0 elsewhere
  142. IF( zrau(ji,jj) <= 0.5 .OR. zrau(ji,jj) >= 1. ) THEN ; zmskd3(ji,jj) = 0._wp
  143. ELSE ; zmskd3(ji,jj) = 1._wp
  144. ENDIF
  145. END DO
  146. END DO
  147. ! mask zmsk in order to have avt and avs masked
  148. zmsks(:,:) = zmsks(:,:) * wmask(:,:,jk)
  149. ! Update avt and avs
  150. ! ------------------
  151. ! Constant eddy coefficient: reset to the background value
  152. !CDIR NOVERRCHK
  153. DO jj = 1, jpj
  154. !CDIR NOVERRCHK
  155. DO ji = 1, jpi
  156. zinr = 1._wp / zrau(ji,jj)
  157. ! salt fingering
  158. zrr = zrau(ji,jj) / rn_hsbfr
  159. zrr = zrr * zrr
  160. zavfs = rn_avts / ( 1 + zrr*zrr*zrr ) * zmsks(ji,jj) * zmskf(ji,jj)
  161. zavft = 0.7 * zavfs * zinr
  162. ! diffusive layering
  163. zavdt = 1.3635e-6 * EXP( 4.6 * EXP( -0.54*(zinr-1.) ) ) * zmsks(ji,jj) * zmskd1(ji,jj)
  164. zavds = zavdt * zmsks(ji,jj) * ( ( 1.85 * zrau(ji,jj) - 0.85 ) * zmskd3(ji,jj) &
  165. & + 0.15 * zrau(ji,jj) * zmskd2(ji,jj) )
  166. ! add to the eddy viscosity coef. previously computed
  167. # if defined key_zdftmx_new
  168. ! key_zdftmx_new: New internal wave-driven param: use avs value computed by zdftmx
  169. avs (ji,jj,jk) = avs(ji,jj,jk) + zavfs + zavds
  170. # else
  171. avs (ji,jj,jk) = avt(ji,jj,jk) + zavfs + zavds
  172. # endif
  173. avt (ji,jj,jk) = avt(ji,jj,jk) + zavft + zavdt
  174. avm (ji,jj,jk) = avm(ji,jj,jk) + MAX( zavft + zavdt, zavfs + zavds )
  175. END DO
  176. END DO
  177. ! Increase avmu, avmv if necessary
  178. ! --------------------------------
  179. !!gm to be changed following the definition of avm.
  180. DO jj = 1, jpjm1
  181. DO ji = 1, fs_jpim1 ! vector opt.
  182. avmu(ji,jj,jk) = MAX( avmu(ji,jj,jk), &
  183. & avt(ji,jj,jk), avt(ji+1,jj,jk), &
  184. & avs(ji,jj,jk), avs(ji+1,jj,jk) ) * wumask(ji,jj,jk)
  185. avmv(ji,jj,jk) = MAX( avmv(ji,jj,jk), &
  186. & avt(ji,jj,jk), avt(ji,jj+1,jk), &
  187. & avs(ji,jj,jk), avs(ji,jj+1,jk) ) * wvmask(ji,jj,jk)
  188. END DO
  189. END DO
  190. ! ! ===============
  191. END DO ! End of slab
  192. ! ! ===============
  193. !
  194. CALL lbc_lnk( avt , 'W', 1._wp ) ! Lateral boundary conditions (unchanged sign)
  195. CALL lbc_lnk( avs , 'W', 1._wp )
  196. CALL lbc_lnk( avm , 'W', 1._wp )
  197. CALL lbc_lnk( avmu, 'U', 1._wp )
  198. CALL lbc_lnk( avmv, 'V', 1._wp )
  199. IF(ln_ctl) THEN
  200. CALL prt_ctl(tab3d_1=avt , clinfo1=' ddm - t: ', tab3d_2=avs , clinfo2=' s: ', ovlap=1, kdim=jpk)
  201. CALL prt_ctl(tab3d_1=avmu, clinfo1=' ddm - u: ', mask1=umask, &
  202. & tab3d_2=avmv, clinfo2= ' v: ', mask2=vmask, ovlap=1, kdim=jpk)
  203. ENDIF
  204. !
  205. CALL wrk_dealloc( jpi,jpj, zrau, zmsks, zmskf, zmskd1, zmskd2, zmskd3 )
  206. !
  207. IF( nn_timing == 1 ) CALL timing_stop('zdf_ddm')
  208. !
  209. END SUBROUTINE zdf_ddm
  210. SUBROUTINE zdf_ddm_init
  211. !!----------------------------------------------------------------------
  212. !! *** ROUTINE zdf_ddm_init ***
  213. !!
  214. !! ** Purpose : Initialization of double diffusion mixing scheme
  215. !!
  216. !! ** Method : Read the namzdf_ddm namelist and check the parameter values
  217. !! called by zdf_ddm at the first timestep (nit000)
  218. !!----------------------------------------------------------------------
  219. INTEGER :: ios ! local integer
  220. !!
  221. NAMELIST/namzdf_ddm/ rn_avts, rn_hsbfr
  222. !!----------------------------------------------------------------------
  223. !
  224. REWIND( numnam_ref ) ! Namelist namzdf_ddm in reference namelist : Double diffusion mixing scheme
  225. READ ( numnam_ref, namzdf_ddm, IOSTAT = ios, ERR = 901)
  226. 901 IF( ios /= 0 ) CALL ctl_nam ( ios , 'namzdf_ddm in reference namelist', lwp )
  227. REWIND( numnam_cfg ) ! Namelist namzdf_ddm in configuration namelist : Double diffusion mixing scheme
  228. READ ( numnam_cfg, namzdf_ddm, IOSTAT = ios, ERR = 902 )
  229. 902 IF( ios /= 0 ) CALL ctl_nam ( ios , 'namzdf_ddm in configuration namelist', lwp )
  230. IF(lwm) WRITE ( numond, namzdf_ddm )
  231. !
  232. IF(lwp) THEN ! Parameter print
  233. WRITE(numout,*)
  234. WRITE(numout,*) 'zdf_ddm : double diffusive mixing'
  235. WRITE(numout,*) '~~~~~~~'
  236. WRITE(numout,*) ' Namelist namzdf_ddm : set dd mixing parameter'
  237. WRITE(numout,*) ' maximum avs for dd mixing rn_avts = ', rn_avts
  238. WRITE(numout,*) ' heat/salt buoyancy flux ratio rn_hsbfr = ', rn_hsbfr
  239. ENDIF
  240. !
  241. ! ! allocate zdfddm arrays
  242. IF( zdf_ddm_alloc() /= 0 ) CALL ctl_stop( 'STOP', 'zdf_ddm_init : unable to allocate arrays' )
  243. ! ! initialization to masked Kz
  244. avs(:,:,:) = rn_avt0 * wmask(:,:,:)
  245. !
  246. END SUBROUTINE zdf_ddm_init
  247. #else
  248. !!----------------------------------------------------------------------
  249. !! Default option : Dummy module No double diffusion
  250. !!----------------------------------------------------------------------
  251. LOGICAL, PUBLIC, PARAMETER :: lk_zdfddm = .FALSE. !: double diffusion flag
  252. CONTAINS
  253. SUBROUTINE zdf_ddm( kt ) ! Dummy routine
  254. WRITE(*,*) 'zdf_ddm: You should not have seen this print! error?', kt
  255. END SUBROUTINE zdf_ddm
  256. SUBROUTINE zdf_ddm_init ! Dummy routine
  257. END SUBROUTINE zdf_ddm_init
  258. #endif
  259. !!======================================================================
  260. END MODULE zdfddm