New URL for NEMO forge!   http://forge.nemo-ocean.eu

Since March 2022 along with NEMO 4.2 release, the code development moved to a self-hosted GitLab.
This present forge is now archived and remained online for history.
trcbdy.F90 in branches/UKMO/AMM15_v3_6_STABLE_package_reanalysis4/NEMOGCM/NEMO/TOP_SRC – NEMO

source: branches/UKMO/AMM15_v3_6_STABLE_package_reanalysis4/NEMOGCM/NEMO/TOP_SRC/trcbdy.F90

Last change on this file was 13008, checked in by rrenshaw, 4 years ago

revert Sarah's boundary conditions change for v5 reanalysis

File size: 14.2 KB
Line 
1MODULE trcbdy
2   !!======================================================================
3   !!                       ***  MODULE  bdytrc  ***
4   !! Ocean tracers:   Apply boundary conditions for tracers in TOP component
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   !!            3.6  !  2015     (T. Lovato) Adapt BDY for tracers in TOP component
11! RJR: Sarah's boundary changes reverted here to see if they fix the BGC blow-ups
12   !!----------------------------------------------------------------------
13#if defined key_bdy && key_top
14   !!----------------------------------------------------------------------
15   !!   'key_bdy'                     Unstructured Open Boundary Conditions
16   !!----------------------------------------------------------------------
17   !!   trc_bdy            : Apply open boundary conditions to T and S
18   !!   trc_bdy_frs        : Apply Flow Relaxation Scheme
19   !!----------------------------------------------------------------------
20   USE timing                       ! Timing
21   USE oce_trc                      ! ocean dynamics and tracers variables
22   USE par_trc
23   USE trc                          ! ocean space and time domain variables
24   USE bdylib                       ! for orlanski library routines
25   USE lbclnk                       ! ocean lateral boundary conditions (or mpp link)
26   USE in_out_manager               ! I/O manager
27   USE bdy_oce, only: idx_bdy, OBC_INDEX, BDYTMASK, lk_bdy       ! ocean open boundary conditions
28
29   IMPLICIT NONE
30   PRIVATE
31
32   PUBLIC trc_bdy      ! routine called in trcnxt.F90
33   PUBLIC trc_bdy_dmp  ! routine called in trcstp.F90
34
35   !!----------------------------------------------------------------------
36   !! NEMO/OPA 3.6 , NEMO Consortium (2015)
37   !! $Id$
38   !! Software governed by the CeCILL licence (NEMOGCM/NEMO_CeCILL.txt)
39   !!----------------------------------------------------------------------
40CONTAINS
41
42   SUBROUTINE trc_bdy( kt )
43      !!----------------------------------------------------------------------
44      !!                  ***  SUBROUTINE trc_bdy  ***
45      !!
46      !! ** Purpose : - Apply open boundary conditions for tracers in TOP component
47      !!                and scale the tracer data
48      !!
49      !!----------------------------------------------------------------------
50      INTEGER, INTENT( in ) :: kt     ! Main time step counter
51      !!
52      INTEGER               :: ib_bdy, jn ! Loop indeces
53      !!----------------------------------------------------------------------
54      !
55      IF( nn_timing == 1 ) CALL timing_start('trc_bdy')
56      !
57      DO jn = 1, jptra
58         DO ib_bdy=1, nb_bdy
59
60            SELECT CASE( trcdta_bdy(jn,ib_bdy)%cn_obc )
61            CASE('none')
62               CYCLE
63            CASE('frs')
64               CALL bdy_trc_frs( jn, idx_bdy(ib_bdy), trcdta_bdy(jn,ib_bdy), kt )
65            CASE('specified')
66               CALL bdy_trc_spe( jn, idx_bdy(ib_bdy), trcdta_bdy(jn,ib_bdy), kt )
67            CASE('neumann')
68               CALL bdy_trc_nmn( jn, idx_bdy(ib_bdy), trcdta_bdy(jn,ib_bdy), kt )
69            CASE('orlanski')
70               CALL bdy_trc_orlanski( jn, idx_bdy(ib_bdy), trcdta_bdy(jn,ib_bdy), ll_npo=.false. )
71            CASE('orlanski_npo')
72               CALL bdy_trc_orlanski( jn, idx_bdy(ib_bdy), trcdta_bdy(jn,ib_bdy), ll_npo=.true. )
73            CASE DEFAULT
74               CALL ctl_stop( 'bdy_tra : unrecognised option for open boundaries for T and S' )
75            END SELECT
76
77            ! Boundary points should be updated
78            CALL lbc_bdy_lnk( tra(:,:,:,jn), 'T', 1., ib_bdy )
79
80         ENDDO
81      ENDDO
82      !
83      IF( nn_timing == 1 ) CALL timing_stop('trc_bdy')
84
85   END SUBROUTINE trc_bdy
86
87   SUBROUTINE bdy_trc_frs( jn, idx, dta, kt )
88      !!----------------------------------------------------------------------
89      !!                 ***  SUBROUTINE bdy_trc_frs  ***
90      !!                   
91      !! ** Purpose : Apply the Flow Relaxation Scheme for tracers at open boundaries.
92      !!
93      !! Reference : Engedahl H., 1995, Tellus, 365-382.
94      !!----------------------------------------------------------------------
95      INTEGER,         INTENT(in) ::   kt
96      INTEGER,         INTENT(in) ::   jn   ! Tracer index
97      TYPE(OBC_INDEX), INTENT(in) ::   idx  ! OBC indices
98      TYPE(OBC_DATA),  INTENT(in) ::   dta  ! OBC external data
99      !!
100      REAL(wp) ::   zwgt           ! boundary weight
101      INTEGER  ::   ib, ik, igrd   ! dummy loop indices
102      INTEGER  ::   ii, ij         ! 2D addresses
103      !!----------------------------------------------------------------------
104      !
105      IF( nn_timing == 1 ) CALL timing_start('bdy_trc_frs')
106      !
107      igrd = 1                       ! Everything is at T-points here
108      DO ib = 1, idx%nblen(igrd)
109         DO ik = 1, jpkm1
110            ii = idx%nbi(ib,igrd)
111            ij = idx%nbj(ib,igrd)
112! RJR: Sarah's boundary changes reverted here to see if they fix the BGC blow-ups
113!           zwgt = idx%nbw(ib,igrd) * rdttrc(ik) / 86400.d0  ! damping with a timescale of day
114            zwgt = idx%nbw(ib,igrd)
115            tra(ii,ij,ik,jn) = ( tra(ii,ij,ik,jn) + zwgt * ( ( dta%trc(ib,ik) * dta%rn_fac)  & 
116                        &  - tra(ii,ij,ik,jn) ) ) * tmask(ii,ij,ik)
117         END DO
118      END DO 
119! ! tra is overwritten at the boundary so damping doesn't work here - need neumann in addition
120! ! to duplicate the internal value at the boundary
121!       CALL bdy_trc_nmn( jn,  idx, dta, kt )
122
123
124      !
125      IF( kt .eq. nit000 ) CLOSE( unit = 102 )
126      !
127      IF( nn_timing == 1 ) CALL timing_stop('bdy_trc_frs')
128      !
129   END SUBROUTINE bdy_trc_frs
130 
131   SUBROUTINE bdy_trc_spe( jn, idx, dta, kt )
132      !!----------------------------------------------------------------------
133      !!                 ***  SUBROUTINE bdy_trc_frs  ***
134      !!                   
135      !! ** Purpose : Apply a specified value for tracers at open boundaries.
136      !!
137      !!----------------------------------------------------------------------
138      INTEGER,         INTENT(in) ::   kt
139      INTEGER,         INTENT(in) ::   jn   ! Tracer index
140      TYPE(OBC_INDEX), INTENT(in) ::   idx  ! OBC indices
141      TYPE(OBC_DATA),  INTENT(in) ::   dta  ! OBC external data
142      !!
143      REAL(wp) ::   zwgt           ! boundary weight
144      INTEGER  ::   ib, ik, igrd   ! dummy loop indices
145      INTEGER  ::   ii, ij         ! 2D addresses
146      !!----------------------------------------------------------------------
147      !
148      IF( nn_timing == 1 ) CALL timing_start('bdy_trc_spe')
149      !
150      igrd = 1                       ! Everything is at T-points here
151      DO ib = 1, idx%nblenrim(igrd)
152         ii = idx%nbi(ib,igrd)
153         ij = idx%nbj(ib,igrd)
154         DO ik = 1, jpkm1
155            tra(ii,ij,ik,jn) = dta%trc(ib,ik) * dta%rn_fac * tmask(ii,ij,ik)
156         END DO
157      END DO
158      !
159      IF( kt .eq. nit000 ) CLOSE( unit = 102 )
160      !
161      IF( nn_timing == 1 ) CALL timing_stop('bdy_trc_spe')
162      !
163   END SUBROUTINE bdy_trc_spe
164
165   SUBROUTINE bdy_trc_nmn( jn, idx, dta, kt )
166      !!----------------------------------------------------------------------
167      !!                 ***  SUBROUTINE bdy_trc_nmn  ***
168      !!                   
169      !! ** Purpose : Duplicate the value for tracers at open boundaries.
170      !!
171      !!----------------------------------------------------------------------
172      INTEGER,         INTENT(in) ::   kt
173      INTEGER,         INTENT(in) ::   jn   ! Tracer index
174      TYPE(OBC_INDEX), INTENT(in) ::   idx  ! OBC indices
175      TYPE(OBC_DATA),  INTENT(in) ::   dta  ! OBC external data
176      !!
177      REAL(wp) ::   zcoef, zcoef1, zcoef2           ! boundary weight
178      INTEGER  ::   ib, ik, igrd   ! dummy loop indices
179      INTEGER  ::   ii, ij, ip, jp   ! 2D addresses
180      !!----------------------------------------------------------------------
181      !
182      IF( nn_timing == 1 ) CALL timing_start('bdy_trc_nmn')
183      !
184      igrd = 1                       ! Everything is at T-points here
185      DO ib = 1, idx%nblenrim(igrd)
186         ii = idx%nbi(ib,igrd)
187         ij = idx%nbj(ib,igrd)
188         DO ik = 1, jpkm1
189            ! search the sense of the gradient
190            zcoef1 = bdytmask(ii-1,ij  )*tmask(ii-1,ij,ik) +  bdytmask(ii+1,ij  )*tmask(ii+1,ij,ik)
191            zcoef2 = bdytmask(ii  ,ij-1)*tmask(ii,ij-1,ik) +  bdytmask(ii  ,ij+1)*tmask(ii,ij+1,ik)
192            IF ( nint(zcoef1+zcoef2) == 0) THEN
193               ! corner
194               zcoef = tmask(ii-1,ij,ik) + tmask(ii+1,ij,ik) +  tmask(ii,ij-1,ik) +  tmask(ii,ij+1,ik)
195               IF (zcoef > .5_wp) THEN ! Only set not isolated points.
196                 tra(ii,ij,ik,jn) = tra(ii-1,ij  ,ik,jn) * tmask(ii-1,ij  ,ik) + &
197                   &              tra(ii+1,ij  ,ik,jn) * tmask(ii+1,ij  ,ik) + &
198                   &              tra(ii  ,ij-1,ik,jn) * tmask(ii  ,ij-1,ik) + &
199                   &              tra(ii  ,ij+1,ik,jn) * tmask(ii  ,ij+1,ik)
200                 tra(ii,ij,ik,jn) = ( tra(ii,ij,ik,jn) / zcoef ) * tmask(ii,ij,ik)
201               ENDIF
202            ELSEIF ( nint(zcoef1+zcoef2) == 2) THEN
203               ! oblique corner
204               zcoef = tmask(ii-1,ij,ik)*bdytmask(ii-1,ij  ) + tmask(ii+1,ij,ik)*bdytmask(ii+1,ij  ) + &
205                  &  tmask(ii,ij-1,ik)*bdytmask(ii,ij -1 ) +  tmask(ii,ij+1,ik)*bdytmask(ii,ij+1  )
206               tra(ii,ij,ik,jn) = tra(ii-1,ij  ,ik,jn) * tmask(ii-1,ij  ,ik)*bdytmask(ii-1,ij  ) + &
207                  &              tra(ii+1,ij  ,ik,jn) * tmask(ii+1,ij  ,ik)*bdytmask(ii+1,ij  )  + &
208                  &              tra(ii  ,ij-1,ik,jn) * tmask(ii  ,ij-1,ik)*bdytmask(ii,ij -1 ) + &
209                  &              tra(ii  ,ij+1,ik,jn) * tmask(ii  ,ij+1,ik)*bdytmask(ii,ij+1  )
210 
211               tra(ii,ij,ik,jn) = ( tra(ii,ij,ik,jn) / MAX(1._wp, zcoef) ) * tmask(ii,ij,ik)
212            ELSE
213               ip = nint(bdytmask(ii+1,ij  )*tmask(ii+1,ij,ik) - bdytmask(ii-1,ij  )*tmask(ii-1,ij,ik))
214               jp = nint(bdytmask(ii  ,ij+1)*tmask(ii,ij+1,ik) - bdytmask(ii  ,ij-1)*tmask(ii,ij-1,ik))
215               tra(ii,ij,ik,jn) = tra(ii+ip,ij+jp,ik,jn) * tmask(ii+ip,ij+jp,ik) * tmask(ii,ij,ik)
216            ENDIF
217         END DO
218      END DO
219      !
220      IF( kt .eq. nit000 ) CLOSE( unit = 102 )
221      !
222      IF( nn_timing == 1 ) CALL timing_stop('bdy_trc_nmn')
223      !
224   END SUBROUTINE bdy_trc_nmn
225 
226
227   SUBROUTINE bdy_trc_orlanski( jn, idx, dta, ll_npo )
228      !!----------------------------------------------------------------------
229      !!                 ***  SUBROUTINE bdy_trc_orlanski  ***
230      !!             
231      !!              - Apply Orlanski radiation to tracers of TOP component.
232      !!              - Wrapper routine for bdy_orlanski_3d
233      !!
234      !!
235      !! References:  Marchesiello, McWilliams and Shchepetkin, Ocean Modelling vol. 3 (2001)   
236      !!----------------------------------------------------------------------
237      INTEGER,                      INTENT(in) ::   jn      ! Tracer index
238      TYPE(OBC_INDEX),              INTENT(in) ::   idx     ! OBC indices
239      TYPE(OBC_DATA),               INTENT(in) ::   dta     ! OBC external data
240      LOGICAL,                      INTENT(in) ::   ll_npo  ! switch for NPO version
241
242      INTEGER  ::   igrd                                    ! grid index
243      !!----------------------------------------------------------------------
244
245      IF( nn_timing == 1 ) CALL timing_start('bdy_trc_orlanski')
246      !
247      igrd = 1      ! Orlanski bc on tracers;
248      !           
249      CALL bdy_orlanski_3d( idx, igrd, trb(:,:,:,jn), tra(:,:,:,jn), (dta%trc * dta%rn_fac), ll_npo )
250      !
251      IF( nn_timing == 1 ) CALL timing_stop('bdy_trc_orlanski')
252      !
253
254   END SUBROUTINE bdy_trc_orlanski
255
256   SUBROUTINE trc_bdy_dmp( kt )
257      !!----------------------------------------------------------------------
258      !!                 ***  SUBROUTINE trc_bdy_dmp  ***
259      !!                   
260      !! ** Purpose : Apply damping for tracers at open boundaries.
261      !!             It currently applies the damping to all tracers!!!
262      !!
263      !!----------------------------------------------------------------------
264      INTEGER,         INTENT(in) ::   kt
265      !!
266      INTEGER  ::   jn             ! Tracer index
267      REAL(wp) ::   zwgt           ! boundary weight
268      REAL(wp) ::   zta, zsa, ztime
269      INTEGER  ::   ib, ik, igrd   ! dummy loop indices
270      INTEGER  ::   ii, ij         ! 2D addresses
271      INTEGER  ::   ib_bdy         ! Loop index
272      !!----------------------------------------------------------------------
273      !
274      IF( nn_timing == 1 ) CALL timing_start('trc_bdy_dmp')
275      !
276      DO jn = 1, jptra
277         DO ib_bdy=1, nb_bdy
278            IF ( trcdta_bdy(jn, ib_bdy)%dmp ) THEN
279               igrd = 1                       ! Everything is at T-points here
280               DO ib = 1, idx_bdy(ib_bdy)%nblen(igrd)
281                  ii = idx_bdy(ib_bdy)%nbi(ib,igrd)
282                  ij = idx_bdy(ib_bdy)%nbj(ib,igrd)
283                  zwgt = idx_bdy(ib_bdy)%nbd(ib,igrd)
284                  DO ik = 1, jpkm1
285                     zta = zwgt * ( trcdta_bdy(jn, ib_bdy)%trc(ib,ik) - trb(ii,ij,ik,jn) ) * tmask(ii,ij,ik)
286                     tra(ii,ij,ik,jn) = tra(ii,ij,ik,jn) + zta
287                  END DO
288               END DO
289            ENDIF
290         ENDDO
291      ENDDO
292      !
293      IF( nn_timing == 1 ) CALL timing_stop('trc_bdy_dmp')
294      !
295   END SUBROUTINE trc_bdy_dmp
296 
297#else
298   !!----------------------------------------------------------------------
299   !!   Dummy module                   NO Unstruct Open Boundary Conditions
300   !!----------------------------------------------------------------------
301CONTAINS
302   SUBROUTINE trc_bdy(kt)      ! Empty routine
303      WRITE(*,*) 'trc_bdy: You should not have seen this print! error?', kt
304   END SUBROUTINE trc_bdy
305
306   SUBROUTINE trc_bdy_dmp(kt)      ! Empty routine
307      WRITE(*,*) 'trc_bdy_dmp: You should not have seen this print! error?', kt
308   END SUBROUTINE trc_bdy_dmp
309
310#endif
311
312   !!======================================================================
313END MODULE trcbdy
Note: See TracBrowser for help on using the repository browser.