diahth.F90 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  1. MODULE diahth
  2. !!======================================================================
  3. !! *** MODULE diahth ***
  4. !! Ocean diagnostics: thermocline and 20 degree depth
  5. !!======================================================================
  6. !! History : OPA ! 1994-09 (J.-P. Boulanger) Original code
  7. !! ! 1996-11 (E. Guilyardi) OPA8
  8. !! ! 1997-08 (G. Madec) optimization
  9. !! ! 1999-07 (E. Guilyardi) hd28 + heat content
  10. !! 8.5 ! 2002-06 (G. Madec) F90: Free form and module
  11. !! NEMO 3.2 ! 2009-07 (S. Masson) hc300 bugfix + cleaning + add new diag
  12. !! NEMO 3.6 ! 2015_07 (J.F. Gueremy) hd26
  13. !! NEMO 3.6 ! 2016_03 (M. Chevallier ) hc700 + hc2000
  14. !! NEMO 3.6 ! 2017_09 (C. Ethe ) taking vvl into account properly + simplyfing + cleaning
  15. !!----------------------------------------------------------------------
  16. #if defined key_diahth || defined key_esopa
  17. !!----------------------------------------------------------------------
  18. !! 'key_diahth' : thermocline depth diag.
  19. !!----------------------------------------------------------------------
  20. !! dia_hth : Compute varius diagnostics associated with the thermal vertical structure
  21. !!----------------------------------------------------------------------
  22. USE oce ! ocean dynamics and tracers
  23. USE dom_oce ! ocean space and time domain
  24. USE phycst ! physical constants
  25. USE in_out_manager ! I/O manager
  26. USE lib_mpp ! MPP library
  27. USE iom ! I/O library
  28. USE timing ! preformance summary
  29. IMPLICIT NONE
  30. PRIVATE
  31. PUBLIC dia_hth ! routine called by step.F90
  32. PUBLIC dia_hth_alloc ! routine called by nemogcm.F90
  33. LOGICAL , PUBLIC, PARAMETER :: lk_diahth = .TRUE. !: thermocline-20d depths flag
  34. ! note: following variables should move to local variables once iom_put is always used
  35. REAL(wp), PUBLIC, ALLOCATABLE, SAVE, DIMENSION(:,:) :: hth !: depth of the max vertical temperature gradient [m]
  36. REAL(wp), PUBLIC, ALLOCATABLE, SAVE, DIMENSION(:,:) :: hd20 !: depth of 20 C isotherm [m]
  37. REAL(wp), PUBLIC, ALLOCATABLE, SAVE, DIMENSION(:,:) :: hd26 !: depth of 26 C isotherm
  38. REAL(wp), PUBLIC, ALLOCATABLE, SAVE, DIMENSION(:,:) :: hd28 !: depth of 28 C isotherm [m]
  39. REAL(wp), PUBLIC, ALLOCATABLE, SAVE, DIMENSION(:,:) :: htc3 !: heat content of first 300 m [J/m2]
  40. REAL(wp), ALLOCATABLE, SAVE, DIMENSION(:,:) :: htc7 !: heat content of first 700 m [J/m2]
  41. REAL(wp), ALLOCATABLE, SAVE, DIMENSION(:,:) :: htc2 !: heat content of first 2000 m [J/m2]
  42. !! * Substitutions
  43. # include "domzgr_substitute.h90"
  44. !!----------------------------------------------------------------------
  45. !! NEMO/OPA 4.0 , NEMO Consortium (2011)
  46. !! $Id$
  47. !! Software governed by the CeCILL licence (NEMOGCM/NEMO_CeCILL.txt)
  48. !!----------------------------------------------------------------------
  49. CONTAINS
  50. FUNCTION dia_hth_alloc()
  51. !!---------------------------------------------------------------------
  52. INTEGER :: dia_hth_alloc
  53. !!---------------------------------------------------------------------
  54. !
  55. ALLOCATE(hth(jpi,jpj), hd20(jpi,jpj), hd26(jpi,jpj), hd28(jpi,jpj), htc3(jpi,jpj), &
  56. & htc7(jpi,jpj), htc2(jpi,jpj), STAT=dia_hth_alloc)
  57. !
  58. IF( lk_mpp ) CALL mpp_sum ( dia_hth_alloc )
  59. IF(dia_hth_alloc /= 0) CALL ctl_warn('dia_hth_alloc: failed to allocate arrays.')
  60. !
  61. END FUNCTION dia_hth_alloc
  62. SUBROUTINE dia_hth( kt )
  63. !!---------------------------------------------------------------------
  64. !! *** ROUTINE dia_hth ***
  65. !!
  66. !! ** Purpose : Computes
  67. !! the mixing layer depth (turbocline): avt = 5.e-4
  68. !! the depth of strongest vertical temperature gradient
  69. !! the mixed layer depth with density criteria: rho = rho(10m or surf) + 0.03(or 0.01)
  70. !! the mixed layer depth with temperature criteria: abs( tn - tn(10m) ) = 0.2
  71. !! the top of the thermochine: tn = tn(10m) - ztem2
  72. !! the pycnocline depth with density criteria equivalent to a temperature variation
  73. !! rho = rho10m + (dr/dT)(T,S,10m)*(-0.2 degC)
  74. !! the barrier layer thickness
  75. !! the maximal verical inversion of temperature and its depth max( 0, max of tn - tn(10m) )
  76. !! the depth of the 20 degree isotherm (linear interpolation)
  77. !! the depth of the 26 degree isotherm (linear interpolation)
  78. !! the depth of the 28 degree isotherm (linear interpolation)
  79. !! the heat content of first 300 m (+ 700 m and 2000 m for CMIP6 :MCH)
  80. !!
  81. !! ** Method :
  82. !!-------------------------------------------------------------------
  83. INTEGER, INTENT( in ) :: kt ! ocean time-step index
  84. !!
  85. INTEGER :: ji, jj, jk ! dummy loop arguments
  86. REAL(wp) :: zrho3 = 0.03_wp ! density criterion for mixed layer depth
  87. REAL(wp) :: zrho1 = 0.01_wp ! density criterion for mixed layer depth
  88. REAL(wp) :: ztem2 = 0.2_wp ! temperature criterion for mixed layer depth
  89. REAL(wp) :: zztmp, zzdep ! temporary scalars inside do loop
  90. REAL(wp) :: zu, zv, zw, zut, zvt ! temporary workspace
  91. REAL(wp), DIMENSION(jpi,jpj) :: zabs2 ! MLD: abs( tn - tn(10m) ) = ztem2
  92. REAL(wp), DIMENSION(jpi,jpj) :: ztm2 ! Top of thermocline: tn = tn(10m) - ztem2
  93. REAL(wp), DIMENSION(jpi,jpj) :: zrho10_3 ! MLD: rho = rho10m + zrho3
  94. REAL(wp), DIMENSION(jpi,jpj) :: zpycn ! pycnocline: rho = rho10m + (dr/dT)(T,S,10m)*(-0.2 degC)
  95. REAL(wp), DIMENSION(jpi,jpj) :: ztinv ! max of temperature inversion
  96. REAL(wp), DIMENSION(jpi,jpj) :: zdepinv ! depth of temperature inversion
  97. REAL(wp), DIMENSION(jpi,jpj) :: zrho0_3 ! MLD rho = rho(surf) = 0.03
  98. REAL(wp), DIMENSION(jpi,jpj) :: zrho0_1 ! MLD rho = rho(surf) = 0.01
  99. REAL(wp), DIMENSION(jpi,jpj) :: zmaxdzT ! max of dT/dz
  100. REAL(wp), DIMENSION(jpi,jpj) :: zdelr ! delta rho equivalent to deltaT = 0.2
  101. REAL(wp), DIMENSION(jpi,jpj,jpk) :: ztemp ! temperature
  102. !!----------------------------------------------------------------------
  103. IF( nn_timing == 1 ) CALL timing_start('dia_hth')
  104. IF( kt == nit000 ) THEN
  105. ! ! allocate dia_hth array
  106. IF( dia_hth_alloc() /= 0 ) CALL ctl_stop( 'STOP', 'lim_sbc_init : unable to allocate standard arrays' )
  107. IF(lwp) WRITE(numout,*)
  108. IF(lwp) WRITE(numout,*) 'dia_hth : diagnostics of the thermocline depth'
  109. IF(lwp) WRITE(numout,*) '~~~~~~~ '
  110. IF(lwp) WRITE(numout,*)
  111. !
  112. ENDIF
  113. ! initialization
  114. ztinv (:,:) = 0._wp
  115. zdepinv(:,:) = 0._wp
  116. zmaxdzT(:,:) = 0._wp
  117. DO jj = 1, jpj
  118. DO ji = 1, jpi
  119. zztmp = bathy(ji,jj)
  120. hth (ji,jj) = zztmp
  121. zabs2 (ji,jj) = zztmp
  122. ztm2 (ji,jj) = zztmp
  123. zrho10_3(ji,jj) = zztmp
  124. zpycn (ji,jj) = zztmp
  125. END DO
  126. END DO
  127. IF( nla10 > 1 ) THEN
  128. DO jj = 1, jpj
  129. DO ji = 1, jpi
  130. zztmp = bathy(ji,jj)
  131. zrho0_3(ji,jj) = zztmp
  132. zrho0_1(ji,jj) = zztmp
  133. END DO
  134. END DO
  135. ENDIF
  136. ! Preliminary computation
  137. ! computation of zdelr = (dr/dT)(T,S,10m)*(-0.2 degC)
  138. DO jj = 1, jpj
  139. DO ji = 1, jpi
  140. IF( tmask(ji,jj,nla10) == 1. ) THEN
  141. zu = 1779.50 + 11.250 * tsn(ji,jj,nla10,jp_tem) - 3.80 * tsn(ji,jj,nla10,jp_sal) &
  142. & - 0.0745 * tsn(ji,jj,nla10,jp_tem) * tsn(ji,jj,nla10,jp_tem) &
  143. & - 0.0100 * tsn(ji,jj,nla10,jp_tem) * tsn(ji,jj,nla10,jp_sal)
  144. zv = 5891.00 + 38.000 * tsn(ji,jj,nla10,jp_tem) + 3.00 * tsn(ji,jj,nla10,jp_sal) &
  145. & - 0.3750 * tsn(ji,jj,nla10,jp_tem) * tsn(ji,jj,nla10,jp_tem)
  146. zut = 11.25 - 0.149 * tsn(ji,jj,nla10,jp_tem) - 0.01 * tsn(ji,jj,nla10,jp_sal)
  147. zvt = 38.00 - 0.750 * tsn(ji,jj,nla10,jp_tem)
  148. zw = (zu + 0.698*zv) * (zu + 0.698*zv)
  149. zdelr(ji,jj) = ztem2 * (1000.*(zut*zv - zvt*zu)/zw)
  150. ELSE
  151. zdelr(ji,jj) = 0._wp
  152. ENDIF
  153. END DO
  154. END DO
  155. ! ------------------------------------------------------------- !
  156. ! thermocline depth: strongest vertical gradient of temperature !
  157. ! turbocline depth (mixing layer depth): avt = zavt5 !
  158. ! MLD: rho = rho(1) + zrho3 !
  159. ! MLD: rho = rho(1) + zrho1 !
  160. ! ------------------------------------------------------------- !
  161. DO jk = jpkm1, 2, -1 ! loop from bottom to 2
  162. DO jj = 1, jpj
  163. DO ji = 1, jpi
  164. !
  165. zzdep = fsdepw(ji,jj,jk)
  166. zztmp = ( tsn(ji,jj,jk-1,jp_tem) - tsn(ji,jj,jk,jp_tem) ) / zzdep * tmask(ji,jj,jk) ! vertical gradient of temperature (dT/dz)
  167. zzdep = zzdep * tmask(ji,jj,1)
  168. IF( zztmp > zmaxdzT(ji,jj) ) THEN
  169. zmaxdzT(ji,jj) = zztmp ; hth (ji,jj) = zzdep ! max and depth of dT/dz
  170. ENDIF
  171. IF( nla10 > 1 ) THEN
  172. zztmp = rhop(ji,jj,jk) - rhop(ji,jj,1) ! delta rho(1)
  173. IF( zztmp > zrho3 ) zrho0_3(ji,jj) = zzdep ! > 0.03
  174. IF( zztmp > zrho1 ) zrho0_1(ji,jj) = zzdep ! > 0.01
  175. ENDIF
  176. END DO
  177. END DO
  178. END DO
  179. CALL iom_put( "mlddzt", hth ) ! depth of the thermocline
  180. IF( nla10 > 1 ) THEN
  181. CALL iom_put( "mldr0_3", zrho0_3 ) ! MLD delta rho(surf) = 0.03
  182. CALL iom_put( "mldr0_1", zrho0_1 ) ! MLD delta rho(surf) = 0.01
  183. ENDIF
  184. ! ------------------------------------------------------------- !
  185. ! MLD: abs( tn - tn(10m) ) = ztem2 !
  186. ! Top of thermocline: tn = tn(10m) - ztem2 !
  187. ! MLD: rho = rho10m + zrho3 !
  188. ! pycnocline: rho = rho10m + (dr/dT)(T,S,10m)*(-0.2 degC) !
  189. ! temperature inversion: max( 0, max of tn - tn(10m) ) !
  190. ! depth of temperature inversion !
  191. ! ------------------------------------------------------------- !
  192. DO jk = jpkm1, nlb10, -1 ! loop from bottom to nlb10
  193. DO jj = 1, jpj
  194. DO ji = 1, jpi
  195. !
  196. zzdep = fsdepw(ji,jj,jk) * tmask(ji,jj,1)
  197. !
  198. zztmp = tsn(ji,jj,nla10,jp_tem) - tsn(ji,jj,jk,jp_tem) ! - delta T(10m)
  199. IF( ABS(zztmp) > ztem2 ) zabs2 (ji,jj) = zzdep ! abs > 0.2
  200. IF( zztmp > ztem2 ) ztm2 (ji,jj) = zzdep ! > 0.2
  201. zztmp = -zztmp ! delta T(10m)
  202. IF( zztmp > ztinv(ji,jj) ) THEN ! temperature inversion
  203. ztinv(ji,jj) = zztmp ; zdepinv (ji,jj) = zzdep ! max value and depth
  204. ENDIF
  205. zztmp = rhop(ji,jj,jk) - rhop(ji,jj,nla10) ! delta rho(10m)
  206. IF( zztmp > zrho3 ) zrho10_3(ji,jj) = zzdep ! > 0.03
  207. IF( zztmp > zdelr(ji,jj) ) zpycn (ji,jj) = zzdep ! > equi. delta T(10m) - 0.2
  208. !
  209. END DO
  210. END DO
  211. END DO
  212. CALL iom_put( "mld_dt02", zabs2 ) ! MLD abs(delta t) - 0.2
  213. CALL iom_put( "topthdep", ztm2 ) ! T(10) - 0.2
  214. CALL iom_put( "mldr10_3", zrho10_3 ) ! MLD delta rho(10m) = 0.03
  215. CALL iom_put( "pycndep" , zpycn ) ! MLD delta rho equi. delta T(10m) = 0.2
  216. CALL iom_put( "tinv" , ztinv ) ! max. temp. inv. (t10 ref)
  217. CALL iom_put( "depti" , zdepinv ) ! depth of max. temp. inv. (t10 ref)
  218. ! ------------------------------- !
  219. ! Depth of 20C/26C/28C isotherm !
  220. ! ------------------------------- !
  221. IF( iom_use ("20d") ) THEN ! depth of the 20 isotherm
  222. ztem2 = 20.
  223. CALL dia_hth_dep( ztem2, hd20 )
  224. CALL iom_put( "20d", hd20 )
  225. ENDIF
  226. !
  227. IF( iom_use ("26d") ) THEN ! depth of the 26 isotherm
  228. ztem2 = 26.
  229. CALL dia_hth_dep( ztem2, hd26 )
  230. CALL iom_put( "26d", hd26 )
  231. ENDIF
  232. !
  233. IF( iom_use ("28d") ) THEN ! depth of the 28 isotherm
  234. ztem2 = 28.
  235. CALL dia_hth_dep( ztem2, hd28 )
  236. CALL iom_put( "28d", hd28 )
  237. ENDIF
  238. ! ----------------------------- !
  239. ! Heat content of first 300 m !
  240. ! ----------------------------- !
  241. IF( iom_use ("hc300") .OR. iom_use ("hc700") .OR. iom_use ("hc2000") ) THEN
  242. !ztemp(:,:,:) = tsn(:,:,:,jp_tem) ! to get heat content in J/m2
  243. ztemp(:,:,:) = tsn(:,:,:,jp_tem) + rt0 ! to get heat content in K*m (CMIP6)
  244. ENDIF
  245. IF( iom_use ("hc300") ) THEN
  246. zzdep = 300.
  247. CALL dia_hth_htc( zzdep, ztemp, htc3 )
  248. !htc3(:,:) = rau0_rcp * htc3(:,:) ! to get heat content in J/m2
  249. CALL iom_put( "hc300", htc3 ) ! vertically integrated heat content (in K*m)
  250. ENDIF
  251. !
  252. ! ----------------------------- !
  253. ! Heat content of first 700 m !
  254. ! ----------------------------- !
  255. IF( iom_use ("hc700") ) THEN
  256. zzdep = 700.
  257. CALL dia_hth_htc( zzdep, ztemp, htc7 )
  258. !htc7(:,:) = rau0_rcp * htc7(:,:) ! to get heat content in J/m2
  259. CALL iom_put( "hc700", htc7 ) ! vertically integrated heat content (K*m)
  260. ENDIF
  261. !
  262. ! ----------------------------- !
  263. ! Heat content of first 2000 m !
  264. ! ----------------------------- !
  265. IF( iom_use ("hc2000") ) THEN
  266. zzdep = 2000.
  267. CALL dia_hth_htc( zzdep, ztemp, htc2 )
  268. !htc2(:,:) = rau0_rcp * htc2(:,:) ! to get heat content in J/m2
  269. CALL iom_put( "hc2000", htc2 ) ! vertically integrated heat content (K*m)
  270. ENDIF
  271. !
  272. IF( nn_timing == 1 ) CALL timing_stop('dia_hth')
  273. !
  274. END SUBROUTINE dia_hth
  275. SUBROUTINE dia_hth_dep( ptem, pdept )
  276. !
  277. REAL(wp), INTENT(in) :: ptem
  278. REAL(wp), DIMENSION(jpi,jpj), INTENT(out) :: pdept
  279. !
  280. INTEGER :: ji, jj, jk, iid
  281. REAL(wp) :: zztmp, zzdep
  282. INTEGER, DIMENSION(jpi,jpj) :: iktem
  283. ! --------------------------------------- !
  284. ! search deepest level above ptem !
  285. ! --------------------------------------- !
  286. iktem(:,:) = 1
  287. DO jk = 1, jpkm1 ! beware temperature is not always decreasing with depth => loop from top to bottom
  288. DO jj = 1, jpj
  289. DO ji = 1, jpi
  290. zztmp = tsn(ji,jj,jk,jp_tem)
  291. IF( zztmp >= ptem ) iktem(ji,jj) = jk
  292. END DO
  293. END DO
  294. END DO
  295. ! ------------------------------- !
  296. ! Depth of ptem isotherm !
  297. ! ------------------------------- !
  298. DO jj = 1, jpj
  299. DO ji = 1, jpi
  300. !
  301. zzdep = fsdepw(ji,jj,mbkt(ji,jj)+1) ! depth of the ocean bottom
  302. !
  303. iid = iktem(ji,jj)
  304. IF( iid /= 1 ) THEN
  305. zztmp = fsdept(ji,jj,iid ) & ! linear interpolation
  306. & + ( fsdept(ji,jj,iid+1) - fsdept(ji,jj,iid) ) &
  307. & * ( 20.*tmask(ji,jj,iid+1) - tsn(ji,jj,iid,jp_tem) ) &
  308. & / ( tsn(ji,jj,iid+1,jp_tem) - tsn(ji,jj,iid,jp_tem) + (1.-tmask(ji,jj,1)) )
  309. pdept(ji,jj) = MIN( zztmp , zzdep) * tmask(ji,jj,1) ! bound by the ocean depth
  310. ELSE
  311. pdept(ji,jj) = 0._wp
  312. ENDIF
  313. END DO
  314. END DO
  315. !
  316. END SUBROUTINE dia_hth_dep
  317. SUBROUTINE dia_hth_htc( pdep, ptn, phtc )
  318. !
  319. REAL(wp), INTENT(in) :: pdep ! depth over the heat content
  320. REAL(wp), DIMENSION(jpi,jpj,jpk), INTENT(in) :: ptn
  321. REAL(wp), DIMENSION(jpi,jpj), INTENT(inout) :: phtc
  322. !
  323. INTEGER :: ji, jj, jk, ik
  324. REAL(wp), DIMENSION(jpi,jpj) :: zthick
  325. INTEGER , DIMENSION(jpi,jpj) :: ilevel
  326. ! surface boundary condition
  327. IF( lk_vvl ) THEN ; zthick(:,:) = 0._wp ; phtc(:,:) = 0._wp
  328. ELSE ; zthick(:,:) = sshn(:,:) ; phtc(:,:) = ptn(:,:,1) * sshn(:,:) * tmask(:,:,1)
  329. ENDIF
  330. !
  331. ilevel(:,:) = 1
  332. DO jk = 2, jpkm1
  333. DO jj = 1, jpj
  334. DO ji = 1, jpi
  335. IF( ( fsdept(ji,jj,jk ) < pdep ) .AND. ( tmask(ji,jj,jk) == 1 ) ) THEN
  336. ilevel(ji,jj) = jk
  337. zthick(ji,jj) = zthick(ji,jj) + fse3t(ji,jj,jk)
  338. phtc (ji,jj) = phtc (ji,jj) + fse3t(ji,jj,jk) * ptn(ji,jj,jk)
  339. ENDIF
  340. ENDDO
  341. ENDDO
  342. ENDDO
  343. !
  344. DO jj = 1, jpj
  345. DO ji = 1, jpi
  346. ik = ilevel(ji,jj)
  347. zthick(ji,jj) = pdep - zthick(ji,jj) ! remaining thickness to reach depht pdep
  348. phtc(ji,jj) = phtc(ji,jj) + ptn(ji,jj,ik+1) * MIN( fse3t(ji,jj,ik+1), zthick(ji,jj) ) &
  349. * tmask(ji,jj,ik+1)
  350. END DO
  351. ENDDO
  352. !
  353. !
  354. END SUBROUTINE dia_hth_htc
  355. #else
  356. !!----------------------------------------------------------------------
  357. !! Default option : Empty module
  358. !!----------------------------------------------------------------------
  359. LOGICAL , PUBLIC, PARAMETER :: lk_diahth = .FALSE. !: thermocline-20d depths flag
  360. CONTAINS
  361. SUBROUTINE dia_hth( kt ) ! Empty routine
  362. WRITE(*,*) 'dia_hth: You should not have seen this print! error?', kt
  363. END SUBROUTINE dia_hth
  364. #endif
  365. !!======================================================================
  366. END MODULE diahth