traadv_ubs.F90 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. MODULE traadv_ubs
  2. !!==============================================================================
  3. !! *** MODULE traadv_ubs ***
  4. !! Ocean active tracers: horizontal & vertical advective trend
  5. !!==============================================================================
  6. !! History : 1.0 ! 2006-08 (L. Debreu, R. Benshila) Original code
  7. !! 3.3 ! 2010-05 (C. Ethe, G. Madec) merge TRC-TRA + switch from velocity to transport
  8. !!----------------------------------------------------------------------
  9. !!----------------------------------------------------------------------
  10. !! tra_adv_ubs : update the tracer trend with the horizontal
  11. !! advection trends using a third order biaised scheme
  12. !!----------------------------------------------------------------------
  13. USE oce ! ocean dynamics and active tracers
  14. USE dom_oce ! ocean space and time domain
  15. USE trc_oce ! share passive tracers/Ocean variables
  16. USE trd_oce ! trends: ocean variables
  17. USE trdtra ! trends manager: tracers
  18. USE dynspg_oce ! choice/control of key cpp for surface pressure gradient
  19. USE diaptr ! poleward transport diagnostics
  20. !
  21. USE lib_mpp ! I/O library
  22. USE lbclnk ! ocean lateral boundary condition (or mpp link)
  23. USE in_out_manager ! I/O manager
  24. USE wrk_nemo ! Memory Allocation
  25. USE timing ! Timing
  26. USE lib_fortran ! Fortran utilities (allows no signed zero when 'key_nosignedzero' defined)
  27. IMPLICIT NONE
  28. PRIVATE
  29. PUBLIC tra_adv_ubs ! routine called by traadv module
  30. LOGICAL :: l_trd ! flag to compute trends or not
  31. !! * Substitutions
  32. # include "domzgr_substitute.h90"
  33. # include "vectopt_loop_substitute.h90"
  34. !!----------------------------------------------------------------------
  35. !! NEMO/OPA 3.3 , NEMO Consortium (2010)
  36. !! $Id: traadv_ubs.F90 4990 2014-12-15 16:42:49Z timgraham $
  37. !! Software governed by the CeCILL licence (NEMOGCM/NEMO_CeCILL.txt)
  38. !!----------------------------------------------------------------------
  39. CONTAINS
  40. SUBROUTINE tra_adv_ubs ( kt, kit000, cdtype, p2dt, pun, pvn, pwn, &
  41. & ptb, ptn, pta, kjpt )
  42. !!----------------------------------------------------------------------
  43. !! *** ROUTINE tra_adv_ubs ***
  44. !!
  45. !! ** Purpose : Compute the now trend due to the advection of tracers
  46. !! and add it to the general trend of passive tracer equations.
  47. !!
  48. !! ** Method : The upstream biased scheme (UBS) is based on a 3rd order
  49. !! upstream-biased parabolic interpolation (Shchepetkin and McWilliams 2005)
  50. !! It is only used in the horizontal direction.
  51. !! For example the i-component of the advective fluxes are given by :
  52. !! ! e2u e3u un ( mi(Tn) - zltu(i ) ) if un(i) >= 0
  53. !! ztu = ! or
  54. !! ! e2u e3u un ( mi(Tn) - zltu(i+1) ) if un(i) < 0
  55. !! where zltu is the second derivative of the before temperature field:
  56. !! zltu = 1/e3t di[ e2u e3u / e1u di[Tb] ]
  57. !! This results in a dissipatively dominant (i.e. hyper-diffusive)
  58. !! truncation error. The overall performance of the advection scheme
  59. !! is similar to that reported in (Farrow and Stevens, 1995).
  60. !! For stability reasons, the first term of the fluxes which corresponds
  61. !! to a second order centered scheme is evaluated using the now velocity
  62. !! (centered in time) while the second term which is the diffusive part
  63. !! of the scheme, is evaluated using the before velocity (forward in time).
  64. !! Note that UBS is not positive. Do not use it on passive tracers.
  65. !! On the vertical, the advection is evaluated using a TVD scheme,
  66. !! as the UBS have been found to be too diffusive.
  67. !!
  68. !! ** Action : - update (pta) with the now advective tracer trends
  69. !!
  70. !! Reference : Shchepetkin, A. F., J. C. McWilliams, 2005, Ocean Modelling, 9, 347-404.
  71. !! Farrow, D.E., Stevens, D.P., 1995, J. Phys. Ocean. 25, 1731Ð1741.
  72. !!----------------------------------------------------------------------
  73. INTEGER , INTENT(in ) :: kt ! ocean time-step index
  74. INTEGER , INTENT(in ) :: kit000 ! first time step index
  75. CHARACTER(len=3) , INTENT(in ) :: cdtype ! =TRA or TRC (tracer indicator)
  76. INTEGER , INTENT(in ) :: kjpt ! number of tracers
  77. REAL(wp), DIMENSION( jpk ), INTENT(in ) :: p2dt ! vertical profile of tracer time-step
  78. REAL(wp), DIMENSION(jpi,jpj,jpk ), INTENT(in ) :: pun, pvn, pwn ! 3 ocean transport components
  79. REAL(wp), DIMENSION(jpi,jpj,jpk,kjpt), INTENT(in ) :: ptb, ptn ! before and now tracer fields
  80. REAL(wp), DIMENSION(jpi,jpj,jpk,kjpt), INTENT(inout) :: pta ! tracer trend
  81. !
  82. INTEGER :: ji, jj, jk, jn ! dummy loop indices
  83. REAL(wp) :: ztra, zbtr, zcoef, z2dtt ! local scalars
  84. REAL(wp) :: zfp_ui, zfm_ui, zcenut, ztak, zfp_wk, zfm_wk ! - -
  85. REAL(wp) :: zfp_vj, zfm_vj, zcenvt, zeeu, zeev, z_hdivn ! - -
  86. REAL(wp), POINTER, DIMENSION(:,:,:) :: ztu, ztv, zltu, zltv, zti, ztw
  87. !!----------------------------------------------------------------------
  88. !
  89. IF( nn_timing == 1 ) CALL timing_start('tra_adv_ubs')
  90. !
  91. CALL wrk_alloc( jpi, jpj, jpk, ztu, ztv, zltu, zltv, zti, ztw )
  92. !
  93. IF( kt == kit000 ) THEN
  94. IF(lwp) WRITE(numout,*)
  95. IF(lwp) WRITE(numout,*) 'tra_adv_ubs : horizontal UBS advection scheme on ', cdtype
  96. IF(lwp) WRITE(numout,*) '~~~~~~~~~~~~'
  97. ENDIF
  98. !
  99. l_trd = .FALSE.
  100. IF( ( cdtype == 'TRA' .AND. l_trdtra ) .OR. ( cdtype == 'TRC' .AND. l_trdtrc ) ) l_trd = .TRUE.
  101. !
  102. ! ! ===========
  103. DO jn = 1, kjpt ! tracer loop
  104. ! ! ===========
  105. ! 1. Bottom value : flux set to zero
  106. ! ----------------------------------
  107. zltu(:,:,jpk) = 0.e0 ; zltv(:,:,jpk) = 0.e0
  108. !
  109. DO jk = 1, jpkm1 ! Horizontal slab
  110. !
  111. ! Laplacian
  112. DO jj = 1, jpjm1 ! First derivative (gradient)
  113. DO ji = 1, fs_jpim1 ! vector opt.
  114. zeeu = e2u(ji,jj) * fse3u(ji,jj,jk) / e1u(ji,jj) * umask(ji,jj,jk)
  115. zeev = e1v(ji,jj) * fse3v(ji,jj,jk) / e2v(ji,jj) * vmask(ji,jj,jk)
  116. ztu(ji,jj,jk) = zeeu * ( ptb(ji+1,jj ,jk,jn) - ptb(ji,jj,jk,jn) )
  117. ztv(ji,jj,jk) = zeev * ( ptb(ji ,jj+1,jk,jn) - ptb(ji,jj,jk,jn) )
  118. END DO
  119. END DO
  120. DO jj = 2, jpjm1 ! Second derivative (divergence)
  121. DO ji = fs_2, fs_jpim1 ! vector opt.
  122. zcoef = 1. / ( 6. * fse3t(ji,jj,jk) )
  123. zltu(ji,jj,jk) = ( ztu(ji,jj,jk) - ztu(ji-1,jj,jk) ) * zcoef
  124. zltv(ji,jj,jk) = ( ztv(ji,jj,jk) - ztv(ji,jj-1,jk) ) * zcoef
  125. END DO
  126. END DO
  127. !
  128. END DO ! End of slab
  129. CALL lbc_lnk( zltu, 'T', 1. ) ; CALL lbc_lnk( zltv, 'T', 1. ) ! Lateral boundary cond. (unchanged sgn)
  130. !
  131. ! Horizontal advective fluxes
  132. DO jk = 1, jpkm1 ! Horizontal slab
  133. DO jj = 1, jpjm1
  134. DO ji = 1, fs_jpim1 ! vector opt.
  135. ! upstream transport (x2)
  136. zfp_ui = pun(ji,jj,jk) + ABS( pun(ji,jj,jk) )
  137. zfm_ui = pun(ji,jj,jk) - ABS( pun(ji,jj,jk) )
  138. zfp_vj = pvn(ji,jj,jk) + ABS( pvn(ji,jj,jk) )
  139. zfm_vj = pvn(ji,jj,jk) - ABS( pvn(ji,jj,jk) )
  140. ! 2nd order centered advective fluxes (x2)
  141. zcenut = pun(ji,jj,jk) * ( ptn(ji,jj,jk,jn) + ptn(ji+1,jj ,jk,jn) )
  142. zcenvt = pvn(ji,jj,jk) * ( ptn(ji,jj,jk,jn) + ptn(ji ,jj+1,jk,jn) )
  143. ! UBS advective fluxes
  144. ztu(ji,jj,jk) = 0.5 * ( zcenut - zfp_ui * zltu(ji,jj,jk) - zfm_ui * zltu(ji+1,jj,jk) )
  145. ztv(ji,jj,jk) = 0.5 * ( zcenvt - zfp_vj * zltv(ji,jj,jk) - zfm_vj * zltv(ji,jj+1,jk) )
  146. END DO
  147. END DO
  148. END DO ! End of slab
  149. zltu(:,:,:) = pta(:,:,:,jn) ! store pta trends
  150. DO jk = 1, jpkm1 ! Horizontal advective trends
  151. DO jj = 2, jpjm1
  152. DO ji = fs_2, fs_jpim1 ! vector opt.
  153. pta(ji,jj,jk,jn) = pta(ji,jj,jk,jn) &
  154. & - ( ztu(ji,jj,jk) - ztu(ji-1,jj ,jk) &
  155. & + ztv(ji,jj,jk) - ztv(ji ,jj-1,jk) ) / ( e1e2t(ji,jj) * fse3t(ji,jj,jk) )
  156. END DO
  157. END DO
  158. !
  159. END DO ! End of slab
  160. ! Horizontal trend used in tra_adv_ztvd subroutine
  161. zltu(:,:,:) = pta(:,:,:,jn) - zltu(:,:,:)
  162. !
  163. IF( l_trd ) THEN ! trend diagnostics
  164. CALL trd_tra( kt, cdtype, jn, jptra_xad, ztu, pun, ptn(:,:,:,jn) )
  165. CALL trd_tra( kt, cdtype, jn, jptra_yad, ztv, pvn, ptn(:,:,:,jn) )
  166. END IF
  167. ! ! "Poleward" heat and salt transports (contribution of upstream fluxes)
  168. IF( cdtype == 'TRA' .AND. ln_diaptr ) CALL dia_ptr_ohst_components( jn, 'adv', ztv(:,:,:) )
  169. ! TVD scheme for the vertical direction
  170. ! ----------------------
  171. IF( l_trd ) zltv(:,:,:) = pta(:,:,:,jn) ! store pta if trend diag.
  172. ! Bottom value : flux set to zero
  173. ztw(:,:,jpk) = 0.e0 ; zti(:,:,jpk) = 0.e0
  174. ! Surface value
  175. IF( lk_vvl ) THEN ; ztw(:,:,1) = 0.e0 ! variable volume : flux set to zero
  176. ELSE ; ztw(:,:,1) = pwn(:,:,1) * ptb(:,:,1,jn) ! free constant surface
  177. ENDIF
  178. ! upstream advection with initial mass fluxes & intermediate update
  179. ! -------------------------------------------------------------------
  180. ! Interior value
  181. DO jk = 2, jpkm1
  182. DO jj = 1, jpj
  183. DO ji = 1, jpi
  184. zfp_wk = pwn(ji,jj,jk) + ABS( pwn(ji,jj,jk) )
  185. zfm_wk = pwn(ji,jj,jk) - ABS( pwn(ji,jj,jk) )
  186. ztw(ji,jj,jk) = 0.5 * ( zfp_wk * ptb(ji,jj,jk,jn) + zfm_wk * ptb(ji,jj,jk-1,jn) )
  187. END DO
  188. END DO
  189. END DO
  190. ! update and guess with monotonic sheme
  191. DO jk = 1, jpkm1
  192. z2dtt = p2dt(jk)
  193. DO jj = 2, jpjm1
  194. DO ji = fs_2, fs_jpim1 ! vector opt.
  195. zbtr = 1. / ( e1t(ji,jj) * e2t(ji,jj) * fse3t(ji,jj,jk) )
  196. ztak = - ( ztw(ji,jj,jk) - ztw(ji,jj,jk+1) ) * zbtr
  197. pta(ji,jj,jk,jn) = pta(ji,jj,jk,jn) + ztak
  198. zti(ji,jj,jk) = ( ptb(ji,jj,jk,jn) + z2dtt * ( ztak + zltu(ji,jj,jk) ) ) * tmask(ji,jj,jk)
  199. END DO
  200. END DO
  201. END DO
  202. !
  203. CALL lbc_lnk( zti, 'T', 1. ) ! Lateral boundary conditions on zti, zsi (unchanged sign)
  204. ! antidiffusive flux : high order minus low order
  205. ztw(:,:,1) = 0.e0 ! Surface value
  206. DO jk = 2, jpkm1 ! Interior value
  207. DO jj = 1, jpj
  208. DO ji = 1, jpi
  209. ztw(ji,jj,jk) = 0.5 * pwn(ji,jj,jk) * ( ptn(ji,jj,jk,jn) + ptn(ji,jj,jk-1,jn) ) - ztw(ji,jj,jk)
  210. END DO
  211. END DO
  212. END DO
  213. !
  214. CALL nonosc_z( ptb(:,:,:,jn), ztw, zti, p2dt ) ! monotonicity algorithm
  215. ! final trend with corrected fluxes
  216. DO jk = 1, jpkm1
  217. DO jj = 2, jpjm1
  218. DO ji = fs_2, fs_jpim1 ! vector opt.
  219. zbtr = 1. / ( e1t(ji,jj) * e2t(ji,jj) * fse3t(ji,jj,jk) )
  220. ! k- vertical advective trends
  221. ztra = - zbtr * ( ztw(ji,jj,jk) - ztw(ji,jj,jk+1) )
  222. ! added to the general tracer trends
  223. pta(ji,jj,jk,jn) = pta(ji,jj,jk,jn) + ztra
  224. END DO
  225. END DO
  226. END DO
  227. ! Save the final vertical advective trends
  228. IF( l_trd ) THEN ! vertical advective trend diagnostics
  229. DO jk = 1, jpkm1 ! (compute -w.dk[ptn]= -dk[w.ptn] + ptn.dk[w])
  230. DO jj = 2, jpjm1
  231. DO ji = fs_2, fs_jpim1 ! vector opt.
  232. zbtr = 1.e0 / ( e1t(ji,jj) * e2t(ji,jj) * fse3t(ji,jj,jk) )
  233. z_hdivn = ( pwn(ji,jj,jk) - pwn(ji,jj,jk+1) ) * zbtr
  234. zltv(ji,jj,jk) = pta(ji,jj,jk,jn) - zltv(ji,jj,jk) + ptn(ji,jj,jk,jn) * z_hdivn
  235. END DO
  236. END DO
  237. END DO
  238. CALL trd_tra( kt, cdtype, jn, jptra_zad, zltv )
  239. ENDIF
  240. !
  241. END DO
  242. !
  243. CALL wrk_dealloc( jpi, jpj, jpk, ztu, ztv, zltu, zltv, zti, ztw )
  244. !
  245. IF( nn_timing == 1 ) CALL timing_stop('tra_adv_ubs')
  246. !
  247. END SUBROUTINE tra_adv_ubs
  248. SUBROUTINE nonosc_z( pbef, pcc, paft, p2dt )
  249. !!---------------------------------------------------------------------
  250. !! *** ROUTINE nonosc_z ***
  251. !!
  252. !! ** Purpose : compute monotonic tracer fluxes from the upstream
  253. !! scheme and the before field by a nonoscillatory algorithm
  254. !!
  255. !! ** Method : ... ???
  256. !! warning : pbef and paft must be masked, but the boundaries
  257. !! conditions on the fluxes are not necessary zalezak (1979)
  258. !! drange (1995) multi-dimensional forward-in-time and upstream-
  259. !! in-space based differencing for fluid
  260. !!----------------------------------------------------------------------
  261. REAL(wp), INTENT(in ), DIMENSION(jpk) :: p2dt ! vertical profile of tracer time-step
  262. REAL(wp), DIMENSION (jpi,jpj,jpk) :: pbef ! before field
  263. REAL(wp), INTENT(inout), DIMENSION (jpi,jpj,jpk) :: paft ! after field
  264. REAL(wp), INTENT(inout), DIMENSION (jpi,jpj,jpk) :: pcc ! monotonic flux in the k direction
  265. !
  266. INTEGER :: ji, jj, jk ! dummy loop indices
  267. INTEGER :: ikm1 ! local integer
  268. REAL(wp) :: zpos, zneg, zbt, za, zb, zc, zbig, zrtrn, z2dtt ! local scalars
  269. REAL(wp), POINTER, DIMENSION(:,:,:) :: zbetup, zbetdo
  270. !!----------------------------------------------------------------------
  271. !
  272. IF( nn_timing == 1 ) CALL timing_start('nonosc_z')
  273. !
  274. CALL wrk_alloc( jpi, jpj, jpk, zbetup, zbetdo )
  275. !
  276. zbig = 1.e+40_wp
  277. zrtrn = 1.e-15_wp
  278. zbetup(:,:,:) = 0._wp ; zbetdo(:,:,:) = 0._wp
  279. ! Search local extrema
  280. ! --------------------
  281. ! large negative value (-zbig) inside land
  282. pbef(:,:,:) = pbef(:,:,:) * tmask(:,:,:) - zbig * ( 1.e0 - tmask(:,:,:) )
  283. paft(:,:,:) = paft(:,:,:) * tmask(:,:,:) - zbig * ( 1.e0 - tmask(:,:,:) )
  284. ! search maximum in neighbourhood
  285. DO jk = 1, jpkm1
  286. ikm1 = MAX(jk-1,1)
  287. DO jj = 2, jpjm1
  288. DO ji = fs_2, fs_jpim1 ! vector opt.
  289. zbetup(ji,jj,jk) = MAX( pbef(ji ,jj ,jk ), paft(ji ,jj ,jk ), &
  290. & pbef(ji ,jj ,ikm1), pbef(ji ,jj ,jk+1), &
  291. & paft(ji ,jj ,ikm1), paft(ji ,jj ,jk+1) )
  292. END DO
  293. END DO
  294. END DO
  295. ! large positive value (+zbig) inside land
  296. pbef(:,:,:) = pbef(:,:,:) * tmask(:,:,:) + zbig * ( 1.e0 - tmask(:,:,:) )
  297. paft(:,:,:) = paft(:,:,:) * tmask(:,:,:) + zbig * ( 1.e0 - tmask(:,:,:) )
  298. ! search minimum in neighbourhood
  299. DO jk = 1, jpkm1
  300. ikm1 = MAX(jk-1,1)
  301. DO jj = 2, jpjm1
  302. DO ji = fs_2, fs_jpim1 ! vector opt.
  303. zbetdo(ji,jj,jk) = MIN( pbef(ji ,jj ,jk ), paft(ji ,jj ,jk ), &
  304. & pbef(ji ,jj ,ikm1), pbef(ji ,jj ,jk+1), &
  305. & paft(ji ,jj ,ikm1), paft(ji ,jj ,jk+1) )
  306. END DO
  307. END DO
  308. END DO
  309. ! restore masked values to zero
  310. pbef(:,:,:) = pbef(:,:,:) * tmask(:,:,:)
  311. paft(:,:,:) = paft(:,:,:) * tmask(:,:,:)
  312. ! 2. Positive and negative part of fluxes and beta terms
  313. ! ------------------------------------------------------
  314. DO jk = 1, jpkm1
  315. z2dtt = p2dt(jk)
  316. DO jj = 2, jpjm1
  317. DO ji = fs_2, fs_jpim1 ! vector opt.
  318. ! positive & negative part of the flux
  319. zpos = MAX( 0., pcc(ji ,jj ,jk+1) ) - MIN( 0., pcc(ji ,jj ,jk ) )
  320. zneg = MAX( 0., pcc(ji ,jj ,jk ) ) - MIN( 0., pcc(ji ,jj ,jk+1) )
  321. ! up & down beta terms
  322. zbt = e1t(ji,jj) * e2t(ji,jj) * fse3t(ji,jj,jk) / z2dtt
  323. zbetup(ji,jj,jk) = ( zbetup(ji,jj,jk) - paft(ji,jj,jk) ) / (zpos+zrtrn) * zbt
  324. zbetdo(ji,jj,jk) = ( paft(ji,jj,jk) - zbetdo(ji,jj,jk) ) / (zneg+zrtrn) * zbt
  325. END DO
  326. END DO
  327. END DO
  328. ! monotonic flux in the k direction, i.e. pcc
  329. ! -------------------------------------------
  330. DO jk = 2, jpkm1
  331. DO jj = 2, jpjm1
  332. DO ji = fs_2, fs_jpim1 ! vector opt.
  333. za = MIN( 1., zbetdo(ji,jj,jk), zbetup(ji,jj,jk-1) )
  334. zb = MIN( 1., zbetup(ji,jj,jk), zbetdo(ji,jj,jk-1) )
  335. zc = 0.5 * ( 1.e0 + SIGN( 1.e0, pcc(ji,jj,jk) ) )
  336. pcc(ji,jj,jk) = pcc(ji,jj,jk) * ( zc * za + ( 1.e0 - zc) * zb )
  337. END DO
  338. END DO
  339. END DO
  340. !
  341. CALL wrk_dealloc( jpi, jpj, jpk, zbetup, zbetdo )
  342. !
  343. IF( nn_timing == 1 ) CALL timing_stop('nonosc_z')
  344. !
  345. END SUBROUTINE nonosc_z
  346. !!======================================================================
  347. END MODULE traadv_ubs