1 | MODULE zdfdrg |
---|
2 | !!====================================================================== |
---|
3 | !! *** MODULE zdfdrg *** |
---|
4 | !! Ocean physics: top and/or Bottom friction |
---|
5 | !!====================================================================== |
---|
6 | !! History : OPA ! 1997-06 (G. Madec, A.-M. Treguier) Original code |
---|
7 | !! NEMO 1.0 ! 2002-06 (G. Madec) F90: Free form and module |
---|
8 | !! 3.2 ! 2009-09 (A.C.Coward) Correction to include barotropic contribution |
---|
9 | !! 3.3 ! 2010-10 (C. Ethe, G. Madec) reorganisation of initialisation phase |
---|
10 | !! 3.4 ! 2011-11 (H. Liu) implementation of semi-implicit bottom friction option |
---|
11 | !! ! 2012-06 (H. Liu) implementation of Log Layer bottom friction option |
---|
12 | !! 4.0 ! 2017-05 (G. Madec) zdfbfr becomes zdfdrg + variable names change |
---|
13 | !! + drag defined at t-point + new user interface + top drag (ocean cavities) |
---|
14 | !!---------------------------------------------------------------------- |
---|
15 | |
---|
16 | !!---------------------------------------------------------------------- |
---|
17 | !! zdf_drg : update bottom friction coefficient (non-linear bottom friction only) |
---|
18 | !! zdf_drg_exp : compute the top & bottom friction in explicit case |
---|
19 | !! zdf_drg_init : read in namdrg namelist and control the bottom friction parameters. |
---|
20 | !! drg_init : |
---|
21 | !!---------------------------------------------------------------------- |
---|
22 | USE oce ! ocean dynamics and tracers variables |
---|
23 | USE phycst , ONLY : vkarmn |
---|
24 | USE dom_oce ! ocean space and time domain variables |
---|
25 | USE zdf_oce ! ocean vertical physics variables |
---|
26 | USE trd_oce ! trends: ocean variables |
---|
27 | USE trddyn ! trend manager: dynamics |
---|
28 | ! |
---|
29 | USE in_out_manager ! I/O manager |
---|
30 | USE iom ! I/O module |
---|
31 | USE lbclnk ! ocean lateral boundary conditions (or mpp link) |
---|
32 | USE lib_mpp ! distributed memory computing |
---|
33 | USE prtctl ! Print control |
---|
34 | USE sbc_oce, ONLY: nn_ice |
---|
35 | |
---|
36 | IMPLICIT NONE |
---|
37 | PRIVATE |
---|
38 | |
---|
39 | PUBLIC zdf_drg ! called by zdf_phy |
---|
40 | PUBLIC zdf_drg_exp ! called by dyn_zdf |
---|
41 | PUBLIC zdf_drg_init ! called by zdf_phy_init |
---|
42 | |
---|
43 | ! !!* Namelist namdrg: nature of drag coefficient namelist * |
---|
44 | LOGICAL :: ln_OFF ! free-slip : Cd = 0 |
---|
45 | LOGICAL :: ln_lin ! linear drag: Cd = Cd0_lin |
---|
46 | LOGICAL :: ln_non_lin ! non-linear drag: Cd = Cd0_nl |U| |
---|
47 | LOGICAL :: ln_loglayer ! logarithmic drag: Cd = vkarmn/log(z/z0) |
---|
48 | LOGICAL , PUBLIC :: ln_drgimp ! implicit top/bottom friction flag |
---|
49 | LOGICAL , PUBLIC :: ln_drgice_imp ! implicit ice-ocean drag |
---|
50 | ! !!* Namelist namdrg_top & _bot: TOP or BOTTOM coefficient namelist * |
---|
51 | REAL(wp) :: rn_Cd0 !: drag coefficient [ - ] |
---|
52 | REAL(wp) :: rn_Uc0 !: characteristic velocity (linear case: tau=rho*Cd0*Uc0*u) [m/s] |
---|
53 | REAL(wp) :: rn_Cdmax !: drag value maximum (ln_loglayer=T) [ - ] |
---|
54 | REAL(wp) :: rn_z0 !: roughness (ln_loglayer=T) [ m ] |
---|
55 | REAL(wp) :: rn_ke0 !: background kinetic energy (non-linear case) [m2/s2] |
---|
56 | LOGICAL :: ln_boost !: =T regional boost of Cd0 ; =F Cd0 horizontally uniform |
---|
57 | REAL(wp) :: rn_boost !: local boost factor [ - ] |
---|
58 | |
---|
59 | REAL(wp), PUBLIC :: r_Cdmin_top, r_Cdmax_top, r_z0_top, r_ke0_top ! set from namdrg_top namelist values |
---|
60 | REAL(wp), PUBLIC :: r_Cdmin_bot, r_Cdmax_bot, r_z0_bot, r_ke0_bot ! - - namdrg_bot - - |
---|
61 | |
---|
62 | INTEGER :: ndrg ! choice of the type of drag coefficient |
---|
63 | ! ! associated indices: |
---|
64 | INTEGER, PARAMETER :: np_OFF = 0 ! free-slip: drag set to zero |
---|
65 | INTEGER, PARAMETER :: np_lin = 1 ! linear drag: Cd = Cd0_lin |
---|
66 | INTEGER, PARAMETER :: np_non_lin = 2 ! non-linear drag: Cd = Cd0_nl |U| |
---|
67 | INTEGER, PARAMETER :: np_loglayer = 3 ! non linear drag (logarithmic formulation): Cd = vkarmn/log(z/z0) |
---|
68 | |
---|
69 | LOGICAL , PUBLIC :: l_zdfdrg !: flag to update at each time step the top/bottom Cd |
---|
70 | LOGICAL :: l_log_not_linssh !: flag to update at each time step the position ot the velocity point |
---|
71 | ! |
---|
72 | REAL(wp), ALLOCATABLE, SAVE, DIMENSION(:,:), PUBLIC :: rCd0_top, rCd0_bot !: precomputed top/bottom drag coeff. at t-point (>0) |
---|
73 | REAL(wp), ALLOCATABLE, SAVE, DIMENSION(:,:), PUBLIC :: rCdU_top, rCdU_bot !: top/bottom drag coeff. at t-point (<0) [m/s] |
---|
74 | |
---|
75 | !! * Substitutions |
---|
76 | # include "vectopt_loop_substitute.h90" |
---|
77 | !!---------------------------------------------------------------------- |
---|
78 | !! NEMO/OCE 4.0 , NEMO Consortium (2018) |
---|
79 | !! $Id$ |
---|
80 | !! Software governed by the CeCILL license (see ./LICENSE) |
---|
81 | !!---------------------------------------------------------------------- |
---|
82 | CONTAINS |
---|
83 | |
---|
84 | SUBROUTINE zdf_drg( kt, k_mk, pCdmin, pCdmax, pz0, pke0, pCd0, & ! <<== in |
---|
85 | & pCdU ) ! ==>> out : bottom drag [m/s] |
---|
86 | !!---------------------------------------------------------------------- |
---|
87 | !! *** ROUTINE zdf_drg *** |
---|
88 | !! |
---|
89 | !! ** Purpose : update the top/bottom drag coefficient (non-linear case only) |
---|
90 | !! |
---|
91 | !! ** Method : In non linear friction case, the drag coeficient is |
---|
92 | !! a function of the velocity: |
---|
93 | !! Cd = cd0 * |U+Ut| |
---|
94 | !! where U is the top or bottom velocity and |
---|
95 | !! Ut a tidal velocity (Ut^2 = Tidal kinetic energy |
---|
96 | !! assumed here here to be constant) |
---|
97 | !! Depending on the input variable, the top- or bottom drag is compted |
---|
98 | !! |
---|
99 | !! ** Action : p_Cd drag coefficient at t-point |
---|
100 | !!---------------------------------------------------------------------- |
---|
101 | INTEGER , INTENT(in ) :: kt ! ocean time-step index |
---|
102 | ! ! !! !== top or bottom variables ==! |
---|
103 | INTEGER , DIMENSION(:,:), INTENT(in ) :: k_mk ! wet level (1st or last) |
---|
104 | REAL(wp) , INTENT(in ) :: pCdmin ! min drag value |
---|
105 | REAL(wp) , INTENT(in ) :: pCdmax ! max drag value |
---|
106 | REAL(wp) , INTENT(in ) :: pz0 ! roughness |
---|
107 | REAL(wp) , INTENT(in ) :: pke0 ! background tidal KE |
---|
108 | REAL(wp), DIMENSION(:,:), INTENT(in ) :: pCd0 ! masked precomputed part of Cd0 |
---|
109 | REAL(wp), DIMENSION(:,:), INTENT( out) :: pCdU ! = - Cd*|U| (t-points) [m/s] |
---|
110 | !! |
---|
111 | INTEGER :: ji, jj ! dummy loop indices |
---|
112 | INTEGER :: imk ! local integers |
---|
113 | REAL(wp):: zzz, zut, zvt, zcd ! local scalars |
---|
114 | !!---------------------------------------------------------------------- |
---|
115 | ! |
---|
116 | IF( l_log_not_linssh ) THEN !== "log layer" ==! compute Cd and -Cd*|U| |
---|
117 | DO jj = 2, jpjm1 |
---|
118 | DO ji = 2, jpim1 |
---|
119 | imk = k_mk(ji,jj) ! ocean bottom level at t-points |
---|
120 | zut = un(ji,jj,imk) + un(ji-1,jj,imk) ! 2 x velocity at t-point |
---|
121 | zvt = vn(ji,jj,imk) + vn(ji,jj-1,imk) |
---|
122 | zzz = 0.5_wp * e3t_n(ji,jj,imk) ! altitude below/above (top/bottom) the boundary |
---|
123 | ! |
---|
124 | !!JC: possible WAD implementation should modify line below if layers vanish |
---|
125 | zcd = ( vkarmn / LOG( zzz / pz0 ) )**2 |
---|
126 | zcd = pCd0(ji,jj) * MIN( MAX( pCdmin , zcd ) , pCdmax ) ! here pCd0 = mask*boost |
---|
127 | pCdU(ji,jj) = - zcd * SQRT( 0.25 * ( zut*zut + zvt*zvt ) + pke0 ) |
---|
128 | END DO |
---|
129 | END DO |
---|
130 | ELSE !== standard Cd ==! |
---|
131 | DO jj = 2, jpjm1 |
---|
132 | DO ji = 2, jpim1 |
---|
133 | imk = k_mk(ji,jj) ! ocean bottom level at t-points |
---|
134 | zut = un(ji,jj,imk) + un(ji-1,jj,imk) ! 2 x velocity at t-point |
---|
135 | zvt = vn(ji,jj,imk) + vn(ji,jj-1,imk) |
---|
136 | ! ! here pCd0 = mask*boost * drag |
---|
137 | pCdU(ji,jj) = - pCd0(ji,jj) * SQRT( 0.25 * ( zut*zut + zvt*zvt ) + pke0 ) |
---|
138 | END DO |
---|
139 | END DO |
---|
140 | ENDIF |
---|
141 | ! |
---|
142 | IF(ln_ctl) CALL prt_ctl( tab2d_1=pCdU, clinfo1=' Cd*U ') |
---|
143 | ! |
---|
144 | END SUBROUTINE zdf_drg |
---|
145 | |
---|
146 | |
---|
147 | SUBROUTINE zdf_drg_exp( kt, pub, pvb, pua, pva ) |
---|
148 | !!---------------------------------------------------------------------- |
---|
149 | !! *** ROUTINE zdf_drg_exp *** |
---|
150 | !! |
---|
151 | !! ** Purpose : compute and add the explicit top and bottom frictions. |
---|
152 | !! |
---|
153 | !! ** Method : in explicit case, |
---|
154 | !! |
---|
155 | !! NB: in implicit case the calculation is performed in dynzdf.F90 |
---|
156 | !! |
---|
157 | !! ** Action : (pua,pva) momentum trend increased by top & bottom friction trend |
---|
158 | !!--------------------------------------------------------------------- |
---|
159 | INTEGER , INTENT(in ) :: kt ! ocean time-step index |
---|
160 | REAL(wp), DIMENSION(jpi,jpj,jpk), INTENT(inout) :: pub, pvb ! the two components of the before velocity |
---|
161 | REAL(wp), DIMENSION(jpi,jpj,jpk), INTENT(inout) :: pua, pva ! the two components of the velocity tendency |
---|
162 | !! |
---|
163 | INTEGER :: ji, jj ! dummy loop indexes |
---|
164 | INTEGER :: ikbu, ikbv ! local integers |
---|
165 | REAL(wp) :: zm1_2dt ! local scalar |
---|
166 | REAL(wp) :: zCdu, zCdv ! - - |
---|
167 | REAL(wp), DIMENSION(:,:,:), ALLOCATABLE :: ztrdu, ztrdv |
---|
168 | !!--------------------------------------------------------------------- |
---|
169 | ! |
---|
170 | !!gm bug : time step is only rdt (not 2 rdt if euler start !) |
---|
171 | zm1_2dt = - 1._wp / ( 2._wp * rdt ) |
---|
172 | |
---|
173 | IF( l_trddyn ) THEN ! trends: store the input trends |
---|
174 | ALLOCATE( ztrdu(jpi,jpj,jpk) , ztrdv(jpi,jpj,jpk) ) |
---|
175 | ztrdu(:,:,:) = pua(:,:,:) |
---|
176 | ztrdv(:,:,:) = pva(:,:,:) |
---|
177 | ENDIF |
---|
178 | |
---|
179 | DO jj = 2, jpjm1 |
---|
180 | DO ji = 2, jpim1 |
---|
181 | ikbu = mbku(ji,jj) ! deepest wet ocean u- & v-levels |
---|
182 | ikbv = mbkv(ji,jj) |
---|
183 | ! |
---|
184 | ! Apply stability criteria on absolute value : abs(bfr/e3) < 1/(2dt) => bfr/e3 > -1/(2dt) |
---|
185 | zCdu = 0.5*( rCdU_bot(ji+1,jj)+rCdU_bot(ji,jj) ) / e3u_n(ji,jj,ikbu) |
---|
186 | zCdv = 0.5*( rCdU_bot(ji,jj+1)+rCdU_bot(ji,jj) ) / e3v_n(ji,jj,ikbv) |
---|
187 | ! |
---|
188 | pua(ji,jj,ikbu) = pua(ji,jj,ikbu) + MAX( zCdu , zm1_2dt ) * pub(ji,jj,ikbu) |
---|
189 | pva(ji,jj,ikbv) = pva(ji,jj,ikbv) + MAX( zCdv , zm1_2dt ) * pvb(ji,jj,ikbv) |
---|
190 | END DO |
---|
191 | END DO |
---|
192 | ! |
---|
193 | IF( ln_isfcav ) THEN ! ocean cavities |
---|
194 | DO jj = 2, jpjm1 |
---|
195 | DO ji = 2, jpim1 |
---|
196 | ikbu = miku(ji,jj) ! first wet ocean u- & v-levels |
---|
197 | ikbv = mikv(ji,jj) |
---|
198 | ! |
---|
199 | ! Apply stability criteria on absolute value : abs(bfr/e3) < 1/(2dt) => bfr/e3 > -1/(2dt) |
---|
200 | zCdu = 0.5*( rCdU_top(ji+1,jj)+rCdU_top(ji,jj) ) / e3u_n(ji,jj,ikbu) ! NB: Cdtop masked |
---|
201 | zCdv = 0.5*( rCdU_top(ji,jj+1)+rCdU_top(ji,jj) ) / e3v_n(ji,jj,ikbv) |
---|
202 | ! |
---|
203 | pua(ji,jj,ikbu) = pua(ji,jj,ikbu) + MAX( zCdu , zm1_2dt ) * pub(ji,jj,ikbu) |
---|
204 | pva(ji,jj,ikbv) = pva(ji,jj,ikbv) + MAX( zCdv , zm1_2dt ) * pvb(ji,jj,ikbv) |
---|
205 | END DO |
---|
206 | END DO |
---|
207 | ENDIF |
---|
208 | ! |
---|
209 | IF( l_trddyn ) THEN ! trends: send trends to trddyn for further diagnostics |
---|
210 | ztrdu(:,:,:) = pua(:,:,:) - ztrdu(:,:,:) |
---|
211 | ztrdv(:,:,:) = pva(:,:,:) - ztrdv(:,:,:) |
---|
212 | CALL trd_dyn( ztrdu(:,:,:), ztrdv(:,:,:), jpdyn_bfr, kt ) |
---|
213 | DEALLOCATE( ztrdu, ztrdv ) |
---|
214 | ENDIF |
---|
215 | ! ! print mean trends (used for debugging) |
---|
216 | IF(ln_ctl) CALL prt_ctl( tab3d_1=pua, clinfo1=' bfr - Ua: ', mask1=umask, & |
---|
217 | & tab3d_2=pva, clinfo2= ' Va: ', mask2=vmask, clinfo3='dyn' ) |
---|
218 | ! |
---|
219 | END SUBROUTINE zdf_drg_exp |
---|
220 | |
---|
221 | |
---|
222 | SUBROUTINE zdf_drg_init |
---|
223 | !!---------------------------------------------------------------------- |
---|
224 | !! *** ROUTINE zdf_brg_init *** |
---|
225 | !! |
---|
226 | !! ** Purpose : Initialization of the bottom friction |
---|
227 | !! |
---|
228 | !! ** Method : Read the namdrg namelist and check their consistency |
---|
229 | !! called at the first timestep (nit000) |
---|
230 | !!---------------------------------------------------------------------- |
---|
231 | INTEGER :: ji, jj ! dummy loop indexes |
---|
232 | INTEGER :: ios, ioptio ! local integers |
---|
233 | !! |
---|
234 | NAMELIST/namdrg/ ln_OFF, ln_lin, ln_non_lin, ln_loglayer, ln_drgimp, ln_drgice_imp |
---|
235 | !!---------------------------------------------------------------------- |
---|
236 | ! |
---|
237 | ! !== drag nature ==! |
---|
238 | ! |
---|
239 | REWIND( numnam_ref ) ! Namelist namdrg in reference namelist |
---|
240 | READ ( numnam_ref, namdrg, IOSTAT = ios, ERR = 901) |
---|
241 | 901 IF( ios /= 0 ) CALL ctl_nam( ios , 'namdrg in reference namelist' ) |
---|
242 | REWIND( numnam_cfg ) ! Namelist namdrg in configuration namelist |
---|
243 | READ ( numnam_cfg, namdrg, IOSTAT = ios, ERR = 902 ) |
---|
244 | 902 IF( ios > 0 ) CALL ctl_nam( ios , 'namdrg in configuration namelist' ) |
---|
245 | IF(lwm) WRITE ( numond, namdrg ) |
---|
246 | ! |
---|
247 | IF(lwp) THEN |
---|
248 | WRITE(numout,*) |
---|
249 | WRITE(numout,*) 'zdf_drg_init : top and/or bottom drag setting' |
---|
250 | WRITE(numout,*) '~~~~~~~~~~~~' |
---|
251 | WRITE(numout,*) ' Namelist namdrg : top/bottom friction choices' |
---|
252 | WRITE(numout,*) ' free-slip : Cd = 0 ln_OFF = ', ln_OFF |
---|
253 | WRITE(numout,*) ' linear drag : Cd = Cd0 ln_lin = ', ln_lin |
---|
254 | WRITE(numout,*) ' non-linear drag: Cd = Cd0_nl |U| ln_non_lin = ', ln_non_lin |
---|
255 | WRITE(numout,*) ' logarithmic drag: Cd = vkarmn/log(z/z0) ln_loglayer = ', ln_loglayer |
---|
256 | WRITE(numout,*) ' implicit friction ln_drgimp = ', ln_drgimp |
---|
257 | WRITE(numout,*) ' implicit ice-ocean drag ln_drgice_imp =', ln_drgice_imp |
---|
258 | ENDIF |
---|
259 | ! |
---|
260 | ioptio = 0 ! set ndrg and control check |
---|
261 | IF( ln_OFF ) THEN ; ndrg = np_OFF ; ioptio = ioptio + 1 ; ENDIF |
---|
262 | IF( ln_lin ) THEN ; ndrg = np_lin ; ioptio = ioptio + 1 ; ENDIF |
---|
263 | IF( ln_non_lin ) THEN ; ndrg = np_non_lin ; ioptio = ioptio + 1 ; ENDIF |
---|
264 | IF( ln_loglayer ) THEN ; ndrg = np_loglayer ; ioptio = ioptio + 1 ; ENDIF |
---|
265 | ! |
---|
266 | IF( ioptio /= 1 ) CALL ctl_stop( 'zdf_drg_init: Choose ONE type of drag coef in namdrg' ) |
---|
267 | ! |
---|
268 | IF ( ln_drgice_imp.AND.(.NOT.ln_drgimp) ) & |
---|
269 | & CALL ctl_stop( 'zdf_drg_init: ln_drgice_imp=T requires ln_drgimp=T' ) |
---|
270 | ! |
---|
271 | IF ( ln_drgice_imp.AND.( nn_ice /=2 ) ) & |
---|
272 | & CALL ctl_stop( 'zdf_drg_init: ln_drgice_imp=T requires si3' ) |
---|
273 | ! |
---|
274 | ! !== BOTTOM drag setting ==! (applied at seafloor) |
---|
275 | ! |
---|
276 | ALLOCATE( rCd0_bot(jpi,jpj), rCdU_bot(jpi,jpj) ) |
---|
277 | CALL drg_init( 'BOTTOM' , mbkt , & ! <== in |
---|
278 | & r_Cdmin_bot, r_Cdmax_bot, r_z0_bot, r_ke0_bot, rCd0_bot, rCdU_bot ) ! ==> out |
---|
279 | |
---|
280 | ! |
---|
281 | ! !== TOP drag setting ==! (applied at the top of ocean cavities) |
---|
282 | ! |
---|
283 | IF( ln_isfcav.OR.ln_drgice_imp ) THEN ! Ocean cavities: top friction setting |
---|
284 | ALLOCATE( rCdU_top(jpi,jpj) ) |
---|
285 | ENDIF |
---|
286 | ! |
---|
287 | IF( ln_isfcav ) THEN |
---|
288 | ALLOCATE( rCd0_top(jpi,jpj)) |
---|
289 | CALL drg_init( 'TOP ' , mikt , & ! <== in |
---|
290 | & r_Cdmin_top, r_Cdmax_top, r_z0_top, r_ke0_top, rCd0_top, rCdU_top ) ! ==> out |
---|
291 | ENDIF |
---|
292 | ! |
---|
293 | END SUBROUTINE zdf_drg_init |
---|
294 | |
---|
295 | |
---|
296 | SUBROUTINE drg_init( cd_topbot, k_mk, & |
---|
297 | & pCdmin, pCdmax, pz0, pke0, pCd0, pCdU ) |
---|
298 | !!---------------------------------------------------------------------- |
---|
299 | !! *** ROUTINE drg_init *** |
---|
300 | !! |
---|
301 | !! ** Purpose : Initialization of the top/bottom friction CdO and Cd |
---|
302 | !! from namelist parameters |
---|
303 | !!---------------------------------------------------------------------- |
---|
304 | CHARACTER(len=6) , INTENT(in ) :: cd_topbot ! top/ bot indicator |
---|
305 | INTEGER , DIMENSION(:,:), INTENT(in ) :: k_mk ! 1st/last wet level |
---|
306 | REAL(wp) , INTENT( out) :: pCdmin, pCdmax ! min and max drag coef. [-] |
---|
307 | REAL(wp) , INTENT( out) :: pz0 ! roughness [m] |
---|
308 | REAL(wp) , INTENT( out) :: pke0 ! background KE [m2/s2] |
---|
309 | REAL(wp), DIMENSION(:,:), INTENT( out) :: pCd0 ! masked precomputed part of the non-linear drag coefficient |
---|
310 | REAL(wp), DIMENSION(:,:), INTENT( out) :: pCdU ! minus linear drag*|U| at t-points [m/s] |
---|
311 | !! |
---|
312 | CHARACTER(len=40) :: cl_namdrg, cl_file, cl_varname, cl_namref, cl_namcfg ! local names |
---|
313 | INTEGER :: ji, jj ! dummy loop indexes |
---|
314 | LOGICAL :: ll_top, ll_bot ! local logical |
---|
315 | INTEGER :: ios, inum, imk ! local integers |
---|
316 | REAL(wp):: zmsk, zzz, zcd ! local scalars |
---|
317 | REAL(wp), DIMENSION(jpi,jpj) :: zmsk_boost ! 2D workspace |
---|
318 | !! |
---|
319 | NAMELIST/namdrg_top/ rn_Cd0, rn_Uc0, rn_Cdmax, rn_ke0, rn_z0, ln_boost, rn_boost |
---|
320 | NAMELIST/namdrg_bot/ rn_Cd0, rn_Uc0, rn_Cdmax, rn_ke0, rn_z0, ln_boost, rn_boost |
---|
321 | !!---------------------------------------------------------------------- |
---|
322 | ! |
---|
323 | ! !== set TOP / BOTTOM specificities ==! |
---|
324 | ll_top = .FALSE. |
---|
325 | ll_bot = .FALSE. |
---|
326 | ! |
---|
327 | SELECT CASE (cd_topbot) |
---|
328 | CASE( 'TOP ' ) |
---|
329 | ll_top = .TRUE. |
---|
330 | cl_namdrg = 'namdrg_top' |
---|
331 | cl_namref = 'namdrg_top in reference namelist' |
---|
332 | cl_namcfg = 'namdrg_top in configuration namelist' |
---|
333 | cl_file = 'tfr_coef.nc' |
---|
334 | cl_varname = 'tfr_coef' |
---|
335 | CASE( 'BOTTOM' ) |
---|
336 | ll_bot = .TRUE. |
---|
337 | cl_namdrg = 'namdrg_bot' |
---|
338 | cl_namref = 'namdrg_bot in reference namelist' |
---|
339 | cl_namcfg = 'namdrg_bot in configuration namelist' |
---|
340 | cl_file = 'bfr_coef.nc' |
---|
341 | cl_varname = 'bfr_coef' |
---|
342 | CASE DEFAULT |
---|
343 | CALL ctl_stop( 'drg_init: bad value for cd_topbot ' ) |
---|
344 | END SELECT |
---|
345 | ! |
---|
346 | ! !== read namlist ==! |
---|
347 | ! |
---|
348 | REWIND( numnam_ref ) ! Namelist cl_namdrg in reference namelist |
---|
349 | IF(ll_top) READ ( numnam_ref, namdrg_top, IOSTAT = ios, ERR = 901) |
---|
350 | IF(ll_bot) READ ( numnam_ref, namdrg_bot, IOSTAT = ios, ERR = 901) |
---|
351 | 901 IF( ios /= 0 ) CALL ctl_nam( ios , TRIM(cl_namref) ) |
---|
352 | REWIND( numnam_cfg ) ! Namelist cd_namdrg in configuration namelist |
---|
353 | IF(ll_top) READ ( numnam_cfg, namdrg_top, IOSTAT = ios, ERR = 902 ) |
---|
354 | IF(ll_bot) READ ( numnam_cfg, namdrg_bot, IOSTAT = ios, ERR = 902 ) |
---|
355 | 902 IF( ios > 0 ) CALL ctl_nam( ios , TRIM(cl_namcfg) ) |
---|
356 | IF(lwm .AND. ll_top) WRITE ( numond, namdrg_top ) |
---|
357 | IF(lwm .AND. ll_bot) WRITE ( numond, namdrg_bot ) |
---|
358 | ! |
---|
359 | IF(lwp) THEN |
---|
360 | WRITE(numout,*) |
---|
361 | WRITE(numout,*) ' Namelist ',TRIM(cl_namdrg),' : set ',TRIM(cd_topbot),' friction parameters' |
---|
362 | WRITE(numout,*) ' drag coefficient rn_Cd0 = ', rn_Cd0 |
---|
363 | WRITE(numout,*) ' characteristic velocity (linear case) rn_Uc0 = ', rn_Uc0, ' m/s' |
---|
364 | WRITE(numout,*) ' non-linear drag maximum rn_Cdmax = ', rn_Cdmax |
---|
365 | WRITE(numout,*) ' background kinetic energy (n-l case) rn_ke0 = ', rn_ke0 |
---|
366 | WRITE(numout,*) ' bottom roughness (n-l case) rn_z0 = ', rn_z0 |
---|
367 | WRITE(numout,*) ' set a regional boost of Cd0 ln_boost = ', ln_boost |
---|
368 | WRITE(numout,*) ' associated boost factor rn_boost = ', rn_boost |
---|
369 | ENDIF |
---|
370 | ! |
---|
371 | ! !== return some namelist parametres ==! (used in non_lin and loglayer cases) |
---|
372 | pCdmin = rn_Cd0 |
---|
373 | pCdmax = rn_Cdmax |
---|
374 | pz0 = rn_z0 |
---|
375 | pke0 = rn_ke0 |
---|
376 | ! |
---|
377 | ! !== mask * boost factor ==! |
---|
378 | ! |
---|
379 | IF( ln_boost ) THEN !* regional boost: boost factor = 1 + regional boost |
---|
380 | IF(lwp) WRITE(numout,*) |
---|
381 | IF(lwp) WRITE(numout,*) ' ==>>> use a regional boost read in ', TRIM(cl_file), ' file' |
---|
382 | IF(lwp) WRITE(numout,*) ' using enhancement factor of ', rn_boost |
---|
383 | ! cl_varname is a coefficient in [0,1] giving where to apply the regional boost |
---|
384 | CALL iom_open ( TRIM(cl_file), inum ) |
---|
385 | CALL iom_get ( inum, jpdom_data, TRIM(cl_varname), zmsk_boost, 1 ) |
---|
386 | CALL iom_close( inum) |
---|
387 | zmsk_boost(:,:) = 1._wp + rn_boost * zmsk_boost(:,:) |
---|
388 | ! |
---|
389 | ELSE !* no boost: boost factor = 1 |
---|
390 | zmsk_boost(:,:) = 1._wp |
---|
391 | ENDIF |
---|
392 | ! !* mask outside ocean cavities area (top) or land area (bot) |
---|
393 | IF(ll_top) zmsk_boost(:,:) = zmsk_boost(:,:) * ssmask(:,:) * (1. - tmask(:,:,1) ) ! none zero in ocean cavities only |
---|
394 | IF(ll_bot) zmsk_boost(:,:) = zmsk_boost(:,:) * ssmask(:,:) ! x seafloor mask |
---|
395 | ! |
---|
396 | ! |
---|
397 | SELECT CASE( ndrg ) |
---|
398 | ! |
---|
399 | CASE( np_OFF ) !== No top/bottom friction ==! (pCdU = 0) |
---|
400 | IF(lwp) WRITE(numout,*) |
---|
401 | IF(lwp) WRITE(numout,*) ' ==>>> ',TRIM(cd_topbot),' free-slip, friction set to zero' |
---|
402 | ! |
---|
403 | l_zdfdrg = .FALSE. ! no time variation of the drag: set it one for all |
---|
404 | ! |
---|
405 | pCdU(:,:) = 0._wp |
---|
406 | pCd0(:,:) = 0._wp |
---|
407 | ! |
---|
408 | CASE( np_lin ) !== linear friction ==! (pCdU = Cd0 * Uc0) |
---|
409 | IF(lwp) WRITE(numout,*) |
---|
410 | IF(lwp) WRITE(numout,*) ' ==>>> linear ',TRIM(cd_topbot),' friction (constant coef = Cd0*Uc0 = ', rn_Cd0*rn_Uc0, ')' |
---|
411 | ! |
---|
412 | l_zdfdrg = .FALSE. ! no time variation of the Cd*|U| : set it one for all |
---|
413 | ! |
---|
414 | pCd0(:,:) = rn_Cd0 * zmsk_boost(:,:) !* constant in time drag coefficient (= mask (and boost) Cd0) |
---|
415 | pCdU(:,:) = - pCd0(:,:) * rn_Uc0 ! using a constant velocity |
---|
416 | ! |
---|
417 | CASE( np_non_lin ) !== non-linear friction ==! (pCd0 = Cd0 ) |
---|
418 | IF(lwp) WRITE(numout,*) |
---|
419 | IF(lwp) WRITE(numout,*) ' ==>>> quadratic ',TRIM(cd_topbot),' friction (propotional to module of the velocity)' |
---|
420 | IF(lwp) WRITE(numout,*) ' with a drag coefficient Cd0 = ', rn_Cd0, ', and' |
---|
421 | IF(lwp) WRITE(numout,*) ' a background velocity module of (rn_ke0)^1/2 = ', SQRT(rn_ke0), 'm/s)' |
---|
422 | ! |
---|
423 | l_zdfdrg = .TRUE. !* Cd*|U| updated at each time-step (it depends on ocean velocity) |
---|
424 | ! |
---|
425 | pCd0(:,:) = rn_Cd0 * zmsk_boost(:,:) !* constant in time proportionality coefficient (= mask (and boost) Cd0) |
---|
426 | pCdU(:,:) = 0._wp ! |
---|
427 | ! |
---|
428 | CASE( np_loglayer ) !== logarithmic layer formulation of friction ==! (CdU = (vkarman log(z/z0))^2 |U| ) |
---|
429 | IF(lwp) WRITE(numout,*) |
---|
430 | IF(lwp) WRITE(numout,*) ' ==>>> quadratic ',TRIM(cd_topbot),' drag (propotional to module of the velocity)' |
---|
431 | IF(lwp) WRITE(numout,*) ' with a logarithmic Cd0 formulation Cd0 = ( vkarman log(z/z0) )^2 ,' |
---|
432 | IF(lwp) WRITE(numout,*) ' a background velocity module of (rn_ke0)^1/2 = ', SQRT(pke0), 'm/s), ' |
---|
433 | IF(lwp) WRITE(numout,*) ' a logarithmic formulation: a roughness of ', pz0, ' meters, and ' |
---|
434 | IF(lwp) WRITE(numout,*) ' a proportionality factor bounded by min/max values of ', pCdmin, pCdmax |
---|
435 | ! |
---|
436 | l_zdfdrg = .TRUE. !* Cd*|U| updated at each time-step (it depends on ocean velocity) |
---|
437 | ! |
---|
438 | IF( ln_linssh ) THEN !* pCd0 = (v log(z/z0))^2 as velocity points have a fixed z position |
---|
439 | IF(lwp) WRITE(numout,*) |
---|
440 | IF(lwp) WRITE(numout,*) ' N.B. linear free surface case, Cd0 computed one for all' |
---|
441 | ! |
---|
442 | l_log_not_linssh = .FALSE. !- don't update Cd at each time step |
---|
443 | ! |
---|
444 | DO jj = 1, jpj ! pCd0 = mask (and boosted) logarithmic drag coef. |
---|
445 | DO ji = 1, jpi |
---|
446 | zzz = 0.5_wp * e3t_0(ji,jj,k_mk(ji,jj)) |
---|
447 | zcd = ( vkarmn / LOG( zzz / rn_z0 ) )**2 |
---|
448 | pCd0(ji,jj) = zmsk_boost(ji,jj) * MIN( MAX( rn_Cd0 , zcd ) , rn_Cdmax ) ! rn_Cd0 < Cd0 < rn_Cdmax |
---|
449 | END DO |
---|
450 | END DO |
---|
451 | ELSE !* Cd updated at each time-step ==> pCd0 = mask * boost |
---|
452 | IF(lwp) WRITE(numout,*) |
---|
453 | IF(lwp) WRITE(numout,*) ' N.B. non-linear free surface case, Cd0 updated at each time-step ' |
---|
454 | ! |
---|
455 | l_log_not_linssh = .TRUE. ! compute the drag coef. at each time-step |
---|
456 | ! |
---|
457 | pCd0(:,:) = zmsk_boost(:,:) |
---|
458 | ENDIF |
---|
459 | pCdU(:,:) = 0._wp ! initialisation to zero (will be updated at each time step) |
---|
460 | ! |
---|
461 | CASE DEFAULT |
---|
462 | CALL ctl_stop( 'drg_init: bad flag value for ndrg ' ) |
---|
463 | END SELECT |
---|
464 | ! |
---|
465 | END SUBROUTINE drg_init |
---|
466 | |
---|
467 | !!====================================================================== |
---|
468 | END MODULE zdfdrg |
---|