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.
icbthm.F90 in NEMO/trunk/src/OCE/ICB – NEMO

source: NEMO/trunk/src/OCE/ICB/icbthm.F90 @ 14367

Last change on this file since 14367 was 14030, checked in by mathiot, 4 years ago

merge tickets_icb_1900 into trunk

  • Property svn:keywords set to Id
File size: 15.0 KB
RevLine 
[3614]1MODULE icbthm
2   !!======================================================================
3   !!                       ***  MODULE  icbthm  ***
4   !! Icebergs:  thermodynamics routines for icebergs
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   !!            -    !  2011-05  (Alderson)       Use tmask instead of tmask_i
11   !!----------------------------------------------------------------------
12   !!----------------------------------------------------------------------
13   !!   icb_thm : initialise
14   !!             reference for equations - M = Martin + Adcroft, OM 34, 2010
15   !!----------------------------------------------------------------------
16   USE par_oce        ! NEMO parameters
17   USE dom_oce        ! NEMO domain
18   USE in_out_manager ! NEMO IO routines, numout in particular
19   USE lib_mpp        ! NEMO MPI routines, ctl_stop in particular
20   USE phycst         ! NEMO physical constants
21   USE sbc_oce
[13281]22   USE eosbn2         ! equation of state
[12291]23   USE lib_fortran, ONLY : DDPDD
[3614]24
25   USE icb_oce        ! define iceberg arrays
26   USE icbutl         ! iceberg utility routines
27   USE icbdia         ! iceberg budget routines
28
29   IMPLICIT NONE
30   PRIVATE
31
32   PUBLIC   icb_thm ! routine called in icbstp.F90 module
33
[9190]34   !!----------------------------------------------------------------------
[9598]35   !! NEMO/OCE 4.0 , NEMO Consortium (2018)
[5215]36   !! $Id$
[10068]37   !! Software governed by the CeCILL license (see ./LICENSE)
[9190]38   !!----------------------------------------------------------------------
[3614]39CONTAINS
40
41   SUBROUTINE icb_thm( kt )
42      !!----------------------------------------------------------------------
43      !!                  ***  ROUTINE icb_thm  ***
44      !!
45      !! ** Purpose :   compute the iceberg thermodynamics.
46      !!
47      !! ** Method  : - See Martin & Adcroft, Ocean Modelling 34, 2010
48      !!----------------------------------------------------------------------
49      INTEGER, INTENT(in) ::   kt   ! timestep number, just passed to icb_utl_print_berg
50      !
[14030]51      INTEGER  ::   ii, ij, jk, ikb
52      REAL(wp) ::   zM, zT, zW, zL, zSST, zVol, zLn, zWn, zTn, znVol, zIC, zDn, zD, zvb, zub, ztb
53      REAL(wp) ::   zMv, zMe, zMb, zmelt, zdvo, zdvob, zdva, zdM, zSs, zdMe, zdMb, zdMv
[13281]54      REAL(wp) ::   zSSS, zfzpt
[9990]55      REAL(wp) ::   zMnew, zMnew1, zMnew2, zheat_hcflux, zheat_latent, z1_12
[3614]56      REAL(wp) ::   zMbits, znMbits, zdMbitsE, zdMbitsM, zLbits, zAbits, zMbb
[14030]57      REAL(wp) ::   zxi, zyj, zff, z1_rday, z1_e1e2, zdt, z1_dt, z1_dt_e1e2, zdepw
58      REAL(wp), DIMENSION(jpk) :: ztoce, zuoce, zvoce, ze3t, zzMv
[3614]59      TYPE(iceberg), POINTER ::   this, next
60      TYPE(point)  , POINTER ::   pt
[12291]61      !
[13226]62      COMPLEX(dp), DIMENSION(jpi,jpj) :: cicb_melt, cicb_hflx
[3614]63      !!----------------------------------------------------------------------
64      !
[12291]65      !! initialiaze cicb_melt and cicb_heat
[13226]66      cicb_melt = CMPLX( 0.e0, 0.e0, dp ) 
67      cicb_hflx = CMPLX( 0.e0, 0.e0, dp ) 
[12291]68      !
[3614]69      z1_rday = 1._wp / rday
[9940]70      z1_12   = 1._wp / 12._wp
71      zdt     = berg_dt
72      z1_dt   = 1._wp / zdt
[9190]73      !
[3614]74      ! we're either going to ignore berg fresh water melt flux and associated heat
75      ! or we pass it into the ocean, so at this point we set them both to zero,
76      ! accumulate the contributions to them from each iceberg in the while loop following
77      ! and then pass them (or not) to the ocean
78      !
79      berg_grid%floating_melt(:,:) = 0._wp
[9990]80      ! calving_hflx re-used here as temporary workspace for the heat flux associated with melting
[3614]81      berg_grid%calving_hflx(:,:)  = 0._wp
[9190]82      !
[3614]83      this => first_berg
[9190]84      DO WHILE( ASSOCIATED(this) )
[3614]85         !
86         pt => this%current_point
87         nknberg = this%number(1)
[14030]88
89         CALL icb_utl_interp( pt%xi, pt%yj,            &   ! position
90             &                 pssu=pt%ssu, pua=pt%ua, &   ! oce/atm velocities
91             &                 pssv=pt%ssv, pva=pt%va, &   ! oce/atm velocities
92             &                 psst=pt%sst, pcn=pt%cn, &
93             &                 psss=pt%sss             )
94
95         IF ( nn_sample_rate > 0 .AND. MOD(kt-1,nn_sample_rate) == 0 ) THEN
96            CALL icb_utl_interp( pt%xi, pt%yj, pe1=pt%e1, pe2=pt%e2,                 &
97               &                 pui=pt%ui, pssh_i=pt%ssh_x, &
98               &                 pvi=pt%vi, pssh_j=pt%ssh_y, &
99               &                 phi=pt%hi,                  &
100               &                 plat=pt%lat, plon=pt%lon )
101         END IF
[3614]102         !
103         zSST = pt%sst
[13281]104         zSSS = pt%sss
105         CALL eos_fzp(zSSS,zfzpt)                       ! freezing point
[3614]106         zIC  = MIN( 1._wp, pt%cn + rn_sicn_shift )     ! Shift sea-ice concentration       !!gm ???
107         zM   = pt%mass
108         zT   = pt%thickness                               ! total thickness
[14030]109         zD   = rho_berg_1_oce * zT                        ! draught (keel depth)
[3614]110         zW   = pt%width
111         zL   = pt%length
112         zxi  = pt%xi                                      ! position in (i,j) referential
113         zyj  = pt%yj
114         ii  = INT( zxi + 0.5 )                            ! T-cell of the berg
115         ii  = mi1( ii )
116         ij  = INT( zyj + 0.5 )             
117         ij  = mj1( ij )
118         zVol = zT * zW * zL
119
120         ! Environment
[14030]121         ! default sst, ssu and ssv
122         ! ln_M2016: use temp, u and v profile
123         IF ( ln_M2016 ) THEN
[3614]124
[14030]125            ! load t, u, v and e3 profile at icb position
126            CALL icb_utl_interp( pt%xi, pt%yj, ptoce=ztoce, puoce=zuoce, pvoce=zvoce, pe3t=ze3t )
127           
128            !compute bottom level
129            CALL icb_utl_getkb( pt%kb, ze3t, zD )
130
131            ikb = MIN(pt%kb,mbkt(ii,ij))                             ! limit pt%kb by mbkt
132                                                                     ! => bottom temperature used to fill ztoce(mbkt:jpk)
133            ztb = ztoce(ikb)                                         ! basal temperature
134            zub = zuoce(ikb)
135            zvb = zvoce(ikb)
136         ELSE
137            ztb = pt%sst
138            zub = pt%ssu
139            zvb = pt%ssv
140         END IF
141
142         zdvob = SQRT( (pt%uvel-zub)**2 + (pt%vvel-zvb)**2 )        ! relative basal velocity
143         zdva  = SQRT( (pt%ua  -pt%ssu)**2 + (pt%va  -pt%ssv)**2 )  ! relative wind
144         zSs   = 1.5_wp * SQRT( zdva ) + 0.1_wp * zdva              ! Sea state      (eqn M.A9)
145         !
[3614]146         ! Melt rates in m/s (i.e. division by rday)
[14030]147         ! Buoyant convection at sides (eqn M.A10)
148         IF ( ln_M2016 ) THEN
149            ! averaging along all the iceberg draft
150            zzMv(:) = MAX( 7.62d-3*ztoce(:)+1.29d-3*(ztoce(:)**2), 0._wp ) * z1_rday
151            CALL icb_utl_zavg(zMv, zzMv, ze3t, zD, ikb )
152         ELSE
153            zMv = MAX( 7.62d-3*zSST+1.29d-3*(zSST**2), 0._wp ) * z1_rday
154         END IF
155         !
156         ! Basal turbulent melting     (eqn M.A7 )
[13281]157         IF ( zSST > zfzpt ) THEN                                                              ! Calculate basal melting only if SST above freezing point 
[14030]158            zMb = MAX( 0.58_wp*(zdvob**0.8_wp)*(ztb+4.0_wp)/(zL**0.2_wp) , 0._wp ) * z1_rday
[13281]159         ELSE
160            zMb = 0._wp                                                                        ! No basal melting if SST below freezing point     
161         ENDIF
[14030]162         !
163         ! Wave erosion                (eqn M.A8 )
164         zMe = MAX( z1_12*(zSST+2.)*zSs*(1._wp+COS(rpi*(zIC**3)))     , 0._wp ) * z1_rday
[3614]165
166         IF( ln_operator_splitting ) THEN      ! Operator split update of volume/mass
167            zTn    = MAX( zT - zMb*zdt , 0._wp )         ! new total thickness (m)
[9190]168            znVol  = zTn * zW * zL                       ! new volume (m^3)
[9940]169            zMnew1 = ( znVol / zVol ) * zM               ! new mass (kg)
[3614]170            zdMb   = zM - zMnew1                         ! mass lost to basal melting (>0) (kg)
171            !
172            zLn    = MAX( zL - zMv*zdt , 0._wp )         ! new length (m)
173            zWn    = MAX( zW - zMv*zdt , 0._wp )         ! new width (m)
[9190]174            znVol  = zTn * zWn * zLn                     ! new volume (m^3)
[9940]175            zMnew2 = ( znVol / zVol ) * zM               ! new mass (kg)
[3614]176            zdMv   = zMnew1 - zMnew2                     ! mass lost to buoyant convection (>0) (kg)
177            !
178            zLn    = MAX( zLn - zMe*zdt , 0._wp )        ! new length (m)
179            zWn    = MAX( zWn - zMe*zdt , 0._wp )        ! new width (m)
[9190]180            znVol  = zTn * zWn * zLn                     ! new volume (m^3)
181            zMnew  = ( znVol / zVol ) * zM               ! new mass (kg)
[3614]182            zdMe   = zMnew2 - zMnew                      ! mass lost to erosion (>0) (kg)
183            zdM    = zM - zMnew                          ! mass lost to all erosion and melting (>0) (kg)
184            !
185         ELSE                                         ! Update dimensions of berg
[9190]186            zLn = MAX( zL -(zMv+zMe)*zdt ,0._wp )        ! (m)
187            zWn = MAX( zW -(zMv+zMe)*zdt ,0._wp )        ! (m)
[3614]188            zTn = MAX( zT - zMb    *zdt ,0._wp )         ! (m)
189            ! Update volume and mass of berg
[9190]190            znVol = zTn*zWn*zLn                          ! (m^3)
191            zMnew = (znVol/zVol)*zM                      ! (kg)
[3614]192            zdM   = zM - zMnew                           ! (kg)
[9190]193            zdMb = (zM/zVol) * (zW*   zL ) *zMb*zdt      ! approx. mass loss to basal melting (kg)
194            zdMe = (zM/zVol) * (zT*(zW+zL)) *zMe*zdt     ! approx. mass lost to erosion (kg)
195            zdMv = (zM/zVol) * (zT*(zW+zL)) *zMv*zdt     ! approx. mass loss to buoyant convection (kg)
[3614]196         ENDIF
197
[9190]198         IF( rn_bits_erosion_fraction > 0._wp ) THEN     ! Bergy bits
[3614]199            !
200            zMbits   = pt%mass_of_bits                                               ! mass of bergy bits (kg)
[9190]201            zdMbitsE = rn_bits_erosion_fraction * zdMe                               ! change in mass of bits (kg)
202            znMbits  = zMbits + zdMbitsE                                             ! add new bergy bits to mass (kg)
203            zLbits   = MIN( zL, zW, zT, 40._wp )                                     ! assume bergy bits are smallest dimension or 40 meters
204            zAbits   = ( zMbits / rn_rho_bergs ) / zLbits                            ! Effective bottom area (assuming T=Lbits)
[9940]205            zMbb     = MAX( 0.58_wp*(zdvo**0.8_wp)*(zSST+2._wp) /   &
206               &                              ( zLbits**0.2_wp ) , 0._wp ) * z1_rday ! Basal turbulent melting (for bits)
[9190]207            zMbb     = rn_rho_bergs * zAbits * zMbb                                  ! in kg/s
208            zdMbitsM = MIN( zMbb*zdt , znMbits )                                     ! bergy bits mass lost to melting (kg)
209            znMbits  = znMbits-zdMbitsM                                              ! remove mass lost to bergy bits melt
[3614]210            IF( zMnew == 0._wp ) THEN                                                ! if parent berg has completely melted then
[9190]211               zdMbitsM = zdMbitsM + znMbits                                         ! instantly melt all the bergy bits
[3614]212               znMbits  = 0._wp
213            ENDIF
214         ELSE                                                     ! No bergy bits
215            zAbits   = 0._wp
216            zdMbitsE = 0._wp
217            zdMbitsM = 0._wp
218            znMbits  = pt%mass_of_bits                             ! retain previous value incase non-zero
219         ENDIF
220
221         ! use tmask rather than tmask_i when dealing with icebergs
222         IF( tmask(ii,ij,1) /= 0._wp ) THEN    ! Add melting to the grid and field diagnostics
[5836]223            z1_e1e2    = r1_e1e2t(ii,ij) * this%mass_scaling
[3614]224            z1_dt_e1e2 = z1_dt * z1_e1e2
[12291]225            !
226            ! iceberg melt
227            !! the use of DDPDD function for the cumulative sum is needed for reproducibility
[3614]228            zmelt    = ( zdM - ( zdMbitsE - zdMbitsM ) ) * z1_dt   ! kg/s
[13226]229            CALL DDPDD( CMPLX( zmelt * z1_e1e2, 0.e0, dp ), cicb_melt(ii,ij) )
[12291]230            !
231            ! iceberg heat flux
232            !! the use of DDPDD function for the cumulative sum is needed for reproducibility
[9990]233            !! NB. The src_calving_hflx field is currently hardwired to zero in icb_stp, which means that the
234            !!     heat density of the icebergs is zero and the heat content flux to the ocean from iceberg
235            !!     melting is always zero. Leaving the term in the code until such a time as this is fixed. DS.
236            zheat_hcflux = zmelt * pt%heat_density       ! heat content flux : kg/s x J/kg = J/s
237            zheat_latent = - zmelt * rLfus               ! latent heat flux:  kg/s x J/kg = J/s
[13226]238            CALL DDPDD( CMPLX( ( zheat_hcflux + zheat_latent ) * z1_e1e2, 0.e0, dp ), cicb_hflx(ii,ij) )
[12291]239            !
240            ! diagnostics
[9990]241            CALL icb_dia_melt( ii, ij, zMnew, zheat_hcflux, zheat_latent, this%mass_scaling,       &
[9190]242               &                       zdM, zdMbitsE, zdMbitsM, zdMb, zdMe,   &
243               &                       zdMv, z1_dt_e1e2 )
[3614]244         ELSE
245            WRITE(numout,*) 'icb_thm: berg ',this%number(:),' appears to have grounded  at ',narea,ii,ij
246            CALL icb_utl_print_berg( this, kt )
247            WRITE(numout,*) 'msk=',tmask(ii,ij,1), e1e2t(ii,ij)
248            CALL ctl_stop('icb_thm', 'berg appears to have grounded!')
249         ENDIF
250
251         ! Rolling
[14030]252         zDn = rho_berg_1_oce * zTn       ! draught (keel depth)
[3614]253         IF( zDn > 0._wp .AND. MAX(zWn,zLn) < SQRT( 0.92*(zDn**2) + 58.32*zDn ) ) THEN
254            zT  = zTn
255            zTn = zWn
256            zWn = zT
[9190]257         ENDIF
[3614]258
259         ! Store the new state of iceberg (with L>W)
260         pt%mass         = zMnew
261         pt%mass_of_bits = znMbits
262         pt%thickness    = zTn
[9190]263         pt%width        = MIN( zWn , zLn )
264         pt%length       = MAX( zWn , zLn )
[3614]265
266         next=>this%next
267
268!!gm  add a test to avoid over melting ?
[14030]269!!pm  I agree, over melting could break conservation (more melt than calving)
[3614]270
271         IF( zMnew <= 0._wp ) THEN       ! Delete the berg if completely melted
272            CALL icb_utl_delete( first_berg, this )
273            !
274         ELSE                            ! Diagnose mass distribution on grid
[5836]275            z1_e1e2 = r1_e1e2t(ii,ij) * this%mass_scaling
[3614]276            CALL icb_dia_size( ii, ij, zWn, zLn, zAbits,   &
[9190]277               &               this%mass_scaling, zMnew, znMbits, z1_e1e2 )
[3614]278         ENDIF
279         !
280         this=>next
281         !
282      END DO
[12291]283      !
[13226]284      berg_grid%floating_melt = REAL(cicb_melt,dp)    ! kg/m2/s
285      berg_grid%calving_hflx  = REAL(cicb_hflx,dp)
[12291]286      !
[3614]287      ! now use melt and associated heat flux in ocean (or not)
288      !
289      IF(.NOT. ln_passive_mode ) THEN
290         emp (:,:) = emp (:,:) - berg_grid%floating_melt(:,:)
[9990]291         qns (:,:) = qns (:,:) + berg_grid%calving_hflx (:,:) 
[3614]292      ENDIF
293      !
294   END SUBROUTINE icb_thm
295
296   !!======================================================================
297END MODULE icbthm
Note: See TracBrowser for help on using the repository browser.