icbdyn.F90 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450
  1. MODULE icbdyn
  2. !!======================================================================
  3. !! *** MODULE icbdyn ***
  4. !! Iceberg: time stepping routine for iceberg tracking
  5. !!======================================================================
  6. !! History : 3.3 ! 2010-01 (Martin&Adcroft) Original code
  7. !! - ! 2011-03 (Madec) Part conversion to NEMO form
  8. !! - ! Removal of mapping from another grid
  9. !! - ! 2011-04 (Alderson) Split into separate modules
  10. !! - ! 2011-05 (Alderson) Replace broken grounding routine with one of
  11. !! - ! Gurvan's suggestions (just like the broken one)
  12. !!----------------------------------------------------------------------
  13. USE par_oce ! NEMO parameters
  14. USE dom_oce ! NEMO ocean domain
  15. USE phycst ! NEMO physical constants
  16. USE in_out_manager ! IO parameters
  17. !
  18. USE icb_oce ! define iceberg arrays
  19. USE icbutl ! iceberg utility routines
  20. USE icbdia ! iceberg budget routines
  21. IMPLICIT NONE
  22. PRIVATE
  23. PUBLIC icb_dyn ! routine called in icbstp.F90 module
  24. !!----------------------------------------------------------------------
  25. !! NEMO/OCE 4.0 , NEMO Consortium (2018)
  26. !! $Id: icbdyn.F90 15088 2021-07-06 13:03:34Z acc $
  27. !! Software governed by the CeCILL license (see ./LICENSE)
  28. !!----------------------------------------------------------------------
  29. CONTAINS
  30. SUBROUTINE icb_dyn( kt )
  31. !!----------------------------------------------------------------------
  32. !! *** ROUTINE icb_dyn ***
  33. !!
  34. !! ** Purpose : iceberg evolution.
  35. !!
  36. !! ** Method : - See Martin & Adcroft, Ocean Modelling 34, 2010
  37. !!----------------------------------------------------------------------
  38. INTEGER, INTENT(in) :: kt !
  39. !
  40. LOGICAL :: ll_bounced
  41. REAL(wp) :: zuvel1 , zvvel1 , zu1, zv1, zax1, zay1, zxi1 , zyj1
  42. REAL(wp) :: zuvel2 , zvvel2 , zu2, zv2, zax2, zay2, zxi2 , zyj2
  43. REAL(wp) :: zuvel3 , zvvel3 , zu3, zv3, zax3, zay3, zxi3 , zyj3
  44. REAL(wp) :: zuvel4 , zvvel4 , zu4, zv4, zax4, zay4, zxi4 , zyj4
  45. REAL(wp) :: zuvel_n, zvvel_n, zxi_n , zyj_n
  46. REAL(wp) :: zdt, zdt_2, zdt_6, ze1, ze2
  47. TYPE(iceberg), POINTER :: berg
  48. TYPE(point) , POINTER :: pt
  49. !!----------------------------------------------------------------------
  50. !
  51. ! 4th order Runge-Kutta to solve: d/dt X = V, d/dt V = A
  52. ! with I.C.'s: X=X1 and V=V1
  53. !
  54. ! ; A1=A(X1,V1)
  55. ! X2 = X1+dt/2*V1 ; V2 = V1+dt/2*A1 ; A2=A(X2,V2)
  56. ! X3 = X1+dt/2*V2 ; V3 = V1+dt/2*A2 ; A3=A(X3,V3)
  57. ! X4 = X1+ dt*V3 ; V4 = V1+ dt*A3 ; A4=A(X4,V4)
  58. !
  59. ! Xn = X1+dt*(V1+2*V2+2*V3+V4)/6
  60. ! Vn = V1+dt*(A1+2*A2+2*A3+A4)/6
  61. ! time steps
  62. zdt = berg_dt
  63. zdt_2 = zdt * 0.5_wp
  64. zdt_6 = zdt / 6._wp
  65. berg => first_berg ! start from the first berg
  66. !
  67. DO WHILE ( ASSOCIATED(berg) ) !== loop over all bergs ==!
  68. !
  69. pt => berg%current_point
  70. ll_bounced = .FALSE.
  71. ! STEP 1 !
  72. ! ====== !
  73. zxi1 = pt%xi ; zuvel1 = pt%uvel !** X1 in (i,j) ; V1 in m/s
  74. zyj1 = pt%yj ; zvvel1 = pt%vvel
  75. ! !** A1 = A(X1,V1)
  76. CALL icb_accel( kt, berg , zxi1, ze1, zuvel1, zuvel1, zax1, &
  77. & zyj1, ze2, zvvel1, zvvel1, zay1, zdt_2, 0.5_wp )
  78. !
  79. zu1 = zuvel1 / ze1 !** V1 in d(i,j)/dt
  80. zv1 = zvvel1 / ze2
  81. ! STEP 2 !
  82. ! ====== !
  83. ! !** X2 = X1+dt/2*V1 ; V2 = V1+dt/2*A1
  84. ! position using di/dt & djdt ! V2 in m/s
  85. zxi2 = zxi1 + zdt_2 * zu1 ; zuvel2 = zuvel1 + zdt_2 * zax1
  86. zyj2 = zyj1 + zdt_2 * zv1 ; zvvel2 = zvvel1 + zdt_2 * zay1
  87. !
  88. CALL icb_ground( berg, zxi2, zxi1, zu1, &
  89. & zyj2, zyj1, zv1, ll_bounced )
  90. ! !** A2 = A(X2,V2)
  91. CALL icb_accel( kt, berg , zxi2, ze1, zuvel2, zuvel1, zax2, &
  92. & zyj2, ze2, zvvel2, zvvel1, zay2, zdt_2, 0.5_wp )
  93. !
  94. zu2 = zuvel2 / ze1 !** V2 in d(i,j)/dt
  95. zv2 = zvvel2 / ze2
  96. !
  97. ! STEP 3 !
  98. ! ====== !
  99. ! !** X3 = X1+dt/2*V2 ; V3 = V1+dt/2*A2; A3=A(X3)
  100. zxi3 = zxi1 + zdt_2 * zu2 ; zuvel3 = zuvel1 + zdt_2 * zax2
  101. zyj3 = zyj1 + zdt_2 * zv2 ; zvvel3 = zvvel1 + zdt_2 * zay2
  102. !
  103. CALL icb_ground( berg, zxi3, zxi1, zu2, &
  104. & zyj3, zyj1, zv2, ll_bounced )
  105. ! !** A3 = A(X3,V3)
  106. CALL icb_accel( kt, berg , zxi3, ze1, zuvel3, zuvel1, zax3, &
  107. & zyj3, ze2, zvvel3, zvvel1, zay3, zdt, 1._wp )
  108. !
  109. zu3 = zuvel3 / ze1 !** V3 in d(i,j)/dt
  110. zv3 = zvvel3 / ze2
  111. ! STEP 4 !
  112. ! ====== !
  113. ! !** X4 = X1+dt*V3 ; V4 = V1+dt*A3
  114. zxi4 = zxi1 + zdt * zu3 ; zuvel4 = zuvel1 + zdt * zax3
  115. zyj4 = zyj1 + zdt * zv3 ; zvvel4 = zvvel1 + zdt * zay3
  116. CALL icb_ground( berg, zxi4, zxi1, zu3, &
  117. & zyj4, zyj1, zv3, ll_bounced )
  118. ! !** A4 = A(X4,V4)
  119. CALL icb_accel( kt, berg , zxi4, ze1, zuvel4, zuvel1, zax4, &
  120. & zyj4, ze2, zvvel4, zvvel1, zay4, zdt, 1._wp )
  121. zu4 = zuvel4 / ze1 !** V4 in d(i,j)/dt
  122. zv4 = zvvel4 / ze2
  123. ! FINAL STEP !
  124. ! ========== !
  125. ! !** Xn = X1+dt*(V1+2*V2+2*V3+V4)/6
  126. ! !** Vn = V1+dt*(A1+2*A2+2*A3+A4)/6
  127. zxi_n = pt%xi + zdt_6 * ( zu1 + 2.*(zu2 + zu3 ) + zu4 )
  128. zyj_n = pt%yj + zdt_6 * ( zv1 + 2.*(zv2 + zv3 ) + zv4 )
  129. zuvel_n = pt%uvel + zdt_6 * ( zax1 + 2.*(zax2 + zax3) + zax4 )
  130. zvvel_n = pt%vvel + zdt_6 * ( zay1 + 2.*(zay2 + zay3) + zay4 )
  131. CALL icb_ground( berg, zxi_n, zxi1, zuvel_n, &
  132. & zyj_n, zyj1, zvvel_n, ll_bounced )
  133. pt%uvel = zuvel_n !** save in berg structure
  134. pt%vvel = zvvel_n
  135. pt%xi = zxi_n
  136. pt%yj = zyj_n
  137. berg => berg%next ! switch to the next berg
  138. !
  139. END DO !== end loop over all bergs ==!
  140. !
  141. END SUBROUTINE icb_dyn
  142. SUBROUTINE icb_ground( berg, pi, pi0, pu, &
  143. & pj, pj0, pv, ld_bounced )
  144. !!----------------------------------------------------------------------
  145. !! *** ROUTINE icb_ground ***
  146. !!
  147. !! ** Purpose : iceberg grounding.
  148. !!
  149. !! ** Method : - adjust velocity and then put iceberg back to start position
  150. !! NB two possibilities available one of which is hard-coded here
  151. !!----------------------------------------------------------------------
  152. TYPE(iceberg ), POINTER, INTENT(in ) :: berg ! berg
  153. !
  154. REAL(wp), INTENT(inout) :: pi , pj ! current iceberg position
  155. REAL(wp), INTENT(in ) :: pi0, pj0 ! previous iceberg position
  156. REAL(wp), INTENT(inout) :: pu , pv ! current iceberg velocities
  157. LOGICAL , INTENT( out) :: ld_bounced ! bounced indicator
  158. !
  159. INTEGER :: ii, ii0
  160. INTEGER :: ij, ij0
  161. INTEGER :: ikb
  162. INTEGER :: ibounce_method
  163. !
  164. REAL(wp) :: zD
  165. REAL(wp), DIMENSION(jpk) :: ze3t
  166. !
  167. LOGICAL :: licb_free
  168. !!----------------------------------------------------------------------
  169. !
  170. ld_bounced = .FALSE.
  171. !
  172. ii0 = INT( pi0+0.5 ) + (nn_hls-1) ; ij0 = INT( pj0+0.5 ) + (nn_hls-1) ! initial gridpoint position (T-cell)
  173. ii = INT( pi +0.5 ) + (nn_hls-1) ; ij = INT( pj +0.5 ) + (nn_hls-1) ! current - -
  174. !
  175. IF( ii == ii0 .AND. ij == ij0 ) RETURN ! berg remains in the same cell
  176. !
  177. ! map into current processor
  178. ii0 = mi1( ii0 )
  179. ij0 = mj1( ij0 )
  180. ii = mi1( ii )
  181. ij = mj1( ij )
  182. !
  183. ! first check if enough room to go in the new cell (use before virtual area to avoid reproducibility issue)
  184. ! case icb stay in the same cell => icb free to move (prevent issue with icb with icb area > cell area).
  185. licb_free=.TRUE.
  186. IF ( ln_icb_area_mask ) THEN !
  187. IF ( ii0 /= ii .OR. ij0 /= ij ) THEN ! icb enter in a new cell
  188. IF ( virtual_area_e(ii,ij) > e1e2t(ii,ij) ) licb_free=.FALSE. ! the new cell is full, icb cannot go in
  189. END IF
  190. END IF
  191. ! assume icb is grounded if tmask(ii,ij,1) or tmask(ii,ij,ikb), depending of the option is not 0
  192. IF ( ln_M2016 .AND. ln_icb_grd ) THEN
  193. !
  194. ! draught (keel depth)
  195. zD = rho_berg_1_oce * berg%current_point%thickness
  196. !
  197. ! interpol needed data
  198. CALL icb_utl_interp( pi, pj, pe3t=ze3t )
  199. !
  200. !compute bottom level
  201. CALL icb_utl_getkb( ikb, ze3t, zD )
  202. !
  203. ! berg reach a new t-cell, but an ocean one
  204. ! .AND. needed in case berg hit an isf (tmask(ii,ij,1) == 0 and tmask(ii,ij,ikb) /= 0)
  205. IF( tmask(ii,ij,ikb) /= 0._wp .AND. tmask(ii,ij,1) /= 0._wp .AND. licb_free ) RETURN
  206. !
  207. ELSE
  208. IF( tmask(ii,ij,1) /= 0._wp .AND. licb_free ) RETURN ! berg reach a new t-cell, but an ocean one
  209. END IF
  210. !
  211. ! From here, berg have reach land: treat grounding/bouncing
  212. ! -------------------------------
  213. ld_bounced = .TRUE.
  214. !! not obvious what should happen now
  215. !! if berg tries to enter a land box, the only location we can return it to is the start
  216. !! position (pi0,pj0), since it has to be in a wet box to do any melting;
  217. !! first option is simply to set whole velocity to zero and move back to start point
  218. !! second option (suggested by gm) is only to set the velocity component in the (i,j) direction
  219. !! of travel to zero; at a coastal boundary this has the effect of sliding the berg along the coast
  220. ibounce_method = 2
  221. SELECT CASE ( ibounce_method )
  222. CASE ( 1 )
  223. pi = pi0
  224. pj = pj0
  225. pu = 0._wp
  226. pv = 0._wp
  227. CASE ( 2 )
  228. IF( ii0 /= ii ) THEN
  229. pi = pi0 ! return back to the initial position
  230. pu = 0._wp ! zeroing of velocity in the direction of the grounding
  231. ENDIF
  232. IF( ij0 /= ij ) THEN
  233. pj = pj0 ! return back to the initial position
  234. pv = 0._wp ! zeroing of velocity in the direction of the grounding
  235. ENDIF
  236. END SELECT
  237. !
  238. END SUBROUTINE icb_ground
  239. SUBROUTINE icb_accel( kt, berg , pxi, pe1, puvel, puvel0, pax, &
  240. & pyj, pe2, pvvel, pvvel0, pay, pdt, pcfl_scale )
  241. !!----------------------------------------------------------------------
  242. !! *** ROUTINE icb_accel ***
  243. !!
  244. !! ** Purpose : compute the iceberg acceleration.
  245. !!
  246. !! ** Method : - sum the terms in the momentum budget
  247. !!----------------------------------------------------------------------
  248. TYPE(iceberg ), POINTER, INTENT(in ) :: berg ! berg
  249. INTEGER , INTENT(in ) :: kt ! time step
  250. REAL(wp) , INTENT(in ) :: pcfl_scale
  251. REAL(wp) , INTENT(in ) :: pxi , pyj ! berg position in (i,j) referential
  252. REAL(wp) , INTENT(in ) :: puvel , pvvel ! berg velocity [m/s]
  253. REAL(wp) , INTENT(in ) :: puvel0, pvvel0 ! initial berg velocity [m/s]
  254. REAL(wp) , INTENT( out) :: pe1, pe2 ! horizontal scale factor at (xi,yj)
  255. REAL(wp) , INTENT(inout) :: pax, pay ! berg acceleration
  256. REAL(wp) , INTENT(in ) :: pdt ! berg time step
  257. !
  258. REAL(wp), PARAMETER :: pp_alpha = 0._wp !
  259. REAL(wp), PARAMETER :: pp_beta = 1._wp !
  260. REAL(wp), PARAMETER :: pp_vel_lim =15._wp ! max allowed berg speed
  261. REAL(wp), PARAMETER :: pp_accel_lim = 1.e-2_wp ! max allowed berg acceleration
  262. REAL(wp), PARAMETER :: pp_Cr0 = 0.06_wp !
  263. !
  264. INTEGER :: itloop, ikb, jk
  265. REAL(wp) :: zuo, zssu, zui, zua, zuwave, zssh_x, zcn, zhi
  266. REAL(wp) :: zvo, zssv, zvi, zva, zvwave, zssh_y
  267. REAL(wp) :: zff, zT, zD, zW, zL, zM, zF
  268. REAL(wp) :: zdrag_ocn, zdrag_atm, zdrag_ice, zwave_rad
  269. REAL(wp) :: z_ocn, z_atm, z_ice, zdep
  270. REAL(wp) :: zampl, zwmod, zCr, zLwavelength, zLcutoff, zLtop
  271. REAL(wp) :: zlambda, zdetA, zA11, zA12, zaxe, zaye, zD_hi
  272. REAL(wp) :: zuveln, zvveln, zus, zvs, zspeed, zloc_dx, zspeed_new
  273. REAL(wp), DIMENSION(jpk) :: zuoce, zvoce, ze3t, zdepw
  274. !!----------------------------------------------------------------------
  275. ! Interpolate gridded fields to berg
  276. nknberg = berg%number(1)
  277. CALL icb_utl_interp( pxi, pyj, pe1=pe1, pe2=pe2, & ! scale factor
  278. & pssu=zssu, pui=zui, pua=zua, & ! oce/ice/atm velocities
  279. & pssv=zssv, pvi=zvi, pva=zva, & ! oce/ice/atm velocities
  280. & pssh_i=zssh_x, pssh_j=zssh_y, & ! ssh gradient
  281. & phi=zhi, pff=zff) ! ice thickness and coriolis
  282. zM = berg%current_point%mass
  283. zT = berg%current_point%thickness ! total thickness
  284. zD = rho_berg_1_oce * zT ! draught (keel depth)
  285. zF = zT - zD ! freeboard
  286. zW = berg%current_point%width
  287. zL = berg%current_point%length
  288. zhi = MIN( zhi , zD )
  289. zD_hi = MAX( 0._wp, zD-zhi )
  290. ! Wave radiation
  291. zuwave = zua - zssu ; zvwave = zva - zssv ! Use wind speed rel. to ocean for wave model
  292. zwmod = zuwave*zuwave + zvwave*zvwave ! The wave amplitude and length depend on the current;
  293. ! ! wind speed relative to the ocean. Actually wmod is wmod**2 here.
  294. zampl = 0.5_wp * 0.02025_wp * zwmod ! This is "a", the wave amplitude
  295. zLwavelength = 0.32_wp * zwmod ! Surface wave length fitted to data in table at
  296. ! ! http://www4.ncsu.edu/eos/users/c/ceknowle/public/chapter10/part2.html
  297. zLcutoff = 0.125_wp * zLwavelength
  298. zLtop = 0.25_wp * zLwavelength
  299. zCr = pp_Cr0 * MIN( MAX( 0._wp, (zL-zLcutoff) / ((zLtop-zLcutoff)+1.e-30)) , 1._wp) ! Wave radiation coefficient
  300. ! ! fitted to graph from Carrieres et al., POAC Drift Model.
  301. zwave_rad = 0.5_wp * pp_rho_seawater / zM * zCr * grav * zampl * MIN( zampl,zF ) * (2._wp*zW*zL) / (zW+zL)
  302. zwmod = SQRT( zua*zua + zva*zva ) ! Wind speed
  303. IF( zwmod /= 0._wp ) THEN
  304. zuwave = zua/zwmod ! Wave radiation force acts in wind direction ... !!gm this should be the wind rel. to ocean ?
  305. zvwave = zva/zwmod
  306. ELSE
  307. zuwave = 0._wp ; zvwave=0._wp ; zwave_rad=0._wp ! ... and only when wind is present. !!gm wave_rad=0. is useless
  308. ENDIF
  309. ! Weighted drag coefficients
  310. z_ocn = pp_rho_seawater / zM * (0.5_wp*pp_Cd_wv*zW*(zD_hi)+pp_Cd_wh*zW*zL)
  311. z_atm = pp_rho_air / zM * (0.5_wp*pp_Cd_av*zW*zF +pp_Cd_ah*zW*zL)
  312. z_ice = pp_rho_ice / zM * (0.5_wp*pp_Cd_iv*zW*zhi )
  313. IF( abs(zui) + abs(zvi) == 0._wp ) z_ice = 0._wp
  314. ! lateral velocities
  315. ! default ssu and ssv
  316. ! ln_M2016: mean velocity along the profile
  317. IF ( ln_M2016 ) THEN
  318. ! interpol needed data
  319. CALL icb_utl_interp( pxi, pyj, puoce=zuoce, pvoce=zvoce, pe3t=ze3t ) ! 3d velocities
  320. !compute bottom level
  321. CALL icb_utl_getkb( ikb, ze3t, zD )
  322. ! compute mean velocity
  323. CALL icb_utl_zavg(zuo, zuoce, ze3t, zD, ikb)
  324. CALL icb_utl_zavg(zvo, zvoce, ze3t, zD, ikb)
  325. ELSE
  326. zuo = zssu
  327. zvo = zssv
  328. END IF
  329. zuveln = puvel ; zvveln = pvvel ! Copy starting uvel, vvel
  330. !
  331. DO itloop = 1, 2 ! Iterate on drag coefficients
  332. !
  333. zus = 0.5_wp * ( zuveln + puvel )
  334. zvs = 0.5_wp * ( zvveln + pvvel )
  335. zdrag_ocn = z_ocn * SQRT( (zus-zuo)*(zus-zuo) + (zvs-zvo)*(zvs-zvo) )
  336. zdrag_atm = z_atm * SQRT( (zus-zua)*(zus-zua) + (zvs-zva)*(zvs-zva) )
  337. zdrag_ice = z_ice * SQRT( (zus-zui)*(zus-zui) + (zvs-zvi)*(zvs-zvi) )
  338. !
  339. ! Explicit accelerations
  340. !zaxe= zff*pvvel -grav*zssh_x +zwave_rad*zuwave &
  341. ! -zdrag_ocn*(puvel-zssu) -zdrag_atm*(puvel-zua) -zdrag_ice*(puvel-zui)
  342. !zaye=-zff*puvel -grav*zssh_y +zwave_rad*zvwave &
  343. ! -zdrag_ocn*(pvvel-zssv) -zdrag_atm*(pvvel-zva) -zdrag_ice*(pvvel-zvi)
  344. zaxe = -grav * zssh_x + zwave_rad * zuwave
  345. zaye = -grav * zssh_y + zwave_rad * zvwave
  346. IF( pp_alpha > 0._wp ) THEN ! If implicit, use time-level (n) rather than RK4 latest
  347. zaxe = zaxe + zff*pvvel0
  348. zaye = zaye - zff*puvel0
  349. ELSE
  350. zaxe = zaxe + zff*pvvel
  351. zaye = zaye - zff*puvel
  352. ENDIF
  353. IF( pp_beta > 0._wp ) THEN ! If implicit, use time-level (n) rather than RK4 latest
  354. zaxe = zaxe - zdrag_ocn*(puvel0-zuo) - zdrag_atm*(puvel0-zua) -zdrag_ice*(puvel0-zui)
  355. zaye = zaye - zdrag_ocn*(pvvel0-zvo) - zdrag_atm*(pvvel0-zva) -zdrag_ice*(pvvel0-zvi)
  356. ELSE
  357. zaxe = zaxe - zdrag_ocn*(puvel -zuo) - zdrag_atm*(puvel -zua) -zdrag_ice*(puvel -zui)
  358. zaye = zaye - zdrag_ocn*(pvvel -zvo) - zdrag_atm*(pvvel -zva) -zdrag_ice*(pvvel -zvi)
  359. ENDIF
  360. ! Solve for implicit accelerations
  361. IF( pp_alpha + pp_beta > 0._wp ) THEN
  362. zlambda = zdrag_ocn + zdrag_atm + zdrag_ice
  363. zA11 = 1._wp + pp_beta *pdt*zlambda
  364. zA12 = pp_alpha*pdt*zff
  365. zdetA = 1._wp / ( zA11*zA11 + zA12*zA12 )
  366. pax = zdetA * ( zA11*zaxe + zA12*zaye )
  367. pay = zdetA * ( zA11*zaye - zA12*zaxe )
  368. ELSE
  369. pax = zaxe ; pay = zaye
  370. ENDIF
  371. zuveln = puvel0 + pdt*pax
  372. zvveln = pvvel0 + pdt*pay
  373. !
  374. END DO ! itloop
  375. IF( rn_speed_limit > 0._wp ) THEN ! Limit speed of bergs based on a CFL criteria (if asked)
  376. zspeed = SQRT( zuveln*zuveln + zvveln*zvveln ) ! Speed of berg
  377. IF( zspeed > 0._wp ) THEN
  378. zloc_dx = MIN( pe1, pe2 ) ! minimum grid spacing
  379. ! cfl scale is function of the RK4 step
  380. zspeed_new = zloc_dx / pdt * rn_speed_limit * pcfl_scale ! Speed limit as a factor of dx / dt
  381. IF( zspeed_new < zspeed ) THEN
  382. zuveln = zuveln * ( zspeed_new / zspeed ) ! Scale velocity to reduce speed
  383. zvveln = zvveln * ( zspeed_new / zspeed ) ! without changing the direction
  384. pax = (zuveln - puvel0)/pdt
  385. pay = (zvveln - pvvel0)/pdt
  386. !
  387. ! print speeding ticket
  388. IF (nn_verbose_level > 0) THEN
  389. WRITE(numicb, 9200) 'icb speeding : ',kt, nknberg, zspeed, &
  390. & pxi, pyj, zuo, zvo, zua, zva, zui, zvi
  391. 9200 FORMAT(a,i9,i6,f9.2,1x,4(1x,2f9.2))
  392. END IF
  393. !
  394. CALL icb_dia_speed()
  395. ENDIF
  396. ENDIF
  397. ENDIF
  398. ! ! check the speed and acceleration limits
  399. IF (nn_verbose_level > 0) THEN
  400. IF( ABS( zuveln ) > pp_vel_lim .OR. ABS( zvveln ) > pp_vel_lim ) &
  401. WRITE(numicb,'("pe=",i3,x,a)') narea,'Dump triggered by excessive velocity'
  402. IF( ABS( pax ) > pp_accel_lim .OR. ABS( pay ) > pp_accel_lim ) &
  403. WRITE(numicb,'("pe=",i3,x,a)') narea,'Dump triggered by excessive acceleration'
  404. ENDIF
  405. !
  406. END SUBROUTINE icb_accel
  407. !!======================================================================
  408. END MODULE icbdyn