bdytra.F90 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. MODULE bdytra
  2. !!======================================================================
  3. !! *** MODULE bdytra ***
  4. !! Ocean tracers: Apply boundary conditions for tracers
  5. !!======================================================================
  6. !! History : 1.0 ! 2005-01 (J. Chanut, A. Sellar) Original code
  7. !! 3.0 ! 2008-04 (NEMO team) add in the reference version
  8. !! 3.4 ! 2011 (D. Storkey) rewrite in preparation for OBC-BDY merge
  9. !! 3.5 ! 2012 (S. Mocavero, I. Epicoco) Optimization of BDY communications
  10. !!----------------------------------------------------------------------
  11. #if defined key_bdy
  12. !!----------------------------------------------------------------------
  13. !! 'key_bdy' Unstructured Open Boundary Conditions
  14. !!----------------------------------------------------------------------
  15. !! bdy_tra : Apply open boundary conditions to T and S
  16. !! bdy_tra_frs : Apply Flow Relaxation Scheme
  17. !!----------------------------------------------------------------------
  18. USE timing ! Timing
  19. USE oce ! ocean dynamics and tracers variables
  20. USE dom_oce ! ocean space and time domain variables
  21. USE bdy_oce ! ocean open boundary conditions
  22. USE bdylib ! for orlanski library routines
  23. USE bdydta, ONLY: bf
  24. USE lbclnk ! ocean lateral boundary conditions (or mpp link)
  25. USE in_out_manager ! I/O manager
  26. IMPLICIT NONE
  27. PRIVATE
  28. PUBLIC bdy_tra ! routine called in tranxt.F90
  29. PUBLIC bdy_tra_dmp ! routine called in step.F90
  30. !!----------------------------------------------------------------------
  31. !! NEMO/OPA 3.3 , NEMO Consortium (2010)
  32. !! $Id: bdytra.F90 4292 2013-11-20 16:28:04Z cetlod $
  33. !! Software governed by the CeCILL licence (NEMOGCM/NEMO_CeCILL.txt)
  34. !!----------------------------------------------------------------------
  35. CONTAINS
  36. SUBROUTINE bdy_tra( kt )
  37. !!----------------------------------------------------------------------
  38. !! *** SUBROUTINE bdy_tra ***
  39. !!
  40. !! ** Purpose : - Apply open boundary conditions for temperature and salinity
  41. !!
  42. !!----------------------------------------------------------------------
  43. INTEGER, INTENT( in ) :: kt ! Main time step counter
  44. !!
  45. INTEGER :: ib_bdy ! Loop index
  46. DO ib_bdy=1, nb_bdy
  47. SELECT CASE( cn_tra(ib_bdy) )
  48. CASE('none')
  49. CYCLE
  50. CASE('frs')
  51. CALL bdy_tra_frs( idx_bdy(ib_bdy), dta_bdy(ib_bdy), kt )
  52. CASE('specified')
  53. CALL bdy_tra_spe( idx_bdy(ib_bdy), dta_bdy(ib_bdy), kt )
  54. CASE('neumann')
  55. CALL bdy_tra_nmn( idx_bdy(ib_bdy), dta_bdy(ib_bdy), kt )
  56. CASE('orlanski')
  57. CALL bdy_tra_orlanski( idx_bdy(ib_bdy), dta_bdy(ib_bdy), ll_npo=.false. )
  58. CASE('orlanski_npo')
  59. CALL bdy_tra_orlanski( idx_bdy(ib_bdy), dta_bdy(ib_bdy), ll_npo=.true. )
  60. CASE('runoff')
  61. CALL bdy_tra_rnf( idx_bdy(ib_bdy), dta_bdy(ib_bdy), kt )
  62. CASE DEFAULT
  63. CALL ctl_stop( 'bdy_tra : unrecognised option for open boundaries for T and S' )
  64. END SELECT
  65. ! Boundary points should be updated
  66. CALL lbc_bdy_lnk( tsa(:,:,:,jp_tem), 'T', 1., ib_bdy )
  67. CALL lbc_bdy_lnk( tsa(:,:,:,jp_sal), 'T', 1., ib_bdy )
  68. ENDDO
  69. !
  70. END SUBROUTINE bdy_tra
  71. SUBROUTINE bdy_tra_frs( idx, dta, kt )
  72. !!----------------------------------------------------------------------
  73. !! *** SUBROUTINE bdy_tra_frs ***
  74. !!
  75. !! ** Purpose : Apply the Flow Relaxation Scheme for tracers at open boundaries.
  76. !!
  77. !! Reference : Engedahl H., 1995, Tellus, 365-382.
  78. !!----------------------------------------------------------------------
  79. INTEGER, INTENT(in) :: kt
  80. TYPE(OBC_INDEX), INTENT(in) :: idx ! OBC indices
  81. TYPE(OBC_DATA), INTENT(in) :: dta ! OBC external data
  82. !!
  83. REAL(wp) :: zwgt ! boundary weight
  84. INTEGER :: ib, ik, igrd ! dummy loop indices
  85. INTEGER :: ii, ij ! 2D addresses
  86. !!----------------------------------------------------------------------
  87. !
  88. IF( nn_timing == 1 ) CALL timing_start('bdy_tra_frs')
  89. !
  90. igrd = 1 ! Everything is at T-points here
  91. DO ib = 1, idx%nblen(igrd)
  92. DO ik = 1, jpkm1
  93. ii = idx%nbi(ib,igrd)
  94. ij = idx%nbj(ib,igrd)
  95. zwgt = idx%nbw(ib,igrd)
  96. tsa(ii,ij,ik,jp_tem) = ( tsa(ii,ij,ik,jp_tem) + zwgt * ( dta%tem(ib,ik) - tsa(ii,ij,ik,jp_tem) ) ) * tmask(ii,ij,ik)
  97. tsa(ii,ij,ik,jp_sal) = ( tsa(ii,ij,ik,jp_sal) + zwgt * ( dta%sal(ib,ik) - tsa(ii,ij,ik,jp_sal) ) ) * tmask(ii,ij,ik)
  98. END DO
  99. END DO
  100. !
  101. IF( kt .eq. nit000 ) CLOSE( unit = 102 )
  102. !
  103. IF( nn_timing == 1 ) CALL timing_stop('bdy_tra_frs')
  104. !
  105. END SUBROUTINE bdy_tra_frs
  106. SUBROUTINE bdy_tra_spe( idx, dta, kt )
  107. !!----------------------------------------------------------------------
  108. !! *** SUBROUTINE bdy_tra_frs ***
  109. !!
  110. !! ** Purpose : Apply a specified value for tracers at open boundaries.
  111. !!
  112. !!----------------------------------------------------------------------
  113. INTEGER, INTENT(in) :: kt
  114. TYPE(OBC_INDEX), INTENT(in) :: idx ! OBC indices
  115. TYPE(OBC_DATA), INTENT(in) :: dta ! OBC external data
  116. !!
  117. REAL(wp) :: zwgt ! boundary weight
  118. INTEGER :: ib, ik, igrd ! dummy loop indices
  119. INTEGER :: ii, ij ! 2D addresses
  120. !!----------------------------------------------------------------------
  121. !
  122. IF( nn_timing == 1 ) CALL timing_start('bdy_tra_spe')
  123. !
  124. igrd = 1 ! Everything is at T-points here
  125. DO ib = 1, idx%nblenrim(igrd)
  126. ii = idx%nbi(ib,igrd)
  127. ij = idx%nbj(ib,igrd)
  128. DO ik = 1, jpkm1
  129. tsa(ii,ij,ik,jp_tem) = dta%tem(ib,ik) * tmask(ii,ij,ik)
  130. tsa(ii,ij,ik,jp_sal) = dta%sal(ib,ik) * tmask(ii,ij,ik)
  131. END DO
  132. END DO
  133. !
  134. IF( kt .eq. nit000 ) CLOSE( unit = 102 )
  135. !
  136. IF( nn_timing == 1 ) CALL timing_stop('bdy_tra_spe')
  137. !
  138. END SUBROUTINE bdy_tra_spe
  139. SUBROUTINE bdy_tra_nmn( idx, dta, kt )
  140. !!----------------------------------------------------------------------
  141. !! *** SUBROUTINE bdy_tra_nmn ***
  142. !!
  143. !! ** Purpose : Duplicate the value for tracers at open boundaries.
  144. !!
  145. !!----------------------------------------------------------------------
  146. INTEGER, INTENT(in) :: kt
  147. TYPE(OBC_INDEX), INTENT(in) :: idx ! OBC indices
  148. TYPE(OBC_DATA), INTENT(in) :: dta ! OBC external data
  149. !!
  150. REAL(wp) :: zwgt ! boundary weight
  151. INTEGER :: ib, ik, igrd ! dummy loop indices
  152. INTEGER :: ii, ij,zcoef, zcoef1,zcoef2, ip, jp ! 2D addresses
  153. !!----------------------------------------------------------------------
  154. !
  155. IF( nn_timing == 1 ) CALL timing_start('bdy_tra_nmn')
  156. !
  157. igrd = 1 ! Everything is at T-points here
  158. DO ib = 1, idx%nblenrim(igrd)
  159. ii = idx%nbi(ib,igrd)
  160. ij = idx%nbj(ib,igrd)
  161. DO ik = 1, jpkm1
  162. ! search the sense of the gradient
  163. zcoef1 = bdytmask(ii-1,ij ) + bdytmask(ii+1,ij )
  164. zcoef2 = bdytmask(ii ,ij-1) + bdytmask(ii ,ij+1)
  165. IF ( zcoef1+zcoef2 == 0) THEN
  166. ! corner
  167. zcoef = tmask(ii-1,ij,ik) + tmask(ii+1,ij,ik) + tmask(ii,ij-1,ik) + tmask(ii,ij+1,ik)
  168. tsa(ii,ij,ik,jp_tem) = tsa(ii-1,ij ,ik,jp_tem) * tmask(ii-1,ij ,ik) + &
  169. & tsa(ii+1,ij ,ik,jp_tem) * tmask(ii+1,ij ,ik) + &
  170. & tsa(ii ,ij-1,ik,jp_tem) * tmask(ii ,ij-1,ik) + &
  171. & tsa(ii ,ij+1,ik,jp_tem) * tmask(ii ,ij+1,ik)
  172. tsa(ii,ij,ik,jp_tem) = ( tsa(ii,ij,ik,jp_tem) / MAX( 1, zcoef) ) * tmask(ii,ij,ik)
  173. tsa(ii,ij,ik,jp_sal) = tsa(ii-1,ij ,ik,jp_sal) * tmask(ii-1,ij ,ik) + &
  174. & tsa(ii+1,ij ,ik,jp_sal) * tmask(ii+1,ij ,ik) + &
  175. & tsa(ii ,ij-1,ik,jp_sal) * tmask(ii ,ij-1,ik) + &
  176. & tsa(ii ,ij+1,ik,jp_sal) * tmask(ii ,ij+1,ik)
  177. tsa(ii,ij,ik,jp_sal) = ( tsa(ii,ij,ik,jp_sal) / MAX( 1, zcoef) ) * tmask(ii,ij,ik)
  178. ELSE
  179. ip = bdytmask(ii+1,ij ) - bdytmask(ii-1,ij )
  180. jp = bdytmask(ii ,ij+1) - bdytmask(ii ,ij-1)
  181. tsa(ii,ij,ik,jp_tem) = tsa(ii+ip,ij+jp,ik,jp_tem) * tmask(ii+ip,ij+jp,ik)
  182. tsa(ii,ij,ik,jp_sal) = tsa(ii+ip,ij+jp,ik,jp_sal) * tmask(ii+ip,ij+jp,ik)
  183. ENDIF
  184. END DO
  185. END DO
  186. !
  187. IF( kt .eq. nit000 ) CLOSE( unit = 102 )
  188. !
  189. IF( nn_timing == 1 ) CALL timing_stop('bdy_tra_nmn')
  190. !
  191. END SUBROUTINE bdy_tra_nmn
  192. SUBROUTINE bdy_tra_orlanski( idx, dta, ll_npo )
  193. !!----------------------------------------------------------------------
  194. !! *** SUBROUTINE bdy_tra_orlanski ***
  195. !!
  196. !! - Apply Orlanski radiation to temperature and salinity.
  197. !! - Wrapper routine for bdy_orlanski_3d
  198. !!
  199. !!
  200. !! References: Marchesiello, McWilliams and Shchepetkin, Ocean Modelling vol. 3 (2001)
  201. !!----------------------------------------------------------------------
  202. TYPE(OBC_INDEX), INTENT(in) :: idx ! OBC indices
  203. TYPE(OBC_DATA), INTENT(in) :: dta ! OBC external data
  204. LOGICAL, INTENT(in) :: ll_npo ! switch for NPO version
  205. INTEGER :: igrd ! grid index
  206. !!----------------------------------------------------------------------
  207. IF( nn_timing == 1 ) CALL timing_start('bdy_tra_orlanski')
  208. !
  209. igrd = 1 ! Orlanski bc on temperature;
  210. !
  211. CALL bdy_orlanski_3d( idx, igrd, tsb(:,:,:,jp_tem), tsa(:,:,:,jp_tem), dta%tem, ll_npo )
  212. igrd = 1 ! Orlanski bc on salinity;
  213. !
  214. CALL bdy_orlanski_3d( idx, igrd, tsb(:,:,:,jp_sal), tsa(:,:,:,jp_sal), dta%sal, ll_npo )
  215. !
  216. IF( nn_timing == 1 ) CALL timing_stop('bdy_tra_orlanski')
  217. !
  218. END SUBROUTINE bdy_tra_orlanski
  219. SUBROUTINE bdy_tra_rnf( idx, dta, kt )
  220. !!----------------------------------------------------------------------
  221. !! *** SUBROUTINE bdy_tra_rnf ***
  222. !!
  223. !! ** Purpose : Apply the runoff values for tracers at open boundaries:
  224. !! - specified to 0.1 PSU for the salinity
  225. !! - duplicate the value for the temperature
  226. !!
  227. !!----------------------------------------------------------------------
  228. INTEGER, INTENT(in) :: kt
  229. TYPE(OBC_INDEX), INTENT(in) :: idx ! OBC indices
  230. TYPE(OBC_DATA), INTENT(in) :: dta ! OBC external data
  231. !!
  232. REAL(wp) :: zwgt ! boundary weight
  233. INTEGER :: ib, ik, igrd ! dummy loop indices
  234. INTEGER :: ii, ij, ip, jp ! 2D addresses
  235. !!----------------------------------------------------------------------
  236. !
  237. IF( nn_timing == 1 ) CALL timing_start('bdy_tra_rnf')
  238. !
  239. igrd = 1 ! Everything is at T-points here
  240. DO ib = 1, idx%nblenrim(igrd)
  241. ii = idx%nbi(ib,igrd)
  242. ij = idx%nbj(ib,igrd)
  243. DO ik = 1, jpkm1
  244. ip = bdytmask(ii+1,ij ) - bdytmask(ii-1,ij )
  245. jp = bdytmask(ii ,ij+1) - bdytmask(ii ,ij-1)
  246. tsa(ii,ij,ik,jp_tem) = tsa(ii+ip,ij+jp,ik,jp_tem) * tmask(ii,ij,ik)
  247. tsa(ii,ij,ik,jp_sal) = 0.1 * tmask(ii,ij,ik)
  248. END DO
  249. END DO
  250. !
  251. IF( kt .eq. nit000 ) CLOSE( unit = 102 )
  252. !
  253. IF( nn_timing == 1 ) CALL timing_stop('bdy_tra_rnf')
  254. !
  255. END SUBROUTINE bdy_tra_rnf
  256. SUBROUTINE bdy_tra_dmp( kt )
  257. !!----------------------------------------------------------------------
  258. !! *** SUBROUTINE bdy_tra_dmp ***
  259. !!
  260. !! ** Purpose : Apply damping for tracers at open boundaries.
  261. !!
  262. !!----------------------------------------------------------------------
  263. INTEGER, INTENT(in) :: kt
  264. !!
  265. REAL(wp) :: zwgt ! boundary weight
  266. REAL(wp) :: zta, zsa, ztime
  267. INTEGER :: ib, ik, igrd ! dummy loop indices
  268. INTEGER :: ii, ij ! 2D addresses
  269. INTEGER :: ib_bdy ! Loop index
  270. !!----------------------------------------------------------------------
  271. !
  272. IF( nn_timing == 1 ) CALL timing_start('bdy_tra_dmp')
  273. !
  274. DO ib_bdy=1, nb_bdy
  275. IF ( ln_tra_dmp(ib_bdy) ) THEN
  276. igrd = 1 ! Everything is at T-points here
  277. DO ib = 1, idx_bdy(ib_bdy)%nblen(igrd)
  278. ii = idx_bdy(ib_bdy)%nbi(ib,igrd)
  279. ij = idx_bdy(ib_bdy)%nbj(ib,igrd)
  280. zwgt = idx_bdy(ib_bdy)%nbd(ib,igrd)
  281. DO ik = 1, jpkm1
  282. zta = zwgt * ( dta_bdy(ib_bdy)%tem(ib,ik) - tsb(ii,ij,ik,jp_tem) ) * tmask(ii,ij,ik)
  283. zsa = zwgt * ( dta_bdy(ib_bdy)%sal(ib,ik) - tsb(ii,ij,ik,jp_sal) ) * tmask(ii,ij,ik)
  284. tsa(ii,ij,ik,jp_tem) = tsa(ii,ij,ik,jp_tem) + zta
  285. tsa(ii,ij,ik,jp_sal) = tsa(ii,ij,ik,jp_sal) + zsa
  286. END DO
  287. END DO
  288. ENDIF
  289. ENDDO
  290. !
  291. IF( nn_timing == 1 ) CALL timing_stop('bdy_tra_dmp')
  292. !
  293. END SUBROUTINE bdy_tra_dmp
  294. #else
  295. !!----------------------------------------------------------------------
  296. !! Dummy module NO Unstruct Open Boundary Conditions
  297. !!----------------------------------------------------------------------
  298. CONTAINS
  299. SUBROUTINE bdy_tra(kt) ! Empty routine
  300. WRITE(*,*) 'bdy_tra: You should not have seen this print! error?', kt
  301. END SUBROUTINE bdy_tra
  302. SUBROUTINE bdy_tra_dmp(kt) ! Empty routine
  303. WRITE(*,*) 'bdy_tra_dmp: You should not have seen this print! error?', kt
  304. END SUBROUTINE bdy_tra_dmp
  305. #endif
  306. !!======================================================================
  307. END MODULE bdytra