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/branches/2019/UKMO_MERGE_2019/src/OCE/ISF – NEMO

source: NEMO/branches/2019/UKMO_MERGE_2019/src/OCE/ISF/isfcpl.F90 @ 12068

Last change on this file since 12068 was 12068, checked in by davestorkey, 4 years ago

2019/UKMO_MERGE_2019 : Merging in changes from ENHANCE-02_ISF_nemo.

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