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/UKMO/dev_r12866_HPC-02_Daley_Tiling_trial_extra_halo/src/OCE/TRA – NEMO

source: NEMO/branches/UKMO/dev_r12866_HPC-02_Daley_Tiling_trial_extra_halo/src/OCE/TRA/traadv_fct.F90 @ 12906

Last change on this file since 12906 was 12866, checked in by smasson, 4 years ago

Extra_Halo: using input files without halos, see #2366

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