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.
dynzdf_imp.F90 in branches/2017/dev_r7881_HPC09_ZDF/NEMOGCM/NEMO/OPA_SRC/DYN – NEMO

source: branches/2017/dev_r7881_HPC09_ZDF/NEMOGCM/NEMO/OPA_SRC/DYN/dynzdf_imp.F90 @ 8143

Last change on this file since 8143 was 8143, checked in by gm, 7 years ago

#1880 (HPC-09) - step-7: top/bottom drag computed at T-points, zdfbfr.F90 replaced by zdfdrg.F90 + changes in namelist

  • Property svn:keywords set to Id
File size: 15.5 KB
Line 
1MODULE dynzdf_imp
2   !!======================================================================
3   !!                    ***  MODULE  dynzdf_imp  ***
4   !! Ocean dynamics:  vertical component(s) of the momentum mixing trend, implicit scheme
5   !!======================================================================
6   !! History :  OPA  !  1990-10  (B. Blanke)  Original code
7   !!            8.0  !  1997-05  (G. Madec)  vertical component of isopycnal
8   !!   NEMO     0.5  !  2002-08  (G. Madec)  F90: Free form and module
9   !!            3.3  !  2010-04  (M. Leclair, G. Madec)  Forcing averaged over 2 time steps
10   !!            3.4  !  2012-01  (H. Liu) Semi-implicit bottom friction
11   !!            4.0  !  2017-05  (G. Madec)  drag coef. defined at t-point (zdfdrg.F90)
12   !!----------------------------------------------------------------------
13
14   !!----------------------------------------------------------------------
15   !!   dyn_zdf_imp   : compute the vertical diffusion using a implicit time-stepping
16   !!                   together with the Leap-Frog time integration.
17   !!----------------------------------------------------------------------
18   USE oce            ! ocean dynamics and tracers
19   USE phycst         ! physical constants
20   USE dom_oce        ! ocean space and time domain
21   USE domvvl         ! variable volume
22   USE sbc_oce        ! surface boundary condition: ocean
23   USE dynadv   , ONLY: ln_dynadv_vec ! Momentum advection form
24   USE zdf_oce        ! ocean vertical physics
25   USE zdfdrg         ! vertical physics: top/bottom drag coef.
26   !
27   USE in_out_manager ! I/O manager
28   USE lib_mpp        ! MPP library
29   USE timing         ! Timing
30
31   IMPLICIT NONE
32   PRIVATE
33
34   PUBLIC   dyn_zdf_imp   ! called by step.F90
35
36   REAL(wp) ::  r_vvl     ! non-linear free surface indicator: =0 if ln_linssh=T, =1 otherwise
37
38   !! * Substitutions
39#  include "vectopt_loop_substitute.h90"
40   !!----------------------------------------------------------------------
41   !! NEMO/OPA 4.0 , NEMO Consortium (2017)
42   !! $Id$
43   !! Software governed by the CeCILL licence     (NEMOGCM/NEMO_CeCILL.txt)
44   !!----------------------------------------------------------------------
45CONTAINS
46
47   SUBROUTINE dyn_zdf_imp( kt, p2dt )
48      !!----------------------------------------------------------------------
49      !!                  ***  ROUTINE dyn_zdf_imp  ***
50      !!                   
51      !! ** Purpose :   Compute the trend due to the vert. momentum diffusion
52      !!              together with the Leap-Frog time stepping using an
53      !!              implicit scheme.
54      !!
55      !! ** Method  :  - Leap-Frog time stepping on all trends but the vertical mixing
56      !!         ua =         ub + 2*dt *       ua             vector form or linear free surf.
57      !!         ua = ( e3u_b*ub + 2*dt * e3u_n*ua ) / e3u_a   otherwise
58      !!               - update the after velocity with the implicit vertical mixing.
59      !!      This requires to solver the following system:
60      !!         ua = ua + 1/e3u_a dk+1[ avmu / e3uw_a dk[ua] ]
61      !!      with the following surface/top/bottom boundary condition:
62      !!      surface: wind stress input (averaged over kt-1/2 & kt+1/2)
63      !!      top & bottom : top stress (iceshelf-ocean) & bottom stress (cf zdfdrg.F90)
64      !!
65      !! ** Action :   (ua,va) after velocity
66      !!---------------------------------------------------------------------
67      INTEGER , INTENT(in) ::  kt     ! ocean time-step index
68      REAL(wp), INTENT(in) ::  p2dt   ! vertical profile of tracer time-step
69      !
70      INTEGER  ::   ji, jj, jk    ! dummy loop indices
71      INTEGER  ::   ikbu, ikbv    ! local integers
72      REAL(wp) ::   zzwi, ze3ua   ! local scalars
73      REAL(wp) ::   zzws, ze3va   !   -      -
74      REAL(wp), DIMENSION(jpi,jpj,jpk) ::  zwi, zwd, zws
75      !!----------------------------------------------------------------------
76      !
77      IF( nn_timing == 1 )  CALL timing_start('dyn_zdf_imp')
78      !
79      IF( kt == nit000 ) THEN
80         IF(lwp) WRITE(numout,*)
81         IF(lwp) WRITE(numout,*) 'dyn_zdf_imp : vertical momentum diffusion implicit operator'
82         IF(lwp) WRITE(numout,*) '~~~~~~~~~~~ '
83         !
84         If( ln_linssh ) THEN   ;    r_vvl = 0._wp    ! non-linear free surface indicator
85         ELSE                   ;    r_vvl = 1._wp
86         ENDIF
87      ENDIF
88      !
89      !              !==  Time step dynamics  ==!
90      !
91      IF( ln_dynadv_vec .OR. ln_linssh ) THEN      ! applied on velocity
92         DO jk = 1, jpkm1
93            ua(:,:,jk) = ( ub(:,:,jk) + p2dt * ua(:,:,jk) ) * umask(:,:,jk)
94            va(:,:,jk) = ( vb(:,:,jk) + p2dt * va(:,:,jk) ) * vmask(:,:,jk)
95         END DO
96      ELSE                                         ! applied on thickness weighted velocity
97         DO jk = 1, jpkm1
98            ua(:,:,jk) = (         e3u_b(:,:,jk) * ub(:,:,jk)  &
99               &          + p2dt * e3u_n(:,:,jk) * ua(:,:,jk)  ) / e3u_a(:,:,jk) * umask(:,:,jk)
100            va(:,:,jk) = (         e3v_b(:,:,jk) * vb(:,:,jk)  &
101               &          + p2dt * e3v_n(:,:,jk) * va(:,:,jk)  ) / e3v_a(:,:,jk) * vmask(:,:,jk)
102         END DO
103      ENDIF
104      !
105      !              !==  Apply semi-implicit bottom friction  ==!
106      !
107      ! Only needed for semi-implicit bottom friction setup. The explicit
108      ! bottom friction has been included in "u(v)a" which act as the R.H.S
109      ! column vector of the tri-diagonal matrix equation
110      !
111      IF( ln_drgimp ) THEN
112         DO jj = 2, jpjm1
113            DO ji = 2, jpim1
114               ikbu = mbku(ji,jj)       ! ocean bottom level at u- and v-points
115               ikbv = mbkv(ji,jj)       ! (deepest ocean u- and v-points)
116               avmu(ji,jj,ikbu+1) = -0.5*( rCdU_bot(ji+1,jj)+rCdU_bot(ji,jj) ) * e3uw_n(ji,jj,ikbu+1)
117               avmv(ji,jj,ikbv+1) = -0.5*( rCdU_bot(ji,jj+1)+rCdU_bot(ji,jj) ) * e3vw_n(ji,jj,ikbv+1)
118            END DO
119         END DO
120         IF ( ln_isfcav ) THEN
121            DO jj = 2, jpjm1
122               DO ji = 2, jpim1
123                  ikbu = miku(ji,jj)       ! ocean top level at u- and v-points
124                  ikbv = mikv(ji,jj)       ! (first wet ocean u- and v-points)
125                  ! top Cd is masked (=0 outside cavities) no need of test on mik>=2
126                  avmu(ji,jj,ikbu) = -0.5*( rCdU_top(ji+1,jj)+rCdU_top(ji,jj) ) * e3uw_n(ji,jj,ikbu)
127                  avmv(ji,jj,ikbv) = -0.5*( rCdU_top(ji+1,jj)+rCdU_top(ji,jj) ) * e3vw_n(ji,jj,ikbv)
128               END DO
129            END DO
130         END IF
131      ENDIF
132      !
133      ! With split-explicit free surface, barotropic stress is treated explicitly
134      ! Update velocities at the bottom.
135      ! J. Chanut: The bottom stress is computed considering after barotropic velocities, which does
136      !            not lead to the effective stress seen over the whole barotropic loop.
137      ! G. Madec : in linear free surface, e3u_a = e3u_n = e3u_0, so systematic use of e3u_a
138      IF( ln_drgimp .AND. ln_dynspg_ts ) THEN
139         DO jk = 1, jpkm1        ! remove barotropic velocities
140            ua(:,:,jk) = ( ua(:,:,jk) - ua_b(:,:) ) * umask(:,:,jk)
141            va(:,:,jk) = ( va(:,:,jk) - va_b(:,:) ) * vmask(:,:,jk)
142         END DO
143         DO jj = 2, jpjm1        ! Add bottom/top stress due to barotropic component only
144            DO ji = fs_2, fs_jpim1   ! vector opt.
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               ze3ua =  ( 1._wp - r_vvl ) * e3u_n(ji,jj,ikbu) + r_vvl * e3u_a(ji,jj,ikbu)
148               ze3va =  ( 1._wp - r_vvl ) * e3v_n(ji,jj,ikbv) + r_vvl * e3v_a(ji,jj,ikbv)
149               ua(ji,jj,ikbu) = ua(ji,jj,ikbu) + p2dt * 0.5*( rCdU_bot(ji+1,jj)+rCdU_bot(ji,jj) ) * ua_b(ji,jj) / ze3ua
150               va(ji,jj,ikbv) = va(ji,jj,ikbv) + p2dt * 0.5*( rCdU_bot(ji,jj+1)+rCdU_bot(ji,jj) ) * va_b(ji,jj) / ze3va
151            END DO
152         END DO
153         IF( ln_isfcav ) THEN    ! Ocean cavities (ISF)
154            DO jj = 2, jpjm1       
155               DO ji = fs_2, fs_jpim1   ! vector opt.
156                  ikbu = miku(ji,jj)         ! top ocean level at u- and v-points
157                  ikbv = mikv(ji,jj)         ! (first wet ocean u- and v-points)
158                  ze3ua =  ( 1._wp - r_vvl ) * e3u_n(ji,jj,ikbu) + r_vvl * e3u_a(ji,jj,ikbu)
159                  ze3va =  ( 1._wp - r_vvl ) * e3v_n(ji,jj,ikbv) + r_vvl * e3v_a(ji,jj,ikbv)
160                  ua(ji,jj,ikbu) = ua(ji,jj,ikbu) + p2dt * 0.5*( rCdU_top(ji+1,jj)+rCdU_top(ji,jj) ) * ua_b(ji,jj) / ze3ua
161                  va(ji,jj,ikbv) = va(ji,jj,ikbv) + p2dt * 0.5*( rCdU_top(ji+1,jj)+rCdU_top(ji,jj) ) * va_b(ji,jj) / ze3va
162               END DO
163            END DO
164         END IF
165      ENDIF
166      !
167      !              !==  Vertical diffusion on u  ==!
168      !
169      ! Matrix and second member construction
170      ! bottom boundary condition: both zwi and zws must be masked as avmu can take
171      ! non zero value at the ocean bottom depending on the bottom friction used.
172      !
173      DO jk = 1, jpkm1        ! Matrix
174         DO jj = 2, jpjm1 
175            DO ji = fs_2, fs_jpim1   ! vector opt.
176               ze3ua =  ( 1._wp - r_vvl ) * e3u_n(ji,jj,jk) + r_vvl * e3u_a(ji,jj,jk)   ! after scale factor at T-point
177               zzwi = - p2dt * avmu(ji,jj,jk  ) / ( ze3ua * e3uw_n(ji,jj,jk  ) )
178               zzws = - p2dt * avmu(ji,jj,jk+1) / ( ze3ua * e3uw_n(ji,jj,jk+1) )
179               zwi(ji,jj,jk) = zzwi * wumask(ji,jj,jk  )
180               zws(ji,jj,jk) = zzws * wumask(ji,jj,jk+1)
181               zwd(ji,jj,jk) = 1._wp - zzwi - zzws
182            END DO
183         END DO
184      END DO
185      DO jj = 2, jpjm1        ! Surface boundary conditions
186         DO ji = fs_2, fs_jpim1   ! vector opt.
187            zwi(ji,jj,1) = 0._wp
188            zwd(ji,jj,1) = 1._wp - zws(ji,jj,1)
189         END DO
190      END DO
191
192      ! Matrix inversion starting from the first level
193      !-----------------------------------------------------------------------
194      !   solve m.x = y  where m is a tri diagonal matrix ( jpk*jpk )
195      !
196      !        ( zwd1 zws1   0    0    0  )( zwx1 ) ( zwy1 )
197      !        ( zwi2 zwd2 zws2   0    0  )( zwx2 ) ( zwy2 )
198      !        (  0   zwi3 zwd3 zws3   0  )( zwx3 )=( zwy3 )
199      !        (        ...               )( ...  ) ( ...  )
200      !        (  0    0    0   zwik zwdk )( zwxk ) ( zwyk )
201      !
202      !   m is decomposed in the product of an upper and a lower triangular matrix
203      !   The 3 diagonal terms are in 2d arrays: zwd, zws, zwi
204      !   The solution (the after velocity) is in ua
205      !-----------------------------------------------------------------------
206      !
207      DO jk = 2, jpkm1        !==  First recurrence : Dk = Dk - Lk * Uk-1 / Dk-1   (increasing k)  ==
208         DO jj = 2, jpjm1   
209            DO ji = fs_2, fs_jpim1   ! vector opt.
210               zwd(ji,jj,jk) = zwd(ji,jj,jk) - zwi(ji,jj,jk) * zws(ji,jj,jk-1) / zwd(ji,jj,jk-1)
211            END DO
212         END DO
213      END DO
214      !
215      DO jj = 2, jpjm1        !==  second recurrence:    SOLk = RHSk - Lk / Dk-1  Lk-1  ==!
216         DO ji = fs_2, fs_jpim1   ! vector opt.
217            ze3ua =  ( 1._wp - r_vvl ) * e3u_n(ji,jj,1) + r_vvl * e3u_a(ji,jj,1) 
218            ua(ji,jj,1) = ua(ji,jj,1) + p2dt * 0.5_wp * ( utau_b(ji,jj) + utau(ji,jj) )   &
219               &                                      / ( ze3ua * rau0 ) * umask(ji,jj,1) 
220         END DO
221      END DO
222      DO jk = 2, jpkm1
223         DO jj = 2, jpjm1
224            DO ji = fs_2, fs_jpim1
225               ua(ji,jj,jk) = ua(ji,jj,jk) - zwi(ji,jj,jk) / zwd(ji,jj,jk-1) * ua(ji,jj,jk-1)
226            END DO
227         END DO
228      END DO
229      !
230      DO jj = 2, jpjm1        !==  thrid recurrence : SOLk = ( Lk - Uk * Ek+1 ) / Dk  ==!
231         DO ji = fs_2, fs_jpim1   ! vector opt.
232            ua(ji,jj,jpkm1) = ua(ji,jj,jpkm1) / zwd(ji,jj,jpkm1)
233         END DO
234      END DO
235      DO jk = jpk-2, 1, -1
236         DO jj = 2, jpjm1
237            DO ji = fs_2, fs_jpim1
238               ua(ji,jj,jk) = ( ua(ji,jj,jk) - zws(ji,jj,jk) * ua(ji,jj,jk+1) ) / zwd(ji,jj,jk)
239            END DO
240         END DO
241      END DO
242      !
243      !              !==  Vertical diffusion on v  ==!
244      !
245      ! Matrix and second member construction
246      ! bottom boundary condition: both zwi and zws must be masked as avmv can take
247      ! non zero value at the ocean bottom depending on the bottom friction used
248      !
249      DO jk = 1, jpkm1        ! Matrix
250         DO jj = 2, jpjm1   
251            DO ji = fs_2, fs_jpim1   ! vector opt.
252               ze3va =  ( 1._wp - r_vvl ) * e3v_n(ji,jj,jk) + r_vvl * e3v_a(ji,jj,jk)   ! after scale factor at T-point
253               zzwi = - p2dt * avmv (ji,jj,jk  ) / ( ze3va * e3vw_n(ji,jj,jk  ) )
254               zzws = - p2dt * avmv (ji,jj,jk+1) / ( ze3va * e3vw_n(ji,jj,jk+1) )
255               zwi(ji,jj,jk) = zzwi * wvmask(ji,jj,jk  )
256               zws(ji,jj,jk) = zzws * wvmask(ji,jj,jk+1)
257               zwd(ji,jj,jk) = 1._wp - zzwi - zzws
258            END DO
259         END DO
260      END DO
261      DO jj = 2, jpjm1        ! Surface boundary conditions
262         DO ji = fs_2, fs_jpim1   ! vector opt.
263            zwi(ji,jj,1) = 0._wp
264            zwd(ji,jj,1) = 1._wp - zws(ji,jj,1)
265         END DO
266      END DO
267
268      ! Matrix inversion
269      !-----------------------------------------------------------------------
270      !   solve m.x = y  where m is a tri diagonal matrix ( jpk*jpk )
271      !
272      !        ( zwd1 zws1   0    0    0  )( zwx1 ) ( zwy1 )
273      !        ( zwi2 zwd2 zws2   0    0  )( zwx2 ) ( zwy2 )
274      !        (  0   zwi3 zwd3 zws3   0  )( zwx3 )=( zwy3 )
275      !        (        ...               )( ...  ) ( ...  )
276      !        (  0    0    0   zwik zwdk )( zwxk ) ( zwyk )
277      !
278      !   m is decomposed in the product of an upper and lower triangular matrix
279      !   The 3 diagonal terms are in 2d arrays: zwd, zws, zwi
280      !   The solution (after velocity) is in 2d array va
281      !-----------------------------------------------------------------------
282      !
283      DO jk = 2, jpkm1        !==  First recurrence : Dk = Dk - Lk * Uk-1 / Dk-1   (increasing k)  ==
284         DO jj = 2, jpjm1   
285            DO ji = fs_2, fs_jpim1   ! vector opt.
286               zwd(ji,jj,jk) = zwd(ji,jj,jk) - zwi(ji,jj,jk) * zws(ji,jj,jk-1) / zwd(ji,jj,jk-1)
287            END DO
288         END DO
289      END DO
290      !
291      DO jj = 2, jpjm1        !==  second recurrence:    SOLk = RHSk - Lk / Dk-1  Lk-1  ==!
292         DO ji = fs_2, fs_jpim1   ! vector opt.         
293            ze3va =  ( 1._wp - r_vvl ) * e3v_n(ji,jj,1) + r_vvl * e3v_a(ji,jj,1) 
294            va(ji,jj,1) = va(ji,jj,1) + p2dt * 0.5_wp * ( vtau_b(ji,jj) + vtau(ji,jj) )   &
295               &                                      / ( ze3va * rau0 ) * vmask(ji,jj,1) 
296         END DO
297      END DO
298      DO jk = 2, jpkm1
299         DO jj = 2, jpjm1
300            DO ji = fs_2, fs_jpim1   ! vector opt.
301               va(ji,jj,jk) = va(ji,jj,jk) - zwi(ji,jj,jk) / zwd(ji,jj,jk-1) * va(ji,jj,jk-1)
302            END DO
303         END DO
304      END DO
305      !
306      DO jj = 2, jpjm1        !==  third recurrence : SOLk = ( Lk - Uk * SOLk+1 ) / Dk  ==!
307         DO ji = fs_2, fs_jpim1   ! vector opt.
308            va(ji,jj,jpkm1) = va(ji,jj,jpkm1) / zwd(ji,jj,jpkm1)
309         END DO
310      END DO
311      DO jk = jpk-2, 1, -1
312         DO jj = 2, jpjm1
313            DO ji = fs_2, fs_jpim1
314               va(ji,jj,jk) = ( va(ji,jj,jk) - zws(ji,jj,jk) * va(ji,jj,jk+1) ) / zwd(ji,jj,jk)
315            END DO
316         END DO
317      END DO
318      !
319      IF( nn_timing == 1 )   CALL timing_stop('dyn_zdf_imp')
320      !
321   END SUBROUTINE dyn_zdf_imp
322
323   !!==============================================================================
324END MODULE dynzdf_imp
Note: See TracBrowser for help on using the repository browser.