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.
traadv_fct.F90 in branches/2017/dev_r7881_no_wrk_alloc/NEMOGCM/NEMO/OPA_SRC/TRA – NEMO

source: branches/2017/dev_r7881_no_wrk_alloc/NEMOGCM/NEMO/OPA_SRC/TRA/traadv_fct.F90 @ 7910

Last change on this file since 7910 was 7910, checked in by timgraham, 7 years ago

All wrk_alloc removed

  • Property svn:keywords set to Id
File size: 47.9 KB
Line 
1MODULE traadv_fct
2   !!==============================================================================
3   !!                       ***  MODULE  traadv_fct  ***
4   !! Ocean  tracers:  horizontal & vertical advective trend (2nd/4th order Flux Corrected Transport method)
5   !!==============================================================================
6   !! History :  3.7  !  2015-09  (L. Debreu, G. Madec)  original code (inspired from traadv_tvd.F90)
7   !!----------------------------------------------------------------------
8
9   !!----------------------------------------------------------------------
10   !!  tra_adv_fct    : update the tracer trend with a 3D advective trends using a 2nd or 4th order FCT scheme
11   !!  tra_adv_fct_zts: update the tracer trend with a 3D advective trends using a 2nd order FCT scheme
12   !!                   with sub-time-stepping in the vertical direction
13   !!  nonosc         : compute monotonic tracer fluxes by a non-oscillatory algorithm
14   !!  interp_4th_cpt : 4th order compact scheme for the vertical component of the advection
15   !!----------------------------------------------------------------------
16   USE oce            ! ocean dynamics and active tracers
17   USE dom_oce        ! ocean space and time domain
18   USE trc_oce        ! share passive tracers/Ocean variables
19   USE trd_oce        ! trends: ocean variables
20   USE trdtra         ! tracers trends
21   USE diaptr         ! poleward transport diagnostics
22   USE diaar5         ! AR5 diagnostics
23   USE phycst, ONLY: rau0_rcp
24   !
25   USE in_out_manager ! I/O manager
26   USE iom
27   USE lib_mpp        ! MPP library
28   USE lbclnk         ! ocean lateral boundary condition (or mpp link)
29   USE lib_fortran    ! Fortran utilities (allows no signed zero when 'key_nosignedzero' defined) 
30   USE timing         ! Timing
31
32   IMPLICIT NONE
33   PRIVATE
34
35   PUBLIC   tra_adv_fct        ! routine called by traadv.F90
36   PUBLIC   tra_adv_fct_zts    ! routine called by traadv.F90
37   PUBLIC   interp_4th_cpt     ! routine called by traadv_cen.F90
38
39   LOGICAL  ::   l_trd   ! flag to compute trends
40   LOGICAL  ::   l_ptr   ! flag to compute poleward transport
41   LOGICAL  ::   l_hst   ! flag to compute heat/salt transport
42   REAL(wp) ::   r1_6 = 1._wp / 6._wp   ! =1/6
43
44   !                                        ! tridiag solver associated indices:
45   INTEGER, PARAMETER ::   np_NH   = 0   ! Neumann homogeneous boundary condition
46   INTEGER, PARAMETER ::   np_CEN2 = 1   ! 2nd order centered  boundary condition
47
48   !! * Substitutions
49#  include "vectopt_loop_substitute.h90"
50   !!----------------------------------------------------------------------
51   !! NEMO/OPA 3.7 , NEMO Consortium (2014)
52   !! $Id$
53   !! Software governed by the CeCILL licence     (NEMOGCM/NEMO_CeCILL.txt)
54   !!----------------------------------------------------------------------
55CONTAINS
56
57   SUBROUTINE tra_adv_fct( kt, kit000, cdtype, p2dt, pun, pvn, pwn,       &
58      &                                              ptb, ptn, pta, kjpt, kn_fct_h, kn_fct_v )
59      !!----------------------------------------------------------------------
60      !!                  ***  ROUTINE tra_adv_fct  ***
61      !!
62      !! **  Purpose :   Compute the now trend due to total advection of tracers
63      !!               and add it to the general trend of tracer equations
64      !!
65      !! **  Method  : - 2nd or 4th FCT scheme on the horizontal direction
66      !!               (choice through the value of kn_fct)
67      !!               - on the vertical the 4th order is a compact scheme
68      !!               - corrected flux (monotonic correction)
69      !!
70      !! ** Action : - update pta  with the now advective tracer trends
71      !!             - send trends to trdtra module for further diagnostcs (l_trdtra=T)
72      !!             - htr_adv, str_adv : poleward advective heat and salt transport (ln_diaptr=T)
73      !!----------------------------------------------------------------------
74      INTEGER                              , INTENT(in   ) ::   kt              ! ocean time-step index
75      INTEGER                              , INTENT(in   ) ::   kit000          ! first time step index
76      CHARACTER(len=3)                     , INTENT(in   ) ::   cdtype          ! =TRA or TRC (tracer indicator)
77      INTEGER                              , INTENT(in   ) ::   kjpt            ! number of tracers
78      INTEGER                              , INTENT(in   ) ::   kn_fct_h        ! order of the FCT scheme (=2 or 4)
79      INTEGER                              , INTENT(in   ) ::   kn_fct_v        ! order of the FCT scheme (=2 or 4)
80      REAL(wp)                             , INTENT(in   ) ::   p2dt            ! tracer time-step
81      REAL(wp), DIMENSION(jpi,jpj,jpk     ), INTENT(in   ) ::   pun, pvn, pwn   ! 3 ocean velocity components
82      REAL(wp), DIMENSION(jpi,jpj,jpk,kjpt), INTENT(in   ) ::   ptb, ptn        ! before and now tracer fields
83      REAL(wp), DIMENSION(jpi,jpj,jpk,kjpt), INTENT(inout) ::   pta             ! tracer trend
84      !
85      INTEGER  ::   ji, jj, jk, jn                           ! dummy loop indices 
86      REAL(wp) ::   ztra                                     ! local scalar
87      REAL(wp) ::   zfp_ui, zfp_vj, zfp_wk, zC2t_u, zC4t_u   !   -      -
88      REAL(wp) ::   zfm_ui, zfm_vj, zfm_wk, zC2t_v, zC4t_v   !   -      -
89      REAL(wp), DIMENSION(jpi,jpj,jpk) ::   zwi, zwx, zwy, zwz, ztu, ztv, zltu, zltv, ztw
90      REAL(wp), DIMENSION(jpi,jpj,jpk) ::   ztrdx, ztrdy, ztrdz, zptry
91      REAL(wp), POINTER, DIMENSION(:,:)   :: z2d
92      !!----------------------------------------------------------------------
93      !
94      IF( nn_timing == 1 )  CALL timing_start('tra_adv_fct')
95      !
96      !
97      IF( kt == kit000 )  THEN
98         IF(lwp) WRITE(numout,*)
99         IF(lwp) WRITE(numout,*) 'tra_adv_fct : FCT advection scheme on ', cdtype
100         IF(lwp) WRITE(numout,*) '~~~~~~~~~~~'
101      ENDIF
102      !
103      l_trd = .FALSE.
104      l_hst = .FALSE.
105      l_ptr = .FALSE.
106      IF( ( cdtype == 'TRA'   .AND. l_trdtra ) .OR. ( cdtype == 'TRC' .AND. l_trdtrc ) )     l_trd = .TRUE.
107      IF(   cdtype == 'TRA'   .AND. ln_diaptr )                                              l_ptr = .TRUE. 
108      IF(   cdtype == 'TRA' .AND. ( iom_use("uadv_heattr") .OR. iom_use("vadv_heattr") .OR. &
109         &                          iom_use("uadv_salttr") .OR. iom_use("vadv_salttr")  ) )  l_hst = .TRUE.
110      !
111      IF( l_trd .OR. l_hst )  THEN
112         ztrdx(:,:,:) = 0._wp   ;    ztrdy(:,:,:) = 0._wp   ;   ztrdz(:,:,:) = 0._wp
113      ENDIF
114      !
115      IF( l_ptr ) THEN 
116         zptry(:,:,:) = 0._wp
117      ENDIF
118      !                          ! surface & bottom value : flux set to zero one for all
119      zwz(:,:, 1 ) = 0._wp           
120      zwx(:,:,jpk) = 0._wp   ;   zwy(:,:,jpk) = 0._wp    ;    zwz(:,:,jpk) = 0._wp
121      !
122      zwi(:,:,:) = 0._wp       
123      !
124      DO jn = 1, kjpt            !==  loop over the tracers  ==!
125         !
126         !        !==  upstream advection with initial mass fluxes & intermediate update  ==!
127         !                    !* upstream tracer flux in the i and j direction
128         DO jk = 1, jpkm1
129            DO jj = 1, jpjm1
130               DO ji = 1, fs_jpim1   ! vector opt.
131                  ! upstream scheme
132                  zfp_ui = pun(ji,jj,jk) + ABS( pun(ji,jj,jk) )
133                  zfm_ui = pun(ji,jj,jk) - ABS( pun(ji,jj,jk) )
134                  zfp_vj = pvn(ji,jj,jk) + ABS( pvn(ji,jj,jk) )
135                  zfm_vj = pvn(ji,jj,jk) - ABS( pvn(ji,jj,jk) )
136                  zwx(ji,jj,jk) = 0.5 * ( zfp_ui * ptb(ji,jj,jk,jn) + zfm_ui * ptb(ji+1,jj  ,jk,jn) )
137                  zwy(ji,jj,jk) = 0.5 * ( zfp_vj * ptb(ji,jj,jk,jn) + zfm_vj * ptb(ji  ,jj+1,jk,jn) )
138               END DO
139            END DO
140         END DO
141         !                    !* upstream tracer flux in the k direction *!
142         DO jk = 2, jpkm1        ! Interior value ( multiplied by wmask)
143            DO jj = 1, jpj
144               DO ji = 1, jpi
145                  zfp_wk = pwn(ji,jj,jk) + ABS( pwn(ji,jj,jk) )
146                  zfm_wk = pwn(ji,jj,jk) - ABS( pwn(ji,jj,jk) )
147                  zwz(ji,jj,jk) = 0.5 * ( zfp_wk * ptb(ji,jj,jk,jn) + zfm_wk * ptb(ji,jj,jk-1,jn) ) * wmask(ji,jj,jk)
148               END DO
149            END DO
150         END DO
151         IF( ln_linssh ) THEN    ! top ocean value (only in linear free surface as zwz has been w-masked)
152            IF( ln_isfcav ) THEN             ! top of the ice-shelf cavities and at the ocean surface
153               DO jj = 1, jpj
154                  DO ji = 1, jpi
155                     zwz(ji,jj, mikt(ji,jj) ) = pwn(ji,jj,mikt(ji,jj)) * ptb(ji,jj,mikt(ji,jj),jn)   ! linear free surface
156                  END DO
157               END DO   
158            ELSE                             ! no cavities: only at the ocean surface
159               zwz(:,:,1) = pwn(:,:,1) * ptb(:,:,1,jn)
160            ENDIF
161         ENDIF
162         !               
163         DO jk = 1, jpkm1     !* trend and after field with monotonic scheme
164            DO jj = 2, jpjm1
165               DO ji = fs_2, fs_jpim1   ! vector opt.
166                  !                             ! total intermediate advective trends
167                  ztra = - (  zwx(ji,jj,jk) - zwx(ji-1,jj  ,jk  )   &
168                     &      + zwy(ji,jj,jk) - zwy(ji  ,jj-1,jk  )   &
169                     &      + zwz(ji,jj,jk) - zwz(ji  ,jj  ,jk+1) ) * r1_e1e2t(ji,jj)
170                  !                             ! update and guess with monotonic sheme
171                  pta(ji,jj,jk,jn) =                     pta(ji,jj,jk,jn) +        ztra   / e3t_n(ji,jj,jk) * tmask(ji,jj,jk)
172                  zwi(ji,jj,jk)    = ( e3t_b(ji,jj,jk) * ptb(ji,jj,jk,jn) + p2dt * ztra ) / e3t_a(ji,jj,jk) * tmask(ji,jj,jk)
173               END DO
174            END DO
175         END DO
176         CALL lbc_lnk( zwi, 'T', 1. )  ! Lateral boundary conditions on zwi  (unchanged sign)
177         !               
178         IF( l_trd .OR. l_hst )  THEN             ! trend diagnostics (contribution of upstream fluxes)
179            ztrdx(:,:,:) = zwx(:,:,:)   ;   ztrdy(:,:,:) = zwy(:,:,:)   ;   ztrdz(:,:,:) = zwz(:,:,:)
180         END IF
181         !                             ! "Poleward" heat and salt transports (contribution of upstream fluxes)
182         IF( l_ptr )  zptry(:,:,:) = zwy(:,:,:) 
183         !
184         !        !==  anti-diffusive flux : high order minus low order  ==!
185         !
186         SELECT CASE( kn_fct_h )    !* horizontal anti-diffusive fluxes
187         !
188         CASE(  2  )                   !- 2nd order centered
189            DO jk = 1, jpkm1
190               DO jj = 1, jpjm1
191                  DO ji = 1, fs_jpim1   ! vector opt.
192                     zwx(ji,jj,jk) = 0.5_wp * pun(ji,jj,jk) * ( ptn(ji,jj,jk,jn) + ptn(ji+1,jj,jk,jn) ) - zwx(ji,jj,jk)
193                     zwy(ji,jj,jk) = 0.5_wp * pvn(ji,jj,jk) * ( ptn(ji,jj,jk,jn) + ptn(ji,jj+1,jk,jn) ) - zwy(ji,jj,jk)
194                  END DO
195               END DO
196            END DO
197            !
198         CASE(  4  )                   !- 4th order centered
199            zltu(:,:,jpk) = 0._wp            ! Bottom value : flux set to zero
200            zltv(:,:,jpk) = 0._wp
201            DO jk = 1, jpkm1                 ! Laplacian
202               DO jj = 1, jpjm1                    ! 1st derivative (gradient)
203                  DO ji = 1, fs_jpim1   ! vector opt.
204                     ztu(ji,jj,jk) = ( ptn(ji+1,jj  ,jk,jn) - ptn(ji,jj,jk,jn) ) * umask(ji,jj,jk)
205                     ztv(ji,jj,jk) = ( ptn(ji  ,jj+1,jk,jn) - ptn(ji,jj,jk,jn) ) * vmask(ji,jj,jk)
206                  END DO
207               END DO
208               DO jj = 2, jpjm1                    ! 2nd derivative * 1/ 6
209                  DO ji = fs_2, fs_jpim1   ! vector opt.
210                     zltu(ji,jj,jk) = (  ztu(ji,jj,jk) + ztu(ji-1,jj,jk)  ) * r1_6
211                     zltv(ji,jj,jk) = (  ztv(ji,jj,jk) + ztv(ji,jj-1,jk)  ) * r1_6
212                  END DO
213               END DO
214            END DO
215            CALL lbc_lnk( zltu, 'T', 1. )   ;    CALL lbc_lnk( zltv, 'T', 1. )   ! Lateral boundary cond. (unchanged sgn)
216            !
217            DO jk = 1, jpkm1                 ! Horizontal advective fluxes
218               DO jj = 1, jpjm1
219                  DO ji = 1, fs_jpim1   ! vector opt.
220                     zC2t_u = ptn(ji,jj,jk,jn) + ptn(ji+1,jj  ,jk,jn)   ! 2 x C2 interpolation of T at u- & v-points
221                     zC2t_v = ptn(ji,jj,jk,jn) + ptn(ji  ,jj+1,jk,jn)
222                     !                                                  ! C4 minus upstream advective fluxes
223                     zwx(ji,jj,jk) =  0.5_wp * pun(ji,jj,jk) * ( zC2t_u + zltu(ji,jj,jk) - zltu(ji+1,jj,jk) ) - zwx(ji,jj,jk)
224                     zwy(ji,jj,jk) =  0.5_wp * pvn(ji,jj,jk) * ( zC2t_v + zltv(ji,jj,jk) - zltv(ji,jj+1,jk) ) - zwy(ji,jj,jk)
225                  END DO
226               END DO
227            END DO         
228            !
229         CASE(  41 )                   !- 4th order centered       ==>>   !!gm coding attempt   need to be tested
230            ztu(:,:,jpk) = 0._wp             ! Bottom value : flux set to zero
231            ztv(:,:,jpk) = 0._wp
232            DO jk = 1, jpkm1                 ! 1st derivative (gradient)
233               DO jj = 1, jpjm1
234                  DO ji = 1, fs_jpim1   ! vector opt.
235                     ztu(ji,jj,jk) = ( ptn(ji+1,jj  ,jk,jn) - ptn(ji,jj,jk,jn) ) * umask(ji,jj,jk)
236                     ztv(ji,jj,jk) = ( ptn(ji  ,jj+1,jk,jn) - ptn(ji,jj,jk,jn) ) * vmask(ji,jj,jk)
237                  END DO
238               END DO
239            END DO
240            CALL lbc_lnk( ztu, 'U', -1. )   ;    CALL lbc_lnk( ztv, 'V', -1. )   ! Lateral boundary cond. (unchanged sgn)
241            !
242            DO jk = 1, jpkm1                 ! Horizontal advective fluxes
243               DO jj = 2, jpjm1
244                  DO ji = 2, fs_jpim1   ! vector opt.
245                     zC2t_u = ptn(ji,jj,jk,jn) + ptn(ji+1,jj  ,jk,jn)   ! 2 x C2 interpolation of T at u- & v-points (x2)
246                     zC2t_v = ptn(ji,jj,jk,jn) + ptn(ji  ,jj+1,jk,jn)
247                     !                                                  ! C4 interpolation of T at u- & v-points (x2)
248                     zC4t_u =  zC2t_u + r1_6 * ( ztu(ji-1,jj  ,jk) - ztu(ji+1,jj  ,jk) )
249                     zC4t_v =  zC2t_v + r1_6 * ( ztv(ji  ,jj-1,jk) - ztv(ji  ,jj+1,jk) )
250                     !                                                  ! C4 minus upstream advective fluxes
251                     zwx(ji,jj,jk) =  0.5_wp * pun(ji,jj,jk) * zC4t_u - zwx(ji,jj,jk)
252                     zwy(ji,jj,jk) =  0.5_wp * pvn(ji,jj,jk) * zC4t_v - zwy(ji,jj,jk)
253                  END DO
254               END DO
255            END DO
256            !
257         END SELECT
258         !                     
259         SELECT CASE( kn_fct_v )    !* vertical anti-diffusive fluxes (w-masked interior values)
260         !
261         CASE(  2  )                   !- 2nd order centered
262            DO jk = 2, jpkm1   
263               DO jj = 2, jpjm1
264                  DO ji = fs_2, fs_jpim1
265                     zwz(ji,jj,jk) =  (  pwn(ji,jj,jk) * 0.5_wp * ( ptn(ji,jj,jk,jn) + ptn(ji,jj,jk-1,jn) )   &
266                        &              - zwz(ji,jj,jk)  ) * wmask(ji,jj,jk)
267                  END DO
268               END DO
269            END DO
270            !
271         CASE(  4  )                   !- 4th order COMPACT
272            CALL interp_4th_cpt( ptn(:,:,:,jn) , ztw )   ! zwt = COMPACT interpolation of T at w-point
273            DO jk = 2, jpkm1
274               DO jj = 2, jpjm1
275                  DO ji = fs_2, fs_jpim1
276                     zwz(ji,jj,jk) = ( pwn(ji,jj,jk) * ztw(ji,jj,jk) - zwz(ji,jj,jk) ) * wmask(ji,jj,jk)
277                  END DO
278               END DO
279            END DO
280            !
281         END SELECT
282         IF( ln_linssh ) THEN    ! top ocean value: high order = upstream  ==>>  zwz=0
283            zwz(:,:,1) = 0._wp   ! only ocean surface as interior zwz values have been w-masked
284         ENDIF
285         !
286         CALL lbc_lnk( zwx, 'U', -1. )   ;   CALL lbc_lnk( zwy, 'V', -1. )         ! Lateral bondary conditions
287         CALL lbc_lnk( zwz, 'W',  1. )
288         !
289         !        !==  monotonicity algorithm  ==!
290         !
291         CALL nonosc( ptb(:,:,:,jn), zwx, zwy, zwz, zwi, p2dt )
292         !
293         !        !==  final trend with corrected fluxes  ==!
294         !
295         DO jk = 1, jpkm1
296            DO jj = 2, jpjm1
297               DO ji = fs_2, fs_jpim1   ! vector opt. 
298                  pta(ji,jj,jk,jn) = pta(ji,jj,jk,jn) - (  zwx(ji,jj,jk) - zwx(ji-1,jj  ,jk  )   &
299                     &                                   + zwy(ji,jj,jk) - zwy(ji  ,jj-1,jk  )   &
300                     &                                   + zwz(ji,jj,jk) - zwz(ji  ,jj  ,jk+1) ) &
301                     &                                * r1_e1e2t(ji,jj) / e3t_n(ji,jj,jk)
302               END DO
303            END DO
304         END DO
305         !
306         IF( l_trd .OR. l_hst ) THEN     ! trend diagnostics (contribution of upstream fluxes)
307            ztrdx(:,:,:) = ztrdx(:,:,:) + zwx(:,:,:)  ! <<< Add to previously computed
308            ztrdy(:,:,:) = ztrdy(:,:,:) + zwy(:,:,:)  ! <<< Add to previously computed
309            ztrdz(:,:,:) = ztrdz(:,:,:) + zwz(:,:,:)  ! <<< Add to previously computed
310         ENDIF
311            !
312         IF( l_trd ) THEN
313            CALL trd_tra( kt, cdtype, jn, jptra_xad, ztrdx, pun, ptn(:,:,:,jn) )
314            CALL trd_tra( kt, cdtype, jn, jptra_yad, ztrdy, pvn, ptn(:,:,:,jn) )
315            CALL trd_tra( kt, cdtype, jn, jptra_zad, ztrdz, pwn, ptn(:,:,:,jn) )
316            !
317         END IF
318         !                                !  heat/salt transport
319         IF( l_hst )  CALL dia_ar5_hst( jn, 'adv', ztrdx(:,:,:), ztrdy(:,:,:) )
320
321         !                                ! "Poleward" heat and salt transports (contribution of upstream fluxes)
322         IF( l_ptr ) THEN 
323            zptry(:,:,:) = zptry(:,:,:) + zwy(:,:,:)  ! <<< Add to previously computed
324            CALL dia_ptr_hst( jn, 'adv', zptry(:,:,:) )
325         ENDIF
326         !
327      END DO                     ! end of tracer loop
328      !
329      !
330      IF( nn_timing == 1 )  CALL timing_stop('tra_adv_fct')
331      !
332   END SUBROUTINE tra_adv_fct
333
334
335   SUBROUTINE tra_adv_fct_zts( kt, kit000, cdtype, p2dt, pun, pvn, pwn,      &
336      &                                                  ptb, ptn, pta, kjpt, kn_fct_zts )
337      !!----------------------------------------------------------------------
338      !!                  ***  ROUTINE tra_adv_fct_zts  ***
339      !!
340      !! **  Purpose :   Compute the now trend due to total advection of
341      !!       tracers and add it to the general trend of tracer equations
342      !!
343      !! **  Method  :   TVD ZTS scheme, i.e. 2nd order centered scheme with
344      !!       corrected flux (monotonic correction). This version use sub-
345      !!       timestepping for the vertical advection which increases stability
346      !!       when vertical metrics are small.
347      !!       note: - this advection scheme needs a leap-frog time scheme
348      !!
349      !! ** Action : - update (pta) with the now advective tracer trends
350      !!             - save the trends
351      !!----------------------------------------------------------------------
352      INTEGER                              , INTENT(in   ) ::   kt              ! ocean time-step index
353      INTEGER                              , INTENT(in   ) ::   kit000          ! first time step index
354      CHARACTER(len=3)                     , INTENT(in   ) ::   cdtype          ! =TRA or TRC (tracer indicator)
355      INTEGER                              , INTENT(in   ) ::   kjpt            ! number of tracers
356      INTEGER                              , INTENT(in   ) ::   kn_fct_zts      ! number of number of vertical sub-timesteps
357      REAL(wp)                             , INTENT(in   ) ::   p2dt            ! tracer time-step
358      REAL(wp), DIMENSION(jpi,jpj,jpk     ), INTENT(in   ) ::   pun, pvn, pwn   ! 3 ocean velocity components
359      REAL(wp), DIMENSION(jpi,jpj,jpk,kjpt), INTENT(in   ) ::   ptb, ptn        ! before and now tracer fields
360      REAL(wp), DIMENSION(jpi,jpj,jpk,kjpt), INTENT(inout) ::   pta             ! tracer trend
361      !
362      REAL(wp), DIMENSION( jpk )                           ::   zts             ! length of sub-timestep for vertical advection
363      REAL(wp)                                             ::   zr_p2dt         ! reciprocal of tracer timestep
364      INTEGER  ::   ji, jj, jk, jl, jn       ! dummy loop indices 
365      INTEGER  ::   jtb, jtn, jta   ! sub timestep pointers for leap-frog/euler forward steps
366      INTEGER  ::   jtaken          ! toggle for collecting appropriate fluxes from sub timesteps
367      REAL(wp) ::   z_rzts          ! Fractional length of Euler forward sub-timestep for vertical advection
368      REAL(wp) ::   ztra            ! local scalar
369      REAL(wp) ::   zfp_ui, zfp_vj, zfp_wk   !   -      -
370      REAL(wp) ::   zfm_ui, zfm_vj, zfm_wk   !   -      -
371      REAL(wp), DIMENSION(jpi,jpj)   ::   zwx_sav , zwy_sav
372      REAL(wp), DIMENSION(jpi,jpj,jpk)   ::   zwi, zwx, zwy, zwz, zhdiv, zwzts, zwz_sav
373      REAL(wp), DIMENSION(jpi,jpj,jpk)   ::   ztrdx, ztrdy, ztrdz
374      REAL(wp), DIMENSION(jpi,jpj,jpk) :: zptry
375      REAL(wp), DIMENSION(jpi,jpj,jpk,kjpt+1) ::   ztrs
376      !!----------------------------------------------------------------------
377      !
378      IF( nn_timing == 1 )  CALL timing_start('tra_adv_fct_zts')
379      !
380      !
381      IF( kt == kit000 )  THEN
382         IF(lwp) WRITE(numout,*)
383         IF(lwp) WRITE(numout,*) 'tra_adv_fct_zts : 2nd order FCT scheme with ', kn_fct_zts, ' vertical sub-timestep on ', cdtype
384         IF(lwp) WRITE(numout,*) '~~~~~~~~~~~'
385      ENDIF
386      !
387      l_trd = .FALSE.
388      l_hst = .FALSE.
389      l_ptr = .FALSE.
390      IF( ( cdtype == 'TRA' .AND. l_trdtra ) .OR. ( cdtype == 'TRC' .AND. l_trdtrc ) )      l_trd = .TRUE.
391      IF(   cdtype == 'TRA' .AND. ln_diaptr )                                               l_ptr = .TRUE. 
392      IF(   cdtype == 'TRA' .AND. ( iom_use("uadv_heattr") .OR. iom_use("vadv_heattr") .OR. &
393         &                          iom_use("uadv_salttr") .OR. iom_use("vadv_salttr")  ) ) l_hst = .TRUE.
394      !
395      IF( l_trd .OR. l_hst )  THEN
396         ztrdx(:,:,:) = 0._wp  ;    ztrdy(:,:,:) = 0._wp  ;   ztrdz(:,:,:) = 0._wp
397      ENDIF
398      !
399      IF( l_ptr ) THEN 
400         zptry(:,:,:) = 0._wp
401      ENDIF
402      zwi(:,:,:) = 0._wp
403      z_rzts = 1._wp / REAL( kn_fct_zts, wp )
404      zr_p2dt = 1._wp / p2dt
405      !
406      ! surface & Bottom value : flux set to zero for all tracers
407      zwz(:,:, 1 ) = 0._wp
408      zwx(:,:,jpk) = 0._wp   ;    zwz(:,:,jpk) = 0._wp
409      zwy(:,:,jpk) = 0._wp   ;    zwi(:,:,jpk) = 0._wp
410      !
411      !                                                          ! ===========
412      DO jn = 1, kjpt                                            ! tracer loop
413         !                                                       ! ===========
414         !
415         ! Upstream advection with initial mass fluxes & intermediate update
416         DO jk = 1, jpkm1        ! upstream tracer flux in the i and j direction
417            DO jj = 1, jpjm1
418               DO ji = 1, fs_jpim1   ! vector opt.
419                  ! upstream scheme
420                  zfp_ui = pun(ji,jj,jk) + ABS( pun(ji,jj,jk) )
421                  zfm_ui = pun(ji,jj,jk) - ABS( pun(ji,jj,jk) )
422                  zfp_vj = pvn(ji,jj,jk) + ABS( pvn(ji,jj,jk) )
423                  zfm_vj = pvn(ji,jj,jk) - ABS( pvn(ji,jj,jk) )
424                  zwx(ji,jj,jk) = 0.5_wp * ( zfp_ui * ptb(ji,jj,jk,jn) + zfm_ui * ptb(ji+1,jj  ,jk,jn) )
425                  zwy(ji,jj,jk) = 0.5_wp * ( zfp_vj * ptb(ji,jj,jk,jn) + zfm_vj * ptb(ji  ,jj+1,jk,jn) )
426               END DO
427            END DO
428         END DO
429         !                       ! upstream tracer flux in the k direction
430         DO jk = 2, jpkm1              ! Interior value
431            DO jj = 1, jpj
432               DO ji = 1, jpi
433                  zfp_wk = pwn(ji,jj,jk) + ABS( pwn(ji,jj,jk) )
434                  zfm_wk = pwn(ji,jj,jk) - ABS( pwn(ji,jj,jk) )
435                  zwz(ji,jj,jk) = 0.5_wp * ( zfp_wk * ptb(ji,jj,jk,jn) + zfm_wk * ptb(ji,jj,jk-1,jn) ) * wmask(ji,jj,jk)
436               END DO
437            END DO
438         END DO
439         IF( ln_linssh ) THEN          ! top value : linear free surface case only (as zwz is multiplied by wmask)
440            IF( ln_isfcav ) THEN             ! ice-shelf cavities: top value
441               DO jj = 1, jpj
442                  DO ji = 1, jpi
443                     zwz(ji,jj, mikt(ji,jj) ) = pwn(ji,jj,mikt(ji,jj)) * ptb(ji,jj,mikt(ji,jj),jn) 
444                  END DO
445               END DO   
446            ELSE                             ! no cavities, surface value
447               zwz(:,:,1) = pwn(:,:,1) * ptb(:,:,1,jn)
448            ENDIF
449         ENDIF
450         !
451         DO jk = 1, jpkm1         ! total advective trend
452            DO jj = 2, jpjm1
453               DO ji = fs_2, fs_jpim1   ! vector opt.
454                  !                             ! total intermediate advective trends
455                  ztra = - (  zwx(ji,jj,jk) - zwx(ji-1,jj  ,jk  )   &
456                     &      + zwy(ji,jj,jk) - zwy(ji  ,jj-1,jk  )   &
457                     &      + zwz(ji,jj,jk) - zwz(ji  ,jj  ,jk+1)   ) * r1_e1e2t(ji,jj)
458                  !                             ! update and guess with monotonic sheme
459                  pta(ji,jj,jk,jn) =                     pta(ji,jj,jk,jn) +        ztra   / e3t_n(ji,jj,jk) * tmask(ji,jj,jk)
460                  zwi(ji,jj,jk)    = ( e3t_b(ji,jj,jk) * ptb(ji,jj,jk,jn) + p2dt * ztra ) / e3t_a(ji,jj,jk) * tmask(ji,jj,jk)
461               END DO
462            END DO
463         END DO
464         !                           
465         CALL lbc_lnk( zwi, 'T', 1. )     ! Lateral boundary conditions on zwi  (unchanged sign)
466         !               
467         IF( l_trd .OR. l_hst )  THEN                ! trend diagnostics (contribution of upstream fluxes)
468            ztrdx(:,:,:) = zwx(:,:,:)   ;    ztrdy(:,:,:) = zwy(:,:,:)  ;   ztrdz(:,:,:) = zwz(:,:,:)
469         END IF
470         !                                ! "Poleward" heat and salt transports (contribution of upstream fluxes)
471         IF( l_ptr )  zptry(:,:,:) = zwy(:,:,:)
472
473         ! 3. anti-diffusive flux : high order minus low order
474         ! ---------------------------------------------------
475
476         DO jk = 1, jpkm1                    !* horizontal anti-diffusive fluxes
477            !
478            DO jj = 1, jpjm1
479               DO ji = 1, fs_jpim1   ! vector opt.
480                  zwx_sav(ji,jj) = zwx(ji,jj,jk)
481                  zwy_sav(ji,jj) = zwy(ji,jj,jk)
482                  !
483                  zwx(ji,jj,jk) = 0.5_wp * pun(ji,jj,jk) * ( ptn(ji,jj,jk,jn) + ptn(ji+1,jj,jk,jn) )
484                  zwy(ji,jj,jk) = 0.5_wp * pvn(ji,jj,jk) * ( ptn(ji,jj,jk,jn) + ptn(ji,jj+1,jk,jn) )
485               END DO
486            END DO
487            !
488            DO jj = 2, jpjm1                    ! partial horizontal divergence
489               DO ji = fs_2, fs_jpim1
490                  zhdiv(ji,jj,jk) = (  zwx(ji,jj,jk) - zwx(ji-1,jj  ,jk)   &
491                     &               + zwy(ji,jj,jk) - zwy(ji  ,jj-1,jk)  )
492               END DO
493            END DO
494            !
495            DO jj = 1, jpjm1
496               DO ji = 1, fs_jpim1   ! vector opt.
497                  zwx(ji,jj,jk) = zwx(ji,jj,jk) - zwx_sav(ji,jj)
498                  zwy(ji,jj,jk) = zwy(ji,jj,jk) - zwy_sav(ji,jj)
499               END DO
500            END DO
501         END DO
502         !
503         !                                !* vertical anti-diffusive flux
504         zwz_sav(:,:,:)   = zwz(:,:,:)
505         ztrs   (:,:,:,1) = ptb(:,:,:,jn)
506         ztrs   (:,:,1,2) = ptb(:,:,1,jn)
507         ztrs   (:,:,1,3) = ptb(:,:,1,jn)
508         zwzts  (:,:,:)   = 0._wp
509         !
510         DO jl = 1, kn_fct_zts                  ! Start of sub timestepping loop
511            !
512            IF( jl == 1 ) THEN                        ! Euler forward to kick things off
513               jtb = 1   ;   jtn = 1   ;   jta = 2
514               zts(:) = p2dt * z_rzts
515               jtaken = MOD( kn_fct_zts + 1 , 2)            ! Toggle to collect every second flux
516               !                                            ! starting at jl =1 if kn_fct_zts is odd;
517               !                                            ! starting at jl =2 otherwise
518            ELSEIF( jl == 2 ) THEN                    ! First leapfrog step
519               jtb = 1   ;   jtn = 2   ;   jta = 3
520               zts(:) = 2._wp * p2dt * z_rzts
521            ELSE                                      ! Shuffle pointers for subsequent leapfrog steps
522               jtb = MOD(jtb,3) + 1
523               jtn = MOD(jtn,3) + 1
524               jta = MOD(jta,3) + 1
525            ENDIF
526            DO jk = 2, jpkm1                          ! interior value
527               DO jj = 2, jpjm1
528                  DO ji = fs_2, fs_jpim1
529                     zwz(ji,jj,jk) = 0.5_wp * pwn(ji,jj,jk) * ( ztrs(ji,jj,jk,jtn) + ztrs(ji,jj,jk-1,jtn) ) * wmask(ji,jj,jk)
530                     IF( jtaken == 0 )   zwzts(ji,jj,jk) = zwzts(ji,jj,jk) + zwz(ji,jj,jk) * zts(jk)    ! Accumulate time-weighted vertcal flux
531                  END DO
532               END DO
533            END DO
534            IF( ln_linssh ) THEN                    ! top value (only in linear free surface case)
535               IF( ln_isfcav ) THEN                      ! ice-shelf cavities
536                  DO jj = 1, jpj
537                     DO ji = 1, jpi
538                        zwz(ji,jj, mikt(ji,jj) ) = pwn(ji,jj,mikt(ji,jj)) * ptb(ji,jj,mikt(ji,jj),jn)   ! linear free surface
539                     END DO
540                  END DO   
541               ELSE                                      ! no ocean cavities
542                  zwz(:,:,1) = pwn(:,:,1) * ptb(:,:,1,jn)
543               ENDIF
544            ENDIF
545            !
546            jtaken = MOD( jtaken + 1 , 2 )
547            !
548            DO jk = 2, jpkm1                             ! total advective trends
549               DO jj = 2, jpjm1
550                  DO ji = fs_2, fs_jpim1
551                     ztrs(ji,jj,jk,jta) = ztrs(ji,jj,jk,jtb)                                                 &
552                        &               - zts(jk) * (  zhdiv(ji,jj,jk) + zwz(ji,jj,jk) - zwz(ji,jj,jk+1) )   &
553                        &                         * r1_e1e2t(ji,jj) / e3t_n(ji,jj,jk)
554                  END DO
555               END DO
556            END DO
557            !
558         END DO
559
560         DO jk = 2, jpkm1          ! Anti-diffusive vertical flux using average flux from the sub-timestepping
561            DO jj = 2, jpjm1
562               DO ji = fs_2, fs_jpim1
563                  zwz(ji,jj,jk) = ( zwzts(ji,jj,jk) * zr_p2dt - zwz_sav(ji,jj,jk) ) * wmask(ji,jj,jk)
564               END DO
565            END DO
566         END DO
567         CALL lbc_lnk( zwx, 'U', -1. )   ;   CALL lbc_lnk( zwy, 'V', -1. )         ! Lateral bondary conditions
568         CALL lbc_lnk( zwz, 'W',  1. )
569
570         ! 4. monotonicity algorithm
571         ! -------------------------
572         CALL nonosc( ptb(:,:,:,jn), zwx, zwy, zwz, zwi, p2dt )
573
574
575         ! 5. final trend with corrected fluxes
576         ! ------------------------------------
577         DO jk = 1, jpkm1
578            DO jj = 2, jpjm1
579               DO ji = fs_2, fs_jpim1   ! vector opt. 
580                  pta(ji,jj,jk,jn) = pta(ji,jj,jk,jn) + (   zwy(ji,jj,jk) - zwy(ji  ,jj-1,jk  )       &
581                     &                                    + zwz(ji,jj,jk) - zwz(ji  ,jj  ,jk+1)   )   &
582                     &                                * r1_e1e2t(ji,jj) / e3t_n(ji,jj,jk)
583               END DO
584            END DO
585         END DO
586
587        !
588         IF( l_trd .OR. l_hst ) THEN     ! trend diagnostics (contribution of upstream fluxes)
589            ztrdx(:,:,:) = ztrdx(:,:,:) + zwx(:,:,:)  ! <<< Add to previously computed
590            ztrdy(:,:,:) = ztrdy(:,:,:) + zwy(:,:,:)  ! <<< Add to previously computed
591            ztrdz(:,:,:) = ztrdz(:,:,:) + zwz(:,:,:)  ! <<< Add to previously computed
592         ENDIF
593            !
594         IF( l_trd ) THEN
595            CALL trd_tra( kt, cdtype, jn, jptra_xad, ztrdx, pun, ptn(:,:,:,jn) )
596            CALL trd_tra( kt, cdtype, jn, jptra_yad, ztrdy, pvn, ptn(:,:,:,jn) )
597            CALL trd_tra( kt, cdtype, jn, jptra_zad, ztrdz, pwn, ptn(:,:,:,jn) )
598            !
599         END IF
600         !                                             ! heat/salt transport
601         IF( l_hst )  CALL dia_ar5_hst( jn, 'adv', ztrdx(:,:,:), ztrdy(:,:,:) )
602
603         !                                            ! "Poleward" heat and salt transports (contribution of upstream fluxes)
604         IF( l_ptr ) THEN 
605            zptry(:,:,:) = zptry(:,:,:) + zwy(:,:,:)  ! <<< Add to previously computed
606            CALL dia_ptr_hst( jn, 'adv', zptry(:,:,:) )
607         ENDIF
608         !
609      END DO
610      !
611      !
612      IF( nn_timing == 1 )  CALL timing_stop('tra_adv_fct_zts')
613      !
614   END SUBROUTINE tra_adv_fct_zts
615
616
617   SUBROUTINE nonosc( pbef, paa, pbb, pcc, paft, p2dt )
618      !!---------------------------------------------------------------------
619      !!                    ***  ROUTINE nonosc  ***
620      !!     
621      !! **  Purpose :   compute monotonic tracer fluxes from the upstream
622      !!       scheme and the before field by a nonoscillatory algorithm
623      !!
624      !! **  Method  :   ... ???
625      !!       warning : pbef and paft must be masked, but the boundaries
626      !!       conditions on the fluxes are not necessary zalezak (1979)
627      !!       drange (1995) multi-dimensional forward-in-time and upstream-
628      !!       in-space based differencing for fluid
629      !!----------------------------------------------------------------------
630      REAL(wp)                         , INTENT(in   ) ::   p2dt            ! tracer time-step
631      REAL(wp), DIMENSION (jpi,jpj,jpk), INTENT(in   ) ::   pbef, paft      ! before & after field
632      REAL(wp), DIMENSION (jpi,jpj,jpk), INTENT(inout) ::   paa, pbb, pcc   ! monotonic fluxes in the 3 directions
633      !
634      INTEGER  ::   ji, jj, jk   ! dummy loop indices
635      INTEGER  ::   ikm1         ! local integer
636      REAL(wp) ::   zpos, zneg, zbt, za, zb, zc, zbig, zrtrn    ! local scalars
637      REAL(wp) ::   zau, zbu, zcu, zav, zbv, zcv, zup, zdo            !   -      -
638      REAL(wp), DIMENSION(jpi,jpj,jpk) :: zbetup, zbetdo, zbup, zbdo
639      !!----------------------------------------------------------------------
640      !
641      IF( nn_timing == 1 )  CALL timing_start('nonosc')
642      !
643      !
644      zbig  = 1.e+40_wp
645      zrtrn = 1.e-15_wp
646      zbetup(:,:,:) = 0._wp   ;   zbetdo(:,:,:) = 0._wp
647
648      ! Search local extrema
649      ! --------------------
650      ! max/min of pbef & paft with large negative/positive value (-/+zbig) inside land
651      zbup = MAX( pbef * tmask - zbig * ( 1._wp - tmask ),   &
652         &        paft * tmask - zbig * ( 1._wp - tmask )  )
653      zbdo = MIN( pbef * tmask + zbig * ( 1._wp - tmask ),   &
654         &        paft * tmask + zbig * ( 1._wp - tmask )  )
655
656      DO jk = 1, jpkm1
657         ikm1 = MAX(jk-1,1)
658         DO jj = 2, jpjm1
659            DO ji = fs_2, fs_jpim1   ! vector opt.
660
661               ! search maximum in neighbourhood
662               zup = MAX(  zbup(ji  ,jj  ,jk  ),   &
663                  &        zbup(ji-1,jj  ,jk  ), zbup(ji+1,jj  ,jk  ),   &
664                  &        zbup(ji  ,jj-1,jk  ), zbup(ji  ,jj+1,jk  ),   &
665                  &        zbup(ji  ,jj  ,ikm1), zbup(ji  ,jj  ,jk+1)  )
666
667               ! search minimum in neighbourhood
668               zdo = MIN(  zbdo(ji  ,jj  ,jk  ),   &
669                  &        zbdo(ji-1,jj  ,jk  ), zbdo(ji+1,jj  ,jk  ),   &
670                  &        zbdo(ji  ,jj-1,jk  ), zbdo(ji  ,jj+1,jk  ),   &
671                  &        zbdo(ji  ,jj  ,ikm1), zbdo(ji  ,jj  ,jk+1)  )
672
673               ! positive part of the flux
674               zpos = MAX( 0., paa(ji-1,jj  ,jk  ) ) - MIN( 0., paa(ji  ,jj  ,jk  ) )   &
675                  & + MAX( 0., pbb(ji  ,jj-1,jk  ) ) - MIN( 0., pbb(ji  ,jj  ,jk  ) )   &
676                  & + MAX( 0., pcc(ji  ,jj  ,jk+1) ) - MIN( 0., pcc(ji  ,jj  ,jk  ) )
677
678               ! negative part of the flux
679               zneg = MAX( 0., paa(ji  ,jj  ,jk  ) ) - MIN( 0., paa(ji-1,jj  ,jk  ) )   &
680                  & + MAX( 0., pbb(ji  ,jj  ,jk  ) ) - MIN( 0., pbb(ji  ,jj-1,jk  ) )   &
681                  & + MAX( 0., pcc(ji  ,jj  ,jk  ) ) - MIN( 0., pcc(ji  ,jj  ,jk+1) )
682
683               ! up & down beta terms
684               zbt = e1e2t(ji,jj) * e3t_n(ji,jj,jk) / p2dt
685               zbetup(ji,jj,jk) = ( zup            - paft(ji,jj,jk) ) / ( zpos + zrtrn ) * zbt
686               zbetdo(ji,jj,jk) = ( paft(ji,jj,jk) - zdo            ) / ( zneg + zrtrn ) * zbt
687            END DO
688         END DO
689      END DO
690      CALL lbc_lnk( zbetup, 'T', 1. )   ;   CALL lbc_lnk( zbetdo, 'T', 1. )   ! lateral boundary cond. (unchanged sign)
691
692      ! 3. monotonic flux in the i & j direction (paa & pbb)
693      ! ----------------------------------------
694      DO jk = 1, jpkm1
695         DO jj = 2, jpjm1
696            DO ji = fs_2, fs_jpim1   ! vector opt.
697               zau = MIN( 1._wp, zbetdo(ji,jj,jk), zbetup(ji+1,jj,jk) )
698               zbu = MIN( 1._wp, zbetup(ji,jj,jk), zbetdo(ji+1,jj,jk) )
699               zcu =       ( 0.5  + SIGN( 0.5 , paa(ji,jj,jk) ) )
700               paa(ji,jj,jk) = paa(ji,jj,jk) * ( zcu * zau + ( 1._wp - zcu) * zbu )
701
702               zav = MIN( 1._wp, zbetdo(ji,jj,jk), zbetup(ji,jj+1,jk) )
703               zbv = MIN( 1._wp, zbetup(ji,jj,jk), zbetdo(ji,jj+1,jk) )
704               zcv =       ( 0.5  + SIGN( 0.5 , pbb(ji,jj,jk) ) )
705               pbb(ji,jj,jk) = pbb(ji,jj,jk) * ( zcv * zav + ( 1._wp - zcv) * zbv )
706
707      ! monotonic flux in the k direction, i.e. pcc
708      ! -------------------------------------------
709               za = MIN( 1., zbetdo(ji,jj,jk+1), zbetup(ji,jj,jk) )
710               zb = MIN( 1., zbetup(ji,jj,jk+1), zbetdo(ji,jj,jk) )
711               zc =       ( 0.5  + SIGN( 0.5 , pcc(ji,jj,jk+1) ) )
712               pcc(ji,jj,jk+1) = pcc(ji,jj,jk+1) * ( zc * za + ( 1._wp - zc) * zb )
713            END DO
714         END DO
715      END DO
716      CALL lbc_lnk( paa, 'U', -1. )   ;   CALL lbc_lnk( pbb, 'V', -1. )   ! lateral boundary condition (changed sign)
717      !
718      !
719      IF( nn_timing == 1 )  CALL timing_stop('nonosc')
720      !
721   END SUBROUTINE nonosc
722
723
724   SUBROUTINE interp_4th_cpt_org( pt_in, pt_out )
725      !!----------------------------------------------------------------------
726      !!                  ***  ROUTINE interp_4th_cpt_org  ***
727      !!
728      !! **  Purpose :   Compute the interpolation of tracer at w-point
729      !!
730      !! **  Method  :   4th order compact interpolation
731      !!----------------------------------------------------------------------
732      REAL(wp),DIMENSION(jpi,jpj,jpk), INTENT(in   ) ::   pt_in    ! now tracer fields
733      REAL(wp),DIMENSION(jpi,jpj,jpk), INTENT(  out) ::   pt_out   ! now tracer field interpolated at w-pts
734      !
735      INTEGER :: ji, jj, jk   ! dummy loop integers
736      REAL(wp),DIMENSION(jpi,jpj,jpk) :: zwd, zwi, zws, zwrm, zwt
737      !!----------------------------------------------------------------------
738     
739      DO jk = 3, jpkm1        !==  build the three diagonal matrix  ==!
740         DO jj = 1, jpj
741            DO ji = 1, jpi
742               zwd (ji,jj,jk) = 4._wp
743               zwi (ji,jj,jk) = 1._wp
744               zws (ji,jj,jk) = 1._wp
745               zwrm(ji,jj,jk) = 3._wp * ( pt_in(ji,jj,jk-1) + pt_in(ji,jj,jk) )
746               !
747               IF( tmask(ji,jj,jk+1) == 0._wp) THEN   ! Switch to second order centered at bottom
748                  zwd (ji,jj,jk) = 1._wp
749                  zwi (ji,jj,jk) = 0._wp
750                  zws (ji,jj,jk) = 0._wp
751                  zwrm(ji,jj,jk) = 0.5 * ( pt_in(ji,jj,jk-1) + pt_in(ji,jj,jk) )   
752               ENDIF
753            END DO
754         END DO
755      END DO
756      !
757      jk = 2                                          ! Switch to second order centered at top
758      DO jj = 1, jpj
759         DO ji = 1, jpi
760            zwd (ji,jj,jk) = 1._wp
761            zwi (ji,jj,jk) = 0._wp
762            zws (ji,jj,jk) = 0._wp
763            zwrm(ji,jj,jk) = 0.5 * ( pt_in(ji,jj,jk-1) + pt_in(ji,jj,jk) )
764         END DO
765      END DO   
766      !
767      !                       !==  tridiagonal solve  ==!
768      DO jj = 1, jpj                ! first recurrence
769         DO ji = 1, jpi
770            zwt(ji,jj,2) = zwd(ji,jj,2)
771         END DO
772      END DO
773      DO jk = 3, jpkm1
774         DO jj = 1, jpj
775            DO ji = 1, jpi
776               zwt(ji,jj,jk) = zwd(ji,jj,jk) - zwi(ji,jj,jk) * zws(ji,jj,jk-1) /zwt(ji,jj,jk-1)
777            END DO
778         END DO
779      END DO
780      !
781      DO jj = 1, jpj                ! second recurrence:    Zk = Yk - Ik / Tk-1  Zk-1
782         DO ji = 1, jpi
783            pt_out(ji,jj,2) = zwrm(ji,jj,2)
784         END DO
785      END DO
786      DO jk = 3, jpkm1
787         DO jj = 1, jpj
788            DO ji = 1, jpi
789               pt_out(ji,jj,jk) = zwrm(ji,jj,jk) - zwi(ji,jj,jk) / zwt(ji,jj,jk-1) *pt_out(ji,jj,jk-1)             
790            END DO
791         END DO
792      END DO
793
794      DO jj = 1, jpj                ! third recurrence: Xk = (Zk - Sk Xk+1 ) / Tk
795         DO ji = 1, jpi
796            pt_out(ji,jj,jpkm1) = pt_out(ji,jj,jpkm1) / zwt(ji,jj,jpkm1)
797         END DO
798      END DO
799      DO jk = jpk-2, 2, -1
800         DO jj = 1, jpj
801            DO ji = 1, jpi
802               pt_out(ji,jj,jk) = ( pt_out(ji,jj,jk) - zws(ji,jj,jk) * pt_out(ji,jj,jk+1) ) / zwt(ji,jj,jk)
803            END DO
804         END DO
805      END DO
806      !   
807   END SUBROUTINE interp_4th_cpt_org
808   
809
810   SUBROUTINE interp_4th_cpt( pt_in, pt_out )
811      !!----------------------------------------------------------------------
812      !!                  ***  ROUTINE interp_4th_cpt  ***
813      !!
814      !! **  Purpose :   Compute the interpolation of tracer at w-point
815      !!
816      !! **  Method  :   4th order compact interpolation
817      !!----------------------------------------------------------------------
818      REAL(wp),DIMENSION(jpi,jpj,jpk), INTENT(in   ) ::   pt_in    ! field at t-point
819      REAL(wp),DIMENSION(jpi,jpj,jpk), INTENT(  out) ::   pt_out   ! field interpolated at w-point
820      !
821      INTEGER ::   ji, jj, jk   ! dummy loop integers
822      INTEGER ::   ikt, ikb     ! local integers
823      REAL(wp),DIMENSION(jpi,jpj,jpk) :: zwd, zwi, zws, zwrm, zwt
824      !!----------------------------------------------------------------------
825      !
826      !                      !==  build the three diagonal matrix & the RHS  ==!
827      !
828      DO jk = 3, jpkm1                 ! interior (from jk=3 to jpk-1)
829         DO jj = 2, jpjm1
830            DO ji = fs_2, fs_jpim1
831               zwd (ji,jj,jk) = 3._wp * wmask(ji,jj,jk) + 1._wp                 !       diagonal
832               zwi (ji,jj,jk) =         wmask(ji,jj,jk)                         ! lower diagonal
833               zws (ji,jj,jk) =         wmask(ji,jj,jk)                         ! upper diagonal
834               zwrm(ji,jj,jk) = 3._wp * wmask(ji,jj,jk)                     &   ! RHS
835                  &           *       ( pt_in(ji,jj,jk) + pt_in(ji,jj,jk-1) )
836            END DO
837         END DO
838      END DO
839      !
840!!gm
841!      SELECT CASE( kbc )               !* boundary condition
842!      CASE( np_NH   )   ! Neumann homogeneous at top & bottom
843!      CASE( np_CEN2 )   ! 2nd order centered  at top & bottom
844!      END SELECT
845!!gm 
846      !
847      DO jj = 2, jpjm1                 ! 2nd order centered at top & bottom
848         DO ji = fs_2, fs_jpim1
849            ikt = mikt(ji,jj) + 1            ! w-point below the 1st  wet point
850            ikb = mbkt(ji,jj)                !     -   above the last wet point
851            !
852            zwd (ji,jj,ikt) = 1._wp          ! top
853            zwi (ji,jj,ikt) = 0._wp
854            zws (ji,jj,ikt) = 0._wp
855            zwrm(ji,jj,ikt) = 0.5_wp * ( pt_in(ji,jj,jk-1) + pt_in(ji,jj,jk) )
856            !
857            zwd (ji,jj,ikb) = 1._wp          ! bottom
858            zwi (ji,jj,ikb) = 0._wp
859            zws (ji,jj,ikb) = 0._wp
860            zwrm(ji,jj,ikb) = 0.5_wp * ( pt_in(ji,jj,jk-1) + pt_in(ji,jj,jk) )           
861         END DO
862      END DO   
863      !
864      !                       !==  tridiagonal solver  ==!
865      !
866      DO jj = 2, jpjm1              !* 1st recurrence:   Tk = Dk - Ik Sk-1 / Tk-1
867         DO ji = fs_2, fs_jpim1
868            zwt(ji,jj,2) = zwd(ji,jj,2)
869         END DO
870      END DO
871      DO jk = 3, jpkm1
872         DO jj = 2, jpjm1
873            DO ji = fs_2, fs_jpim1
874               zwt(ji,jj,jk) = zwd(ji,jj,jk) - zwi(ji,jj,jk) * zws(ji,jj,jk-1) /zwt(ji,jj,jk-1)
875            END DO
876         END DO
877      END DO
878      !
879      DO jj = 2, jpjm1              !* 2nd recurrence:    Zk = Yk - Ik / Tk-1  Zk-1
880         DO ji = fs_2, fs_jpim1
881            pt_out(ji,jj,2) = zwrm(ji,jj,2)
882         END DO
883      END DO
884      DO jk = 3, jpkm1
885         DO jj = 2, jpjm1
886            DO ji = fs_2, fs_jpim1
887               pt_out(ji,jj,jk) = zwrm(ji,jj,jk) - zwi(ji,jj,jk) / zwt(ji,jj,jk-1) *pt_out(ji,jj,jk-1)             
888            END DO
889         END DO
890      END DO
891
892      DO jj = 2, jpjm1              !* 3d recurrence:    Xk = (Zk - Sk Xk+1 ) / Tk
893         DO ji = fs_2, fs_jpim1
894            pt_out(ji,jj,jpkm1) = pt_out(ji,jj,jpkm1) / zwt(ji,jj,jpkm1)
895         END DO
896      END DO
897      DO jk = jpk-2, 2, -1
898         DO jj = 2, jpjm1
899            DO ji = fs_2, fs_jpim1
900               pt_out(ji,jj,jk) = ( pt_out(ji,jj,jk) - zws(ji,jj,jk) * pt_out(ji,jj,jk+1) ) / zwt(ji,jj,jk)
901            END DO
902         END DO
903      END DO
904      !   
905   END SUBROUTINE interp_4th_cpt
906
907
908   SUBROUTINE tridia_solver( pD, pU, pL, pRHS, pt_out , klev )
909      !!----------------------------------------------------------------------
910      !!                  ***  ROUTINE tridia_solver  ***
911      !!
912      !! **  Purpose :   solve a symmetric 3diagonal system
913      !!
914      !! **  Method  :   solve M.t_out = RHS(t)  where M is a tri diagonal matrix ( jpk*jpk )
915      !!     
916      !!             ( D_1 U_1  0   0   0  )( t_1 )   ( RHS_1 )
917      !!             ( L_2 D_2 U_2  0   0  )( t_2 )   ( RHS_2 )
918      !!             (  0  L_3 D_3 U_3  0  )( t_3 ) = ( RHS_3 )
919      !!             (        ...          )( ... )   ( ...  )
920      !!             (  0   0   0  L_k D_k )( t_k )   ( RHS_k )
921      !!     
922      !!        M is decomposed in the product of an upper and lower triangular matrix.
923      !!        The tri-diagonals matrix is given as input 3D arrays:   pD, pU, pL
924      !!        (i.e. the Diagonal, the Upper diagonal, and the Lower diagonal).
925      !!        The solution is pta.
926      !!        The 3d array zwt is used as a work space array.
927      !!----------------------------------------------------------------------
928      REAL(wp),DIMENSION(:,:,:), INTENT(in   ) ::   pD, pU, PL    ! 3-diagonal matrix
929      REAL(wp),DIMENSION(:,:,:), INTENT(in   ) ::   pRHS          ! Right-Hand-Side
930      REAL(wp),DIMENSION(:,:,:), INTENT(  out) ::   pt_out        !!gm field at level=F(klev)
931      INTEGER                  , INTENT(in   ) ::   klev          ! =1 pt_out at w-level
932      !                                                           ! =0 pt at t-level
933      INTEGER ::   ji, jj, jk   ! dummy loop integers
934      INTEGER ::   kstart       ! local indices
935      REAL(wp),DIMENSION(jpi,jpj,jpk) ::   zwt   ! 3D work array
936      !!----------------------------------------------------------------------
937      !
938      kstart =  1  + klev
939      !
940      DO jj = 2, jpjm1              !* 1st recurrence:   Tk = Dk - Ik Sk-1 / Tk-1
941         DO ji = fs_2, fs_jpim1
942            zwt(ji,jj,kstart) = pD(ji,jj,kstart)
943         END DO
944      END DO
945      DO jk = kstart+1, jpkm1
946         DO jj = 2, jpjm1
947            DO ji = fs_2, fs_jpim1
948               zwt(ji,jj,jk) = pD(ji,jj,jk) - pL(ji,jj,jk) * pU(ji,jj,jk-1) /zwt(ji,jj,jk-1)
949            END DO
950         END DO
951      END DO
952      !
953      DO jj = 2, jpjm1              !* 2nd recurrence:    Zk = Yk - Ik / Tk-1  Zk-1
954         DO ji = fs_2, fs_jpim1
955            pt_out(ji,jj,kstart) = pRHS(ji,jj,kstart)
956         END DO
957      END DO
958      DO jk = kstart+1, jpkm1
959         DO jj = 2, jpjm1
960            DO ji = fs_2, fs_jpim1
961               pt_out(ji,jj,jk) = pRHS(ji,jj,jk) - pL(ji,jj,jk) / zwt(ji,jj,jk-1) *pt_out(ji,jj,jk-1)             
962            END DO
963         END DO
964      END DO
965
966      DO jj = 2, jpjm1              !* 3d recurrence:    Xk = (Zk - Sk Xk+1 ) / Tk
967         DO ji = fs_2, fs_jpim1
968            pt_out(ji,jj,jpkm1) = pt_out(ji,jj,jpkm1) / zwt(ji,jj,jpkm1)
969         END DO
970      END DO
971      DO jk = jpk-2, kstart, -1
972         DO jj = 2, jpjm1
973            DO ji = fs_2, fs_jpim1
974               pt_out(ji,jj,jk) = ( pt_out(ji,jj,jk) - pU(ji,jj,jk) * pt_out(ji,jj,jk+1) ) / zwt(ji,jj,jk)
975            END DO
976         END DO
977      END DO
978      !
979   END SUBROUTINE tridia_solver
980
981   !!======================================================================
982END MODULE traadv_fct
Note: See TracBrowser for help on using the repository browser.