traadv_tvd.F90 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726
  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 4990 2014-12-15 16:42:49Z 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 )
  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. !
  78. INTEGER :: ji, jj, jk, jn ! dummy loop indices
  79. INTEGER :: ik
  80. REAL(wp) :: z2dtt, zbtr, ztra ! local scalar
  81. REAL(wp) :: zfp_ui, zfp_vj, zfp_wk ! - -
  82. REAL(wp) :: zfm_ui, zfm_vj, zfm_wk ! - -
  83. REAL(wp), POINTER, DIMENSION(:,:,:) :: zwi, zwz
  84. REAL(wp), POINTER, DIMENSION(:,:,:) :: ztrdx, ztrdy, ztrdz, zptry
  85. REAL(wp), POINTER, DIMENSION(:,:) :: z2d
  86. !!----------------------------------------------------------------------
  87. !
  88. IF( nn_timing == 1 ) CALL timing_start('tra_adv_tvd')
  89. !
  90. CALL wrk_alloc( jpi, jpj, jpk, zwi, zwz )
  91. !
  92. IF( kt == kit000 ) THEN
  93. IF(lwp) WRITE(numout,*)
  94. IF(lwp) WRITE(numout,*) 'tra_adv_tvd : TVD advection scheme on ', cdtype
  95. IF(lwp) WRITE(numout,*) '~~~~~~~~~~~'
  96. !
  97. ENDIF
  98. l_trd = .FALSE.
  99. l_trans = .FALSE.
  100. IF( ( cdtype == 'TRA' .AND. l_trdtra ) .OR. ( cdtype == 'TRC' .AND. l_trdtrc ) ) l_trd = .TRUE.
  101. IF( cdtype == 'TRA' .AND. (iom_use("uadv_heattr") .OR. iom_use("vadv_heattr") ) ) l_trans = .TRUE.
  102. !
  103. IF( l_trd .OR. l_trans ) THEN
  104. CALL wrk_alloc( jpi, jpj, jpk, ztrdx, ztrdy, ztrdz )
  105. ztrdx(:,:,:) = 0.e0 ; ztrdy(:,:,:) = 0.e0 ; ztrdz(:,:,:) = 0.e0
  106. CALL wrk_alloc( jpi, jpj, z2d )
  107. ENDIF
  108. !
  109. IF( cdtype == 'TRA' .AND. ln_diaptr ) THEN
  110. CALL wrk_alloc( jpi, jpj, jpk, zptry )
  111. zptry(:,:,:) = 0._wp
  112. ENDIF
  113. !
  114. zwi(:,:,:) = 0.e0 ;
  115. !
  116. ! ! ===========
  117. DO jn = 1, kjpt ! tracer loop
  118. ! ! ===========
  119. ! 1. Bottom and k=1 value : flux set to zero
  120. ! ----------------------------------
  121. zwx(:,:,jpk) = 0.e0 ; zwz(:,:,jpk) = 0.e0
  122. zwy(:,:,jpk) = 0.e0 ; zwi(:,:,jpk) = 0.e0
  123. zwz(:,:,1 ) = 0._wp
  124. ! 2. upstream advection with initial mass fluxes & intermediate update
  125. ! --------------------------------------------------------------------
  126. ! upstream tracer flux in the i and j direction
  127. DO jk = 1, jpkm1
  128. DO jj = 1, jpjm1
  129. DO ji = 1, fs_jpim1 ! vector opt.
  130. ! upstream scheme
  131. zfp_ui = pun(ji,jj,jk) + ABS( pun(ji,jj,jk) )
  132. zfm_ui = pun(ji,jj,jk) - ABS( pun(ji,jj,jk) )
  133. zfp_vj = pvn(ji,jj,jk) + ABS( pvn(ji,jj,jk) )
  134. zfm_vj = pvn(ji,jj,jk) - ABS( pvn(ji,jj,jk) )
  135. zwx(ji,jj,jk) = 0.5 * ( zfp_ui * ptb(ji,jj,jk,jn) + zfm_ui * ptb(ji+1,jj ,jk,jn) )
  136. zwy(ji,jj,jk) = 0.5 * ( zfp_vj * ptb(ji,jj,jk,jn) + zfm_vj * ptb(ji ,jj+1,jk,jn) )
  137. END DO
  138. END DO
  139. END DO
  140. ! upstream tracer flux in the k direction
  141. ! Interior value
  142. DO jk = 2, jpkm1
  143. DO jj = 1, jpj
  144. DO ji = 1, jpi
  145. zfp_wk = pwn(ji,jj,jk) + ABS( pwn(ji,jj,jk) )
  146. zfm_wk = pwn(ji,jj,jk) - ABS( pwn(ji,jj,jk) )
  147. 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)
  148. END DO
  149. END DO
  150. END DO
  151. ! Surface value
  152. IF( lk_vvl ) THEN
  153. IF ( ln_isfcav ) THEN
  154. DO jj = 1, jpj
  155. DO ji = 1, jpi
  156. zwz(ji,jj, mikt(ji,jj) ) = 0.e0 ! volume variable
  157. END DO
  158. END DO
  159. ELSE
  160. zwz(:,:,1) = 0.e0 ! volume variable
  161. END IF
  162. ELSE
  163. IF ( ln_isfcav ) THEN
  164. DO jj = 1, jpj
  165. DO ji = 1, jpi
  166. zwz(ji,jj, mikt(ji,jj) ) = pwn(ji,jj,mikt(ji,jj)) * ptb(ji,jj,mikt(ji,jj),jn) ! linear free surface
  167. END DO
  168. END DO
  169. ELSE
  170. zwz(:,:,1) = pwn(:,:,1) * ptb(:,:,1,jn) ! linear free surface
  171. END IF
  172. ENDIF
  173. ! total advective trend
  174. DO jk = 1, jpkm1
  175. z2dtt = p2dt(jk)
  176. DO jj = 2, jpjm1
  177. DO ji = fs_2, fs_jpim1 ! vector opt.
  178. ! total intermediate advective trends
  179. ztra = - ( zwx(ji,jj,jk) - zwx(ji-1,jj ,jk ) &
  180. & + zwy(ji,jj,jk) - zwy(ji ,jj-1,jk ) &
  181. & + zwz(ji,jj,jk) - zwz(ji ,jj ,jk+1) ) / e1e2t(ji,jj)
  182. ! update and guess with monotonic sheme
  183. pta(ji,jj,jk,jn) = pta(ji,jj,jk,jn) + ztra / fse3t_n(ji,jj,jk) * tmask(ji,jj,jk)
  184. 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)
  185. END DO
  186. END DO
  187. END DO
  188. ! ! Lateral boundary conditions on zwi (unchanged sign)
  189. CALL lbc_lnk( zwi, 'T', 1. )
  190. ! ! trend diagnostics (contribution of upstream fluxes)
  191. IF( l_trd .OR. l_trans ) THEN
  192. ! store intermediate advective trends
  193. ztrdx(:,:,:) = zwx(:,:,:) ; ztrdy(:,:,:) = zwy(:,:,:) ; ztrdz(:,:,:) = zwz(:,:,:)
  194. END IF
  195. ! ! "Poleward" heat and salt transports (contribution of upstream fluxes)
  196. IF( cdtype == 'TRA' .AND. ln_diaptr ) zptry(:,:,:) = zwy(:,:,:)
  197. ! 3. antidiffusive flux : high order minus low order
  198. ! --------------------------------------------------
  199. ! antidiffusive flux on i and j
  200. DO jk = 1, jpkm1
  201. DO jj = 1, jpjm1
  202. DO ji = 1, fs_jpim1 ! vector opt.
  203. 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)
  204. 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)
  205. END DO
  206. END DO
  207. END DO
  208. ! antidiffusive flux on k
  209. ! Interior value
  210. DO jk = 2, jpkm1
  211. DO jj = 1, jpj
  212. DO ji = 1, jpi
  213. 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)
  214. END DO
  215. END DO
  216. END DO
  217. ! surface value
  218. IF ( ln_isfcav ) THEN
  219. DO jj = 1, jpj
  220. DO ji = 1, jpi
  221. zwz(ji,jj,mikt(ji,jj)) = 0.e0
  222. END DO
  223. END DO
  224. ELSE
  225. zwz(:,:,1) = 0.e0
  226. END IF
  227. CALL lbc_lnk( zwx, 'U', -1. ) ; CALL lbc_lnk( zwy, 'V', -1. ) ! Lateral bondary conditions
  228. CALL lbc_lnk( zwz, 'W', 1. )
  229. ! 4. monotonicity algorithm
  230. ! -------------------------
  231. CALL nonosc( ptb(:,:,:,jn), zwx, zwy, zwz, zwi, p2dt )
  232. ! 5. final trend with corrected fluxes
  233. ! ------------------------------------
  234. DO jk = 1, jpkm1
  235. DO jj = 2, jpjm1
  236. DO ji = fs_2, fs_jpim1 ! vector opt.
  237. zbtr = 1. / ( e1t(ji,jj) * e2t(ji,jj) * fse3t(ji,jj,jk) )
  238. ! total advective trends
  239. ztra = - zbtr * ( zwx(ji,jj,jk) - zwx(ji-1,jj ,jk ) &
  240. & + zwy(ji,jj,jk) - zwy(ji ,jj-1,jk ) &
  241. & + zwz(ji,jj,jk) - zwz(ji ,jj ,jk+1) )
  242. ! add them to the general tracer trends
  243. pta(ji,jj,jk,jn) = pta(ji,jj,jk,jn) + ztra * tmask(ji,jj,jk)
  244. END DO
  245. END DO
  246. END DO
  247. ! ! trend diagnostics (contribution of upstream fluxes)
  248. IF( l_trd .OR. l_trans ) THEN
  249. ztrdx(:,:,:) = ztrdx(:,:,:) + zwx(:,:,:) ! <<< Add to previously computed
  250. ztrdy(:,:,:) = ztrdy(:,:,:) + zwy(:,:,:) ! <<< Add to previously computed
  251. ztrdz(:,:,:) = ztrdz(:,:,:) + zwz(:,:,:) ! <<< Add to previously computed
  252. ENDIF
  253. IF( l_trd ) THEN
  254. CALL trd_tra( kt, cdtype, jn, jptra_xad, ztrdx, pun, ptn(:,:,:,jn) )
  255. CALL trd_tra( kt, cdtype, jn, jptra_yad, ztrdy, pvn, ptn(:,:,:,jn) )
  256. CALL trd_tra( kt, cdtype, jn, jptra_zad, ztrdz, pwn, ptn(:,:,:,jn) )
  257. END IF
  258. IF( l_trans .AND. jn==jp_tem ) THEN
  259. z2d(:,:) = 0._wp
  260. DO jk = 1, jpkm1
  261. DO jj = 2, jpjm1
  262. DO ji = fs_2, fs_jpim1 ! vector opt.
  263. z2d(ji,jj) = z2d(ji,jj) + ztrdx(ji,jj,jk)
  264. END DO
  265. END DO
  266. END DO
  267. CALL lbc_lnk( z2d, 'U', -1. )
  268. CALL iom_put( "uadv_heattr", rau0_rcp * z2d ) ! heat transport in i-direction
  269. !
  270. z2d(:,:) = 0._wp
  271. DO jk = 1, jpkm1
  272. DO jj = 2, jpjm1
  273. DO ji = fs_2, fs_jpim1 ! vector opt.
  274. z2d(ji,jj) = z2d(ji,jj) + ztrdy(ji,jj,jk)
  275. END DO
  276. END DO
  277. END DO
  278. CALL lbc_lnk( z2d, 'V', -1. )
  279. CALL iom_put( "vadv_heattr", rau0_rcp * z2d ) ! heat transport in j-direction
  280. ENDIF
  281. ! "Poleward" heat and salt transports (contribution of upstream fluxes)
  282. IF( cdtype == 'TRA' .AND. ln_diaptr ) THEN
  283. zptry(:,:,:) = zptry(:,:,:) + zwy(:,:,:) ! <<< Add to previously computed
  284. CALL dia_ptr_ohst_components( jn, 'adv', zptry(:,:,:) )
  285. ENDIF
  286. !
  287. END DO
  288. !
  289. CALL wrk_dealloc( jpi, jpj, jpk, zwi, zwz )
  290. IF( l_trd .OR. l_trans ) THEN
  291. CALL wrk_dealloc( jpi, jpj, jpk, ztrdx, ztrdy, ztrdz )
  292. CALL wrk_dealloc( jpi, jpj, z2d )
  293. ENDIF
  294. IF( cdtype == 'TRA' .AND. ln_diaptr ) CALL wrk_dealloc( jpi, jpj, jpk, zptry )
  295. !
  296. IF( nn_timing == 1 ) CALL timing_stop('tra_adv_tvd')
  297. !
  298. END SUBROUTINE tra_adv_tvd
  299. SUBROUTINE tra_adv_tvd_zts ( kt, kit000, cdtype, p2dt, pun, pvn, pwn, &
  300. & ptb, ptn, pta, kjpt )
  301. !!----------------------------------------------------------------------
  302. !! *** ROUTINE tra_adv_tvd_zts ***
  303. !!
  304. !! ** Purpose : Compute the now trend due to total advection of
  305. !! tracers and add it to the general trend of tracer equations
  306. !!
  307. !! ** Method : TVD ZTS scheme, i.e. 2nd order centered scheme with
  308. !! corrected flux (monotonic correction). This version use sub-
  309. !! timestepping for the vertical advection which increases stability
  310. !! when vertical metrics are small.
  311. !! note: - this advection scheme needs a leap-frog time scheme
  312. !!
  313. !! ** Action : - update (pta) with the now advective tracer trends
  314. !! - save the trends
  315. !!----------------------------------------------------------------------
  316. USE oce , ONLY: zwx => ua , zwy => va ! (ua,va) used as workspace
  317. !
  318. INTEGER , INTENT(in ) :: kt ! ocean time-step index
  319. INTEGER , INTENT(in ) :: kit000 ! first time step index
  320. CHARACTER(len=3) , INTENT(in ) :: cdtype ! =TRA or TRC (tracer indicator)
  321. INTEGER , INTENT(in ) :: kjpt ! number of tracers
  322. REAL(wp), DIMENSION( jpk ), INTENT(in ) :: p2dt ! vertical profile of tracer time-step
  323. REAL(wp), DIMENSION(jpi,jpj,jpk ), INTENT(in ) :: pun, pvn, pwn ! 3 ocean velocity components
  324. REAL(wp), DIMENSION(jpi,jpj,jpk,kjpt), INTENT(in ) :: ptb, ptn ! before and now tracer fields
  325. REAL(wp), DIMENSION(jpi,jpj,jpk,kjpt), INTENT(inout) :: pta ! tracer trend
  326. !
  327. REAL(wp), DIMENSION( jpk ) :: zts ! length of sub-timestep for vertical advection
  328. REAL(wp), DIMENSION( jpk ) :: zr_p2dt ! reciprocal of tracer timestep
  329. INTEGER :: ji, jj, jk, jl, jn ! dummy loop indices
  330. INTEGER :: jnzts = 5 ! number of sub-timesteps for vertical advection
  331. INTEGER :: jtb, jtn, jta ! sub timestep pointers for leap-frog/euler forward steps
  332. INTEGER :: jtaken ! toggle for collecting appropriate fluxes from sub timesteps
  333. REAL(wp) :: z_rzts ! Fractional length of Euler forward sub-timestep for vertical advection
  334. REAL(wp) :: z2dtt, zbtr, ztra ! local scalar
  335. REAL(wp) :: zfp_ui, zfp_vj, zfp_wk ! - -
  336. REAL(wp) :: zfm_ui, zfm_vj, zfm_wk ! - -
  337. REAL(wp), POINTER, DIMENSION(:,: ) :: zwx_sav , zwy_sav
  338. REAL(wp), POINTER, DIMENSION(:,:,:) :: zwi, zwz, zhdiv, zwz_sav, zwzts
  339. REAL(wp), POINTER, DIMENSION(:,:,:) :: ztrdx, ztrdy, ztrdz
  340. REAL(wp), POINTER, DIMENSION(:,:,:) :: zptry
  341. REAL(wp), POINTER, DIMENSION(:,:,:,:) :: ztrs
  342. !!----------------------------------------------------------------------
  343. !
  344. IF( nn_timing == 1 ) CALL timing_start('tra_adv_tvd_zts')
  345. !
  346. CALL wrk_alloc( jpi, jpj, zwx_sav, zwy_sav )
  347. CALL wrk_alloc( jpi, jpj, jpk, zwi, zwz , zhdiv, zwz_sav, zwzts )
  348. CALL wrk_alloc( jpi, jpj, jpk, kjpt+1, ztrs )
  349. !
  350. IF( kt == kit000 ) THEN
  351. IF(lwp) WRITE(numout,*)
  352. IF(lwp) WRITE(numout,*) 'tra_adv_tvd_zts : TVD ZTS advection scheme on ', cdtype
  353. IF(lwp) WRITE(numout,*) '~~~~~~~~~~~'
  354. ENDIF
  355. !
  356. l_trd = .FALSE.
  357. IF( ( cdtype == 'TRA' .AND. l_trdtra ) .OR. ( cdtype == 'TRC' .AND. l_trdtrc ) ) l_trd = .TRUE.
  358. !
  359. IF( l_trd ) THEN
  360. CALL wrk_alloc( jpi, jpj, jpk, ztrdx, ztrdy, ztrdz )
  361. ztrdx(:,:,:) = 0._wp ; ztrdy(:,:,:) = 0._wp ; ztrdz(:,:,:) = 0._wp
  362. ENDIF
  363. !
  364. IF( cdtype == 'TRA' .AND. ln_diaptr ) THEN
  365. CALL wrk_alloc( jpi, jpj,jpk, zptry )
  366. zptry(:,:,:) = 0._wp
  367. ENDIF
  368. !
  369. zwi(:,:,:) = 0._wp
  370. z_rzts = 1._wp / REAL( jnzts, wp )
  371. zr_p2dt(:) = 1._wp / p2dt(:)
  372. !
  373. ! ! ===========
  374. DO jn = 1, kjpt ! tracer loop
  375. ! ! ===========
  376. ! 1. Bottom value : flux set to zero
  377. ! ----------------------------------
  378. zwx(:,:,jpk) = 0._wp ; zwz(:,:,jpk) = 0._wp
  379. zwy(:,:,jpk) = 0._wp ; zwi(:,:,jpk) = 0._wp
  380. ! 2. upstream advection with initial mass fluxes & intermediate update
  381. ! --------------------------------------------------------------------
  382. ! upstream tracer flux in the i and j direction
  383. DO jk = 1, jpkm1
  384. DO jj = 1, jpjm1
  385. DO ji = 1, fs_jpim1 ! vector opt.
  386. ! upstream scheme
  387. zfp_ui = pun(ji,jj,jk) + ABS( pun(ji,jj,jk) )
  388. zfm_ui = pun(ji,jj,jk) - ABS( pun(ji,jj,jk) )
  389. zfp_vj = pvn(ji,jj,jk) + ABS( pvn(ji,jj,jk) )
  390. zfm_vj = pvn(ji,jj,jk) - ABS( pvn(ji,jj,jk) )
  391. zwx(ji,jj,jk) = 0.5_wp * ( zfp_ui * ptb(ji,jj,jk,jn) + zfm_ui * ptb(ji+1,jj ,jk,jn) )
  392. zwy(ji,jj,jk) = 0.5_wp * ( zfp_vj * ptb(ji,jj,jk,jn) + zfm_vj * ptb(ji ,jj+1,jk,jn) )
  393. END DO
  394. END DO
  395. END DO
  396. ! upstream tracer flux in the k direction
  397. ! Interior value
  398. DO jk = 2, jpkm1
  399. DO jj = 1, jpj
  400. DO ji = 1, jpi
  401. zfp_wk = pwn(ji,jj,jk) + ABS( pwn(ji,jj,jk) )
  402. zfm_wk = pwn(ji,jj,jk) - ABS( pwn(ji,jj,jk) )
  403. zwz(ji,jj,jk) = 0.5_wp * ( zfp_wk * ptb(ji,jj,jk,jn) + zfm_wk * ptb(ji,jj,jk-1,jn) )
  404. END DO
  405. END DO
  406. END DO
  407. ! Surface value
  408. IF( lk_vvl ) THEN
  409. IF ( ln_isfcav ) THEN
  410. DO jj = 1, jpj
  411. DO ji = 1, jpi
  412. zwz(ji,jj, mikt(ji,jj) ) = 0.e0 ! volume variable + isf
  413. END DO
  414. END DO
  415. ELSE
  416. zwz(:,:,1) = 0.e0 ! volume variable + no isf
  417. END IF
  418. ELSE
  419. IF ( ln_isfcav ) THEN
  420. DO jj = 1, jpj
  421. DO ji = 1, jpi
  422. zwz(ji,jj, mikt(ji,jj) ) = pwn(ji,jj,mikt(ji,jj)) * ptb(ji,jj,mikt(ji,jj),jn) ! linear free surface + isf
  423. END DO
  424. END DO
  425. ELSE
  426. zwz(:,:,1) = pwn(:,:,1) * ptb(:,:,1,jn) ! linear free surface + no isf
  427. END IF
  428. ENDIF
  429. ! total advective trend
  430. DO jk = 1, jpkm1
  431. z2dtt = p2dt(jk)
  432. DO jj = 2, jpjm1
  433. DO ji = fs_2, fs_jpim1 ! vector opt.
  434. ! total intermediate advective trends
  435. ztra = - ( zwx(ji,jj,jk) - zwx(ji-1,jj ,jk ) &
  436. & + zwy(ji,jj,jk) - zwy(ji ,jj-1,jk ) &
  437. & + zwz(ji,jj,jk) - zwz(ji ,jj ,jk+1) ) / e1e2t(ji,jj)
  438. ! update and guess with monotonic sheme
  439. pta(ji,jj,jk,jn) = pta(ji,jj,jk,jn) + ztra / fse3t_n(ji,jj,jk) * tmask(ji,jj,jk)
  440. 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)
  441. END DO
  442. END DO
  443. END DO
  444. ! ! Lateral boundary conditions on zwi (unchanged sign)
  445. CALL lbc_lnk( zwi, 'T', 1. )
  446. ! ! trend diagnostics (contribution of upstream fluxes)
  447. IF( l_trd ) THEN
  448. ! store intermediate advective trends
  449. ztrdx(:,:,:) = zwx(:,:,:) ; ztrdy(:,:,:) = zwy(:,:,:) ; ztrdz(:,:,:) = zwz(:,:,:)
  450. END IF
  451. ! ! "Poleward" heat and salt transports (contribution of upstream fluxes)
  452. IF( cdtype == 'TRA' .AND. ln_diaptr ) zptry(:,:,:) = zwy(:,:,:)
  453. ! 3. antidiffusive flux : high order minus low order
  454. ! --------------------------------------------------
  455. ! antidiffusive flux on i and j
  456. !
  457. DO jk = 1, jpkm1
  458. !
  459. DO jj = 1, jpjm1
  460. DO ji = 1, fs_jpim1 ! vector opt.
  461. zwx_sav(ji,jj) = zwx(ji,jj,jk)
  462. zwy_sav(ji,jj) = zwy(ji,jj,jk)
  463. zwx(ji,jj,jk) = 0.5_wp * pun(ji,jj,jk) * ( ptn(ji,jj,jk,jn) + ptn(ji+1,jj,jk,jn) )
  464. zwy(ji,jj,jk) = 0.5_wp * pvn(ji,jj,jk) * ( ptn(ji,jj,jk,jn) + ptn(ji,jj+1,jk,jn) )
  465. END DO
  466. END DO
  467. DO jj = 2, jpjm1 ! partial horizontal divergence
  468. DO ji = fs_2, fs_jpim1
  469. zhdiv(ji,jj,jk) = ( zwx(ji,jj,jk) - zwx(ji-1,jj ,jk) &
  470. & + zwy(ji,jj,jk) - zwy(ji ,jj-1,jk) )
  471. END DO
  472. END DO
  473. DO jj = 1, jpjm1
  474. DO ji = 1, fs_jpim1 ! vector opt.
  475. zwx(ji,jj,jk) = zwx(ji,jj,jk) - zwx_sav(ji,jj)
  476. zwy(ji,jj,jk) = zwy(ji,jj,jk) - zwy_sav(ji,jj)
  477. END DO
  478. END DO
  479. END DO
  480. ! antidiffusive flux on k
  481. zwz(:,:,1) = 0._wp ! Surface value
  482. zwz_sav(:,:,:) = zwz(:,:,:)
  483. !
  484. ztrs(:,:,:,1) = ptb(:,:,:,jn)
  485. zwzts(:,:,:) = 0._wp
  486. DO jl = 1, jnzts ! Start of sub timestepping loop
  487. IF( jl == 1 ) THEN ! Euler forward to kick things off
  488. jtb = 1 ; jtn = 1 ; jta = 2
  489. zts(:) = p2dt(:) * z_rzts
  490. jtaken = MOD( jnzts + 1 , 2) ! Toggle to collect every second flux
  491. ! starting at jl =1 if jnzts is odd;
  492. ! starting at jl =2 otherwise
  493. ELSEIF( jl == 2 ) THEN ! First leapfrog step
  494. jtb = 1 ; jtn = 2 ; jta = 3
  495. zts(:) = 2._wp * p2dt(:) * z_rzts
  496. ELSE ! Shuffle pointers for subsequent leapfrog steps
  497. jtb = MOD(jtb,3) + 1
  498. jtn = MOD(jtn,3) + 1
  499. jta = MOD(jta,3) + 1
  500. ENDIF
  501. DO jk = 2, jpkm1 ! Interior value
  502. DO jj = 2, jpjm1
  503. DO ji = fs_2, fs_jpim1
  504. zwz(ji,jj,jk) = 0.5_wp * pwn(ji,jj,jk) * ( ztrs(ji,jj,jk,jtn) + ztrs(ji,jj,jk-1,jtn) )
  505. IF( jtaken == 0 ) zwzts(ji,jj,jk) = zwzts(ji,jj,jk) + zwz(ji,jj,jk)*zts(jk) ! Accumulate time-weighted vertcal flux
  506. END DO
  507. END DO
  508. END DO
  509. jtaken = MOD( jtaken + 1 , 2 )
  510. DO jk = 2, jpkm1 ! Interior value
  511. DO jj = 2, jpjm1
  512. DO ji = fs_2, fs_jpim1
  513. zbtr = 1._wp / ( e1t(ji,jj) * e2t(ji,jj) * fse3t(ji,jj,jk) )
  514. ! total advective trends
  515. ztra = - zbtr * ( zhdiv(ji,jj,jk) + zwz(ji,jj,jk) - zwz(ji ,jj ,jk+1) )
  516. ztrs(ji,jj,jk,jta) = ztrs(ji,jj,jk,jtb) + zts(jk) * ztra
  517. END DO
  518. END DO
  519. END DO
  520. END DO
  521. DO jk = 2, jpkm1 ! Anti-diffusive vertical flux using average flux from the sub-timestepping
  522. DO jj = 2, jpjm1
  523. DO ji = fs_2, fs_jpim1
  524. zwz(ji,jj,jk) = zwzts(ji,jj,jk) * zr_p2dt(jk) - zwz_sav(ji,jj,jk)
  525. END DO
  526. END DO
  527. END DO
  528. CALL lbc_lnk( zwx, 'U', -1. ) ; CALL lbc_lnk( zwy, 'V', -1. ) ! Lateral bondary conditions
  529. CALL lbc_lnk( zwz, 'W', 1. )
  530. ! 4. monotonicity algorithm
  531. ! -------------------------
  532. CALL nonosc( ptb(:,:,:,jn), zwx, zwy, zwz, zwi, p2dt )
  533. ! 5. final trend with corrected fluxes
  534. ! ------------------------------------
  535. DO jk = 1, jpkm1
  536. DO jj = 2, jpjm1
  537. DO ji = fs_2, fs_jpim1 ! vector opt.
  538. zbtr = 1. / ( e1t(ji,jj) * e2t(ji,jj) * fse3t(ji,jj,jk) )
  539. ! total advective trends
  540. ztra = - zbtr * ( zwx(ji,jj,jk) - zwx(ji-1,jj ,jk ) &
  541. & + zwy(ji,jj,jk) - zwy(ji ,jj-1,jk ) &
  542. & + zwz(ji,jj,jk) - zwz(ji ,jj ,jk+1) )
  543. ! add them to the general tracer trends
  544. pta(ji,jj,jk,jn) = pta(ji,jj,jk,jn) + ztra
  545. END DO
  546. END DO
  547. END DO
  548. ! ! trend diagnostics (contribution of upstream fluxes)
  549. IF( l_trd ) THEN
  550. ztrdx(:,:,:) = ztrdx(:,:,:) + zwx(:,:,:) ! <<< Add to previously computed
  551. ztrdy(:,:,:) = ztrdy(:,:,:) + zwy(:,:,:) ! <<< Add to previously computed
  552. ztrdz(:,:,:) = ztrdz(:,:,:) + zwz(:,:,:) ! <<< Add to previously computed
  553. CALL trd_tra( kt, cdtype, jn, jptra_xad, ztrdx, pun, ptn(:,:,:,jn) )
  554. CALL trd_tra( kt, cdtype, jn, jptra_yad, ztrdy, pvn, ptn(:,:,:,jn) )
  555. CALL trd_tra( kt, cdtype, jn, jptra_zad, ztrdz, pwn, ptn(:,:,:,jn) )
  556. END IF
  557. ! ! "Poleward" heat and salt transports (contribution of upstream fluxes)
  558. IF( cdtype == 'TRA' .AND. ln_diaptr ) THEN
  559. zptry(:,:,:) = zptry(:,:,:) + zwy(:,:,:)
  560. CALL dia_ptr_ohst_components( jn, 'adv', zptry(:,:,:) )
  561. ENDIF
  562. !
  563. END DO
  564. !
  565. CALL wrk_dealloc( jpi, jpj, jpk, zwi, zwz, zhdiv, zwz_sav, zwzts )
  566. CALL wrk_dealloc( jpi, jpj, jpk, kjpt+1, ztrs )
  567. CALL wrk_dealloc( jpi, jpj, zwx_sav, zwy_sav )
  568. IF( l_trd ) CALL wrk_dealloc( jpi, jpj, jpk, ztrdx, ztrdy, ztrdz )
  569. IF( cdtype == 'TRA' .AND. ln_diaptr ) CALL wrk_dealloc( jpi, jpj, jpk, zptry )
  570. !
  571. IF( nn_timing == 1 ) CALL timing_stop('tra_adv_tvd_zts')
  572. !
  573. END SUBROUTINE tra_adv_tvd_zts
  574. SUBROUTINE nonosc( pbef, paa, pbb, pcc, paft, p2dt )
  575. !!---------------------------------------------------------------------
  576. !! *** ROUTINE nonosc ***
  577. !!
  578. !! ** Purpose : compute monotonic tracer fluxes from the upstream
  579. !! scheme and the before field by a nonoscillatory algorithm
  580. !!
  581. !! ** Method : ... ???
  582. !! warning : pbef and paft must be masked, but the boundaries
  583. !! conditions on the fluxes are not necessary zalezak (1979)
  584. !! drange (1995) multi-dimensional forward-in-time and upstream-
  585. !! in-space based differencing for fluid
  586. !!----------------------------------------------------------------------
  587. REAL(wp), DIMENSION(jpk) , INTENT(in ) :: p2dt ! vertical profile of tracer time-step
  588. REAL(wp), DIMENSION (jpi,jpj,jpk), INTENT(in ) :: pbef, paft ! before & after field
  589. REAL(wp), DIMENSION (jpi,jpj,jpk), INTENT(inout) :: paa, pbb, pcc ! monotonic fluxes in the 3 directions
  590. !
  591. INTEGER :: ji, jj, jk ! dummy loop indices
  592. INTEGER :: ikm1 ! local integer
  593. REAL(wp) :: zpos, zneg, zbt, za, zb, zc, zbig, zrtrn, z2dtt ! local scalars
  594. REAL(wp) :: zau, zbu, zcu, zav, zbv, zcv, zup, zdo ! - -
  595. REAL(wp), POINTER, DIMENSION(:,:,:) :: zbetup, zbetdo, zbup, zbdo
  596. !!----------------------------------------------------------------------
  597. !
  598. IF( nn_timing == 1 ) CALL timing_start('nonosc')
  599. !
  600. CALL wrk_alloc( jpi, jpj, jpk, zbetup, zbetdo, zbup, zbdo )
  601. !
  602. zbig = 1.e+40_wp
  603. zrtrn = 1.e-15_wp
  604. zbetup(:,:,:) = 0._wp ; zbetdo(:,:,:) = 0._wp
  605. ! Search local extrema
  606. ! --------------------
  607. ! max/min of pbef & paft with large negative/positive value (-/+zbig) inside land
  608. zbup = MAX( pbef * tmask - zbig * ( 1._wp - tmask ), &
  609. & paft * tmask - zbig * ( 1._wp - tmask ) )
  610. zbdo = MIN( pbef * tmask + zbig * ( 1._wp - tmask ), &
  611. & paft * tmask + zbig * ( 1._wp - tmask ) )
  612. DO jk = 1, jpkm1
  613. ikm1 = MAX(jk-1,1)
  614. z2dtt = p2dt(jk)
  615. DO jj = 2, jpjm1
  616. DO ji = fs_2, fs_jpim1 ! vector opt.
  617. ! search maximum in neighbourhood
  618. zup = MAX( zbup(ji ,jj ,jk ), &
  619. & zbup(ji-1,jj ,jk ), zbup(ji+1,jj ,jk ), &
  620. & zbup(ji ,jj-1,jk ), zbup(ji ,jj+1,jk ), &
  621. & zbup(ji ,jj ,ikm1), zbup(ji ,jj ,jk+1) )
  622. ! search minimum in neighbourhood
  623. zdo = MIN( zbdo(ji ,jj ,jk ), &
  624. & zbdo(ji-1,jj ,jk ), zbdo(ji+1,jj ,jk ), &
  625. & zbdo(ji ,jj-1,jk ), zbdo(ji ,jj+1,jk ), &
  626. & zbdo(ji ,jj ,ikm1), zbdo(ji ,jj ,jk+1) )
  627. ! positive part of the flux
  628. zpos = MAX( 0., paa(ji-1,jj ,jk ) ) - MIN( 0., paa(ji ,jj ,jk ) ) &
  629. & + MAX( 0., pbb(ji ,jj-1,jk ) ) - MIN( 0., pbb(ji ,jj ,jk ) ) &
  630. & + MAX( 0., pcc(ji ,jj ,jk+1) ) - MIN( 0., pcc(ji ,jj ,jk ) )
  631. ! negative part of the flux
  632. zneg = MAX( 0., paa(ji ,jj ,jk ) ) - MIN( 0., paa(ji-1,jj ,jk ) ) &
  633. & + MAX( 0., pbb(ji ,jj ,jk ) ) - MIN( 0., pbb(ji ,jj-1,jk ) ) &
  634. & + MAX( 0., pcc(ji ,jj ,jk ) ) - MIN( 0., pcc(ji ,jj ,jk+1) )
  635. ! up & down beta terms
  636. zbt = e1t(ji,jj) * e2t(ji,jj) * fse3t(ji,jj,jk) / z2dtt
  637. zbetup(ji,jj,jk) = ( zup - paft(ji,jj,jk) ) / ( zpos + zrtrn ) * zbt
  638. zbetdo(ji,jj,jk) = ( paft(ji,jj,jk) - zdo ) / ( zneg + zrtrn ) * zbt
  639. END DO
  640. END DO
  641. END DO
  642. CALL lbc_lnk( zbetup, 'T', 1. ) ; CALL lbc_lnk( zbetdo, 'T', 1. ) ! lateral boundary cond. (unchanged sign)
  643. ! 3. monotonic flux in the i & j direction (paa & pbb)
  644. ! ----------------------------------------
  645. DO jk = 1, jpkm1
  646. DO jj = 2, jpjm1
  647. DO ji = fs_2, fs_jpim1 ! vector opt.
  648. zau = MIN( 1._wp, zbetdo(ji,jj,jk), zbetup(ji+1,jj,jk) )
  649. zbu = MIN( 1._wp, zbetup(ji,jj,jk), zbetdo(ji+1,jj,jk) )
  650. zcu = ( 0.5 + SIGN( 0.5 , paa(ji,jj,jk) ) )
  651. paa(ji,jj,jk) = paa(ji,jj,jk) * ( zcu * zau + ( 1._wp - zcu) * zbu )
  652. zav = MIN( 1._wp, zbetdo(ji,jj,jk), zbetup(ji,jj+1,jk) )
  653. zbv = MIN( 1._wp, zbetup(ji,jj,jk), zbetdo(ji,jj+1,jk) )
  654. zcv = ( 0.5 + SIGN( 0.5 , pbb(ji,jj,jk) ) )
  655. pbb(ji,jj,jk) = pbb(ji,jj,jk) * ( zcv * zav + ( 1._wp - zcv) * zbv )
  656. ! monotonic flux in the k direction, i.e. pcc
  657. ! -------------------------------------------
  658. za = MIN( 1., zbetdo(ji,jj,jk+1), zbetup(ji,jj,jk) )
  659. zb = MIN( 1., zbetup(ji,jj,jk+1), zbetdo(ji,jj,jk) )
  660. zc = ( 0.5 + SIGN( 0.5 , pcc(ji,jj,jk+1) ) )
  661. pcc(ji,jj,jk+1) = pcc(ji,jj,jk+1) * ( zc * za + ( 1._wp - zc) * zb )
  662. END DO
  663. END DO
  664. END DO
  665. CALL lbc_lnk( paa, 'U', -1. ) ; CALL lbc_lnk( pbb, 'V', -1. ) ! lateral boundary condition (changed sign)
  666. !
  667. CALL wrk_dealloc( jpi, jpj, jpk, zbetup, zbetdo, zbup, zbdo )
  668. !
  669. IF( nn_timing == 1 ) CALL timing_stop('nonosc')
  670. !
  671. END SUBROUTINE nonosc
  672. !!======================================================================
  673. END MODULE traadv_tvd