traadv_tvd.F90 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776
  1. MODULE traadv_tvd
  2. !!==============================================================================
  3. !! *** MODULE traadv_tvd ***
  4. !! Ocean tracers: horizontal & vertical advective trend
  5. !!==============================================================================
  6. !! History : OPA ! 1995-12 (L. Mortier) Original code
  7. !! ! 2000-01 (H. Loukos) adapted to ORCA
  8. !! ! 2000-10 (MA Foujols E.Kestenare) include file not routine
  9. !! ! 2000-12 (E. Kestenare M. Levy) fix bug in trtrd indexes
  10. !! ! 2001-07 (E. Durand G. Madec) adaptation to ORCA config
  11. !! 8.5 ! 2002-06 (G. Madec) F90: Free form and module
  12. !! NEMO 1.0 ! 2004-01 (A. de Miranda, G. Madec, J.M. Molines ): advective bbl
  13. !! 2.0 ! 2008-04 (S. Cravatte) add the i-, j- & k- trends computation
  14. !! - ! 2009-11 (V. Garnier) Surface pressure gradient organization
  15. !! 3.3 ! 2010-05 (C. Ethe, G. Madec) merge TRC-TRA + switch from velocity to transport
  16. !!----------------------------------------------------------------------
  17. !!----------------------------------------------------------------------
  18. !! tra_adv_tvd : update the tracer trend with the 3D advection trends using a TVD scheme
  19. !! nonosc : compute monotonic tracer fluxes by a non-oscillatory algorithm
  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 trd_oce ! trends: ocean variables
  25. USE trdtra ! tracers trends
  26. USE dynspg_oce ! choice/control of key cpp for surface pressure gradient
  27. USE diaptr ! poleward transport diagnostics
  28. USE phycst
  29. !
  30. USE lib_mpp ! MPP library
  31. USE lbclnk ! ocean lateral boundary condition (or mpp link)
  32. USE in_out_manager ! I/O manager
  33. USE wrk_nemo ! Memory Allocation
  34. USE timing ! Timing
  35. USE lib_fortran ! Fortran utilities (allows no signed zero when 'key_nosignedzero' defined)
  36. USE iom
  37. IMPLICIT NONE
  38. PRIVATE
  39. PUBLIC tra_adv_tvd ! routine called by traadv.F90
  40. PUBLIC tra_adv_tvd_zts ! routine called by traadv.F90
  41. LOGICAL :: l_trd ! flag to compute trends
  42. LOGICAL :: l_trans ! flag to output vertically integrated transports
  43. !! * Substitutions
  44. # include "domzgr_substitute.h90"
  45. # include "vectopt_loop_substitute.h90"
  46. !!----------------------------------------------------------------------
  47. !! NEMO/OPA 3.3 , NEMO Consortium (2010)
  48. !! $Id: traadv_tvd.F90 7561 2017-01-16 13:41:01Z timgraham $
  49. !! Software governed by the CeCILL licence (NEMOGCM/NEMO_CeCILL.txt)
  50. !!----------------------------------------------------------------------
  51. CONTAINS
  52. SUBROUTINE tra_adv_tvd ( kt, kit000, cdtype, p2dt, pun, pvn, pwn, &
  53. & ptb, ptn, pta, kjpt, ld_dia )
  54. !!----------------------------------------------------------------------
  55. !! *** ROUTINE tra_adv_tvd ***
  56. !!
  57. !! ** Purpose : Compute the now trend due to total advection of
  58. !! tracers and add it to the general trend of tracer equations
  59. !!
  60. !! ** Method : TVD scheme, i.e. 2nd order centered scheme with
  61. !! corrected flux (monotonic correction)
  62. !! note: - this advection scheme needs a leap-frog time scheme
  63. !!
  64. !! ** Action : - update (pta) with the now advective tracer trends
  65. !! - save the trends
  66. !!----------------------------------------------------------------------
  67. USE oce , ONLY: zwx => ua , zwy => va ! (ua,va) used as workspace
  68. !
  69. INTEGER , INTENT(in ) :: kt ! ocean time-step index
  70. INTEGER , INTENT(in ) :: kit000 ! first time step index
  71. CHARACTER(len=3) , INTENT(in ) :: cdtype ! =TRA or TRC (tracer indicator)
  72. INTEGER , INTENT(in ) :: kjpt ! number of tracers
  73. REAL(wp), DIMENSION( jpk ), INTENT(in ) :: p2dt ! vertical profile of tracer time-step
  74. REAL(wp), DIMENSION(jpi,jpj,jpk ), INTENT(in ) :: pun, pvn, pwn ! 3 ocean velocity components
  75. REAL(wp), DIMENSION(jpi,jpj,jpk,kjpt), INTENT(in ) :: ptb, ptn ! before and now tracer fields
  76. REAL(wp), DIMENSION(jpi,jpj,jpk,kjpt), INTENT(inout) :: pta ! tracer trend
  77. LOGICAL , OPTIONAL, INTENT(in) :: ld_dia ! computation of trends diag
  78. !
  79. INTEGER :: ji, jj, jk, jn ! dummy loop indices
  80. INTEGER :: ik
  81. REAL(wp) :: z2dtt, zbtr, ztra ! local scalar
  82. REAL(wp) :: zfp_ui, zfp_vj, zfp_wk ! - -
  83. REAL(wp) :: zfm_ui, zfm_vj, zfm_wk ! - -
  84. REAL(wp), POINTER, DIMENSION(:,:,:) :: zwi, zwz
  85. REAL(wp), POINTER, DIMENSION(:,:,:) :: ztrdx, ztrdy, ztrdz, zptry
  86. REAL(wp), POINTER, DIMENSION(:,:) :: z2d
  87. !!----------------------------------------------------------------------
  88. !
  89. IF( nn_timing == 1 ) CALL timing_start('tra_adv_tvd')
  90. !
  91. CALL wrk_alloc( jpi, jpj, jpk, zwi, zwz )
  92. !
  93. IF( kt == kit000 ) THEN
  94. IF(lwp) WRITE(numout,*)
  95. IF( PRESENT( ld_dia ) ) THEN
  96. IF(lwp) WRITE(numout,*) 'tra_adv_tvd : TVD advection scheme on ', cdtype, ' for eiv trends diagnostics only'
  97. ELSE
  98. IF(lwp) WRITE(numout,*) 'tra_adv_tvd : TVD advection scheme on ', cdtype
  99. ENDIF
  100. IF(lwp) WRITE(numout,*) '~~~~~~~~~~~'
  101. !
  102. ENDIF
  103. l_trd = .FALSE.
  104. l_trans = .FALSE.
  105. IF( ( cdtype == 'TRA' .AND. l_trdtra ) .OR. ( cdtype == 'TRC' .AND. l_trdtrc ) ) l_trd = .TRUE.
  106. IF( cdtype == 'TRA' .AND. (iom_use("uadv_heattr") .OR. iom_use("vadv_heattr") ) ) l_trans = .TRUE.
  107. !
  108. IF( PRESENT( ld_dia ) ) THEN
  109. l_trd = .FALSE.
  110. l_trans = .FALSE.
  111. ENDIF
  112. !
  113. IF( l_trd .OR. l_trans ) THEN
  114. CALL wrk_alloc( jpi, jpj, jpk, ztrdx, ztrdy, ztrdz )
  115. CALL wrk_alloc( jpi, jpj, z2d )
  116. ztrdx(:,:,:) = 0.e0 ; ztrdy(:,:,:) = 0.e0 ; ztrdz(:,:,:) = 0.e0
  117. ENDIF
  118. !
  119. IF( cdtype == 'TRA' .AND. ln_diaptr ) THEN
  120. CALL wrk_alloc( jpi, jpj, jpk, zptry )
  121. zptry(:,:,:) = 0._wp
  122. ENDIF
  123. !
  124. zwi(:,:,:) = 0.e0 ;
  125. !
  126. ! ! ===========
  127. DO jn = 1, kjpt ! tracer loop
  128. ! ! ===========
  129. ! 1. Bottom and k=1 value : flux set to zero
  130. ! ----------------------------------
  131. zwx(:,:,jpk) = 0.e0 ; zwz(:,:,jpk) = 0.e0
  132. zwy(:,:,jpk) = 0.e0 ; zwi(:,:,jpk) = 0.e0
  133. zwz(:,:,1 ) = 0._wp
  134. ! 2. upstream advection with initial mass fluxes & intermediate update
  135. ! --------------------------------------------------------------------
  136. ! upstream tracer flux in the i and j direction
  137. DO jk = 1, jpkm1
  138. DO jj = 1, jpjm1
  139. DO ji = 1, fs_jpim1 ! vector opt.
  140. ! upstream scheme
  141. zfp_ui = pun(ji,jj,jk) + ABS( pun(ji,jj,jk) )
  142. zfm_ui = pun(ji,jj,jk) - ABS( pun(ji,jj,jk) )
  143. zfp_vj = pvn(ji,jj,jk) + ABS( pvn(ji,jj,jk) )
  144. zfm_vj = pvn(ji,jj,jk) - ABS( pvn(ji,jj,jk) )
  145. zwx(ji,jj,jk) = 0.5 * ( zfp_ui * ptb(ji,jj,jk,jn) + zfm_ui * ptb(ji+1,jj ,jk,jn) )
  146. zwy(ji,jj,jk) = 0.5 * ( zfp_vj * ptb(ji,jj,jk,jn) + zfm_vj * ptb(ji ,jj+1,jk,jn) )
  147. END DO
  148. END DO
  149. END DO
  150. ! upstream tracer flux in the k direction
  151. ! Interior value
  152. DO jk = 2, jpkm1
  153. DO jj = 1, jpj
  154. DO ji = 1, jpi
  155. zfp_wk = pwn(ji,jj,jk) + ABS( pwn(ji,jj,jk) )
  156. zfm_wk = pwn(ji,jj,jk) - ABS( pwn(ji,jj,jk) )
  157. zwz(ji,jj,jk) = 0.5 * ( zfp_wk * ptb(ji,jj,jk,jn) + zfm_wk * ptb(ji,jj,jk-1,jn) ) * wmask(ji,jj,jk)
  158. END DO
  159. END DO
  160. END DO
  161. ! Surface value
  162. IF( lk_vvl ) THEN
  163. IF ( ln_isfcav ) THEN
  164. DO jj = 1, jpj
  165. DO ji = 1, jpi
  166. zwz(ji,jj, mikt(ji,jj) ) = 0.e0 ! volume variable
  167. END DO
  168. END DO
  169. ELSE
  170. zwz(:,:,1) = 0.e0 ! volume variable
  171. END IF
  172. ELSE
  173. IF ( ln_isfcav ) THEN
  174. DO jj = 1, jpj
  175. DO ji = 1, jpi
  176. zwz(ji,jj, mikt(ji,jj) ) = pwn(ji,jj,mikt(ji,jj)) * ptb(ji,jj,mikt(ji,jj),jn) ! linear free surface
  177. END DO
  178. END DO
  179. ELSE
  180. zwz(:,:,1) = pwn(:,:,1) * ptb(:,:,1,jn) ! linear free surface
  181. END IF
  182. ENDIF
  183. ! total advective trend
  184. DO jk = 1, jpkm1
  185. z2dtt = p2dt(jk)
  186. DO jj = 2, jpjm1
  187. DO ji = fs_2, fs_jpim1 ! vector opt.
  188. ! total intermediate advective trends
  189. ztra = - ( zwx(ji,jj,jk) - zwx(ji-1,jj ,jk ) &
  190. & + zwy(ji,jj,jk) - zwy(ji ,jj-1,jk ) &
  191. & + zwz(ji,jj,jk) - zwz(ji ,jj ,jk+1) ) / e1e2t(ji,jj)
  192. ! update and guess with monotonic sheme
  193. pta(ji,jj,jk,jn) = pta(ji,jj,jk,jn) + ztra / fse3t_n(ji,jj,jk) * tmask(ji,jj,jk)
  194. zwi(ji,jj,jk) = ( fse3t_b(ji,jj,jk) * ptb(ji,jj,jk,jn) + z2dtt * ztra ) / fse3t_a(ji,jj,jk) * tmask(ji,jj,jk)
  195. END DO
  196. END DO
  197. END DO
  198. ! ! Lateral boundary conditions on zwi (unchanged sign)
  199. CALL lbc_lnk( zwi, 'T', 1. )
  200. ! ! trend diagnostics (contribution of upstream fluxes)
  201. IF( l_trd .OR. l_trans ) THEN
  202. ! store intermediate advective trends
  203. ztrdx(:,:,:) = zwx(:,:,:) ; ztrdy(:,:,:) = zwy(:,:,:) ; ztrdz(:,:,:) = zwz(:,:,:)
  204. END IF
  205. ! ! "Poleward" heat and salt transports (contribution of upstream fluxes)
  206. IF( cdtype == 'TRA' .AND. ln_diaptr ) zptry(:,:,:) = zwy(:,:,:)
  207. ! 3. antidiffusive flux : high order minus low order
  208. ! --------------------------------------------------
  209. ! antidiffusive flux on i and j
  210. DO jk = 1, jpkm1
  211. DO jj = 1, jpjm1
  212. DO ji = 1, fs_jpim1 ! vector opt.
  213. zwx(ji,jj,jk) = 0.5 * pun(ji,jj,jk) * ( ptn(ji,jj,jk,jn) + ptn(ji+1,jj,jk,jn) ) - zwx(ji,jj,jk)
  214. zwy(ji,jj,jk) = 0.5 * pvn(ji,jj,jk) * ( ptn(ji,jj,jk,jn) + ptn(ji,jj+1,jk,jn) ) - zwy(ji,jj,jk)
  215. END DO
  216. END DO
  217. END DO
  218. ! antidiffusive flux on k
  219. ! Interior value
  220. DO jk = 2, jpkm1
  221. DO jj = 1, jpj
  222. DO ji = 1, jpi
  223. zwz(ji,jj,jk) = 0.5 * pwn(ji,jj,jk) * ( ptn(ji,jj,jk,jn) + ptn(ji,jj,jk-1,jn) ) - zwz(ji,jj,jk)
  224. END DO
  225. END DO
  226. END DO
  227. ! surface value
  228. IF ( ln_isfcav ) THEN
  229. DO jj = 1, jpj
  230. DO ji = 1, jpi
  231. zwz(ji,jj,mikt(ji,jj)) = 0.e0
  232. END DO
  233. END DO
  234. ELSE
  235. zwz(:,:,1) = 0.e0
  236. END IF
  237. CALL lbc_lnk( zwx, 'U', -1. ) ; CALL lbc_lnk( zwy, 'V', -1. ) ! Lateral bondary conditions
  238. CALL lbc_lnk( zwz, 'W', 1. )
  239. ! 4. monotonicity algorithm
  240. ! -------------------------
  241. CALL nonosc( ptb(:,:,:,jn), zwx, zwy, zwz, zwi, p2dt )
  242. ! 5. final trend with corrected fluxes
  243. ! ------------------------------------
  244. DO jk = 1, jpkm1
  245. DO jj = 2, jpjm1
  246. DO ji = fs_2, fs_jpim1 ! vector opt.
  247. zbtr = 1. / ( e1t(ji,jj) * e2t(ji,jj) * fse3t(ji,jj,jk) )
  248. ! total advective trends
  249. ztra = - zbtr * ( zwx(ji,jj,jk) - zwx(ji-1,jj ,jk ) &
  250. & + zwy(ji,jj,jk) - zwy(ji ,jj-1,jk ) &
  251. & + zwz(ji,jj,jk) - zwz(ji ,jj ,jk+1) )
  252. ! add them to the general tracer trends
  253. pta(ji,jj,jk,jn) = pta(ji,jj,jk,jn) + ztra * tmask(ji,jj,jk)
  254. END DO
  255. END DO
  256. END DO
  257. ! ! trend diagnostics (contribution of upstream fluxes)
  258. IF( l_trd .OR. l_trans ) THEN
  259. ztrdx(:,:,:) = ztrdx(:,:,:) + zwx(:,:,:) ! <<< Add to previously computed
  260. ztrdy(:,:,:) = ztrdy(:,:,:) + zwy(:,:,:) ! <<< Add to previously computed
  261. ztrdz(:,:,:) = ztrdz(:,:,:) + zwz(:,:,:) ! <<< Add to previously computed
  262. ENDIF
  263. IF( l_trd ) THEN
  264. CALL trd_tra( kt, cdtype, jn, jptra_xad, ztrdx, pun, ptn(:,:,:,jn) )
  265. CALL trd_tra( kt, cdtype, jn, jptra_yad, ztrdy, pvn, ptn(:,:,:,jn) )
  266. CALL trd_tra( kt, cdtype, jn, jptra_zad, ztrdz, pwn, ptn(:,:,:,jn) )
  267. END IF
  268. IF( l_trans .AND. jn==jp_tem ) THEN
  269. z2d(:,:) = 0._wp
  270. DO jk = 1, jpkm1
  271. DO jj = 2, jpjm1
  272. DO ji = fs_2, fs_jpim1 ! vector opt.
  273. z2d(ji,jj) = z2d(ji,jj) + ztrdx(ji,jj,jk)
  274. END DO
  275. END DO
  276. END DO
  277. z2d(:,:) = rau0_rcp * z2d(:,:)
  278. CALL lbc_lnk( z2d, 'U', -1. )
  279. CALL iom_put( "uadv_heattr", z2d ) ! heat transport in i-direction
  280. !
  281. z2d(:,:) = 0._wp
  282. DO jk = 1, jpkm1
  283. DO jj = 2, jpjm1
  284. DO ji = fs_2, fs_jpim1 ! vector opt.
  285. z2d(ji,jj) = z2d(ji,jj) + ztrdy(ji,jj,jk)
  286. END DO
  287. END DO
  288. END DO
  289. z2d(:,:) = rau0_rcp * z2d(:,:)
  290. CALL lbc_lnk( z2d, 'V', -1. )
  291. CALL iom_put( "vadv_heattr", z2d ) ! heat transport in j-direction
  292. ENDIF
  293. ! "Poleward" heat and salt transports (contribution of upstream fluxes)
  294. IF( cdtype == 'TRA' .AND. ln_diaptr ) THEN
  295. zptry(:,:,:) = zptry(:,:,:) + zwy(:,:,:) ! <<< Add to previously computed
  296. CALL dia_ptr_ohst_components( jn, 'adv', zptry(:,:,:) )
  297. ENDIF
  298. !
  299. END DO
  300. !
  301. CALL wrk_dealloc( jpi, jpj, jpk, zwi, zwz )
  302. IF( l_trd .OR. l_trans ) THEN
  303. CALL wrk_dealloc( jpi, jpj, jpk, ztrdx, ztrdy, ztrdz )
  304. CALL wrk_dealloc( jpi, jpj, z2d )
  305. ENDIF
  306. IF( cdtype == 'TRA' .AND. ln_diaptr ) CALL wrk_dealloc( jpi, jpj, jpk, zptry )
  307. !
  308. IF( nn_timing == 1 ) CALL timing_stop('tra_adv_tvd')
  309. !
  310. END SUBROUTINE tra_adv_tvd
  311. SUBROUTINE tra_adv_tvd_zts ( kt, kit000, cdtype, p2dt, pun, pvn, pwn, &
  312. & ptb, ptn, pta, kjpt )
  313. !!----------------------------------------------------------------------
  314. !! *** ROUTINE tra_adv_tvd_zts ***
  315. !!
  316. !! ** Purpose : Compute the now trend due to total advection of
  317. !! tracers and add it to the general trend of tracer equations
  318. !!
  319. !! ** Method : TVD ZTS scheme, i.e. 2nd order centered scheme with
  320. !! corrected flux (monotonic correction). This version use sub-
  321. !! timestepping for the vertical advection which increases stability
  322. !! when vertical metrics are small.
  323. !! note: - this advection scheme needs a leap-frog time scheme
  324. !!
  325. !! ** Action : - update (pta) with the now advective tracer trends
  326. !! - save the trends
  327. !!----------------------------------------------------------------------
  328. USE oce , ONLY: zwx => ua , zwy => va ! (ua,va) used as workspace
  329. !
  330. INTEGER , INTENT(in ) :: kt ! ocean time-step index
  331. INTEGER , INTENT(in ) :: kit000 ! first time step index
  332. CHARACTER(len=3) , INTENT(in ) :: cdtype ! =TRA or TRC (tracer indicator)
  333. INTEGER , INTENT(in ) :: kjpt ! number of tracers
  334. REAL(wp), DIMENSION( jpk ), INTENT(in ) :: p2dt ! vertical profile of tracer time-step
  335. REAL(wp), DIMENSION(jpi,jpj,jpk ), INTENT(in ) :: pun, pvn, pwn ! 3 ocean velocity components
  336. REAL(wp), DIMENSION(jpi,jpj,jpk,kjpt), INTENT(in ) :: ptb, ptn ! before and now tracer fields
  337. REAL(wp), DIMENSION(jpi,jpj,jpk,kjpt), INTENT(inout) :: pta ! tracer trend
  338. !
  339. REAL(wp), DIMENSION( jpk ) :: zts ! length of sub-timestep for vertical advection
  340. REAL(wp), DIMENSION( jpk ) :: zr_p2dt ! reciprocal of tracer timestep
  341. INTEGER :: ji, jj, jk, jl, jn ! dummy loop indices
  342. INTEGER :: jnzts = 5 ! number of sub-timesteps for vertical advection
  343. INTEGER :: jtb, jtn, jta ! sub timestep pointers for leap-frog/euler forward steps
  344. INTEGER :: jtaken ! toggle for collecting appropriate fluxes from sub timesteps
  345. REAL(wp) :: z_rzts ! Fractional length of Euler forward sub-timestep for vertical advection
  346. REAL(wp) :: z2dtt, zbtr, ztra ! local scalar
  347. REAL(wp) :: zfp_ui, zfp_vj, zfp_wk ! - -
  348. REAL(wp) :: zfm_ui, zfm_vj, zfm_wk ! - -
  349. REAL(wp), POINTER, DIMENSION(:,: ) :: zwx_sav , zwy_sav
  350. REAL(wp), POINTER, DIMENSION(:,:,:) :: zwi, zwz, zhdiv, zwz_sav, zwzts
  351. REAL(wp), POINTER, DIMENSION(:,:,:) :: ztrdx, ztrdy, ztrdz
  352. REAL(wp), POINTER, DIMENSION(:,:,:) :: zptry
  353. REAL(wp), POINTER, DIMENSION(:,:,:,:) :: ztrs
  354. REAL(wp), POINTER, DIMENSION(:,:) :: z2d
  355. !!----------------------------------------------------------------------
  356. !
  357. IF( nn_timing == 1 ) CALL timing_start('tra_adv_tvd_zts')
  358. !
  359. CALL wrk_alloc( jpi, jpj, zwx_sav, zwy_sav )
  360. CALL wrk_alloc( jpi, jpj, jpk, zwi, zwz , zhdiv, zwz_sav, zwzts )
  361. CALL wrk_alloc( jpi, jpj, jpk, kjpt+1, ztrs )
  362. !
  363. IF( kt == kit000 ) THEN
  364. IF(lwp) WRITE(numout,*)
  365. IF(lwp) WRITE(numout,*) 'tra_adv_tvd_zts : TVD ZTS advection scheme on ', cdtype
  366. IF(lwp) WRITE(numout,*) '~~~~~~~~~~~'
  367. ENDIF
  368. !
  369. l_trd = .FALSE.
  370. l_trans = .FALSE.
  371. IF( ( cdtype == 'TRA' .AND. l_trdtra ) .OR. ( cdtype == 'TRC' .AND. l_trdtrc ) ) l_trd = .TRUE.
  372. IF( cdtype == 'TRA' .AND. (iom_use("uadv_heattr") .OR. iom_use("vadv_heattr") ) ) l_trans = .TRUE.
  373. !
  374. IF( l_trd .OR. l_trans ) THEN
  375. CALL wrk_alloc( jpi, jpj, jpk, ztrdx, ztrdy, ztrdz )
  376. CALL wrk_alloc( jpi, jpj, z2d )
  377. ztrdx(:,:,:) = 0.e0 ; ztrdy(:,:,:) = 0.e0 ; ztrdz(:,:,:) = 0.e0
  378. ENDIF
  379. !
  380. IF( cdtype == 'TRA' .AND. ln_diaptr ) THEN
  381. CALL wrk_alloc( jpi, jpj,jpk, zptry )
  382. zptry(:,:,:) = 0._wp
  383. ENDIF
  384. !
  385. zwi(:,:,:) = 0._wp
  386. z_rzts = 1._wp / REAL( jnzts, wp )
  387. zr_p2dt(:) = 1._wp / p2dt(:)
  388. !
  389. ! ! ===========
  390. DO jn = 1, kjpt ! tracer loop
  391. ! ! ===========
  392. ! 1. Bottom value : flux set to zero
  393. ! ----------------------------------
  394. zwx(:,:,jpk) = 0._wp ; zwz(:,:,jpk) = 0._wp
  395. zwy(:,:,jpk) = 0._wp ; zwi(:,:,jpk) = 0._wp
  396. ! 2. upstream advection with initial mass fluxes & intermediate update
  397. ! --------------------------------------------------------------------
  398. ! upstream tracer flux in the i and j direction
  399. DO jk = 1, jpkm1
  400. DO jj = 1, jpjm1
  401. DO ji = 1, fs_jpim1 ! vector opt.
  402. ! upstream scheme
  403. zfp_ui = pun(ji,jj,jk) + ABS( pun(ji,jj,jk) )
  404. zfm_ui = pun(ji,jj,jk) - ABS( pun(ji,jj,jk) )
  405. zfp_vj = pvn(ji,jj,jk) + ABS( pvn(ji,jj,jk) )
  406. zfm_vj = pvn(ji,jj,jk) - ABS( pvn(ji,jj,jk) )
  407. zwx(ji,jj,jk) = 0.5_wp * ( zfp_ui * ptb(ji,jj,jk,jn) + zfm_ui * ptb(ji+1,jj ,jk,jn) )
  408. zwy(ji,jj,jk) = 0.5_wp * ( zfp_vj * ptb(ji,jj,jk,jn) + zfm_vj * ptb(ji ,jj+1,jk,jn) )
  409. END DO
  410. END DO
  411. END DO
  412. ! upstream tracer flux in the k direction
  413. ! Interior value
  414. DO jk = 2, jpkm1
  415. DO jj = 1, jpj
  416. DO ji = 1, jpi
  417. zfp_wk = pwn(ji,jj,jk) + ABS( pwn(ji,jj,jk) )
  418. zfm_wk = pwn(ji,jj,jk) - ABS( pwn(ji,jj,jk) )
  419. zwz(ji,jj,jk) = 0.5_wp * ( zfp_wk * ptb(ji,jj,jk,jn) + zfm_wk * ptb(ji,jj,jk-1,jn) )
  420. END DO
  421. END DO
  422. END DO
  423. ! Surface value
  424. IF( lk_vvl ) THEN
  425. IF ( ln_isfcav ) THEN
  426. DO jj = 1, jpj
  427. DO ji = 1, jpi
  428. zwz(ji,jj, mikt(ji,jj) ) = 0.e0 ! volume variable + isf
  429. END DO
  430. END DO
  431. ELSE
  432. zwz(:,:,1) = 0.e0 ! volume variable + no isf
  433. END IF
  434. ELSE
  435. IF ( ln_isfcav ) THEN
  436. DO jj = 1, jpj
  437. DO ji = 1, jpi
  438. zwz(ji,jj, mikt(ji,jj) ) = pwn(ji,jj,mikt(ji,jj)) * ptb(ji,jj,mikt(ji,jj),jn) ! linear free surface + isf
  439. END DO
  440. END DO
  441. ELSE
  442. zwz(:,:,1) = pwn(:,:,1) * ptb(:,:,1,jn) ! linear free surface + no isf
  443. END IF
  444. ENDIF
  445. ! total advective trend
  446. DO jk = 1, jpkm1
  447. z2dtt = p2dt(jk)
  448. DO jj = 2, jpjm1
  449. DO ji = fs_2, fs_jpim1 ! vector opt.
  450. ! total intermediate advective trends
  451. ztra = - ( zwx(ji,jj,jk) - zwx(ji-1,jj ,jk ) &
  452. & + zwy(ji,jj,jk) - zwy(ji ,jj-1,jk ) &
  453. & + zwz(ji,jj,jk) - zwz(ji ,jj ,jk+1) ) / e1e2t(ji,jj)
  454. ! update and guess with monotonic sheme
  455. pta(ji,jj,jk,jn) = pta(ji,jj,jk,jn) + ztra / fse3t_n(ji,jj,jk) * tmask(ji,jj,jk)
  456. zwi(ji,jj,jk) = ( fse3t_b(ji,jj,jk) * ptb(ji,jj,jk,jn) + z2dtt * ztra ) / fse3t_a(ji,jj,jk) * tmask(ji,jj,jk)
  457. END DO
  458. END DO
  459. END DO
  460. ! ! Lateral boundary conditions on zwi (unchanged sign)
  461. CALL lbc_lnk( zwi, 'T', 1. )
  462. ! ! trend diagnostics (contribution of upstream fluxes)
  463. IF( l_trd .OR. l_trans ) THEN
  464. ! store intermediate advective trends
  465. ztrdx(:,:,:) = zwx(:,:,:) ; ztrdy(:,:,:) = zwy(:,:,:) ; ztrdz(:,:,:) = zwz(:,:,:)
  466. END IF
  467. ! ! "Poleward" heat and salt transports (contribution of upstream fluxes)
  468. IF( cdtype == 'TRA' .AND. ln_diaptr ) zptry(:,:,:) = zwy(:,:,:)
  469. ! 3. antidiffusive flux : high order minus low order
  470. ! --------------------------------------------------
  471. ! antidiffusive flux on i and j
  472. !
  473. DO jk = 1, jpkm1
  474. !
  475. DO jj = 1, jpjm1
  476. DO ji = 1, fs_jpim1 ! vector opt.
  477. zwx_sav(ji,jj) = zwx(ji,jj,jk)
  478. zwy_sav(ji,jj) = zwy(ji,jj,jk)
  479. zwx(ji,jj,jk) = 0.5_wp * pun(ji,jj,jk) * ( ptn(ji,jj,jk,jn) + ptn(ji+1,jj,jk,jn) )
  480. zwy(ji,jj,jk) = 0.5_wp * pvn(ji,jj,jk) * ( ptn(ji,jj,jk,jn) + ptn(ji,jj+1,jk,jn) )
  481. END DO
  482. END DO
  483. DO jj = 2, jpjm1 ! partial horizontal divergence
  484. DO ji = fs_2, fs_jpim1
  485. zhdiv(ji,jj,jk) = ( zwx(ji,jj,jk) - zwx(ji-1,jj ,jk) &
  486. & + zwy(ji,jj,jk) - zwy(ji ,jj-1,jk) )
  487. END DO
  488. END DO
  489. DO jj = 1, jpjm1
  490. DO ji = 1, fs_jpim1 ! vector opt.
  491. zwx(ji,jj,jk) = zwx(ji,jj,jk) - zwx_sav(ji,jj)
  492. zwy(ji,jj,jk) = zwy(ji,jj,jk) - zwy_sav(ji,jj)
  493. END DO
  494. END DO
  495. END DO
  496. ! antidiffusive flux on k
  497. zwz(:,:,1) = 0._wp ! Surface value
  498. zwz_sav(:,:,:) = zwz(:,:,:)
  499. !
  500. ztrs(:,:,:,1) = ptb(:,:,:,jn)
  501. ztrs(:,:,1,2) = ptb(:,:,1,jn)
  502. ztrs(:,:,1,3) = ptb(:,:,1,jn)
  503. zwzts(:,:,:) = 0._wp
  504. DO jl = 1, jnzts ! Start of sub timestepping loop
  505. IF( jl == 1 ) THEN ! Euler forward to kick things off
  506. jtb = 1 ; jtn = 1 ; jta = 2
  507. zts(:) = p2dt(:) * z_rzts
  508. jtaken = MOD( jnzts + 1 , 2) ! Toggle to collect every second flux
  509. ! starting at jl =1 if jnzts is odd;
  510. ! starting at jl =2 otherwise
  511. ELSEIF( jl == 2 ) THEN ! First leapfrog step
  512. jtb = 1 ; jtn = 2 ; jta = 3
  513. zts(:) = 2._wp * p2dt(:) * z_rzts
  514. ELSE ! Shuffle pointers for subsequent leapfrog steps
  515. jtb = MOD(jtb,3) + 1
  516. jtn = MOD(jtn,3) + 1
  517. jta = MOD(jta,3) + 1
  518. ENDIF
  519. DO jk = 2, jpkm1 ! Interior value
  520. DO jj = 2, jpjm1
  521. DO ji = fs_2, fs_jpim1
  522. zwz(ji,jj,jk) = 0.5_wp * pwn(ji,jj,jk) * ( ztrs(ji,jj,jk,jtn) + ztrs(ji,jj,jk-1,jtn) )
  523. IF( jtaken == 0 ) zwzts(ji,jj,jk) = zwzts(ji,jj,jk) + zwz(ji,jj,jk)*zts(jk) ! Accumulate time-weighted vertcal flux
  524. END DO
  525. END DO
  526. END DO
  527. jtaken = MOD( jtaken + 1 , 2 )
  528. DO jk = 2, jpkm1 ! Interior value
  529. DO jj = 2, jpjm1
  530. DO ji = fs_2, fs_jpim1
  531. zbtr = 1._wp / ( e1t(ji,jj) * e2t(ji,jj) * fse3t(ji,jj,jk) )
  532. ! total advective trends
  533. ztra = - zbtr * ( zhdiv(ji,jj,jk) + zwz(ji,jj,jk) - zwz(ji ,jj ,jk+1) )
  534. ztrs(ji,jj,jk,jta) = ztrs(ji,jj,jk,jtb) + zts(jk) * ztra
  535. END DO
  536. END DO
  537. END DO
  538. END DO
  539. DO jk = 2, jpkm1 ! Anti-diffusive vertical flux using average flux from the sub-timestepping
  540. DO jj = 2, jpjm1
  541. DO ji = fs_2, fs_jpim1
  542. zwz(ji,jj,jk) = zwzts(ji,jj,jk) * zr_p2dt(jk) - zwz_sav(ji,jj,jk)
  543. END DO
  544. END DO
  545. END DO
  546. CALL lbc_lnk( zwx, 'U', -1. ) ; CALL lbc_lnk( zwy, 'V', -1. ) ! Lateral bondary conditions
  547. CALL lbc_lnk( zwz, 'W', 1. )
  548. ! 4. monotonicity algorithm
  549. ! -------------------------
  550. CALL nonosc( ptb(:,:,:,jn), zwx, zwy, zwz, zwi, p2dt )
  551. ! 5. final trend with corrected fluxes
  552. ! ------------------------------------
  553. DO jk = 1, jpkm1
  554. DO jj = 2, jpjm1
  555. DO ji = fs_2, fs_jpim1 ! vector opt.
  556. zbtr = 1. / ( e1t(ji,jj) * e2t(ji,jj) * fse3t(ji,jj,jk) )
  557. ! total advective trends
  558. ztra = - zbtr * ( zwx(ji,jj,jk) - zwx(ji-1,jj ,jk ) &
  559. & + zwy(ji,jj,jk) - zwy(ji ,jj-1,jk ) &
  560. & + zwz(ji,jj,jk) - zwz(ji ,jj ,jk+1) )
  561. ! add them to the general tracer trends
  562. pta(ji,jj,jk,jn) = pta(ji,jj,jk,jn) + ztra
  563. END DO
  564. END DO
  565. END DO
  566. ! ! trend diagnostics (contribution of upstream fluxes)
  567. IF( l_trd .OR. l_trans ) THEN
  568. ztrdx(:,:,:) = ztrdx(:,:,:) + zwx(:,:,:) ! <<< Add to previously computed
  569. ztrdy(:,:,:) = ztrdy(:,:,:) + zwy(:,:,:) ! <<< Add to previously computed
  570. ztrdz(:,:,:) = ztrdz(:,:,:) + zwz(:,:,:) ! <<< Add to previously computed
  571. ENDIF
  572. IF( l_trd ) THEN
  573. CALL trd_tra( kt, cdtype, jn, jptra_xad, ztrdx, pun, ptn(:,:,:,jn) )
  574. CALL trd_tra( kt, cdtype, jn, jptra_yad, ztrdy, pvn, ptn(:,:,:,jn) )
  575. CALL trd_tra( kt, cdtype, jn, jptra_zad, ztrdz, pwn, ptn(:,:,:,jn) )
  576. ENDIF
  577. !
  578. IF( l_trans .AND. jn==jp_tem ) THEN
  579. z2d(:,:) = 0._wp
  580. DO jk = 1, jpkm1
  581. DO jj = 2, jpjm1
  582. DO ji = fs_2, fs_jpim1 ! vector opt.
  583. z2d(ji,jj) = z2d(ji,jj) + ztrdx(ji,jj,jk)
  584. END DO
  585. END DO
  586. END DO
  587. z2d(:,:) = rau0_rcp * z2d(:,:)
  588. CALL lbc_lnk( z2d, 'U', -1. )
  589. CALL iom_put( "uadv_heattr", z2d ) ! heat transport in i-direction
  590. !
  591. z2d(:,:) = 0._wp
  592. DO jk = 1, jpkm1
  593. DO jj = 2, jpjm1
  594. DO ji = fs_2, fs_jpim1 ! vector opt.
  595. z2d(ji,jj) = z2d(ji,jj) + ztrdy(ji,jj,jk)
  596. END DO
  597. END DO
  598. END DO
  599. z2d(:,:) = rau0_rcp * z2d(:,:)
  600. CALL lbc_lnk( z2d, 'V', -1. )
  601. CALL iom_put( "vadv_heattr", z2d ) ! heat transport in j-direction
  602. ENDIF
  603. ! ! "Poleward" heat and salt transports (contribution of upstream fluxes)
  604. IF( cdtype == 'TRA' .AND. ln_diaptr ) THEN
  605. zptry(:,:,:) = zptry(:,:,:) + zwy(:,:,:)
  606. CALL dia_ptr_ohst_components( jn, 'adv', zptry(:,:,:) )
  607. ENDIF
  608. !
  609. END DO
  610. !
  611. CALL wrk_dealloc( jpi, jpj, jpk, zwi, zwz, zhdiv, zwz_sav, zwzts )
  612. CALL wrk_dealloc( jpi, jpj, jpk, kjpt+1, ztrs )
  613. CALL wrk_dealloc( jpi, jpj, zwx_sav, zwy_sav )
  614. IF( l_trd .OR. l_trans ) THEN
  615. CALL wrk_dealloc( jpi, jpj, jpk, ztrdx, ztrdy, ztrdz )
  616. CALL wrk_dealloc( jpi, jpj, z2d )
  617. ENDIF
  618. IF( cdtype == 'TRA' .AND. ln_diaptr ) CALL wrk_dealloc( jpi, jpj, jpk, zptry )
  619. !
  620. IF( nn_timing == 1 ) CALL timing_stop('tra_adv_tvd_zts')
  621. !
  622. END SUBROUTINE tra_adv_tvd_zts
  623. SUBROUTINE nonosc( pbef, paa, pbb, pcc, paft, p2dt )
  624. !!---------------------------------------------------------------------
  625. !! *** ROUTINE nonosc ***
  626. !!
  627. !! ** Purpose : compute monotonic tracer fluxes from the upstream
  628. !! scheme and the before field by a nonoscillatory algorithm
  629. !!
  630. !! ** Method : ... ???
  631. !! warning : pbef and paft must be masked, but the boundaries
  632. !! conditions on the fluxes are not necessary zalezak (1979)
  633. !! drange (1995) multi-dimensional forward-in-time and upstream-
  634. !! in-space based differencing for fluid
  635. !!----------------------------------------------------------------------
  636. REAL(wp), DIMENSION(jpk) , INTENT(in ) :: p2dt ! vertical profile of tracer time-step
  637. REAL(wp), DIMENSION (jpi,jpj,jpk), INTENT(in ) :: pbef, paft ! before & after field
  638. REAL(wp), DIMENSION (jpi,jpj,jpk), INTENT(inout) :: paa, pbb, pcc ! monotonic fluxes in the 3 directions
  639. !
  640. INTEGER :: ji, jj, jk ! dummy loop indices
  641. INTEGER :: ikm1 ! local integer
  642. REAL(wp) :: zpos, zneg, zbt, za, zb, zc, zbig, zrtrn, z2dtt ! local scalars
  643. REAL(wp) :: zau, zbu, zcu, zav, zbv, zcv, zup, zdo ! - -
  644. REAL(wp), POINTER, DIMENSION(:,:,:) :: zbetup, zbetdo, zbup, zbdo
  645. !!----------------------------------------------------------------------
  646. !
  647. IF( nn_timing == 1 ) CALL timing_start('nonosc')
  648. !
  649. CALL wrk_alloc( jpi, jpj, jpk, zbetup, zbetdo, zbup, zbdo )
  650. !
  651. zbig = 1.e+40_wp
  652. zrtrn = 1.e-15_wp
  653. zbetup(:,:,:) = 0._wp ; zbetdo(:,:,:) = 0._wp
  654. ! Search local extrema
  655. ! --------------------
  656. ! max/min of pbef & paft with large negative/positive value (-/+zbig) inside land
  657. zbup = MAX( pbef * tmask - zbig * ( 1._wp - tmask ), &
  658. & paft * tmask - zbig * ( 1._wp - tmask ) )
  659. zbdo = MIN( pbef * tmask + zbig * ( 1._wp - tmask ), &
  660. & paft * tmask + zbig * ( 1._wp - tmask ) )
  661. DO jk = 1, jpkm1
  662. ikm1 = MAX(jk-1,1)
  663. z2dtt = p2dt(jk)
  664. DO jj = 2, jpjm1
  665. DO ji = fs_2, fs_jpim1 ! vector opt.
  666. ! search maximum in neighbourhood
  667. zup = MAX( zbup(ji ,jj ,jk ), &
  668. & zbup(ji-1,jj ,jk ), zbup(ji+1,jj ,jk ), &
  669. & zbup(ji ,jj-1,jk ), zbup(ji ,jj+1,jk ), &
  670. & zbup(ji ,jj ,ikm1), zbup(ji ,jj ,jk+1) )
  671. ! search minimum in neighbourhood
  672. zdo = MIN( zbdo(ji ,jj ,jk ), &
  673. & zbdo(ji-1,jj ,jk ), zbdo(ji+1,jj ,jk ), &
  674. & zbdo(ji ,jj-1,jk ), zbdo(ji ,jj+1,jk ), &
  675. & zbdo(ji ,jj ,ikm1), zbdo(ji ,jj ,jk+1) )
  676. ! positive part of the flux
  677. zpos = MAX( 0., paa(ji-1,jj ,jk ) ) - MIN( 0., paa(ji ,jj ,jk ) ) &
  678. & + MAX( 0., pbb(ji ,jj-1,jk ) ) - MIN( 0., pbb(ji ,jj ,jk ) ) &
  679. & + MAX( 0., pcc(ji ,jj ,jk+1) ) - MIN( 0., pcc(ji ,jj ,jk ) )
  680. ! negative part of the flux
  681. zneg = MAX( 0., paa(ji ,jj ,jk ) ) - MIN( 0., paa(ji-1,jj ,jk ) ) &
  682. & + MAX( 0., pbb(ji ,jj ,jk ) ) - MIN( 0., pbb(ji ,jj-1,jk ) ) &
  683. & + MAX( 0., pcc(ji ,jj ,jk ) ) - MIN( 0., pcc(ji ,jj ,jk+1) )
  684. ! up & down beta terms
  685. zbt = e1t(ji,jj) * e2t(ji,jj) * fse3t(ji,jj,jk) / z2dtt
  686. zbetup(ji,jj,jk) = ( zup - paft(ji,jj,jk) ) / ( zpos + zrtrn ) * zbt
  687. zbetdo(ji,jj,jk) = ( paft(ji,jj,jk) - zdo ) / ( zneg + zrtrn ) * zbt
  688. END DO
  689. END DO
  690. END DO
  691. CALL lbc_lnk( zbetup, 'T', 1. ) ; CALL lbc_lnk( zbetdo, 'T', 1. ) ! lateral boundary cond. (unchanged sign)
  692. ! 3. monotonic flux in the i & j direction (paa & pbb)
  693. ! ----------------------------------------
  694. DO jk = 1, jpkm1
  695. DO jj = 2, jpjm1
  696. DO ji = fs_2, fs_jpim1 ! vector opt.
  697. zau = MIN( 1._wp, zbetdo(ji,jj,jk), zbetup(ji+1,jj,jk) )
  698. zbu = MIN( 1._wp, zbetup(ji,jj,jk), zbetdo(ji+1,jj,jk) )
  699. zcu = ( 0.5 + SIGN( 0.5 , paa(ji,jj,jk) ) )
  700. paa(ji,jj,jk) = paa(ji,jj,jk) * ( zcu * zau + ( 1._wp - zcu) * zbu )
  701. zav = MIN( 1._wp, zbetdo(ji,jj,jk), zbetup(ji,jj+1,jk) )
  702. zbv = MIN( 1._wp, zbetup(ji,jj,jk), zbetdo(ji,jj+1,jk) )
  703. zcv = ( 0.5 + SIGN( 0.5 , pbb(ji,jj,jk) ) )
  704. pbb(ji,jj,jk) = pbb(ji,jj,jk) * ( zcv * zav + ( 1._wp - zcv) * zbv )
  705. ! monotonic flux in the k direction, i.e. pcc
  706. ! -------------------------------------------
  707. za = MIN( 1., zbetdo(ji,jj,jk+1), zbetup(ji,jj,jk) )
  708. zb = MIN( 1., zbetup(ji,jj,jk+1), zbetdo(ji,jj,jk) )
  709. zc = ( 0.5 + SIGN( 0.5 , pcc(ji,jj,jk+1) ) )
  710. pcc(ji,jj,jk+1) = pcc(ji,jj,jk+1) * ( zc * za + ( 1._wp - zc) * zb )
  711. END DO
  712. END DO
  713. END DO
  714. CALL lbc_lnk( paa, 'U', -1. ) ; CALL lbc_lnk( pbb, 'V', -1. ) ! lateral boundary condition (changed sign)
  715. !
  716. CALL wrk_dealloc( jpi, jpj, jpk, zbetup, zbetdo, zbup, zbdo )
  717. !
  718. IF( nn_timing == 1 ) CALL timing_stop('nonosc')
  719. !
  720. END SUBROUTINE nonosc
  721. !!======================================================================
  722. END MODULE traadv_tvd