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.
zdfbfr.F90 in trunk/NEMOGCM/NEMO/OPA_SRC/ZDF – NEMO

source: trunk/NEMOGCM/NEMO/OPA_SRC/ZDF/zdfbfr.F90 @ 7698

Last change on this file since 7698 was 7698, checked in by mocavero, 7 years ago

update trunk with OpenMP parallelization

  • Property svn:keywords set to Id
File size: 27.2 KB
Line 
1MODULE zdfbfr
2   !!======================================================================
3   !!                       ***  MODULE  zdfbfr  ***
4   !! Ocean physics: Bottom friction
5   !!======================================================================
6   !! History :  OPA  ! 1997-06  (G. Madec, A.-M. Treguier)  Original code
7   !!   NEMO     1.0  ! 2002-06  (G. Madec)  F90: Free form and module
8   !!            3.2  ! 2009-09  (A.C.Coward)  Correction to include barotropic contribution
9   !!            3.3  ! 2010-10  (C. Ethe, G. Madec) reorganisation of initialisation phase
10   !!            3.4  ! 2011-11  (H. Liu) implementation of semi-implicit bottom friction option
11   !!                 ! 2012-06  (H. Liu) implementation of Log Layer bottom friction option
12   !!----------------------------------------------------------------------
13
14   !!----------------------------------------------------------------------
15   !!   zdf_bfr      : update bottom friction coefficient (non-linear bottom friction only)
16   !!   zdf_bfr_init : read in namelist and control the bottom friction parameters.
17   !!----------------------------------------------------------------------
18   USE oce             ! ocean dynamics and tracers variables
19   USE dom_oce         ! ocean space and time domain variables
20   USE zdf_oce         ! ocean vertical physics variables
21   USE in_out_manager  ! I/O manager
22   USE lbclnk          ! ocean lateral boundary conditions (or mpp link)
23   USE lib_mpp         ! distributed memory computing
24   USE prtctl          ! Print control
25   USE timing          ! Timing
26   USE wrk_nemo        ! Memory Allocation
27   USE phycst, ONLY: vkarmn
28
29   IMPLICIT NONE
30   PRIVATE
31
32   PUBLIC   zdf_bfr         ! called by step.F90
33   PUBLIC   zdf_bfr_init    ! called by nemogcm.F90
34
35   !                                 !!* Namelist nambfr: bottom friction namelist *
36   INTEGER , PUBLIC ::   nn_bfr       ! = 0/1/2/3 type of bottom friction  (PUBLIC for TAM)
37   REAL(wp), PUBLIC ::   rn_bfri1     ! bottom drag coefficient (linear case)  (PUBLIC for TAM)
38   REAL(wp), PUBLIC ::   rn_bfri2     ! bottom drag coefficient (non linear case) (PUBLIC for TAM)
39   REAL(wp), PUBLIC ::   rn_bfri2_max ! Maximum bottom drag coefficient (non linear case and ln_loglayer=T) (PUBLIC for TAM)
40   REAL(wp), PUBLIC ::   rn_bfeb2     ! background bottom turbulent kinetic energy  [m2/s2] (PUBLIC for TAM)
41   REAL(wp), PUBLIC ::   rn_bfrien    ! local factor to enhance coefficient bfri (PUBLIC for TAM)
42   LOGICAL , PUBLIC ::   ln_bfr2d     ! logical switch for 2D enhancement (PUBLIC for TAM)
43   REAL(wp), PUBLIC ::   rn_tfri1     ! top drag coefficient (linear case)  (PUBLIC for TAM)
44   REAL(wp), PUBLIC ::   rn_tfri2     ! top drag coefficient (non linear case) (PUBLIC for TAM)
45   REAL(wp), PUBLIC ::   rn_tfri2_max ! Maximum top drag coefficient (non linear case and ln_loglayer=T) (PUBLIC for TAM)
46   REAL(wp), PUBLIC ::   rn_tfeb2     ! background top turbulent kinetic energy  [m2/s2] (PUBLIC for TAM)
47   REAL(wp), PUBLIC ::   rn_tfrien    ! local factor to enhance coefficient tfri (PUBLIC for TAM)
48   LOGICAL , PUBLIC ::   ln_tfr2d     ! logical switch for 2D enhancement (PUBLIC for TAM)
49
50   LOGICAL , PUBLIC ::   ln_loglayer  ! switch for log layer bfr coeff. (PUBLIC for TAM)
51   REAL(wp), PUBLIC ::   rn_bfrz0     ! bottom roughness for loglayer bfr coeff (PUBLIC for TAM)
52   REAL(wp), PUBLIC ::   rn_tfrz0     ! bottom roughness for loglayer bfr coeff (PUBLIC for TAM)
53   LOGICAL , PUBLIC ::   ln_bfrimp    ! logical switch for implicit bottom friction
54   REAL(wp), ALLOCATABLE, SAVE, DIMENSION(:,:), PUBLIC ::  bfrcoef2d, tfrcoef2d   ! 2D bottom/top drag coefficient (PUBLIC for TAM)
55
56   !! * Substitutions
57#  include "vectopt_loop_substitute.h90"
58   !!----------------------------------------------------------------------
59   !! NEMO/OPA 4.0 , NEMO Consortium (2011)
60   !! $Id$
61   !! Software governed by the CeCILL licence     (NEMOGCM/NEMO_CeCILL.txt)
62   !!----------------------------------------------------------------------
63CONTAINS
64
65   INTEGER FUNCTION zdf_bfr_alloc()
66      !!----------------------------------------------------------------------
67      !!                ***  FUNCTION zdf_bfr_alloc  ***
68      !!----------------------------------------------------------------------
69      ALLOCATE( bfrcoef2d(jpi,jpj), tfrcoef2d(jpi,jpj), STAT=zdf_bfr_alloc )
70      !
71      IF( lk_mpp             )   CALL mpp_sum ( zdf_bfr_alloc )
72      IF( zdf_bfr_alloc /= 0 )   CALL ctl_warn('zdf_bfr_alloc: failed to allocate arrays.')
73   END FUNCTION zdf_bfr_alloc
74
75
76   SUBROUTINE zdf_bfr( kt )
77      !!----------------------------------------------------------------------
78      !!                   ***  ROUTINE zdf_bfr  ***
79      !!
80      !! ** Purpose :   compute the bottom friction coefficient.
81      !!
82      !! ** Method  :   Calculate and store part of the momentum trend due
83      !!              to bottom friction following the chosen friction type
84      !!              (free-slip, linear, or quadratic). The component
85      !!              calculated here is multiplied by the bottom velocity in
86      !!              dyn_bfr to provide the trend term.
87      !!                The coefficients are updated at each time step only
88      !!              in the quadratic case.
89      !!
90      !! ** Action  :   bfrua , bfrva   bottom friction coefficients
91      !!----------------------------------------------------------------------
92      INTEGER, INTENT( in ) ::   kt   ! ocean time-step index
93      !!
94      INTEGER  ::   ji, jj                       ! dummy loop indices
95      INTEGER  ::   ikbt, ikbu, ikbv             ! local integers
96      REAL(wp) ::   zvu, zuv, zecu, zecv, ztmp   ! temporary scalars
97      REAL(wp), POINTER, DIMENSION(:,:) ::  zbfrt, ztfrt
98      !!----------------------------------------------------------------------
99      !
100      IF( nn_timing == 1 )  CALL timing_start('zdf_bfr')
101      !
102      IF( nn_bfr == 2 ) THEN                 ! quadratic bottom friction only
103         !
104         CALL wrk_alloc( jpi, jpj, zbfrt, ztfrt )
105
106         IF ( ln_loglayer.AND. .NOT.ln_linssh ) THEN ! "log layer" bottom friction coefficient
107
108!$OMP PARALLEL DO schedule(static) private(jj,ji,ikbt,ztmp)
109            DO jj = 1, jpj
110               DO ji = 1, jpi
111                  ikbt = mbkt(ji,jj)
112!! JC: possible WAD implementation should modify line below if layers vanish
113                  ztmp = tmask(ji,jj,ikbt) * ( vkarmn / LOG( 0.5_wp * e3t_n(ji,jj,ikbt) / rn_bfrz0 ))**2._wp
114                  zbfrt(ji,jj) = MAX(bfrcoef2d(ji,jj), ztmp)
115                  zbfrt(ji,jj) = MIN(zbfrt(ji,jj), rn_bfri2_max)
116               END DO
117            END DO
118! (ISF)
119            IF ( ln_isfcav ) THEN
120!$OMP PARALLEL DO schedule(static) private(jj,ji,ikbt,ztmp)
121               DO jj = 1, jpj
122                  DO ji = 1, jpi
123                     ikbt = mikt(ji,jj)
124! JC: possible WAD implementation should modify line below if layers vanish
125                     ztmp = (1.-tmask(ji,jj,1)) * ( vkarmn / LOG( 0.5_wp * e3t_n(ji,jj,ikbt) / rn_bfrz0 ))**2._wp
126                     ztfrt(ji,jj) = MAX(tfrcoef2d(ji,jj), ztmp)
127                     ztfrt(ji,jj) = MIN(ztfrt(ji,jj), rn_tfri2_max)
128                  END DO
129               END DO
130            END IF
131            !   
132         ELSE
133!$OMP PARALLEL DO schedule(static) private(jj,ji)
134            DO jj = 1, jpj
135               DO ji = 1, jpi
136                  zbfrt(ji,jj) = bfrcoef2d(ji,jj)
137                  ztfrt(ji,jj) = tfrcoef2d(ji,jj)
138               END DO
139            END DO
140         ENDIF
141
142!$OMP PARALLEL DO schedule(static) private(jj,ji,ikbu,ikbv,zvu,zuv,zecu,zecv)
143         DO jj = 2, jpjm1
144            DO ji = 2, jpim1
145               ikbu = mbku(ji,jj)         ! ocean bottom level at u- and v-points
146               ikbv = mbkv(ji,jj)         ! (deepest ocean u- and v-points)
147               !
148               zvu  = 0.25 * (  vn(ji,jj  ,ikbu) + vn(ji+1,jj  ,ikbu)     &
149                  &           + vn(ji,jj-1,ikbu) + vn(ji+1,jj-1,ikbu)  )
150               zuv  = 0.25 * (  un(ji,jj  ,ikbv) + un(ji-1,jj  ,ikbv)     &
151                  &           + un(ji,jj+1,ikbv) + un(ji-1,jj+1,ikbv)  )
152               !
153               zecu = SQRT(  un(ji,jj,ikbu) * un(ji,jj,ikbu) + zvu*zvu + rn_bfeb2  )
154               zecv = SQRT(  vn(ji,jj,ikbv) * vn(ji,jj,ikbv) + zuv*zuv + rn_bfeb2  )
155               !
156               bfrua(ji,jj) = - 0.5_wp * ( zbfrt(ji,jj) + zbfrt(ji+1,jj  ) ) * zecu
157               bfrva(ji,jj) = - 0.5_wp * ( zbfrt(ji,jj) + zbfrt(ji  ,jj+1) ) * zecv
158               !
159               ! in case of 2 cell water column, we assume each cell feels the top and bottom friction
160               IF ( ln_isfcav ) THEN
161                  IF ( miku(ji,jj) + 1  >=  mbku(ji,jj) ) THEN
162                     bfrua(ji,jj) = - 0.5_wp * ( ( zbfrt(ji,jj) + zbfrt(ji+1,jj  ) )   &
163                                  &            + ( ztfrt(ji,jj) + ztfrt(ji+1,jj  ) ) ) &
164                                  &          * zecu * (1._wp - umask(ji,jj,1))
165                  ENDIF
166                  IF( mikv(ji,jj) + 1  >=  mbkv(ji,jj) ) THEN
167                     bfrva(ji,jj) = - 0.5_wp * ( ( zbfrt(ji,jj) + zbfrt(ji  ,jj+1) )   &
168                                  &            + ( ztfrt(ji,jj) + ztfrt(ji  ,jj+1) ) ) &
169                                  &          * zecv * (1._wp - vmask(ji,jj,1))
170                  ENDIF
171               ENDIF
172            END DO
173         END DO
174         CALL lbc_lnk( bfrua, 'U', 1. )   ;   CALL lbc_lnk( bfrva, 'V', 1. )      ! Lateral boundary condition
175
176         IF( ln_isfcav ) THEN
177!$OMP PARALLEL DO schedule(static) private(jj,ji,ikbu,ikbv,zvu,zuv,zecu,zecv)
178            DO jj = 2, jpjm1
179               DO ji = 2, jpim1
180                  ! (ISF) ========================================================================
181                  ikbu = miku(ji,jj)         ! ocean top level at u- and v-points
182                  ikbv = mikv(ji,jj)         ! (1st wet ocean u- and v-points)
183                  !
184                  zvu  = 0.25 * (  vn(ji,jj  ,ikbu) + vn(ji+1,jj  ,ikbu)     &
185                     &           + vn(ji,jj-1,ikbu) + vn(ji+1,jj-1,ikbu)  )
186                  zuv  = 0.25 * (  un(ji,jj  ,ikbv) + un(ji-1,jj  ,ikbv)     &
187                     &           + un(ji,jj+1,ikbv) + un(ji-1,jj+1,ikbv)  )
188              !
189                  zecu = SQRT(  un(ji,jj,ikbu) * un(ji,jj,ikbu) + zvu*zvu + rn_tfeb2 )
190                  zecv = SQRT(  vn(ji,jj,ikbv) * vn(ji,jj,ikbv) + zuv*zuv + rn_tfeb2 )
191              !
192                  tfrua(ji,jj) = - 0.5_wp * ( ztfrt(ji,jj) + ztfrt(ji+1,jj  ) ) * zecu * (1._wp - umask(ji,jj,1))
193                  tfrva(ji,jj) = - 0.5_wp * ( ztfrt(ji,jj) + ztfrt(ji  ,jj+1) ) * zecv * (1._wp - vmask(ji,jj,1))
194              ! (ISF) END ====================================================================
195              ! in case of 2 cell water column, we assume each cell feels the top and bottom friction
196                  IF ( miku(ji,jj) + 1 .GE. mbku(ji,jj) ) THEN
197                     tfrua(ji,jj) = - 0.5_wp * ( ( ztfrt(ji,jj) + ztfrt(ji+1,jj  ) )   &
198                                  &            + ( zbfrt(ji,jj) + zbfrt(ji+1,jj  ) ) ) &
199                                  &          * zecu * (1._wp - umask(ji,jj,1))
200                  END IF
201                  IF ( mikv(ji,jj) + 1 .GE. mbkv(ji,jj) ) THEN
202                     tfrva(ji,jj) = - 0.5_wp * ( ( ztfrt(ji,jj) + ztfrt(ji  ,jj+1) )   &
203                                  &            + ( zbfrt(ji,jj) + zbfrt(ji  ,jj+1) ) ) &
204                                  &          * zecv * (1._wp - vmask(ji,jj,1))
205                  END IF
206               END DO
207            END DO
208            CALL lbc_lnk( tfrua, 'U', 1. )   ;   CALL lbc_lnk( tfrva, 'V', 1. )      ! Lateral boundary condition
209         END IF
210         !
211         !
212         IF(ln_ctl)   CALL prt_ctl( tab2d_1=bfrua, clinfo1=' bfr  - u: ', mask1=umask,        &
213            &                       tab2d_2=bfrva, clinfo2=       ' v: ', mask2=vmask,ovlap=1 )
214         CALL wrk_dealloc( jpi,jpj,zbfrt, ztfrt )
215      ENDIF
216      !
217      IF( nn_timing == 1 )  CALL timing_stop('zdf_bfr')
218      !
219   END SUBROUTINE zdf_bfr
220
221
222   SUBROUTINE zdf_bfr_init
223      !!----------------------------------------------------------------------
224      !!                  ***  ROUTINE zdf_bfr_init  ***
225      !!
226      !! ** Purpose :   Initialization of the bottom friction
227      !!
228      !! ** Method  :   Read the nambfr namelist and check their consistency
229      !!                called at the first timestep (nit000)
230      !!----------------------------------------------------------------------
231      USE iom   ! I/O module for ehanced bottom friction file
232      !!
233      INTEGER   ::   inum         ! logical unit for enhanced bottom friction file
234      INTEGER   ::   ji, jj       ! dummy loop indexes
235      INTEGER   ::   ikbt, ikbu, ikbv   ! temporary integers
236      INTEGER   ::   ictu, ictv         !    -          -
237      INTEGER   ::   ios
238      REAL(wp)  ::   zminbfr, zmaxbfr   ! temporary scalars
239      REAL(wp)  ::   zmintfr, zmaxtfr   ! temporary scalars
240      REAL(wp)  ::   ztmp, zfru, zfrv   !    -         -
241      !!
242      NAMELIST/nambfr/ nn_bfr, rn_bfri1, rn_bfri2, rn_bfri2_max, rn_bfeb2, rn_bfrz0, ln_bfr2d, &
243                    &          rn_tfri1, rn_tfri2, rn_tfri2_max, rn_tfeb2, rn_tfrz0, ln_tfr2d, &
244                    &  rn_bfrien, rn_tfrien, ln_bfrimp, ln_loglayer
245      !!----------------------------------------------------------------------
246      !
247      IF( nn_timing == 1 )  CALL timing_start('zdf_bfr_init')
248      !
249      !                              !* Allocate zdfbfr arrays
250      IF( zdf_bfr_alloc() /= 0 )   CALL ctl_stop( 'STOP', 'zdf_bfr_init : unable to allocate arrays' )
251      !
252      !                              !* Parameter control and print
253      !
254      REWIND( numnam_ref )              ! Namelist nambfr in reference namelist : Bottom momentum boundary condition
255      READ  ( numnam_ref, nambfr, IOSTAT = ios, ERR = 901)
256901   IF( ios /= 0 ) CALL ctl_nam ( ios , 'nambfr in reference namelist', lwp )
257
258      REWIND( numnam_cfg )              ! Namelist nambfr in configuration namelist : Bottom momentum boundary condition
259      READ  ( numnam_cfg, nambfr, IOSTAT = ios, ERR = 902 )
260902   IF( ios /= 0 ) CALL ctl_nam ( ios , 'nambfr in configuration namelist', lwp )
261      IF(lwm) WRITE ( numond, nambfr )
262      IF(lwp) WRITE(numout,*)
263      IF(lwp) WRITE(numout,*) 'zdf_bfr_init : momentum bottom friction'
264      IF(lwp) WRITE(numout,*) '~~~~~~~~~~~~'
265      IF(lwp) WRITE(numout,*) '   Namelist nam_bfr : set bottom friction parameters'
266      !
267      SELECT CASE (nn_bfr)
268      !
269      CASE( 0 )
270         IF(lwp) WRITE(numout,*) '      free-slip '
271!$OMP PARALLEL DO schedule(static) private(jj,ji)
272            DO jj = 1, jpj
273               DO ji = 1, jpi
274                  bfrua(ji,jj) = 0.e0
275                  bfrva(ji,jj) = 0.e0
276                  tfrua(ji,jj) = 0.e0
277                  tfrva(ji,jj) = 0.e0
278               END DO
279            END DO
280         !
281      CASE( 1 )
282         IF(lwp) WRITE(numout,*) '      linear botton friction'
283         IF(lwp) WRITE(numout,*) '      bottom friction coef.   rn_bfri1  = ', rn_bfri1
284         IF( ln_bfr2d ) THEN
285            IF(lwp) WRITE(numout,*) '      read coef. enhancement distribution from file   ln_bfr2d  = ', ln_bfr2d
286            IF(lwp) WRITE(numout,*) '      coef rn_bfri2 enhancement factor                rn_bfrien  = ',rn_bfrien
287         ENDIF
288         IF ( ln_isfcav ) THEN
289            IF(lwp) WRITE(numout,*) '      top    friction coef.   rn_bfri1  = ', rn_tfri1
290            IF( ln_tfr2d ) THEN
291               IF(lwp) WRITE(numout,*) '      read coef. enhancement distribution from file   ln_tfr2d  = ', ln_tfr2d
292               IF(lwp) WRITE(numout,*) '      coef rn_tfri2 enhancement factor                rn_tfrien  = ',rn_tfrien
293            ENDIF
294         END IF
295         !
296         IF(ln_bfr2d) THEN
297            ! bfr_coef is a coefficient in [0,1] giving the mask where to apply the bfr enhancement
298            CALL iom_open('bfr_coef.nc',inum)
299            CALL iom_get (inum, jpdom_data, 'bfr_coef',bfrcoef2d,1) ! bfrcoef2d is used as tmp array
300            CALL iom_close(inum)
301!$OMP PARALLEL DO schedule(static) private(jj,ji)
302            DO jj = 1, jpj
303               DO ji = 1, jpi
304                  bfrcoef2d(ji,jj) = rn_bfri1 * ( 1 + rn_bfrien * bfrcoef2d(ji,jj) )
305               END DO
306            END DO
307         ELSE
308!$OMP PARALLEL DO schedule(static) private(jj,ji)
309            DO jj = 1, jpj
310               DO ji = 1, jpi
311                  bfrcoef2d(ji,jj) = rn_bfri1  ! initialize bfrcoef2d to the namelist variable
312               END DO
313            END DO
314         ENDIF
315         !
316!$OMP PARALLEL DO schedule(static) private(jj,ji)
317            DO jj = 1, jpj
318               DO ji = 1, jpi
319                  bfrua(ji,jj) = - bfrcoef2d(ji,jj)
320                  bfrva(ji,jj) = - bfrcoef2d(ji,jj)
321               END DO
322            END DO
323         !
324         IF ( ln_isfcav ) THEN
325            IF(ln_tfr2d) THEN
326               ! tfr_coef is a coefficient in [0,1] giving the mask where to apply the bfr enhancement
327               CALL iom_open('tfr_coef.nc',inum)
328               CALL iom_get (inum, jpdom_data, 'tfr_coef',tfrcoef2d,1) ! tfrcoef2d is used as tmp array
329               CALL iom_close(inum)
330!$OMP PARALLEL DO schedule(static) private(jj,ji)
331               DO jj = 1, jpj
332                  DO ji = 1, jpi
333                     tfrcoef2d(ji,jj) = rn_tfri1 * ( 1 + rn_tfrien * tfrcoef2d(ji,jj) )
334                  END DO
335               END DO
336            ELSE
337!$OMP PARALLEL DO schedule(static) private(jj,ji)
338               DO jj = 1, jpj
339                  DO ji = 1, jpi
340                     tfrcoef2d(ji,jj) = rn_tfri1  ! initialize tfrcoef2d to the namelist variable
341                  END DO
342               END DO
343            ENDIF
344            !
345!$OMP PARALLEL DO schedule(static) private(jj,ji)
346            DO jj = 1, jpj
347               DO ji = 1, jpi
348                  tfrua(ji,jj) = - tfrcoef2d(ji,jj)
349                  tfrva(ji,jj) = - tfrcoef2d(ji,jj)
350               END DO
351            END DO
352         END IF
353         !
354      CASE( 2 )
355         IF(lwp) WRITE(numout,*) '      quadratic bottom friction'
356         IF(lwp) WRITE(numout,*) '      friction coef.   rn_bfri2  = ', rn_bfri2
357         IF(lwp) WRITE(numout,*) '      Max. coef. (log case)   rn_bfri2_max  = ', rn_bfri2_max
358         IF(lwp) WRITE(numout,*) '      background tke   rn_bfeb2  = ', rn_bfeb2
359         IF(lwp) WRITE(numout,*) '      log formulation   ln_bfr2d = ', ln_loglayer
360         IF(lwp) WRITE(numout,*) '      bottom roughness  rn_bfrz0 [m] = ', rn_bfrz0
361         IF( rn_bfrz0 <= 0._wp ) THEN
362            WRITE(ctmp1,*) '      bottom roughness must be strictly positive'
363            CALL ctl_stop( ctmp1 )
364         ENDIF
365         IF( ln_bfr2d ) THEN
366            IF(lwp) WRITE(numout,*) '      read coef. enhancement distribution from file   ln_bfr2d  = ', ln_bfr2d
367            IF(lwp) WRITE(numout,*) '      coef rn_bfri2 enhancement factor                rn_bfrien  = ',rn_bfrien
368         ENDIF
369         IF ( ln_isfcav ) THEN
370            IF(lwp) WRITE(numout,*) '      quadratic top    friction'
371            IF(lwp) WRITE(numout,*) '      friction coef.    rn_tfri2     = ', rn_tfri2
372            IF(lwp) WRITE(numout,*) '      Max. coef. (log case)   rn_tfri2_max  = ', rn_tfri2_max
373            IF(lwp) WRITE(numout,*) '      background tke    rn_tfeb2     = ', rn_tfeb2
374            IF(lwp) WRITE(numout,*) '      log formulation   ln_tfr2d     = ', ln_loglayer
375            IF(lwp) WRITE(numout,*) '      top roughness     rn_tfrz0 [m] = ', rn_tfrz0
376            IF( rn_tfrz0 <= 0._wp ) THEN
377               WRITE(ctmp1,*) '      top roughness must be strictly positive'
378               CALL ctl_stop( ctmp1 )
379            ENDIF
380            IF( ln_tfr2d ) THEN
381               IF(lwp) WRITE(numout,*) '      read coef. enhancement distribution from file   ln_tfr2d  = ', ln_tfr2d
382               IF(lwp) WRITE(numout,*) '      coef rn_tfri2 enhancement factor                rn_tfrien  = ',rn_tfrien
383            ENDIF
384         END IF
385         !
386         IF(ln_bfr2d) THEN
387            ! bfr_coef is a coefficient in [0,1] giving the mask where to apply the bfr enhancement
388            CALL iom_open('bfr_coef.nc',inum)
389            CALL iom_get (inum, jpdom_data, 'bfr_coef',bfrcoef2d,1) ! bfrcoef2d is used as tmp array
390            CALL iom_close(inum)
391            !
392!$OMP PARALLEL DO schedule(static) private(jj,ji)
393            DO jj = 1, jpj
394               DO ji = 1, jpi
395                  bfrcoef2d(ji,jj) = rn_bfri2 * ( 1 + rn_bfrien * bfrcoef2d(ji,jj) )
396               END DO
397            END DO
398         ELSE
399!$OMP PARALLEL DO schedule(static) private(jj,ji)
400            DO jj = 1, jpj
401               DO ji = 1, jpi
402                  bfrcoef2d(ji,jj) = rn_bfri2  ! initialize bfrcoef2d to the namelist variable
403               END DO
404            END DO
405         ENDIF
406         
407         IF ( ln_isfcav ) THEN
408            IF(ln_tfr2d) THEN
409               ! tfr_coef is a coefficient in [0,1] giving the mask where to apply the bfr enhancement
410               CALL iom_open('tfr_coef.nc',inum)
411               CALL iom_get (inum, jpdom_data, 'tfr_coef',tfrcoef2d,1) ! tfrcoef2d is used as tmp array
412               CALL iom_close(inum)
413               !
414!$OMP PARALLEL DO schedule(static) private(jj,ji)
415               DO jj = 1, jpj
416                  DO ji = 1, jpi
417                     tfrcoef2d(ji,jj) = rn_tfri2 * ( 1 + rn_tfrien * tfrcoef2d(ji,jj) )
418                  END DO
419               END DO
420            ELSE
421!$OMP PARALLEL DO schedule(static) private(jj,ji)
422               DO jj = 1, jpj
423                  DO ji = 1, jpi
424                     tfrcoef2d(ji,jj) = rn_tfri2  ! initialize tfrcoef2d to the namelist variable
425                  END DO
426               END DO
427            ENDIF
428         END IF
429         !
430         IF( ln_loglayer.AND. ln_linssh ) THEN ! set "log layer" bottom friction once for all
431!$OMP PARALLEL DO schedule(static) private(jj,ji,ikbt,ztmp)
432            DO jj = 1, jpj
433               DO ji = 1, jpi
434                  ikbt = mbkt(ji,jj)
435                  ztmp = tmask(ji,jj,ikbt) * ( vkarmn / LOG( 0.5_wp * e3t_n(ji,jj,ikbt) / rn_bfrz0 ))**2._wp
436                  bfrcoef2d(ji,jj) = MAX(bfrcoef2d(ji,jj), ztmp)
437                  bfrcoef2d(ji,jj) = MIN(bfrcoef2d(ji,jj), rn_bfri2_max)
438               END DO
439            END DO
440            IF ( ln_isfcav ) THEN
441!$OMP PARALLEL DO schedule(static) private(jj,ji,ikbt,ztmp)
442               DO jj = 1, jpj
443                  DO ji = 1, jpi
444                     ikbt = mikt(ji,jj)
445                     ztmp = tmask(ji,jj,ikbt) * ( vkarmn / LOG( 0.5_wp * e3t_n(ji,jj,ikbt) / rn_tfrz0 ))**2._wp
446                     tfrcoef2d(ji,jj) = MAX(tfrcoef2d(ji,jj), ztmp)
447                     tfrcoef2d(ji,jj) = MIN(tfrcoef2d(ji,jj), rn_tfri2_max)
448                  END DO
449               END DO
450            END IF
451         ENDIF
452         !
453      CASE DEFAULT
454         IF(lwp) WRITE(ctmp1,*) '         bad flag value for nn_bfr = ', nn_bfr
455         CALL ctl_stop( ctmp1 )
456         !
457      END SELECT
458      !
459      IF(lwp) WRITE(numout,*) '      implicit bottom friction switch                ln_bfrimp  = ', ln_bfrimp
460      !
461      !                              ! Make sure ln_zdfexp=.false. when use implicit bfr
462      IF( ln_bfrimp .AND. ln_zdfexp ) THEN
463         IF(lwp) THEN
464            WRITE(numout,*)
465            WRITE(numout,*) 'Implicit bottom friction can only be used when ln_zdfexp=.false.'
466            WRITE(numout,*) '         but you set: ln_bfrimp=.true. and ln_zdfexp=.true.!!!!'
467            WRITE(ctmp1,*)  '         set either ln_zdfexp = .false or ln_bfrimp = .false.'
468            CALL ctl_stop( ctmp1 )
469         END IF
470      END IF
471      !
472      ! Basic stability check on bottom friction coefficient
473      !
474      ictu = 0               ! counter for stability criterion breaches at U-pts
475      ictv = 0               ! counter for stability criterion breaches at V-pts
476      zminbfr =  1.e10_wp    ! initialise tracker for minimum of bottom friction coefficient
477      zmaxbfr = -1.e10_wp    ! initialise tracker for maximum of bottom friction coefficient
478      zmintfr =  1.e10_wp    ! initialise tracker for minimum of bottom friction coefficient
479      zmaxtfr = -1.e10_wp    ! initialise tracker for maximum of bottom friction coefficient
480      !
481!$OMP PARALLEL DO schedule(static) private(jj,ji,ikbu,ikbv,zfru,zfrv,ictu,ictv,zminbfr,zmaxbfr,zmintfr,zmaxtfr)
482      DO jj = 2, jpjm1
483         DO ji = 2, jpim1
484             ikbu = mbku(ji,jj)       ! deepest ocean level at u- and v-points
485             ikbv = mbkv(ji,jj)
486             zfru = 0.5 * e3u_n(ji,jj,ikbu) / rdt
487             zfrv = 0.5 * e3v_n(ji,jj,ikbv) / rdt
488             IF( ABS( bfrcoef2d(ji,jj) ) > zfru ) THEN
489                IF( ln_ctl ) THEN
490                   WRITE(numout,*) 'BFR ', narea, nimpp+ji, njmpp+jj, ikbu
491                   WRITE(numout,*) 'BFR ', ABS( bfrcoef2d(ji,jj) ), zfru
492                ENDIF
493                ictu = ictu + 1
494             ENDIF
495             IF( ABS( bfrcoef2d(ji,jj) ) > zfrv ) THEN
496                 IF( ln_ctl ) THEN
497                     WRITE(numout,*) 'BFR ', narea, nimpp+ji, njmpp+jj, ikbv
498                     WRITE(numout,*) 'BFR ', bfrcoef2d(ji,jj), zfrv
499                 ENDIF
500                 ictv = ictv + 1
501             ENDIF
502             zminbfr = MIN(  zminbfr, MIN( zfru, ABS( bfrcoef2d(ji,jj) ) )  )
503             zmaxbfr = MAX(  zmaxbfr, MIN( zfrv, ABS( bfrcoef2d(ji,jj) ) )  )
504! (ISF)
505             IF ( ln_isfcav ) THEN
506                ikbu = miku(ji,jj)       ! 1st wet ocean level at u- and v-points
507                ikbv = mikv(ji,jj)
508                zfru = 0.5 * e3u_n(ji,jj,ikbu) / rdt
509                zfrv = 0.5 * e3v_n(ji,jj,ikbv) / rdt
510                IF( ABS( tfrcoef2d(ji,jj) ) > zfru ) THEN
511                   IF( ln_ctl ) THEN
512                      WRITE(numout,*) 'TFR ', narea, nimpp+ji, njmpp+jj, ikbu
513                      WRITE(numout,*) 'TFR ', ABS( tfrcoef2d(ji,jj) ), zfru
514                   ENDIF
515                   ictu = ictu + 1
516                ENDIF
517                IF( ABS( tfrcoef2d(ji,jj) ) > zfrv ) THEN
518                   IF( ln_ctl ) THEN
519                      WRITE(numout,*) 'TFR ', narea, nimpp+ji, njmpp+jj, ikbv
520                      WRITE(numout,*) 'TFR ', tfrcoef2d(ji,jj), zfrv
521                   ENDIF
522                   ictv = ictv + 1
523                ENDIF
524                zmintfr = MIN(  zmintfr, MIN( zfru, ABS( tfrcoef2d(ji,jj) ) )  )
525                zmaxtfr = MAX(  zmaxtfr, MIN( zfrv, ABS( tfrcoef2d(ji,jj) ) )  )
526             END IF
527! END ISF
528         END DO
529      END DO
530      IF( lk_mpp ) THEN
531         CALL mpp_sum( ictu )
532         CALL mpp_sum( ictv )
533         CALL mpp_min( zminbfr )
534         CALL mpp_max( zmaxbfr )
535         IF ( ln_isfcav) CALL mpp_min( zmintfr )
536         IF ( ln_isfcav) CALL mpp_max( zmaxtfr )
537      ENDIF
538      IF( .NOT.ln_bfrimp) THEN
539      IF( lwp .AND. ictu + ictv > 0 ) THEN
540         WRITE(numout,*) ' Bottom/Top friction stability check failed at ', ictu, ' U-points '
541         WRITE(numout,*) ' Bottom/Top friction stability check failed at ', ictv, ' V-points '
542         WRITE(numout,*) ' Bottom friction coefficient now ranges from: ', zminbfr, ' to ', zmaxbfr
543         IF ( ln_isfcav ) WRITE(numout,*) ' Top friction coefficient now ranges from: ', zmintfr, ' to ', zmaxtfr
544         WRITE(numout,*) ' Bottom/Top friction coefficient will be reduced where necessary'
545      ENDIF
546      ENDIF
547      !
548      IF( nn_timing == 1 )  CALL timing_stop('zdf_bfr_init')
549      !
550   END SUBROUTINE zdf_bfr_init
551
552   !!======================================================================
553END MODULE zdfbfr
Note: See TracBrowser for help on using the repository browser.