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.
dynspg_flt.F90 in branches/dev_004_VVL/NEMO/OPA_SRC/DYN – NEMO

source: branches/dev_004_VVL/NEMO/OPA_SRC/DYN/dynspg_flt.F90 @ 1390

Last change on this file since 1390 was 1390, checked in by rblod, 15 years ago

Cleaning of VVL, ticket #402:

  • dynnxt : correct indice bug
  • wzmod : add obc case
  • dynspg_flt : cosmetic change + computation speed-up
  • dynspg_exp : just update velocity with surface pressure trend
  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to Id
File size: 19.4 KB
Line 
1MODULE dynspg_flt
2   !!======================================================================
3   !!                   ***  MODULE  dynspg_flt  ***
4   !! Ocean dynamics:  surface pressure gradient trend
5   !!======================================================================
6   !! History    8.0  !  98-05  (G. Roullet)  free surface
7   !!                 !  98-10  (G. Madec, M. Imbard)  release 8.2
8   !!            8.5  !  02-08  (G. Madec)  F90: Free form and module
9   !!            " "  !  02-11  (C. Talandier, A-M Treguier) Open boundaries
10   !!            9.0  !  04-08  (C. Talandier) New trends organization
11   !!            " "  !  05-11  (V. Garnier) Surface pressure gradient organization
12   !!            " "  !  06-07  (S. Masson)  distributed restart using iom
13   !!            " "  !  05-01  (J.Chanut, A.Sellar) Calls to BDY routines.
14   !!----------------------------------------------------------------------
15#if defined key_dynspg_flt   ||   defined key_esopa 
16   !!----------------------------------------------------------------------
17   !!   'key_dynspg_flt'                              filtered free surface
18   !!----------------------------------------------------------------------
19   !!----------------------------------------------------------------------
20   !!   dyn_spg_flt  : update the momentum trend with the surface pressure
21   !!                  gradient in the filtered free surface case with
22   !!                  vector optimization
23   !!   flt_rst      : read/write the time-splitting restart fields in the ocean restart file
24   !!----------------------------------------------------------------------
25   USE oce             ! ocean dynamics and tracers
26   USE dom_oce         ! ocean space and time domain
27   USE zdf_oce         ! ocean vertical physics
28   USE sbc_oce         ! surface boundary condition: ocean
29   USE obc_oce         ! Lateral open boundary condition
30   USE sol_oce         ! ocean elliptic solver
31   USE phycst          ! physical constants
32   USE domvvl          ! variable volume
33   USE solver          ! solver initialization
34   USE solpcg          ! preconditionned conjugate gradient solver
35   USE solsor          ! Successive Over-relaxation solver
36   USE solfet          ! FETI solver
37   USE obcdyn          ! ocean open boundary condition (obc_dyn routines)
38   USE obcvol          ! ocean open boundary condition (obc_vol routines)
39   USE bdy_oce         ! Unstructured open boundaries condition
40   USE bdydyn          ! Unstructured open boundaries condition (bdy_dyn routine)
41   USE bdyvol          ! Unstructured open boundaries condition (bdy_vol routine)
42   USE cla_dynspg      ! cross land advection
43   USE in_out_manager  ! I/O manager
44   USE lib_mpp         ! distributed memory computing library
45   USE lbclnk          ! ocean lateral boundary conditions (or mpp link)
46   USE prtctl          ! Print control
47   USE solmat          ! matrix construction for elliptic solvers
48   USE agrif_opa_interp
49   USE iom
50   USE restart         ! only for lrst_oce
51
52   IMPLICIT NONE
53   PRIVATE
54
55   PUBLIC dyn_spg_flt  ! routine called by step.F90
56   PUBLIC flt_rst      ! routine called by istate.F90
57
58   !! * Substitutions
59#  include "domzgr_substitute.h90"
60#  include "vectopt_loop_substitute.h90"
61   !!----------------------------------------------------------------------
62   !!   OPA 9.0 , LOCEAN-IPSL (2005)
63   !! $Id$
64   !! Software governed by the CeCILL licence (modipsl/doc/NEMO_CeCILL.txt)
65   !!----------------------------------------------------------------------
66
67CONTAINS
68
69   SUBROUTINE dyn_spg_flt( kt, kindic )
70      !!----------------------------------------------------------------------
71      !!                  ***  routine dyn_spg_flt  ***
72      !!
73      !! ** Purpose :   Compute the now trend due to the surface pressure
74      !!      gradient in case of filtered free surface formulation  and add
75      !!      it to the general trend of momentum equation.
76      !!
77      !! ** Method  :   Filtered free surface formulation. The surface
78      !!      pressure gradient is given by:
79      !!         spgu = 1/rau0 d/dx(ps) =  1/e1u di( sshn + rnu btda )
80      !!         spgv = 1/rau0 d/dy(ps) =  1/e2v dj( sshn + rnu btda )
81      !!      where sshn is the free surface elevation and btda is the after
82      !!      of the free surface elevation
83      !!       -1- evaluate the surface presure trend (including the addi-
84      !!      tional force) in three steps:
85      !!        a- compute the right hand side of the elliptic equation:
86      !!            gcb = 1/(e1t e2t) [ di(e2u spgu) + dj(e1v spgv) ]
87      !!         where (spgu,spgv) are given by:
88      !!            spgu = vertical sum[ e3u (ub+ 2 rdt ua ) ]
89      !!                 - grav 2 rdt hu /e1u di[sshn + emp]
90      !!            spgv = vertical sum[ e3v (vb+ 2 rdt va) ]
91      !!                 - grav 2 rdt hv /e2v dj[sshn + emp]
92      !!         and define the first guess from previous computation :
93      !!            zbtd = btda
94      !!            btda = 2 zbtd - btdb
95      !!            btdb = zbtd
96      !!        b- compute the relative accuracy to be reached by the
97      !!         iterative solver
98      !!        c- apply the solver by a call to sol... routine
99      !!       -2- compute and add the free surface pressure gradient inclu-
100      !!      ding the additional force used to stabilize the equation.
101      !!
102      !! ** Action : - Update (ua,va) with the surf. pressure gradient trend
103      !!
104      !! References : Roullet and Madec 1999, JGR.
105      !!---------------------------------------------------------------------
106      !! * Modules used
107      USE oce    , ONLY :   zub   => ta,             &  ! ta used as workspace
108                            zvb   => sa                 ! sa   "          "
109
110      INTEGER, INTENT( in )  ::   kt         ! ocean time-step index
111      INTEGER, INTENT( out ) ::   kindic     ! solver convergence flag (<0 if not converge)
112      !!                                   
113      INTEGER  ::   ji, jj, jk                          ! dummy loop indices
114      REAL(wp) ::   z2dt, z2dtg, zraur, znugdt,      &  ! temporary scalars
115         &          znurau, zgcb, zbtd,              &  !   "          "
116         &          ztdgu, ztdgv                        !   "          "
117      !!----------------------------------------------------------------------
118      !
119      IF( kt == nit000 ) THEN
120         IF(lwp) WRITE(numout,*)
121         IF(lwp) WRITE(numout,*) 'dyn_spg_flt : surface pressure gradient trend'
122         IF(lwp) WRITE(numout,*) '~~~~~~~~~~~   (free surface constant volume case)'
123       
124         ! set to zero free surface specific arrays
125         spgu(:,:) = 0.e0                     ! surface pressure gradient (i-direction)
126         spgv(:,:) = 0.e0                     ! surface pressure gradient (j-direction)
127         CALL solver_init( nit000 )           ! Elliptic solver initialisation
128
129         ! read filtered free surface arrays in restart file
130         ! when using agrif, sshn, gcx have to be read in istate
131         IF (.NOT. lk_agrif) CALL flt_rst( nit000, 'READ' )       ! read or initialize the following fields:
132         !                                                        ! gcx, gcxb, sshb, sshn
133      ENDIF
134
135      ! Local constant initialization
136      z2dt = 2. * rdt                                       ! time step: leap-frog
137      IF( neuler == 0 .AND. kt == nit000 ) z2dt = rdt       ! time step: Euler if restart from rest
138      IF( neuler == 0 .AND. kt == nit000+1 ) CALL sol_mat(kt)
139      z2dtg  = grav * z2dt
140      zraur  = 1. / rauw
141      znugdt =  rnu * grav * z2dt
142      znurau =  znugdt * zraur
143
144      !! Explicit physics with thickness weighted updates
145      IF( lk_vvl ) THEN          ! variable volume
146
147         ! Evaluate the masked next velocity (effect of the additional force not included)
148         ! -------------------   (thickness weighted velocity, surface pressure gradient already included in dyn_hpg)
149         DO jk = 1, jpkm1
150            DO jj = 2, jpjm1
151               DO ji = fs_2, fs_jpim1   ! vector opt.
152                  ua(ji,jj,jk) = (        ub(ji,jj,jk) * fse3u_b(ji,jj,jk)      &
153                     &           + z2dt * ua(ji,jj,jk) * fse3u_n(ji,jj,jk)  )   &
154                     &         / fse3u_a(ji,jj,jk) * umask(ji,jj,jk)
155                  va(ji,jj,jk) = (        vb(ji,jj,jk) * fse3v_b(ji,jj,jk)      &
156                     &           + z2dt * va(ji,jj,jk) * fse3v_n(ji,jj,jk)  )   &
157                     &         / fse3v_a(ji,jj,jk) * vmask(ji,jj,jk)
158               END DO
159            END DO
160         END DO
161
162      ELSE                       ! fixed volume
163
164         ! Surface pressure gradient (now)
165         DO jj = 2, jpjm1
166            DO ji = fs_2, fs_jpim1   ! vector opt.
167               spgu(ji,jj) = - grav * ( sshn(ji+1,jj) - sshn(ji,jj) ) / e1u(ji,jj)
168               spgv(ji,jj) = - grav * ( sshn(ji,jj+1) - sshn(ji,jj) ) / e2v(ji,jj)
169            END DO
170         END DO 
171         !
172         ! add the surface pressure trend to the general trend and
173         ! evaluate the masked next velocity (effect of the additional force not included)
174         DO jk = 1, jpkm1
175            DO jj = 2, jpjm1
176               DO ji = fs_2, fs_jpim1   ! vector opt.
177                  ua(ji,jj,jk) = (  ub(ji,jj,jk) + z2dt * ( ua(ji,jj,jk) + spgu(ji,jj) )  ) * umask(ji,jj,jk)
178                  va(ji,jj,jk) = (  vb(ji,jj,jk) + z2dt * ( va(ji,jj,jk) + spgv(ji,jj) )  ) * vmask(ji,jj,jk)
179               END DO
180            END DO
181         END DO
182         !
183      ENDIF
184
185#if defined key_obc
186      CALL obc_dyn( kt )      ! Update velocities on each open boundary with the radiation algorithm
187      CALL obc_vol( kt )      ! Correction of the barotropic componant velocity to control the volume of the system
188#endif
189#if defined key_bdy
190      ! Update velocities on unstructured boundary using the Flow Relaxation Scheme
191      CALL bdy_dyn_frs( kt )
192
193      IF (ln_bdy_vol) THEN
194      ! Correction of the barotropic component velocity to control the volume of the system
195        CALL bdy_vol( kt )
196      ENDIF
197#endif
198#if defined key_agrif
199      CALL Agrif_dyn( kt )    ! Update velocities on each coarse/fine interfaces
200#endif
201#if defined key_orca_r2
202      IF( n_cla == 1 )   CALL dyn_spg_cla( kt )      ! Cross Land Advection (update (ua,va))
203#endif
204
205      ! compute the next vertically averaged velocity (effect of the additional force not included)
206      ! ---------------------------------------------
207      DO jj = 2, jpjm1
208         DO ji = fs_2, fs_jpim1   ! vector opt.
209            spgu(ji,jj) = 0.e0
210            spgv(ji,jj) = 0.e0
211         END DO
212      END DO
213
214      ! vertical sum
215!CDIR NOLOOPCHG
216      IF( lk_vopt_loop ) THEN          ! vector opt., forced unroll
217         DO jk = 1, jpkm1
218            DO ji = 1, jpij
219               spgu(ji,1) = spgu(ji,1) + fse3u(ji,1,jk) * ua(ji,1,jk)
220               spgv(ji,1) = spgv(ji,1) + fse3v(ji,1,jk) * va(ji,1,jk)
221            END DO
222         END DO
223      ELSE                        ! No  vector opt.
224         DO jk = 1, jpkm1
225            DO jj = 2, jpjm1
226               DO ji = 2, jpim1
227                  spgu(ji,jj) = spgu(ji,jj) + fse3u(ji,jj,jk) * ua(ji,jj,jk)
228                  spgv(ji,jj) = spgv(ji,jj) + fse3v(ji,jj,jk) * va(ji,jj,jk)
229               END DO
230            END DO
231         END DO
232      ENDIF
233
234      ! transport: multiplied by the horizontal scale factor
235      DO jj = 2, jpjm1
236         DO ji = fs_2, fs_jpim1   ! vector opt.
237            spgu(ji,jj) = spgu(ji,jj) * e2u(ji,jj)
238            spgv(ji,jj) = spgv(ji,jj) * e1v(ji,jj)
239         END DO
240      END DO
241
242      ! Boundary conditions on (spgu,spgv)
243      CALL lbc_lnk( spgu, 'U', -1. )
244      CALL lbc_lnk( spgv, 'V', -1. )
245
246      IF( lk_vvl ) CALL sol_mat( kt )      ! build the matrix at kt (vvl case only)
247
248      ! Right hand side of the elliptic equation and first guess
249      ! -----------------------------------------------------------
250      DO jj = 2, jpjm1
251         DO ji = fs_2, fs_jpim1   ! vector opt.
252            ! Divergence of the after vertically averaged velocity
253            zgcb =  spgu(ji,jj) - spgu(ji-1,jj)   &
254                  + spgv(ji,jj) - spgv(ji,jj-1)
255            gcb(ji,jj) = gcdprc(ji,jj) * zgcb
256            ! First guess of the after barotropic transport divergence
257            zbtd = gcx(ji,jj)
258            gcx (ji,jj) = 2. * zbtd   - gcxb(ji,jj)
259            gcxb(ji,jj) =      zbtd
260         END DO
261      END DO
262      ! applied the lateral boundary conditions
263      IF( nsolv == 2 .AND. MAX( jpr2di, jpr2dj ) > 0 ) CALL lbc_lnk_e( gcb, c_solver_pt, 1. )   
264
265#if defined key_agrif
266      IF( .NOT. AGRIF_ROOT() ) THEN
267         ! add contribution of gradient of after barotropic transport divergence
268         IF( nbondi == -1 .OR. nbondi == 2 )   gcb(3     ,:) =   &
269            &    gcb(3     ,:) - znugdt * z2dt * laplacu(2     ,:) * gcdprc(3     ,:) * hu(2     ,:) * e2u(2     ,:)
270         IF( nbondi ==  1 .OR. nbondi == 2 )   gcb(nlci-2,:) =   &
271            &    gcb(nlci-2,:) + znugdt * z2dt * laplacu(nlci-2,:) * gcdprc(nlci-2,:) * hu(nlci-2,:) * e2u(nlci-2,:)
272         IF( nbondj == -1 .OR. nbondj == 2 )   gcb(:     ,3) =   &
273            &    gcb(:,3     ) - znugdt * z2dt * laplacv(:,2     ) * gcdprc(:,3     ) * hv(:,2     ) * e1v(:,2     )
274         IF( nbondj ==  1 .OR. nbondj == 2 )   gcb(:,nlcj-2) =   &
275            &    gcb(:,nlcj-2) + znugdt * z2dt * laplacv(:,nlcj-2) * gcdprc(:,nlcj-2) * hv(:,nlcj-2) * e1v(:,nlcj-2)
276      ENDIF
277#endif
278
279
280      ! Relative precision (computation on one processor)
281      ! ------------------
282      rnorme =0.e0
283      rnorme = SUM( gcb(1:jpi,1:jpj) * gcdmat(1:jpi,1:jpj) * gcb(1:jpi,1:jpj) * bmask(:,:) )
284      IF( lk_mpp )   CALL mpp_sum( rnorme )   ! sum over the global domain
285
286      epsr = eps * eps * rnorme
287      ncut = 0
288      ! if rnorme is 0, the solution is 0, the solver is not called
289      IF( rnorme == 0.e0 ) THEN
290         gcx(:,:) = 0.e0
291         res   = 0.e0
292         niter = 0
293         ncut  = 999
294      ENDIF
295
296      ! Evaluate the next transport divergence
297      ! --------------------------------------
298      !    Iterarive solver for the elliptic equation (except IF sol.=0)
299      !    (output in gcx with boundary conditions applied)
300      kindic = 0
301      IF( ncut == 0 ) THEN
302         IF( nsolv == 1 ) THEN         ! diagonal preconditioned conjuguate gradient
303            CALL sol_pcg( kindic )
304         ELSEIF( nsolv == 2 ) THEN     ! successive-over-relaxation
305            CALL sol_sor( kindic )
306         ELSEIF( nsolv == 3 ) THEN     ! FETI solver
307            CALL sol_fet( kindic )
308         ELSE                          ! e r r o r in nsolv namelist parameter
309            WRITE(ctmp1,*) ' ~~~~~~~~~~~                not = ', nsolv
310            CALL ctl_stop( ' dyn_spg_flt : e r r o r, nsolv = 1, 2 or 3', ctmp1 )
311         ENDIF
312      ENDIF
313
314      ! Transport divergence gradient multiplied by z2dt
315      ! --------------------------------------------====
316      DO jj = 2, jpjm1
317         DO ji = fs_2, fs_jpim1   ! vector opt.
318            ! trend of Transport divergence gradient
319            ztdgu = znugdt * (gcx(ji+1,jj  ) - gcx(ji,jj) ) / e1u(ji,jj)
320            ztdgv = znugdt * (gcx(ji  ,jj+1) - gcx(ji,jj) ) / e2v(ji,jj)
321            ! multiplied by z2dt
322#if defined key_obc
323            ! caution : grad D = 0 along open boundaries
324            spgu(ji,jj) = z2dt * ztdgu * obcumask(ji,jj)
325            spgv(ji,jj) = z2dt * ztdgv * obcvmask(ji,jj)
326#elif defined key_bdy
327            ! caution : grad D = 0 along open boundaries
328            ! Remark: The filtering force could be reduced here in the FRS zone
329            !         by multiplying spgu/spgv by (1-alpha) ?? 
330            spgu(ji,jj) = z2dt * ztdgu * bdyumask(ji,jj)
331            spgv(ji,jj) = z2dt * ztdgv * bdyvmask(ji,jj)           
332#else
333            spgu(ji,jj) = z2dt * ztdgu
334            spgv(ji,jj) = z2dt * ztdgv
335#endif
336         END DO
337      END DO
338
339#if defined key_agrif     
340      IF( .NOT. Agrif_Root() ) THEN
341         ! caution : grad D (fine) = grad D (coarse) at coarse/fine interface
342         IF( nbondi == -1 .OR. nbondi == 2 ) spgu(2     ,:) = znugdt * z2dt * laplacu(2     ,:) * umask(2     ,:,1)
343         IF( nbondi ==  1 .OR. nbondi == 2 ) spgu(nlci-2,:) = znugdt * z2dt * laplacu(nlci-2,:) * umask(nlci-2,:,1)
344         IF( nbondj == -1 .OR. nbondj == 2 ) spgv(:,2     ) = znugdt * z2dt * laplacv(:,2     ) * vmask(:     ,2,1)
345         IF( nbondj ==  1 .OR. nbondj == 2 ) spgv(:,nlcj-2) = znugdt * z2dt * laplacv(:,nlcj-2) * vmask(:,nlcj-2,1)
346      ENDIF
347#endif     
348      ! Add the trends multiplied by z2dt to the after velocity
349      ! -------------------------------------------------------
350      !     ( c a u t i o n : (ua,va) here are the after velocity not the
351      !                       trend, the leap-frog time stepping will not
352      !                       be done in dynnxt.F90 routine)
353      DO jk = 1, jpkm1
354         DO jj = 2, jpjm1
355            DO ji = fs_2, fs_jpim1   ! vector opt.
356               ua(ji,jj,jk) = (ua(ji,jj,jk) + spgu(ji,jj)) * umask(ji,jj,jk)
357               va(ji,jj,jk) = (va(ji,jj,jk) + spgv(ji,jj)) * vmask(ji,jj,jk)
358            END DO
359         END DO
360      END DO
361
362      ! write filtered free surface arrays in restart file
363      ! --------------------------------------------------
364      IF( lrst_oce ) CALL flt_rst( kt, 'WRITE' )
365
366      ! print sum trends (used for debugging)
367      IF(ln_ctl)     CALL prt_ctl( tab2d_1=sshn, clinfo1=' spg  - ssh: ', mask1=tmask )
368      !
369   END SUBROUTINE dyn_spg_flt
370
371
372   SUBROUTINE flt_rst( kt, cdrw )
373     !!---------------------------------------------------------------------
374     !!                   ***  ROUTINE ts_rst  ***
375     !!
376     !! ** Purpose : Read or write filtered free surface arrays in restart file
377     !!----------------------------------------------------------------------
378     INTEGER         , INTENT(in) ::   kt         ! ocean time-step
379     CHARACTER(len=*), INTENT(in) ::   cdrw       ! "READ"/"WRITE" flag
380     !!----------------------------------------------------------------------
381
382     IF( TRIM(cdrw) == 'READ' ) THEN
383        IF( iom_varid( numror, 'gcx', ldstop = .FALSE. ) > 0 ) THEN
384! Caution : extra-hallow
385! gcx and gcxb are defined as: DIMENSION(1-jpr2di:jpi+jpr2di,1-jpr2dj:jpj+jpr2dj)
386           CALL iom_get( numror, jpdom_autoglo, 'gcx' , gcx (1:jpi,1:jpj) )
387           CALL iom_get( numror, jpdom_autoglo, 'gcxb', gcxb(1:jpi,1:jpj) )
388           IF( neuler == 0 ) THEN
389              gcxb(:,:) = gcx (:,:)
390           ENDIF
391        ELSE
392           gcx (:,:) = 0.e0
393           gcxb(:,:) = 0.e0
394        ENDIF
395     ELSEIF( TRIM(cdrw) == 'WRITE' ) THEN
396! Caution : extra-hallow
397! gcx and gcxb are defined as: DIMENSION(1-jpr2di:jpi+jpr2di,1-jpr2dj:jpj+jpr2dj)
398        CALL iom_rstput( kt, nitrst, numrow, 'gcx' , gcx( 1:jpi,1:jpj) )
399        CALL iom_rstput( kt, nitrst, numrow, 'gcxb', gcxb(1:jpi,1:jpj) )
400     ENDIF
401     !
402   END SUBROUTINE flt_rst
403
404#else
405   !!----------------------------------------------------------------------
406   !!   Default case :   Empty module   No standart free surface cst volume
407   !!----------------------------------------------------------------------
408CONTAINS
409   SUBROUTINE dyn_spg_flt( kt, kindic )       ! Empty routine
410      WRITE(*,*) 'dyn_spg_flt: You should not have seen this print! error?', kt, kindic
411   END SUBROUTINE dyn_spg_flt
412   SUBROUTINE flt_rst    ( kt, cdrw )         ! Empty routine
413      INTEGER         , INTENT(in) ::   kt         ! ocean time-step
414      CHARACTER(len=*), INTENT(in) ::   cdrw       ! "READ"/"WRITE" flag
415      WRITE(*,*) 'flt_rst: You should not have seen this print! error?', kt, cdrw
416   END SUBROUTINE flt_rst
417#endif
418   
419   !!======================================================================
420END MODULE dynspg_flt
Note: See TracBrowser for help on using the repository browser.