traldf_bilapg.F90 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. MODULE traldf_bilapg
  2. !!==============================================================================
  3. !! *** MODULE traldf_bilapg ***
  4. !! Ocean tracers: horizontal component of the lateral tracer mixing trend
  5. !!==============================================================================
  6. !! History : 8.0 ! 1997-07 (G. Madec) Original code
  7. !! NEMO 1.0 ! 2002-08 (G. Madec) F90: Free form and module
  8. !! 3.3 ! 2010-06 (C. Ethe, G. Madec) Merge TRA-TRC
  9. !!==============================================================================
  10. #if defined key_ldfslp || defined key_esopa
  11. !!----------------------------------------------------------------------
  12. !! 'key_ldfslp' rotation of the lateral mixing tensor
  13. !!----------------------------------------------------------------------
  14. !! tra_ldf_bilapg : update the tracer trend with the horizontal diffusion
  15. !! using an horizontal biharmonic operator in s-coordinate
  16. !! ldfght : ???
  17. !!----------------------------------------------------------------------
  18. USE oce ! ocean dynamics and tracers variables
  19. USE dom_oce ! ocean space and time domain variables
  20. USE ldftra_oce ! ocean active tracers: lateral physics
  21. USE in_out_manager ! I/O manager
  22. USE ldfslp ! iso-neutral slopes available
  23. USE lbclnk ! ocean lateral boundary condition (or mpp link)
  24. USE diaptr ! poleward transport diagnostics
  25. USE trc_oce ! share passive tracers/Ocean variables
  26. USE lib_mpp ! MPP library
  27. USE wrk_nemo ! Memory Allocation
  28. USE timing ! Timing
  29. IMPLICIT NONE
  30. PRIVATE
  31. PUBLIC tra_ldf_bilapg ! routine called by step.F90
  32. !! * Substitutions
  33. # include "domzgr_substitute.h90"
  34. # include "ldftra_substitute.h90"
  35. # include "ldfeiv_substitute.h90"
  36. !!----------------------------------------------------------------------
  37. !! NEMO/OPA 3.3 , NEMO Consortium (2010)
  38. !! $Id: traldf_bilapg.F90 4292 2013-11-20 16:28:04Z cetlod $
  39. !! Software governed by the CeCILL licence (NEMOGCM/NEMO_CeCILL.txt)
  40. !!----------------------------------------------------------------------
  41. CONTAINS
  42. SUBROUTINE tra_ldf_bilapg( kt, kit000, cdtype, ptb, pta, kjpt )
  43. !!----------------------------------------------------------------------
  44. !! *** ROUTINE tra_ldf_bilapg ***
  45. !!
  46. !! ** Purpose : Compute the before horizontal tracer diffusive
  47. !! trend and add it to the general trend of tracer equation.
  48. !!
  49. !! ** Method : The lateral diffusive trends is provided by a 4th order
  50. !! operator rotated along geopotential surfaces. It is computed
  51. !! using before fields (forward in time) and geopotential slopes
  52. !! computed in routine inildf.
  53. !! -1- compute the geopotential harmonic operator applied to
  54. !! ptb and multiply it by the eddy diffusivity coefficient
  55. !! (done by a call to ldfght routine, result in wk1 arrays).
  56. !! Applied the domain lateral boundary conditions by call to lbc_lnk
  57. !! -2- compute the geopotential harmonic operator applied to
  58. !! wk1 by a second call to ldfght routine (result in wk2)
  59. !! arrays).
  60. !! -3- Add this trend to the general trend
  61. !! pta = pta + wk2
  62. !!
  63. !! ** Action : - Update pta arrays with the before geopotential
  64. !! biharmonic mixing trend.
  65. !!----------------------------------------------------------------------
  66. !
  67. INTEGER , INTENT(in ) :: kt ! ocean time-step index
  68. INTEGER , INTENT(in ) :: kit000 ! first time step index
  69. CHARACTER(len=3), INTENT(in ) :: cdtype ! =TRA or TRC (tracer indicator)
  70. INTEGER , INTENT(in ) :: kjpt ! number of tracers
  71. REAL(wp), DIMENSION(jpi,jpj,jpk,kjpt), INTENT(in ) :: ptb ! before and now tracer fields
  72. REAL(wp), DIMENSION(jpi,jpj,jpk,kjpt), INTENT(inout) :: pta ! tracer trend
  73. !
  74. INTEGER :: ji, jj, jk, jn ! dummy loop indices
  75. REAL(wp), POINTER, DIMENSION(:,:,:,:) :: zwk1, zwk2
  76. !!----------------------------------------------------------------------
  77. !
  78. IF( nn_timing == 1 ) CALL timing_start('tra_ldf_bilapg')
  79. !
  80. CALL wrk_alloc( jpi, jpj, jpk, kjpt, zwk1, zwk2 )
  81. !
  82. IF( kt == kit000 ) THEN
  83. IF(lwp) WRITE(numout,*)
  84. IF(lwp) WRITE(numout,*) 'tra_ldf_bilapg : horizontal biharmonic operator in s-coordinate on ', cdtype
  85. IF(lwp) WRITE(numout,*) '~~~~~~~~~~~~~~'
  86. ENDIF
  87. ! 1. Laplacian of ptb * aht
  88. ! -----------------------------
  89. CALL ldfght( kt, cdtype, ptb, zwk1, kjpt, 1 ) ! rotated harmonic operator applied to ptb and multiply by aht
  90. ! ! output in wk1
  91. !
  92. DO jn = 1, kjpt
  93. CALL lbc_lnk( zwk1(:,:,:,jn) , 'T', 1. ) ! Lateral boundary conditions on wk1 (unchanged sign)
  94. END DO
  95. ! 2. Bilaplacian of ptb
  96. ! -------------------------
  97. CALL ldfght( kt, cdtype, zwk1, zwk2, kjpt, 2 ) ! rotated harmonic operator applied to wk1 ; output in wk2
  98. ! 3. Update the tracer trends (j-slab : 2, jpj-1)
  99. ! ---------------------------
  100. DO jn = 1, kjpt
  101. DO jj = 2, jpjm1
  102. DO jk = 1, jpkm1
  103. DO ji = 2, jpim1
  104. ! add it to the general tracer trends
  105. pta(ji,jj,jk,jn) = pta(ji,jj,jk,jn) + zwk2(ji,jj,jk,jn)
  106. END DO
  107. END DO
  108. END DO
  109. END DO
  110. !
  111. CALL wrk_dealloc( jpi, jpj, jpk, kjpt, zwk1, zwk2 )
  112. !
  113. IF( nn_timing == 1 ) CALL timing_stop('tra_ldf_bilapg')
  114. !
  115. END SUBROUTINE tra_ldf_bilapg
  116. SUBROUTINE ldfght ( kt, cdtype, pt, plt, kjpt, kaht )
  117. !!----------------------------------------------------------------------
  118. !! *** ROUTINE ldfght ***
  119. !!
  120. !! ** Purpose : Apply a geopotential harmonic operator to (pt) and
  121. !! multiply it by the eddy diffusivity coefficient (if kaht=1).
  122. !! Routine only used in s-coordinates (l_sco=T) with bilaplacian
  123. !! operator (ln_traldf_bilap=T) acting along geopotential surfaces
  124. !! (ln_traldf_hor).
  125. !!
  126. !! ** Method : The harmonic operator rotated along geopotential
  127. !! surfaces is applied to (pt) using the slopes of geopotential
  128. !! surfaces computed in inildf routine. The result is provided in
  129. !! (plt,pls) arrays. It is computed in 2 steps:
  130. !!
  131. !! First step: horizontal part of the operator. It is computed on
  132. !! ========== pt as follows (idem on ps)
  133. !! horizontal fluxes :
  134. !! zftu = e2u*e3u/e1u di[ pt ] - e2u*uslp dk[ mi(mk(pt)) ]
  135. !! zftv = e1v*e3v/e2v dj[ pt ] - e1v*vslp dk[ mj(mk(pt)) ]
  136. !! take the horizontal divergence of the fluxes (no divided by
  137. !! the volume element :
  138. !! plt = di-1[ zftu ] + dj-1[ zftv ]
  139. !!
  140. !! Second step: vertical part of the operator. It is computed on
  141. !! =========== pt as follows (idem on ps)
  142. !! vertical fluxes :
  143. !! zftw = e1t*e2t/e3w * (wslpi^2+wslpj^2) dk-1[ pt ]
  144. !! - e2t * wslpi di[ mi(mk(pt)) ]
  145. !! - e1t * wslpj dj[ mj(mk(pt)) ]
  146. !! take the vertical divergence of the fluxes add it to the hori-
  147. !! zontal component, divide the result by the volume element and
  148. !! if kaht=1, multiply by the eddy diffusivity coefficient:
  149. !! plt = aht / (e1t*e2t*e3t) { plt + dk[ zftw ] }
  150. !! else:
  151. !! plt = 1 / (e1t*e2t*e3t) { plt + dk[ zftw ] }
  152. !!
  153. !!----------------------------------------------------------------------
  154. USE oce , ONLY: zftv => ua ! ua used as workspace
  155. !
  156. INTEGER , INTENT(in ) :: kt ! ocean time-step index
  157. CHARACTER(len=3), INTENT(in ) :: cdtype ! =TRA or TRC (tracer indicator)
  158. INTEGER , INTENT(in ) :: kjpt !: dimension of
  159. REAL(wp) , INTENT(in ), DIMENSION(jpi,jpj,jpk,kjpt) :: pt ! tracer fields ( before for 1st call
  160. ! ! and laplacian of these fields for 2nd call.
  161. REAL(wp) , INTENT(out), DIMENSION(jpi,jpj,jpk,kjpt) :: plt !: partial harmonic operator applied to pt components except
  162. ! !: second order vertical derivative term
  163. INTEGER , INTENT(in ) :: kaht !: =1 multiply the laplacian by the eddy diffusivity coeff.
  164. ! !: =2 no multiplication
  165. !!
  166. INTEGER :: ji, jj, jk,jn ! dummy loop indices
  167. ! ! temporary scalars
  168. REAL(wp) :: zabe1, zabe2, zmku, zmkv
  169. REAL(wp) :: zbtr, ztah, ztav
  170. REAL(wp) :: zcof0, zcof1, zcof2, zcof3, zcof4
  171. REAL(wp), POINTER, DIMENSION(:,:) :: zftu, zdkt, zdk1t
  172. REAL(wp), POINTER, DIMENSION(:,:) :: zftw, zdit, zdjt, zdj1t
  173. !!----------------------------------------------------------------------
  174. !
  175. IF( nn_timing == 1 ) CALL timing_start('ldfght')
  176. !
  177. CALL wrk_alloc( jpi, jpj, zftu, zdkt, zdk1t )
  178. CALL wrk_alloc( jpi, jpk, zftw, zdit, zdjt, zdj1t )
  179. !
  180. DO jn = 1, kjpt
  181. ! ! ********** ! ! ===============
  182. DO jk = 1, jpkm1 ! First step ! ! Horizontal slab
  183. ! ! ********** ! ! ===============
  184. ! I.1 Vertical gradient of pt and ps at level jk and jk+1
  185. ! -------------------------------------------------------
  186. ! surface boundary condition: zdkt(jk=1)=zdkt(jk=2)
  187. zdk1t(:,:) = ( pt(:,:,jk,jn) - pt(:,:,jk+1,jn) ) * tmask(:,:,jk+1)
  188. IF( jk == 1 ) THEN
  189. zdkt(:,:) = zdk1t(:,:)
  190. ELSE
  191. zdkt(:,:) = ( pt(:,:,jk-1,jn) - pt(:,:,jk,jn) ) * tmask(:,:,jk)
  192. ENDIF
  193. ! I.2 Horizontal fluxes
  194. ! ---------------------
  195. DO jj = 1, jpjm1
  196. DO ji = 1, jpim1
  197. zabe1 = re2u_e1u(ji,jj) * fse3u_n(ji,jj,jk)
  198. zabe2 = re1v_e2v(ji,jj) * fse3v_n(ji,jj,jk)
  199. zmku = 1./MAX( tmask(ji+1,jj,jk )+tmask(ji,jj,jk+1) &
  200. & +tmask(ji+1,jj,jk+1)+tmask(ji,jj,jk ),1. )
  201. zmkv = 1./MAX( tmask(ji,jj+1,jk )+tmask(ji,jj,jk+1) &
  202. & +tmask(ji,jj+1,jk+1)+tmask(ji,jj,jk ),1. )
  203. zcof1 = -e2u(ji,jj) * uslp(ji,jj,jk) * zmku
  204. zcof2 = -e1v(ji,jj) * vslp(ji,jj,jk) * zmkv
  205. zftu(ji,jj)= umask(ji,jj,jk) * &
  206. & ( zabe1 *( pt (ji+1,jj,jk,jn) - pt(ji,jj,jk,jn) ) &
  207. & + zcof1 *( zdkt (ji+1,jj) + zdk1t(ji,jj) &
  208. & +zdk1t(ji+1,jj) + zdkt (ji,jj) ) )
  209. zftv(ji,jj,jk)= vmask(ji,jj,jk) * &
  210. & ( zabe2 *( pt(ji,jj+1,jk,jn) - pt(ji,jj,jk,jn) ) &
  211. & + zcof2 *( zdkt (ji,jj+1) + zdk1t(ji,jj) &
  212. & +zdk1t(ji,jj+1) + zdkt (ji,jj) ) )
  213. END DO
  214. END DO
  215. ! I.3 Second derivative (divergence) (not divided by the volume)
  216. ! ---------------------
  217. DO jj = 2 , jpjm1
  218. DO ji = 2 , jpim1
  219. ztah = zftu(ji,jj) - zftu(ji-1,jj) + zftv(ji,jj,jk) - zftv(ji,jj-1,jk)
  220. plt(ji,jj,jk,jn) = ztah
  221. END DO
  222. END DO
  223. ! ! ===============
  224. END DO ! End of slab
  225. ! ! ===============
  226. ! "Poleward" diffusive heat or salt transport
  227. ! note sign is reversed to give down-gradient diffusive transports (#1043)
  228. IF( cdtype == 'TRA' .AND. ln_diaptr .AND. ( kaht == 2 ) ) CALL dia_ptr_ohst_components( jn, 'ldf', -zftv(:,:,:) )
  229. ! ! ************ ! ! ===============
  230. DO jj = 2, jpjm1 ! Second step ! ! Horizontal slab
  231. ! ! ************ ! ! ===============
  232. ! II.1 horizontal tracer gradient
  233. ! -------------------------------
  234. DO jk = 1, jpk
  235. DO ji = 1, jpim1
  236. zdit (ji,jk) = ( pt(ji+1,jj ,jk,jn) - pt(ji,jj ,jk,jn) ) * umask(ji,jj ,jk)
  237. zdjt (ji,jk) = ( pt(ji ,jj+1,jk,jn) - pt(ji,jj ,jk,jn) ) * vmask(ji,jj ,jk)
  238. zdj1t(ji,jk) = ( pt(ji ,jj ,jk,jn) - pt(ji,jj-1,jk,jn) ) * vmask(ji,jj-1,jk)
  239. END DO
  240. END DO
  241. ! II.2 Vertical fluxes
  242. ! --------------------
  243. ! Surface and bottom vertical fluxes set to zero
  244. zftw(:, 1 ) = 0.e0
  245. zftw(:,jpk) = 0.e0
  246. ! interior (2=<jk=<jpk-1)
  247. DO jk = 2, jpkm1
  248. DO ji = 2, jpim1
  249. zcof0 = e12t(ji,jj) / fse3w_n(ji,jj,jk) &
  250. & * ( wslpi(ji,jj,jk) * wslpi(ji,jj,jk) &
  251. & + wslpj(ji,jj,jk) * wslpj(ji,jj,jk) )
  252. zmku = 1./MAX( umask(ji ,jj,jk-1)+umask(ji-1,jj,jk) &
  253. & +umask(ji-1,jj,jk-1)+umask(ji ,jj,jk), 1. )
  254. zmkv = 1./MAX( vmask(ji,jj ,jk-1)+vmask(ji,jj-1,jk) &
  255. & +vmask(ji,jj-1,jk-1)+vmask(ji,jj ,jk), 1. )
  256. zcof3 = - e2t(ji,jj) * wslpi (ji,jj,jk) * zmku
  257. zcof4 = - e1t(ji,jj) * wslpj (ji,jj,jk) * zmkv
  258. zftw(ji,jk) = tmask(ji,jj,jk) * &
  259. & ( zcof0 * ( pt (ji,jj,jk-1,jn) - pt (ji ,jj,jk,jn) ) &
  260. & + zcof3 * ( zdit (ji ,jk-1 ) + zdit (ji-1,jk ) &
  261. & +zdit (ji-1 ,jk-1 ) + zdit (ji ,jk ) ) &
  262. & + zcof4 * ( zdjt (ji ,jk-1 ) + zdj1t(ji ,jk) &
  263. & +zdj1t(ji ,jk-1 ) + zdjt (ji ,jk ) ) )
  264. END DO
  265. END DO
  266. ! II.3 Divergence of vertical fluxes added to the horizontal divergence
  267. ! ---------------------------------------------------------------------
  268. IF( kaht == 1 ) THEN
  269. ! multiply the laplacian by the eddy diffusivity coefficient
  270. DO jk = 1, jpkm1
  271. DO ji = 2, jpim1
  272. ! eddy coef. divided by the volume element
  273. zbtr = 1.0 / ( e12t(ji,jj) * fse3t_n(ji,jj,jk) )
  274. ! vertical divergence
  275. ztav = fsahtt(ji,jj,jk) * ( zftw(ji,jk) - zftw(ji,jk+1) )
  276. ! harmonic operator applied to (pt,ps) and multiply by aht
  277. plt(ji,jj,jk,jn) = ( plt(ji,jj,jk,jn) + ztav ) * zbtr
  278. END DO
  279. END DO
  280. ELSEIF( kaht == 2 ) THEN
  281. ! second call, no multiplication
  282. DO jk = 1, jpkm1
  283. DO ji = 2, jpim1
  284. ! inverse of the volume element
  285. zbtr = 1.0 / ( e12t(ji,jj) * fse3t_n(ji,jj,jk) )
  286. ! vertical divergence
  287. ztav = zftw(ji,jk) - zftw(ji,jk+1)
  288. ! harmonic operator applied to (pt,ps)
  289. plt(ji,jj,jk,jn) = ( plt(ji,jj,jk,jn) + ztav ) * zbtr
  290. END DO
  291. END DO
  292. ELSE
  293. IF(lwp) WRITE(numout,*) ' ldfght: kaht= 1 or 2, here =', kaht
  294. IF(lwp) WRITE(numout,*) ' We stop'
  295. STOP 'ldfght'
  296. ENDIF
  297. ! ! ===============
  298. END DO ! End of slab
  299. ! ! ===============
  300. END DO
  301. !
  302. CALL wrk_dealloc( jpi, jpj, zftu, zdkt, zdk1t )
  303. CALL wrk_dealloc( jpi, jpk, zftw, zdit, zdjt, zdj1t )
  304. !
  305. IF( nn_timing == 1 ) CALL timing_stop('ldfght')
  306. !
  307. END SUBROUTINE ldfght
  308. #else
  309. !!----------------------------------------------------------------------
  310. !! Dummy module : NO rotation of the lateral mixing tensor
  311. !!----------------------------------------------------------------------
  312. CONTAINS
  313. SUBROUTINE tra_ldf_bilapg( kt, kit000, cdtype, ptb, pta, kjpt ) ! Empty routine
  314. INTEGER :: kt, kit000
  315. CHARACTER(len=3) :: cdtype
  316. REAL, DIMENSION(:,:,:,:) :: ptb, pta
  317. WRITE(*,*) 'tra_ldf_iso: You should not have seen this print! error?', &
  318. & kt, kit000, cdtype, ptb(1,1,1,1), pta(1,1,1,1), kjpt
  319. END SUBROUTINE tra_ldf_bilapg
  320. #endif
  321. !!==============================================================================
  322. END MODULE traldf_bilapg