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.
tranpc.F90 in NEMO/branches/2021/dev_r14116_HPC-10_mcastril_Mixed_Precision_implementation/src/OCE/TRA – NEMO

source: NEMO/branches/2021/dev_r14116_HPC-10_mcastril_Mixed_Precision_implementation/src/OCE/TRA/tranpc.F90 @ 15540

Last change on this file since 15540 was 15540, checked in by sparonuz, 3 years ago

Mixed precision version, tested up to 30 years on ORCA2.

  • Property svn:keywords set to Id
File size: 16.7 KB
Line 
1MODULE tranpc
2   !!==============================================================================
3   !!                       ***  MODULE  tranpc  ***
4   !! Ocean active tracers:  non penetrative convective adjustment scheme
5   !!==============================================================================
6   !! History :  1.0  ! 1990-09  (G. Madec)  Original code
7   !!                 ! 1996-01  (G. Madec)  statement function for e3
8   !!   NEMO     1.0  ! 2002-06  (G. Madec)  free form F90
9   !!            3.0  ! 2008-06  (G. Madec)  applied on ta, sa and called before tranxt in step.F90
10   !!            3.3  ! 2010-05  (C. Ethe, G. Madec)  merge TRC-TRA
11   !!            3.6  ! 2015-05  (L. Brodeau) new algorithm based on local Brunt-Vaisala freq.
12   !!----------------------------------------------------------------------
13
14   !!----------------------------------------------------------------------
15   !!   tra_npc       : apply the non penetrative convection scheme
16   !!----------------------------------------------------------------------
17   USE oce            ! ocean dynamics and active tracers
18   USE dom_oce        ! ocean space and time domain
19   USE phycst         ! physical constants
20   USE zdf_oce        ! ocean vertical physics
21   USE trd_oce        ! ocean active tracer trends
22   USE trdtra         ! ocean active tracer trends
23   USE eosbn2         ! equation of state (eos routine)
24   !
25   USE lbclnk         ! lateral boundary conditions (or mpp link)
26   USE in_out_manager ! I/O manager
27   USE lib_mpp        ! MPP library
28   USE timing         ! Timing
29
30   IMPLICIT NONE
31   PRIVATE
32
33   PUBLIC   tra_npc    ! routine called by step.F90
34
35   INTEGER  ::   nnpcc        ! number of statically instable water column
36
37   !! * Substitutions
38#  include "do_loop_substitute.h90"
39#  include "domzgr_substitute.h90"
40#  include "single_precision_substitute.h90"
41   !!----------------------------------------------------------------------
42   !! NEMO/OCE 4.0 , NEMO Consortium (2018)
43   !! $Id$
44   !! Software governed by the CeCILL license (see ./LICENSE)
45   !!----------------------------------------------------------------------
46CONTAINS
47
48   SUBROUTINE tra_npc( kt, Kmm, Krhs, pts, Kaa )
49      !!----------------------------------------------------------------------
50      !!                  ***  ROUTINE tranpc  ***
51      !!
52      !! ** Purpose : Non-penetrative convective adjustment scheme. solve
53      !!      the static instability of the water column on after fields
54      !!      while conserving heat and salt contents.
55      !!
56      !! ** Method  : updated algorithm able to deal with non-linear equation of state
57      !!              (i.e. static stability computed locally)
58      !!
59      !! ** Action  : - tsa: after tracers with the application of the npc scheme
60      !!              - send the associated trends for on-line diagnostics (l_trdtra=T)
61      !!
62      !! References :     Madec, et al., 1991, JPO, 21, 9, 1349-1371.
63      !!----------------------------------------------------------------------
64      INTEGER,                                   INTENT(in   ) :: kt              ! ocean time-step index
65      INTEGER,                                   INTENT(in   ) :: Kmm, Krhs, Kaa  ! time level indices
66      REAL(dp), DIMENSION(jpi,jpj,jpk,jpts,jpt), INTENT(inout) :: pts             ! active tracers and RHS of tracer equation
67      !
68      INTEGER  ::   ji, jj, jk   ! dummy loop indices
69      INTEGER  ::   jiter, ikbot, ikp, ikup, ikdown, ilayer, ik_low   ! local integers
70      LOGICAL  ::   l_bottom_reached, l_column_treated
71      REAL(dp) ::   zta, zalfa, zsum_temp, zsum_alfa, zaw, zdz, zsum_z
72      REAL(dp) ::   zsa, zbeta, zsum_sali, zsum_beta, zbw, zrw, z1_rDt
73      REAL(dp), PARAMETER ::   zn2_zero = 1.e-14_wp             ! acceptance criteria for neutrality (N2==0)
74      REAL(dp), DIMENSION(    jpk     )   ::   zvn2             ! vertical profile of N2 at 1 given point...
75      REAL(dp), DIMENSION(    jpk,jpts)   ::   zvts, zvab       ! vertical profile of T & S , and  alpha & betaat 1 given point
76      REAL(dp), DIMENSION(A2D(nn_hls),jpk     )   ::   zn2              ! N^2
77      REAL(dp), DIMENSION(A2D(nn_hls),jpk,jpts)   ::   zab              ! alpha and beta
78      REAL(dp), ALLOCATABLE, DIMENSION(:,:,:) ::   ztrdt, ztrds ! 3D workspace
79      !
80      LOGICAL, PARAMETER :: l_LB_debug = .FALSE. ! set to true if you want to follow what is
81      INTEGER :: ilc1, jlc1, klc1, nncpu         ! actually happening in a water column at point "ilc1, jlc1"
82      LOGICAL :: lp_monitor_point = .FALSE.      ! in CPU domain "nncpu"
83      !!----------------------------------------------------------------------
84      !
85      IF( ln_timing )   CALL timing_start('tra_npc')
86      !
87      IF( MOD( kt, nn_npc ) == 0 ) THEN
88         !
89         IF( l_trdtra )   THEN                    !* Save initial after fields
90            ALLOCATE( ztrdt(jpi,jpj,jpk) , ztrds(jpi,jpj,jpk) )
91            ztrdt(:,:,:) = pts(:,:,:,jp_tem,Kaa)
92            ztrds(:,:,:) = pts(:,:,:,jp_sal,Kaa)
93         ENDIF
94         !
95         IF( l_LB_debug ) THEN
96            ! Location of 1 known convection site to follow what's happening in the water column
97            ilc1 = 45 ;  jlc1 = 3 ; !  ORCA2 4x4, Antarctic coast, more than 2 unstable portions in the  water column...
98            nncpu = 1  ;            ! the CPU domain contains the convection spot
99            klc1 =  mbkt(ilc1,jlc1) ! bottom of the ocean for debug point...
100         ENDIF
101         !
102         CALL eos_rab( pts(:,:,:,:,Kaa), zab, Kmm )         ! after alpha and beta (given on T-points)
103         CALL bn2    ( pts(:,:,:,:,Kaa), zab, zn2, Kmm )    ! after Brunt-Vaisala  (given on W-points)
104         !
105         IF( .NOT. l_istiled .OR. ntile == 1 ) nnpcc = 0         ! Do only on the first tile
106         !
107         DO_2D_OVR( 0, 0, 0, 0 )                        ! interior column only
108            !
109            IF( tmask(ji,jj,2) == 1 ) THEN      ! At least 2 ocean points
110               !                                     ! consider one ocean column
111               zvts(:,jp_tem) = pts(ji,jj,:,jp_tem,Kaa)      ! temperature
112               zvts(:,jp_sal) = pts(ji,jj,:,jp_sal,Kaa)      ! salinity
113               !
114               zvab(:,jp_tem)  = zab(ji,jj,:,jp_tem)     ! Alpha
115               zvab(:,jp_sal)  = zab(ji,jj,:,jp_sal)     ! Beta
116               zvn2(:)         = zn2(ji,jj,:)            ! N^2
117               !
118               IF( l_LB_debug ) THEN                  !LB debug:
119                  lp_monitor_point = .FALSE.
120                  IF( ( ji == ilc1 ).AND.( jj == jlc1 ) ) lp_monitor_point = .TRUE.
121                  ! writing only if on CPU domain where conv region is:
122                  lp_monitor_point = (narea == nncpu).AND.lp_monitor_point
123               ENDIF                                  !LB debug  end
124               !
125               ikbot = mbkt(ji,jj)   ! ikbot: ocean bottom T-level
126               ikp = 1                  ! because N2 is irrelevant at the surface level (will start at ikp=2)
127               ilayer = 0
128               jiter  = 0
129               l_column_treated = .FALSE.
130               !
131               DO WHILE ( .NOT. l_column_treated )
132                  !
133                  jiter = jiter + 1
134                  !
135                  IF( jiter >= 400 ) EXIT
136                  !
137                  l_bottom_reached = .FALSE.
138                  !
139                  DO WHILE ( .NOT. l_bottom_reached )
140                     !
141                     ikp = ikp + 1
142                     !
143                     !! Testing level ikp for instability
144                     !! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
145                     IF( zvn2(ikp) <  -zn2_zero ) THEN ! Instability found!
146                        !
147                        ilayer = ilayer + 1    ! yet another instable portion of the water column found....
148                        !
149                        IF( lp_monitor_point ) THEN
150                           WRITE(numout,*)
151                           IF( ilayer == 1 .AND. jiter == 1 ) THEN   ! first time a column is spoted with an instability
152                              WRITE(numout,*)
153                              WRITE(numout,*) 'Time step = ',kt,' !!!'
154                           ENDIF
155                           WRITE(numout,*)  ' * Iteration #',jiter,': found instable portion #',ilayer,   &
156                              &                                    ' in column! Starting at ikp =', ikp
157                           WRITE(numout,*)  ' *** N2 for point (i,j) = ',ji,' , ',jj
158                           DO jk = 1, klc1
159                              WRITE(numout,*) jk, zvn2(jk)
160                           END DO
161                           WRITE(numout,*)
162                        ENDIF
163                        !
164                        IF( jiter == 1 )   nnpcc = nnpcc + 1
165                        !
166                        IF( lp_monitor_point )   WRITE(numout, *) 'Negative N2 at ikp =',ikp,' for layer #', ilayer
167                        !
168                        !! ikup is the uppermost point where mixing will start:
169                        ikup = ikp - 1 ! ikup is always "at most at ikp-1", less if neutral levels overlying
170                        !
171                        !! If the points above ikp-1 have N2 == 0 they must also be mixed:
172                        IF( ikp > 2 ) THEN
173                           DO jk = ikp-1, 2, -1
174                              IF( ABS(zvn2(jk)) < zn2_zero ) THEN
175                                 ikup = ikup - 1  ! 1 more upper level has N2=0 and must be added for the mixing
176                              ELSE
177                                 EXIT
178                              ENDIF
179                           END DO
180                        ENDIF
181                        !
182                        IF( ikup < 1 )   CALL ctl_stop( 'tra_npc :  PROBLEM #1')
183                        !
184                        zsum_temp = 0._wp
185                        zsum_sali = 0._wp
186                        zsum_alfa = 0._wp
187                        zsum_beta = 0._wp
188                        zsum_z    = 0._wp
189
190                        DO jk = ikup, ikbot      ! Inside the instable (and overlying neutral) portion of the column
191                           !
192                           zdz       = e3t(ji,jj,jk,Kmm)
193                           zsum_temp = zsum_temp + zvts(jk,jp_tem)*zdz
194                           zsum_sali = zsum_sali + zvts(jk,jp_sal)*zdz
195                           zsum_alfa = zsum_alfa + zvab(jk,jp_tem)*zdz
196                           zsum_beta = zsum_beta + zvab(jk,jp_sal)*zdz
197                           zsum_z    = zsum_z    + zdz
198                           !
199                           IF( jk == ikbot ) EXIT ! avoid array-index overshoot in case ikbot = jpk, cause we're calling jk+1 next line
200                           !! EXIT when we have reached the last layer that is instable (N2<0) or neutral (N2=0):
201                           IF( zvn2(jk+1) > zn2_zero ) EXIT
202                        END DO
203
204                        ikdown = jk ! for the current unstable layer, ikdown is the deepest point with a negative or neutral N2
205                        IF( ikup == ikdown )   CALL ctl_stop( 'tra_npc :  PROBLEM #2')
206
207                        ! Mixing Temperature, salinity, alpha and beta from ikup to ikdown included:
208                        zta   = zsum_temp/zsum_z
209                        zsa   = zsum_sali/zsum_z
210                        zalfa = zsum_alfa/zsum_z
211                        zbeta = zsum_beta/zsum_z
212
213                        IF( lp_monitor_point ) THEN
214                           WRITE(numout,*) 'MIXED T, S, alfa and beta between ikup =',ikup,   &
215                              &            ' and ikdown =',ikdown,', in layer #',ilayer
216                           WRITE(numout,*) '  => Mean temp. in that portion =', zta
217                           WRITE(numout,*) '  => Mean sali. in that portion =', zsa
218                           WRITE(numout,*) '  => Mean Alfa  in that portion =', zalfa
219                           WRITE(numout,*) '  => Mean Beta  in that portion =', zbeta
220                        ENDIF
221
222                        !! Homogenaizing the temperature, salinity, alpha and beta in this portion of the column
223                        DO jk = ikup, ikdown
224                           zvts(jk,jp_tem) = zta
225                           zvts(jk,jp_sal) = zsa
226                           zvab(jk,jp_tem) = zalfa
227                           zvab(jk,jp_sal) = zbeta
228                        END DO
229
230
231                        !! Updating N2 in the relvant portion of the water column
232                        !! Temperature, Salinity, Alpha and Beta have been homogenized in the unstable portion
233                        !! => Need to re-compute N2! will use Alpha and Beta!
234
235                        ikup   = MAX(2,ikup)         ! ikup can never be 1 !
236                        ik_low = MIN(ikdown+1,ikbot) ! we must go 1 point deeper than ikdown!
237
238                        DO jk = ikup, ik_low              ! we must go 1 point deeper than ikdown!
239
240                           !! Interpolating alfa and beta at W point:
241                           zrw =  (gdepw(ji,jj,jk  ,Kmm) - gdept(ji,jj,jk,Kmm)) &
242                              & / (gdept(ji,jj,jk-1,Kmm) - gdept(ji,jj,jk,Kmm))
243                           zaw = zvab(jk,jp_tem) * (1._wp - zrw) + zvab(jk-1,jp_tem) * zrw
244                           zbw = zvab(jk,jp_sal) * (1._wp - zrw) + zvab(jk-1,jp_sal) * zrw
245
246                           !! N2 at W point, doing exactly as in eosbn2.F90:
247                           zvn2(jk) = grav*( zaw * ( zvts(jk-1,jp_tem) - zvts(jk,jp_tem) )     &
248                              &            - zbw * ( zvts(jk-1,jp_sal) - zvts(jk,jp_sal) )  )  &
249                              &       / e3w(ji,jj,jk,Kmm) * tmask(ji,jj,jk)
250
251                           !! OR, faster  => just considering the vertical gradient of density
252                           !! as only the signa maters...
253                           !zvn2(jk) = (  zaw * ( zvts(jk-1,jp_tem) - zvts(jk,jp_tem) )     &
254                           !     &      - zbw * ( zvts(jk-1,jp_sal) - zvts(jk,jp_sal) )  )
255
256                        END DO
257
258                        ikp = MIN(ikdown+1,ikbot)
259
260
261                     ENDIF  !IF( zvn2(ikp) < 0. )
262
263
264                     IF( ikp == ikbot ) l_bottom_reached = .TRUE.
265                     !
266                  END DO ! DO WHILE ( .NOT. l_bottom_reached )
267
268                  IF( ikp /= ikbot )   CALL ctl_stop( 'tra_npc :  PROBLEM #3')
269
270                  ! ******* At this stage ikp == ikbot ! *******
271
272                  IF( ilayer > 0 ) THEN      !! least an unstable layer has been found
273                     !
274                     IF( lp_monitor_point ) THEN
275                        WRITE(numout,*)
276                        WRITE(numout,*) 'After ',jiter,' iteration(s), we neutralized ',ilayer,' instable layer(s)'
277                        WRITE(numout,*) '   ==> N2 at i,j=',ji,',',jj,' now looks like this:'
278                        DO jk = 1, klc1
279                           WRITE(numout,*) jk, zvn2(jk)
280                        END DO
281                        WRITE(numout,*)
282                     ENDIF
283                     !
284                     ikp    = 1     ! starting again at the surface for the next iteration
285                     ilayer = 0
286                  ENDIF
287                  !
288                  IF( ikp >= ikbot )   l_column_treated = .TRUE.
289                  !
290               END DO ! DO WHILE ( .NOT. l_column_treated )
291
292               !! Updating pts:
293               pts(ji,jj,:,jp_tem,Kaa) = zvts(:,jp_tem)
294               pts(ji,jj,:,jp_sal,Kaa) = zvts(:,jp_sal)
295
296               !! LB:  Potentially some other global variable beside theta and S can be treated here
297               !!      like BGC tracers.
298
299               IF( lp_monitor_point )   WRITE(numout,*)
300
301            ENDIF ! IF( tmask(ji,jj,3) == 1 ) THEN
302
303         END_2D
304         !
305         IF( l_trdtra ) THEN         ! send the Non penetrative mixing trends for diagnostic
306            z1_rDt = 1._wp / (2._wp * rn_Dt)
307            ztrdt(:,:,:) = ( pts(:,:,:,jp_tem,Kaa) - ztrdt(:,:,:) ) * z1_rDt
308            ztrds(:,:,:) = ( pts(:,:,:,jp_sal,Kaa) - ztrds(:,:,:) ) * z1_rDt
309            CALL trd_tra( kt, Kmm, Krhs, 'TRA', jp_tem, jptra_npc, ztrdt )
310            CALL trd_tra( kt, Kmm, Krhs, 'TRA', jp_sal, jptra_npc, ztrds )
311            DEALLOCATE( ztrdt, ztrds )
312         ENDIF
313         !
314         IF( .NOT. l_istiled .OR. ntile == nijtile )  THEN                ! Do only for the full domain
315            IF( lwp .AND. l_LB_debug ) THEN
316               WRITE(numout,*) 'Exiting tra_npc , kt = ',kt,', => numb. of statically instable water-columns: ', nnpcc
317               WRITE(numout,*)
318            ENDIF
319         ENDIF
320         !
321      ENDIF   ! IF( MOD( kt, nn_npc ) == 0 ) THEN
322      !
323      IF( ln_timing )   CALL timing_stop('tra_npc')
324      !
325   END SUBROUTINE tra_npc
326
327   !!======================================================================
328END MODULE tranpc
Note: See TracBrowser for help on using the repository browser.