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/2020/dev_r13333_KERNEL-08_techene_gm_HPG_SPG/src/OCE/ISF – NEMO

source: NEMO/branches/2020/dev_r13333_KERNEL-08_techene_gm_HPG_SPG/src/OCE/ISF/isfcpl.F90 @ 14037

Last change on this file since 14037 was 14037, checked in by ayoung, 3 years ago

Updated to trunk at 14020. Sette tests passed with change of results for configurations with non-linear ssh. Ticket #2506.

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