trazdf_imp.F90 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. MODULE trazdf_imp
  2. !!======================================================================
  3. !! *** MODULE trazdf_imp ***
  4. !! Ocean tracers: vertical component of the tracer mixing trend
  5. !!======================================================================
  6. !! History : OPA ! 1990-10 (B. Blanke) Original code
  7. !! 7.0 ! 1991-11 (G. Madec)
  8. !! ! 1992-06 (M. Imbard) correction on tracer trend loops
  9. !! ! 1996-01 (G. Madec) statement function for e3
  10. !! ! 1997-05 (G. Madec) vertical component of isopycnal
  11. !! ! 1997-07 (G. Madec) geopotential diffusion in s-coord
  12. !! ! 2000-08 (G. Madec) double diffusive mixing
  13. !! NEMO 1.0 ! 2002-08 (G. Madec) F90: Free form and module
  14. !! 2.0 ! 2006-11 (G. Madec) New step reorganisation
  15. !! 3.2 ! 2009-03 (G. Madec) heat and salt content trends
  16. !! 3.3 ! 2010-06 (C. Ethe, G. Madec) Merge TRA-TRC
  17. !! - ! 2011-02 (A. Coward, C. Ethe, G. Madec) improvment of surface boundary condition
  18. !!----------------------------------------------------------------------
  19. !!----------------------------------------------------------------------
  20. !! tra_zdf_imp : Update the tracer trend with the diagonal vertical
  21. !! part of the mixing tensor.
  22. !!----------------------------------------------------------------------
  23. USE oce ! ocean dynamics and tracers variables
  24. USE dom_oce ! ocean space and time domain variables
  25. USE zdf_oce ! ocean vertical physics variables
  26. USE trc_oce ! share passive tracers/ocean variables
  27. USE domvvl ! variable volume
  28. USE ldftra_oce ! ocean active tracers: lateral physics
  29. USE ldftra ! lateral mixing type
  30. USE ldfslp ! lateral physics: slope of diffusion
  31. USE zdfddm ! ocean vertical physics: double diffusion
  32. USE traldf_iso_grif ! active tracers: Griffies operator
  33. USE in_out_manager ! I/O manager
  34. USE lbclnk ! ocean lateral boundary conditions (or mpp link)
  35. USE lib_mpp ! MPP library
  36. USE wrk_nemo ! Memory Allocation
  37. USE timing ! Timing
  38. IMPLICIT NONE
  39. PRIVATE
  40. PUBLIC tra_zdf_imp ! routine called by step.F90
  41. REAL(wp) :: r_vvl ! variable volume indicator, =1 if lk_vvl=T, =0 otherwise
  42. !! * Substitutions
  43. # include "domzgr_substitute.h90"
  44. # include "ldftra_substitute.h90"
  45. # include "zdfddm_substitute.h90"
  46. # include "vectopt_loop_substitute.h90"
  47. !!----------------------------------------------------------------------
  48. !! NEMO/OPA 3.3 , NEMO Consortium (2010)
  49. !! $Id: trazdf_imp.F90 4990 2014-12-15 16:42:49Z timgraham $
  50. !! Software governed by the CeCILL licence (NEMOGCM/NEMO_CeCILL.txt)
  51. !!----------------------------------------------------------------------
  52. CONTAINS
  53. SUBROUTINE tra_zdf_imp( kt, kit000, cdtype, p2dt, ptb, pta, kjpt )
  54. !!----------------------------------------------------------------------
  55. !! *** ROUTINE tra_zdf_imp ***
  56. !!
  57. !! ** Purpose : Compute the after tracer through a implicit computation
  58. !! of the vertical tracer diffusion (including the vertical component
  59. !! of lateral mixing (only for 2nd order operator, for fourth order
  60. !! it is already computed and add to the general trend in traldf)
  61. !!
  62. !! ** Method : The vertical diffusion of the tracer t is given by:
  63. !! difft = dz( avt dz(t) ) = 1/e3t dk+1( avt/e3w dk(t) )
  64. !! It is computed using a backward time scheme (t=ta).
  65. !! If lk_zdfddm=T, use avs for salinity or for passive tracers
  66. !! Surface and bottom boundary conditions: no diffusive flux on
  67. !! both tracers (bottom, applied through the masked field avt).
  68. !! If iso-neutral mixing, add to avt the contribution due to lateral mixing.
  69. !!
  70. !! ** Action : - pta becomes the after tracer
  71. !!---------------------------------------------------------------------
  72. USE oce , ONLY: zwd => ua , zws => va ! (ua,va) used as 3D workspace
  73. !
  74. INTEGER , INTENT(in ) :: kt ! ocean time-step index
  75. INTEGER , INTENT(in ) :: kit000 ! first time step index
  76. CHARACTER(len=3) , INTENT(in ) :: cdtype ! =TRA or TRC (tracer indicator)
  77. INTEGER , INTENT(in ) :: kjpt ! number of tracers
  78. REAL(wp), DIMENSION( jpk ), INTENT(in ) :: p2dt ! vertical profile of tracer time-step
  79. REAL(wp), DIMENSION(jpi,jpj,jpk,kjpt), INTENT(in ) :: ptb ! before and now tracer fields
  80. REAL(wp), DIMENSION(jpi,jpj,jpk,kjpt), INTENT(inout) :: pta ! tracer trend
  81. !
  82. INTEGER :: ji, jj, jk, jn ! dummy loop indices
  83. REAL(wp) :: zrhs, ze3tb, ze3tn, ze3ta ! local scalars
  84. REAL(wp), POINTER, DIMENSION(:,:,:) :: zwi, zwt
  85. !!---------------------------------------------------------------------
  86. !
  87. IF( nn_timing == 1 ) CALL timing_start('tra_zdf_imp')
  88. !
  89. CALL wrk_alloc( jpi, jpj, jpk, zwi, zwt )
  90. !
  91. IF( kt == kit000 ) THEN
  92. IF(lwp)WRITE(numout,*)
  93. IF(lwp)WRITE(numout,*) 'tra_zdf_imp : implicit vertical mixing on ', cdtype
  94. IF(lwp)WRITE(numout,*) '~~~~~~~~~~~ '
  95. !
  96. IF( lk_vvl ) THEN ; r_vvl = 1._wp ! Variable volume indicator
  97. ELSE ; r_vvl = 0._wp
  98. ENDIF
  99. ENDIF
  100. !
  101. ! ! ============= !
  102. DO jn = 1, kjpt ! tracer loop !
  103. ! ! ============= !
  104. !
  105. ! Matrix construction
  106. ! --------------------
  107. ! Build matrix if temperature or salinity (only in double diffusion case) or first passive tracer
  108. !
  109. IF( ( cdtype == 'TRA' .AND. ( jn == jp_tem .OR. ( jn == jp_sal .AND. lk_zdfddm ) ) ) .OR. &
  110. & ( cdtype == 'TRC' .AND. jn == 1 ) ) THEN
  111. !
  112. ! vertical mixing coef.: avt for temperature, avs for salinity and passive tracers
  113. IF( cdtype == 'TRA' .AND. jn == jp_tem ) THEN ; zwt(:,:,2:jpk) = avt (:,:,2:jpk)
  114. ELSE ; zwt(:,:,2:jpk) = fsavs(:,:,2:jpk)
  115. ENDIF
  116. DO jj=1, jpj
  117. DO ji=1, jpi
  118. zwt(ji,jj,1) = 0._wp
  119. END DO
  120. END DO
  121. !
  122. #if defined key_ldfslp
  123. ! isoneutral diffusion: add the contribution
  124. IF( ln_traldf_grif ) THEN ! Griffies isoneutral diff
  125. DO jk = 2, jpkm1
  126. DO jj = 2, jpjm1
  127. DO ji = fs_2, fs_jpim1 ! vector opt.
  128. zwt(ji,jj,jk) = zwt(ji,jj,jk) + ah_wslp2(ji,jj,jk)
  129. END DO
  130. END DO
  131. END DO
  132. ELSE IF( l_traldf_rot ) THEN ! standard isoneutral diff
  133. DO jk = 2, jpkm1
  134. DO jj = 2, jpjm1
  135. DO ji = fs_2, fs_jpim1 ! vector opt.
  136. zwt(ji,jj,jk) = zwt(ji,jj,jk) + fsahtw(ji,jj,jk) &
  137. & * ( wslpi(ji,jj,jk) * wslpi(ji,jj,jk) &
  138. & + wslpj(ji,jj,jk) * wslpj(ji,jj,jk) )
  139. END DO
  140. END DO
  141. END DO
  142. ENDIF
  143. #endif
  144. ! Diagonal, lower (i), upper (s) (including the bottom boundary condition since avt is masked)
  145. DO jk = 1, jpkm1
  146. DO jj = 2, jpjm1
  147. DO ji = fs_2, fs_jpim1 ! vector opt.
  148. ze3ta = ( 1. - r_vvl ) + r_vvl * fse3t_a(ji,jj,jk) ! after scale factor at T-point
  149. ze3tn = r_vvl + ( 1. - r_vvl ) * fse3t_n(ji,jj,jk) ! now scale factor at T-point
  150. zwi(ji,jj,jk) = - p2dt(jk) * zwt(ji,jj,jk ) / ( ze3tn * fse3w(ji,jj,jk ) )
  151. zws(ji,jj,jk) = - p2dt(jk) * zwt(ji,jj,jk+1) / ( ze3tn * fse3w(ji,jj,jk+1) )
  152. zwd(ji,jj,jk) = ze3ta - zwi(ji,jj,jk) - zws(ji,jj,jk)
  153. END DO
  154. END DO
  155. END DO
  156. !
  157. !! Matrix inversion from the first level
  158. !!----------------------------------------------------------------------
  159. ! solve m.x = y where m is a tri diagonal matrix ( jpk*jpk )
  160. !
  161. ! ( zwd1 zws1 0 0 0 )( zwx1 ) ( zwy1 )
  162. ! ( zwi2 zwd2 zws2 0 0 )( zwx2 ) ( zwy2 )
  163. ! ( 0 zwi3 zwd3 zws3 0 )( zwx3 )=( zwy3 )
  164. ! ( ... )( ... ) ( ... )
  165. ! ( 0 0 0 zwik zwdk )( zwxk ) ( zwyk )
  166. !
  167. ! m is decomposed in the product of an upper and lower triangular matrix.
  168. ! The 3 diagonal terms are in 3d arrays: zwd, zws, zwi.
  169. ! Suffices i,s and d indicate "inferior" (below diagonal), diagonal
  170. ! and "superior" (above diagonal) components of the tridiagonal system.
  171. ! The solution will be in the 4d array pta.
  172. ! The 3d array zwt is used as a work space array.
  173. ! En route to the solution pta is used a to evaluate the rhs and then
  174. ! used as a work space array: its value is modified.
  175. !
  176. ! first recurrence: Tk = Dk - Ik Sk-1 / Tk-1 (increasing k)
  177. ! done once for all passive tracers (so included in the IF instruction)
  178. DO jj = 2, jpjm1
  179. DO ji = fs_2, fs_jpim1
  180. zwt(ji,jj,1) = zwd(ji,jj,1)
  181. END DO
  182. END DO
  183. DO jk = 2, jpkm1
  184. DO jj = 2, jpjm1
  185. DO ji = fs_2, fs_jpim1
  186. zwt(ji,jj,jk) = zwd(ji,jj,jk) - zwi(ji,jj,jk) * zws(ji,jj,jk-1) / zwt(ji,jj,jk-1)
  187. END DO
  188. END DO
  189. END DO
  190. !
  191. END IF
  192. !
  193. ! second recurrence: Zk = Yk - Ik / Tk-1 Zk-1
  194. DO jj = 2, jpjm1
  195. DO ji = fs_2, fs_jpim1
  196. ze3tb = ( 1. - r_vvl ) + r_vvl * fse3t_b(ji,jj,1)
  197. ze3tn = ( 1. - r_vvl ) + r_vvl * fse3t(ji,jj,1)
  198. pta(ji,jj,1,jn) = ze3tb * ptb(ji,jj,1,jn) &
  199. & + p2dt(1) * ze3tn * pta(ji,jj,1,jn)
  200. END DO
  201. END DO
  202. DO jk = 2, jpkm1
  203. DO jj = 2, jpjm1
  204. DO ji = fs_2, fs_jpim1
  205. ze3tb = ( 1. - r_vvl ) + r_vvl * fse3t_b(ji,jj,jk)
  206. ze3tn = ( 1. - r_vvl ) + r_vvl * fse3t (ji,jj,jk)
  207. zrhs = ze3tb * ptb(ji,jj,jk,jn) + p2dt(jk) * ze3tn * pta(ji,jj,jk,jn) ! zrhs=right hand side
  208. pta(ji,jj,jk,jn) = zrhs - zwi(ji,jj,jk) / zwt(ji,jj,jk-1) * pta(ji,jj,jk-1,jn)
  209. END DO
  210. END DO
  211. END DO
  212. ! third recurrence: Xk = (Zk - Sk Xk+1 ) / Tk (result is the after tracer)
  213. DO jj = 2, jpjm1
  214. DO ji = fs_2, fs_jpim1
  215. pta(ji,jj,jpkm1,jn) = pta(ji,jj,jpkm1,jn) / zwt(ji,jj,jpkm1) * tmask(ji,jj,jpkm1)
  216. END DO
  217. END DO
  218. DO jk = jpk-2, 1, -1
  219. DO jj = 2, jpjm1
  220. DO ji = fs_2, fs_jpim1
  221. pta(ji,jj,jk,jn) = ( pta(ji,jj,jk,jn) - zws(ji,jj,jk) * pta(ji,jj,jk+1,jn) ) &
  222. & / zwt(ji,jj,jk) * tmask(ji,jj,jk)
  223. END DO
  224. END DO
  225. END DO
  226. ! ! ================= !
  227. END DO ! end tracer loop !
  228. ! ! ================= !
  229. !
  230. CALL wrk_dealloc( jpi, jpj, jpk, zwi, zwt )
  231. !
  232. IF( nn_timing == 1 ) CALL timing_stop('tra_zdf_imp')
  233. !
  234. END SUBROUTINE tra_zdf_imp
  235. !!==============================================================================
  236. END MODULE trazdf_imp