[3614] | 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 |
---|
[14030] | 10 | !! 4.2 ! 2020-07 (P. Mathiot) simplification of interpolation routine |
---|
| 11 | !! ! and add Nacho Merino work |
---|
[3614] | 12 | !!---------------------------------------------------------------------- |
---|
[9190] | 13 | |
---|
[3614] | 14 | !!---------------------------------------------------------------------- |
---|
| 15 | !! icb_utl_interp : |
---|
[14030] | 16 | !! icb_utl_pos : compute bottom left corner indice, weight and mask |
---|
| 17 | !! icb_utl_bilin_h : interpolation field to icb position |
---|
| 18 | !! icb_utl_bilin_e : interpolation of scale factor to icb position |
---|
[3614] | 19 | !!---------------------------------------------------------------------- |
---|
| 20 | USE par_oce ! ocean parameters |
---|
[14030] | 21 | USE oce, ONLY: ts, uu, vv |
---|
[3614] | 22 | USE dom_oce ! ocean domain |
---|
| 23 | USE in_out_manager ! IO parameters |
---|
| 24 | USE lbclnk ! lateral boundary condition |
---|
| 25 | USE lib_mpp ! MPI code and lk_mpp in particular |
---|
| 26 | USE icb_oce ! define iceberg arrays |
---|
| 27 | USE sbc_oce ! ocean surface boundary conditions |
---|
[9570] | 28 | #if defined key_si3 |
---|
[9656] | 29 | USE ice, ONLY: u_ice, v_ice, hm_i ! SI3 variables |
---|
[10332] | 30 | USE icevar ! ice_var_sshdyn |
---|
| 31 | USE sbc_ice, ONLY: snwice_mass, snwice_mass_b |
---|
[3614] | 32 | #endif |
---|
| 33 | |
---|
| 34 | IMPLICIT NONE |
---|
| 35 | PRIVATE |
---|
| 36 | |
---|
[14030] | 37 | INTERFACE icb_utl_bilin_h |
---|
| 38 | MODULE PROCEDURE icb_utl_bilin_2d_h, icb_utl_bilin_3d_h |
---|
| 39 | END INTERFACE |
---|
| 40 | |
---|
[3614] | 41 | PUBLIC icb_utl_copy ! routine called in icbstp module |
---|
[14030] | 42 | PUBLIC icb_utl_getkb ! routine called in icbdyn and icbthm modules |
---|
| 43 | PUBLIC test_icb_utl_getkb ! routine called in icbdyn and icbthm modules |
---|
| 44 | PUBLIC icb_utl_zavg ! routine called in icbdyn and icbthm modules |
---|
[3614] | 45 | PUBLIC icb_utl_interp ! routine called in icbdyn, icbthm modules |
---|
[14030] | 46 | PUBLIC icb_utl_bilin_h ! routine called in icbdyn module |
---|
[3614] | 47 | PUBLIC icb_utl_add ! routine called in icbini.F90, icbclv, icblbc and icbrst modules |
---|
| 48 | PUBLIC icb_utl_delete ! routine called in icblbc, icbthm modules |
---|
| 49 | PUBLIC icb_utl_destroy ! routine called in icbstp module |
---|
| 50 | PUBLIC icb_utl_track ! routine not currently used, retain just in case |
---|
| 51 | PUBLIC icb_utl_print_berg ! routine called in icbthm module |
---|
| 52 | PUBLIC icb_utl_print ! routine called in icbini, icbstp module |
---|
| 53 | PUBLIC icb_utl_count ! routine called in icbdia, icbini, icblbc, icbrst modules |
---|
| 54 | PUBLIC icb_utl_incr ! routine called in icbini, icbclv modules |
---|
| 55 | PUBLIC icb_utl_yearday ! routine called in icbclv, icbstp module |
---|
| 56 | PUBLIC icb_utl_mass ! routine called in icbdia module |
---|
| 57 | PUBLIC icb_utl_heat ! routine called in icbdia module |
---|
| 58 | |
---|
[14118] | 59 | !! * Substitutions |
---|
| 60 | # include "domzgr_substitute.h90" |
---|
[3614] | 61 | !!---------------------------------------------------------------------- |
---|
[9598] | 62 | !! NEMO/OCE 4.0 , NEMO Consortium (2018) |
---|
[5215] | 63 | !! $Id$ |
---|
[10068] | 64 | !! Software governed by the CeCILL license (see ./LICENSE) |
---|
[9190] | 65 | !!---------------------------------------------------------------------- |
---|
[3614] | 66 | CONTAINS |
---|
| 67 | |
---|
[14030] | 68 | SUBROUTINE icb_utl_copy( Kmm ) |
---|
[3614] | 69 | !!---------------------------------------------------------------------- |
---|
| 70 | !! *** ROUTINE icb_utl_copy *** |
---|
| 71 | !! |
---|
| 72 | !! ** Purpose : iceberg initialization. |
---|
| 73 | !! |
---|
| 74 | !! ** Method : - blah blah |
---|
| 75 | !!---------------------------------------------------------------------- |
---|
[14030] | 76 | REAL(wp), DIMENSION(0:jpi+1,0:jpj+1) :: ztmp |
---|
[10332] | 77 | #if defined key_si3 |
---|
| 78 | REAL(wp), DIMENSION(jpi,jpj) :: zssh_lead_m ! ocean surface (ssh_m) if ice is not embedded |
---|
| 79 | ! ! ocean surface in leads if ice is embedded |
---|
| 80 | #endif |
---|
[14030] | 81 | INTEGER :: jk ! vertical loop index |
---|
| 82 | INTEGER :: Kmm ! ocean time levelindex |
---|
| 83 | ! |
---|
[3614] | 84 | ! copy nemo forcing arrays into iceberg versions with extra halo |
---|
| 85 | ! only necessary for variables not on T points |
---|
| 86 | ! and ssh which is used to calculate gradients |
---|
[14030] | 87 | ! |
---|
| 88 | ! surface forcing |
---|
| 89 | ! |
---|
| 90 | ssu_e(1:jpi,1:jpj) = ssu_m(:,:) * umask(:,:,1) |
---|
| 91 | ssv_e(1:jpi,1:jpj) = ssv_m(:,:) * vmask(:,:,1) |
---|
| 92 | sst_e(1:jpi,1:jpj) = sst_m(:,:) |
---|
| 93 | sss_e(1:jpi,1:jpj) = sss_m(:,:) |
---|
| 94 | fr_e (1:jpi,1:jpj) = fr_i (:,:) |
---|
| 95 | ua_e (1:jpi,1:jpj) = utau (:,:) * umask(:,:,1) ! maybe mask useless because mask applied in sbcblk |
---|
| 96 | va_e (1:jpi,1:jpj) = vtau (:,:) * vmask(:,:,1) ! maybe mask useless because mask applied in sbcblk |
---|
[10702] | 97 | ff_e(1:jpi,1:jpj) = ff_f (:,:) |
---|
[9190] | 98 | ! |
---|
[14030] | 99 | CALL lbc_lnk_icb( 'icbutl', ssu_e, 'U', -1._wp, 1, 1 ) |
---|
| 100 | CALL lbc_lnk_icb( 'icbutl', ssv_e, 'V', -1._wp, 1, 1 ) |
---|
| 101 | CALL lbc_lnk_icb( 'icbutl', ua_e , 'U', -1._wp, 1, 1 ) |
---|
| 102 | CALL lbc_lnk_icb( 'icbutl', va_e , 'V', -1._wp, 1, 1 ) |
---|
[9570] | 103 | #if defined key_si3 |
---|
[10702] | 104 | hi_e(1:jpi, 1:jpj) = hm_i (:,:) |
---|
| 105 | ui_e(1:jpi, 1:jpj) = u_ice(:,:) |
---|
| 106 | vi_e(1:jpi, 1:jpj) = v_ice(:,:) |
---|
[10332] | 107 | ! |
---|
| 108 | ! compute ssh slope using ssh_lead if embedded |
---|
| 109 | zssh_lead_m(:,:) = ice_var_sshdyn(ssh_m, snwice_mass, snwice_mass_b) |
---|
[10702] | 110 | ssh_e(1:jpi, 1:jpj) = zssh_lead_m(:,:) * tmask(:,:,1) |
---|
[9190] | 111 | ! |
---|
[10425] | 112 | CALL lbc_lnk_icb( 'icbutl', ui_e , 'U', -1._wp, 1, 1 ) |
---|
| 113 | CALL lbc_lnk_icb( 'icbutl', vi_e , 'V', -1._wp, 1, 1 ) |
---|
[10332] | 114 | #else |
---|
[14030] | 115 | ssh_e(1:jpi, 1:jpj) = ssh_m(:,:) * tmask(:,:,1) |
---|
[3614] | 116 | #endif |
---|
| 117 | ! |
---|
[14030] | 118 | ! (PM) could be improve with a 3d lbclnk gathering both variables |
---|
| 119 | ! should be done once extra haloe generalised |
---|
| 120 | IF ( ln_M2016 ) THEN |
---|
| 121 | DO jk = 1,jpk |
---|
| 122 | ! uoce |
---|
| 123 | ztmp(1:jpi,1:jpj) = uu(:,:,jk,Kmm) |
---|
| 124 | CALL lbc_lnk_icb( 'icbutl', ztmp, 'U', -1._wp, 1, 1 ) |
---|
| 125 | uoce_e(:,:,jk) = ztmp(:,:) |
---|
| 126 | ! |
---|
| 127 | ! voce |
---|
| 128 | ztmp(1:jpi,1:jpj) = vv(:,:,jk,Kmm) |
---|
| 129 | CALL lbc_lnk_icb( 'icbutl', ztmp, 'V', -1._wp, 1, 1 ) |
---|
| 130 | voce_e(:,:,jk) = ztmp(:,:) |
---|
[14118] | 131 | ! |
---|
| 132 | e3t_e(1:jpi,1:jpj,jk) = e3t(:,:,jk,Kmm) |
---|
[14030] | 133 | END DO |
---|
[14118] | 134 | toce_e(1:jpi,1:jpj,:) = ts(:,:,:,1,Kmm) |
---|
[14030] | 135 | END IF |
---|
| 136 | ! |
---|
[3614] | 137 | END SUBROUTINE icb_utl_copy |
---|
| 138 | |
---|
| 139 | |
---|
[14030] | 140 | SUBROUTINE icb_utl_interp( pi, pj, pe1 , pssu, pui, pua, pssh_i, & |
---|
| 141 | & pe2 , pssv, pvi, pva, pssh_j, & |
---|
| 142 | & psst, psss, pcn, phi, pff , & |
---|
| 143 | & plon, plat, ptoce, puoce, pvoce, pe3t ) |
---|
[3614] | 144 | !!---------------------------------------------------------------------- |
---|
| 145 | !! *** ROUTINE icb_utl_interp *** |
---|
| 146 | !! |
---|
| 147 | !! ** Purpose : interpolation |
---|
| 148 | !! |
---|
| 149 | !! ** Method : - interpolate from various ocean arrays onto iceberg position |
---|
| 150 | !! |
---|
| 151 | !! !!gm CAUTION here I do not care of the slip/no-slip conditions |
---|
| 152 | !! this can be done later (not that easy to do...) |
---|
| 153 | !! right now, U is 0 in land so that the coastal value of velocity parallel to the coast |
---|
| 154 | !! is half the off shore value, wile the normal-to-the-coast value is zero. |
---|
| 155 | !! This is OK as a starting point. |
---|
[10691] | 156 | !! !!pm HARD CODED: - rho_air now computed in sbcblk (what are the effect ?) |
---|
| 157 | !! - drag coefficient (should it be namelist parameter ?) |
---|
[3614] | 158 | !! |
---|
| 159 | !!---------------------------------------------------------------------- |
---|
| 160 | REAL(wp), INTENT(in ) :: pi , pj ! position in (i,j) referential |
---|
[14030] | 161 | REAL(wp), INTENT( out), OPTIONAL :: pe1, pe2 ! i- and j scale factors |
---|
| 162 | REAL(wp), INTENT( out), OPTIONAL :: pssu, pssv, pui, pvi, pua, pva ! ocean, ice and wind speeds |
---|
| 163 | REAL(wp), INTENT( out), OPTIONAL :: pssh_i, pssh_j ! ssh i- & j-gradients |
---|
| 164 | REAL(wp), INTENT( out), OPTIONAL :: psst, psss, pcn, phi, pff ! SST, SSS, ice concentration, ice thickness, Coriolis |
---|
| 165 | REAL(wp), INTENT( out), OPTIONAL :: plat, plon ! position |
---|
| 166 | REAL(wp), DIMENSION(jpk), INTENT( out), OPTIONAL :: ptoce, puoce, pvoce, pe3t ! 3D variables |
---|
[3614] | 167 | ! |
---|
[14030] | 168 | REAL(wp), DIMENSION(4) :: zwT , zwU , zwV , zwF ! interpolation weight |
---|
| 169 | REAL(wp), DIMENSION(4) :: zmskF, zmskU, zmskV, zmskT ! mask |
---|
| 170 | REAL(wp), DIMENSION(4) :: zwTp, zmskTp, zwTm, zmskTm |
---|
| 171 | REAL(wp), DIMENSION(4,jpk) :: zw1d |
---|
| 172 | INTEGER :: iiT, iiU, iiV, iiF, ijT, ijU, ijV, ijF ! bottom left corner |
---|
| 173 | INTEGER :: iiTp, iiTm, ijTp, ijTm |
---|
[3614] | 174 | REAL(wp) :: zcd, zmod ! local scalars |
---|
| 175 | !!---------------------------------------------------------------------- |
---|
| 176 | ! |
---|
[14030] | 177 | ! get position, weight and mask |
---|
| 178 | CALL icb_utl_pos( pi, pj, 'T', iiT, ijT, zwT, zmskT ) |
---|
| 179 | CALL icb_utl_pos( pi, pj, 'U', iiU, ijU, zwU, zmskU ) |
---|
| 180 | CALL icb_utl_pos( pi, pj, 'V', iiV, ijV, zwV, zmskV ) |
---|
| 181 | CALL icb_utl_pos( pi, pj, 'F', iiF, ijF, zwF, zmskF ) |
---|
[3614] | 182 | ! |
---|
[14030] | 183 | ! metrics and coordinates |
---|
| 184 | IF ( PRESENT(pe1 ) ) pe1 = icb_utl_bilin_e( e1t, e1u, e1v, e1f, pi, pj ) ! scale factors |
---|
| 185 | IF ( PRESENT(pe2 ) ) pe2 = icb_utl_bilin_e( e2t, e2u, e2v, e2f, pi, pj ) |
---|
| 186 | IF ( PRESENT(plon) ) plon= icb_utl_bilin_h( rlon_e, iiT, ijT, zwT, .true. ) |
---|
| 187 | IF ( PRESENT(plat) ) plat= icb_utl_bilin_h( rlat_e, iiT, ijT, zwT, .false. ) |
---|
| 188 | ! |
---|
| 189 | IF ( PRESENT(pssu) ) pssu = icb_utl_bilin_h( ssu_e, iiU, ijU, zwU , .false. ) ! ocean velocities |
---|
| 190 | IF ( PRESENT(pssv) ) pssv = icb_utl_bilin_h( ssv_e, iiV, ijV, zwV , .false. ) ! |
---|
| 191 | IF ( PRESENT(psst) ) psst = icb_utl_bilin_h( sst_e, iiT, ijT, zwT * zmskT, .false. ) ! sst |
---|
| 192 | IF ( PRESENT(psss) ) psss = icb_utl_bilin_h( sss_e, iiT, ijT, zwT * zmskT, .false. ) ! sss |
---|
| 193 | IF ( PRESENT(pcn ) ) pcn = icb_utl_bilin_h( fr_e , iiT, ijT, zwT * zmskT, .false. ) ! ice concentration |
---|
| 194 | IF ( PRESENT(pff ) ) pff = icb_utl_bilin_h( ff_e , iiF, ijF, zwF , .false. ) ! Coriolis parameter |
---|
| 195 | ! |
---|
| 196 | IF ( PRESENT(pua) .AND. PRESENT(pva) ) THEN |
---|
| 197 | pua = icb_utl_bilin_h( ua_e, iiU, ijU, zwU * zmskU, .false. ) ! 10m wind |
---|
| 198 | pva = icb_utl_bilin_h( va_e, iiV, ijV, zwV * zmskV, .false. ) ! here (ua,va) are stress => rough conversion from stress to speed |
---|
| 199 | zcd = 1.22_wp * 1.5e-3_wp ! air density * drag coefficient |
---|
| 200 | zmod = 1._wp / MAX( 1.e-20, SQRT( zcd * SQRT( pua*pua + pva*pva) ) ) |
---|
| 201 | pua = pua * zmod ! note: stress module=0 necessarly implies ua=va=0 |
---|
| 202 | pva = pva * zmod |
---|
| 203 | END IF |
---|
| 204 | ! |
---|
[9570] | 205 | #if defined key_si3 |
---|
[14030] | 206 | IF ( PRESENT(pui) ) pui = icb_utl_bilin_h( ui_e , iiU, ijU, zwU , .false. ) ! sea-ice velocities |
---|
| 207 | IF ( PRESENT(pvi) ) pvi = icb_utl_bilin_h( vi_e , iiV, ijV, zwV , .false. ) |
---|
| 208 | IF ( PRESENT(phi) ) phi = icb_utl_bilin_h( hi_e , iiT, ijT, zwT * zmskT, .false. ) ! ice thickness |
---|
[3614] | 209 | #else |
---|
[14030] | 210 | IF ( PRESENT(pui) ) pui = 0._wp |
---|
| 211 | IF ( PRESENT(pvi) ) pvi = 0._wp |
---|
| 212 | IF ( PRESENT(phi) ) phi = 0._wp |
---|
[3614] | 213 | #endif |
---|
[14030] | 214 | ! |
---|
[3614] | 215 | ! Estimate SSH gradient in i- and j-direction (centred evaluation) |
---|
[14030] | 216 | IF ( PRESENT(pssh_i) .AND. PRESENT(pssh_j) ) THEN |
---|
| 217 | CALL icb_utl_pos( pi+0.1, pj , 'T', iiTp, ijTp, zwTp, zmskTp ) |
---|
| 218 | CALL icb_utl_pos( pi-0.1, pj , 'T', iiTm, ijTm, zwTm, zmskTm ) |
---|
| 219 | ! |
---|
| 220 | IF ( .NOT. PRESENT(pe1) ) pe1 = icb_utl_bilin_e( e1t, e1u, e1v, e1f, pi, pj ) |
---|
| 221 | pssh_i = ( icb_utl_bilin_h( ssh_e, iiTp, ijTp, zwTp*zmskTp, .false. ) - & |
---|
| 222 | & icb_utl_bilin_h( ssh_e, iiTm, ijTm, zwTm*zmskTm, .false. ) ) / ( 0.2_wp * pe1 ) |
---|
| 223 | ! |
---|
| 224 | CALL icb_utl_pos( pi , pj+0.1, 'T', iiTp, ijTp, zwTp, zmskTp ) |
---|
| 225 | CALL icb_utl_pos( pi , pj-0.1, 'T', iiTm, ijTm, zwTm, zmskTm ) |
---|
| 226 | ! |
---|
| 227 | IF ( .NOT. PRESENT(pe2) ) pe2 = icb_utl_bilin_e( e2t, e2u, e2v, e2f, pi, pj ) |
---|
| 228 | pssh_j = ( icb_utl_bilin_h( ssh_e, iiTp, ijTp, zwTp*zmskTp, .false. ) - & |
---|
| 229 | & icb_utl_bilin_h( ssh_e, iiTm, ijTm, zwTm*zmskTm, .false. ) ) / ( 0.2_wp * pe2 ) |
---|
| 230 | END IF |
---|
[3614] | 231 | ! |
---|
[14030] | 232 | ! 3d interpolation |
---|
| 233 | IF ( PRESENT(puoce) .AND. PRESENT(pvoce) ) THEN |
---|
| 234 | ! no need to mask as 0 is a valid data for land |
---|
| 235 | zw1d(1,:) = zwU(1) ; zw1d(2,:) = zwU(2) ; zw1d(3,:) = zwU(3) ; zw1d(4,:) = zwU(4) ; |
---|
| 236 | puoce(:) = icb_utl_bilin_h( uoce_e , iiU, ijU, zw1d ) |
---|
| 237 | |
---|
| 238 | zw1d(1,:) = zwV(1) ; zw1d(2,:) = zwV(2) ; zw1d(3,:) = zwV(3) ; zw1d(4,:) = zwV(4) ; |
---|
| 239 | pvoce(:) = icb_utl_bilin_h( voce_e , iiV, ijV, zw1d ) |
---|
| 240 | END IF |
---|
| 241 | |
---|
| 242 | IF ( PRESENT(ptoce) ) THEN |
---|
| 243 | ! for temperature we need to mask the weight properly |
---|
| 244 | ! no need of extra halo as it is a T point variable |
---|
| 245 | zw1d(1,:) = tmask(iiT ,ijT ,:) * zwT(1) * zmskT(1) |
---|
| 246 | zw1d(2,:) = tmask(iiT+1,ijT ,:) * zwT(2) * zmskT(2) |
---|
| 247 | zw1d(3,:) = tmask(iiT ,ijT+1,:) * zwT(3) * zmskT(3) |
---|
| 248 | zw1d(4,:) = tmask(iiT+1,ijT+1,:) * zwT(4) * zmskT(4) |
---|
| 249 | ptoce(:) = icb_utl_bilin_h( toce_e , iiT, ijT, zw1d ) |
---|
| 250 | END IF |
---|
| 251 | ! |
---|
| 252 | IF ( PRESENT(pe3t) ) pe3t(:) = e3t_e(iiT,ijT,:) ! as in Nacho tarball need to be fix once we are able to reproduce Nacho results |
---|
| 253 | ! |
---|
[3614] | 254 | END SUBROUTINE icb_utl_interp |
---|
| 255 | |
---|
[14030] | 256 | SUBROUTINE icb_utl_pos( pi, pj, cd_type, kii, kij, pw, pmsk ) |
---|
[3614] | 257 | !!---------------------------------------------------------------------- |
---|
| 258 | !! *** FUNCTION icb_utl_bilin *** |
---|
| 259 | !! |
---|
| 260 | !! ** Purpose : bilinear interpolation at berg location depending on the grid-point type |
---|
| 261 | !! this version deals with extra halo points |
---|
| 262 | !! |
---|
| 263 | !! !!gm CAUTION an optional argument should be added to handle |
---|
| 264 | !! the slip/no-slip conditions ==>>> to be done later |
---|
| 265 | !! |
---|
| 266 | !!---------------------------------------------------------------------- |
---|
[14030] | 267 | REAL(wp) , INTENT(IN) :: pi, pj ! targeted coordinates in (i,j) referential |
---|
| 268 | CHARACTER(len=1) , INTENT(IN) :: cd_type ! point type |
---|
| 269 | REAL(wp), DIMENSION(4), INTENT(OUT) :: pw, pmsk ! weight and mask |
---|
| 270 | INTEGER , INTENT(OUT) :: kii, kij ! bottom left corner position in local domain |
---|
[3614] | 271 | ! |
---|
[14030] | 272 | REAL(wp) :: zwi, zwj ! distance to bottom left corner |
---|
| 273 | INTEGER :: ierr |
---|
| 274 | ! |
---|
[3614] | 275 | !!---------------------------------------------------------------------- |
---|
| 276 | ! |
---|
| 277 | SELECT CASE ( cd_type ) |
---|
[9190] | 278 | CASE ( 'T' ) |
---|
| 279 | ! note that here there is no +0.5 added |
---|
| 280 | ! since we're looking for four T points containing quadrant we're in of |
---|
| 281 | ! current T cell |
---|
[14030] | 282 | kii = MAX(0, INT( pi )) |
---|
| 283 | kij = MAX(0, INT( pj )) ! T-point |
---|
| 284 | zwi = pi - REAL(kii,wp) |
---|
| 285 | zwj = pj - REAL(kij,wp) |
---|
[9190] | 286 | CASE ( 'U' ) |
---|
[14030] | 287 | kii = MAX(0, INT( pi-0.5_wp )) |
---|
| 288 | kij = MAX(0, INT( pj )) ! U-point |
---|
| 289 | zwi = pi - 0.5_wp - REAL(kii,wp) |
---|
| 290 | zwj = pj - REAL(kij,wp) |
---|
[9190] | 291 | CASE ( 'V' ) |
---|
[14030] | 292 | kii = MAX(0, INT( pi )) |
---|
| 293 | kij = MAX(0, INT( pj-0.5_wp )) ! V-point |
---|
| 294 | zwi = pi - REAL(kii,wp) |
---|
| 295 | zwj = pj - 0.5_wp - REAL(kij,wp) |
---|
[9190] | 296 | CASE ( 'F' ) |
---|
[14030] | 297 | kii = MAX(0, INT( pi-0.5_wp )) |
---|
| 298 | kij = MAX(0, INT( pj-0.5_wp )) ! F-point |
---|
| 299 | zwi = pi - 0.5_wp - REAL(kii,wp) |
---|
| 300 | zwj = pj - 0.5_wp - REAL(kij,wp) |
---|
[3614] | 301 | END SELECT |
---|
| 302 | ! |
---|
[14030] | 303 | ! compute weight |
---|
| 304 | pw(1) = (1._wp-zwi) * (1._wp-zwj) |
---|
| 305 | pw(2) = zwi * (1._wp-zwj) |
---|
| 306 | pw(3) = (1._wp-zwi) * zwj |
---|
| 307 | pw(4) = zwi * zwj |
---|
| 308 | ! |
---|
[4990] | 309 | ! find position in this processor. Prevent near edge problems (see #1389) |
---|
[14030] | 310 | ! |
---|
| 311 | IF (TRIM(cd_type) == 'T' ) THEN |
---|
| 312 | ierr = 0 |
---|
| 313 | IF ( kii < mig( 1 ) ) THEN ; ierr = ierr + 1 |
---|
| 314 | ELSEIF( kii >= mig(jpi) ) THEN ; ierr = ierr + 1 |
---|
| 315 | ENDIF |
---|
| 316 | ! |
---|
| 317 | IF ( kij < mjg( 1 ) ) THEN ; ierr = ierr + 1 |
---|
| 318 | ELSEIF( kij >= mjg(jpj) ) THEN ; ierr = ierr + 1 |
---|
| 319 | ENDIF |
---|
| 320 | ! |
---|
| 321 | IF ( ierr > 0 ) THEN |
---|
| 322 | WRITE(numout,*) 'bottom left corner T point out of bound' |
---|
| 323 | WRITE(numout,*) pi, kii, mig( 1 ), mig(jpi) |
---|
| 324 | WRITE(numout,*) pj, kij, mjg( 1 ), mjg(jpj) |
---|
| 325 | WRITE(numout,*) pmsk |
---|
| 326 | CALL ctl_stop('STOP','icb_utl_bilin_h: an icebergs coordinates is out of valid range (out of bound error)') |
---|
| 327 | END IF |
---|
| 328 | END IF |
---|
| 329 | ! |
---|
| 330 | ! find position in this processor. Prevent near edge problems (see #1389) |
---|
[10702] | 331 | ! (PM) will be useless if extra halo is used in NEMO |
---|
[3614] | 332 | ! |
---|
[14030] | 333 | IF ( kii <= mig(1)-1 ) THEN ; kii = 0 |
---|
| 334 | ELSEIF( kii > mig(jpi) ) THEN ; kii = jpi |
---|
| 335 | ELSE ; kii = mi1(kii) |
---|
[9190] | 336 | ENDIF |
---|
[14030] | 337 | IF ( kij <= mjg(1)-1 ) THEN ; kij = 0 |
---|
| 338 | ELSEIF( kij > mjg(jpj) ) THEN ; kij = jpj |
---|
| 339 | ELSE ; kij = mj1(kij) |
---|
[9190] | 340 | ENDIF |
---|
| 341 | ! |
---|
[10691] | 342 | ! define mask array |
---|
[14030] | 343 | ! land value is not used in the interpolation |
---|
| 344 | SELECT CASE ( cd_type ) |
---|
| 345 | CASE ( 'T' ) |
---|
| 346 | pmsk = (/tmask_e(kii,kij), tmask_e(kii+1,kij), tmask_e(kii,kij+1), tmask_e(kii+1,kij+1)/) |
---|
| 347 | CASE ( 'U' ) |
---|
| 348 | pmsk = (/umask_e(kii,kij), umask_e(kii+1,kij), umask_e(kii,kij+1), umask_e(kii+1,kij+1)/) |
---|
| 349 | CASE ( 'V' ) |
---|
| 350 | pmsk = (/vmask_e(kii,kij), vmask_e(kii+1,kij), vmask_e(kii,kij+1), vmask_e(kii+1,kij+1)/) |
---|
| 351 | CASE ( 'F' ) |
---|
| 352 | ! F case only used for coriolis, ff_f is not mask so zmask = 1 |
---|
| 353 | pmsk = 1. |
---|
| 354 | END SELECT |
---|
| 355 | END SUBROUTINE icb_utl_pos |
---|
[3614] | 356 | |
---|
[14030] | 357 | REAL(wp) FUNCTION icb_utl_bilin_2d_h( pfld, pii, pij, pw, pllon ) |
---|
[3614] | 358 | !!---------------------------------------------------------------------- |
---|
| 359 | !! *** FUNCTION icb_utl_bilin *** |
---|
| 360 | !! |
---|
| 361 | !! ** Purpose : bilinear interpolation at berg location depending on the grid-point type |
---|
[14030] | 362 | !! this version deals with extra halo points |
---|
[3614] | 363 | !! |
---|
| 364 | !! !!gm CAUTION an optional argument should be added to handle |
---|
| 365 | !! the slip/no-slip conditions ==>>> to be done later |
---|
| 366 | !! |
---|
| 367 | !!---------------------------------------------------------------------- |
---|
[14030] | 368 | REAL(wp), DIMENSION(0:jpi+1,0:jpj+1), INTENT(in) :: pfld ! field to be interpolated |
---|
| 369 | REAL(wp), DIMENSION(4) , INTENT(in) :: pw ! weight |
---|
| 370 | LOGICAL , INTENT(in) :: pllon ! input data is a longitude |
---|
| 371 | INTEGER , INTENT(in) :: pii, pij ! bottom left corner |
---|
[3614] | 372 | ! |
---|
[14030] | 373 | REAL(wp), DIMENSION(4) :: zdat ! input data |
---|
[3614] | 374 | !!---------------------------------------------------------------------- |
---|
| 375 | ! |
---|
[14030] | 376 | ! data |
---|
| 377 | zdat(1) = pfld(pii ,pij ) |
---|
| 378 | zdat(2) = pfld(pii+1,pij ) |
---|
| 379 | zdat(3) = pfld(pii ,pij+1) |
---|
| 380 | zdat(4) = pfld(pii+1,pij+1) |
---|
[3614] | 381 | ! |
---|
[14030] | 382 | IF( pllon .AND. MAXVAL(zdat) - MINVAL(zdat) > 90._wp ) THEN |
---|
| 383 | WHERE( zdat < 0._wp ) zdat = zdat + 360._wp |
---|
[9190] | 384 | ENDIF |
---|
| 385 | ! |
---|
[14030] | 386 | ! compute interpolated value |
---|
| 387 | icb_utl_bilin_2d_h = ( zdat(1)*pw(1) + zdat(2)*pw(2) + zdat(3)*pw(3) + zdat(4)*pw(4) ) / MAX(1.e-20, pw(1)+pw(2)+pw(3)+pw(4)) |
---|
[9190] | 388 | ! |
---|
[14030] | 389 | IF( pllon .AND. icb_utl_bilin_2d_h > 180._wp ) icb_utl_bilin_2d_h = icb_utl_bilin_2d_h - 360._wp |
---|
[3614] | 390 | ! |
---|
[14030] | 391 | END FUNCTION icb_utl_bilin_2d_h |
---|
[3614] | 392 | |
---|
[14030] | 393 | FUNCTION icb_utl_bilin_3d_h( pfld, pii, pij, pw ) |
---|
[3614] | 394 | !!---------------------------------------------------------------------- |
---|
[14030] | 395 | !! *** FUNCTION icb_utl_bilin *** |
---|
[3614] | 396 | !! |
---|
| 397 | !! ** Purpose : bilinear interpolation at berg location depending on the grid-point type |
---|
[14030] | 398 | !! this version deals with extra halo points |
---|
[3614] | 399 | !! |
---|
| 400 | !! !!gm CAUTION an optional argument should be added to handle |
---|
| 401 | !! the slip/no-slip conditions ==>>> to be done later |
---|
| 402 | !! |
---|
| 403 | !!---------------------------------------------------------------------- |
---|
[14030] | 404 | REAL(wp), DIMENSION(0:jpi+1,0:jpj+1, jpk), INTENT(in) :: pfld ! field to be interpolated |
---|
| 405 | REAL(wp), DIMENSION(4,jpk) , INTENT(in) :: pw ! weight |
---|
| 406 | INTEGER , INTENT(in) :: pii, pij ! bottom left corner |
---|
| 407 | REAL(wp), DIMENSION(jpk) :: icb_utl_bilin_3d_h |
---|
[3614] | 408 | ! |
---|
[14030] | 409 | REAL(wp), DIMENSION(4,jpk) :: zdat ! input data |
---|
| 410 | INTEGER :: jk |
---|
[3614] | 411 | !!---------------------------------------------------------------------- |
---|
| 412 | ! |
---|
[14030] | 413 | ! data |
---|
| 414 | zdat(1,:) = pfld(pii ,pij ,:) |
---|
| 415 | zdat(2,:) = pfld(pii+1,pij ,:) |
---|
| 416 | zdat(3,:) = pfld(pii ,pij+1,:) |
---|
| 417 | zdat(4,:) = pfld(pii+1,pij+1,:) |
---|
[3614] | 418 | ! |
---|
[14030] | 419 | ! compute interpolated value |
---|
| 420 | DO jk=1,jpk |
---|
| 421 | icb_utl_bilin_3d_h(jk) = ( zdat(1,jk)*pw(1,jk) + zdat(2,jk)*pw(2,jk) + zdat(3,jk)*pw(3,jk) + zdat(4,jk)*pw(4,jk) ) & |
---|
| 422 | & / MAX(1.e-20, pw(1,jk)+pw(2,jk)+pw(3,jk)+pw(4,jk)) |
---|
| 423 | END DO |
---|
[9190] | 424 | ! |
---|
[14030] | 425 | END FUNCTION icb_utl_bilin_3d_h |
---|
[3614] | 426 | |
---|
| 427 | REAL(wp) FUNCTION icb_utl_bilin_e( pet, peu, pev, pef, pi, pj ) |
---|
| 428 | !!---------------------------------------------------------------------- |
---|
| 429 | !! *** FUNCTION dom_init *** |
---|
| 430 | !! |
---|
| 431 | !! ** Purpose : bilinear interpolation at berg location of horizontal scale factor |
---|
| 432 | !! ** Method : interpolation done using the 4 nearest grid points among |
---|
| 433 | !! t-, u-, v-, and f-points. |
---|
| 434 | !!---------------------------------------------------------------------- |
---|
| 435 | REAL(wp), DIMENSION(:,:), INTENT(in) :: pet, peu, pev, pef ! horizontal scale factor to be interpolated at t-,u-,v- & f-pts |
---|
[14030] | 436 | REAL(wp) , INTENT(IN) :: pi , pj ! iceberg position |
---|
[3614] | 437 | ! |
---|
| 438 | ! weights corresponding to corner points of a T cell quadrant |
---|
| 439 | REAL(wp) :: zi, zj ! local real |
---|
[14030] | 440 | INTEGER :: ii, ij ! bottom left corner coordinate in local domain |
---|
[3614] | 441 | ! |
---|
| 442 | ! values at corner points of a T cell quadrant |
---|
| 443 | ! 00 = bottom left, 10 = bottom right, 01 = top left, 11 = top right |
---|
| 444 | REAL(wp) :: ze00, ze10, ze01, ze11 |
---|
| 445 | !!---------------------------------------------------------------------- |
---|
| 446 | ! |
---|
[14030] | 447 | ! cannot used iiT because need ii/ij reltaive to global indices not local one |
---|
[3821] | 448 | ii = MAX(1, INT( pi )) ; ij = MAX(1, INT( pj )) ! left bottom T-point (i,j) indices |
---|
[14030] | 449 | ! |
---|
[3614] | 450 | ! fractional box spacing |
---|
| 451 | ! 0 <= zi < 0.5, 0 <= zj < 0.5 --> NW quadrant of current T cell |
---|
| 452 | ! 0.5 <= zi < 1 , 0 <= zj < 0.5 --> NE quadrant |
---|
| 453 | ! 0 <= zi < 0.5, 0.5 <= zj < 1 --> SE quadrant |
---|
| 454 | ! 0.5 <= zi < 1 , 0.5 <= zj < 1 --> SW quadrant |
---|
| 455 | |
---|
| 456 | zi = pi - REAL(ii,wp) !!gm use here mig, mjg arrays |
---|
| 457 | zj = pj - REAL(ij,wp) |
---|
| 458 | |
---|
[14030] | 459 | ! conversion to local domain (no need to do a sanity check already done in icbpos) |
---|
| 460 | ii = mi1(ii) |
---|
| 461 | ij = mj1(ij) |
---|
[10702] | 462 | ! |
---|
[3614] | 463 | IF( 0.0_wp <= zi .AND. zi < 0.5_wp ) THEN |
---|
| 464 | IF( 0.0_wp <= zj .AND. zj < 0.5_wp ) THEN ! NE quadrant |
---|
| 465 | ! ! i=I i=I+1/2 |
---|
| 466 | ze01 = pev(ii ,ij ) ; ze11 = pef(ii ,ij ) ! j=J+1/2 V ------- F |
---|
| 467 | ze00 = pet(ii ,ij ) ; ze10 = peu(ii ,ij ) ! j=J T ------- U |
---|
| 468 | zi = 2._wp * zi |
---|
| 469 | zj = 2._wp * zj |
---|
| 470 | ELSE ! SE quadrant |
---|
| 471 | ! ! i=I i=I+1/2 |
---|
| 472 | ze01 = pet(ii ,ij+1) ; ze11 = peu(ii ,ij+1) ! j=J+1 T ------- U |
---|
| 473 | ze00 = pev(ii ,ij ) ; ze10 = pef(ii ,ij ) ! j=J+1/2 V ------- F |
---|
| 474 | zi = 2._wp * zi |
---|
| 475 | zj = 2._wp * (zj-0.5_wp) |
---|
| 476 | ENDIF |
---|
| 477 | ELSE |
---|
| 478 | IF( 0.0_wp <= zj .AND. zj < 0.5_wp ) THEN ! NW quadrant |
---|
| 479 | ! ! i=I i=I+1/2 |
---|
| 480 | ze01 = pef(ii ,ij ) ; ze11 = pev(ii+1,ij) ! j=J+1/2 F ------- V |
---|
| 481 | ze00 = peu(ii ,ij ) ; ze10 = pet(ii+1,ij) ! j=J U ------- T |
---|
| 482 | zi = 2._wp * (zi-0.5_wp) |
---|
| 483 | zj = 2._wp * zj |
---|
| 484 | ELSE ! SW quadrant |
---|
| 485 | ! ! i=I+1/2 i=I+1 |
---|
| 486 | ze01 = peu(ii ,ij+1) ; ze11 = pet(ii+1,ij+1) ! j=J+1 U ------- T |
---|
| 487 | ze00 = pef(ii ,ij ) ; ze10 = pev(ii+1,ij ) ! j=J+1/2 F ------- V |
---|
| 488 | zi = 2._wp * (zi-0.5_wp) |
---|
| 489 | zj = 2._wp * (zj-0.5_wp) |
---|
| 490 | ENDIF |
---|
| 491 | ENDIF |
---|
| 492 | ! |
---|
[10702] | 493 | icb_utl_bilin_e = ( ze01 * (1._wp-zi) + ze11 * zi ) * zj & |
---|
| 494 | & + ( ze00 * (1._wp-zi) + ze10 * zi ) * (1._wp-zj) |
---|
[3614] | 495 | ! |
---|
| 496 | END FUNCTION icb_utl_bilin_e |
---|
| 497 | |
---|
[14030] | 498 | SUBROUTINE icb_utl_getkb( kb, pe3, pD ) |
---|
| 499 | !!---------------------------------------------------------------------- |
---|
| 500 | !! *** ROUTINE icb_utl_getkb *** |
---|
| 501 | !! |
---|
| 502 | !! ** Purpose : compute the latest level affected by icb |
---|
| 503 | !! |
---|
| 504 | !!---------------------------------------------------------------------- |
---|
| 505 | INTEGER, INTENT(out):: kb |
---|
| 506 | REAL(wp), DIMENSION(:), INTENT(in) :: pe3 |
---|
| 507 | REAL(wp), INTENT(in) :: pD |
---|
| 508 | !! |
---|
| 509 | INTEGER :: jk |
---|
| 510 | REAL(wp) :: zdepw |
---|
| 511 | !!---------------------------------------------------------------------- |
---|
| 512 | !! |
---|
| 513 | zdepw = pe3(1) ; kb = 2 |
---|
| 514 | DO WHILE ( zdepw < pD) |
---|
| 515 | zdepw = zdepw + pe3(kb) |
---|
| 516 | kb = kb + 1 |
---|
| 517 | END DO |
---|
| 518 | kb = MIN(kb - 1,jpk) |
---|
| 519 | END SUBROUTINE |
---|
[3614] | 520 | |
---|
[14030] | 521 | SUBROUTINE icb_utl_zavg(pzavg, pdat, pe3, pD, kb ) |
---|
| 522 | !!---------------------------------------------------------------------- |
---|
| 523 | !! *** ROUTINE icb_utl_getkb *** |
---|
| 524 | !! |
---|
| 525 | !! ** Purpose : compute the vertical average of ocean properties affected by icb |
---|
| 526 | !! |
---|
| 527 | !!---------------------------------------------------------------------- |
---|
| 528 | INTEGER, INTENT(in ) :: kb ! deepest level affected by icb |
---|
| 529 | REAL(wp), DIMENSION(:), INTENT(in ) :: pe3, pdat ! vertical profile |
---|
| 530 | REAL(wp), INTENT(in ) :: pD ! draft |
---|
| 531 | REAL(wp), INTENT(out) :: pzavg ! z average |
---|
| 532 | !!---------------------------------------------------------------------- |
---|
| 533 | INTEGER :: jk |
---|
| 534 | REAL(wp) :: zdep |
---|
| 535 | !!---------------------------------------------------------------------- |
---|
| 536 | pzavg = 0.0 ; zdep = 0.0 |
---|
| 537 | DO jk = 1,kb-1 |
---|
| 538 | pzavg = pzavg + pe3(jk)*pdat(jk) |
---|
| 539 | zdep = zdep + pe3(jk) |
---|
| 540 | END DO |
---|
| 541 | ! if kb is limited by mbkt => bottom value is used between bathy and icb tail |
---|
| 542 | ! if kb not limited by mbkt => ocean value over mask is used (ie 0.0 for u, v) |
---|
| 543 | pzavg = ( pzavg + (pD - zdep)*pdat(kb)) / pD |
---|
| 544 | END SUBROUTINE |
---|
| 545 | |
---|
[3614] | 546 | SUBROUTINE icb_utl_add( bergvals, ptvals ) |
---|
| 547 | !!---------------------------------------------------------------------- |
---|
| 548 | !! *** ROUTINE icb_utl_add *** |
---|
| 549 | !! |
---|
| 550 | !! ** Purpose : add a new berg to the iceberg list |
---|
| 551 | !! |
---|
| 552 | !!---------------------------------------------------------------------- |
---|
| 553 | TYPE(iceberg), INTENT(in) :: bergvals |
---|
| 554 | TYPE(point) , INTENT(in) :: ptvals |
---|
| 555 | ! |
---|
| 556 | TYPE(iceberg), POINTER :: new => NULL() |
---|
| 557 | !!---------------------------------------------------------------------- |
---|
| 558 | ! |
---|
| 559 | new => NULL() |
---|
| 560 | CALL icb_utl_create( new, bergvals, ptvals ) |
---|
| 561 | CALL icb_utl_insert( new ) |
---|
| 562 | new => NULL() ! Clear new |
---|
| 563 | ! |
---|
| 564 | END SUBROUTINE icb_utl_add |
---|
| 565 | |
---|
| 566 | |
---|
| 567 | SUBROUTINE icb_utl_create( berg, bergvals, ptvals ) |
---|
| 568 | !!---------------------------------------------------------------------- |
---|
| 569 | !! *** ROUTINE icb_utl_create *** |
---|
| 570 | !! |
---|
| 571 | !! ** Purpose : add a new berg to the iceberg list |
---|
| 572 | !! |
---|
| 573 | !!---------------------------------------------------------------------- |
---|
| 574 | TYPE(iceberg), INTENT(in) :: bergvals |
---|
| 575 | TYPE(point) , INTENT(in) :: ptvals |
---|
| 576 | TYPE(iceberg), POINTER :: berg |
---|
| 577 | ! |
---|
| 578 | TYPE(point) , POINTER :: pt |
---|
| 579 | INTEGER :: istat |
---|
| 580 | !!---------------------------------------------------------------------- |
---|
| 581 | ! |
---|
| 582 | IF( ASSOCIATED(berg) ) CALL ctl_stop( 'icebergs, icb_utl_create: berg already associated' ) |
---|
| 583 | ALLOCATE(berg, STAT=istat) |
---|
| 584 | IF( istat /= 0 ) CALL ctl_stop( 'failed to allocate iceberg' ) |
---|
| 585 | berg%number(:) = bergvals%number(:) |
---|
| 586 | berg%mass_scaling = bergvals%mass_scaling |
---|
| 587 | berg%prev => NULL() |
---|
| 588 | berg%next => NULL() |
---|
| 589 | ! |
---|
| 590 | ALLOCATE(pt, STAT=istat) |
---|
| 591 | IF( istat /= 0 ) CALL ctl_stop( 'failed to allocate first iceberg point' ) |
---|
| 592 | pt = ptvals |
---|
| 593 | berg%current_point => pt |
---|
| 594 | ! |
---|
| 595 | END SUBROUTINE icb_utl_create |
---|
| 596 | |
---|
| 597 | |
---|
| 598 | SUBROUTINE icb_utl_insert( newberg ) |
---|
| 599 | !!---------------------------------------------------------------------- |
---|
| 600 | !! *** ROUTINE icb_utl_insert *** |
---|
| 601 | !! |
---|
| 602 | !! ** Purpose : add a new berg to the iceberg list |
---|
| 603 | !! |
---|
| 604 | !!---------------------------------------------------------------------- |
---|
| 605 | TYPE(iceberg), POINTER :: newberg |
---|
| 606 | ! |
---|
| 607 | TYPE(iceberg), POINTER :: this, prev, last |
---|
| 608 | !!---------------------------------------------------------------------- |
---|
| 609 | ! |
---|
| 610 | IF( ASSOCIATED( first_berg ) ) THEN |
---|
| 611 | last => first_berg |
---|
| 612 | DO WHILE (ASSOCIATED(last%next)) |
---|
| 613 | last => last%next |
---|
| 614 | ENDDO |
---|
| 615 | newberg%prev => last |
---|
| 616 | last%next => newberg |
---|
| 617 | last => newberg |
---|
| 618 | ELSE ! list is empty so create it |
---|
| 619 | first_berg => newberg |
---|
| 620 | ENDIF |
---|
| 621 | ! |
---|
| 622 | END SUBROUTINE icb_utl_insert |
---|
| 623 | |
---|
| 624 | |
---|
| 625 | REAL(wp) FUNCTION icb_utl_yearday(kmon, kday, khr, kmin, ksec) |
---|
| 626 | !!---------------------------------------------------------------------- |
---|
| 627 | !! *** FUNCTION icb_utl_yearday *** |
---|
| 628 | !! |
---|
| 629 | !! ** Purpose : |
---|
| 630 | !! |
---|
| 631 | ! sga - improved but still only applies to 365 day year, need to do this properly |
---|
| 632 | ! |
---|
| 633 | !!gm all these info are already known in daymod, no??? |
---|
| 634 | !! |
---|
| 635 | !!---------------------------------------------------------------------- |
---|
| 636 | INTEGER, INTENT(in) :: kmon, kday, khr, kmin, ksec |
---|
| 637 | ! |
---|
| 638 | INTEGER, DIMENSION(12) :: imonths = (/ 0,31,28,31,30,31,30,31,31,30,31,30 /) |
---|
| 639 | !!---------------------------------------------------------------------- |
---|
| 640 | ! |
---|
| 641 | icb_utl_yearday = REAL( SUM( imonths(1:kmon) ), wp ) |
---|
| 642 | icb_utl_yearday = icb_utl_yearday + REAL(kday-1,wp) + (REAL(khr,wp) + (REAL(kmin,wp) + REAL(ksec,wp)/60.)/60.)/24. |
---|
| 643 | ! |
---|
| 644 | END FUNCTION icb_utl_yearday |
---|
| 645 | |
---|
| 646 | !!------------------------------------------------------------------------- |
---|
| 647 | |
---|
| 648 | SUBROUTINE icb_utl_delete( first, berg ) |
---|
| 649 | !!---------------------------------------------------------------------- |
---|
| 650 | !! *** ROUTINE icb_utl_delete *** |
---|
| 651 | !! |
---|
| 652 | !! ** Purpose : |
---|
| 653 | !! |
---|
| 654 | !!---------------------------------------------------------------------- |
---|
| 655 | TYPE(iceberg), POINTER :: first, berg |
---|
| 656 | !!---------------------------------------------------------------------- |
---|
| 657 | ! Connect neighbors to each other |
---|
| 658 | IF ( ASSOCIATED(berg%prev) ) THEN |
---|
| 659 | berg%prev%next => berg%next |
---|
| 660 | ELSE |
---|
| 661 | first => berg%next |
---|
| 662 | ENDIF |
---|
| 663 | IF (ASSOCIATED(berg%next)) berg%next%prev => berg%prev |
---|
| 664 | ! |
---|
| 665 | CALL icb_utl_destroy(berg) |
---|
| 666 | ! |
---|
| 667 | END SUBROUTINE icb_utl_delete |
---|
| 668 | |
---|
| 669 | |
---|
| 670 | SUBROUTINE icb_utl_destroy( berg ) |
---|
| 671 | !!---------------------------------------------------------------------- |
---|
| 672 | !! *** ROUTINE icb_utl_destroy *** |
---|
| 673 | !! |
---|
| 674 | !! ** Purpose : remove a single iceberg instance |
---|
| 675 | !! |
---|
| 676 | !!---------------------------------------------------------------------- |
---|
| 677 | TYPE(iceberg), POINTER :: berg |
---|
| 678 | !!---------------------------------------------------------------------- |
---|
| 679 | ! |
---|
| 680 | ! Remove any points |
---|
| 681 | IF( ASSOCIATED( berg%current_point ) ) DEALLOCATE( berg%current_point ) |
---|
| 682 | ! |
---|
| 683 | DEALLOCATE(berg) |
---|
| 684 | ! |
---|
| 685 | END SUBROUTINE icb_utl_destroy |
---|
| 686 | |
---|
| 687 | |
---|
| 688 | SUBROUTINE icb_utl_track( knum, cd_label, kt ) |
---|
| 689 | !!---------------------------------------------------------------------- |
---|
| 690 | !! *** ROUTINE icb_utl_track *** |
---|
| 691 | !! |
---|
| 692 | !! ** Purpose : |
---|
| 693 | !! |
---|
| 694 | !!---------------------------------------------------------------------- |
---|
| 695 | INTEGER, DIMENSION(nkounts) :: knum ! iceberg number |
---|
| 696 | CHARACTER(len=*) :: cd_label ! |
---|
| 697 | INTEGER :: kt ! timestep number |
---|
| 698 | ! |
---|
| 699 | TYPE(iceberg), POINTER :: this |
---|
| 700 | LOGICAL :: match |
---|
| 701 | INTEGER :: k |
---|
| 702 | !!---------------------------------------------------------------------- |
---|
| 703 | ! |
---|
| 704 | this => first_berg |
---|
| 705 | DO WHILE( ASSOCIATED(this) ) |
---|
| 706 | match = .TRUE. |
---|
| 707 | DO k = 1, nkounts |
---|
| 708 | IF( this%number(k) /= knum(k) ) match = .FALSE. |
---|
| 709 | END DO |
---|
| 710 | IF( match ) CALL icb_utl_print_berg(this, kt) |
---|
| 711 | this => this%next |
---|
| 712 | END DO |
---|
| 713 | ! |
---|
| 714 | END SUBROUTINE icb_utl_track |
---|
| 715 | |
---|
| 716 | |
---|
| 717 | SUBROUTINE icb_utl_print_berg( berg, kt ) |
---|
| 718 | !!---------------------------------------------------------------------- |
---|
| 719 | !! *** ROUTINE icb_utl_print_berg *** |
---|
| 720 | !! |
---|
| 721 | !! ** Purpose : print one |
---|
| 722 | !! |
---|
| 723 | !!---------------------------------------------------------------------- |
---|
| 724 | TYPE(iceberg), POINTER :: berg |
---|
| 725 | TYPE(point) , POINTER :: pt |
---|
| 726 | INTEGER :: kt ! timestep number |
---|
| 727 | !!---------------------------------------------------------------------- |
---|
| 728 | ! |
---|
[10570] | 729 | IF (nn_verbose_level == 0) RETURN |
---|
[3614] | 730 | pt => berg%current_point |
---|
| 731 | WRITE(numicb, 9200) kt, berg%number(1), & |
---|
| 732 | pt%xi, pt%yj, pt%lon, pt%lat, pt%uvel, pt%vvel, & |
---|
[14030] | 733 | pt%ssu, pt%ssv, pt%ua, pt%va, pt%ui, pt%vi |
---|
[3614] | 734 | CALL flush( numicb ) |
---|
| 735 | 9200 FORMAT(5x,i5,2x,i10,6(2x,2f10.4)) |
---|
| 736 | ! |
---|
| 737 | END SUBROUTINE icb_utl_print_berg |
---|
| 738 | |
---|
| 739 | |
---|
| 740 | SUBROUTINE icb_utl_print( cd_label, kt ) |
---|
| 741 | !!---------------------------------------------------------------------- |
---|
| 742 | !! *** ROUTINE icb_utl_print *** |
---|
| 743 | !! |
---|
| 744 | !! ** Purpose : print many |
---|
| 745 | !! |
---|
| 746 | !!---------------------------------------------------------------------- |
---|
| 747 | CHARACTER(len=*) :: cd_label |
---|
| 748 | INTEGER :: kt ! timestep number |
---|
| 749 | ! |
---|
| 750 | INTEGER :: ibergs, inbergs |
---|
| 751 | TYPE(iceberg), POINTER :: this |
---|
| 752 | !!---------------------------------------------------------------------- |
---|
| 753 | ! |
---|
[10570] | 754 | IF (nn_verbose_level == 0) RETURN |
---|
[3614] | 755 | this => first_berg |
---|
| 756 | IF( ASSOCIATED(this) ) THEN |
---|
| 757 | WRITE(numicb,'(a," pe=(",i3,")")' ) cd_label, narea |
---|
| 758 | WRITE(numicb,'(a8,4x,a6,12x,a5,15x,a7,19x,a3,17x,a5,17x,a5,17x,a5)' ) & |
---|
[14030] | 759 | & 'timestep', 'number', 'xi,yj','lon,lat','u,v','ssu,ssv','ua,va','ui,vi' |
---|
[3614] | 760 | ENDIF |
---|
| 761 | DO WHILE( ASSOCIATED(this) ) |
---|
| 762 | CALL icb_utl_print_berg(this, kt) |
---|
| 763 | this => this%next |
---|
| 764 | END DO |
---|
| 765 | ibergs = icb_utl_count() |
---|
| 766 | inbergs = ibergs |
---|
[10425] | 767 | CALL mpp_sum('icbutl', inbergs) |
---|
[3614] | 768 | IF( ibergs > 0 ) WRITE(numicb,'(a," there are",i5," bergs out of",i6," on PE ",i4)') & |
---|
| 769 | & cd_label, ibergs, inbergs, narea |
---|
| 770 | ! |
---|
| 771 | END SUBROUTINE icb_utl_print |
---|
| 772 | |
---|
| 773 | |
---|
| 774 | SUBROUTINE icb_utl_incr() |
---|
| 775 | !!---------------------------------------------------------------------- |
---|
| 776 | !! *** ROUTINE icb_utl_incr *** |
---|
| 777 | !! |
---|
| 778 | !! ** Purpose : |
---|
| 779 | !! |
---|
| 780 | ! Small routine for coping with very large integer values labelling icebergs |
---|
| 781 | ! num_bergs is a array of integers |
---|
| 782 | ! the first member is incremented in steps of jpnij starting from narea |
---|
| 783 | ! this means each iceberg is labelled with a unique number |
---|
| 784 | ! when this gets to the maximum allowed integer the second and subsequent members are |
---|
| 785 | ! used to count how many times the member before cycles |
---|
| 786 | !!---------------------------------------------------------------------- |
---|
| 787 | INTEGER :: ii, ibig |
---|
| 788 | !!---------------------------------------------------------------------- |
---|
| 789 | |
---|
| 790 | ibig = HUGE(num_bergs(1)) |
---|
| 791 | IF( ibig-jpnij < num_bergs(1) ) THEN |
---|
| 792 | num_bergs(1) = narea |
---|
| 793 | DO ii = 2,nkounts |
---|
| 794 | IF( num_bergs(ii) == ibig ) THEN |
---|
| 795 | num_bergs(ii) = 0 |
---|
| 796 | IF( ii == nkounts ) CALL ctl_stop('Sorry, run out of iceberg number space') |
---|
| 797 | ELSE |
---|
| 798 | num_bergs(ii) = num_bergs(ii) + 1 |
---|
| 799 | EXIT |
---|
| 800 | ENDIF |
---|
| 801 | END DO |
---|
| 802 | ELSE |
---|
| 803 | num_bergs(1) = num_bergs(1) + jpnij |
---|
| 804 | ENDIF |
---|
| 805 | ! |
---|
| 806 | END SUBROUTINE icb_utl_incr |
---|
| 807 | |
---|
| 808 | |
---|
| 809 | INTEGER FUNCTION icb_utl_count() |
---|
| 810 | !!---------------------------------------------------------------------- |
---|
| 811 | !! *** FUNCTION icb_utl_count *** |
---|
| 812 | !! |
---|
| 813 | !! ** Purpose : |
---|
| 814 | !!---------------------------------------------------------------------- |
---|
| 815 | TYPE(iceberg), POINTER :: this |
---|
| 816 | !!---------------------------------------------------------------------- |
---|
| 817 | ! |
---|
| 818 | icb_utl_count = 0 |
---|
| 819 | this => first_berg |
---|
| 820 | DO WHILE( ASSOCIATED(this) ) |
---|
| 821 | icb_utl_count = icb_utl_count+1 |
---|
| 822 | this => this%next |
---|
| 823 | END DO |
---|
| 824 | ! |
---|
| 825 | END FUNCTION icb_utl_count |
---|
| 826 | |
---|
| 827 | |
---|
| 828 | REAL(wp) FUNCTION icb_utl_mass( first, justbits, justbergs ) |
---|
| 829 | !!---------------------------------------------------------------------- |
---|
| 830 | !! *** FUNCTION icb_utl_mass *** |
---|
| 831 | !! |
---|
| 832 | !! ** Purpose : compute the mass all iceberg, all berg bits or all bergs. |
---|
| 833 | !!---------------------------------------------------------------------- |
---|
| 834 | TYPE(iceberg) , POINTER :: first |
---|
| 835 | TYPE(point) , POINTER :: pt |
---|
| 836 | LOGICAL, INTENT(in), OPTIONAL :: justbits, justbergs |
---|
| 837 | ! |
---|
| 838 | TYPE(iceberg), POINTER :: this |
---|
| 839 | !!---------------------------------------------------------------------- |
---|
| 840 | icb_utl_mass = 0._wp |
---|
| 841 | this => first |
---|
| 842 | ! |
---|
| 843 | IF( PRESENT( justbergs ) ) THEN |
---|
| 844 | DO WHILE( ASSOCIATED( this ) ) |
---|
| 845 | pt => this%current_point |
---|
| 846 | icb_utl_mass = icb_utl_mass + pt%mass * this%mass_scaling |
---|
| 847 | this => this%next |
---|
| 848 | END DO |
---|
| 849 | ELSEIF( PRESENT(justbits) ) THEN |
---|
| 850 | DO WHILE( ASSOCIATED( this ) ) |
---|
| 851 | pt => this%current_point |
---|
| 852 | icb_utl_mass = icb_utl_mass + pt%mass_of_bits * this%mass_scaling |
---|
| 853 | this => this%next |
---|
| 854 | END DO |
---|
| 855 | ELSE |
---|
| 856 | DO WHILE( ASSOCIATED( this ) ) |
---|
| 857 | pt => this%current_point |
---|
| 858 | icb_utl_mass = icb_utl_mass + ( pt%mass + pt%mass_of_bits ) * this%mass_scaling |
---|
| 859 | this => this%next |
---|
| 860 | END DO |
---|
| 861 | ENDIF |
---|
| 862 | ! |
---|
| 863 | END FUNCTION icb_utl_mass |
---|
| 864 | |
---|
| 865 | |
---|
| 866 | REAL(wp) FUNCTION icb_utl_heat( first, justbits, justbergs ) |
---|
| 867 | !!---------------------------------------------------------------------- |
---|
| 868 | !! *** FUNCTION icb_utl_heat *** |
---|
| 869 | !! |
---|
| 870 | !! ** Purpose : compute the heat in all iceberg, all bergies or all bergs. |
---|
| 871 | !!---------------------------------------------------------------------- |
---|
| 872 | TYPE(iceberg) , POINTER :: first |
---|
| 873 | LOGICAL, INTENT(in), OPTIONAL :: justbits, justbergs |
---|
| 874 | ! |
---|
| 875 | TYPE(iceberg) , POINTER :: this |
---|
| 876 | TYPE(point) , POINTER :: pt |
---|
| 877 | !!---------------------------------------------------------------------- |
---|
| 878 | icb_utl_heat = 0._wp |
---|
| 879 | this => first |
---|
| 880 | ! |
---|
| 881 | IF( PRESENT( justbergs ) ) THEN |
---|
| 882 | DO WHILE( ASSOCIATED( this ) ) |
---|
| 883 | pt => this%current_point |
---|
| 884 | icb_utl_heat = icb_utl_heat + pt%mass * this%mass_scaling * pt%heat_density |
---|
| 885 | this => this%next |
---|
| 886 | END DO |
---|
| 887 | ELSEIF( PRESENT(justbits) ) THEN |
---|
| 888 | DO WHILE( ASSOCIATED( this ) ) |
---|
| 889 | pt => this%current_point |
---|
| 890 | icb_utl_heat = icb_utl_heat + pt%mass_of_bits * this%mass_scaling * pt%heat_density |
---|
| 891 | this => this%next |
---|
| 892 | END DO |
---|
| 893 | ELSE |
---|
| 894 | DO WHILE( ASSOCIATED( this ) ) |
---|
| 895 | pt => this%current_point |
---|
| 896 | icb_utl_heat = icb_utl_heat + ( pt%mass + pt%mass_of_bits ) * this%mass_scaling * pt%heat_density |
---|
| 897 | this => this%next |
---|
| 898 | END DO |
---|
| 899 | ENDIF |
---|
| 900 | ! |
---|
| 901 | END FUNCTION icb_utl_heat |
---|
| 902 | |
---|
[14030] | 903 | SUBROUTINE test_icb_utl_getkb |
---|
| 904 | !!---------------------------------------------------------------------- |
---|
| 905 | !! *** FUNCTION test_icb_utl_getkb *** |
---|
| 906 | !! |
---|
| 907 | !! ** Purpose : Test routine icb_utl_getkb, icb_utl_zavg |
---|
| 908 | !! ** Methode : Call each subroutine with specific input data |
---|
| 909 | !! What should be the output is easy to determined and check |
---|
| 910 | !! if NEMO return the correct answer. |
---|
| 911 | !! ** Comments : not called, if needed a CALL test_icb_utl_getkb need to be added in icb_step |
---|
| 912 | !!---------------------------------------------------------------------- |
---|
| 913 | INTEGER :: ikb |
---|
| 914 | REAL(wp) :: zD, zout |
---|
| 915 | REAL(wp), DIMENSION(jpk) :: ze3, zin |
---|
| 916 | WRITE(numout,*) 'Test icb_utl_getkb : ' |
---|
| 917 | zD = 0.0 ; ze3= 20.0 |
---|
| 918 | WRITE(numout,*) 'INPUT : zD = ',zD,' ze3 = ',ze3(1) |
---|
| 919 | CALL icb_utl_getkb(ikb, ze3, zD) |
---|
| 920 | WRITE(numout,*) 'OUTPUT : kb = ',ikb |
---|
| 921 | |
---|
| 922 | zD = 8000000.0 ; ze3= 20.0 |
---|
| 923 | WRITE(numout,*) 'INPUT : zD = ',zD,' ze3 = ',ze3(1) |
---|
| 924 | CALL icb_utl_getkb(ikb, ze3, zD) |
---|
| 925 | WRITE(numout,*) 'OUTPUT : kb = ',ikb |
---|
| 926 | |
---|
| 927 | zD = 80.0 ; ze3= 20.0 |
---|
| 928 | WRITE(numout,*) 'INPUT : zD = ',zD,' ze3 = ',ze3(1) |
---|
| 929 | CALL icb_utl_getkb(ikb, ze3, zD) |
---|
| 930 | WRITE(numout,*) 'OUTPUT : kb = ',ikb |
---|
| 931 | |
---|
| 932 | zD = 85.0 ; ze3= 20.0 |
---|
| 933 | WRITE(numout,*) 'INPUT : zD = ',zD,' ze3 = ',ze3(1) |
---|
| 934 | CALL icb_utl_getkb(ikb, ze3, zD) |
---|
| 935 | WRITE(numout,*) 'OUTPUT : kb = ',ikb |
---|
| 936 | |
---|
| 937 | zD = 75.0 ; ze3= 20.0 |
---|
| 938 | WRITE(numout,*) 'INPUT : zD = ',zD,' ze3 = ',ze3(1) |
---|
| 939 | CALL icb_utl_getkb(ikb, ze3, zD) |
---|
| 940 | WRITE(numout,*) 'OUTPUT : kb = ',ikb |
---|
| 941 | |
---|
| 942 | WRITE(numout,*) '==================================' |
---|
| 943 | WRITE(numout,*) 'Test icb_utl_zavg' |
---|
| 944 | zD = 0.0 ; ze3= 20.0 ; zin=1.0 |
---|
| 945 | CALL icb_utl_getkb(ikb, ze3, zD) |
---|
| 946 | CALL icb_utl_zavg(zout, zin, ze3, zD, ikb) |
---|
| 947 | WRITE(numout,*) 'INPUT : zD = ',zD,' ze3 = ',ze3(1),' zin = ', zin, ' ikb = ',ikb |
---|
| 948 | WRITE(numout,*) 'OUTPUT : zout = ',zout |
---|
| 949 | |
---|
| 950 | zD = 50.0 ; ze3= 20.0 ; zin=1.0; zin(3:jpk) = 0.0 |
---|
| 951 | CALL icb_utl_getkb(ikb, ze3, zD) |
---|
| 952 | CALL icb_utl_zavg(zout, zin, ze3, zD, ikb) |
---|
| 953 | WRITE(numout,*) 'INPUT : zD = ',zD,' ze3 = ',ze3(1),' zin = ', zin, ' ikb = ',ikb |
---|
| 954 | WRITE(numout,*) 'OUTPUT : zout = ',zout |
---|
| 955 | CALL FLUSH(numout) |
---|
| 956 | |
---|
| 957 | zD = 80.0 ; ze3= 20.0 ; zin=1.0; zin(3:jpk) = 0.0 |
---|
| 958 | CALL icb_utl_getkb(ikb, ze3, zD) |
---|
| 959 | CALL icb_utl_zavg(zout, zin, ze3, zD, ikb) |
---|
| 960 | WRITE(numout,*) 'INPUT : zD = ',zD,' ze3 = ',ze3(1),' zin = ', zin, ' ikb = ',ikb |
---|
| 961 | WRITE(numout,*) 'OUTPUT : zout = ',zout |
---|
| 962 | |
---|
| 963 | zD = 80 ; ze3= 20.0 ; zin=1.0 ; zin(3:jpk) = 0.0 |
---|
| 964 | CALL icb_utl_getkb(ikb, ze3, zD) |
---|
| 965 | ikb = 2 |
---|
| 966 | CALL icb_utl_zavg(zout, zin, ze3, zD, ikb) |
---|
| 967 | WRITE(numout,*) 'INPUT : zD = ',zD,' ze3 = ',ze3(1),' zin = ', zin, ' ikb = ',ikb |
---|
| 968 | WRITE(numout,*) 'OUTPUT : zout = ',zout |
---|
| 969 | |
---|
| 970 | CALL FLUSH(numout) |
---|
| 971 | |
---|
| 972 | END SUBROUTINE test_icb_utl_getkb |
---|
| 973 | |
---|
[3614] | 974 | !!====================================================================== |
---|
| 975 | END MODULE icbutl |
---|