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.
isfcpl.F90 in NEMO/trunk/src/OCE/ISF – NEMO

source: NEMO/trunk/src/OCE/ISF/isfcpl.F90 @ 15085

Last change on this file since 15085 was 15085, checked in by clem, 3 years ago

ISF further cleaning and debugging(?) for isfcpl but I think it requires more attention

File size: 35.9 KB
RevLine 
[11553]1MODULE isfcpl
2   !!======================================================================
3   !!                       ***  MODULE  isfcpl  ***
4   !!
5   !! iceshelf coupling module : module managing the coupling between NEMO and an ice sheet model
6   !!
7   !!======================================================================
8   !! History :  4.1  !  2019-07  (P. Mathiot) Original code
9   !!----------------------------------------------------------------------
10
11   !!----------------------------------------------------------------------
[14053]12   !!   isfrst        : read/write iceshelf variables in/from restart
[11553]13   !!----------------------------------------------------------------------
[14053]14   USE oce            ! ocean dynamics and tracers
15#if defined key_qco
16   USE domqco  , ONLY : dom_qco_zgr      ! vertical scale factor interpolation
[14143]17#elif defined key_linssh
18   !                                     ! fix in time coordinate
[13237]19#else
[14053]20   USE domvvl  , ONLY : dom_vvl_zgr      ! vertical scale factor interpolation
[13237]21#endif
[14053]22   USE domutl  , ONLY : dom_ngb          ! find the closest grid point from a given lon/lat position
23   USE isf_oce        ! ice shelf variable
24   USE isfutils, ONLY : debug
[11852]25   !
[11553]26   USE in_out_manager ! I/O manager
27   USE iom            ! I/O library
[14053]28   USE lib_mpp , ONLY : mpp_sum, mpp_max ! mpp routine
[11553]29   !
30   IMPLICIT NONE
31
32   PRIVATE
33
[14072]34   PUBLIC isfcpl_rst_write, isfcpl_init                    ! iceshelf restart read and write
35   PUBLIC isfcpl_ssh, isfcpl_tra, isfcpl_vol, isfcpl_cons  ! iceshelf correction for ssh, tra, dyn and conservation
[11553]36
37   TYPE isfcons
[14053]38      INTEGER ::   ii     ! i global
39      INTEGER ::   jj     ! j global
40      INTEGER ::   kk     ! k level
41      REAL(wp)::   dvol   ! volume increment
42      REAL(wp)::   dsal   ! salt increment
43      REAL(wp)::   dtem   ! heat increment
44      REAL(wp)::   lon    ! lon
45      REAL(wp)::   lat    ! lat
46      INTEGER ::   ngb    ! 0/1 (valid location or not (ie on halo or no neigbourg))
[11553]47   END TYPE
48   !
[12340]49   !! * Substitutions
50#  include "do_loop_substitute.h90"
[13237]51#  include "domzgr_substitute.h90"
[11553]52   !!----------------------------------------------------------------------
53   !! NEMO/OCE 4.0 , NEMO Consortium (2018)
54   !! $Id: sbcisf.F90 10536 2019-01-16 19:21:09Z mathiot $
55   !! Software governed by the CeCILL license (see ./LICENSE)
56   !!----------------------------------------------------------------------
57CONTAINS
[12068]58   SUBROUTINE isfcpl_init(Kbb, Kmm, Kaa)
[11902]59      !!---------------------------------------------------------------------
[12077]60      !!                   ***  ROUTINE iscpl_init  ***
[14072]61      !!
62      !! ** Purpose : correct ocean state for new wet cell and horizontal divergence
[12077]63      !!              correction for the dynamical adjustement
[11902]64      !!
[12077]65      !! ** Action : - compute ssh on new wet cell
66      !!             - compute T/S on new wet cell
67      !!             - compute horizontal divergence correction as a volume flux
68      !!             - compute the T/S/vol correction increment to keep trend to 0
69      !!
[11902]70      !!---------------------------------------------------------------------
[12068]71      INTEGER, INTENT(in) :: Kbb, Kmm, Kaa      ! ocean time level indices
72      !!---------------------------------------------------------------------
[11902]73      INTEGER :: id
74      !!----------------------------------------------------------------------
[11852]75      !
76      ! start on an euler time step
[12489]77      l_1st_euler = .TRUE.
[14072]78      !
[11902]79      ! allocation and initialisation to 0
[11553]80      CALL isf_alloc_cpl()
81      !
[11902]82      ! check presence of variable needed for coupling
83      ! iom_varid return 0 if not found
[11908]84      id = 1
[11902]85      id = id * iom_varid(numror, 'ssmask', ldstop = .false.)
86      id = id * iom_varid(numror, 'tmask' , ldstop = .false.)
87      id = id * iom_varid(numror, 'e3t_n' , ldstop = .false.)
88      id = id * iom_varid(numror, 'e3u_n' , ldstop = .false.)
89      id = id * iom_varid(numror, 'e3v_n' , ldstop = .false.)
90      IF(lwp) WRITE(numout,*) ' isfcpl_init:', id
91      IF (id == 0) THEN
[14072]92         IF(lwp) WRITE(numout,*) ' isfcpl_init: restart variables for ice sheet coupling are missing, skip coupling for this leg '
[11902]93         IF(lwp) WRITE(numout,*) ' ~~~~~~~~~~~'
94         IF(lwp) WRITE(numout,*) ''
95      ELSE
96         ! extrapolation ssh
[12068]97         CALL isfcpl_ssh(Kbb, Kmm, Kaa)
[11902]98         !
99         ! extrapolation tracer properties
[12068]100         CALL isfcpl_tra(Kmm)
[11902]101         !
102         ! correction of the horizontal divergence and associated temp. and salt content flux
103         ! Need to : - include in the cpl cons the risfcpl_vol/tsc contribution
104         !           - decide how to manage thickness level change in conservation
[12068]105         CALL isfcpl_vol(Kmm)
[11902]106         !
107         ! apply the 'conservation' method
[12068]108         IF ( ln_isfcpl_cons ) CALL isfcpl_cons(Kmm)
[11902]109         !
110      END IF
[11553]111      !
112      ! mask velocity properly (mask used in restart not compatible with new mask)
[12068]113      uu(:,:,:,Kmm) = uu(:,:,:,Kmm) * umask(:,:,:)
114      vv(:,:,:,Kmm) = vv(:,:,:,Kmm) * vmask(:,:,:)
[11553]115      !
[11852]116      ! all before fields set to now values
[12068]117      ts  (:,:,:,:,Kbb) = ts  (:,:,:,:,Kmm)
118      uu   (:,:,:,Kbb)   = uu   (:,:,:,Kmm)
119      vv   (:,:,:,Kbb)   = vv   (:,:,:,Kmm)
120      ssh (:,:,Kbb)     = ssh (:,:,Kmm)
[14143]121#if ! defined key_qco   &&   ! defined key_linssh
[12068]122      e3t(:,:,:,Kbb)   = e3t(:,:,:,Kmm)
[14072]123#endif
[11553]124   END SUBROUTINE isfcpl_init
[14053]125
[14072]126
[14053]127   SUBROUTINE isfcpl_rst_write( kt, Kmm )
[11553]128      !!---------------------------------------------------------------------
[11931]129      !!                   ***  ROUTINE iscpl_rst_write  ***
[14072]130      !!
[11931]131      !! ** Purpose : write icesheet coupling variables in restart
132      !!
[11553]133      !!-------------------------- IN  --------------------------------------
134      INTEGER, INTENT(in) :: kt
[12068]135      INTEGER, INTENT(in) :: Kmm    ! ocean time level index
[11553]136      !!----------------------------------------------------------------------
[13237]137      INTEGER :: jk                               ! loop index
[14053]138      REAL(wp), DIMENSION(jpi,jpj,jpk) :: ze3t, ze3u, ze3v, zgdepw  ! for qco substitution
[13237]139      !!----------------------------------------------------------------------
[11553]140      !
[13237]141      DO jk = 1, jpk
142         ze3t(:,:,jk) = e3t(:,:,jk,Kmm)
143         ze3u(:,:,jk) = e3u(:,:,jk,Kmm)
144         ze3v(:,:,jk) = e3v(:,:,jk,Kmm)
145         !
146         zgdepw(:,:,jk) = gdepw(:,:,jk,Kmm)
[14072]147      END DO
[13237]148      !
[13970]149      CALL iom_rstput( kt, nitrst, numrow, 'tmask'  , tmask  )
150      CALL iom_rstput( kt, nitrst, numrow, 'ssmask' , ssmask )
151      CALL iom_rstput( kt, nitrst, numrow, 'e3t_n'  , ze3t   )
152      CALL iom_rstput( kt, nitrst, numrow, 'e3u_n'  , ze3u   )
153      CALL iom_rstput( kt, nitrst, numrow, 'e3v_n'  , ze3v   )
154      CALL iom_rstput( kt, nitrst, numrow, 'gdepw_n', zgdepw )
[11553]155      !
156   END SUBROUTINE isfcpl_rst_write
157
[14072]158
[12068]159   SUBROUTINE isfcpl_ssh(Kbb, Kmm, Kaa)
[14072]160      !!----------------------------------------------------------------------
[11553]161      !!                   ***  ROUTINE iscpl_ssh  ***
[14072]162      !!
[11931]163      !! ** Purpose :   basic guess of ssh in new wet cell
[14072]164      !!
[11553]165      !! ** Method  :   basic extrapolation from neigbourg cells
166      !!
167      !!----------------------------------------------------------------------
168      !!
[12068]169      INTEGER, INTENT(in) :: Kbb, Kmm, Kaa    ! ocean time level indices
170      !!----------------------------------------------------------------------
[11908]171      INTEGER :: ji, jj, jd, jk      !! loop index
[11553]172      INTEGER :: jip1, jim1, jjp1, jjm1
173      !!
174      REAL(wp):: zsummsk
175      REAL(wp), DIMENSION(jpi,jpj) :: zdssmask, zssmask0, zssmask_b, zssh
176      !!----------------------------------------------------------------------
177      !
[13970]178      CALL iom_get( numror, jpdom_auto, 'ssmask'  , zssmask_b   ) ! need to extrapolate T/S
[11553]179
[14072]180      ! compute new ssh if we open a full water column
[11553]181      ! rude average of the closest neigbourgs (e1e2t not taking into account)
182      !
[12068]183      zssh(:,:)     = ssh(:,:,Kmm)
[11553]184      zssmask0(:,:) = zssmask_b(:,:)
185      !
186      DO jd = 1, nn_drown
187         !
188         zdssmask(:,:) = ssmask(:,:) - zssmask0(:,:)
[13295]189         DO_2D( 0, 0, 0, 0 )
[14053]190            jip1=ji+1   ;   jim1=ji-1
191            jjp1=jj+1   ;   jjm1=jj-1
[12353]192            !
193            zsummsk = zssmask0(jip1,jj) + zssmask0(jim1,jj) + zssmask0(ji,jjp1) + zssmask0(ji,jjm1)
194            !
195            IF (zdssmask(ji,jj) == 1._wp .AND. zsummsk /= 0._wp) THEN
196               ssh(ji,jj,Kmm)=( zssh(jip1,jj)*zssmask0(jip1,jj)     &
[14053]197                  &           + zssh(jim1,jj)*zssmask0(jim1,jj)     &
198                  &           + zssh(ji,jjp1)*zssmask0(ji,jjp1)     &
199                  &           + zssh(ji,jjm1)*zssmask0(ji,jjm1)) / zsummsk
[12353]200               zssmask_b(ji,jj) = 1._wp
201            ENDIF
202         END_2D
[15085]203         CALL lbc_lnk( 'isfcpl', ssh(:,:,Kmm), 'T', 1.0_wp, zssmask_b(:,:), 'T', 1.0_wp )
[11553]204         !
[12068]205         zssh(:,:) = ssh(:,:,Kmm)
[11553]206         zssmask0(:,:) = zssmask_b(:,:)
207         !
208         !
209      END DO
210      !
[12068]211      ! update ssh(:,:,Kmm)
212      ssh(:,:,Kmm) = zssh(:,:) * ssmask(:,:)
[11553]213      !
[12068]214      ssh(:,:,Kbb) = ssh(:,:,Kmm)
[11553]215      !
[12068]216      IF ( ln_isfdebug ) CALL debug('isfcpl_ssh: sshn',ssh(:,:,Kmm))
[11902]217      !
[11823]218      ! recompute the vertical scale factor, depth and water thickness
[12068]219      IF(lwp) write(numout,*) 'isfcpl_ssh : recompute scale factor from ssh (new wet cell,Kmm)'
[11908]220      IF(lwp) write(numout,*) '~~~~~~~~~~~'
[14143]221#if defined key_qco
222      CALL dom_qco_zgr(Kbb, Kmm)
223#elif defined key_linssh
224      ! linear ssh : fix in time coord.
225#else
[11908]226      DO jk = 1, jpk
[13237]227         e3t(:,:,jk,Kmm) = e3t_0(:,:,jk) * ( 1._wp + (ht_0(:,:) + ssh(:,:,Kmm)) * r1_ht_0(:,:) )
[11908]228      END DO
[12068]229      e3t(:,:,:,Kbb) = e3t(:,:,:,Kmm)
230      CALL dom_vvl_zgr(Kbb, Kmm, Kaa)
[13237]231#endif
[11823]232      !
[11553]233   END SUBROUTINE isfcpl_ssh
234
[14072]235
[12068]236   SUBROUTINE isfcpl_tra(Kmm)
[14072]237      !!----------------------------------------------------------------------
[11553]238      !!                   ***  ROUTINE iscpl_tra  ***
[14072]239      !!
240      !! ** Purpose :   compute new tn, sn in case of evolving geometry of ice shelves
241      !!
[11553]242      !! ** Method  :   tn, sn : basic extrapolation from neigbourg cells
243      !!
244      !!----------------------------------------------------------------------
[12068]245      INTEGER, INTENT(in) :: Kmm    ! ocean time level index
246      !!----------------------------------------------------------------------
[11553]247      REAL(wp), DIMENSION(jpi,jpj,jpk) :: ztmask_b
248      !REAL(wp), DIMENSION(:,:,:  ), INTENT(in ) :: pdepw_b                         !! depth w before
249      !!
250      INTEGER :: ji, jj, jk, jd          !! loop index
251      INTEGER :: jip1, jim1, jjp1, jjm1, jkp1, jkm1
252      !!
253      REAL(wp):: zsummsk
254      REAL(wp):: zdz, zdzm1, zdzp1
255      !!
[14072]256      REAL(wp), DIMENSION(jpi,jpj)          :: zdmask
[11553]257      REAL(wp), DIMENSION(jpi,jpj,jpk)      :: ztmask0, zwmaskn
258      REAL(wp), DIMENSION(jpi,jpj,jpk)      :: ztmask1, zwmaskb, ztmp3d
259      REAL(wp), DIMENSION(jpi,jpj,jpk,jpts) :: zts0
260      !!----------------------------------------------------------------------
[14072]261      !
[13970]262      CALL iom_get( numror, jpdom_auto, 'tmask'  , ztmask_b   ) ! need to extrapolate T/S
263      !CALL iom_get( numror, jpdom_auto, 'wmask'  , zwmask_b  ) ! need to extrapolate T/S
264      !CALL iom_get( numror, jpdom_auto, 'gdepw_n', zdepw_b(:,:,:) ) ! need to interpol vertical profile (vvl)
[11553]265      !
[14072]266      !
[11553]267      ! compute new T/S (interpolation) if vvl only for common wet cell in before and after wmask
268      !PM: Is this IF needed since change to VVL by default
269      !bugged : to be corrected (PM)
270      ! back up original t/s/mask
[12068]271      !tsb (:,:,:,:) = ts(:,:,:,:,Kmm)
[11553]272      !
273     ! compute new T/S (interpolation) if vvl only for common wet cell in before and after wmask
274
275!      IF (.NOT.ln_linssh) THEN
276!         DO jk = 2,jpk-1
277!            DO jj = 1,jpj
278!               DO ji = 1,jpi
279!                  IF (wmask(ji,jj,jk) * zwmaskb(ji,jj,jk) == 1._wp .AND. (tmask(ji,jj,1)==0._wp .OR. ztmask_b(ji,jj,1)==0._wp) ) THEN
280!
281!                     !compute weight
[12068]282!                     zdzp1 = MAX(0._wp,pdepw_b(ji,jj,jk+1) - gdepw(ji,jj,jk+1,Kmm))
283!                     zdzm1 = MAX(0._wp,gdepw(ji,jj,jk  ,Kmm) - pdepw_b(ji,jj,jk  ))
284!                     zdz   = e3t(ji,jj,jk,Kmm) - zdzp1 - zdzm1 ! if isf : e3t = gdepw(ji,jj,jk+1,Kmm)- gdepw(ji,jj,jk,Kmm)
[11553]285!
286!                     IF (zdz .LT. 0._wp) THEN
287!                        CALL ctl_stop( 'STOP', 'rst_iscpl : unable to compute the interpolation' )
288!                     END IF
289!
[12068]290!                     ts(ji,jj,jk,jp_tem,Kmm) = ( zdzp1*ts(ji,jj,jk+1,jp_tem,Kbb) &
291!                        &                   + zdz  *ts(ji,jj,jk  ,jp_tem,Kbb) &
292!                        &                   + zdzm1*ts(ji,jj,jk-1,jp_tem,Kbb) )/e3t(ji,jj,jk,Kmm)
[11553]293!
[12068]294!                     ts(ji,jj,jk,jp_sal,Kmm) = ( zdzp1*ts(ji,jj,jk+1,jp_sal,Kbb) &
295!                        &                   + zdz  *ts(ji,jj,jk  ,jp_sal,Kbb) &
296!                        &                   + zdzm1*ts(ji,jj,jk-1,jp_sal,Kbb) )/e3t(ji,jj,jk,Kmm)
[11553]297!
298!                  END IF
299!               END DO
300!            END DO
301!         END DO
302!      END IF
303
[12068]304      zts0(:,:,:,:)  = ts(:,:,:,:,Kmm)
[11553]305      ztmask0(:,:,:) = ztmask_b(:,:,:)
306      ztmask1(:,:,:) = ztmask_b(:,:,:)
307      !
308      ! iterate the extrapolation processes nn_drown times
309      DO jd = 1,nn_drown ! resolution dependent (OK for ISOMIP+ case)
310         DO jk = 1,jpk-1
311            !
312            ! define new wet cell
313            zdmask(:,:) = tmask(:,:,jk) - ztmask0(:,:,jk);
314            !
[13295]315            DO_2D( 0, 0, 0, 0 )
[12353]316               jip1=ji+1; jim1=ji-1;
317               jjp1=jj+1; jjm1=jj-1;
318               !
319               ! check if a wet neigbourg cell is present
320               zsummsk = ztmask0(jip1,jj  ,jk) + ztmask0(jim1,jj  ,jk) &
321                       + ztmask0(ji  ,jjp1,jk) + ztmask0(ji  ,jjm1,jk)
322               !
323               ! if neigbourg wet cell available at the same level
324               IF ( zdmask(ji,jj) == 1._wp  .AND. zsummsk /= 0._wp ) THEN
[11553]325                  !
[12353]326                  ! horizontal basic extrapolation
327                  ts(ji,jj,jk,1,Kmm)=( zts0(jip1,jj  ,jk,1) * ztmask0(jip1,jj  ,jk) &
328                  &               + zts0(jim1,jj  ,jk,1) * ztmask0(jim1,jj  ,jk) &
329                  &               + zts0(ji  ,jjp1,jk,1) * ztmask0(ji  ,jjp1,jk) &
330                  &               + zts0(ji  ,jjm1,jk,1) * ztmask0(ji  ,jjm1,jk) ) / zsummsk
331                  ts(ji,jj,jk,2,Kmm)=( zts0(jip1,jj  ,jk,2) * ztmask0(jip1,jj  ,jk) &
332                  &               + zts0(jim1,jj  ,jk,2) * ztmask0(jim1,jj  ,jk) &
333                  &               + zts0(ji  ,jjp1,jk,2) * ztmask0(ji  ,jjp1,jk) &
334                  &               + zts0(ji  ,jjm1,jk,2) * ztmask0(ji  ,jjm1,jk) ) / zsummsk
335                  !
336                  ! update mask for next pass
337                  ztmask1(ji,jj,jk)=1
338                  !
339               ! in case no neigbourg wet cell available at the same level
340               ! check if a wet cell is available below
341               ELSEIF (zdmask(ji,jj) == 1._wp .AND. zsummsk == 0._wp) THEN
342                  !
343                  ! vertical extrapolation if horizontal extrapolation failed
344                  jkm1=max(1,jk-1) ; jkp1=min(jpk,jk+1)
345                  !
[11553]346                  ! check if a wet neigbourg cell is present
[12353]347                  zsummsk = ztmask0(ji,jj,jkm1) + ztmask0(ji,jj,jkp1)
348                  IF (zdmask(ji,jj) == 1._wp .AND. zsummsk /= 0._wp ) THEN
349                     ts(ji,jj,jk,1,Kmm)=( zts0(ji,jj,jkp1,1)*ztmask0(ji,jj,jkp1)     &
350                     &               + zts0(ji,jj,jkm1,1)*ztmask0(ji,jj,jkm1)) / zsummsk
351                     ts(ji,jj,jk,2,Kmm)=( zts0(ji,jj,jkp1,2)*ztmask0(ji,jj,jkp1)     &
352                     &               + zts0(ji,jj,jkm1,2)*ztmask0(ji,jj,jkm1)) / zsummsk
[11553]353                     !
354                     ! update mask for next pass
[12353]355                     ztmask1(ji,jj,jk)=1._wp
[11553]356                  END IF
[12353]357               END IF
358            END_2D
[11553]359         END DO
360         !
[15085]361         CALL lbc_lnk( 'isfcpl', ts(:,:,:,jp_tem,Kmm), 'T', 1.0_wp, ts(:,:,:,jp_sal,Kmm), 'T', 1.0_wp, ztmask1, 'T', 1.0_wp)
362         !
[11553]363         ! update temperature and salinity and mask
[12068]364         zts0(:,:,:,:)  = ts(:,:,:,:,Kmm)
[11553]365         ztmask0(:,:,:) = ztmask1(:,:,:)
366         !
367         !
368      END DO  ! nn_drown
369      !
[12068]370      ! mask new ts(:,:,:,:,Kmm) field
371      ts(:,:,:,jp_tem,Kmm) = zts0(:,:,:,jp_tem) * tmask(:,:,:)
372      ts(:,:,:,jp_sal,Kmm) = zts0(:,:,:,jp_sal) * tmask(:,:,:)
[11553]373      !
374      ! sanity check
375      ! -----------------------------------------------------------------------------------------
376      ! case we open a cell but no neigbour cells available to get an estimate of T and S
[15053]377      DO_3D( 0, 0, 0, 0, 1,jpk-1 )
[12340]378         IF (tmask(ji,jj,jk) == 1._wp .AND. ts(ji,jj,jk,2,Kmm) == 0._wp)              &
379            &   CALL ctl_stop('STOP', 'failing to fill all new weet cell,     &
380            &                          try increase nn_drown or activate XXXX &
381            &                         in your domain cfg computation'         )
382      END_3D
[14072]383      !
[11553]384   END SUBROUTINE isfcpl_tra
385
[14072]386
[12068]387   SUBROUTINE isfcpl_vol(Kmm)
[14072]388      !!----------------------------------------------------------------------
[11553]389      !!                   ***  ROUTINE iscpl_vol  ***
[14072]390      !!
391      !! ** Purpose : compute the correction of the local divergence to apply
[11931]392      !!              during the first time step after the coupling.
393      !!
394      !! ** Method  : - compute horizontal vol div. before/after coupling
395      !!              - compute vertical input
396      !!              - compute correction
[14072]397      !!
[11553]398      !!----------------------------------------------------------------------
399      !!
[12068]400      INTEGER, INTENT(in) :: Kmm    ! ocean time level index
401      !!----------------------------------------------------------------------
[14072]402      INTEGER :: ji, jj, jk
[11553]403      INTEGER :: ikb, ikt
404      !!
[11931]405      REAL(wp), DIMENSION(jpi,jpj,jpk) :: zqvolb, zqvoln  ! vol flux div.         before/after coupling
406      REAL(wp), DIMENSION(jpi,jpj,jpk) :: ze3u_b, ze3v_b  ! vertical scale factor before/after coupling
407      REAL(wp), DIMENSION(jpi,jpj,jpk) :: ztmask_b        ! mask                  before       coupling
[11553]408      !!----------------------------------------------------------------------
409      !
[13970]410      CALL iom_get( numror, jpdom_auto, 'tmask'  , ztmask_b )
411      CALL iom_get( numror, jpdom_auto, 'e3u_n'  , ze3u_b   )
412      CALL iom_get( numror, jpdom_auto, 'e3v_n'  , ze3v_b   )
[11553]413      !
[11931]414      ! 1.0: compute horizontal volume flux divergence difference before-after coupling
415      !
[11553]416      DO jk = 1, jpk                                 ! Horizontal slab
[11931]417         ! 1.1: get volume flux before coupling (>0 out)
[13295]418         DO_2D( 0, 0, 0, 0 )
[13237]419            zqvolb(ji,jj,jk) =    &
420               &  (   e2u(ji  ,jj  ) * ze3u_b(ji  ,jj  ,jk) * uu(ji  ,jj  ,jk,Kmm)      &
421               &    - e2u(ji-1,jj  ) * ze3u_b(ji-1,jj  ,jk) * uu(ji-1,jj  ,jk,Kmm)      &
422               &    + e1v(ji  ,jj  ) * ze3v_b(ji  ,jj  ,jk) * vv(ji  ,jj  ,jk,Kmm)      &
423               &    - e1v(ji  ,jj-1) * ze3v_b(ji  ,jj-1,jk) * vv(ji  ,jj-1,jk,Kmm)  )   &
[12340]424               &                * ztmask_b(ji,jj,jk)
425         END_2D
[11553]426         !
[11931]427         ! 1.2: get volume flux after coupling (>0 out)
[14072]428         ! properly mask velocity
[11553]429         ! (velocity are still mask with old mask at this stage)
[12068]430         uu(:,:,jk,Kmm) = uu(:,:,jk,Kmm) * umask(:,:,jk)
431         vv(:,:,jk,Kmm) = vv(:,:,jk,Kmm) * vmask(:,:,jk)
[11931]432         ! compute volume flux divergence after coupling
[13295]433         DO_2D( 0, 0, 0, 0 )
[13237]434            zqvoln(ji,jj,jk) =   &
435               &  (   e2u(ji  ,jj  ) * e3u(ji  ,jj  ,jk,Kmm) * uu(ji  ,jj  ,jk,Kmm)    &
436               &    - e2u(ji-1,jj  ) * e3u(ji-1,jj  ,jk,Kmm) * uu(ji-1,jj  ,jk,Kmm)    &
437               &    + e1v(ji  ,jj  ) * e3v(ji  ,jj  ,jk,Kmm) * vv(ji  ,jj  ,jk,Kmm)    &
438               &    - e1v(ji  ,jj-1) * e3v(ji  ,jj-1,jk,Kmm) * vv(ji  ,jj-1,jk,Kmm)  ) &
[12340]439               &               * tmask(ji,jj,jk)
[15085]440            !
441            ! 1.3: get 3d volume flux difference (before - after cpl) (>0 out)
442            !      correction to add is _b - _n
443            risfcpl_vol(ji,jj,jk) = zqvolb(ji,jj,jk) - zqvoln(ji,jj,jk)
[12340]444         END_2D
[11553]445      END DO
446      !
[11931]447      ! 2.0: include the contribution of the vertical velocity in the volume flux correction
448      !
[13295]449      DO_2D( 0, 0, 0, 0 )
[12340]450         !
451         ikt = mikt(ji,jj)
452         IF ( ikt > 1 .AND. ssmask(ji,jj) == 1 ) THEN
453            risfcpl_vol(ji,jj,ikt) = risfcpl_vol(ji,jj,ikt) + SUM(zqvolb(ji,jj,1:ikt-1))  ! test sign
454         ENDIF
455         !
456      END_2D
[11553]457      !
[15085]458      CALL lbc_lnk( 'isfcpl', risfcpl_vol, 'T', 1.0_wp )
[11931]459      !
[12068]460      ! 3.0: set total correction (div, tr(:,:,:,:,Krhs), ssh)
[11931]461      !
462      ! 3.1: mask volume flux divergence correction
[11553]463      risfcpl_vol(:,:,:) = risfcpl_vol(:,:,:) * tmask(:,:,:)
464      !
[12068]465      ! 3.2: get 3d tr(:,:,:,:,Krhs) increment to apply at the first time step
[14072]466      ! temperature and salt content flux computed using local ts(:,:,:,:,Kmm)
[11553]467      ! (very simple advection scheme)
468      ! (>0 out)
[12068]469      risfcpl_tsc(:,:,:,jp_tem) = -risfcpl_vol(:,:,:) * ts(:,:,:,jp_tem,Kmm)
470      risfcpl_tsc(:,:,:,jp_sal) = -risfcpl_vol(:,:,:) * ts(:,:,:,jp_sal,Kmm)
[11553]471      !
[11931]472      ! 3.3: ssh correction (for dynspg_ts)
[11553]473      risfcpl_ssh(:,:) = 0.0
474      DO jk = 1,jpk
475         risfcpl_ssh(:,:) = risfcpl_ssh(:,:) + risfcpl_vol(:,:,jk) * r1_e1e2t(:,:)
476      END DO
[14053]477      !
[11553]478   END SUBROUTINE isfcpl_vol
479
[14072]480
[12068]481   SUBROUTINE isfcpl_cons(Kmm)
[14072]482      !!----------------------------------------------------------------------
[11553]483      !!                   ***  ROUTINE iscpl_cons  ***
[14072]484      !!
[11553]485      !! ** Purpose :   compute the corrective increment in volume/salt/heat to put back the vol/heat/salt
486      !!                removed or added during the coupling processes (wet or dry new cell)
[14072]487      !!
[11553]488      !! ** Method  :   - compare volume/heat/salt before and after
489      !!                - look for the closest wet cells (share amoung neigbourgs if there are)
490      !!                - build the correction increment to applied at each time step
[14072]491      !!
[11553]492      !!----------------------------------------------------------------------
493      !
[11931]494      TYPE(isfcons), DIMENSION(:),ALLOCATABLE :: zisfpts ! list of point receiving a correction
[11553]495      !
[12068]496      !!----------------------------------------------------------------------
497      INTEGER, INTENT(in) :: Kmm    ! ocean time level index
498      !!----------------------------------------------------------------------
[11931]499      INTEGER  ::   ji   , jj  , jk  , jproc          ! loop index
500      INTEGER  ::   jip1 , jim1, jjp1, jjm1           ! dummy indices
501      INTEGER  ::   iig  , ijg, ik                    ! dummy indices
502      INTEGER  ::   jisf                              ! start, end and current position in the increment array
[14072]503      INTEGER  ::   ingb, ifind                       ! 0/1 target found or need to be found
504      INTEGER  ::   nisfl_area                        ! global number of cell concerned by the wet->dry case
[11931]505      INTEGER, DIMENSION(jpnij) :: nisfl              ! local  number of cell concerned by the wet->dry case
[11553]506      !
507      REAL(wp) ::   z1_sum, z1_rdtiscpl
[11931]508      REAL(wp) ::   zdtem, zdsal, zdvol, zratio       ! tem, sal, vol increment
[14072]509      REAL(wp) ::   zlon , zlat                       ! target location
[11931]510      REAL(wp), DIMENSION(jpi,jpj,jpk) :: ztmask_b    ! mask before
511      REAL(wp), DIMENSION(jpi,jpj,jpk) :: ze3t_b      ! scale factor before
512      REAL(wp), DIMENSION(jpi,jpj,jpk) :: zt_b      ! scale factor before
513      REAL(wp), DIMENSION(jpi,jpj,jpk) :: zs_b      ! scale factor before
[11553]514      !!----------------------------------------------------------------------
515
[11931]516      !==============================================================================
517      ! 1.0: initialisation
518      !==============================================================================
519
[11553]520      ! get restart variable
[13970]521      CALL iom_get( numror, jpdom_auto, 'tmask'  , ztmask_b(:,:,:) ) ! need to extrapolate T/S
522      CALL iom_get( numror, jpdom_auto, 'e3t_n'  , ze3t_b(:,:,:)   )
523      CALL iom_get( numror, jpdom_auto, 'tn'     , zt_b(:,:,:)     )
524      CALL iom_get( numror, jpdom_auto, 'sn'     , zs_b(:,:,:)     )
[11553]525
526      ! compute run length
527      nstp_iscpl  = nitend - nit000 + 1
[12489]528      rdt_iscpl   = nstp_iscpl * rn_Dt
[14072]529      z1_rdtiscpl = 1._wp / rdt_iscpl
[11931]530
[11553]531      IF (lwp) WRITE(numout,*) '            nb of stp for cons  = ', nstp_iscpl
532      IF (lwp) WRITE(numout,*) '            coupling time step  = ', rdt_iscpl
533
[11931]534      ! initialisation correction
535      risfcpl_cons_vol = 0.0
536      risfcpl_cons_ssh = 0.0
537      risfcpl_cons_tsc = 0.0
[11553]538
539      !==============================================================================
[11931]540      ! 2.0: diagnose the heat, salt and volume input and compute the correction variable
541      !      for case where we wet a cell or cell still wet (no change in cell status)
[11553]542      !==============================================================================
543
544      DO jk = 1,jpk-1
[13286]545         DO jj = Njs0,Nje0
546            DO ji = Nis0,Nie0
[11553]547
548               ! volume diff
[15062]549               zdvol =   e3t(ji,jj,jk,Kmm) *  tmask  (ji,jj,jk)   &
[13237]550                  &   - ze3t_b(ji,jj,jk    ) * ztmask_b(ji,jj,jk)
[11553]551
552               ! heat diff
[12068]553               zdtem = ts (ji,jj,jk,jp_tem,Kmm) *  e3t(ji,jj,jk,Kmm) *  tmask  (ji,jj,jk)   &
[11931]554                     - zt_b(ji,jj,jk)        * ze3t_b(ji,jj,jk) * ztmask_b(ji,jj,jk)
[11553]555
556               ! salt diff
[12068]557               zdsal = ts(ji,jj,jk,jp_sal,Kmm) *  e3t(ji,jj,jk,Kmm) *  tmask  (ji,jj,jk)   &
[11931]558                     - zs_b(ji,jj,jk)       * ze3t_b(ji,jj,jk) * ztmask_b(ji,jj,jk)
[14072]559
[11553]560               ! volume, heat and salt differences in each cell (>0 means correction is an outward flux)
[11931]561               ! in addition to the geometry change unconservation, need to add the divergence correction as it is flux across the boundary
562               risfcpl_cons_vol(ji,jj,jk)        = (   zdvol * e1e2t(ji,jj) + risfcpl_vol(ji,jj,jk)        ) * z1_rdtiscpl
563               risfcpl_cons_tsc(ji,jj,jk,jp_sal) = ( - zdsal * e1e2t(ji,jj) + risfcpl_tsc(ji,jj,jk,jp_sal) ) * z1_rdtiscpl
564               risfcpl_cons_tsc(ji,jj,jk,jp_tem) = ( - zdtem * e1e2t(ji,jj) + risfcpl_tsc(ji,jj,jk,jp_tem) ) * z1_rdtiscpl
[11553]565
566            END DO
567         END DO
568      END DO
569      !
[11931]570      !==============================================================================
571      ! 3.0: diagnose the heat, salt and volume input and compute the correction variable
572      !      for case where we close a cell
573      !==============================================================================
574      !
[11553]575      ! compute the total number of point receiving a correction increment for each processor
576      ! local
[11931]577      nisfl(:)=0
[11553]578      DO jk = 1,jpk-1
[13286]579         DO jj = Njs0,Nje0
580            DO ji = Nis0,Nie0
[11553]581               jip1=MIN(ji+1,jpi) ; jim1=MAX(ji-1,1) ; jjp1=MIN(jj+1,jpj) ; jjm1=MAX(jj-1,1) ;
[14072]582               IF ( tmask(ji,jj,jk) == 0._wp .AND. ztmask_b(ji,jj,jk) == 1._wp ) THEN
[13237]583                  nisfl(narea) = nisfl(narea) + MAX(SUM(tmask(jim1:jip1,jjm1:jjp1,jk)),1._wp)
584               ENDIF
[11553]585            ENDDO
586         ENDDO
587      ENDDO
588      !
[14072]589      ! global
[11931]590      CALL mpp_sum('isfcpl',nisfl  )
[11553]591      !
592      ! allocate list of point receiving correction
[11931]593      ALLOCATE(zisfpts(nisfl(narea)))
594      !
[11553]595      zisfpts(:) = isfcons(0,0,0,-HUGE(1.0), -HUGE(1.0), -HUGE(1.0), -HUGE(1.0), -HUGE(1.0), 0)
596      !
597      ! start computing the correction and fill zisfpts
598      ! local
[11931]599      jisf = 0
[11553]600      DO jk = 1,jpk-1
[13286]601         DO jj = Njs0,Nje0
602            DO ji = Nis0,Nie0
[11553]603               IF ( tmask(ji,jj,jk) == 0._wp .AND. ztmask_b(ji,jj,jk) == 1._wp ) THEN
604
605                  jip1=MIN(ji+1,jpi) ; jim1=MAX(ji-1,1) ; jjp1=MIN(jj+1,jpj) ; jjm1=MAX(jj-1,1) ;
606
607                  zdvol = risfcpl_cons_vol(ji,jj,jk       )
608                  zdsal = risfcpl_cons_tsc(ji,jj,jk,jp_sal)
609                  zdtem = risfcpl_cons_tsc(ji,jj,jk,jp_tem)
610
611                  IF ( SUM( tmask(jim1:jip1,jjm1:jjp1,jk) ) > 0._wp ) THEN
612                     ! spread correction amoung neigbourg wet cells (horizontal direction first)
613                     ! as it is a rude correction corner and lateral cell have the same weight
614                     !
615                     z1_sum =  1._wp / SUM( tmask(jim1:jip1,jjm1:jjp1,jk) )
616                     !
617                     ! lateral cells
618                     IF (tmask(jip1,jj  ,jk) == 1) CALL update_isfpts(zisfpts, jisf, jip1, jj  , jk, zdvol, zdsal, zdtem, z1_sum)
619                     IF (tmask(jim1,jj  ,jk) == 1) CALL update_isfpts(zisfpts, jisf, jim1, jj  , jk, zdvol, zdsal, zdtem, z1_sum)
620                     IF (tmask(ji  ,jjp1,jk) == 1) CALL update_isfpts(zisfpts, jisf, ji  , jjp1, jk, zdvol, zdsal, zdtem, z1_sum)
621                     IF (tmask(ji  ,jjm1,jk) == 1) CALL update_isfpts(zisfpts, jisf, ji  , jjm1, jk, zdvol, zdsal, zdtem, z1_sum)
622                     !
623                     ! corner  cells
624                     IF (tmask(jip1,jjm1,jk) == 1) CALL update_isfpts(zisfpts, jisf, jip1, jjm1, jk, zdvol, zdsal, zdtem, z1_sum)
625                     IF (tmask(jim1,jjm1,jk) == 1) CALL update_isfpts(zisfpts, jisf, jim1, jjm1, jk, zdvol, zdsal, zdtem, z1_sum)
626                     IF (tmask(jim1,jjp1,jk) == 1) CALL update_isfpts(zisfpts, jisf, jim1, jjp1, jk, zdvol, zdsal, zdtem, z1_sum)
627                     IF (tmask(jip1,jjp1,jk) == 1) CALL update_isfpts(zisfpts, jisf, jip1, jjp1, jk, zdvol, zdsal, zdtem, z1_sum)
628                     !
629                  ELSE IF ( tmask(ji,jj,jk+1) == 1._wp ) THEN
630                     ! spread correction amoung neigbourg wet cells (vertical direction)
[13226]631                     CALL update_isfpts(zisfpts, jisf, ji  , jj  , jk+1, zdvol, zdsal, zdtem, 1.0_wp, 0)
[11553]632                  ELSE
633                     ! need to find where to put correction in later on
[13226]634                     CALL update_isfpts(zisfpts, jisf, ji  , jj  , jk  , zdvol, zdsal, zdtem, 1.0_wp, 1)
[11553]635                  END IF
636               END IF
637            END DO
638         END DO
639      END DO
640      !
641      ! share data among all processes because for some point we need to find the closest wet point (could be on other process)
[11931]642      DO jproc=1,jpnij
[14072]643         !
[11931]644         ! share total number of isf point treated for proc jproc
645         IF (jproc==narea) THEN
646            nisfl_area=nisfl(jproc)
647         ELSE
648            nisfl_area=0
649         END IF
650         CALL mpp_max('isfcpl',nisfl_area)
[11553]651         !
[11931]652         DO jisf = 1,nisfl_area
653            !
654            IF (jproc==narea) THEN
655               ! indices (conversion to global indices and sharing)
656               iig = zisfpts(jisf)%ii       ; ijg = zisfpts(jisf)%jj       ; ik = zisfpts(jisf)%kk
657               !
658               ! data
659               zdvol = zisfpts(jisf)%dvol   ; zdsal = zisfpts(jisf)%dsal   ; zdtem = zisfpts(jisf)%dtem
660               !
661               ! location
662               zlat = zisfpts(jisf)%lat     ; zlon = zisfpts(jisf)%lon
663               !
664               ! find flag
665               ingb = zisfpts(jisf)%ngb
666            ELSE
[14072]667               iig  =0   ; ijg  =0   ; ik   =0
[11931]668               zdvol=-HUGE(1.0) ; zdsal=-HUGE(1.0) ; zdtem=-HUGE(1.0)
[14072]669               zlat =-HUGE(1.0) ; zlon =-HUGE(1.0)
[11931]670               ingb = 0
671            END IF
672            !
673            ! share data (need synchronisation of data as get_correction call a global com)
674            CALL mpp_max('isfcpl',iig)   ; CALL mpp_max('isfcpl',ijg)   ; CALL mpp_max('isfcpl',ik)
675            CALL mpp_max('isfcpl',zdvol) ; CALL mpp_max('isfcpl',zdsal) ; CALL mpp_max('isfcpl',zdtem)
676            CALL mpp_max('isfcpl',zlat)  ; CALL mpp_max('isfcpl',zlon)
677            CALL mpp_max('isfcpl',ingb)
678            !
679            ! fill the 3d correction array
680            CALL get_correction(iig, ijg, ik, zlon, zlat, zdvol, zdsal, zdtem, ingb)
681         END DO
[11553]682      END DO
683      !
[11931]684      !==============================================================================
685      ! 4.0: finalisation and compute ssh equivalent of the volume correction
686      !==============================================================================
687      !
[15004]688      ! mask
[11553]689      risfcpl_cons_vol(:,:,:       ) = risfcpl_cons_vol(:,:,:       ) * tmask(:,:,:)
690      risfcpl_cons_tsc(:,:,:,jp_sal) = risfcpl_cons_tsc(:,:,:,jp_sal) * tmask(:,:,:)
691      risfcpl_cons_tsc(:,:,:,jp_tem) = risfcpl_cons_tsc(:,:,:,jp_tem) * tmask(:,:,:)
692      !
693      ! add lbclnk
[15085]694      CALL lbc_lnk( 'isfcpl', risfcpl_cons_tsc(:,:,:,jp_tem), 'T', 1.0_wp, risfcpl_cons_tsc(:,:,:,jp_sal), 'T', 1.0_wp, &
695         &                    risfcpl_cons_vol(:,:,:)       , 'T', 1.0_wp)
[11553]696      !
697      ! ssh correction (for dynspg_ts)
698      DO jk = 1,jpk
699         risfcpl_cons_ssh(:,:) = risfcpl_cons_ssh(:,:) + risfcpl_cons_vol(:,:,jk)
700      END DO
701      risfcpl_cons_ssh(:,:) = risfcpl_cons_ssh(:,:) * r1_e1e2t(:,:)
702      !
703   END SUBROUTINE isfcpl_cons
704   !
705   SUBROUTINE update_isfpts(sisfpts, kpts, ki, kj, kk, pdvol, pdsal, pdtem, pratio, kfind)
706      !!---------------------------------------------------------------------
707      !!                  ***  ROUTINE update_isfpts  ***
708      !!
709      !! ** Purpose : if a cell become dry, we need to put the corrective increment elsewhere
710      !!
711      !! ** Action  : update the list of point
712      !!
713      !!----------------------------------------------------------------------
714      !!----------------------------------------------------------------------
715      TYPE(isfcons), DIMENSION(:), INTENT(inout) :: sisfpts
[11931]716      INTEGER,                     INTENT(inout) :: kpts
[11553]717      !!----------------------------------------------------------------------
[14072]718      INTEGER,      INTENT(in   )           :: ki, kj, kk                  !    target location (kfind=0)
[11931]719      !                                                                    ! or source location (kfind=1)
720      INTEGER,      INTENT(in   ), OPTIONAL :: kfind                       ! 0  target cell already found
721      !                                                                    ! 1  target to be determined
[14072]722      REAL(wp),     INTENT(in   )           :: pdvol, pdsal, pdtem, pratio ! vol/sal/tem increment
[11931]723      !                                                                    ! and ratio in case increment span over multiple cells.
[11553]724      !!----------------------------------------------------------------------
725      INTEGER :: ifind
726      !!----------------------------------------------------------------------
[14072]727      !
[11553]728      ! increment position
729      kpts = kpts + 1
730      !
731      ! define if we need to look for closest valid wet cell (no neighbours or neigbourg on halo)
732      IF ( PRESENT(kfind) ) THEN
733         ifind = kfind
734      ELSE
735         ifind = ( 1 - tmask_h(ki,kj) ) * tmask(ki,kj,kk)
736      END IF
737      !
738      ! update isfpts structure
739      sisfpts(kpts) = isfcons(mig(ki), mjg(kj), kk, pratio * pdvol, pratio * pdsal, pratio * pdtem, glamt(ki,kj), gphit(ki,kj), ifind )
740      !
741   END SUBROUTINE update_isfpts
742   !
[11931]743   SUBROUTINE get_correction( ki, kj, kk, plon, plat, pvolinc, psalinc, pteminc, kfind)
[11553]744      !!---------------------------------------------------------------------
745      !!                  ***  ROUTINE get_correction  ***
746      !!
747      !! ** Action : - Find the closest valid cell if needed (wet and not on the halo)
748      !!             - Scale the correction depending of pratio (case where multiple wet neigbourgs)
749      !!             - Fill the correction array
750      !!
751      !!----------------------------------------------------------------------
[11931]752      INTEGER , INTENT(in) :: ki, kj, kk, kfind        ! target point indices
753      REAL(wp), INTENT(in) :: plon, plat               ! target point lon/lat
754      REAL(wp), INTENT(in) :: pvolinc, pteminc,psalinc ! correction increment for vol/temp/salt
[11553]755      !!----------------------------------------------------------------------
756      INTEGER :: jj, ji, iig, ijg
757      !!----------------------------------------------------------------------
758      !
759      ! define global indice of correction location
760      iig = ki ; ijg = kj
[11931]761      IF ( kfind == 1 ) CALL dom_ngb( plon, plat, iig, ijg,'T', kk)
[11553]762      !
763      ! fill the correction array
764      DO jj = mj0(ijg),mj1(ijg)
765         DO ji = mi0(iig),mi1(iig)
[11931]766            ! correct the vol_flx and corresponding heat/salt flx in the closest cell
[11553]767            risfcpl_cons_vol(ji,jj,kk)        =  risfcpl_cons_vol(ji,jj,kk       ) + pvolinc
768            risfcpl_cons_tsc(ji,jj,kk,jp_sal) =  risfcpl_cons_tsc(ji,jj,kk,jp_sal) + psalinc
769            risfcpl_cons_tsc(ji,jj,kk,jp_tem) =  risfcpl_cons_tsc(ji,jj,kk,jp_tem) + pteminc
770         END DO
771      END DO
772
773   END SUBROUTINE get_correction
774
775END MODULE isfcpl
Note: See TracBrowser for help on using the repository browser.