New URL for NEMO forge!   http://forge.nemo-ocean.eu

Since March 2022 along with NEMO 4.2 release, the code development moved to a self-hosted GitLab.
This present forge is now archived and remained online for history.
icbutl.F90 in NEMO/branches/2020/dev_r14116_HPC-04_mcastril_Mixed_Precision_implementation_final/src/OCE/ICB – NEMO

source: NEMO/branches/2020/dev_r14116_HPC-04_mcastril_Mixed_Precision_implementation_final/src/OCE/ICB/icbutl.F90 @ 14219

Last change on this file since 14219 was 14219, checked in by mcastril, 4 years ago

Add Mixed Precision support by Oriol Tintó

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