traldf_iso.F90 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. MODULE traldf_iso
  2. !!======================================================================
  3. !! *** MODULE traldf_iso ***
  4. !! Ocean tracers: horizontal component of the lateral tracer mixing trend
  5. !!======================================================================
  6. !! History : OPA ! 1994-08 (G. Madec, M. Imbard)
  7. !! 8.0 ! 1997-05 (G. Madec) split into traldf and trazdf
  8. !! NEMO ! 2002-08 (G. Madec) Free form, F90
  9. !! 1.0 ! 2005-11 (G. Madec) merge traldf and trazdf :-)
  10. !! 3.3 ! 2010-09 (C. Ethe, G. Madec) Merge TRA-TRC
  11. !!----------------------------------------------------------------------
  12. #if defined key_ldfslp || defined key_esopa
  13. !!----------------------------------------------------------------------
  14. !! 'key_ldfslp' slope of the lateral diffusive direction
  15. !!----------------------------------------------------------------------
  16. !! tra_ldf_iso : update the tracer trend with the horizontal
  17. !! component of a iso-neutral laplacian operator
  18. !! and with the vertical part of
  19. !! the isopycnal or geopotential s-coord. operator
  20. !!----------------------------------------------------------------------
  21. USE oce ! ocean dynamics and active tracers
  22. USE dom_oce ! ocean space and time domain
  23. USE trc_oce ! share passive tracers/Ocean variables
  24. USE zdf_oce ! ocean vertical physics
  25. USE ldftra_oce ! ocean active tracers: lateral physics
  26. USE ldfslp ! iso-neutral slopes
  27. USE diaptr ! poleward transport diagnostics
  28. USE in_out_manager ! I/O manager
  29. USE iom ! I/O library
  30. USE phycst ! physical constants
  31. USE lbclnk ! ocean lateral boundary conditions (or mpp link)
  32. USE wrk_nemo ! Memory Allocation
  33. USE timing ! Timing
  34. IMPLICIT NONE
  35. PRIVATE
  36. PUBLIC tra_ldf_iso ! routine called by step.F90
  37. !! * Substitutions
  38. # include "domzgr_substitute.h90"
  39. # include "ldftra_substitute.h90"
  40. # include "vectopt_loop_substitute.h90"
  41. !!----------------------------------------------------------------------
  42. !! NEMO/OPA 3.3 , NEMO Consortium (2010)
  43. !! $Id: traldf_iso.F90 4990 2014-12-15 16:42:49Z timgraham $
  44. !! Software governed by the CeCILL licence (NEMOGCM/NEMO_CeCILL.txt)
  45. !!----------------------------------------------------------------------
  46. CONTAINS
  47. SUBROUTINE tra_ldf_iso( kt, kit000, cdtype, pgu, pgv, &
  48. & pgui, pgvi, &
  49. & ptb, pta, kjpt, pahtb0 )
  50. !!----------------------------------------------------------------------
  51. !! *** ROUTINE tra_ldf_iso ***
  52. !!
  53. !! ** Purpose : Compute the before horizontal tracer (t & s) diffusive
  54. !! trend for a laplacian tensor (ezxcept the dz[ dz[.] ] term) and
  55. !! add it to the general trend of tracer equation.
  56. !!
  57. !! ** Method : The horizontal component of the lateral diffusive trends
  58. !! is provided by a 2nd order operator rotated along neural or geopo-
  59. !! tential surfaces to which an eddy induced advection can be added
  60. !! It is computed using before fields (forward in time) and isopyc-
  61. !! nal or geopotential slopes computed in routine ldfslp.
  62. !!
  63. !! 1st part : masked horizontal derivative of T ( di[ t ] )
  64. !! ======== with partial cell update if ln_zps=T.
  65. !!
  66. !! 2nd part : horizontal fluxes of the lateral mixing operator
  67. !! ========
  68. !! zftu = (aht+ahtb0) e2u*e3u/e1u di[ tb ]
  69. !! - aht e2u*uslp dk[ mi(mk(tb)) ]
  70. !! zftv = (aht+ahtb0) e1v*e3v/e2v dj[ tb ]
  71. !! - aht e2u*vslp dk[ mj(mk(tb)) ]
  72. !! take the horizontal divergence of the fluxes:
  73. !! difft = 1/(e1t*e2t*e3t) { di-1[ zftu ] + dj-1[ zftv ] }
  74. !! Add this trend to the general trend (ta,sa):
  75. !! ta = ta + difft
  76. !!
  77. !! 3rd part: vertical trends of the lateral mixing operator
  78. !! ======== (excluding the vertical flux proportional to dk[t] )
  79. !! vertical fluxes associated with the rotated lateral mixing:
  80. !! zftw =-aht { e2t*wslpi di[ mi(mk(tb)) ]
  81. !! + e1t*wslpj dj[ mj(mk(tb)) ] }
  82. !! take the horizontal divergence of the fluxes:
  83. !! difft = 1/(e1t*e2t*e3t) dk[ zftw ]
  84. !! Add this trend to the general trend (ta,sa):
  85. !! pta = pta + difft
  86. !!
  87. !! ** Action : Update pta arrays with the before rotated diffusion
  88. !!----------------------------------------------------------------------
  89. USE oce , ONLY: zftu => ua , zftv => va ! (ua,va) used as workspace
  90. !
  91. INTEGER , INTENT(in ) :: kt ! ocean time-step index
  92. INTEGER , INTENT(in ) :: kit000 ! first time step index
  93. CHARACTER(len=3) , INTENT(in ) :: cdtype ! =TRA or TRC (tracer indicator)
  94. INTEGER , INTENT(in ) :: kjpt ! number of tracers
  95. REAL(wp), DIMENSION(jpi,jpj ,kjpt), INTENT(in ) :: pgu , pgv ! tracer gradient at pstep levels
  96. REAL(wp), DIMENSION(jpi,jpj ,kjpt), INTENT(in ) :: pgui, pgvi ! tracer gradient at pstep levels
  97. REAL(wp), DIMENSION(jpi,jpj,jpk,kjpt), INTENT(in ) :: ptb ! before and now tracer fields
  98. REAL(wp), DIMENSION(jpi,jpj,jpk,kjpt), INTENT(inout) :: pta ! tracer trend
  99. REAL(wp) , INTENT(in ) :: pahtb0 ! background diffusion coef
  100. !
  101. INTEGER :: ji, jj, jk, jn ! dummy loop indices
  102. INTEGER :: ikt
  103. REAL(wp) :: zmsku, zabe1, zcof1, zcoef3 ! local scalars
  104. REAL(wp) :: zmskv, zabe2, zcof2, zcoef4 ! - -
  105. REAL(wp) :: zcoef0, zbtr, ztra ! - -
  106. REAL(wp), POINTER, DIMENSION(:,: ) :: z2d
  107. REAL(wp), POINTER, DIMENSION(:,:,:) :: zdkt, zdk1t, zdit, zdjt, ztfw
  108. !!----------------------------------------------------------------------
  109. !
  110. IF( nn_timing == 1 ) CALL timing_start('tra_ldf_iso')
  111. !
  112. CALL wrk_alloc( jpi, jpj, z2d )
  113. CALL wrk_alloc( jpi, jpj, jpk, zdit, zdjt, ztfw, zdkt, zdk1t )
  114. !
  115. IF( kt == kit000 ) THEN
  116. IF(lwp) WRITE(numout,*)
  117. IF(lwp) WRITE(numout,*) 'tra_ldf_iso : rotated laplacian diffusion operator on ', cdtype
  118. IF(lwp) WRITE(numout,*) '~~~~~~~~~~~'
  119. ENDIF
  120. !
  121. ! ! ===========
  122. DO jn = 1, kjpt ! tracer loop
  123. ! ! ===========
  124. !
  125. !!----------------------------------------------------------------------
  126. !! I - masked horizontal derivative
  127. !!----------------------------------------------------------------------
  128. !!bug ajout.... why? ( 1,jpj,:) and (jpi,1,:) should be sufficient....
  129. zdit (1,:,:) = 0.e0 ; zdit (jpi,:,:) = 0.e0
  130. zdjt (1,:,:) = 0.e0 ; zdjt (jpi,:,:) = 0.e0
  131. !!end
  132. ! Horizontal tracer gradient
  133. DO jk = 1, jpkm1
  134. DO jj = 1, jpjm1
  135. DO ji = 1, fs_jpim1 ! vector opt.
  136. zdit(ji,jj,jk) = ( ptb(ji+1,jj ,jk,jn) - ptb(ji,jj,jk,jn) ) * umask(ji,jj,jk)
  137. zdjt(ji,jj,jk) = ( ptb(ji ,jj+1,jk,jn) - ptb(ji,jj,jk,jn) ) * vmask(ji,jj,jk)
  138. END DO
  139. END DO
  140. END DO
  141. ! partial cell correction
  142. IF( ln_zps ) THEN ! partial steps correction at the last ocean level
  143. DO jj = 1, jpjm1
  144. DO ji = 1, fs_jpim1 ! vector opt.
  145. ! IF useless if zpshde defines pgu everywhere
  146. zdit(ji,jj,mbku(ji,jj)) = pgu(ji,jj,jn)
  147. zdjt(ji,jj,mbkv(ji,jj)) = pgv(ji,jj,jn)
  148. END DO
  149. END DO
  150. ENDIF
  151. IF( ln_zps .AND. ln_isfcav ) THEN ! partial steps correction at the first wet level beneath a cavity
  152. DO jj = 1, jpjm1
  153. DO ji = 1, fs_jpim1 ! vector opt.
  154. IF (miku(ji,jj) > 1) zdit(ji,jj,miku(ji,jj)) = pgui(ji,jj,jn)
  155. IF (mikv(ji,jj) > 1) zdjt(ji,jj,mikv(ji,jj)) = pgvi(ji,jj,jn)
  156. END DO
  157. END DO
  158. END IF
  159. !!----------------------------------------------------------------------
  160. !! II - horizontal trend (full)
  161. !!----------------------------------------------------------------------
  162. !!!!!!!!!!CDIR PARALLEL DO PRIVATE( zdk1t )
  163. ! 1. Vertical tracer gradient at level jk and jk+1
  164. ! ------------------------------------------------
  165. !
  166. ! interior value
  167. DO jk = 2, jpkm1
  168. DO jj = 1, jpj
  169. DO ji = 1, jpi ! vector opt.
  170. zdk1t(ji,jj,jk) = ( ptb(ji,jj,jk,jn ) - ptb(ji,jj,jk+1,jn) ) * wmask(ji,jj,jk+1)
  171. !
  172. zdkt(ji,jj,jk) = ( ptb(ji,jj,jk-1,jn) - ptb(ji,jj,jk,jn ) ) * wmask(ji,jj,jk)
  173. END DO
  174. END DO
  175. END DO
  176. ! surface boundary condition: zdkt(jk=1)=zdkt(jk=2)
  177. zdk1t(:,:,1) = ( ptb(:,:,1,jn ) - ptb(:,:,2,jn) ) * wmask(:,:,2)
  178. zdkt (:,:,1) = zdk1t(:,:,1)
  179. IF ( ln_isfcav ) THEN
  180. DO jj = 1, jpj
  181. DO ji = 1, jpi ! vector opt.
  182. ikt = mikt(ji,jj) ! surface level
  183. zdk1t(ji,jj,ikt) = ( ptb(ji,jj,ikt,jn ) - ptb(ji,jj,ikt+1,jn) ) * wmask(ji,jj,ikt+1)
  184. zdkt (ji,jj,ikt) = zdk1t(ji,jj,ikt)
  185. END DO
  186. END DO
  187. END IF
  188. ! 2. Horizontal fluxes
  189. ! --------------------
  190. DO jk = 1, jpkm1
  191. DO jj = 1 , jpjm1
  192. DO ji = 1, fs_jpim1 ! vector opt.
  193. zabe1 = ( fsahtu(ji,jj,jk) + pahtb0 ) * re2u_e1u(ji,jj) * fse3u_n(ji,jj,jk)
  194. zabe2 = ( fsahtv(ji,jj,jk) + pahtb0 ) * re1v_e2v(ji,jj) * fse3v_n(ji,jj,jk)
  195. !
  196. zmsku = 1. / MAX( tmask(ji+1,jj,jk ) + tmask(ji,jj,jk+1) &
  197. & + tmask(ji+1,jj,jk+1) + tmask(ji,jj,jk ), 1. )
  198. !
  199. zmskv = 1. / MAX( tmask(ji,jj+1,jk ) + tmask(ji,jj,jk+1) &
  200. & + tmask(ji,jj+1,jk+1) + tmask(ji,jj,jk ), 1. )
  201. !
  202. zcof1 = - fsahtu(ji,jj,jk) * e2u(ji,jj) * uslp(ji,jj,jk) * zmsku
  203. zcof2 = - fsahtv(ji,jj,jk) * e1v(ji,jj) * vslp(ji,jj,jk) * zmskv
  204. !
  205. zftu(ji,jj,jk ) = ( zabe1 * zdit(ji,jj,jk) &
  206. & + zcof1 * ( zdkt (ji+1,jj,jk) + zdk1t(ji,jj,jk) &
  207. & + zdk1t(ji+1,jj,jk) + zdkt (ji,jj,jk) ) ) * umask(ji,jj,jk)
  208. zftv(ji,jj,jk) = ( zabe2 * zdjt(ji,jj,jk) &
  209. & + zcof2 * ( zdkt (ji,jj+1,jk) + zdk1t(ji,jj,jk) &
  210. & + zdk1t(ji,jj+1,jk) + zdkt (ji,jj,jk) ) ) * vmask(ji,jj,jk)
  211. END DO
  212. END DO
  213. ! II.4 Second derivative (divergence) and add to the general trend
  214. ! ----------------------------------------------------------------
  215. DO jj = 2 , jpjm1
  216. DO ji = fs_2, fs_jpim1 ! vector opt.
  217. zbtr = 1.0 / ( e12t(ji,jj) * fse3t_n(ji,jj,jk) )
  218. ztra = zbtr * ( zftu(ji,jj,jk) - zftu(ji-1,jj,jk) + zftv(ji,jj,jk) - zftv(ji,jj-1,jk) )
  219. pta(ji,jj,jk,jn) = pta(ji,jj,jk,jn) + ztra
  220. END DO
  221. END DO
  222. ! ! ===============
  223. END DO ! End of slab
  224. ! ! ===============
  225. !
  226. ! "Poleward" diffusive heat or salt transports (T-S case only)
  227. ! note sign is reversed to give down-gradient diffusive transports (#1043)
  228. IF( cdtype == 'TRA' .AND. ln_diaptr ) CALL dia_ptr_ohst_components( jn, 'ldf', -zftv(:,:,:) )
  229. IF( iom_use("udiff_heattr") .OR. iom_use("vdiff_heattr") ) THEN
  230. !
  231. IF( cdtype == 'TRA' .AND. jn == jp_tem ) THEN
  232. z2d(:,:) = 0._wp
  233. DO jk = 1, jpkm1
  234. DO jj = 2, jpjm1
  235. DO ji = fs_2, fs_jpim1 ! vector opt.
  236. z2d(ji,jj) = z2d(ji,jj) + zftu(ji,jj,jk)
  237. END DO
  238. END DO
  239. END DO
  240. z2d(:,:) = - rau0_rcp * z2d(:,:) ! note sign is reversed to give down-gradient diffusive transports (#1043)
  241. CALL lbc_lnk( z2d, 'U', -1. )
  242. CALL iom_put( "udiff_heattr", z2d ) ! heat transport in i-direction
  243. !
  244. z2d(:,:) = 0._wp
  245. DO jk = 1, jpkm1
  246. DO jj = 2, jpjm1
  247. DO ji = fs_2, fs_jpim1 ! vector opt.
  248. z2d(ji,jj) = z2d(ji,jj) + zftv(ji,jj,jk)
  249. END DO
  250. END DO
  251. END DO
  252. z2d(:,:) = - rau0_rcp * z2d(:,:) ! note sign is reversed to give down-gradient diffusive transports (#1043)
  253. CALL lbc_lnk( z2d, 'V', -1. )
  254. CALL iom_put( "vdiff_heattr", z2d ) ! heat transport in i-direction
  255. END IF
  256. !
  257. ENDIF
  258. !!----------------------------------------------------------------------
  259. !! III - vertical trend of T & S (extra diagonal terms only)
  260. !!----------------------------------------------------------------------
  261. ! Local constant initialization
  262. ! -----------------------------
  263. ztfw(1,:,:) = 0.e0 ; ztfw(jpi,:,:) = 0.e0
  264. ! Vertical fluxes
  265. ! ---------------
  266. ! Surface and bottom vertical fluxes set to zero
  267. ztfw(:,:, 1 ) = 0.e0 ; ztfw(:,:,jpk) = 0.e0
  268. ! interior (2=<jk=<jpk-1)
  269. DO jk = 2, jpkm1
  270. DO jj = 2, jpjm1
  271. DO ji = fs_2, fs_jpim1 ! vector opt.
  272. zcoef0 = - fsahtw(ji,jj,jk) * wmask(ji,jj,jk)
  273. !
  274. zmsku = 1./MAX( umask(ji ,jj,jk-1) + umask(ji-1,jj,jk) &
  275. & + umask(ji-1,jj,jk-1) + umask(ji ,jj,jk), 1. )
  276. zmskv = 1./MAX( vmask(ji,jj ,jk-1) + vmask(ji,jj-1,jk) &
  277. & + vmask(ji,jj-1,jk-1) + vmask(ji,jj ,jk), 1. )
  278. !
  279. zcoef3 = zcoef0 * e2t(ji,jj) * zmsku * wslpi (ji,jj,jk)
  280. zcoef4 = zcoef0 * e1t(ji,jj) * zmskv * wslpj (ji,jj,jk)
  281. !
  282. ztfw(ji,jj,jk) = zcoef3 * ( zdit(ji ,jj ,jk-1) + zdit(ji-1,jj ,jk) &
  283. & + zdit(ji-1,jj ,jk-1) + zdit(ji ,jj ,jk) ) &
  284. & + zcoef4 * ( zdjt(ji ,jj ,jk-1) + zdjt(ji ,jj-1,jk) &
  285. & + zdjt(ji ,jj-1,jk-1) + zdjt(ji ,jj ,jk) )
  286. END DO
  287. END DO
  288. END DO
  289. ! I.5 Divergence of vertical fluxes added to the general tracer trend
  290. ! -------------------------------------------------------------------
  291. DO jk = 1, jpkm1
  292. DO jj = 2, jpjm1
  293. DO ji = fs_2, fs_jpim1 ! vector opt.
  294. zbtr = 1.0 / ( e12t(ji,jj) * fse3t_n(ji,jj,jk) )
  295. ztra = ( ztfw(ji,jj,jk) - ztfw(ji,jj,jk+1) ) * zbtr
  296. pta(ji,jj,jk,jn) = pta(ji,jj,jk,jn) + ztra
  297. END DO
  298. END DO
  299. END DO
  300. !
  301. END DO
  302. !
  303. CALL wrk_dealloc( jpi, jpj, z2d )
  304. CALL wrk_dealloc( jpi, jpj, jpk, zdit, zdjt, ztfw, zdkt, zdk1t )
  305. !
  306. IF( nn_timing == 1 ) CALL timing_stop('tra_ldf_iso')
  307. !
  308. END SUBROUTINE tra_ldf_iso
  309. #else
  310. !!----------------------------------------------------------------------
  311. !! default option : Dummy code NO rotation of the diffusive tensor
  312. !!----------------------------------------------------------------------
  313. CONTAINS
  314. SUBROUTINE tra_ldf_iso( kt, kit000,cdtype, pgu, pgv, pgui, pgvi, ptb, pta, kjpt, pahtb0 ) ! Empty routine
  315. INTEGER:: kt, kit000
  316. CHARACTER(len=3) :: cdtype
  317. REAL, DIMENSION(:,:,:) :: pgu, pgv, pgui, pgvi ! tracer gradient at pstep levels
  318. REAL, DIMENSION(:,:,:,:) :: ptb, pta
  319. WRITE(*,*) 'tra_ldf_iso: You should not have seen this print! error?', kt, kit000, cdtype, &
  320. & pgu(1,1,1), pgv(1,1,1), ptb(1,1,1,1), pta(1,1,1,1), kjpt, pahtb0
  321. END SUBROUTINE tra_ldf_iso
  322. #endif
  323. !!==============================================================================
  324. END MODULE traldf_iso