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 NEMO/branches/2020/dev_r12377_KERNEL-06_techene_e3/src/OCE/TRA – NEMO

source: NEMO/branches/2020/dev_r12377_KERNEL-06_techene_e3/src/OCE/TRA/traadv_fct.F90 @ 12590

Last change on this file since 12590 was 12590, checked in by techene, 4 years ago

all: add e3 substitute, OCE/DOM/domzgr_substitute.h90: correct a bug for e3f

  • Property svn:keywords set to Id
File size: 32.4 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   !!                   with sub-time-stepping in the vertical direction
12   !!  nonosc         : compute monotonic tracer fluxes by a non-oscillatory algorithm
13   !!  interp_4th_cpt : 4th order compact scheme for the vertical component of the advection
14   !!----------------------------------------------------------------------
15   USE oce            ! ocean dynamics and active tracers
16   USE dom_oce        ! ocean space and time domain
17   USE trc_oce        ! share passive tracers/Ocean variables
18   USE trd_oce        ! trends: ocean variables
19   USE trdtra         ! tracers trends
20   USE diaptr         ! poleward transport diagnostics
21   USE diaar5         ! AR5 diagnostics
22   USE phycst  , ONLY : rau0_rcp
23   USE zdf_oce , ONLY : ln_zad_Aimp
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
31   IMPLICIT NONE
32   PRIVATE
33
34   PUBLIC   tra_adv_fct        ! called by traadv.F90
35   PUBLIC   interp_4th_cpt     ! called by traadv_cen.F90
36
37   LOGICAL  ::   l_trd   ! flag to compute trends
38   LOGICAL  ::   l_ptr   ! flag to compute poleward transport
39   LOGICAL  ::   l_hst   ! flag to compute heat/salt transport
40   REAL(wp) ::   r1_6 = 1._wp / 6._wp   ! =1/6
41
42   !                                        ! tridiag solver associated indices:
43   INTEGER, PARAMETER ::   np_NH   = 0   ! Neumann homogeneous boundary condition
44   INTEGER, PARAMETER ::   np_CEN2 = 1   ! 2nd order centered  boundary condition
45
46   !! * Substitutions
47#  include "do_loop_substitute.h90"
48#  include "domzgr_substitute.h90"
49   !!----------------------------------------------------------------------
50   !! NEMO/OCE 4.0 , NEMO Consortium (2018)
51   !! $Id$
52   !! Software governed by the CeCILL license (see ./LICENSE)
53   !!----------------------------------------------------------------------
54CONTAINS
55
56   SUBROUTINE tra_adv_fct( kt, kit000, cdtype, p2dt, pU, pV, pW,       &
57      &                    Kbb, Kmm, pt, kjpt, Krhs, kn_fct_h, kn_fct_v )
58      !!----------------------------------------------------------------------
59      !!                  ***  ROUTINE tra_adv_fct  ***
60      !!
61      !! **  Purpose :   Compute the now trend due to total advection of tracers
62      !!               and add it to the general trend of tracer equations
63      !!
64      !! **  Method  : - 2nd or 4th FCT scheme on the horizontal direction
65      !!               (choice through the value of kn_fct)
66      !!               - on the vertical the 4th order is a compact scheme
67      !!               - corrected flux (monotonic correction)
68      !!
69      !! ** Action : - update pt(:,:,:,:,Krhs)  with the now advective tracer trends
70      !!             - send trends to trdtra module for further diagnostics (l_trdtra=T)
71      !!             - poleward advective heat and salt transport (ln_diaptr=T)
72      !!----------------------------------------------------------------------
73      INTEGER                                  , INTENT(in   ) ::   kt              ! ocean time-step index
74      INTEGER                                  , INTENT(in   ) ::   Kbb, Kmm, Krhs  ! ocean time level indices
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   ) ::   pU, pV, pW      ! 3 ocean volume flux components
82      REAL(wp), DIMENSION(jpi,jpj,jpk,kjpt,jpt), INTENT(inout) ::   pt              ! tracers and RHS of tracer equation
83      !
84      INTEGER  ::   ji, jj, jk, jn                           ! dummy loop indices
85      REAL(wp) ::   ztra                                     ! local scalar
86      REAL(wp) ::   zfp_ui, zfp_vj, zfp_wk, zC2t_u, zC4t_u   !   -      -
87      REAL(wp) ::   zfm_ui, zfm_vj, zfm_wk, zC2t_v, zC4t_v   !   -      -
88      REAL(wp), DIMENSION(jpi,jpj,jpk)        ::   zwi, zwx, zwy, zwz, ztu, ztv, zltu, zltv, ztw
89      REAL(wp), DIMENSION(:,:,:), ALLOCATABLE ::   ztrdx, ztrdy, ztrdz, zptry
90      REAL(wp), DIMENSION(:,:,:), ALLOCATABLE ::   zwinf, zwdia, zwsup
91      LOGICAL  ::   ll_zAimp                                 ! flag to apply adaptive implicit vertical advection
92      !!----------------------------------------------------------------------
93      !
94      IF( kt == kit000 )  THEN
95         IF(lwp) WRITE(numout,*)
96         IF(lwp) WRITE(numout,*) 'tra_adv_fct : FCT advection scheme on ', cdtype
97         IF(lwp) WRITE(numout,*) '~~~~~~~~~~~'
98      ENDIF
99      !
100      l_trd = .FALSE.            ! set local switches
101      l_hst = .FALSE.
102      l_ptr = .FALSE.
103      ll_zAimp = .FALSE.
104      IF( ( cdtype == 'TRA' .AND. l_trdtra  ) .OR. ( cdtype =='TRC' .AND. l_trdtrc ) )      l_trd = .TRUE.
105      IF(   cdtype == 'TRA' .AND. ( iom_use( 'sophtadv' ) .OR. iom_use( 'sophtadv' ) ) )    l_ptr = .TRUE.
106      IF(   cdtype == 'TRA' .AND. ( iom_use("uadv_heattr") .OR. iom_use("vadv_heattr") .OR.  &
107         &                         iom_use("uadv_salttr") .OR. iom_use("vadv_salttr")  ) )  l_hst = .TRUE.
108      !
109      IF( l_trd .OR. l_hst )  THEN
110         ALLOCATE( ztrdx(jpi,jpj,jpk), ztrdy(jpi,jpj,jpk), ztrdz(jpi,jpj,jpk) )
111         ztrdx(:,:,:) = 0._wp   ;    ztrdy(:,:,:) = 0._wp   ;   ztrdz(:,:,:) = 0._wp
112      ENDIF
113      !
114      IF( l_ptr ) THEN
115         ALLOCATE( zptry(jpi,jpj,jpk) )
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      ! If adaptive vertical advection, check if it is needed on this PE at this time
125      IF( ln_zad_Aimp ) THEN
126         IF( MAXVAL( ABS( wi(:,:,:) ) ) > 0._wp ) ll_zAimp = .TRUE.
127      END IF
128      ! If active adaptive vertical advection, build tridiagonal matrix
129      IF( ll_zAimp ) THEN
130         ALLOCATE(zwdia(jpi,jpj,jpk), zwinf(jpi,jpj,jpk),zwsup(jpi,jpj,jpk))
131         DO_3D_00_00( 1, jpkm1 )
132            zwdia(ji,jj,jk) =  1._wp + p2dt * ( MAX( wi(ji,jj,jk) , 0._wp ) - MIN( wi(ji,jj,jk+1) , 0._wp ) )   &
133            &                               / e3t(ji,jj,jk,Krhs)
134            zwinf(ji,jj,jk) =  p2dt * MIN( wi(ji,jj,jk  ) , 0._wp ) / e3t(ji,jj,jk,Krhs)
135            zwsup(ji,jj,jk) = -p2dt * MAX( wi(ji,jj,jk+1) , 0._wp ) / e3t(ji,jj,jk,Krhs)
136         END_3D
137      END IF
138      !
139      DO jn = 1, kjpt            !==  loop over the tracers  ==!
140         !
141         !        !==  upstream advection with initial mass fluxes & intermediate update  ==!
142         !                    !* upstream tracer flux in the i and j direction
143         DO_3D_10_10( 1, jpkm1 )
144            ! upstream scheme
145            zfp_ui = pU(ji,jj,jk) + ABS( pU(ji,jj,jk) )
146            zfm_ui = pU(ji,jj,jk) - ABS( pU(ji,jj,jk) )
147            zfp_vj = pV(ji,jj,jk) + ABS( pV(ji,jj,jk) )
148            zfm_vj = pV(ji,jj,jk) - ABS( pV(ji,jj,jk) )
149            zwx(ji,jj,jk) = 0.5 * ( zfp_ui * pt(ji,jj,jk,jn,Kbb) + zfm_ui * pt(ji+1,jj  ,jk,jn,Kbb) )
150            zwy(ji,jj,jk) = 0.5 * ( zfp_vj * pt(ji,jj,jk,jn,Kbb) + zfm_vj * pt(ji  ,jj+1,jk,jn,Kbb) )
151         END_3D
152         !                    !* upstream tracer flux in the k direction *!
153         DO_3D_11_11( 2, jpkm1 )
154            zfp_wk = pW(ji,jj,jk) + ABS( pW(ji,jj,jk) )
155            zfm_wk = pW(ji,jj,jk) - ABS( pW(ji,jj,jk) )
156            zwz(ji,jj,jk) = 0.5 * ( zfp_wk * pt(ji,jj,jk,jn,Kbb) + zfm_wk * pt(ji,jj,jk-1,jn,Kbb) ) * wmask(ji,jj,jk)
157         END_3D
158         IF( ln_linssh ) THEN    ! top ocean value (only in linear free surface as zwz has been w-masked)
159            IF( ln_isfcav ) THEN             ! top of the ice-shelf cavities and at the ocean surface
160               DO_2D_11_11
161                  zwz(ji,jj, mikt(ji,jj) ) = pW(ji,jj,mikt(ji,jj)) * pt(ji,jj,mikt(ji,jj),jn,Kbb)   ! linear free surface
162               END_2D
163            ELSE                             ! no cavities: only at the ocean surface
164               zwz(:,:,1) = pW(:,:,1) * pt(:,:,1,jn,Kbb)
165            ENDIF
166         ENDIF
167         !
168         DO_3D_00_00( 1, jpkm1 )
169            !                             ! total intermediate advective trends
170            ztra = - (  zwx(ji,jj,jk) - zwx(ji-1,jj  ,jk  )   &
171               &      + zwy(ji,jj,jk) - zwy(ji  ,jj-1,jk  )   &
172               &      + zwz(ji,jj,jk) - zwz(ji  ,jj  ,jk+1) ) * r1_e1e2t(ji,jj)
173            !                             ! update and guess with monotonic sheme
174            pt(ji,jj,jk,jn,Krhs) =                   pt(ji,jj,jk,jn,Krhs) +       ztra   &
175               &                                  / e3t(ji,jj,jk,Kmm ) * tmask(ji,jj,jk)
176            zwi(ji,jj,jk)    = ( e3t(ji,jj,jk,Kbb) * pt(ji,jj,jk,jn,Kbb) + p2dt * ztra ) &
177               &                                  / e3t(ji,jj,jk,Krhs) * tmask(ji,jj,jk)
178         END_3D
179
180         IF ( ll_zAimp ) THEN
181            CALL tridia_solver( zwdia, zwsup, zwinf, zwi, zwi , 0 )
182            !
183            ztw(:,:,1) = 0._wp ; ztw(:,:,jpk) = 0._wp ;
184            DO_3D_00_00( 2, jpkm1 )
185               zfp_wk = wi(ji,jj,jk) + ABS( wi(ji,jj,jk) )
186               zfm_wk = wi(ji,jj,jk) - ABS( wi(ji,jj,jk) )
187               ztw(ji,jj,jk) =  0.5 * e1e2t(ji,jj) * ( zfp_wk * zwi(ji,jj,jk) + zfm_wk * zwi(ji,jj,jk-1) ) * wmask(ji,jj,jk)
188               zwz(ji,jj,jk) = zwz(ji,jj,jk) + ztw(ji,jj,jk) ! update vertical fluxes
189            END_3D
190            DO_3D_00_00( 1, jpkm1 )
191               pt(ji,jj,jk,jn,Krhs) = pt(ji,jj,jk,jn,Krhs) - ( ztw(ji,jj,jk) - ztw(ji  ,jj  ,jk+1) ) &
192                  &                                     * r1_e1e2t(ji,jj) / e3t(ji,jj,jk,Kmm)
193            END_3D
194            !
195         END IF
196         !
197         IF( l_trd .OR. l_hst )  THEN             ! trend diagnostics (contribution of upstream fluxes)
198            ztrdx(:,:,:) = zwx(:,:,:)   ;   ztrdy(:,:,:) = zwy(:,:,:)   ;   ztrdz(:,:,:) = zwz(:,:,:)
199         END IF
200         !                             ! "Poleward" heat and salt transports (contribution of upstream fluxes)
201         IF( l_ptr )   zptry(:,:,:) = zwy(:,:,:)
202         !
203         !        !==  anti-diffusive flux : high order minus low order  ==!
204         !
205         SELECT CASE( kn_fct_h )    !* horizontal anti-diffusive fluxes
206         !
207         CASE(  2  )                   !- 2nd order centered
208            DO_3D_10_10( 1, jpkm1 )
209               zwx(ji,jj,jk) = 0.5_wp * pU(ji,jj,jk) * ( pt(ji,jj,jk,jn,Kmm) + pt(ji+1,jj,jk,jn,Kmm) ) - zwx(ji,jj,jk)
210               zwy(ji,jj,jk) = 0.5_wp * pV(ji,jj,jk) * ( pt(ji,jj,jk,jn,Kmm) + pt(ji,jj+1,jk,jn,Kmm) ) - zwy(ji,jj,jk)
211            END_3D
212            !
213         CASE(  4  )                   !- 4th order centered
214            zltu(:,:,jpk) = 0._wp            ! Bottom value : flux set to zero
215            zltv(:,:,jpk) = 0._wp
216            DO jk = 1, jpkm1                 ! Laplacian
217               DO_2D_10_10
218                  ztu(ji,jj,jk) = ( pt(ji+1,jj  ,jk,jn,Kmm) - pt(ji,jj,jk,jn,Kmm) ) * umask(ji,jj,jk)
219                  ztv(ji,jj,jk) = ( pt(ji  ,jj+1,jk,jn,Kmm) - pt(ji,jj,jk,jn,Kmm) ) * vmask(ji,jj,jk)
220               END_2D
221               DO_2D_00_00
222                  zltu(ji,jj,jk) = (  ztu(ji,jj,jk) + ztu(ji-1,jj,jk)  ) * r1_6
223                  zltv(ji,jj,jk) = (  ztv(ji,jj,jk) + ztv(ji,jj-1,jk)  ) * r1_6
224               END_2D
225            END DO
226            CALL lbc_lnk_multi( 'traadv_fct', zltu, 'T', 1. , zltv, 'T', 1. )   ! Lateral boundary cond. (unchanged sgn)
227            !
228            DO_3D_10_10( 1, jpkm1 )
229               zC2t_u = pt(ji,jj,jk,jn,Kmm) + pt(ji+1,jj  ,jk,jn,Kmm)   ! 2 x C2 interpolation of T at u- & v-points
230               zC2t_v = pt(ji,jj,jk,jn,Kmm) + pt(ji  ,jj+1,jk,jn,Kmm)
231               !                                                  ! C4 minus upstream advective fluxes
232               zwx(ji,jj,jk) =  0.5_wp * pU(ji,jj,jk) * ( zC2t_u + zltu(ji,jj,jk) - zltu(ji+1,jj,jk) ) - zwx(ji,jj,jk)
233               zwy(ji,jj,jk) =  0.5_wp * pV(ji,jj,jk) * ( zC2t_v + zltv(ji,jj,jk) - zltv(ji,jj+1,jk) ) - zwy(ji,jj,jk)
234            END_3D
235            !
236         CASE(  41 )                   !- 4th order centered       ==>>   !!gm coding attempt   need to be tested
237            ztu(:,:,jpk) = 0._wp             ! Bottom value : flux set to zero
238            ztv(:,:,jpk) = 0._wp
239            DO_3D_10_10( 1, jpkm1 )
240               ztu(ji,jj,jk) = ( pt(ji+1,jj  ,jk,jn,Kmm) - pt(ji,jj,jk,jn,Kmm) ) * umask(ji,jj,jk)
241               ztv(ji,jj,jk) = ( pt(ji  ,jj+1,jk,jn,Kmm) - pt(ji,jj,jk,jn,Kmm) ) * vmask(ji,jj,jk)
242            END_3D
243            CALL lbc_lnk_multi( 'traadv_fct', ztu, 'U', -1. , ztv, 'V', -1. )   ! Lateral boundary cond. (unchanged sgn)
244            !
245            DO_3D_00_00( 1, jpkm1 )
246               zC2t_u = pt(ji,jj,jk,jn,Kmm) + pt(ji+1,jj  ,jk,jn,Kmm)   ! 2 x C2 interpolation of T at u- & v-points (x2)
247               zC2t_v = pt(ji,jj,jk,jn,Kmm) + pt(ji  ,jj+1,jk,jn,Kmm)
248               !                                                  ! C4 interpolation of T at u- & v-points (x2)
249               zC4t_u =  zC2t_u + r1_6 * ( ztu(ji-1,jj  ,jk) - ztu(ji+1,jj  ,jk) )
250               zC4t_v =  zC2t_v + r1_6 * ( ztv(ji  ,jj-1,jk) - ztv(ji  ,jj+1,jk) )
251               !                                                  ! C4 minus upstream advective fluxes
252               zwx(ji,jj,jk) =  0.5_wp * pU(ji,jj,jk) * zC4t_u - zwx(ji,jj,jk)
253               zwy(ji,jj,jk) =  0.5_wp * pV(ji,jj,jk) * zC4t_v - zwy(ji,jj,jk)
254            END_3D
255            !
256         END SELECT
257         !
258         SELECT CASE( kn_fct_v )    !* vertical anti-diffusive fluxes (w-masked interior values)
259         !
260         CASE(  2  )                   !- 2nd order centered
261            DO_3D_00_00( 2, jpkm1 )
262               zwz(ji,jj,jk) =  (  pW(ji,jj,jk) * 0.5_wp * ( pt(ji,jj,jk,jn,Kmm) + pt(ji,jj,jk-1,jn,Kmm) )   &
263                  &              - zwz(ji,jj,jk)  ) * wmask(ji,jj,jk)
264            END_3D
265            !
266         CASE(  4  )                   !- 4th order COMPACT
267            CALL interp_4th_cpt( pt(:,:,:,jn,Kmm) , ztw )   ! zwt = COMPACT interpolation of T at w-point
268            DO_3D_00_00( 2, jpkm1 )
269               zwz(ji,jj,jk) = ( pW(ji,jj,jk) * ztw(ji,jj,jk) - zwz(ji,jj,jk) ) * wmask(ji,jj,jk)
270            END_3D
271            !
272         END SELECT
273         IF( ln_linssh ) THEN    ! top ocean value: high order = upstream  ==>>  zwz=0
274            zwz(:,:,1) = 0._wp   ! only ocean surface as interior zwz values have been w-masked
275         ENDIF
276         !
277         IF ( ll_zAimp ) THEN
278            DO_3D_00_00( 1, jpkm1 )
279               !                             ! total intermediate advective trends
280               ztra = - (  zwx(ji,jj,jk) - zwx(ji-1,jj  ,jk  )   &
281                  &      + zwy(ji,jj,jk) - zwy(ji  ,jj-1,jk  )   &
282                  &      + zwz(ji,jj,jk) - zwz(ji  ,jj  ,jk+1) ) * r1_e1e2t(ji,jj)
283               ztw(ji,jj,jk) = zwi(ji,jj,jk) + p2dt * ztra / e3t(ji,jj,jk,Krhs)*tmask(ji,jj,jk)
284            END_3D
285            !
286            CALL tridia_solver( zwdia, zwsup, zwinf, ztw, ztw , 0 )
287            !
288            DO_3D_00_00( 2, jpkm1 )
289               zfp_wk = wi(ji,jj,jk) + ABS( wi(ji,jj,jk) )
290               zfm_wk = wi(ji,jj,jk) - ABS( wi(ji,jj,jk) )
291               zwz(ji,jj,jk) =  zwz(ji,jj,jk) + 0.5 * e1e2t(ji,jj) * ( zfp_wk * ztw(ji,jj,jk) + zfm_wk * ztw(ji,jj,jk-1) ) * wmask(ji,jj,jk)
292            END_3D
293         END IF
294         !
295         CALL lbc_lnk_multi( 'traadv_fct', zwi, 'T', 1., zwx, 'U', -1. , zwy, 'V', -1.,  zwz, 'W',  1. )
296         !
297         !        !==  monotonicity algorithm  ==!
298         !
299         CALL nonosc( Kmm, pt(:,:,:,jn,Kbb), zwx, zwy, zwz, zwi, p2dt )
300         !
301         !        !==  final trend with corrected fluxes  ==!
302         !
303         DO_3D_00_00( 1, jpkm1 )
304            ztra = - (  zwx(ji,jj,jk) - zwx(ji-1,jj  ,jk  )   &
305               &      + zwy(ji,jj,jk) - zwy(ji  ,jj-1,jk  )   &
306               &      + zwz(ji,jj,jk) - zwz(ji  ,jj  ,jk+1) ) * r1_e1e2t(ji,jj)
307            pt(ji,jj,jk,jn,Krhs) = pt(ji,jj,jk,jn,Krhs) + ztra / e3t(ji,jj,jk,Kmm)
308            zwi(ji,jj,jk) = zwi(ji,jj,jk) + p2dt * ztra / e3t(ji,jj,jk,Krhs) * tmask(ji,jj,jk)
309         END_3D
310         !
311         IF ( ll_zAimp ) THEN
312            !
313            ztw(:,:,1) = 0._wp ; ztw(:,:,jpk) = 0._wp
314            DO_3D_00_00( 2, jpkm1 )
315               zfp_wk = wi(ji,jj,jk) + ABS( wi(ji,jj,jk) )
316               zfm_wk = wi(ji,jj,jk) - ABS( wi(ji,jj,jk) )
317               ztw(ji,jj,jk) = - 0.5 * e1e2t(ji,jj) * ( zfp_wk * zwi(ji,jj,jk) + zfm_wk * zwi(ji,jj,jk-1) ) * wmask(ji,jj,jk)
318               zwz(ji,jj,jk) = zwz(ji,jj,jk) + ztw(ji,jj,jk) ! Update vertical fluxes for trend diagnostic
319            END_3D
320            DO_3D_00_00( 1, jpkm1 )
321               pt(ji,jj,jk,jn,Krhs) = pt(ji,jj,jk,jn,Krhs) - ( ztw(ji,jj,jk) - ztw(ji  ,jj  ,jk+1) ) &
322                  &                                     * r1_e1e2t(ji,jj) / e3t(ji,jj,jk,Kmm)
323            END_3D
324         END IF
325         !
326         IF( l_trd .OR. l_hst ) THEN   ! trend diagnostics // heat/salt transport
327            ztrdx(:,:,:) = ztrdx(:,:,:) + zwx(:,:,:)  ! <<< add anti-diffusive fluxes
328            ztrdy(:,:,:) = ztrdy(:,:,:) + zwy(:,:,:)  !     to upstream fluxes
329            ztrdz(:,:,:) = ztrdz(:,:,:) + zwz(:,:,:)  !
330            !
331            IF( l_trd ) THEN              ! trend diagnostics
332               CALL trd_tra( kt, Kmm, Krhs, cdtype, jn, jptra_xad, ztrdx, pU, pt(:,:,:,jn,Kmm) )
333               CALL trd_tra( kt, Kmm, Krhs, cdtype, jn, jptra_yad, ztrdy, pV, pt(:,:,:,jn,Kmm) )
334               CALL trd_tra( kt, Kmm, Krhs, cdtype, jn, jptra_zad, ztrdz, pW, pt(:,:,:,jn,Kmm) )
335            ENDIF
336            !                             ! heat/salt transport
337            IF( l_hst )   CALL dia_ar5_hst( jn, 'adv', ztrdx(:,:,:), ztrdy(:,:,:) )
338            !
339         ENDIF
340         IF( l_ptr ) THEN              ! "Poleward" transports
341            zptry(:,:,:) = zptry(:,:,:) + zwy(:,:,:)  ! <<< add anti-diffusive fluxes
342            CALL dia_ptr_hst( jn, 'adv', zptry(:,:,:) )
343         ENDIF
344         !
345      END DO                     ! end of tracer loop
346      !
347      IF ( ll_zAimp ) THEN
348         DEALLOCATE( zwdia, zwinf, zwsup )
349      ENDIF
350      IF( l_trd .OR. l_hst ) THEN
351         DEALLOCATE( ztrdx, ztrdy, ztrdz )
352      ENDIF
353      IF( l_ptr ) THEN
354         DEALLOCATE( zptry )
355      ENDIF
356      !
357   END SUBROUTINE tra_adv_fct
358
359
360   SUBROUTINE nonosc( Kmm, pbef, paa, pbb, pcc, paft, p2dt )
361      !!---------------------------------------------------------------------
362      !!                    ***  ROUTINE nonosc  ***
363      !!
364      !! **  Purpose :   compute monotonic tracer fluxes from the upstream
365      !!       scheme and the before field by a nonoscillatory algorithm
366      !!
367      !! **  Method  :   ... ???
368      !!       warning : pbef and paft must be masked, but the boundaries
369      !!       conditions on the fluxes are not necessary zalezak (1979)
370      !!       drange (1995) multi-dimensional forward-in-time and upstream-
371      !!       in-space based differencing for fluid
372      !!----------------------------------------------------------------------
373      INTEGER                          , INTENT(in   ) ::   Kmm             ! time level index
374      REAL(wp)                         , INTENT(in   ) ::   p2dt            ! tracer time-step
375      REAL(wp), DIMENSION (jpi,jpj,jpk), INTENT(in   ) ::   pbef, paft      ! before & after field
376      REAL(wp), DIMENSION (jpi,jpj,jpk), INTENT(inout) ::   paa, pbb, pcc   ! monotonic fluxes in the 3 directions
377      !
378      INTEGER  ::   ji, jj, jk   ! dummy loop indices
379      INTEGER  ::   ikm1         ! local integer
380      REAL(wp) ::   zpos, zneg, zbt, za, zb, zc, zbig, zrtrn    ! local scalars
381      REAL(wp) ::   zau, zbu, zcu, zav, zbv, zcv, zup, zdo            !   -      -
382      REAL(wp), DIMENSION(jpi,jpj,jpk) :: zbetup, zbetdo, zbup, zbdo
383      !!----------------------------------------------------------------------
384      !
385      zbig  = 1.e+40_wp
386      zrtrn = 1.e-15_wp
387      zbetup(:,:,:) = 0._wp   ;   zbetdo(:,:,:) = 0._wp
388
389      ! Search local extrema
390      ! --------------------
391      ! max/min of pbef & paft with large negative/positive value (-/+zbig) inside land
392      zbup = MAX( pbef * tmask - zbig * ( 1._wp - tmask ),   &
393         &        paft * tmask - zbig * ( 1._wp - tmask )  )
394      zbdo = MIN( pbef * tmask + zbig * ( 1._wp - tmask ),   &
395         &        paft * tmask + zbig * ( 1._wp - tmask )  )
396
397      DO jk = 1, jpkm1
398         ikm1 = MAX(jk-1,1)
399         DO_2D_00_00
400
401            ! search maximum in neighbourhood
402            zup = MAX(  zbup(ji  ,jj  ,jk  ),   &
403               &        zbup(ji-1,jj  ,jk  ), zbup(ji+1,jj  ,jk  ),   &
404               &        zbup(ji  ,jj-1,jk  ), zbup(ji  ,jj+1,jk  ),   &
405               &        zbup(ji  ,jj  ,ikm1), zbup(ji  ,jj  ,jk+1)  )
406
407            ! search minimum in neighbourhood
408            zdo = MIN(  zbdo(ji  ,jj  ,jk  ),   &
409               &        zbdo(ji-1,jj  ,jk  ), zbdo(ji+1,jj  ,jk  ),   &
410               &        zbdo(ji  ,jj-1,jk  ), zbdo(ji  ,jj+1,jk  ),   &
411               &        zbdo(ji  ,jj  ,ikm1), zbdo(ji  ,jj  ,jk+1)  )
412
413            ! positive part of the flux
414            zpos = MAX( 0., paa(ji-1,jj  ,jk  ) ) - MIN( 0., paa(ji  ,jj  ,jk  ) )   &
415               & + MAX( 0., pbb(ji  ,jj-1,jk  ) ) - MIN( 0., pbb(ji  ,jj  ,jk  ) )   &
416               & + MAX( 0., pcc(ji  ,jj  ,jk+1) ) - MIN( 0., pcc(ji  ,jj  ,jk  ) )
417
418            ! negative part of the flux
419            zneg = MAX( 0., paa(ji  ,jj  ,jk  ) ) - MIN( 0., paa(ji-1,jj  ,jk  ) )   &
420               & + MAX( 0., pbb(ji  ,jj  ,jk  ) ) - MIN( 0., pbb(ji  ,jj-1,jk  ) )   &
421               & + MAX( 0., pcc(ji  ,jj  ,jk  ) ) - MIN( 0., pcc(ji  ,jj  ,jk+1) )
422
423            ! up & down beta terms
424            zbt = e1e2t(ji,jj) * e3t(ji,jj,jk,Kmm) / p2dt
425            zbetup(ji,jj,jk) = ( zup            - paft(ji,jj,jk) ) / ( zpos + zrtrn ) * zbt
426            zbetdo(ji,jj,jk) = ( paft(ji,jj,jk) - zdo            ) / ( zneg + zrtrn ) * zbt
427         END_2D
428      END DO
429      CALL lbc_lnk_multi( 'traadv_fct', zbetup, 'T', 1. , zbetdo, 'T', 1. )   ! lateral boundary cond. (unchanged sign)
430
431      ! 3. monotonic flux in the i & j direction (paa & pbb)
432      ! ----------------------------------------
433      DO_3D_00_00( 1, jpkm1 )
434         zau = MIN( 1._wp, zbetdo(ji,jj,jk), zbetup(ji+1,jj,jk) )
435         zbu = MIN( 1._wp, zbetup(ji,jj,jk), zbetdo(ji+1,jj,jk) )
436         zcu =       ( 0.5  + SIGN( 0.5 , paa(ji,jj,jk) ) )
437         paa(ji,jj,jk) = paa(ji,jj,jk) * ( zcu * zau + ( 1._wp - zcu) * zbu )
438
439         zav = MIN( 1._wp, zbetdo(ji,jj,jk), zbetup(ji,jj+1,jk) )
440         zbv = MIN( 1._wp, zbetup(ji,jj,jk), zbetdo(ji,jj+1,jk) )
441         zcv =       ( 0.5  + SIGN( 0.5 , pbb(ji,jj,jk) ) )
442         pbb(ji,jj,jk) = pbb(ji,jj,jk) * ( zcv * zav + ( 1._wp - zcv) * zbv )
443
444! monotonic flux in the k direction, i.e. pcc
445! -------------------------------------------
446         za = MIN( 1., zbetdo(ji,jj,jk+1), zbetup(ji,jj,jk) )
447         zb = MIN( 1., zbetup(ji,jj,jk+1), zbetdo(ji,jj,jk) )
448         zc =       ( 0.5  + SIGN( 0.5 , pcc(ji,jj,jk+1) ) )
449         pcc(ji,jj,jk+1) = pcc(ji,jj,jk+1) * ( zc * za + ( 1._wp - zc) * zb )
450      END_3D
451      CALL lbc_lnk_multi( 'traadv_fct', paa, 'U', -1. , pbb, 'V', -1. )   ! lateral boundary condition (changed sign)
452      !
453   END SUBROUTINE nonosc
454
455
456   SUBROUTINE interp_4th_cpt_org( pt_in, pt_out )
457      !!----------------------------------------------------------------------
458      !!                  ***  ROUTINE interp_4th_cpt_org  ***
459      !!
460      !! **  Purpose :   Compute the interpolation of tracer at w-point
461      !!
462      !! **  Method  :   4th order compact interpolation
463      !!----------------------------------------------------------------------
464      REAL(wp),DIMENSION(jpi,jpj,jpk), INTENT(in   ) ::   pt_in    ! now tracer fields
465      REAL(wp),DIMENSION(jpi,jpj,jpk), INTENT(  out) ::   pt_out   ! now tracer field interpolated at w-pts
466      !
467      INTEGER :: ji, jj, jk   ! dummy loop integers
468      REAL(wp),DIMENSION(jpi,jpj,jpk) :: zwd, zwi, zws, zwrm, zwt
469      !!----------------------------------------------------------------------
470
471      DO_3D_11_11( 3, jpkm1 )
472         zwd (ji,jj,jk) = 4._wp
473         zwi (ji,jj,jk) = 1._wp
474         zws (ji,jj,jk) = 1._wp
475         zwrm(ji,jj,jk) = 3._wp * ( pt_in(ji,jj,jk-1) + pt_in(ji,jj,jk) )
476         !
477         IF( tmask(ji,jj,jk+1) == 0._wp) THEN   ! Switch to second order centered at bottom
478            zwd (ji,jj,jk) = 1._wp
479            zwi (ji,jj,jk) = 0._wp
480            zws (ji,jj,jk) = 0._wp
481            zwrm(ji,jj,jk) = 0.5 * ( pt_in(ji,jj,jk-1) + pt_in(ji,jj,jk) )
482         ENDIF
483      END_3D
484      !
485      jk = 2                                          ! Switch to second order centered at top
486      DO_2D_11_11
487         zwd (ji,jj,jk) = 1._wp
488         zwi (ji,jj,jk) = 0._wp
489         zws (ji,jj,jk) = 0._wp
490         zwrm(ji,jj,jk) = 0.5 * ( pt_in(ji,jj,jk-1) + pt_in(ji,jj,jk) )
491      END_2D
492      !
493      !                       !==  tridiagonal solve  ==!
494      DO_2D_11_11
495         zwt(ji,jj,2) = zwd(ji,jj,2)
496      END_2D
497      DO_3D_11_11( 3, jpkm1 )
498         zwt(ji,jj,jk) = zwd(ji,jj,jk) - zwi(ji,jj,jk) * zws(ji,jj,jk-1) /zwt(ji,jj,jk-1)
499      END_3D
500      !
501      DO_2D_11_11
502         pt_out(ji,jj,2) = zwrm(ji,jj,2)
503      END_2D
504      DO_3D_11_11( 3, jpkm1 )
505         pt_out(ji,jj,jk) = zwrm(ji,jj,jk) - zwi(ji,jj,jk) / zwt(ji,jj,jk-1) *pt_out(ji,jj,jk-1)
506      END_3D
507
508      DO_2D_11_11
509         pt_out(ji,jj,jpkm1) = pt_out(ji,jj,jpkm1) / zwt(ji,jj,jpkm1)
510      END_2D
511      DO_3DS_11_11( jpk-2, 2, -1 )
512         pt_out(ji,jj,jk) = ( pt_out(ji,jj,jk) - zws(ji,jj,jk) * pt_out(ji,jj,jk+1) ) / zwt(ji,jj,jk)
513      END_3D
514      !
515   END SUBROUTINE interp_4th_cpt_org
516
517
518   SUBROUTINE interp_4th_cpt( pt_in, pt_out )
519      !!----------------------------------------------------------------------
520      !!                  ***  ROUTINE interp_4th_cpt  ***
521      !!
522      !! **  Purpose :   Compute the interpolation of tracer at w-point
523      !!
524      !! **  Method  :   4th order compact interpolation
525      !!----------------------------------------------------------------------
526      REAL(wp),DIMENSION(jpi,jpj,jpk), INTENT(in   ) ::   pt_in    ! field at t-point
527      REAL(wp),DIMENSION(jpi,jpj,jpk), INTENT(  out) ::   pt_out   ! field interpolated at w-point
528      !
529      INTEGER ::   ji, jj, jk   ! dummy loop integers
530      INTEGER ::   ikt, ikb     ! local integers
531      REAL(wp),DIMENSION(jpi,jpj,jpk) :: zwd, zwi, zws, zwrm, zwt
532      !!----------------------------------------------------------------------
533      !
534      !                      !==  build the three diagonal matrix & the RHS  ==!
535      !
536      DO_3D_00_00( 3, jpkm1 )
537         zwd (ji,jj,jk) = 3._wp * wmask(ji,jj,jk) + 1._wp                 !       diagonal
538         zwi (ji,jj,jk) =         wmask(ji,jj,jk)                         ! lower diagonal
539         zws (ji,jj,jk) =         wmask(ji,jj,jk)                         ! upper diagonal
540         zwrm(ji,jj,jk) = 3._wp * wmask(ji,jj,jk)                     &   ! RHS
541            &           *       ( pt_in(ji,jj,jk) + pt_in(ji,jj,jk-1) )
542      END_3D
543      !
544!!gm
545!      SELECT CASE( kbc )               !* boundary condition
546!      CASE( np_NH   )   ! Neumann homogeneous at top & bottom
547!      CASE( np_CEN2 )   ! 2nd order centered  at top & bottom
548!      END SELECT
549!!gm
550      !
551      IF ( ln_isfcav ) THEN            ! set level two values which may not be set in ISF case
552         zwd(:,:,2) = 1._wp  ;  zwi(:,:,2) = 0._wp  ;  zws(:,:,2) = 0._wp  ;  zwrm(:,:,2) = 0._wp
553      END IF
554      !
555      DO_2D_00_00
556         ikt = mikt(ji,jj) + 1            ! w-point below the 1st  wet point
557         ikb = MAX(mbkt(ji,jj), 2)        !     -   above the last wet point
558         !
559         zwd (ji,jj,ikt) = 1._wp          ! top
560         zwi (ji,jj,ikt) = 0._wp
561         zws (ji,jj,ikt) = 0._wp
562         zwrm(ji,jj,ikt) = 0.5_wp * ( pt_in(ji,jj,ikt-1) + pt_in(ji,jj,ikt) )
563         !
564         zwd (ji,jj,ikb) = 1._wp          ! bottom
565         zwi (ji,jj,ikb) = 0._wp
566         zws (ji,jj,ikb) = 0._wp
567         zwrm(ji,jj,ikb) = 0.5_wp * ( pt_in(ji,jj,ikb-1) + pt_in(ji,jj,ikb) )
568      END_2D
569      !
570      !                       !==  tridiagonal solver  ==!
571      !
572      DO_2D_00_00
573         zwt(ji,jj,2) = zwd(ji,jj,2)
574      END_2D
575      DO_3D_00_00( 3, jpkm1 )
576         zwt(ji,jj,jk) = zwd(ji,jj,jk) - zwi(ji,jj,jk) * zws(ji,jj,jk-1) /zwt(ji,jj,jk-1)
577      END_3D
578      !
579      DO_2D_00_00
580         pt_out(ji,jj,2) = zwrm(ji,jj,2)
581      END_2D
582      DO_3D_00_00( 3, jpkm1 )
583         pt_out(ji,jj,jk) = zwrm(ji,jj,jk) - zwi(ji,jj,jk) / zwt(ji,jj,jk-1) *pt_out(ji,jj,jk-1)
584      END_3D
585
586      DO_2D_00_00
587         pt_out(ji,jj,jpkm1) = pt_out(ji,jj,jpkm1) / zwt(ji,jj,jpkm1)
588      END_2D
589      DO_3DS_00_00( jpk-2, 2, -1 )
590         pt_out(ji,jj,jk) = ( pt_out(ji,jj,jk) - zws(ji,jj,jk) * pt_out(ji,jj,jk+1) ) / zwt(ji,jj,jk)
591      END_3D
592      !
593   END SUBROUTINE interp_4th_cpt
594
595
596   SUBROUTINE tridia_solver( pD, pU, pL, pRHS, pt_out , klev )
597      !!----------------------------------------------------------------------
598      !!                  ***  ROUTINE tridia_solver  ***
599      !!
600      !! **  Purpose :   solve a symmetric 3diagonal system
601      !!
602      !! **  Method  :   solve M.t_out = RHS(t)  where M is a tri diagonal matrix ( jpk*jpk )
603      !!
604      !!             ( D_1 U_1  0   0   0  )( t_1 )   ( RHS_1 )
605      !!             ( L_2 D_2 U_2  0   0  )( t_2 )   ( RHS_2 )
606      !!             (  0  L_3 D_3 U_3  0  )( t_3 ) = ( RHS_3 )
607      !!             (        ...          )( ... )   ( ...  )
608      !!             (  0   0   0  L_k D_k )( t_k )   ( RHS_k )
609      !!
610      !!        M is decomposed in the product of an upper and lower triangular matrix.
611      !!        The tri-diagonals matrix is given as input 3D arrays:   pD, pU, pL
612      !!        (i.e. the Diagonal, the Upper diagonal, and the Lower diagonal).
613      !!        The solution is pta.
614      !!        The 3d array zwt is used as a work space array.
615      !!----------------------------------------------------------------------
616      REAL(wp),DIMENSION(:,:,:), INTENT(in   ) ::   pD, pU, PL    ! 3-diagonal matrix
617      REAL(wp),DIMENSION(:,:,:), INTENT(in   ) ::   pRHS          ! Right-Hand-Side
618      REAL(wp),DIMENSION(:,:,:), INTENT(  out) ::   pt_out        !!gm field at level=F(klev)
619      INTEGER                  , INTENT(in   ) ::   klev          ! =1 pt_out at w-level
620      !                                                           ! =0 pt at t-level
621      INTEGER ::   ji, jj, jk   ! dummy loop integers
622      INTEGER ::   kstart       ! local indices
623      REAL(wp),DIMENSION(jpi,jpj,jpk) ::   zwt   ! 3D work array
624      !!----------------------------------------------------------------------
625      !
626      kstart =  1  + klev
627      !
628      DO_2D_00_00
629         zwt(ji,jj,kstart) = pD(ji,jj,kstart)
630      END_2D
631      DO_3D_00_00( kstart+1, jpkm1 )
632         zwt(ji,jj,jk) = pD(ji,jj,jk) - pL(ji,jj,jk) * pU(ji,jj,jk-1) /zwt(ji,jj,jk-1)
633      END_3D
634      !
635      DO_2D_00_00
636         pt_out(ji,jj,kstart) = pRHS(ji,jj,kstart)
637      END_2D
638      DO_3D_00_00( kstart+1, jpkm1 )
639         pt_out(ji,jj,jk) = pRHS(ji,jj,jk) - pL(ji,jj,jk) / zwt(ji,jj,jk-1) *pt_out(ji,jj,jk-1)
640      END_3D
641
642      DO_2D_00_00
643         pt_out(ji,jj,jpkm1) = pt_out(ji,jj,jpkm1) / zwt(ji,jj,jpkm1)
644      END_2D
645      DO_3DS_00_00( jpk-2, kstart, -1 )
646         pt_out(ji,jj,jk) = ( pt_out(ji,jj,jk) - pU(ji,jj,jk) * pt_out(ji,jj,jk+1) ) / zwt(ji,jj,jk)
647      END_3D
648      !
649   END SUBROUTINE tridia_solver
650
651   !!======================================================================
652END MODULE traadv_fct
Note: See TracBrowser for help on using the repository browser.