source: NEMO/trunk/src/TOP/TRP/trcsink.F90

Last change on this file was 13295, checked in by acc, 4 months ago

Replace do-loop macros in the trunk with alternative forms with greater flexibility for extra halo applications. This alters a lot of routines but does not change any behaviour or results. do_loop_substitute.h90 is greatly simplified by this change. SETTE results are identical to those with the previous revision

File size: 9.9 KB
Line 
1MODULE trcsink
2   !!======================================================================
3   !!                         ***  MODULE trcsink  ***
4   !! TOP :  vertical flux of particulate matter due to gravitational sinking
5   !!======================================================================
6   !! History :   1.0  !  2004     (O. Aumont) Original code
7   !!             2.0  !  2007-12  (C. Ethe, G. Madec)  F90
8   !!             3.4  !  2011-06  (O. Aumont, C. Ethe) Change aggregation formula
9   !!             3.5  !  2012-07  (O. Aumont) Introduce potential time-splitting
10   !!             4.0  !  2018-12  (O. Aumont) Generalize the PISCES code to make it usable by any model
11   !!----------------------------------------------------------------------
12   !!   trc_sink       :  Compute vertical flux of particulate matter due to gravitational sinking
13   !!----------------------------------------------------------------------
14   USE oce_trc         !  shared variables between ocean and passive tracers
15   USE trc             !  passive tracers common variables
16   USE lib_mpp
17
18   IMPLICIT NONE
19   PRIVATE
20
21   PUBLIC trc_sink
22   PUBLIC trc_sink_ini
23
24   INTEGER, PUBLIC :: nitermax      !: Maximum number of iterations for sinking
25
26   !! * Substitutions
27#  include "do_loop_substitute.h90"
28#  include "domzgr_substitute.h90"
29   !!----------------------------------------------------------------------
30   !! NEMO/TOP 4.0 , NEMO Consortium (2018)
31   !! $Id: trcsink.F90 10069 2018-08-28 14:12:24Z nicolasmartin $
32   !! Software governed by the CeCILL license (see ./LICENSE)
33   !!----------------------------------------------------------------------
34CONTAINS
35
36   !!----------------------------------------------------------------------
37   !!   'standard sinking parameterisation'                  ???
38   !!----------------------------------------------------------------------
39
40   SUBROUTINE trc_sink ( kt, Kbb, Kmm, pwsink, psinkflx, jp_tra, rsfact )
41      !!---------------------------------------------------------------------
42      !!                     ***  ROUTINE trc_sink  ***
43      !!
44      !! ** Purpose :   Compute vertical flux of particulate matter due to
45      !!                gravitational sinking
46      !!
47      !! ** Method  : - ???
48      !!---------------------------------------------------------------------
49      INTEGER , INTENT(in)  :: kt
50      INTEGER , INTENT(in)  :: Kbb, Kmm
51      INTEGER , INTENT(in)  :: jp_tra    ! tracer index index     
52      REAL(wp), INTENT(in)  :: rsfact    ! time step duration
53      REAL(wp), INTENT(in)   , DIMENSION(jpi,jpj,jpk) :: pwsink
54      REAL(wp), INTENT(inout), DIMENSION(jpi,jpj,jpk) :: psinkflx
55      INTEGER  ::   ji, jj, jk
56      INTEGER, DIMENSION(jpi, jpj) ::   iiter
57      REAL(wp) ::   zfact, zwsmax, zmax
58      REAL(wp), DIMENSION(jpi,jpj,jpk) :: zwsink
59      !!---------------------------------------------------------------------
60      !
61      IF( ln_timing )   CALL timing_start('trc_sink')
62      !
63      !
64      ! OA This is (I hope) a temporary solution for the problem that may
65      ! OA arise in specific situation where the CFL criterion is broken
66      ! OA for vertical sedimentation of particles. To avoid this, a time
67      ! OA splitting algorithm has been coded. A specific maximum
68      ! OA iteration number is provided and may be specified in the namelist
69      ! OA This is to avoid very large iteration number when explicit free
70      ! OA surface is used (for instance). When niter?max is set to 1,
71      ! OA this computation is skipped. The crude old threshold method is
72      ! OA then applied. This also happens when niter exceeds nitermax.
73      IF( nitermax == 1 ) THEN
74         iiter(:,:) = 1
75      ELSE
76         DO_2D( 1, 1, 1, 1 )
77            iiter(ji,jj) = 1
78            DO jk = 1, jpkm1
79               IF( tmask(ji,jj,jk) == 1.0 ) THEN
80                   zwsmax =  0.5 * e3t(ji,jj,jk,Kmm) * rday / rsfact
81                   iiter(ji,jj) =  MAX( iiter(ji,jj), INT( pwsink(ji,jj,jk) / zwsmax ) )
82               ENDIF
83            END DO
84         END_2D
85         iiter(:,:) = MIN( iiter(:,:), nitermax )
86      ENDIF
87
88      DO_3D( 1, 1, 1, 1, 1,jpkm1 )
89         IF( tmask(ji,jj,jk) == 1.0 ) THEN
90           zwsmax = 0.5 * e3t(ji,jj,jk,Kmm) * rday / rsfact
91           zwsink(ji,jj,jk) = MIN( pwsink(ji,jj,jk), zwsmax * REAL( iiter(ji,jj), wp ) )
92         ELSE
93           ! provide a default value so there is no use of undefinite value in trc_sink2 for zwsink2 initialization
94           zwsink(ji,jj,jk) = 0.
95         ENDIF
96      END_3D
97
98      !  Initializa to zero all the sinking arrays
99      !  -----------------------------------------
100      psinkflx(:,:,:) = 0.e0
101
102      !   Compute the sedimentation term using trc_sink2 for the considered sinking particle
103      !   -----------------------------------------------------
104      CALL trc_sink2( Kbb, Kmm, zwsink, psinkflx, jp_tra, iiter, rsfact )
105      !
106      IF( ln_timing )   CALL timing_stop('trc_sink')
107      !
108   END SUBROUTINE trc_sink
109
110   SUBROUTINE trc_sink2( Kbb, Kmm, pwsink, psinkflx, jp_tra, kiter, rsfact )
111      !!---------------------------------------------------------------------
112      !!                     ***  ROUTINE trc_sink2  ***
113      !!
114      !! ** Purpose :   Compute the sedimentation terms for the various sinking
115      !!     particles. The scheme used to compute the trends is based
116      !!     on MUSCL.
117      !!
118      !! ** Method  : - this ROUTINE compute not exactly the advection but the
119      !!      transport term, i.e.  div(u*tra).
120      !!---------------------------------------------------------------------
121      INTEGER,  INTENT(in   )                         ::   Kbb, Kmm  ! time level indices
122      INTEGER,  INTENT(in   )                         ::   jp_tra    ! tracer index index     
123      REAL(wp), INTENT(in   )                         ::   rsfact    ! duration of time step
124      INTEGER,  INTENT(in   ), DIMENSION(jpi,jpj)     ::   kiter     ! number of iterations for time-splitting
125      REAL(wp), INTENT(in   ), DIMENSION(jpi,jpj,jpk) ::   pwsink    ! sinking speed
126      REAL(wp), INTENT(inout), DIMENSION(jpi,jpj,jpk) ::   psinkflx  ! sinking fluxe
127      !
128      INTEGER  ::   ji, jj, jk, jn
129      REAL(wp) ::   zigma,zew,zign, zflx, zstep
130      REAL(wp), DIMENSION(jpi,jpj,jpk) :: ztraz, zakz, zwsink2, ztrb 
131      !!---------------------------------------------------------------------
132      !
133      IF( ln_timing )   CALL timing_start('trc_sink2')
134      !
135      ztraz(:,:,:) = 0.e0
136      zakz (:,:,:) = 0.e0
137      ztrb (:,:,:) = tr(:,:,:,jp_tra,Kbb)
138
139      DO jk = 1, jpkm1
140         zwsink2(:,:,jk+1) = -pwsink(:,:,jk) / rday * tmask(:,:,jk+1) 
141      END DO
142      zwsink2(:,:,1) = 0.e0
143
144
145      ! Vertical advective flux
146      DO jn = 1, 2
147         !  first guess of the slopes interior values
148         DO_2D( 1, 1, 1, 1 )
149            !
150            zstep = rsfact / REAL( kiter(ji,jj), wp ) / 2.
151            !             
152            DO jk = 2, jpkm1
153               ztraz(ji,jj,jk) = ( tr(ji,jj,jk-1,jp_tra,Kbb) - tr(ji,jj,jk,jp_tra,Kbb) ) * tmask(ji,jj,jk)
154            END DO
155            ztraz(ji,jj,1  ) = 0.0
156            ztraz(ji,jj,jpk) = 0.0
157
158            ! slopes
159            DO jk = 2, jpkm1
160               zign = 0.25 + SIGN( 0.25_wp, ztraz(ji,jj,jk) * ztraz(ji,jj,jk+1) )
161               zakz(ji,jj,jk) = ( ztraz(ji,jj,jk) + ztraz(ji,jj,jk+1) ) * zign
162            END DO
163     
164            ! Slopes limitation
165            DO jk = 2, jpkm1
166               zakz(ji,jj,jk) = SIGN( 1.0_wp, zakz(ji,jj,jk) ) *        &
167                  &             MIN( ABS( zakz(ji,jj,jk) ), 2. * ABS(ztraz(ji,jj,jk+1)), 2. * ABS(ztraz(ji,jj,jk) ) )
168            END DO
169     
170            ! vertical advective flux
171            DO jk = 1, jpkm1
172               zigma = zwsink2(ji,jj,jk+1) * zstep / e3w(ji,jj,jk+1,Kmm)
173               zew   = zwsink2(ji,jj,jk+1)
174               psinkflx(ji,jj,jk+1) = -zew * ( tr(ji,jj,jk,jp_tra,Kbb) - 0.5 * ( 1 + zigma ) * zakz(ji,jj,jk) ) * zstep
175            END DO
176            !
177            ! Boundary conditions
178            psinkflx(ji,jj,1  ) = 0.e0
179            psinkflx(ji,jj,jpk) = 0.e0
180     
181            DO jk=1,jpkm1
182               zflx = ( psinkflx(ji,jj,jk) - psinkflx(ji,jj,jk+1) ) / e3t(ji,jj,jk,Kmm)
183               tr(ji,jj,jk,jp_tra,Kbb) = tr(ji,jj,jk,jp_tra,Kbb) + zflx
184            END DO
185         END_2D
186      END DO
187
188      DO_3D( 1, 1, 1, 1, 1,jpkm1 )
189         zflx = ( psinkflx(ji,jj,jk) - psinkflx(ji,jj,jk+1) ) / e3t(ji,jj,jk,Kmm)
190         ztrb(ji,jj,jk) = ztrb(ji,jj,jk) + 2. * zflx
191      END_3D
192
193      tr(:,:,:,jp_tra,Kbb) = ztrb(:,:,:)
194      psinkflx(:,:,:)   = 2. * psinkflx(:,:,:)
195      !
196      IF( ln_timing )  CALL timing_stop('trc_sink2')
197      !
198   END SUBROUTINE trc_sink2
199
200  SUBROUTINE trc_sink_ini
201      !!---------------------------------------------------------------------
202      !!                  ***  ROUTINE trc_sink_ini ***
203      !!
204      !! ** Purpose :   read  namelist options
205      !!----------------------------------------------------------------------
206      INTEGER ::   ios   ! Local integer output status for namelist read
207      !!
208      NAMELIST/namtrc_snk/ nitermax
209      !!----------------------------------------------------------------------
210      !
211      READ  ( numnat_ref, namtrc_snk, IOSTAT = ios, ERR = 907)
212907   IF( ios /= 0 )   CALL ctl_nam ( ios , 'namtrc_snk in reference namelist' )
213      READ  ( numnat_cfg, namtrc_snk, IOSTAT = ios, ERR = 908 )
214908   IF( ios > 0 )   CALL ctl_nam ( ios , 'namtrc_snk in configuration namelist' )
215      IF(lwm) WRITE( numont, namtrc_snk )
216
217      IF(lwp) THEN                     !   ! Control print
218         WRITE(numout,*)
219         WRITE(numout,*) 'trc_sink : Sedimentation of particles '
220         WRITE(numout,*) '~~~~~~~ '
221         WRITE(numout,*) '   Namelist namtrc_snk : sedimentation of particles'
222         WRITE(numout,*) '   Maximum number of iterations   nitermax = ', nitermax
223         WRITE(numout,*)
224      ENDIF
225
226   END SUBROUTINE trc_sink_ini
227
228   !!======================================================================
229END MODULE trcsink
Note: See TracBrowser for help on using the repository browser.