dynzad.F90 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. MODULE dynzad
  2. !!======================================================================
  3. !! *** MODULE dynzad ***
  4. !! Ocean dynamics : vertical advection trend
  5. !!======================================================================
  6. !! History : OPA ! 1991-01 (G. Madec) Original code
  7. !! 7.0 ! 1991-11 (G. Madec)
  8. !! 7.5 ! 1996-01 (G. Madec) statement function for e3
  9. !! NEMO 0.5 ! 2002-07 (G. Madec) Free form, F90
  10. !!----------------------------------------------------------------------
  11. !!----------------------------------------------------------------------
  12. !! dyn_zad : vertical advection momentum trend
  13. !!----------------------------------------------------------------------
  14. USE oce ! ocean dynamics and tracers
  15. USE dom_oce ! ocean space and time domain
  16. USE sbc_oce ! surface boundary condition: ocean
  17. USE trd_oce ! trends: ocean variables
  18. USE trddyn ! trend manager: dynamics
  19. !
  20. USE in_out_manager ! I/O manager
  21. USE lib_mpp ! MPP library
  22. USE prtctl ! Print control
  23. USE wrk_nemo ! Memory Allocation
  24. USE timing ! Timing
  25. IMPLICIT NONE
  26. PRIVATE
  27. PUBLIC dyn_zad ! routine called by dynadv.F90
  28. PUBLIC dyn_zad_zts ! routine called by dynadv.F90
  29. !! * Substitutions
  30. # include "domzgr_substitute.h90"
  31. # include "vectopt_loop_substitute.h90"
  32. !!----------------------------------------------------------------------
  33. !! NEMO/OPA 3.3 , NEMO Consortium (2010)
  34. !! $Id: dynzad.F90 4990 2014-12-15 16:42:49Z timgraham $
  35. !! Software governed by the CeCILL licence (NEMOGCM/NEMO_CeCILL.txt)
  36. !!----------------------------------------------------------------------
  37. CONTAINS
  38. SUBROUTINE dyn_zad ( kt )
  39. !!----------------------------------------------------------------------
  40. !! *** ROUTINE dynzad ***
  41. !!
  42. !! ** Purpose : Compute the now vertical momentum advection trend and
  43. !! add it to the general trend of momentum equation.
  44. !!
  45. !! ** Method : The now vertical advection of momentum is given by:
  46. !! w dz(u) = ua + 1/(e1u*e2u*e3u) mk+1[ mi(e1t*e2t*wn) dk(un) ]
  47. !! w dz(v) = va + 1/(e1v*e2v*e3v) mk+1[ mj(e1t*e2t*wn) dk(vn) ]
  48. !! Add this trend to the general trend (ua,va):
  49. !! (ua,va) = (ua,va) + w dz(u,v)
  50. !!
  51. !! ** Action : - Update (ua,va) with the vert. momentum adv. trends
  52. !! - Send the trends to trddyn for diagnostics (l_trddyn=T)
  53. !!----------------------------------------------------------------------
  54. INTEGER, INTENT(in) :: kt ! ocean time-step inedx
  55. !
  56. INTEGER :: ji, jj, jk ! dummy loop indices
  57. REAL(wp) :: zua, zva ! temporary scalars
  58. REAL(wp), POINTER, DIMENSION(:,:,:) :: zwuw , zwvw
  59. REAL(wp), POINTER, DIMENSION(:,: ) :: zww
  60. REAL(wp), POINTER, DIMENSION(:,:,:) :: ztrdu, ztrdv
  61. !!----------------------------------------------------------------------
  62. !
  63. IF( nn_timing == 1 ) CALL timing_start('dyn_zad')
  64. !
  65. CALL wrk_alloc( jpi,jpj, zww )
  66. CALL wrk_alloc( jpi,jpj,jpk, zwuw , zwvw )
  67. !
  68. IF( kt == nit000 ) THEN
  69. IF(lwp)WRITE(numout,*)
  70. IF(lwp)WRITE(numout,*) 'dyn_zad : arakawa advection scheme'
  71. ENDIF
  72. IF( l_trddyn ) THEN ! Save ua and va trends
  73. CALL wrk_alloc( jpi, jpj, jpk, ztrdu, ztrdv )
  74. ztrdu(:,:,:) = ua(:,:,:)
  75. ztrdv(:,:,:) = va(:,:,:)
  76. ENDIF
  77. DO jk = 2, jpkm1 ! Vertical momentum advection at level w and u- and v- vertical
  78. DO jj = 2, jpj ! vertical fluxes
  79. DO ji = fs_2, jpi ! vector opt.
  80. zww(ji,jj) = 0.25_wp * e1t(ji,jj) * e2t(ji,jj) * wn(ji,jj,jk)
  81. END DO
  82. END DO
  83. DO jj = 2, jpjm1 ! vertical momentum advection at w-point
  84. DO ji = fs_2, fs_jpim1 ! vector opt.
  85. zwuw(ji,jj,jk) = ( zww(ji+1,jj ) + zww(ji,jj) ) * ( un(ji,jj,jk-1)-un(ji,jj,jk) )
  86. zwvw(ji,jj,jk) = ( zww(ji ,jj+1) + zww(ji,jj) ) * ( vn(ji,jj,jk-1)-vn(ji,jj,jk) )
  87. END DO
  88. END DO
  89. END DO
  90. !
  91. ! Surface and bottom advective fluxes set to zero
  92. IF ( ln_isfcav ) THEN
  93. DO jj = 2, jpjm1
  94. DO ji = fs_2, fs_jpim1 ! vector opt.
  95. zwuw(ji,jj, 1:miku(ji,jj) ) = 0._wp
  96. zwvw(ji,jj, 1:mikv(ji,jj) ) = 0._wp
  97. zwuw(ji,jj,jpk) = 0._wp
  98. zwvw(ji,jj,jpk) = 0._wp
  99. END DO
  100. END DO
  101. ELSE
  102. DO jj = 2, jpjm1
  103. DO ji = fs_2, fs_jpim1 ! vector opt.
  104. zwuw(ji,jj, 1 ) = 0._wp
  105. zwvw(ji,jj, 1 ) = 0._wp
  106. zwuw(ji,jj,jpk) = 0._wp
  107. zwvw(ji,jj,jpk) = 0._wp
  108. END DO
  109. END DO
  110. END IF
  111. DO jk = 1, jpkm1 ! Vertical momentum advection at u- and v-points
  112. DO jj = 2, jpjm1
  113. DO ji = fs_2, fs_jpim1 ! vector opt.
  114. ! ! vertical momentum advective trends
  115. zua = - ( zwuw(ji,jj,jk) + zwuw(ji,jj,jk+1) ) / ( e1u(ji,jj) * e2u(ji,jj) * fse3u(ji,jj,jk) )
  116. zva = - ( zwvw(ji,jj,jk) + zwvw(ji,jj,jk+1) ) / ( e1v(ji,jj) * e2v(ji,jj) * fse3v(ji,jj,jk) )
  117. ! ! add the trends to the general momentum trends
  118. ua(ji,jj,jk) = ua(ji,jj,jk) + zua
  119. va(ji,jj,jk) = va(ji,jj,jk) + zva
  120. END DO
  121. END DO
  122. END DO
  123. IF( l_trddyn ) THEN ! save the vertical advection trends for diagnostic
  124. ztrdu(:,:,:) = ua(:,:,:) - ztrdu(:,:,:)
  125. ztrdv(:,:,:) = va(:,:,:) - ztrdv(:,:,:)
  126. CALL trd_dyn( ztrdu, ztrdv, jpdyn_zad, kt )
  127. CALL wrk_dealloc( jpi, jpj, jpk, ztrdu, ztrdv )
  128. ENDIF
  129. ! ! Control print
  130. IF(ln_ctl) CALL prt_ctl( tab3d_1=ua, clinfo1=' zad - Ua: ', mask1=umask, &
  131. & tab3d_2=va, clinfo2= ' Va: ', mask2=vmask, clinfo3='dyn' )
  132. !
  133. CALL wrk_dealloc( jpi,jpj, zww )
  134. CALL wrk_dealloc( jpi,jpj,jpk, zwuw , zwvw )
  135. !
  136. IF( nn_timing == 1 ) CALL timing_stop('dyn_zad')
  137. !
  138. END SUBROUTINE dyn_zad
  139. SUBROUTINE dyn_zad_zts ( kt )
  140. !!----------------------------------------------------------------------
  141. !! *** ROUTINE dynzad_zts ***
  142. !!
  143. !! ** Purpose : Compute the now vertical momentum advection trend and
  144. !! add it to the general trend of momentum equation. This version
  145. !! uses sub-timesteps for improved numerical stability with small
  146. !! vertical grid sizes. This is especially relevant when using
  147. !! embedded ice with thin surface boxes.
  148. !!
  149. !! ** Method : The now vertical advection of momentum is given by:
  150. !! w dz(u) = ua + 1/(e1u*e2u*e3u) mk+1[ mi(e1t*e2t*wn) dk(un) ]
  151. !! w dz(v) = va + 1/(e1v*e2v*e3v) mk+1[ mj(e1t*e2t*wn) dk(vn) ]
  152. !! Add this trend to the general trend (ua,va):
  153. !! (ua,va) = (ua,va) + w dz(u,v)
  154. !!
  155. !! ** Action : - Update (ua,va) with the vert. momentum adv. trends
  156. !! - Save the trends in (ztrdu,ztrdv) ('key_trddyn')
  157. !!----------------------------------------------------------------------
  158. INTEGER, INTENT(in) :: kt ! ocean time-step inedx
  159. !
  160. INTEGER :: ji, jj, jk, jl ! dummy loop indices
  161. INTEGER :: jnzts = 5 ! number of sub-timesteps for vertical advection
  162. INTEGER :: jtb, jtn, jta ! sub timestep pointers for leap-frog/euler forward steps
  163. REAL(wp) :: zua, zva ! temporary scalars
  164. REAL(wp) :: zr_rdt ! temporary scalar
  165. REAL(wp) :: z2dtzts ! length of Euler forward sub-timestep for vertical advection
  166. REAL(wp) :: zts ! length of sub-timestep for vertical advection
  167. REAL(wp), POINTER, DIMENSION(:,:,:) :: zwuw , zwvw, zww
  168. REAL(wp), POINTER, DIMENSION(:,:,:) :: ztrdu, ztrdv
  169. REAL(wp), POINTER, DIMENSION(:,:,:,:) :: zus , zvs
  170. !!----------------------------------------------------------------------
  171. !
  172. IF( nn_timing == 1 ) CALL timing_start('dyn_zad_zts')
  173. !
  174. CALL wrk_alloc( jpi,jpj,jpk, zwuw , zwvw, zww )
  175. CALL wrk_alloc( jpi,jpj,jpk,3, zus, zvs )
  176. !
  177. IF( kt == nit000 ) THEN
  178. IF(lwp)WRITE(numout,*)
  179. IF(lwp)WRITE(numout,*) 'dyn_zad_zts : arakawa advection scheme with sub-timesteps'
  180. ENDIF
  181. IF( l_trddyn ) THEN ! Save ua and va trends
  182. CALL wrk_alloc( jpi, jpj, jpk, ztrdu, ztrdv )
  183. ztrdu(:,:,:) = ua(:,:,:)
  184. ztrdv(:,:,:) = va(:,:,:)
  185. ENDIF
  186. IF( neuler == 0 .AND. kt == nit000 ) THEN
  187. z2dtzts = rdt / REAL( jnzts, wp ) ! = rdt (restart with Euler time stepping)
  188. ELSE
  189. z2dtzts = 2._wp * rdt / REAL( jnzts, wp ) ! = 2 rdt (leapfrog)
  190. ENDIF
  191. DO jk = 2, jpkm1 ! Calculate and store vertical fluxes
  192. DO jj = 2, jpj
  193. DO ji = fs_2, jpi ! vector opt.
  194. zww(ji,jj,jk) = 0.25_wp * e1t(ji,jj) * e2t(ji,jj) * wn(ji,jj,jk)
  195. END DO
  196. END DO
  197. END DO
  198. !
  199. ! Surface and bottom advective fluxes set to zero
  200. DO jj = 2, jpjm1
  201. DO ji = fs_2, fs_jpim1 ! vector opt.
  202. zwuw(ji,jj, 1 ) = 0._wp
  203. zwvw(ji,jj, 1 ) = 0._wp
  204. zwuw(ji,jj,jpk) = 0._wp
  205. zwvw(ji,jj,jpk) = 0._wp
  206. END DO
  207. END DO
  208. ! Start with before values and use sub timestepping to reach after values
  209. zus(:,:,:,1) = ub(:,:,:)
  210. zvs(:,:,:,1) = vb(:,:,:)
  211. DO jl = 1, jnzts ! Start of sub timestepping loop
  212. IF( jl == 1 ) THEN ! Euler forward to kick things off
  213. jtb = 1 ; jtn = 1 ; jta = 2
  214. zts = z2dtzts
  215. ELSEIF( jl == 2 ) THEN ! First leapfrog step
  216. jtb = 1 ; jtn = 2 ; jta = 3
  217. zts = 2._wp * z2dtzts
  218. ELSE ! Shuffle pointers for subsequent leapfrog steps
  219. jtb = MOD(jtb,3) + 1
  220. jtn = MOD(jtn,3) + 1
  221. jta = MOD(jta,3) + 1
  222. ENDIF
  223. DO jk = 2, jpkm1 ! Vertical momentum advection at level w and u- and v- vertical
  224. DO jj = 2, jpjm1 ! vertical momentum advection at w-point
  225. DO ji = fs_2, fs_jpim1 ! vector opt.
  226. zwuw(ji,jj,jk) = ( zww(ji+1,jj ,jk) + zww(ji,jj,jk) ) * ( zus(ji,jj,jk-1,jtn)-zus(ji,jj,jk,jtn) ) !* wumask(ji,jj,jk)
  227. zwvw(ji,jj,jk) = ( zww(ji ,jj+1,jk) + zww(ji,jj,jk) ) * ( zvs(ji,jj,jk-1,jtn)-zvs(ji,jj,jk,jtn) ) !* wvmask(ji,jj,jk)
  228. END DO
  229. END DO
  230. END DO
  231. DO jk = 1, jpkm1 ! Vertical momentum advection at u- and v-points
  232. DO jj = 2, jpjm1
  233. DO ji = fs_2, fs_jpim1 ! vector opt.
  234. ! ! vertical momentum advective trends
  235. zua = - ( zwuw(ji,jj,jk) + zwuw(ji,jj,jk+1) ) / ( e1u(ji,jj) * e2u(ji,jj) * fse3u(ji,jj,jk) )
  236. zva = - ( zwvw(ji,jj,jk) + zwvw(ji,jj,jk+1) ) / ( e1v(ji,jj) * e2v(ji,jj) * fse3v(ji,jj,jk) )
  237. zus(ji,jj,jk,jta) = zus(ji,jj,jk,jtb) + zua * zts
  238. zvs(ji,jj,jk,jta) = zvs(ji,jj,jk,jtb) + zva * zts
  239. END DO
  240. END DO
  241. END DO
  242. END DO ! End of sub timestepping loop
  243. zr_rdt = 1._wp / ( REAL( jnzts, wp ) * z2dtzts )
  244. DO jk = 1, jpkm1 ! Recover trends over the outer timestep
  245. DO jj = 2, jpjm1
  246. DO ji = fs_2, fs_jpim1 ! vector opt.
  247. ! ! vertical momentum advective trends
  248. ! ! add the trends to the general momentum trends
  249. ua(ji,jj,jk) = ua(ji,jj,jk) + ( zus(ji,jj,jk,jta) - ub(ji,jj,jk)) * zr_rdt
  250. va(ji,jj,jk) = va(ji,jj,jk) + ( zvs(ji,jj,jk,jta) - vb(ji,jj,jk)) * zr_rdt
  251. END DO
  252. END DO
  253. END DO
  254. IF( l_trddyn ) THEN ! save the vertical advection trends for diagnostic
  255. ztrdu(:,:,:) = ua(:,:,:) - ztrdu(:,:,:)
  256. ztrdv(:,:,:) = va(:,:,:) - ztrdv(:,:,:)
  257. CALL trd_dyn( ztrdu, ztrdv, jpdyn_zad, kt )
  258. CALL wrk_dealloc( jpi, jpj, jpk, ztrdu, ztrdv )
  259. ENDIF
  260. ! ! Control print
  261. IF(ln_ctl) CALL prt_ctl( tab3d_1=ua, clinfo1=' zad - Ua: ', mask1=umask, &
  262. & tab3d_2=va, clinfo2= ' Va: ', mask2=vmask, clinfo3='dyn' )
  263. !
  264. CALL wrk_dealloc( jpi,jpj,jpk, zwuw , zwvw, zww )
  265. CALL wrk_dealloc( jpi,jpj,jpk,3, zus, zvs )
  266. !
  267. IF( nn_timing == 1 ) CALL timing_stop('dyn_zad_zts')
  268. !
  269. END SUBROUTINE dyn_zad_zts
  270. !!======================================================================
  271. END MODULE dynzad