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 trunk/NEMO/OPA_SRC/DYN – NEMO

source: trunk/NEMO/OPA_SRC/DYN/dynspg_flt.F90 @ 1508

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

Merge VVL branch with the trunk (act II), see ticket #429

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