tranpc.F90 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. MODULE tranpc
  2. !!==============================================================================
  3. !! *** MODULE tranpc ***
  4. !! Ocean active tracers: non penetrative convective adjustment scheme
  5. !!==============================================================================
  6. !! History : 1.0 ! 1990-09 (G. Madec) Original code
  7. !! ! 1996-01 (G. Madec) statement function for e3
  8. !! NEMO 1.0 ! 2002-06 (G. Madec) free form F90
  9. !! 3.0 ! 2008-06 (G. Madec) applied on ta, sa and called before tranxt in step.F90
  10. !! 3.3 ! 2010-05 (C. Ethe, G. Madec) merge TRC-TRA
  11. !! 3.6 ! 2015-05 (L. Brodeau) new algorithm based on local Brunt-Vaisala freq.
  12. !!----------------------------------------------------------------------
  13. !!----------------------------------------------------------------------
  14. !! tra_npc : apply the non penetrative convection scheme
  15. !!----------------------------------------------------------------------
  16. USE oce ! ocean dynamics and active tracers
  17. USE dom_oce ! ocean space and time domain
  18. USE phycst ! physical constants
  19. USE zdf_oce ! ocean vertical physics
  20. USE trd_oce ! ocean active tracer trends
  21. USE trdtra ! ocean active tracer trends
  22. USE eosbn2 ! equation of state (eos routine)
  23. !
  24. USE lbclnk ! lateral boundary conditions (or mpp link)
  25. USE in_out_manager ! I/O manager
  26. USE lib_mpp ! MPP library
  27. USE wrk_nemo ! Memory Allocation
  28. USE timing ! Timing
  29. IMPLICIT NONE
  30. PRIVATE
  31. PUBLIC tra_npc ! routine called by step.F90
  32. !! * Substitutions
  33. # include "domzgr_substitute.h90"
  34. # include "vectopt_loop_substitute.h90"
  35. !!----------------------------------------------------------------------
  36. !! NEMO/OPA 3.6 , NEMO Consortium (2014)
  37. !! $Id: tranpc.F90 4990 2014-12-15 16:42:49Z timgraham $
  38. !! Software governed by the CeCILL licence (NEMOGCM/NEMO_CeCILL.txt)
  39. !!----------------------------------------------------------------------
  40. CONTAINS
  41. SUBROUTINE tra_npc( kt )
  42. !!----------------------------------------------------------------------
  43. !! *** ROUTINE tranpc ***
  44. !!
  45. !! ** Purpose : Non-penetrative convective adjustment scheme. solve
  46. !! the static instability of the water column on after fields
  47. !! while conserving heat and salt contents.
  48. !!
  49. !! ** Method : updated algorithm able to deal with non-linear equation of state
  50. !! (i.e. static stability computed locally)
  51. !!
  52. !! ** Action : - (ta,sa) after the application od the npc scheme
  53. !! - send the associated trends for on-line diagnostics (l_trdtra=T)
  54. !!
  55. !! References : Madec, et al., 1991, JPO, 21, 9, 1349-1371.
  56. !!----------------------------------------------------------------------
  57. INTEGER, INTENT(in) :: kt ! ocean time-step index
  58. !
  59. INTEGER :: ji, jj, jk ! dummy loop indices
  60. INTEGER :: inpcc ! number of statically instable water column
  61. INTEGER :: jiter, ikbot, ikp, ikup, ikdown, ilayer, ik_low ! local integers
  62. LOGICAL :: l_bottom_reached, l_column_treated
  63. REAL(wp) :: zta, zalfa, zsum_temp, zsum_alfa, zaw, zdz, zsum_z
  64. REAL(wp) :: zsa, zbeta, zsum_sali, zsum_beta, zbw, zrw, z1_r2dt
  65. REAL(wp), PARAMETER :: zn2_zero = 1.e-14_wp ! acceptance criteria for neutrality (N2==0)
  66. REAL(wp), POINTER, DIMENSION(:) :: zvn2 ! vertical profile of N2 at 1 given point...
  67. REAL(wp), POINTER, DIMENSION(:,:) :: zvts ! vertical profile of T and S at 1 given point...
  68. REAL(wp), POINTER, DIMENSION(:,:) :: zvab ! vertical profile of alpha and beta
  69. REAL(wp), POINTER, DIMENSION(:,:,:) :: zn2 ! N^2
  70. REAL(wp), POINTER, DIMENSION(:,:,:,:) :: zab ! alpha and beta
  71. REAL(wp), POINTER, DIMENSION(:,:,:) :: ztrdt, ztrds ! 3D workspace
  72. !
  73. LOGICAL, PARAMETER :: l_LB_debug = .FALSE. ! set to true if you want to follow what is
  74. INTEGER :: ilc1, jlc1, klc1, nncpu ! actually happening in a water column at point "ilc1, jlc1"
  75. LOGICAL :: lp_monitor_point = .FALSE. ! in CPU domain "nncpu"
  76. !!----------------------------------------------------------------------
  77. !
  78. IF( nn_timing == 1 ) CALL timing_start('tra_npc')
  79. !
  80. IF( MOD( kt, nn_npc ) == 0 ) THEN
  81. !
  82. CALL wrk_alloc( jpi, jpj, jpk, zn2 ) ! N2
  83. CALL wrk_alloc( jpi, jpj, jpk, 2, zab ) ! Alpha and Beta
  84. CALL wrk_alloc( jpk, 2, zvts, zvab ) ! 1D column vector at point ji,jj
  85. CALL wrk_alloc( jpk, zvn2 ) ! 1D column vector at point ji,jj
  86. IF( l_trdtra ) THEN !* Save initial after fields
  87. CALL wrk_alloc( jpi, jpj, jpk, ztrdt, ztrds )
  88. ztrdt(:,:,:) = tsa(:,:,:,jp_tem)
  89. ztrds(:,:,:) = tsa(:,:,:,jp_sal)
  90. ENDIF
  91. IF( l_LB_debug ) THEN
  92. ! Location of 1 known convection site to follow what's happening in the water column
  93. ilc1 = 45 ; jlc1 = 3 ; ! ORCA2 4x4, Antarctic coast, more than 2 unstable portions in the water column...
  94. nncpu = 1 ; ! the CPU domain contains the convection spot
  95. klc1 = mbkt(ilc1,jlc1) ! bottom of the ocean for debug point...
  96. ENDIF
  97. CALL eos_rab( tsa, zab ) ! after alpha and beta (given on T-points)
  98. CALL bn2 ( tsa, zab, zn2 ) ! after Brunt-Vaisala (given on W-points)
  99. inpcc = 0
  100. DO jj = 2, jpjm1 ! interior column only
  101. DO ji = fs_2, fs_jpim1
  102. !
  103. IF( tmask(ji,jj,2) == 1 ) THEN ! At least 2 ocean points
  104. ! ! consider one ocean column
  105. zvts(:,jp_tem) = tsa(ji,jj,:,jp_tem) ! temperature
  106. zvts(:,jp_sal) = tsa(ji,jj,:,jp_sal) ! salinity
  107. zvab(:,jp_tem) = zab(ji,jj,:,jp_tem) ! Alpha
  108. zvab(:,jp_sal) = zab(ji,jj,:,jp_sal) ! Beta
  109. zvn2(:) = zn2(ji,jj,:) ! N^2
  110. IF( l_LB_debug ) THEN !LB debug:
  111. lp_monitor_point = .FALSE.
  112. IF( ( ji == ilc1 ).AND.( jj == jlc1 ) ) lp_monitor_point = .TRUE.
  113. ! writing only if on CPU domain where conv region is:
  114. lp_monitor_point = (narea == nncpu).AND.lp_monitor_point
  115. ENDIF !LB debug end
  116. ikbot = mbkt(ji,jj) ! ikbot: ocean bottom T-level
  117. ikp = 1 ! because N2 is irrelevant at the surface level (will start at ikp=2)
  118. ilayer = 0
  119. jiter = 0
  120. l_column_treated = .FALSE.
  121. DO WHILE ( .NOT. l_column_treated )
  122. !
  123. jiter = jiter + 1
  124. IF( jiter >= 400 ) EXIT
  125. l_bottom_reached = .FALSE.
  126. DO WHILE ( .NOT. l_bottom_reached )
  127. ikp = ikp + 1
  128. !! Testing level ikp for instability
  129. !! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  130. IF( zvn2(ikp) < -zn2_zero ) THEN ! Instability found!
  131. ilayer = ilayer + 1 ! yet another instable portion of the water column found....
  132. IF( lp_monitor_point ) THEN
  133. WRITE(numout,*)
  134. IF( ilayer == 1 .AND. jiter == 1 ) THEN ! first time a column is spoted with an instability
  135. WRITE(numout,*)
  136. WRITE(numout,*) 'Time step = ',kt,' !!!'
  137. ENDIF
  138. WRITE(numout,*) ' * Iteration #',jiter,': found instable portion #',ilayer, &
  139. & ' in column! Starting at ikp =', ikp
  140. WRITE(numout,*) ' *** N2 for point (i,j) = ',ji,' , ',jj
  141. DO jk = 1, klc1
  142. WRITE(numout,*) jk, zvn2(jk)
  143. END DO
  144. WRITE(numout,*)
  145. ENDIF
  146. IF( jiter == 1 ) inpcc = inpcc + 1
  147. IF( lp_monitor_point ) WRITE(numout, *) 'Negative N2 at ikp =',ikp,' for layer #', ilayer
  148. !! ikup is the uppermost point where mixing will start:
  149. ikup = ikp - 1 ! ikup is always "at most at ikp-1", less if neutral levels overlying
  150. !! If the points above ikp-1 have N2 == 0 they must also be mixed:
  151. IF( ikp > 2 ) THEN
  152. DO jk = ikp-1, 2, -1
  153. IF( ABS(zvn2(jk)) < zn2_zero ) THEN
  154. ikup = ikup - 1 ! 1 more upper level has N2=0 and must be added for the mixing
  155. ELSE
  156. EXIT
  157. ENDIF
  158. END DO
  159. ENDIF
  160. IF( ikup < 1 ) CALL ctl_stop( 'tra_npc : PROBLEM #1')
  161. zsum_temp = 0._wp
  162. zsum_sali = 0._wp
  163. zsum_alfa = 0._wp
  164. zsum_beta = 0._wp
  165. zsum_z = 0._wp
  166. DO jk = ikup, ikbot ! Inside the instable (and overlying neutral) portion of the column
  167. !
  168. zdz = fse3t(ji,jj,jk)
  169. zsum_temp = zsum_temp + zvts(jk,jp_tem)*zdz
  170. zsum_sali = zsum_sali + zvts(jk,jp_sal)*zdz
  171. zsum_alfa = zsum_alfa + zvab(jk,jp_tem)*zdz
  172. zsum_beta = zsum_beta + zvab(jk,jp_sal)*zdz
  173. zsum_z = zsum_z + zdz
  174. !
  175. IF( jk == ikbot ) EXIT ! avoid array-index overshoot in case ikbot = jpk, cause we're calling jk+1 next line
  176. !! EXIT when we have reached the last layer that is instable (N2<0) or neutral (N2=0):
  177. IF( zvn2(jk+1) > zn2_zero ) EXIT
  178. END DO
  179. ikdown = jk ! for the current unstable layer, ikdown is the deepest point with a negative or neutral N2
  180. IF( ikup == ikdown ) CALL ctl_stop( 'tra_npc : PROBLEM #2')
  181. ! Mixing Temperature, salinity, alpha and beta from ikup to ikdown included:
  182. zta = zsum_temp/zsum_z
  183. zsa = zsum_sali/zsum_z
  184. zalfa = zsum_alfa/zsum_z
  185. zbeta = zsum_beta/zsum_z
  186. IF( lp_monitor_point ) THEN
  187. WRITE(numout,*) 'MIXED T, S, alfa and beta between ikup =',ikup, &
  188. & ' and ikdown =',ikdown,', in layer #',ilayer
  189. WRITE(numout,*) ' => Mean temp. in that portion =', zta
  190. WRITE(numout,*) ' => Mean sali. in that portion =', zsa
  191. WRITE(numout,*) ' => Mean Alfa in that portion =', zalfa
  192. WRITE(numout,*) ' => Mean Beta in that portion =', zbeta
  193. ENDIF
  194. !! Homogenaizing the temperature, salinity, alpha and beta in this portion of the column
  195. DO jk = ikup, ikdown
  196. zvts(jk,jp_tem) = zta
  197. zvts(jk,jp_sal) = zsa
  198. zvab(jk,jp_tem) = zalfa
  199. zvab(jk,jp_sal) = zbeta
  200. END DO
  201. !! Updating N2 in the relvant portion of the water column
  202. !! Temperature, Salinity, Alpha and Beta have been homogenized in the unstable portion
  203. !! => Need to re-compute N2! will use Alpha and Beta!
  204. ikup = MAX(2,ikup) ! ikup can never be 1 !
  205. ik_low = MIN(ikdown+1,ikbot) ! we must go 1 point deeper than ikdown!
  206. DO jk = ikup, ik_low ! we must go 1 point deeper than ikdown!
  207. !! Interpolating alfa and beta at W point:
  208. zrw = (fsdepw(ji,jj,jk ) - fsdept(ji,jj,jk)) &
  209. & / (fsdept(ji,jj,jk-1) - fsdept(ji,jj,jk))
  210. zaw = zvab(jk,jp_tem) * (1._wp - zrw) + zvab(jk-1,jp_tem) * zrw
  211. zbw = zvab(jk,jp_sal) * (1._wp - zrw) + zvab(jk-1,jp_sal) * zrw
  212. !! N2 at W point, doing exactly as in eosbn2.F90:
  213. zvn2(jk) = grav*( zaw * ( zvts(jk-1,jp_tem) - zvts(jk,jp_tem) ) &
  214. & - zbw * ( zvts(jk-1,jp_sal) - zvts(jk,jp_sal) ) ) &
  215. & / fse3w(ji,jj,jk) * tmask(ji,jj,jk)
  216. !! OR, faster => just considering the vertical gradient of density
  217. !! as only the signa maters...
  218. !zvn2(jk) = ( zaw * ( zvts(jk-1,jp_tem) - zvts(jk,jp_tem) ) &
  219. ! & - zbw * ( zvts(jk-1,jp_sal) - zvts(jk,jp_sal) ) )
  220. END DO
  221. ikp = MIN(ikdown+1,ikbot)
  222. ENDIF !IF( zvn2(ikp) < 0. )
  223. IF( ikp == ikbot ) l_bottom_reached = .TRUE.
  224. !
  225. END DO ! DO WHILE ( .NOT. l_bottom_reached )
  226. IF( ikp /= ikbot ) CALL ctl_stop( 'tra_npc : PROBLEM #3')
  227. ! ******* At this stage ikp == ikbot ! *******
  228. IF( ilayer > 0 ) THEN !! least an unstable layer has been found
  229. !
  230. IF( lp_monitor_point ) THEN
  231. WRITE(numout,*)
  232. WRITE(numout,*) 'After ',jiter,' iteration(s), we neutralized ',ilayer,' instable layer(s)'
  233. WRITE(numout,*) ' ==> N2 at i,j=',ji,',',jj,' now looks like this:'
  234. DO jk = 1, klc1
  235. WRITE(numout,*) jk, zvn2(jk)
  236. END DO
  237. WRITE(numout,*)
  238. ENDIF
  239. !
  240. ikp = 1 ! starting again at the surface for the next iteration
  241. ilayer = 0
  242. ENDIF
  243. !
  244. IF( ikp >= ikbot ) l_column_treated = .TRUE.
  245. !
  246. END DO ! DO WHILE ( .NOT. l_column_treated )
  247. !! Updating tsa:
  248. tsa(ji,jj,:,jp_tem) = zvts(:,jp_tem)
  249. tsa(ji,jj,:,jp_sal) = zvts(:,jp_sal)
  250. !! LB: Potentially some other global variable beside theta and S can be treated here
  251. !! like BGC tracers.
  252. IF( lp_monitor_point ) WRITE(numout,*)
  253. ENDIF ! IF( tmask(ji,jj,3) == 1 ) THEN
  254. END DO ! ji
  255. END DO ! jj
  256. !
  257. IF( l_trdtra ) THEN ! send the Non penetrative mixing trends for diagnostic
  258. z1_r2dt = 1._wp / (2._wp * rdt)
  259. ztrdt(:,:,:) = ( tsa(:,:,:,jp_tem) - ztrdt(:,:,:) ) * z1_r2dt
  260. ztrds(:,:,:) = ( tsa(:,:,:,jp_sal) - ztrds(:,:,:) ) * z1_r2dt
  261. CALL trd_tra( kt, 'TRA', jp_tem, jptra_npc, ztrdt )
  262. CALL trd_tra( kt, 'TRA', jp_sal, jptra_npc, ztrds )
  263. CALL wrk_dealloc( jpi, jpj, jpk, ztrdt, ztrds )
  264. ENDIF
  265. !
  266. CALL lbc_lnk( tsa(:,:,:,jp_tem), 'T', 1. ) ; CALL lbc_lnk( tsa(:,:,:,jp_sal), 'T', 1. )
  267. !
  268. IF( lwp .AND. l_LB_debug ) THEN
  269. WRITE(numout,*) 'Exiting tra_npc , kt = ',kt,', => numb. of statically instable water-columns: ', inpcc
  270. WRITE(numout,*)
  271. ENDIF
  272. !
  273. CALL wrk_dealloc(jpi, jpj, jpk, zn2 )
  274. CALL wrk_dealloc(jpi, jpj, jpk, 2, zab )
  275. CALL wrk_dealloc(jpk, zvn2 )
  276. CALL wrk_dealloc(jpk, 2, zvts, zvab )
  277. !
  278. ENDIF ! IF( MOD( kt, nn_npc ) == 0 ) THEN
  279. !
  280. IF( nn_timing == 1 ) CALL timing_stop('tra_npc')
  281. !
  282. END SUBROUTINE tra_npc
  283. !!======================================================================
  284. END MODULE tranpc