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