icbutl.F90 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835
  1. MODULE icbutl
  2. !!======================================================================
  3. !! *** MODULE icbutl ***
  4. !! Icebergs: various iceberg utility routines
  5. !!======================================================================
  6. !! History : 3.3.1 ! 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. !!----------------------------------------------------------------------
  11. !!----------------------------------------------------------------------
  12. !! icb_utl_interp :
  13. !! icb_utl_bilin :
  14. !! icb_utl_bilin_e :
  15. !!----------------------------------------------------------------------
  16. USE par_oce ! ocean parameters
  17. USE dom_oce ! ocean domain
  18. USE in_out_manager ! IO parameters
  19. USE lbclnk ! lateral boundary condition
  20. USE lib_mpp ! MPI code and lk_mpp in particular
  21. USE icb_oce ! define iceberg arrays
  22. USE sbc_oce ! ocean surface boundary conditions
  23. #if defined key_lim2
  24. USE ice_2, ONLY: u_ice, v_ice ! LIM-2 ice velocities (CAUTION in C-grid do not use key_vp option)
  25. USE ice_2, ONLY: hicif ! LIM-2 ice thickness
  26. #elif defined key_lim3
  27. USE ice, ONLY: u_ice, v_ice ! LIM-3 variables (always in C-grid)
  28. ! gm LIM3 case the mean ice thickness (i.e. averaged over categories)
  29. ! gm has to be computed somewhere in the ice and accessed here
  30. #endif
  31. IMPLICIT NONE
  32. PRIVATE
  33. PUBLIC icb_utl_copy ! routine called in icbstp module
  34. PUBLIC icb_utl_interp ! routine called in icbdyn, icbthm modules
  35. PUBLIC icb_utl_bilin ! routine called in icbini, icbdyn modules
  36. PUBLIC icb_utl_bilin_x ! routine called in icbdyn module
  37. PUBLIC icb_utl_add ! routine called in icbini.F90, icbclv, icblbc and icbrst modules
  38. PUBLIC icb_utl_delete ! routine called in icblbc, icbthm modules
  39. PUBLIC icb_utl_destroy ! routine called in icbstp module
  40. PUBLIC icb_utl_track ! routine not currently used, retain just in case
  41. PUBLIC icb_utl_print_berg ! routine called in icbthm module
  42. PUBLIC icb_utl_print ! routine called in icbini, icbstp module
  43. PUBLIC icb_utl_count ! routine called in icbdia, icbini, icblbc, icbrst modules
  44. PUBLIC icb_utl_incr ! routine called in icbini, icbclv modules
  45. PUBLIC icb_utl_yearday ! routine called in icbclv, icbstp module
  46. PUBLIC icb_utl_mass ! routine called in icbdia module
  47. PUBLIC icb_utl_heat ! routine called in icbdia module
  48. !!----------------------------------------------------------------------
  49. !! NEMO/OPA 3.3 , NEMO Consortium (2011)
  50. !! $Id: icbutl.F90 2355 2015-05-20 07:11:50Z ufla $
  51. !! Software governed by the CeCILL licence (NEMOGCM/NEMO_CeCILL.txt)
  52. !!-------------------------------------------------------------------------
  53. CONTAINS
  54. SUBROUTINE icb_utl_copy()
  55. !!----------------------------------------------------------------------
  56. !! *** ROUTINE icb_utl_copy ***
  57. !!
  58. !! ** Purpose : iceberg initialization.
  59. !!
  60. !! ** Method : - blah blah
  61. !!----------------------------------------------------------------------
  62. ! copy nemo forcing arrays into iceberg versions with extra halo
  63. ! only necessary for variables not on T points
  64. ! and ssh which is used to calculate gradients
  65. uo_e(:,:) = 0._wp ; uo_e(1:jpi, 1:jpj) = ssu_m(:,:) * umask(:,:,1)
  66. vo_e(:,:) = 0._wp ; vo_e(1:jpi, 1:jpj) = ssv_m(:,:) * vmask(:,:,1)
  67. ff_e(:,:) = 0._wp ; ff_e(1:jpi, 1:jpj) = ff (:,:)
  68. tt_e(:,:) = 0._wp ; tt_e(1:jpi, 1:jpj) = sst_m(:,:)
  69. fr_e(:,:) = 0._wp ; fr_e(1:jpi, 1:jpj) = fr_i (:,:)
  70. ua_e(:,:) = 0._wp ; ua_e(1:jpi, 1:jpj) = utau (:,:) * umask(:,:,1) ! maybe mask useless because mask applied in sbcblk
  71. va_e(:,:) = 0._wp ; va_e(1:jpi, 1:jpj) = vtau (:,:) * vmask(:,:,1) ! maybe mask useless because mask applied in sbcblk
  72. CALL lbc_lnk_icb( uo_e, 'U', -1._wp, 1, 1 )
  73. CALL lbc_lnk_icb( vo_e, 'V', -1._wp, 1, 1 )
  74. CALL lbc_lnk_icb( ff_e, 'F', +1._wp, 1, 1 )
  75. CALL lbc_lnk_icb( ua_e, 'U', -1._wp, 1, 1 )
  76. CALL lbc_lnk_icb( va_e, 'V', -1._wp, 1, 1 )
  77. CALL lbc_lnk_icb( fr_e, 'T', +1._wp, 1, 1 )
  78. CALL lbc_lnk_icb( tt_e, 'T', +1._wp, 1, 1 )
  79. #if defined key_lim2
  80. hicth(:,:) = 0._wp ; hicth(1:jpi,1:jpj) = hicif(:,:)
  81. CALL lbc_lnk_icb(hicth, 'T', +1._wp, 1, 1 )
  82. #endif
  83. #if defined key_lim2 || defined key_lim3
  84. ui_e(:,:) = 0._wp ; ui_e(1:jpi, 1:jpj) = u_ice(:,:)
  85. vi_e(:,:) = 0._wp ; vi_e(1:jpi, 1:jpj) = v_ice(:,:)
  86. CALL lbc_lnk_icb( ui_e, 'U', -1._wp, 1, 1 )
  87. CALL lbc_lnk_icb( vi_e, 'V', -1._wp, 1, 1 )
  88. #endif
  89. !! special for ssh which is used to calculate slope
  90. !! so fudge some numbers all the way around the boundary
  91. ssh_e(:,:) = 0._wp ; ssh_e(1:jpi, 1:jpj) = ssh_m(:,:) * tmask(:,:,1)
  92. ssh_e(0 , :) = ssh_e(1 , :)
  93. ssh_e(jpi+1, :) = ssh_e(jpi, :)
  94. ssh_e(: , 0) = ssh_e(: , 1)
  95. ssh_e(: ,jpj+1) = ssh_e(: ,jpj)
  96. ssh_e(0,0) = ssh_e(1,1)
  97. ssh_e(jpi+1,0) = ssh_e(jpi,1)
  98. ssh_e(0,jpj+1) = ssh_e(1,jpj)
  99. ssh_e(jpi+1,jpj+1) = ssh_e(jpi,jpj)
  100. CALL lbc_lnk_icb( ssh_e, 'T', +1._wp, 1, 1 )
  101. !
  102. END SUBROUTINE icb_utl_copy
  103. SUBROUTINE icb_utl_interp( pi, pe1, puo, pui, pua, pssh_i, &
  104. & pj, pe2, pvo, pvi, pva, pssh_j, &
  105. & psst, pcn, phi, pff )
  106. !!----------------------------------------------------------------------
  107. !! *** ROUTINE icb_utl_interp ***
  108. !!
  109. !! ** Purpose : interpolation
  110. !!
  111. !! ** Method : - interpolate from various ocean arrays onto iceberg position
  112. !!
  113. !! !!gm CAUTION here I do not care of the slip/no-slip conditions
  114. !! this can be done later (not that easy to do...)
  115. !! right now, U is 0 in land so that the coastal value of velocity parallel to the coast
  116. !! is half the off shore value, wile the normal-to-the-coast value is zero.
  117. !! This is OK as a starting point.
  118. !!
  119. !!----------------------------------------------------------------------
  120. REAL(wp), INTENT(in ) :: pi , pj ! position in (i,j) referential
  121. REAL(wp), INTENT( out) :: pe1, pe2 ! i- and j scale factors
  122. REAL(wp), INTENT( out) :: puo, pvo, pui, pvi, pua, pva ! ocean, ice and wind speeds
  123. REAL(wp), INTENT( out) :: pssh_i, pssh_j ! ssh i- & j-gradients
  124. REAL(wp), INTENT( out) :: psst, pcn, phi, pff ! SST, ice concentration, ice thickness, Coriolis
  125. !
  126. REAL(wp) :: zcd, zmod ! local scalars
  127. !!----------------------------------------------------------------------
  128. pe1 = icb_utl_bilin_e( e1t, e1u, e1v, e1f, pi, pj ) ! scale factors
  129. pe2 = icb_utl_bilin_e( e2t, e2u, e2v, e2f, pi, pj )
  130. !
  131. puo = icb_utl_bilin_h( uo_e, pi, pj, 'U' ) ! ocean velocities
  132. pvo = icb_utl_bilin_h( vo_e, pi, pj, 'V' )
  133. psst = icb_utl_bilin_h( tt_e, pi, pj, 'T' ) ! SST
  134. pcn = icb_utl_bilin_h( fr_e , pi, pj, 'T' ) ! ice concentration
  135. pff = icb_utl_bilin_h( ff_e , pi, pj, 'F' ) ! Coriolis parameter
  136. !
  137. pua = icb_utl_bilin_h( ua_e , pi, pj, 'U' ) ! 10m wind
  138. pva = icb_utl_bilin_h( va_e , pi, pj, 'V' ) ! here (ua,va) are stress => rough conversion from stress to speed
  139. zcd = 1.22_wp * 1.5e-3_wp ! air density * drag coefficient
  140. zmod = 1._wp / MAX( 1.e-20, SQRT( zcd * SQRT( pua*pua + pva*pva) ) )
  141. pua = pua * zmod ! note: stress module=0 necessarly implies ua=va=0
  142. pva = pva * zmod
  143. #if defined key_lim2 || defined key_lim3
  144. pui = icb_utl_bilin_h( ui_e, pi, pj, 'U' ) ! sea-ice velocities
  145. pvi = icb_utl_bilin_h( vi_e, pi, pj, 'V' )
  146. # if defined key_lim3
  147. phi = 0._wp ! LIM-3 case (to do)
  148. # else
  149. phi = icb_utl_bilin_h(hicth, pi, pj, 'T' ) ! ice thickness
  150. # endif
  151. #else
  152. pui = 0._wp
  153. pvi = 0._wp
  154. phi = 0._wp
  155. #endif
  156. ! Estimate SSH gradient in i- and j-direction (centred evaluation)
  157. pssh_i = ( icb_utl_bilin_h( ssh_e, pi+0.1_wp, pj, 'T' ) - &
  158. & icb_utl_bilin_h( ssh_e, pi-0.1_wp, pj, 'T' ) ) / ( 0.2_wp * pe1 )
  159. pssh_j = ( icb_utl_bilin_h( ssh_e, pi, pj+0.1_wp, 'T' ) - &
  160. & icb_utl_bilin_h( ssh_e, pi, pj-0.1_wp, 'T' ) ) / ( 0.2_wp * pe2 )
  161. !
  162. END SUBROUTINE icb_utl_interp
  163. REAL(wp) FUNCTION icb_utl_bilin_h( pfld, pi, pj, cd_type )
  164. !!----------------------------------------------------------------------
  165. !! *** FUNCTION icb_utl_bilin ***
  166. !!
  167. !! ** Purpose : bilinear interpolation at berg location depending on the grid-point type
  168. !! this version deals with extra halo points
  169. !!
  170. !! !!gm CAUTION an optional argument should be added to handle
  171. !! the slip/no-slip conditions ==>>> to be done later
  172. !!
  173. !!----------------------------------------------------------------------
  174. REAL(wp), DIMENSION(0:jpi+1,0:jpj+1), INTENT(in) :: pfld ! field to be interpolated
  175. REAL(wp) , INTENT(in) :: pi, pj ! targeted coordinates in (i,j) referential
  176. CHARACTER(len=1) , INTENT(in) :: cd_type ! type of pfld array grid-points: = T , U , V or F points
  177. !
  178. INTEGER :: ii, ij ! local integer
  179. REAL(wp) :: zi, zj ! local real
  180. !!----------------------------------------------------------------------
  181. !
  182. SELECT CASE ( cd_type )
  183. CASE ( 'T' )
  184. ! note that here there is no +0.5 added
  185. ! since we're looking for four T points containing quadrant we're in of
  186. ! current T cell
  187. ii = MAX(1, INT( pi ))
  188. ij = MAX(1, INT( pj )) ! T-point
  189. zi = pi - REAL(ii,wp)
  190. zj = pj - REAL(ij,wp)
  191. CASE ( 'U' )
  192. ii = MAX(1, INT( pi-0.5 ))
  193. ij = MAX(1, INT( pj )) ! U-point
  194. zi = pi - 0.5 - REAL(ii,wp)
  195. zj = pj - REAL(ij,wp)
  196. CASE ( 'V' )
  197. ii = MAX(1, INT( pi ))
  198. ij = MAX(1, INT( pj-0.5 )) ! V-point
  199. zi = pi - REAL(ii,wp)
  200. zj = pj - 0.5 - REAL(ij,wp)
  201. CASE ( 'F' )
  202. ii = MAX(1, INT( pi-0.5 ))
  203. ij = MAX(1, INT( pj-0.5 )) ! F-point
  204. zi = pi - 0.5 - REAL(ii,wp)
  205. zj = pj - 0.5 - REAL(ij,wp)
  206. END SELECT
  207. !
  208. ! find position in this processor. Prevent near edge problems (see #1389)
  209. if (ii.lt.mig(1)) then
  210. ii = 1
  211. else if (ii.gt.mig(jpi)) then
  212. ii = jpi
  213. else
  214. ii = mi1( ii )
  215. end if
  216. if (ij.lt.mjg(1)) then
  217. ij = 1
  218. else if (ij.gt.mjg(jpj)) then
  219. ij = jpj
  220. else
  221. ij = mj1( ij )
  222. end if
  223. if (ij.eq.jpj) ij=ij-1
  224. if (ii.eq.jpi) ii=ii-1
  225. !
  226. icb_utl_bilin_h = ( pfld(ii,ij ) * (1.-zi) + pfld(ii+1,ij ) * zi ) * (1.-zj) &
  227. & + ( pfld(ii,ij+1) * (1.-zi) + pfld(ii+1,ij+1) * zi ) * zj
  228. !
  229. END FUNCTION icb_utl_bilin_h
  230. REAL(wp) FUNCTION icb_utl_bilin( pfld, pi, pj, cd_type )
  231. !!----------------------------------------------------------------------
  232. !! *** FUNCTION icb_utl_bilin ***
  233. !!
  234. !! ** Purpose : bilinear interpolation at berg location depending on the grid-point type
  235. !!
  236. !! !!gm CAUTION an optional argument should be added to handle
  237. !! the slip/no-slip conditions ==>>> to be done later
  238. !!
  239. !!----------------------------------------------------------------------
  240. REAL(wp), DIMENSION(jpi,jpj), INTENT(in) :: pfld ! field to be interpolated
  241. REAL(wp) , INTENT(in) :: pi, pj ! targeted coordinates in (i,j) referential
  242. CHARACTER(len=1) , INTENT(in) :: cd_type ! type of pfld array grid-points: = T , U , V or F points
  243. !
  244. INTEGER :: ii, ij ! local integer
  245. REAL(wp) :: zi, zj ! local real
  246. !!----------------------------------------------------------------------
  247. !
  248. SELECT CASE ( cd_type )
  249. CASE ( 'T' )
  250. ! note that here there is no +0.5 added
  251. ! since we're looking for four T points containing quadrant we're in of
  252. ! current T cell
  253. ii = MAX(1, INT( pi ))
  254. ij = MAX(1, INT( pj )) ! T-point
  255. zi = pi - REAL(ii,wp)
  256. zj = pj - REAL(ij,wp)
  257. CASE ( 'U' )
  258. ii = MAX(1, INT( pi-0.5 ))
  259. ij = MAX(1, INT( pj )) ! U-point
  260. zi = pi - 0.5 - REAL(ii,wp)
  261. zj = pj - REAL(ij,wp)
  262. CASE ( 'V' )
  263. ii = MAX(1, INT( pi ))
  264. ij = MAX(1, INT( pj-0.5 )) ! V-point
  265. zi = pi - REAL(ii,wp)
  266. zj = pj - 0.5 - REAL(ij,wp)
  267. CASE ( 'F' )
  268. ii = MAX(1, INT( pi-0.5 ))
  269. ij = MAX(1, INT( pj-0.5 )) ! F-point
  270. zi = pi - 0.5 - REAL(ii,wp)
  271. zj = pj - 0.5 - REAL(ij,wp)
  272. END SELECT
  273. !
  274. ! find position in this processor. Prevent near edge problems (see #1389)
  275. if (ii.lt.mig(1)) then
  276. ii = 1
  277. else if (ii.gt.mig(jpi)) then
  278. ii = jpi
  279. else
  280. ii = mi1( ii )
  281. end if
  282. if (ij.lt.mjg(1)) then
  283. ij = 1
  284. else if (ij.gt.mjg(jpj)) then
  285. ij = jpj
  286. else
  287. ij = mj1( ij )
  288. end if
  289. if (ij.eq.jpj) ij=ij-1
  290. if (ii.eq.jpi) ii=ii-1
  291. icb_utl_bilin = ( pfld(ii,ij ) * (1.-zi) + pfld(ii+1,ij ) * zi ) * (1.-zj) &
  292. & + ( pfld(ii,ij+1) * (1.-zi) + pfld(ii+1,ij+1) * zi ) * zj
  293. !
  294. END FUNCTION icb_utl_bilin
  295. REAL(wp) FUNCTION icb_utl_bilin_x( pfld, pi, pj )
  296. !!----------------------------------------------------------------------
  297. !! *** FUNCTION icb_utl_bilin_x ***
  298. !!
  299. !! ** Purpose : bilinear interpolation at berg location depending on the grid-point type
  300. !! Special case for interpolating longitude
  301. !!
  302. !! !!gm CAUTION an optional argument should be added to handle
  303. !! the slip/no-slip conditions ==>>> to be done later
  304. !!
  305. !!----------------------------------------------------------------------
  306. REAL(wp), DIMENSION(jpi,jpj), INTENT(in) :: pfld ! field to be interpolated
  307. REAL(wp) , INTENT(in) :: pi, pj ! targeted coordinates in (i,j) referential
  308. !
  309. INTEGER :: ii, ij ! local integer
  310. REAL(wp) :: zi, zj ! local real
  311. REAL(wp) :: zret ! local real
  312. REAL(wp), DIMENSION(4) :: z4
  313. !!----------------------------------------------------------------------
  314. !
  315. ! note that here there is no +0.5 added
  316. ! since we're looking for four T points containing quadrant we're in of
  317. ! current T cell
  318. ii = MAX(1, INT( pi ))
  319. ij = MAX(1, INT( pj )) ! T-point
  320. zi = pi - REAL(ii,wp)
  321. zj = pj - REAL(ij,wp)
  322. !
  323. ! find position in this processor. Prevent near edge problems (see #1389)
  324. if (ii.lt.mig(1)) then
  325. ii = 1
  326. else if (ii.gt.mig(jpi)) then
  327. ii = jpi
  328. else
  329. ii = mi1( ii )
  330. end if
  331. if (ij.lt.mjg(1)) then
  332. ij = 1
  333. else if (ij.gt.mjg(jpj)) then
  334. ij = jpj
  335. else
  336. ij = mj1( ij )
  337. end if
  338. if (ij.eq.jpj) ij=ij-1
  339. if (ii.eq.jpi) ii=ii-1
  340. z4(1) = pfld(ii ,ij )
  341. z4(2) = pfld(ii+1,ij )
  342. z4(3) = pfld(ii ,ij+1)
  343. z4(4) = pfld(ii+1,ij+1)
  344. IF( MAXVAL(z4) - MINVAL(z4) > 90._wp ) THEN
  345. WHERE( z4 < 0._wp ) z4 = z4 + 360._wp
  346. ENDIF
  347. !
  348. zret = (z4(1) * (1.-zi) + z4(2) * zi) * (1.-zj) + (z4(3) * (1.-zi) + z4(4) * zi) * zj
  349. IF( zret > 180._wp ) zret = zret - 360._wp
  350. icb_utl_bilin_x = zret
  351. !
  352. END FUNCTION icb_utl_bilin_x
  353. REAL(wp) FUNCTION icb_utl_bilin_e( pet, peu, pev, pef, pi, pj )
  354. !!----------------------------------------------------------------------
  355. !! *** FUNCTION dom_init ***
  356. !!
  357. !! ** Purpose : bilinear interpolation at berg location of horizontal scale factor
  358. !! ** Method : interpolation done using the 4 nearest grid points among
  359. !! t-, u-, v-, and f-points.
  360. !!----------------------------------------------------------------------
  361. REAL(wp), DIMENSION(:,:), INTENT(in) :: pet, peu, pev, pef ! horizontal scale factor to be interpolated at t-,u-,v- & f-pts
  362. REAL(wp) , INTENT(in) :: pi, pj ! targeted coordinates in (i,j) referential
  363. !
  364. INTEGER :: ii, ij, icase ! local integer
  365. !
  366. ! weights corresponding to corner points of a T cell quadrant
  367. REAL(wp) :: zi, zj ! local real
  368. !
  369. ! values at corner points of a T cell quadrant
  370. ! 00 = bottom left, 10 = bottom right, 01 = top left, 11 = top right
  371. REAL(wp) :: ze00, ze10, ze01, ze11
  372. !!----------------------------------------------------------------------
  373. !
  374. ii = MAX(1, INT( pi )) ; ij = MAX(1, INT( pj )) ! left bottom T-point (i,j) indices
  375. ! fractional box spacing
  376. ! 0 <= zi < 0.5, 0 <= zj < 0.5 --> NW quadrant of current T cell
  377. ! 0.5 <= zi < 1 , 0 <= zj < 0.5 --> NE quadrant
  378. ! 0 <= zi < 0.5, 0.5 <= zj < 1 --> SE quadrant
  379. ! 0.5 <= zi < 1 , 0.5 <= zj < 1 --> SW quadrant
  380. zi = pi - REAL(ii,wp) !!gm use here mig, mjg arrays
  381. zj = pj - REAL(ij,wp)
  382. ! find position in this processor. Prevent near edge problems (see #1389)
  383. if (ii.lt.mig(1)) then
  384. ii = 1
  385. else if (ii.gt.mig(jpi)) then
  386. ii = jpi
  387. else
  388. ii = mi1( ii )
  389. end if
  390. if (ij.lt.mjg(1)) then
  391. ij = 1
  392. else if (ij.gt.mjg(jpj)) then
  393. ij = jpj
  394. else
  395. ij = mj1( ij )
  396. end if
  397. if (ij.eq.jpj) ij=ij-1
  398. if (ii.eq.jpi) ii=ii-1
  399. IF( 0.0_wp <= zi .AND. zi < 0.5_wp ) THEN
  400. IF( 0.0_wp <= zj .AND. zj < 0.5_wp ) THEN ! NE quadrant
  401. ! ! i=I i=I+1/2
  402. ze01 = pev(ii ,ij ) ; ze11 = pef(ii ,ij ) ! j=J+1/2 V ------- F
  403. ze00 = pet(ii ,ij ) ; ze10 = peu(ii ,ij ) ! j=J T ------- U
  404. zi = 2._wp * zi
  405. zj = 2._wp * zj
  406. ELSE ! SE quadrant
  407. ! ! i=I i=I+1/2
  408. ze01 = pet(ii ,ij+1) ; ze11 = peu(ii ,ij+1) ! j=J+1 T ------- U
  409. ze00 = pev(ii ,ij ) ; ze10 = pef(ii ,ij ) ! j=J+1/2 V ------- F
  410. zi = 2._wp * zi
  411. zj = 2._wp * (zj-0.5_wp)
  412. ENDIF
  413. ELSE
  414. IF( 0.0_wp <= zj .AND. zj < 0.5_wp ) THEN ! NW quadrant
  415. ! ! i=I i=I+1/2
  416. ze01 = pef(ii ,ij ) ; ze11 = pev(ii+1,ij) ! j=J+1/2 F ------- V
  417. ze00 = peu(ii ,ij ) ; ze10 = pet(ii+1,ij) ! j=J U ------- T
  418. zi = 2._wp * (zi-0.5_wp)
  419. zj = 2._wp * zj
  420. ELSE ! SW quadrant
  421. ! ! i=I+1/2 i=I+1
  422. ze01 = peu(ii ,ij+1) ; ze11 = pet(ii+1,ij+1) ! j=J+1 U ------- T
  423. ze00 = pef(ii ,ij ) ; ze10 = pev(ii+1,ij ) ! j=J+1/2 F ------- V
  424. zi = 2._wp * (zi-0.5_wp)
  425. zj = 2._wp * (zj-0.5_wp)
  426. ENDIF
  427. ENDIF
  428. !
  429. icb_utl_bilin_e = ( ze01 * (1.-zi) + ze11 * zi ) * zj &
  430. & + ( ze00 * (1.-zi) + ze10 * zi ) * (1.-zj)
  431. !
  432. END FUNCTION icb_utl_bilin_e
  433. SUBROUTINE icb_utl_add( bergvals, ptvals )
  434. !!----------------------------------------------------------------------
  435. !! *** ROUTINE icb_utl_add ***
  436. !!
  437. !! ** Purpose : add a new berg to the iceberg list
  438. !!
  439. !!----------------------------------------------------------------------
  440. TYPE(iceberg), INTENT(in) :: bergvals
  441. TYPE(point) , INTENT(in) :: ptvals
  442. !
  443. TYPE(iceberg), POINTER :: new => NULL()
  444. !!----------------------------------------------------------------------
  445. !
  446. new => NULL()
  447. CALL icb_utl_create( new, bergvals, ptvals )
  448. CALL icb_utl_insert( new )
  449. new => NULL() ! Clear new
  450. !
  451. END SUBROUTINE icb_utl_add
  452. SUBROUTINE icb_utl_create( berg, bergvals, ptvals )
  453. !!----------------------------------------------------------------------
  454. !! *** ROUTINE icb_utl_create ***
  455. !!
  456. !! ** Purpose : add a new berg to the iceberg list
  457. !!
  458. !!----------------------------------------------------------------------
  459. TYPE(iceberg), INTENT(in) :: bergvals
  460. TYPE(point) , INTENT(in) :: ptvals
  461. TYPE(iceberg), POINTER :: berg
  462. !
  463. TYPE(point) , POINTER :: pt
  464. INTEGER :: istat
  465. !!----------------------------------------------------------------------
  466. !
  467. IF( ASSOCIATED(berg) ) CALL ctl_stop( 'icebergs, icb_utl_create: berg already associated' )
  468. ALLOCATE(berg, STAT=istat)
  469. IF( istat /= 0 ) CALL ctl_stop( 'failed to allocate iceberg' )
  470. berg%number(:) = bergvals%number(:)
  471. berg%mass_scaling = bergvals%mass_scaling
  472. berg%prev => NULL()
  473. berg%next => NULL()
  474. !
  475. ALLOCATE(pt, STAT=istat)
  476. IF( istat /= 0 ) CALL ctl_stop( 'failed to allocate first iceberg point' )
  477. pt = ptvals
  478. berg%current_point => pt
  479. !
  480. END SUBROUTINE icb_utl_create
  481. SUBROUTINE icb_utl_insert( newberg )
  482. !!----------------------------------------------------------------------
  483. !! *** ROUTINE icb_utl_insert ***
  484. !!
  485. !! ** Purpose : add a new berg to the iceberg list
  486. !!
  487. !!----------------------------------------------------------------------
  488. TYPE(iceberg), POINTER :: newberg
  489. !
  490. TYPE(iceberg), POINTER :: this, prev, last
  491. !!----------------------------------------------------------------------
  492. !
  493. IF( ASSOCIATED( first_berg ) ) THEN
  494. last => first_berg
  495. DO WHILE (ASSOCIATED(last%next))
  496. last => last%next
  497. ENDDO
  498. newberg%prev => last
  499. last%next => newberg
  500. last => newberg
  501. ELSE ! list is empty so create it
  502. first_berg => newberg
  503. ENDIF
  504. !
  505. END SUBROUTINE icb_utl_insert
  506. REAL(wp) FUNCTION icb_utl_yearday(kmon, kday, khr, kmin, ksec)
  507. !!----------------------------------------------------------------------
  508. !! *** FUNCTION icb_utl_yearday ***
  509. !!
  510. !! ** Purpose :
  511. !!
  512. ! sga - improved but still only applies to 365 day year, need to do this properly
  513. !
  514. !!gm all these info are already known in daymod, no???
  515. !!
  516. !!----------------------------------------------------------------------
  517. INTEGER, INTENT(in) :: kmon, kday, khr, kmin, ksec
  518. !
  519. INTEGER, DIMENSION(12) :: imonths = (/ 0,31,28,31,30,31,30,31,31,30,31,30 /)
  520. !!----------------------------------------------------------------------
  521. !
  522. icb_utl_yearday = REAL( SUM( imonths(1:kmon) ), wp )
  523. icb_utl_yearday = icb_utl_yearday + REAL(kday-1,wp) + (REAL(khr,wp) + (REAL(kmin,wp) + REAL(ksec,wp)/60.)/60.)/24.
  524. !
  525. END FUNCTION icb_utl_yearday
  526. !!-------------------------------------------------------------------------
  527. SUBROUTINE icb_utl_delete( first, berg )
  528. !!----------------------------------------------------------------------
  529. !! *** ROUTINE icb_utl_delete ***
  530. !!
  531. !! ** Purpose :
  532. !!
  533. !!----------------------------------------------------------------------
  534. TYPE(iceberg), POINTER :: first, berg
  535. !!----------------------------------------------------------------------
  536. ! Connect neighbors to each other
  537. IF ( ASSOCIATED(berg%prev) ) THEN
  538. berg%prev%next => berg%next
  539. ELSE
  540. first => berg%next
  541. ENDIF
  542. IF (ASSOCIATED(berg%next)) berg%next%prev => berg%prev
  543. !
  544. CALL icb_utl_destroy(berg)
  545. !
  546. END SUBROUTINE icb_utl_delete
  547. SUBROUTINE icb_utl_destroy( berg )
  548. !!----------------------------------------------------------------------
  549. !! *** ROUTINE icb_utl_destroy ***
  550. !!
  551. !! ** Purpose : remove a single iceberg instance
  552. !!
  553. !!----------------------------------------------------------------------
  554. TYPE(iceberg), POINTER :: berg
  555. !!----------------------------------------------------------------------
  556. !
  557. ! Remove any points
  558. IF( ASSOCIATED( berg%current_point ) ) DEALLOCATE( berg%current_point )
  559. !
  560. DEALLOCATE(berg)
  561. !
  562. END SUBROUTINE icb_utl_destroy
  563. SUBROUTINE icb_utl_track( knum, cd_label, kt )
  564. !!----------------------------------------------------------------------
  565. !! *** ROUTINE icb_utl_track ***
  566. !!
  567. !! ** Purpose :
  568. !!
  569. !!----------------------------------------------------------------------
  570. INTEGER, DIMENSION(nkounts) :: knum ! iceberg number
  571. CHARACTER(len=*) :: cd_label !
  572. INTEGER :: kt ! timestep number
  573. !
  574. TYPE(iceberg), POINTER :: this
  575. LOGICAL :: match
  576. INTEGER :: k
  577. !!----------------------------------------------------------------------
  578. !
  579. this => first_berg
  580. DO WHILE( ASSOCIATED(this) )
  581. match = .TRUE.
  582. DO k = 1, nkounts
  583. IF( this%number(k) /= knum(k) ) match = .FALSE.
  584. END DO
  585. IF( match ) CALL icb_utl_print_berg(this, kt)
  586. this => this%next
  587. END DO
  588. !
  589. END SUBROUTINE icb_utl_track
  590. SUBROUTINE icb_utl_print_berg( berg, kt )
  591. !!----------------------------------------------------------------------
  592. !! *** ROUTINE icb_utl_print_berg ***
  593. !!
  594. !! ** Purpose : print one
  595. !!
  596. !!----------------------------------------------------------------------
  597. TYPE(iceberg), POINTER :: berg
  598. TYPE(point) , POINTER :: pt
  599. INTEGER :: kt ! timestep number
  600. !!----------------------------------------------------------------------
  601. !
  602. pt => berg%current_point
  603. WRITE(numicb, 9200) kt, berg%number(1), &
  604. pt%xi, pt%yj, pt%lon, pt%lat, pt%uvel, pt%vvel, &
  605. pt%uo, pt%vo, pt%ua, pt%va, pt%ui, pt%vi
  606. CALL flush( numicb )
  607. 9200 FORMAT(5x,i5,2x,i10,6(2x,2f10.4))
  608. !
  609. END SUBROUTINE icb_utl_print_berg
  610. SUBROUTINE icb_utl_print( cd_label, kt )
  611. !!----------------------------------------------------------------------
  612. !! *** ROUTINE icb_utl_print ***
  613. !!
  614. !! ** Purpose : print many
  615. !!
  616. !!----------------------------------------------------------------------
  617. CHARACTER(len=*) :: cd_label
  618. INTEGER :: kt ! timestep number
  619. !
  620. INTEGER :: ibergs, inbergs
  621. TYPE(iceberg), POINTER :: this
  622. !!----------------------------------------------------------------------
  623. !
  624. this => first_berg
  625. IF( ASSOCIATED(this) ) THEN
  626. WRITE(numicb,'(a," pe=(",i3,")")' ) cd_label, narea
  627. WRITE(numicb,'(a8,4x,a6,12x,a5,15x,a7,19x,a3,17x,a5,17x,a5,17x,a5)' ) &
  628. & 'timestep', 'number', 'xi,yj','lon,lat','u,v','uo,vo','ua,va','ui,vi'
  629. ENDIF
  630. DO WHILE( ASSOCIATED(this) )
  631. CALL icb_utl_print_berg(this, kt)
  632. this => this%next
  633. END DO
  634. ibergs = icb_utl_count()
  635. inbergs = ibergs
  636. IF( lk_mpp ) CALL mpp_sum(inbergs)
  637. IF( ibergs > 0 ) WRITE(numicb,'(a," there are",i5," bergs out of",i6," on PE ",i4)') &
  638. & cd_label, ibergs, inbergs, narea
  639. !
  640. END SUBROUTINE icb_utl_print
  641. SUBROUTINE icb_utl_incr()
  642. !!----------------------------------------------------------------------
  643. !! *** ROUTINE icb_utl_incr ***
  644. !!
  645. !! ** Purpose :
  646. !!
  647. ! Small routine for coping with very large integer values labelling icebergs
  648. ! num_bergs is a array of integers
  649. ! the first member is incremented in steps of jpnij starting from narea
  650. ! this means each iceberg is labelled with a unique number
  651. ! when this gets to the maximum allowed integer the second and subsequent members are
  652. ! used to count how many times the member before cycles
  653. !!----------------------------------------------------------------------
  654. INTEGER :: ii, ibig
  655. !!----------------------------------------------------------------------
  656. ibig = HUGE(num_bergs(1))
  657. IF( ibig-jpnij < num_bergs(1) ) THEN
  658. num_bergs(1) = narea
  659. DO ii = 2,nkounts
  660. IF( num_bergs(ii) == ibig ) THEN
  661. num_bergs(ii) = 0
  662. IF( ii == nkounts ) CALL ctl_stop('Sorry, run out of iceberg number space')
  663. ELSE
  664. num_bergs(ii) = num_bergs(ii) + 1
  665. EXIT
  666. ENDIF
  667. END DO
  668. ELSE
  669. num_bergs(1) = num_bergs(1) + jpnij
  670. ENDIF
  671. !
  672. END SUBROUTINE icb_utl_incr
  673. INTEGER FUNCTION icb_utl_count()
  674. !!----------------------------------------------------------------------
  675. !! *** FUNCTION icb_utl_count ***
  676. !!
  677. !! ** Purpose :
  678. !!----------------------------------------------------------------------
  679. TYPE(iceberg), POINTER :: this
  680. !!----------------------------------------------------------------------
  681. !
  682. icb_utl_count = 0
  683. this => first_berg
  684. DO WHILE( ASSOCIATED(this) )
  685. icb_utl_count = icb_utl_count+1
  686. this => this%next
  687. END DO
  688. !
  689. END FUNCTION icb_utl_count
  690. REAL(wp) FUNCTION icb_utl_mass( first, justbits, justbergs )
  691. !!----------------------------------------------------------------------
  692. !! *** FUNCTION icb_utl_mass ***
  693. !!
  694. !! ** Purpose : compute the mass all iceberg, all berg bits or all bergs.
  695. !!----------------------------------------------------------------------
  696. TYPE(iceberg) , POINTER :: first
  697. TYPE(point) , POINTER :: pt
  698. LOGICAL, INTENT(in), OPTIONAL :: justbits, justbergs
  699. !
  700. TYPE(iceberg), POINTER :: this
  701. !!----------------------------------------------------------------------
  702. icb_utl_mass = 0._wp
  703. this => first
  704. !
  705. IF( PRESENT( justbergs ) ) THEN
  706. DO WHILE( ASSOCIATED( this ) )
  707. pt => this%current_point
  708. icb_utl_mass = icb_utl_mass + pt%mass * this%mass_scaling
  709. this => this%next
  710. END DO
  711. ELSEIF( PRESENT(justbits) ) THEN
  712. DO WHILE( ASSOCIATED( this ) )
  713. pt => this%current_point
  714. icb_utl_mass = icb_utl_mass + pt%mass_of_bits * this%mass_scaling
  715. this => this%next
  716. END DO
  717. ELSE
  718. DO WHILE( ASSOCIATED( this ) )
  719. pt => this%current_point
  720. icb_utl_mass = icb_utl_mass + ( pt%mass + pt%mass_of_bits ) * this%mass_scaling
  721. this => this%next
  722. END DO
  723. ENDIF
  724. !
  725. END FUNCTION icb_utl_mass
  726. REAL(wp) FUNCTION icb_utl_heat( first, justbits, justbergs )
  727. !!----------------------------------------------------------------------
  728. !! *** FUNCTION icb_utl_heat ***
  729. !!
  730. !! ** Purpose : compute the heat in all iceberg, all bergies or all bergs.
  731. !!----------------------------------------------------------------------
  732. TYPE(iceberg) , POINTER :: first
  733. LOGICAL, INTENT(in), OPTIONAL :: justbits, justbergs
  734. !
  735. TYPE(iceberg) , POINTER :: this
  736. TYPE(point) , POINTER :: pt
  737. !!----------------------------------------------------------------------
  738. icb_utl_heat = 0._wp
  739. this => first
  740. !
  741. IF( PRESENT( justbergs ) ) THEN
  742. DO WHILE( ASSOCIATED( this ) )
  743. pt => this%current_point
  744. icb_utl_heat = icb_utl_heat + pt%mass * this%mass_scaling * pt%heat_density
  745. this => this%next
  746. END DO
  747. ELSEIF( PRESENT(justbits) ) THEN
  748. DO WHILE( ASSOCIATED( this ) )
  749. pt => this%current_point
  750. icb_utl_heat = icb_utl_heat + pt%mass_of_bits * this%mass_scaling * pt%heat_density
  751. this => this%next
  752. END DO
  753. ELSE
  754. DO WHILE( ASSOCIATED( this ) )
  755. pt => this%current_point
  756. icb_utl_heat = icb_utl_heat + ( pt%mass + pt%mass_of_bits ) * this%mass_scaling * pt%heat_density
  757. this => this%next
  758. END DO
  759. ENDIF
  760. !
  761. END FUNCTION icb_utl_heat
  762. !!======================================================================
  763. END MODULE icbutl