traadv_tvd.F90 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769
  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. CALL wrk_alloc( jpi, jpj, z2d )
  363. !
  364. IF( kt == kit000 ) THEN
  365. IF(lwp) WRITE(numout,*)
  366. IF(lwp) WRITE(numout,*) 'tra_adv_tvd_zts : TVD ZTS advection scheme on ', cdtype
  367. IF(lwp) WRITE(numout,*) '~~~~~~~~~~~'
  368. ENDIF
  369. !
  370. l_trd = .FALSE.
  371. IF( ( cdtype == 'TRA' .AND. l_trdtra ) .OR. ( cdtype == 'TRC' .AND. l_trdtrc ) ) l_trd = .TRUE.
  372. !
  373. IF( l_trd ) THEN
  374. CALL wrk_alloc( jpi, jpj, jpk, ztrdx, ztrdy, ztrdz )
  375. ztrdx(:,:,:) = 0._wp ; ztrdy(:,:,:) = 0._wp ; ztrdz(:,:,:) = 0._wp
  376. ENDIF
  377. !
  378. IF( cdtype == 'TRA' .AND. ln_diaptr ) THEN
  379. CALL wrk_alloc( jpi, jpj,jpk, zptry )
  380. zptry(:,:,:) = 0._wp
  381. ENDIF
  382. !
  383. zwi(:,:,:) = 0._wp
  384. z_rzts = 1._wp / REAL( jnzts, wp )
  385. zr_p2dt(:) = 1._wp / p2dt(:)
  386. !
  387. ! ! ===========
  388. DO jn = 1, kjpt ! tracer loop
  389. ! ! ===========
  390. ! 1. Bottom value : flux set to zero
  391. ! ----------------------------------
  392. zwx(:,:,jpk) = 0._wp ; zwz(:,:,jpk) = 0._wp
  393. zwy(:,:,jpk) = 0._wp ; zwi(:,:,jpk) = 0._wp
  394. ! 2. upstream advection with initial mass fluxes & intermediate update
  395. ! --------------------------------------------------------------------
  396. ! upstream tracer flux in the i and j direction
  397. DO jk = 1, jpkm1
  398. DO jj = 1, jpjm1
  399. DO ji = 1, fs_jpim1 ! vector opt.
  400. ! upstream scheme
  401. zfp_ui = pun(ji,jj,jk) + ABS( pun(ji,jj,jk) )
  402. zfm_ui = pun(ji,jj,jk) - ABS( pun(ji,jj,jk) )
  403. zfp_vj = pvn(ji,jj,jk) + ABS( pvn(ji,jj,jk) )
  404. zfm_vj = pvn(ji,jj,jk) - ABS( pvn(ji,jj,jk) )
  405. zwx(ji,jj,jk) = 0.5_wp * ( zfp_ui * ptb(ji,jj,jk,jn) + zfm_ui * ptb(ji+1,jj ,jk,jn) )
  406. zwy(ji,jj,jk) = 0.5_wp * ( zfp_vj * ptb(ji,jj,jk,jn) + zfm_vj * ptb(ji ,jj+1,jk,jn) )
  407. END DO
  408. END DO
  409. END DO
  410. ! upstream tracer flux in the k direction
  411. ! Interior value
  412. DO jk = 2, jpkm1
  413. DO jj = 1, jpj
  414. DO ji = 1, jpi
  415. zfp_wk = pwn(ji,jj,jk) + ABS( pwn(ji,jj,jk) )
  416. zfm_wk = pwn(ji,jj,jk) - ABS( pwn(ji,jj,jk) )
  417. zwz(ji,jj,jk) = 0.5_wp * ( zfp_wk * ptb(ji,jj,jk,jn) + zfm_wk * ptb(ji,jj,jk-1,jn) )
  418. END DO
  419. END DO
  420. END DO
  421. ! Surface value
  422. IF( lk_vvl ) THEN
  423. IF ( ln_isfcav ) THEN
  424. DO jj = 1, jpj
  425. DO ji = 1, jpi
  426. zwz(ji,jj, mikt(ji,jj) ) = 0.e0 ! volume variable + isf
  427. END DO
  428. END DO
  429. ELSE
  430. zwz(:,:,1) = 0.e0 ! volume variable + no isf
  431. END IF
  432. ELSE
  433. IF ( ln_isfcav ) THEN
  434. DO jj = 1, jpj
  435. DO ji = 1, jpi
  436. zwz(ji,jj, mikt(ji,jj) ) = pwn(ji,jj,mikt(ji,jj)) * ptb(ji,jj,mikt(ji,jj),jn) ! linear free surface + isf
  437. END DO
  438. END DO
  439. ELSE
  440. zwz(:,:,1) = pwn(:,:,1) * ptb(:,:,1,jn) ! linear free surface + no isf
  441. END IF
  442. ENDIF
  443. ! total advective trend
  444. DO jk = 1, jpkm1
  445. z2dtt = p2dt(jk)
  446. DO jj = 2, jpjm1
  447. DO ji = fs_2, fs_jpim1 ! vector opt.
  448. ! total intermediate advective trends
  449. ztra = - ( zwx(ji,jj,jk) - zwx(ji-1,jj ,jk ) &
  450. & + zwy(ji,jj,jk) - zwy(ji ,jj-1,jk ) &
  451. & + zwz(ji,jj,jk) - zwz(ji ,jj ,jk+1) ) / e1e2t(ji,jj)
  452. ! update and guess with monotonic sheme
  453. pta(ji,jj,jk,jn) = pta(ji,jj,jk,jn) + ztra / fse3t_n(ji,jj,jk) * tmask(ji,jj,jk)
  454. 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)
  455. END DO
  456. END DO
  457. END DO
  458. ! ! Lateral boundary conditions on zwi (unchanged sign)
  459. CALL lbc_lnk( zwi, 'T', 1. )
  460. ! ! trend diagnostics (contribution of upstream fluxes)
  461. IF( l_trd ) THEN
  462. ! store intermediate advective trends
  463. ztrdx(:,:,:) = zwx(:,:,:) ; ztrdy(:,:,:) = zwy(:,:,:) ; ztrdz(:,:,:) = zwz(:,:,:)
  464. END IF
  465. ! ! "Poleward" heat and salt transports (contribution of upstream fluxes)
  466. IF( cdtype == 'TRA' .AND. ln_diaptr ) zptry(:,:,:) = zwy(:,:,:)
  467. ! 3. antidiffusive flux : high order minus low order
  468. ! --------------------------------------------------
  469. ! antidiffusive flux on i and j
  470. !
  471. DO jk = 1, jpkm1
  472. !
  473. DO jj = 1, jpjm1
  474. DO ji = 1, fs_jpim1 ! vector opt.
  475. zwx_sav(ji,jj) = zwx(ji,jj,jk)
  476. zwy_sav(ji,jj) = zwy(ji,jj,jk)
  477. zwx(ji,jj,jk) = 0.5_wp * pun(ji,jj,jk) * ( ptn(ji,jj,jk,jn) + ptn(ji+1,jj,jk,jn) )
  478. zwy(ji,jj,jk) = 0.5_wp * pvn(ji,jj,jk) * ( ptn(ji,jj,jk,jn) + ptn(ji,jj+1,jk,jn) )
  479. END DO
  480. END DO
  481. DO jj = 2, jpjm1 ! partial horizontal divergence
  482. DO ji = fs_2, fs_jpim1
  483. zhdiv(ji,jj,jk) = ( zwx(ji,jj,jk) - zwx(ji-1,jj ,jk) &
  484. & + zwy(ji,jj,jk) - zwy(ji ,jj-1,jk) )
  485. END DO
  486. END DO
  487. DO jj = 1, jpjm1
  488. DO ji = 1, fs_jpim1 ! vector opt.
  489. zwx(ji,jj,jk) = zwx(ji,jj,jk) - zwx_sav(ji,jj)
  490. zwy(ji,jj,jk) = zwy(ji,jj,jk) - zwy_sav(ji,jj)
  491. END DO
  492. END DO
  493. END DO
  494. ! antidiffusive flux on k
  495. zwz(:,:,1) = 0._wp ! Surface value
  496. zwz_sav(:,:,:) = zwz(:,:,:)
  497. !
  498. ztrs(:,:,:,1) = ptb(:,:,:,jn)
  499. ztrs(:,:,1,2) = ptb(:,:,1,jn)
  500. ztrs(:,:,1,3) = ptb(:,:,1,jn)
  501. zwzts(:,:,:) = 0._wp
  502. DO jl = 1, jnzts ! Start of sub timestepping loop
  503. IF( jl == 1 ) THEN ! Euler forward to kick things off
  504. jtb = 1 ; jtn = 1 ; jta = 2
  505. zts(:) = p2dt(:) * z_rzts
  506. jtaken = MOD( jnzts + 1 , 2) ! Toggle to collect every second flux
  507. ! starting at jl =1 if jnzts is odd;
  508. ! starting at jl =2 otherwise
  509. ELSEIF( jl == 2 ) THEN ! First leapfrog step
  510. jtb = 1 ; jtn = 2 ; jta = 3
  511. zts(:) = 2._wp * p2dt(:) * z_rzts
  512. ELSE ! Shuffle pointers for subsequent leapfrog steps
  513. jtb = MOD(jtb,3) + 1
  514. jtn = MOD(jtn,3) + 1
  515. jta = MOD(jta,3) + 1
  516. ENDIF
  517. DO jk = 2, jpkm1 ! Interior value
  518. DO jj = 2, jpjm1
  519. DO ji = fs_2, fs_jpim1
  520. zwz(ji,jj,jk) = 0.5_wp * pwn(ji,jj,jk) * ( ztrs(ji,jj,jk,jtn) + ztrs(ji,jj,jk-1,jtn) )
  521. IF( jtaken == 0 ) zwzts(ji,jj,jk) = zwzts(ji,jj,jk) + zwz(ji,jj,jk)*zts(jk) ! Accumulate time-weighted vertcal flux
  522. END DO
  523. END DO
  524. END DO
  525. jtaken = MOD( jtaken + 1 , 2 )
  526. DO jk = 2, jpkm1 ! Interior value
  527. DO jj = 2, jpjm1
  528. DO ji = fs_2, fs_jpim1
  529. zbtr = 1._wp / ( e1t(ji,jj) * e2t(ji,jj) * fse3t(ji,jj,jk) )
  530. ! total advective trends
  531. ztra = - zbtr * ( zhdiv(ji,jj,jk) + zwz(ji,jj,jk) - zwz(ji ,jj ,jk+1) )
  532. ztrs(ji,jj,jk,jta) = ztrs(ji,jj,jk,jtb) + zts(jk) * ztra
  533. END DO
  534. END DO
  535. END DO
  536. END DO
  537. DO jk = 2, jpkm1 ! Anti-diffusive vertical flux using average flux from the sub-timestepping
  538. DO jj = 2, jpjm1
  539. DO ji = fs_2, fs_jpim1
  540. zwz(ji,jj,jk) = zwzts(ji,jj,jk) * zr_p2dt(jk) - zwz_sav(ji,jj,jk)
  541. END DO
  542. END DO
  543. END DO
  544. CALL lbc_lnk( zwx, 'U', -1. ) ; CALL lbc_lnk( zwy, 'V', -1. ) ! Lateral bondary conditions
  545. CALL lbc_lnk( zwz, 'W', 1. )
  546. ! 4. monotonicity algorithm
  547. ! -------------------------
  548. CALL nonosc( ptb(:,:,:,jn), zwx, zwy, zwz, zwi, p2dt )
  549. ! 5. final trend with corrected fluxes
  550. ! ------------------------------------
  551. DO jk = 1, jpkm1
  552. DO jj = 2, jpjm1
  553. DO ji = fs_2, fs_jpim1 ! vector opt.
  554. zbtr = 1. / ( e1t(ji,jj) * e2t(ji,jj) * fse3t(ji,jj,jk) )
  555. ! total advective trends
  556. ztra = - zbtr * ( zwx(ji,jj,jk) - zwx(ji-1,jj ,jk ) &
  557. & + zwy(ji,jj,jk) - zwy(ji ,jj-1,jk ) &
  558. & + zwz(ji,jj,jk) - zwz(ji ,jj ,jk+1) )
  559. ! add them to the general tracer trends
  560. pta(ji,jj,jk,jn) = pta(ji,jj,jk,jn) + ztra
  561. END DO
  562. END DO
  563. END DO
  564. ! ! trend diagnostics (contribution of upstream fluxes)
  565. IF( l_trd ) THEN
  566. ztrdx(:,:,:) = ztrdx(:,:,:) + zwx(:,:,:) ! <<< Add to previously computed
  567. ztrdy(:,:,:) = ztrdy(:,:,:) + zwy(:,:,:) ! <<< Add to previously computed
  568. ztrdz(:,:,:) = ztrdz(:,:,:) + zwz(:,:,:) ! <<< Add to previously computed
  569. CALL trd_tra( kt, cdtype, jn, jptra_xad, ztrdx, pun, ptn(:,:,:,jn) )
  570. CALL trd_tra( kt, cdtype, jn, jptra_yad, ztrdy, pvn, ptn(:,:,:,jn) )
  571. CALL trd_tra( kt, cdtype, jn, jptra_zad, ztrdz, pwn, ptn(:,:,:,jn) )
  572. END IF
  573. !
  574. IF( jn==jp_tem ) THEN
  575. z2d(:,:) = 0._wp
  576. DO jk = 1, jpkm1
  577. DO jj = 2, jpjm1
  578. DO ji = fs_2, fs_jpim1 ! vector opt.
  579. z2d(ji,jj) = z2d(ji,jj) + ztrdx(ji,jj,jk)
  580. END DO
  581. END DO
  582. END DO
  583. z2d(:,:) = rau0_rcp * z2d(:,:)
  584. CALL lbc_lnk( z2d, 'U', -1. )
  585. CALL iom_put( "uadv_heattr", z2d ) ! heat transport in i-direction
  586. !
  587. z2d(:,:) = 0._wp
  588. DO jk = 1, jpkm1
  589. DO jj = 2, jpjm1
  590. DO ji = fs_2, fs_jpim1 ! vector opt.
  591. z2d(ji,jj) = z2d(ji,jj) + ztrdy(ji,jj,jk)
  592. END DO
  593. END DO
  594. END DO
  595. z2d(:,:) = rau0_rcp * z2d(:,:)
  596. CALL lbc_lnk( z2d, 'V', -1. )
  597. CALL iom_put( "vadv_heattr", z2d ) ! heat transport in j-direction
  598. ENDIF
  599. ! ! "Poleward" heat and salt transports (contribution of upstream fluxes)
  600. IF( cdtype == 'TRA' .AND. ln_diaptr ) THEN
  601. zptry(:,:,:) = zptry(:,:,:) + zwy(:,:,:)
  602. CALL dia_ptr_ohst_components( jn, 'adv', zptry(:,:,:) )
  603. ENDIF
  604. !
  605. END DO
  606. !
  607. CALL wrk_dealloc( jpi, jpj, jpk, zwi, zwz, zhdiv, zwz_sav, zwzts )
  608. CALL wrk_dealloc( jpi, jpj, jpk, kjpt+1, ztrs )
  609. CALL wrk_dealloc( jpi, jpj, zwx_sav, zwy_sav )
  610. IF( l_trd ) CALL wrk_dealloc( jpi, jpj, jpk, ztrdx, ztrdy, ztrdz )
  611. CALL wrk_dealloc( jpi, jpj, z2d )
  612. IF( cdtype == 'TRA' .AND. ln_diaptr ) CALL wrk_dealloc( jpi, jpj, jpk, zptry )
  613. !
  614. IF( nn_timing == 1 ) CALL timing_stop('tra_adv_tvd_zts')
  615. !
  616. END SUBROUTINE tra_adv_tvd_zts
  617. SUBROUTINE nonosc( pbef, paa, pbb, pcc, paft, p2dt )
  618. !!---------------------------------------------------------------------
  619. !! *** ROUTINE nonosc ***
  620. !!
  621. !! ** Purpose : compute monotonic tracer fluxes from the upstream
  622. !! scheme and the before field by a nonoscillatory algorithm
  623. !!
  624. !! ** Method : ... ???
  625. !! warning : pbef and paft must be masked, but the boundaries
  626. !! conditions on the fluxes are not necessary zalezak (1979)
  627. !! drange (1995) multi-dimensional forward-in-time and upstream-
  628. !! in-space based differencing for fluid
  629. !!----------------------------------------------------------------------
  630. REAL(wp), DIMENSION(jpk) , INTENT(in ) :: p2dt ! vertical profile of tracer time-step
  631. REAL(wp), DIMENSION (jpi,jpj,jpk), INTENT(in ) :: pbef, paft ! before & after field
  632. REAL(wp), DIMENSION (jpi,jpj,jpk), INTENT(inout) :: paa, pbb, pcc ! monotonic fluxes in the 3 directions
  633. !
  634. INTEGER :: ji, jj, jk ! dummy loop indices
  635. INTEGER :: ikm1 ! local integer
  636. REAL(wp) :: zpos, zneg, zbt, za, zb, zc, zbig, zrtrn, z2dtt ! local scalars
  637. REAL(wp) :: zau, zbu, zcu, zav, zbv, zcv, zup, zdo ! - -
  638. REAL(wp), POINTER, DIMENSION(:,:,:) :: zbetup, zbetdo, zbup, zbdo
  639. !!----------------------------------------------------------------------
  640. !
  641. IF( nn_timing == 1 ) CALL timing_start('nonosc')
  642. !
  643. CALL wrk_alloc( jpi, jpj, jpk, zbetup, zbetdo, zbup, zbdo )
  644. !
  645. zbig = 1.e+40_wp
  646. zrtrn = 1.e-15_wp
  647. zbetup(:,:,:) = 0._wp ; zbetdo(:,:,:) = 0._wp
  648. ! Search local extrema
  649. ! --------------------
  650. ! max/min of pbef & paft with large negative/positive value (-/+zbig) inside land
  651. zbup = MAX( pbef * tmask - zbig * ( 1._wp - tmask ), &
  652. & paft * tmask - zbig * ( 1._wp - tmask ) )
  653. zbdo = MIN( pbef * tmask + zbig * ( 1._wp - tmask ), &
  654. & paft * tmask + zbig * ( 1._wp - tmask ) )
  655. DO jk = 1, jpkm1
  656. ikm1 = MAX(jk-1,1)
  657. z2dtt = p2dt(jk)
  658. DO jj = 2, jpjm1
  659. DO ji = fs_2, fs_jpim1 ! vector opt.
  660. ! search maximum in neighbourhood
  661. zup = MAX( zbup(ji ,jj ,jk ), &
  662. & zbup(ji-1,jj ,jk ), zbup(ji+1,jj ,jk ), &
  663. & zbup(ji ,jj-1,jk ), zbup(ji ,jj+1,jk ), &
  664. & zbup(ji ,jj ,ikm1), zbup(ji ,jj ,jk+1) )
  665. ! search minimum in neighbourhood
  666. zdo = MIN( zbdo(ji ,jj ,jk ), &
  667. & zbdo(ji-1,jj ,jk ), zbdo(ji+1,jj ,jk ), &
  668. & zbdo(ji ,jj-1,jk ), zbdo(ji ,jj+1,jk ), &
  669. & zbdo(ji ,jj ,ikm1), zbdo(ji ,jj ,jk+1) )
  670. ! positive part of the flux
  671. zpos = MAX( 0., paa(ji-1,jj ,jk ) ) - MIN( 0., paa(ji ,jj ,jk ) ) &
  672. & + MAX( 0., pbb(ji ,jj-1,jk ) ) - MIN( 0., pbb(ji ,jj ,jk ) ) &
  673. & + MAX( 0., pcc(ji ,jj ,jk+1) ) - MIN( 0., pcc(ji ,jj ,jk ) )
  674. ! negative part of the flux
  675. zneg = MAX( 0., paa(ji ,jj ,jk ) ) - MIN( 0., paa(ji-1,jj ,jk ) ) &
  676. & + MAX( 0., pbb(ji ,jj ,jk ) ) - MIN( 0., pbb(ji ,jj-1,jk ) ) &
  677. & + MAX( 0., pcc(ji ,jj ,jk ) ) - MIN( 0., pcc(ji ,jj ,jk+1) )
  678. ! up & down beta terms
  679. zbt = e1t(ji,jj) * e2t(ji,jj) * fse3t(ji,jj,jk) / z2dtt
  680. zbetup(ji,jj,jk) = ( zup - paft(ji,jj,jk) ) / ( zpos + zrtrn ) * zbt
  681. zbetdo(ji,jj,jk) = ( paft(ji,jj,jk) - zdo ) / ( zneg + zrtrn ) * zbt
  682. END DO
  683. END DO
  684. END DO
  685. CALL lbc_lnk( zbetup, 'T', 1. ) ; CALL lbc_lnk( zbetdo, 'T', 1. ) ! lateral boundary cond. (unchanged sign)
  686. ! 3. monotonic flux in the i & j direction (paa & pbb)
  687. ! ----------------------------------------
  688. DO jk = 1, jpkm1
  689. DO jj = 2, jpjm1
  690. DO ji = fs_2, fs_jpim1 ! vector opt.
  691. zau = MIN( 1._wp, zbetdo(ji,jj,jk), zbetup(ji+1,jj,jk) )
  692. zbu = MIN( 1._wp, zbetup(ji,jj,jk), zbetdo(ji+1,jj,jk) )
  693. zcu = ( 0.5 + SIGN( 0.5 , paa(ji,jj,jk) ) )
  694. paa(ji,jj,jk) = paa(ji,jj,jk) * ( zcu * zau + ( 1._wp - zcu) * zbu )
  695. zav = MIN( 1._wp, zbetdo(ji,jj,jk), zbetup(ji,jj+1,jk) )
  696. zbv = MIN( 1._wp, zbetup(ji,jj,jk), zbetdo(ji,jj+1,jk) )
  697. zcv = ( 0.5 + SIGN( 0.5 , pbb(ji,jj,jk) ) )
  698. pbb(ji,jj,jk) = pbb(ji,jj,jk) * ( zcv * zav + ( 1._wp - zcv) * zbv )
  699. ! monotonic flux in the k direction, i.e. pcc
  700. ! -------------------------------------------
  701. za = MIN( 1., zbetdo(ji,jj,jk+1), zbetup(ji,jj,jk) )
  702. zb = MIN( 1., zbetup(ji,jj,jk+1), zbetdo(ji,jj,jk) )
  703. zc = ( 0.5 + SIGN( 0.5 , pcc(ji,jj,jk+1) ) )
  704. pcc(ji,jj,jk+1) = pcc(ji,jj,jk+1) * ( zc * za + ( 1._wp - zc) * zb )
  705. END DO
  706. END DO
  707. END DO
  708. CALL lbc_lnk( paa, 'U', -1. ) ; CALL lbc_lnk( pbb, 'V', -1. ) ! lateral boundary condition (changed sign)
  709. !
  710. CALL wrk_dealloc( jpi, jpj, jpk, zbetup, zbetdo, zbup, zbdo )
  711. !
  712. IF( nn_timing == 1 ) CALL timing_stop('nonosc')
  713. !
  714. END SUBROUTINE nonosc
  715. !!======================================================================
  716. END MODULE traadv_tvd