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.
bdyini.F90 in trunk/NEMO/OPA_SRC/BDY – NEMO

source: trunk/NEMO/OPA_SRC/BDY/bdyini.F90 @ 1125

Last change on this file since 1125 was 1125, checked in by ctlod, 16 years ago

trunk: BDY package code review (coding rules), see ticket: #214

  • Property svn:executable set to *
File size: 19.0 KB
Line 
1MODULE bdyini
2   !!======================================================================
3   !!                       ***  MODULE  bdyini  ***
4   !! Unstructured open boundaries : initialisation
5   !!======================================================================
6   !! History :  1.0  !  2005-01  (J. Chanut, A. Sellar)  Original code
7   !!             -   !  2007-01  (D. Storkey) Update to use IOM module
8   !!             -   !  2007-01  (D. Storkey) Tidal forcing
9   !!            3.0  !  2008-04  (NEMO team)  add in the reference version
10   !!----------------------------------------------------------------------
11#if defined key_bdy
12   !!----------------------------------------------------------------------
13   !!   'key_bdy'                     Unstructured Open Boundary Conditions
14   !!----------------------------------------------------------------------
15   !!   bdy_init       : Initialization of unstructured open boundaries
16   !!----------------------------------------------------------------------
17   USE oce             ! ocean dynamics and tracers variables
18   USE dom_oce         ! ocean space and time domain
19   USE bdy_oce         ! unstructured open boundary conditions
20   USE bdytides        ! tides at open boundaries initialization (tide_init routine)
21   USE in_out_manager  ! I/O units
22   USE lbclnk          ! ocean lateral boundary conditions (or mpp link)
23   USE lib_mpp         ! for mpp_sum 
24   USE iom             ! I/O
25
26   IMPLICIT NONE
27   PRIVATE
28
29   PUBLIC   bdy_init   ! routine called by opa.F90
30
31   !!----------------------------------------------------------------------
32   !! NEMO/OPA 3.0 , LOCEAN-IPSL (2008)
33   !! $Id: $
34   !! Software governed by the CeCILL licence (modipsl/doc/NEMO_CeCILL.txt)
35   !!---------------------------------------------------------------------------------
36
37CONTAINS
38   
39   SUBROUTINE bdy_init
40      !!----------------------------------------------------------------------
41      !!                 ***  ROUTINE bdy_init  ***
42      !!         
43      !! ** Purpose :   Initialization of the dynamics and tracer fields with
44      !!      unstructured open boundaries.
45      !!
46      !! ** Method  :  Read initialization arrays (mask, indices) to identify
47      !!               an unstructured open boundary
48      !!
49      !! ** Input   :  bdy_init.nc, input file for unstructured open boundaries
50      !!
51      !!----------------------------------------------------------------------     
52      INTEGER ::   ii, ij, ik, igrd, ib, ir   ! dummy loop indices
53      INTEGER ::   icount, icountr
54      INTEGER ::   ib_len, ibr_max
55      INTEGER ::   iw, ie, is, in 
56      INTEGER ::   inum                 ! temporary logical unit
57      INTEGER ::   id_dummy             ! temporary integers
58      INTEGER ::   igrd_start, igrd_end ! start and end of loops on igrd
59      INTEGER, DIMENSION (2)             ::   kdimsz
60      INTEGER, DIMENSION(jpbdta, jpbgrd) ::   nbidta, nbjdta   ! Index arrays: i and j indices of bdy dta
61      INTEGER, DIMENSION(jpbdta, jpbgrd) ::   nbrdta           ! Discrete distance from rim points
62      REAL(wp) :: zefl, zwfl, znfl, zsfl                       ! temporary scalars
63      REAL(wp) , DIMENSION(jpidta,jpjdta) ::   zmask           ! global domain mask
64      REAL(wp) , DIMENSION(jpbdta,1)      ::   zdta            ! temporary array
65      CHARACTER(LEN=80),DIMENSION(3)      ::   clfile
66      !!
67      NAMELIST/nambdy/filbdy_mask, filbdy_data_T, filbdy_data_U, filbdy_data_V,          &
68         &            ln_bdy_tides, ln_bdy_clim, ln_bdy_vol, ln_bdy_mask,                &
69         &            ln_bdy_dyn_fla, ln_bdy_dyn_frs, ln_bdy_tra_frs,                    &
70         &            nbdy_dta   , nb_rimwidth  , volbdy
71      !!----------------------------------------------------------------------
72
73      IF(lwp) WRITE(numout,*)
74      IF(lwp) WRITE(numout,*) 'bdy_init : initialization of unstructured open boundaries'
75      IF(lwp) WRITE(numout,*) '~~~~~~~~'
76      !
77      IF( jperio /= 0 ) CALL ctl_stop( 'Cyclic or symmetric,',   &
78           ' and unstructured open boundary condition are not compatible' )
79
80#if defined key_obc
81      CALL ctl_stop( 'Straight open boundaries,',   &
82           ' and unstructured open boundaries are not compatible' )
83#endif
84
85# if defined key_dynspg_rl
86      CALL ctl_stop( 'Rigid lid,',   &
87           ' and unstructured open boundaries are not compatible' )
88#endif
89
90      ! Read namelist parameters
91      ! ---------------------------
92      REWIND( numnam )
93      READ  ( numnam, nambdy )
94
95      ! control prints
96      IF(lwp) WRITE(numout,*) '         nambdy'
97
98      ! Check nbdy_dta value
99      IF(lwp) WRITE(numout,*) 'nbdy_dta =', nbdy_dta     
100      IF(lwp) WRITE(numout,*) ' '
101      SELECT CASE( nbdy_dta )
102      CASE( 0 )
103        IF(lwp) WRITE(numout,*) '         initial state used for bdy data'       
104      CASE( 1 )
105        IF(lwp) WRITE(numout,*) '         boundary data taken from file'
106      CASE DEFAULT
107        CALL ctl_stop( 'nbdy_dta must be 0 or 1' )
108      END SELECT
109
110      IF(lwp) WRITE(numout,*) ' '
111      IF(lwp) WRITE(numout,*) 'Boundary rim width for the FRS nb_rimwidth = ', nb_rimwidth
112
113      IF(lwp) WRITE(numout,*) ' '
114      IF(lwp) WRITE(numout,*) '         volbdy = ', volbdy
115
116      IF (ln_bdy_vol) THEN
117        SELECT CASE ( volbdy ) ! Check volbdy value
118        CASE( 1 )
119          IF(lwp) WRITE(numout,*) '         The total volume will be constant'
120        CASE( 0 )
121          IF(lwp) WRITE(numout,*) '         The total volume will vary according'
122          IF(lwp) WRITE(numout,*) '         to the surface E-P flux'
123        CASE DEFAULT
124          CALL ctl_stop( 'volbdy must be 0 or 1' )
125        END SELECT
126      ELSE
127        IF(lwp) WRITE(numout,*) 'No volume correction with unstructured open boundaries'
128        IF(lwp) WRITE(numout,*) ' '
129      ENDIF
130
131      IF (ln_bdy_tides) THEN
132        IF(lwp) WRITE(numout,*) ' '
133        IF(lwp) WRITE(numout,*) 'Tidal harmonic forcing at unstructured open boundaries'
134        IF(lwp) WRITE(numout,*) ' '
135      ENDIF
136
137      IF (ln_bdy_dyn_fla) THEN
138        IF(lwp) WRITE(numout,*) ' '
139        IF(lwp) WRITE(numout,*) 'Flather condition on U, V at unstructured open boundaries'
140        IF(lwp) WRITE(numout,*) ' '
141      ENDIF
142
143      IF (ln_bdy_dyn_frs) THEN
144        IF(lwp) WRITE(numout,*) ' '
145        IF(lwp) WRITE(numout,*) 'FRS condition on U and V at unstructured open boundaries'
146        IF(lwp) WRITE(numout,*) ' '
147      ENDIF
148
149      IF (ln_bdy_tra_frs) THEN
150        IF(lwp) WRITE(numout,*) ' '
151        IF(lwp) WRITE(numout,*) 'FRS condition on T & S fields at unstructured open boundaries'
152        IF(lwp) WRITE(numout,*) ' '
153      ENDIF
154
155      ! Read tides namelist
156      ! ------------------------
157      IF( ln_bdy_tides )   CALL tide_init
158
159      ! Read arrays defining unstructured open boundaries
160      ! -------------------------------------------------
161
162      ! Read global 2D mask at T-points: bdytmask
163      ! *****************************************
164      ! bdytmask = 1  on the computational domain AND on open boundaries
165      !          = 0  elsewhere   
166 
167      IF( cp_cfg == "eel" .AND. jp_cfg == 5 ) THEN
168         zmask(         :                ,:) = 0.e0
169         zmask(jpizoom+1:jpizoom+jpiglo-2,:) = 1.e0         
170      ELSE IF ( ln_bdy_mask ) THEN
171         CALL iom_open( filbdy_mask, inum )
172         CALL iom_get ( inum, jpdom_data, 'bdy_msk', zmask(:,:) )
173         CALL iom_close( inum )
174      ELSE
175         zmask(:,:) = 1.e0
176      ENDIF
177
178      ! Save mask over local domain     
179      DO ij = 1, nlcj
180         DO ii = 1, nlci
181            bdytmask(ii,ij) = zmask( mig(ii), mjg(ij) )
182         END DO
183      END DO
184
185      ! Derive mask on U and V grid from mask on T grid
186      bdyumask(:,:) = 0.e0
187      bdyvmask(:,:) = 0.e0
188      DO ij=1, jpjm1
189         DO ii=1, jpim1
190            bdyumask(ii,ij)=bdytmask(ii,ij)*bdytmask(ii+1, ij )
191            bdyvmask(ii,ij)=bdytmask(ii,ij)*bdytmask(ii  ,ij+1) 
192         END DO
193      END DO
194
195      ! Lateral boundary conditions
196      CALL lbc_lnk( bdyumask(:,:), 'U', 1. )
197      CALL lbc_lnk( bdyvmask(:,:), 'V', 1. )
198
199      ! Read discrete distance and mapping indices
200      ! ******************************************
201      nbidta(:,:) = 0.e0
202      nbjdta(:,:) = 0.e0
203      nbrdta(:,:) = 0.e0
204
205      IF( cp_cfg == "eel" .AND. jp_cfg == 5 ) THEN
206         icount = 0
207         ! Define west boundary (from ii=2 to ii=1+nb_rimwidth):
208         DO ir = 1, nb_rimwidth         
209            DO ij = 3, jpjglo-2
210               icount=icount+1
211               nbidta(icount,:) = ir + 1 + (jpizoom-1)
212               nbjdta(icount,:) = ij + (jpjzoom-1) 
213               nbrdta(icount,:) = ir
214            END DO
215         END DO
216
217         ! Define east boundary (from ii=jpiglo-1 to ii=jpiglo-nb_rimwidth):
218         DO ir=1,nb_rimwidth         
219            DO ij=3,jpjglo-2
220               icount=icount+1
221               nbidta(icount,:) = jpiglo-ir + (jpizoom-1)
222               nbidta(icount,2) = jpiglo-ir-1 + (jpizoom-1) ! special case for u points
223               nbjdta(icount,:) = ij + (jpjzoom-1)
224               nbrdta(icount,:) = ir
225            END DO
226         END DO
227           
228      ELSE            ! Read indices and distances in unstructured boundary data files
229
230         IF( ln_bdy_tides ) THEN 
231            ! Read tides input files for preference in case there are
232            ! no bdydata files.
233            clfile(1) = TRIM(filtide)//TRIM(tide_cpt(1))//'_grid_T.nc'
234            clfile(2) = TRIM(filtide)//TRIM(tide_cpt(1))//'_grid_U.nc'
235            clfile(3) = TRIM(filtide)//TRIM(tide_cpt(1))//'_grid_V.nc'
236         ELSE
237            clfile(1) = filbdy_data_T
238            clfile(2) = filbdy_data_U
239            clfile(3) = filbdy_data_V
240         ENDIF         
241
242         ! how many files are we to read in?
243         igrd_start = 1
244         igrd_end   = 3
245         IF(.NOT. ln_bdy_tides ) THEN
246            IF(.NOT. (ln_bdy_dyn_fla) .AND..NOT. (ln_bdy_tra_frs)) THEN
247               ! No T-grid file.
248               igrd_start = 2
249            ELSEIF ( .NOT. ln_bdy_dyn_frs .AND..NOT. ln_bdy_dyn_fla ) THEN
250               ! No U-grid or V-grid file.
251               igrd_end   = 1         
252            ENDIF
253         ENDIF
254
255         DO igrd = igrd_start, igrd_end
256            CALL iom_open( clfile(igrd), inum )
257            id_dummy = iom_varid( inum, 'nbidta', kdimsz=kdimsz ) 
258            WRITE(numout,*) 'kdimsz : ',kdimsz
259            ib_len = kdimsz(1)
260            IF( ib_len > jpbdta) CALL ctl_stop(          &
261                'Boundary data array in file too long.', &
262                'File :', TRIM(clfile(igrd)),            &
263                'increase parameter jpbdta.' )
264
265            CALL iom_get( inum, jpdom_unknown, 'nbidta', zdta(1:ib_len,:) )
266            DO ii = 1,ib_len
267               nbidta(ii,igrd) = INT( zdta(ii,1) )
268            END DO
269            CALL iom_get( inum, jpdom_unknown, 'nbjdta', zdta(1:ib_len,:) )
270            DO ii = 1,ib_len
271              nbjdta(ii,igrd) = INT( zdta(ii,1) )
272            END DO
273            CALL iom_get ( inum, jpdom_unknown, 'nbrdta', zdta(1:ib_len,:) )
274            DO ii = 1,ib_len
275              nbrdta(ii,igrd) = INT( zdta(ii,1) )
276            END DO
277            CALL iom_close( inum )
278
279            ! Check that rimwidth in file is big enough:
280            ibr_max = MAXVAL( nbrdta(:,igrd) )
281            IF(lwp) WRITE(numout,*)
282            IF(lwp) WRITE(numout,*) ' Maximum rimwidth in file is ', ibr_max
283            IF(lwp) WRITE(numout,*) ' nb_rimwidth from namelist is ', nb_rimwidth
284            IF (ibr_max < nb_rimwidth) CALL ctl_stop( &
285                'nb_rimwidth is larger than maximum rimwidth in file' )
286            !
287         END DO
288         !
289      ENDIF 
290
291      ! Dispatch mapping indices and discrete distances on each processor
292      ! *****************************************************************
293     
294      iw = mig(1) + 1            ! if monotasking and no zoom, iw=2
295      ie = mig(1) + nlci-1 - 1   ! if monotasking and no zoom, ie=jpim1
296      is = mjg(1) + 1            ! if monotasking and no zoom, is=2
297      in = mjg(1) + nlcj-1 - 1   ! if monotasking and no zoom, in=jpjm1
298
299      DO igrd = igrd_start, igrd_end
300        icount  = 0
301        icountr = 0
302        nblen(igrd) = 0
303        nblenrim(igrd) = 0
304        nblendta(igrd) = 0
305        DO ir=1, nb_rimwidth
306          DO ib = 1, jpbdta
307          ! check if point is in local domain and equals ir
308            IF(  nbidta(ib,igrd) >= iw .AND. nbidta(ib,igrd) <= ie .AND.   &
309               & nbjdta(ib,igrd) >= is .AND. nbjdta(ib,igrd) <= in .AND.   &
310               & nbrdta(ib,igrd) == ir  ) THEN
311               !
312               icount = icount  + 1
313               !
314               IF( ir == 1 )   icountr = icountr+1
315                  IF (icount > jpbdim) THEN
316                     IF(lwp) WRITE(numout,*) 'bdy_ini: jpbdim too small'
317                     nstop = nstop + 1
318                  ELSE
319                     nbi(icount, igrd)  = nbidta(ib,igrd)- mig(1)+1
320                     nbj(icount, igrd)  = nbjdta(ib,igrd)- mjg(1)+1
321                     nbr(icount, igrd)  = nbrdta(ib,igrd)
322                     nbmap(icount,igrd) = ib
323                  ENDIF           
324               ENDIF
325            END DO
326         END DO
327         nblenrim(igrd) = icountr !: length of rim boundary data on each proc
328         nblen   (igrd) = icount  !: length of boundary data on each proc       
329      END DO 
330
331      ! Compute rim weights
332      ! -------------------
333      DO igrd = igrd_start, igrd_end
334         DO ib = 1, nblen(igrd)
335            ! tanh formulation
336            nbw(ib,igrd) = 1.- TANH( FLOAT( nbr(ib,igrd) - 1 ) *0.5 )
337            ! quadratic
338!           nbw(ib,igrd) = (FLOAT(nb_rimwidth+1-nbr(ib,igrd))/FLOAT(nb_rimwidth))**2
339            ! linear
340!           nbw(ib,igrd) =  FLOAT(nb_rimwidth+1-nbr(ib,igrd))/FLOAT(nb_rimwidth)
341         END DO
342      END DO 
343   
344      ! Mask corrections
345      ! ----------------
346      DO ik = 1, jpkm1
347         DO ij = 1, jpj
348            DO ii = 1, jpi
349               tmask(ii,ij,ik) = tmask(ii,ij,ik) * bdytmask(ii,ij)
350               umask(ii,ij,ik) = umask(ii,ij,ik) * bdyumask(ii,ij)
351               vmask(ii,ij,ik) = vmask(ii,ij,ik) * bdyvmask(ii,ij)
352               bmask(ii,ij)    = bmask(ii,ij)    * bdytmask(ii,ij)
353            END DO     
354         END DO
355      END DO
356
357      DO ik = 1, jpkm1
358         DO ij = 2, jpjm1
359            DO ii = 2, jpim1
360               fmask(ii,ij,ik) = fmask(ii,ij,ik) * bdytmask(ii,ij  ) * bdytmask(ii+1,ij  )   &
361                  &                              * bdytmask(ii,ij+1) * bdytmask(ii+1,ij+1)
362            END DO     
363         END DO
364      END DO
365
366      tmask_i (:,:) = tmask(:,:,1) * tmask_i(:,:)             
367      bdytmask(:,:) = tmask(:,:,1)
368
369      ! bdy masks and bmask are now set to zero on boundary points:
370      igrd = 1       ! In the free surface case, bmask is at T-points
371      DO ib = 1, nblenrim(igrd)     
372        bmask(nbi(ib,igrd), nbj(ib,igrd)) = 0.e0
373      END DO
374      !
375      igrd = 1
376      DO ib = 1, nblenrim(igrd)     
377        bdytmask(nbi(ib,igrd), nbj(ib,igrd)) = 0.e0
378      END DO
379      !
380      igrd = 2
381      DO ib = 1, nblenrim(igrd)
382        bdyumask(nbi(ib,igrd), nbj(ib,igrd)) = 0.e0
383      END DO
384      !
385      igrd = 3
386      DO ib = 1, nblenrim(igrd)
387        bdyvmask(nbi(ib,igrd), nbj(ib,igrd)) = 0.e0
388      END DO
389
390      ! Lateral boundary conditions
391      CALL lbc_lnk( fmask        , 'F', 1. )
392      CALL lbc_lnk( bdytmask(:,:), 'T', 1. )
393      CALL lbc_lnk( bdyumask(:,:), 'U', 1. )
394      CALL lbc_lnk( bdyvmask(:,:), 'V', 1. )
395
396      IF( ln_bdy_vol .OR. ln_bdy_dyn_fla ) THEN      ! Indices and directions of rim velocity components
397         !
398         !flagu = -1 : u component is normal to the dynamical boundary but its direction is outward
399         !flagu =  0 : u is tangential
400         !flagu =  1 : u is normal to the boundary and is direction is inward
401         icount = 0 
402         flagu(:) = 0.e0
403 
404         igrd = 2      ! u-component
405         DO ib = 1, nblenrim(igrd) 
406            zefl=bdytmask(nbi(ib,igrd)  , nbj(ib,igrd))
407            zwfl=bdytmask(nbi(ib,igrd)+1, nbj(ib,igrd))
408            IF( zefl + zwfl ==2 ) THEN
409               icount = icount +1
410            ELSE
411               flagu(ib)=-zefl+zwfl
412            ENDIF
413         END DO
414
415         !flagv = -1 : u component is normal to the dynamical boundary but its direction is outward
416         !flagv =  0 : u is tangential
417         !flagv =  1 : u is normal to the boundary and is direction is inward
418         flagv(:) = 0.e0
419
420         igrd = 3      ! v-component
421         DO ib = 1, nblenrim(igrd) 
422            znfl = bdytmask(nbi(ib,igrd), nbj(ib,igrd))
423            zsfl = bdytmask(nbi(ib,igrd), nbj(ib,igrd)+1)
424            IF( znfl + zsfl ==2 ) THEN
425               icount = icount + 1
426            ELSE
427               flagv(ib) = -znfl + zsfl
428            END IF
429         END DO
430 
431         IF( icount /= 0 ) THEN
432            IF(lwp) WRITE(numout,*)
433            IF(lwp) WRITE(numout,*) ' E R R O R : Some data velocity points,',   &
434               ' are not boundary points. Check nbi, nbj, indices.'
435            IF(lwp) WRITE(numout,*) ' ========== '
436            IF(lwp) WRITE(numout,*)
437            nstop = nstop + 1
438         ENDIF
439   
440      ENDIF
441
442      ! Compute total lateral surface for volume correction:
443      ! ----------------------------------------------------
444 
445      bdysurftot = 0.e0 
446      IF( ln_bdy_vol ) THEN 
447         igrd = 2      ! Lateral surface at U-points
448         DO ib = 1, nblenrim(igrd)
449            bdysurftot = bdysurftot + hu     (nbi(ib,igrd)  ,nbj(ib,igrd))                      &
450               &                    * e2u    (nbi(ib,igrd)  ,nbj(ib,igrd)) * ABS( flagu(ib) )   &
451               &                    * tmask_i(nbi(ib,igrd)  ,nbj(ib,igrd))                      &
452               &                    * tmask_i(nbi(ib,igrd)+1,nbj(ib,igrd))                   
453         END DO
454
455         igrd=3 ! Add lateral surface at V-points
456         DO ib = 1, nblenrim(igrd)
457            bdysurftot = bdysurftot + hv     (nbi(ib,igrd),nbj(ib,igrd)  )                      &
458               &                    * e1v    (nbi(ib,igrd),nbj(ib,igrd)  ) * ABS( flagv(ib) )   &
459               &                    * tmask_i(nbi(ib,igrd),nbj(ib,igrd)  )                      &
460               &                    * tmask_i(nbi(ib,igrd),nbj(ib,igrd)+1)
461         END DO
462
463         IF( lk_mpp )   CALL mpp_sum( bdysurftot )      ! sum over the global domain
464      END IF   
465
466      ! Initialise bdy data arrays
467      ! --------------------------
468      tbdy(:,:) = 0.e0
469      sbdy(:,:) = 0.e0
470      ubdy(:,:) = 0.e0
471      vbdy(:,:) = 0.e0
472      sshbdy(:) = 0.e0
473      ubtbdy(:) = 0.e0
474      vbtbdy(:) = 0.e0
475
476      ! Read in tidal constituents and adjust for model start time
477      ! ----------------------------------------------------------
478      IF( ln_bdy_tides )   CALL tide_data
479      !
480   END SUBROUTINE bdy_init
481
482#else
483   !!---------------------------------------------------------------------------------
484   !!   Dummy module                                   NO unstructured open boundaries
485   !!---------------------------------------------------------------------------------
486CONTAINS
487   SUBROUTINE bdy_init      ! Dummy routine
488   END SUBROUTINE bdy_init
489#endif
490
491   !!=================================================================================
492END MODULE bdyini
Note: See TracBrowser for help on using the repository browser.