bdydyn2d.F90 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. MODULE bdydyn2d
  2. !!======================================================================
  3. !! *** MODULE bdydyn ***
  4. !! Unstructured Open Boundary Cond. : Apply boundary conditions to barotropic solution
  5. !!======================================================================
  6. !! History : 3.4 ! 2011 (D. Storkey) new module as part of BDY rewrite
  7. !! 3.5 ! 2012 (S. Mocavero, I. Epicoco) Optimization of BDY communications
  8. !! 3.5 ! 2013-07 (J. Chanut) Compliant with time splitting changes
  9. !!----------------------------------------------------------------------
  10. #if defined key_bdy
  11. !!----------------------------------------------------------------------
  12. !! 'key_bdy' : Unstructured Open Boundary Condition
  13. !!----------------------------------------------------------------------
  14. !! bdy_dyn2d : Apply open boundary conditions to barotropic variables.
  15. !! bdy_dyn2d_frs : Apply Flow Relaxation Scheme
  16. !! bdy_dyn2d_fla : Apply Flather condition
  17. !! bdy_dyn2d_orlanski : Orlanski Radiation
  18. !! bdy_ssh : Duplicate sea level across open boundaries
  19. !!----------------------------------------------------------------------
  20. USE timing ! Timing
  21. USE oce ! ocean dynamics and tracers
  22. USE dom_oce ! ocean space and time domain
  23. USE bdy_oce ! ocean open boundary conditions
  24. USE bdylib ! BDY library routines
  25. USE dynspg_oce ! for barotropic variables
  26. USE phycst ! physical constants
  27. USE lbclnk ! ocean lateral boundary conditions (or mpp link)
  28. USE in_out_manager !
  29. IMPLICIT NONE
  30. PRIVATE
  31. PUBLIC bdy_dyn2d ! routine called in dynspg_ts and bdy_dyn
  32. PUBLIC bdy_ssh ! routine called in dynspg_ts or sshwzv
  33. !!----------------------------------------------------------------------
  34. !! NEMO/OPA 3.3 , NEMO Consortium (2010)
  35. !! $Id: bdydyn2d.F90 2678 2015-11-26 09:59:07Z ufla $
  36. !! Software governed by the CeCILL licence (NEMOGCM/NEMO_CeCILL.txt)
  37. !!----------------------------------------------------------------------
  38. CONTAINS
  39. SUBROUTINE bdy_dyn2d( kt, pua2d, pva2d, pub2d, pvb2d, phur, phvr, pssh )
  40. !!----------------------------------------------------------------------
  41. !! *** SUBROUTINE bdy_dyn2d ***
  42. !!
  43. !! ** Purpose : - Apply open boundary conditions for barotropic variables
  44. !!
  45. !!----------------------------------------------------------------------
  46. INTEGER, INTENT(in) :: kt ! Main time step counter
  47. REAL(wp), DIMENSION(:,:), INTENT(inout) :: pua2d, pva2d
  48. REAL(wp), DIMENSION(:,:), INTENT(in ) :: pub2d, pvb2d
  49. REAL(wp), DIMENSION(:,:), INTENT(in ) :: phur, phvr
  50. REAL(wp), DIMENSION(:,:), INTENT(in ) :: pssh
  51. !!
  52. INTEGER :: ib_bdy ! Loop counter
  53. DO ib_bdy=1, nb_bdy
  54. SELECT CASE( cn_dyn2d(ib_bdy) )
  55. CASE('none')
  56. CYCLE
  57. CASE('frs')
  58. CALL bdy_dyn2d_frs( idx_bdy(ib_bdy), dta_bdy(ib_bdy), ib_bdy, pua2d, pva2d )
  59. CASE('flather')
  60. CALL bdy_dyn2d_fla( idx_bdy(ib_bdy), dta_bdy(ib_bdy), ib_bdy, pua2d, pva2d, pssh, phur, phvr )
  61. CASE('orlanski')
  62. CALL bdy_dyn2d_orlanski( idx_bdy(ib_bdy), dta_bdy(ib_bdy), ib_bdy, &
  63. & pua2d, pva2d, pub2d, pvb2d, ll_npo=.false.)
  64. CASE('orlanski_npo')
  65. CALL bdy_dyn2d_orlanski( idx_bdy(ib_bdy), dta_bdy(ib_bdy), ib_bdy, &
  66. & pua2d, pva2d, pub2d, pvb2d, ll_npo=.true. )
  67. CASE DEFAULT
  68. CALL ctl_stop( 'bdy_dyn2d : unrecognised option for open boundaries for barotropic variables' )
  69. END SELECT
  70. ENDDO
  71. END SUBROUTINE bdy_dyn2d
  72. SUBROUTINE bdy_dyn2d_frs( idx, dta, ib_bdy, pua2d, pva2d )
  73. !!----------------------------------------------------------------------
  74. !! *** SUBROUTINE bdy_dyn2d_frs ***
  75. !!
  76. !! ** Purpose : - Apply the Flow Relaxation Scheme for barotropic velocities
  77. !! at open boundaries.
  78. !!
  79. !! References :- Engedahl H., 1995: Use of the flow relaxation scheme in
  80. !! a three-dimensional baroclinic ocean model with realistic
  81. !! topography. Tellus, 365-382.
  82. !!----------------------------------------------------------------------
  83. TYPE(OBC_INDEX), INTENT(in) :: idx ! OBC indices
  84. TYPE(OBC_DATA), INTENT(in) :: dta ! OBC external data
  85. INTEGER, INTENT(in) :: ib_bdy ! BDY set index
  86. REAL(wp), DIMENSION(:,:), INTENT(inout) :: pua2d, pva2d
  87. !!
  88. INTEGER :: jb, jk ! dummy loop indices
  89. INTEGER :: ii, ij, igrd ! local integers
  90. REAL(wp) :: zwgt ! boundary weight
  91. !!----------------------------------------------------------------------
  92. !
  93. IF( nn_timing == 1 ) CALL timing_start('bdy_dyn2d_frs')
  94. !
  95. igrd = 2 ! Relaxation of zonal velocity
  96. DO jb = 1, idx%nblen(igrd)
  97. ii = idx%nbi(jb,igrd)
  98. ij = idx%nbj(jb,igrd)
  99. zwgt = idx%nbw(jb,igrd)
  100. pua2d(ii,ij) = ( pua2d(ii,ij) + zwgt * ( dta%u2d(jb) - pua2d(ii,ij) ) ) * umask(ii,ij,1)
  101. END DO
  102. !
  103. igrd = 3 ! Relaxation of meridional velocity
  104. DO jb = 1, idx%nblen(igrd)
  105. ii = idx%nbi(jb,igrd)
  106. ij = idx%nbj(jb,igrd)
  107. zwgt = idx%nbw(jb,igrd)
  108. pva2d(ii,ij) = ( pva2d(ii,ij) + zwgt * ( dta%v2d(jb) - pva2d(ii,ij) ) ) * vmask(ii,ij,1)
  109. END DO
  110. CALL lbc_bdy_lnk( pua2d, 'U', -1., ib_bdy )
  111. CALL lbc_bdy_lnk( pva2d, 'V', -1., ib_bdy) ! Boundary points should be updated
  112. !
  113. IF( nn_timing == 1 ) CALL timing_stop('bdy_dyn2d_frs')
  114. !
  115. END SUBROUTINE bdy_dyn2d_frs
  116. SUBROUTINE bdy_dyn2d_fla( idx, dta, ib_bdy, pua2d, pva2d, pssh, phur, phvr )
  117. !!----------------------------------------------------------------------
  118. !! *** SUBROUTINE bdy_dyn2d_fla ***
  119. !!
  120. !! - Apply Flather boundary conditions on normal barotropic velocities
  121. !!
  122. !! ** WARNINGS about FLATHER implementation:
  123. !!1. According to Palma and Matano, 1998 "after ssh" is used.
  124. !! In ROMS and POM implementations, it is "now ssh". In the current
  125. !! implementation (tested only in the EEL-R5 conf.), both cases were unstable.
  126. !! So I use "before ssh" in the following.
  127. !!
  128. !!2. We assume that the normal ssh gradient at the bdy is zero. As a matter of
  129. !! fact, the model ssh just inside the dynamical boundary is used (the outside
  130. !! ssh in the code is not updated).
  131. !!
  132. !! References: Flather, R. A., 1976: A tidal model of the northwest European
  133. !! continental shelf. Mem. Soc. R. Sci. Liege, Ser. 6,10, 141-164.
  134. !!----------------------------------------------------------------------
  135. TYPE(OBC_INDEX), INTENT(in) :: idx ! OBC indices
  136. TYPE(OBC_DATA), INTENT(in) :: dta ! OBC external data
  137. INTEGER, INTENT(in) :: ib_bdy ! BDY set index
  138. REAL(wp), DIMENSION(:,:), INTENT(inout) :: pua2d, pva2d
  139. REAL(wp), DIMENSION(:,:), INTENT(in) :: pssh, phur, phvr
  140. INTEGER :: jb, igrd ! dummy loop indices
  141. INTEGER :: ii, ij, iim1, iip1, ijm1, ijp1 ! 2D addresses
  142. REAL(wp), POINTER :: flagu, flagv ! short cuts
  143. REAL(wp) :: zcorr ! Flather correction
  144. REAL(wp) :: zforc ! temporary scalar
  145. REAL(wp) :: zflag, z1_2 ! " "
  146. !!----------------------------------------------------------------------
  147. IF( nn_timing == 1 ) CALL timing_start('bdy_dyn2d_fla')
  148. z1_2 = 0.5_wp
  149. ! ---------------------------------!
  150. ! Flather boundary conditions :!
  151. ! ---------------------------------!
  152. !!! REPLACE spgu with nemo_wrk work space
  153. ! Fill temporary array with ssh data (here spgu):
  154. igrd = 1
  155. spgu(:,:) = 0.0
  156. DO jb = 1, idx%nblenrim(igrd)
  157. ii = idx%nbi(jb,igrd)
  158. ij = idx%nbj(jb,igrd)
  159. spgu(ii, ij) = dta%ssh(jb)
  160. END DO
  161. CALL lbc_bdy_lnk( spgu(:,:), 'T', 1., ib_bdy )
  162. !
  163. igrd = 2 ! Flather bc on u-velocity;
  164. ! ! remember that flagu=-1 if normal velocity direction is outward
  165. ! ! I think we should rather use after ssh ?
  166. DO jb = 1, idx%nblenrim(igrd)
  167. ii = idx%nbi(jb,igrd)
  168. ij = idx%nbj(jb,igrd)
  169. flagu => idx%flagu(jb,igrd)
  170. iim1 = ii + MAX( 0, INT( flagu ) ) ! T pts i-indice inside the boundary
  171. iip1 = ii - MIN( 0, INT( flagu ) ) ! T pts i-indice outside the boundary
  172. !
  173. zcorr = - flagu * SQRT( grav * phur(ii, ij) ) * ( pssh(iim1, ij) - spgu(iip1,ij) )
  174. ! jchanut tschanges: Set zflag to 0 below to revert to Flather scheme
  175. ! Use characteristics method instead
  176. zflag = ABS(flagu)
  177. zforc = dta%u2d(jb) * (1._wp - z1_2*zflag) + z1_2 * zflag * pua2d(iim1,ij)
  178. pua2d(ii,ij) = zforc + (1._wp - z1_2*zflag) * zcorr * umask(ii,ij,1)
  179. END DO
  180. !
  181. igrd = 3 ! Flather bc on v-velocity
  182. ! ! remember that flagv=-1 if normal velocity direction is outward
  183. DO jb = 1, idx%nblenrim(igrd)
  184. ii = idx%nbi(jb,igrd)
  185. ij = idx%nbj(jb,igrd)
  186. flagv => idx%flagv(jb,igrd)
  187. ijm1 = ij + MAX( 0, INT( flagv ) ) ! T pts j-indice inside the boundary
  188. ijp1 = ij - MIN( 0, INT( flagv ) ) ! T pts j-indice outside the boundary
  189. !
  190. zcorr = - flagv * SQRT( grav * phvr(ii, ij) ) * ( pssh(ii, ijm1) - spgu(ii,ijp1) )
  191. ! jchanut tschanges: Set zflag to 0 below to revert to std Flather scheme
  192. ! Use characteristics method instead
  193. zflag = ABS(flagv)
  194. zforc = dta%v2d(jb) * (1._wp - z1_2*zflag) + z1_2 * zflag * pva2d(ii,ijm1)
  195. pva2d(ii,ij) = zforc + (1._wp - z1_2*zflag) * zcorr * vmask(ii,ij,1)
  196. END DO
  197. CALL lbc_bdy_lnk( pua2d, 'U', -1., ib_bdy ) ! Boundary points should be updated
  198. CALL lbc_bdy_lnk( pva2d, 'V', -1., ib_bdy ) !
  199. !
  200. IF( nn_timing == 1 ) CALL timing_stop('bdy_dyn2d_fla')
  201. !
  202. END SUBROUTINE bdy_dyn2d_fla
  203. SUBROUTINE bdy_dyn2d_orlanski( idx, dta, ib_bdy, pua2d, pva2d, pub2d, pvb2d, ll_npo )
  204. !!----------------------------------------------------------------------
  205. !! *** SUBROUTINE bdy_dyn2d_orlanski ***
  206. !!
  207. !! - Apply Orlanski radiation condition adaptively:
  208. !! - radiation plus weak nudging at outflow points
  209. !! - no radiation and strong nudging at inflow points
  210. !!
  211. !!
  212. !! References: Marchesiello, McWilliams and Shchepetkin, Ocean Modelling vol. 3 (2001)
  213. !!----------------------------------------------------------------------
  214. TYPE(OBC_INDEX), INTENT(in) :: idx ! OBC indices
  215. TYPE(OBC_DATA), INTENT(in) :: dta ! OBC external data
  216. INTEGER, INTENT(in) :: ib_bdy ! number of current open boundary set
  217. REAL(wp), DIMENSION(:,:), INTENT(inout) :: pua2d, pva2d
  218. REAL(wp), DIMENSION(:,:), INTENT(in) :: pub2d, pvb2d
  219. LOGICAL, INTENT(in) :: ll_npo ! flag for NPO version
  220. INTEGER :: ib, igrd ! dummy loop indices
  221. INTEGER :: ii, ij, iibm1, ijbm1 ! indices
  222. !!----------------------------------------------------------------------
  223. IF( nn_timing == 1 ) CALL timing_start('bdy_dyn2d_orlanski')
  224. !
  225. igrd = 2 ! Orlanski bc on u-velocity;
  226. !
  227. CALL bdy_orlanski_2d( idx, igrd, pub2d, pua2d, dta%u2d, ll_npo )
  228. igrd = 3 ! Orlanski bc on v-velocity
  229. !
  230. CALL bdy_orlanski_2d( idx, igrd, pvb2d, pva2d, dta%v2d, ll_npo )
  231. !
  232. IF( nn_timing == 1 ) CALL timing_stop('bdy_dyn2d_orlanski')
  233. !
  234. CALL lbc_bdy_lnk( pua2d, 'U', -1., ib_bdy ) ! Boundary points should be updated
  235. CALL lbc_bdy_lnk( pva2d, 'V', -1., ib_bdy ) !
  236. !
  237. IF( nn_timing == 1 ) CALL timing_stop('bdy_dyn2d_orlanski')
  238. !
  239. END SUBROUTINE bdy_dyn2d_orlanski
  240. SUBROUTINE bdy_ssh( zssh )
  241. !!----------------------------------------------------------------------
  242. !! *** SUBROUTINE bdy_ssh ***
  243. !!
  244. !! ** Purpose : Duplicate sea level across open boundaries
  245. !!
  246. !!----------------------------------------------------------------------
  247. REAL(wp), DIMENSION(:,:), INTENT(inout) :: zssh ! Sea level
  248. !!
  249. INTEGER :: ib_bdy, ib, igrd ! local integers
  250. INTEGER :: ii, ij, zcoef, ip, jp ! " "
  251. igrd = 1 ! Everything is at T-points here
  252. DO ib_bdy = 1, nb_bdy
  253. DO ib = 1, idx_bdy(ib_bdy)%nblenrim(igrd)
  254. ii = idx_bdy(ib_bdy)%nbi(ib,igrd)
  255. ij = idx_bdy(ib_bdy)%nbj(ib,igrd)
  256. ! Set gradient direction:
  257. zcoef = bdytmask(ii-1,ij) + bdytmask(ii+1,ij) + bdytmask(ii,ij-1) + bdytmask(ii,ij+1)
  258. IF ( zcoef == 0 ) THEN
  259. zssh(ii,ij) = 0._wp
  260. ELSE
  261. ip = bdytmask(ii+1,ij ) - bdytmask(ii-1,ij )
  262. jp = bdytmask(ii ,ij+1) - bdytmask(ii ,ij-1)
  263. zssh(ii,ij) = zssh(ii+ip,ij+jp) * tmask(ii+ip,ij+jp,1)
  264. ENDIF
  265. END DO
  266. ! Boundary points should be updated
  267. CALL lbc_bdy_lnk( zssh(:,:), 'T', 1., ib_bdy )
  268. END DO
  269. END SUBROUTINE bdy_ssh
  270. #else
  271. !!----------------------------------------------------------------------
  272. !! Dummy module NO Unstruct Open Boundary Conditions
  273. !!----------------------------------------------------------------------
  274. CONTAINS
  275. SUBROUTINE bdy_dyn2d( kt ) ! Empty routine
  276. INTEGER, intent(in) :: kt
  277. WRITE(*,*) 'bdy_dyn2d: You should not have seen this print! error?', kt
  278. END SUBROUTINE bdy_dyn2d
  279. #endif
  280. !!======================================================================
  281. END MODULE bdydyn2d