123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340 |
- MODULE solmat
- !!======================================================================
- !! *** MODULE solmat ***
- !! solver : construction of the matrix
- !!======================================================================
- !! History : 1.0 ! 1988-04 (G. Madec) Original code
- !! ! 1993-03 (M. Guyon) symetrical conditions
- !! ! 1993-06 (M. Guyon) suppress pointers
- !! ! 1996-05 (G. Madec) merge sor and pcg formulations
- !! ! 1996-11 (A. Weaver) correction to preconditioning
- !! NEMO 1.0 ! 1902-08 (G. Madec) F90: Free form
- !! - ! 1902-11 (C. Talandier, A-M. Treguier) Free surface & Open boundaries
- !! 2.0 ! 2005-09 (R. Benshila) add sol_exd for extra outer halo
- !! - ! 2005-11 (V. Garnier) Surface pressure gradient organization
- !! 3.2 ! 2009-06 (S. Masson) distributed restart using iom
- !! - ! 2009-07 (R. Benshila) suppression of rigid-lid option
- !! 3.3 ! 2010-09 (D. Storkey) update for BDY module.
- !!----------------------------------------------------------------------
- !!----------------------------------------------------------------------
- !! sol_mat : Construction of the matrix of used by the elliptic solvers
- !! sol_exd :
- !!----------------------------------------------------------------------
- USE oce ! ocean dynamics and active tracers
- USE dom_oce ! ocean space and time domain
- USE sol_oce ! ocean solver
- USE phycst ! physical constants
- USE bdy_oce ! unstructured open boundary conditions
- USE lbclnk ! lateral boudary conditions
- USE lib_mpp ! distributed memory computing
- USE c1d ! 1D vertical configuration
- USE in_out_manager ! I/O manager
- USE timing ! timing
- IMPLICIT NONE
- PRIVATE
- PUBLIC sol_mat ! routine called by inisol.F90
- !!----------------------------------------------------------------------
- !! NEMO/OPA 3.3 , NEMO Consortium (2010)
- !! $Id: solmat.F90 4328 2013-12-06 10:25:13Z davestorkey $
- !! Software governed by the CeCILL licence (NEMOGCM/NEMO_CeCILL.txt)
- !!----------------------------------------------------------------------
- CONTAINS
- SUBROUTINE sol_mat( kt )
- !!----------------------------------------------------------------------
- !! *** ROUTINE sol_mat ***
- !!
- !! ** Purpose : Construction of the matrix of used by the elliptic
- !! solvers (either sor or pcg methods).
- !!
- !! ** Method : The matrix is built for the divergence of the transport
- !! system. a diagonal preconditioning matrix is also defined.
- !!
- !! ** Action : - gcp : extra-diagonal elements of the matrix
- !! - gcdmat : preconditioning matrix (diagonal elements)
- !! - gcdprc : inverse of the preconditioning matrix
- !!----------------------------------------------------------------------
- INTEGER, INTENT(in) :: kt
- !!
- INTEGER :: ji, jj ! dummy loop indices
- REAL(wp) :: zcoefs, zcoefw, zcoefe, zcoefn ! temporary scalars
- REAL(wp) :: z2dt, zcoef
- !!----------------------------------------------------------------------
- !
- IF( nn_timing == 1 ) CALL timing_start('sol_mat')
- !
-
- ! 1. Construction of the matrix
- ! -----------------------------
- zcoef = 0.e0 ! initialize to zero
- gcp(:,:,1) = 0.e0
- gcp(:,:,2) = 0.e0
- gcp(:,:,3) = 0.e0
- gcp(:,:,4) = 0.e0
- !
- gcdprc(:,:) = 0.e0
- gcdmat(:,:) = 0.e0
- !
- IF( neuler == 0 .AND. kt == nit000 ) THEN ; z2dt = rdt
- ELSE ; z2dt = 2. * rdt
- ENDIF
- #if defined key_dynspg_flt && ! defined key_bdy
- DO jj = 2, jpjm1 ! matrix of free surface elliptic system
- DO ji = 2, jpim1
- zcoef = z2dt * z2dt * grav * bmask(ji,jj)
- zcoefs = -zcoef * hv(ji ,jj-1) * e1v(ji ,jj-1) / e2v(ji ,jj-1) ! south coefficient
- zcoefw = -zcoef * hu(ji-1,jj ) * e2u(ji-1,jj ) / e1u(ji-1,jj ) ! west coefficient
- zcoefe = -zcoef * hu(ji ,jj ) * e2u(ji ,jj ) / e1u(ji ,jj ) ! east coefficient
- zcoefn = -zcoef * hv(ji ,jj ) * e1v(ji ,jj ) / e2v(ji ,jj ) ! north coefficient
- gcp(ji,jj,1) = zcoefs
- gcp(ji,jj,2) = zcoefw
- gcp(ji,jj,3) = zcoefe
- gcp(ji,jj,4) = zcoefn
- gcdmat(ji,jj) = e1t(ji,jj) * e2t(ji,jj) * bmask(ji,jj) & ! diagonal coefficient
- & - zcoefs -zcoefw -zcoefe -zcoefn
- END DO
- END DO
- # elif defined key_dynspg_flt && defined key_bdy
- ! defined gcdmat in the case of unstructured open boundaries
- DO jj = 2, jpjm1
- DO ji = 2, jpim1
- zcoef = z2dt * z2dt * grav * bmask(ji,jj)
- ! south coefficient
- zcoefs = -zcoef * hv(ji,jj-1) * e1v(ji,jj-1)/e2v(ji,jj-1)
- zcoefs = zcoefs * bdyvmask(ji,jj-1)
- gcp(ji,jj,1) = zcoefs
- ! west coefficient
- zcoefw = -zcoef * hu(ji-1,jj) * e2u(ji-1,jj)/e1u(ji-1,jj)
- zcoefw = zcoefw * bdyumask(ji-1,jj)
- gcp(ji,jj,2) = zcoefw
- ! east coefficient
- zcoefe = -zcoef * hu(ji,jj) * e2u(ji,jj)/e1u(ji,jj)
- zcoefe = zcoefe * bdyumask(ji,jj)
- gcp(ji,jj,3) = zcoefe
- ! north coefficient
- zcoefn = -zcoef * hv(ji,jj) * e1v(ji,jj)/e2v(ji,jj)
- zcoefn = zcoefn * bdyvmask(ji,jj)
- gcp(ji,jj,4) = zcoefn
- ! diagonal coefficient
- gcdmat(ji,jj) = e1t(ji,jj)*e2t(ji,jj)*bmask(ji,jj) &
- - zcoefs -zcoefw -zcoefe -zcoefn
- END DO
- END DO
- #endif
- IF( .NOT. Agrif_Root() ) THEN
- !
- IF( nbondi == -1 .OR. nbondi == 2 ) bmask(2 ,: ) = 0.e0
- IF( nbondi == 1 .OR. nbondi == 2 ) bmask(nlci-1,: ) = 0.e0
- IF( nbondj == -1 .OR. nbondj == 2 ) bmask(: ,2 ) = 0.e0
- IF( nbondj == 1 .OR. nbondj == 2 ) bmask(: ,nlcj-1) = 0.e0
- !
- DO jj = 2, jpjm1
- DO ji = 2, jpim1
- zcoef = z2dt * z2dt * grav * bmask(ji,jj)
- ! south coefficient
- IF( ( nbondj == -1 .OR. nbondj == 2 ) .AND. ( jj == 3 ) ) THEN
- zcoefs = -zcoef * hv(ji,jj-1) * e1v(ji,jj-1)/e2v(ji,jj-1)*(1.-vmask(ji,jj-1,1))
- ELSE
- zcoefs = -zcoef * hv(ji,jj-1) * e1v(ji,jj-1)/e2v(ji,jj-1)
- END IF
- gcp(ji,jj,1) = zcoefs
- !
- ! west coefficient
- IF( ( nbondi == -1 .OR. nbondi == 2 ) .AND. ( ji == 3 ) ) THEN
- zcoefw = -zcoef * hu(ji-1,jj) * e2u(ji-1,jj)/e1u(ji-1,jj)*(1.-umask(ji-1,jj,1))
- ELSE
- zcoefw = -zcoef * hu(ji-1,jj) * e2u(ji-1,jj)/e1u(ji-1,jj)
- END IF
- gcp(ji,jj,2) = zcoefw
- !
- ! east coefficient
- IF( ( nbondi == 1 .OR. nbondi == 2 ) .AND. ( ji == nlci-2 ) ) THEN
- zcoefe = -zcoef * hu(ji,jj) * e2u(ji,jj)/e1u(ji,jj)*(1.-umask(ji,jj,1))
- ELSE
- zcoefe = -zcoef * hu(ji,jj) * e2u(ji,jj)/e1u(ji,jj)
- END IF
- gcp(ji,jj,3) = zcoefe
- !
- ! north coefficient
- IF( ( nbondj == 1 .OR. nbondj == 2 ) .AND. ( jj == nlcj-2 ) ) THEN
- zcoefn = -zcoef * hv(ji,jj) * e1v(ji,jj)/e2v(ji,jj)*(1.-vmask(ji,jj,1))
- ELSE
- zcoefn = -zcoef * hv(ji,jj) * e1v(ji,jj)/e2v(ji,jj)
- END IF
- gcp(ji,jj,4) = zcoefn
- !
- ! diagonal coefficient
- gcdmat(ji,jj) = e1t(ji,jj)*e2t(ji,jj)*bmask(ji,jj) &
- & - zcoefs -zcoefw -zcoefe -zcoefn
- END DO
- END DO
- !
- ENDIF
- ! 2. Boundary conditions
- ! ----------------------
-
- ! Cyclic east-west boundary conditions
- ! ji=2 is the column east of ji=jpim1 and reciprocally,
- ! ji=jpim1 is the column west of ji=2
- ! all the coef are already set to zero as bmask is initialized to
- ! zero for ji=1 and ji=jpj in dommsk.
-
- ! Symetrical conditions
- ! free surface: no specific action
- ! bsf system: n-s gradient of bsf = 0 along j=2 (perhaps a bug !!!!!!)
- ! the diagonal coefficient of the southern grid points must be modify to
- ! account for the existence of the south symmetric bassin.
-
- ! North fold boundary condition
- ! all the coef are already set to zero as bmask is initialized to
- ! zero on duplicated lignes and portion of lignes
-
- ! 3. Preconditioned matrix
- ! ------------------------
-
- ! SOR and PCG solvers
- IF( lk_c1d ) CALL lbc_lnk( gcdmat, 'T', 1._wp ) ! 1D case bmask =/0 but gcdmat not define everywhere
- DO jj = 1, jpj
- DO ji = 1, jpi
- IF( bmask(ji,jj) /= 0.e0 ) gcdprc(ji,jj) = 1.e0 / gcdmat(ji,jj)
- END DO
- END DO
-
- gcp(:,:,1) = gcp(:,:,1) * gcdprc(:,:)
- gcp(:,:,2) = gcp(:,:,2) * gcdprc(:,:)
- gcp(:,:,3) = gcp(:,:,3) * gcdprc(:,:)
- gcp(:,:,4) = gcp(:,:,4) * gcdprc(:,:)
- IF( nn_solv == 2 ) gccd(:,:) = rn_sor * gcp(:,:,2)
- IF( nn_solv == 2 .AND. MAX( jpr2di, jpr2dj ) > 0) THEN
- CALL lbc_lnk_e( gcp (:,:,1), c_solver_pt, 1., jpr2di, jpr2dj ) ! lateral boundary conditions
- CALL lbc_lnk_e( gcp (:,:,2), c_solver_pt, 1., jpr2di, jpr2dj ) ! lateral boundary conditions
- CALL lbc_lnk_e( gcp (:,:,3), c_solver_pt, 1., jpr2di, jpr2dj ) ! lateral boundary conditions
- CALL lbc_lnk_e( gcp (:,:,4), c_solver_pt, 1., jpr2di, jpr2dj ) ! lateral boundary conditions
- CALL lbc_lnk_e( gcdprc(:,:) , c_solver_pt, 1., jpr2di, jpr2dj ) ! lateral boundary conditions
- CALL lbc_lnk_e( gcdmat(:,:) , c_solver_pt, 1., jpr2di, jpr2dj ) ! lateral boundary conditions
- IF( npolj /= 0 ) CALL sol_exd( gcp , c_solver_pt ) ! switch northernelements
- END IF
-
- ! 4. Initialization the arrays used in pcg
- ! ----------------------------------------
- gcb (:,:) = 0.e0
- gcr (:,:) = 0.e0
- gcdes(:,:) = 0.e0
- gccd (:,:) = 0.e0
- !
- IF( nn_timing == 1 ) CALL timing_stop('sol_mat')
- !
- END SUBROUTINE sol_mat
- SUBROUTINE sol_exd( pt3d, cd_type )
- !!----------------------------------------------------------------------
- !! *** routine sol_exd ***
- !!
- !! ** Purpose : Reorder gcb coefficient on the extra outer halo
- !! at north fold in case of T or F pivot
- !!
- !! ** Method : Perform a circular permutation of the coefficients on
- !! the total area strictly above the pivot point,
- !! and on the semi-row of the pivot point
- !!----------------------------------------------------------------------
- CHARACTER(len=1) , INTENT( in ) :: cd_type ! define the nature of pt2d array grid-points
- ! ! = T , U , V , F , W
- ! ! = S : T-point, north fold treatment
- ! ! = G : F-point, north fold treatment
- ! ! = I : sea-ice velocity at F-point with index shift
- REAL(wp), DIMENSION(1-jpr2di:jpi+jpr2di,1-jpr2dj:jpj+jpr2dj,4), INTENT(inout) :: pt3d ! 2D field to be treated
- !!
- INTEGER :: ji, jk ! dummy loop indices
- INTEGER :: iloc ! local integers
- REAL(wp), ALLOCATABLE, SAVE, DIMENSION(:,:,:) :: ztab ! workspace allocated one for all
- !!----------------------------------------------------------------------
- IF( .NOT. ALLOCATED( ztab ) ) THEN
- ALLOCATE( ztab(1-jpr2di:jpi+jpr2di,1-jpr2dj:jpj+jpr2dj,4), STAT=iloc )
- IF( lk_mpp ) CALL mpp_sum ( iloc )
- IF( iloc /= 0 ) CALL ctl_stop('STOP', 'sol_exd: failed to allocate array')
- ENDIF
-
- ztab = pt3d
- SELECT CASE ( npolj ) ! north fold type
- !
- CASE ( 3 , 4 ) !== T pivot ==!
- iloc = jpiglo/2 +1
- !
- SELECT CASE ( cd_type )
- !
- CASE ( 'T' , 'U', 'W' )
- DO jk = 1, 4
- DO ji = 1-jpr2di, nlci+jpr2di
- pt3d(ji,nlcj:nlcj+jpr2dj,jk) = ztab(ji,nlcj:nlcj+jpr2dj,jk+3-2*MOD(jk+3,4))
- END DO
- END DO
- DO jk =1, 4
- DO ji = nlci+jpr2di, 1-jpr2di, -1
- IF( ( ji .LT. mi0(iloc) .AND. mi0(iloc) /= 1 ) &
- & .OR. ( mi0(iloc) == jpi+1 ) ) EXIT
- pt3d(ji,nlcj-1,jk) = ztab(ji,nlcj-1,jk+3-2*MOD(jk+3,4))
- END DO
- END DO
- !
- CASE ( 'F' , 'I', 'V' )
- DO jk =1, 4
- DO ji = 1-jpr2di, nlci+jpr2di
- pt3d(ji,nlcj-1:nlcj+jpr2dj,jk) = ztab(ji,nlcj-1:nlcj+jpr2dj,jk+3-2*MOD(jk+3,4))
- END DO
- END DO
- !
- END SELECT ! cd_type
- !
- CASE ( 5 , 6 ) !== F pivot ==!
- iloc=jpiglo/2
- !
- SELECT CASE (cd_type )
- !
- CASE ( 'T' , 'U', 'W')
- DO jk =1, 4
- DO ji = 1-jpr2di, nlci+jpr2di
- pt3d(ji,nlcj:nlcj+jpr2dj,jk) = ztab(ji,nlcj:nlcj+jpr2dj,jk+3-2*MOD(jk+3,4))
- END DO
- END DO
- !
- CASE ( 'F' , 'I', 'V' )
- DO jk =1, 4
- DO ji = 1-jpr2di, nlci+jpr2di
- pt3d(ji,nlcj:nlcj+jpr2dj,jk) = ztab(ji,nlcj:nlcj+jpr2dj,jk+3-2*MOD(jk+3,4))
- END DO
- END DO
- DO jk =1, 4
- DO ji = nlci+jpr2di, 1-jpr2di, -1
- IF( ( ji .LT. mi0(iloc) .AND. mi0(iloc) /= 1 ) .OR. ( mi0(iloc) == jpi+1 ) ) EXIT
- pt3d(ji,nlcj-1,jk) = ztab(ji,nlcj-1,jk+3-2*MOD(jk+3,4))
- END DO
- END DO
- !
- END SELECT ! cd_type
- !
- END SELECT ! npolj
- !
- END SUBROUTINE sol_exd
- !!======================================================================
- END MODULE solmat
|