LCOV - code coverage report
Current view: top level - icepack/columnphysics - icepack_fsd.F90 (source / functions) Hit Total Coverage
Test: 231018-211459:8916b9ff2c:1:quick Lines: 0 274 0.00 %
Date: 2023-10-18 15:30:36 Functions: 0 10 0.00 %

          Line data    Source code
       1             : !=========================================================================
       2             : !
       3             : !  This module contains the subroutines required to define
       4             : !  a floe size distribution tracer for sea ice
       5             : !
       6             : !  Theory based on:
       7             : !
       8             : !    Horvat, C., & Tziperman, E. (2015). A prognostic model of the sea-ice
       9             : !    floe size and thickness distribution. The Cryosphere, 9(6), 2119-2134.
      10             : !    doi:10.5194/tc-9-2119-2015
      11             : !
      12             : !  and implementation described in:
      13             : !
      14             : !    Roach, L. A., Horvat, C., Dean, S. M., & Bitz, C. M. (2018). An emergent
      15             : !    sea ice floe size distribution in a global coupled ocean--sea ice model.
      16             : !    Journal of Geophysical Research: Oceans, 123(6), 4322-4337.
      17             : !    doi:10.1029/2017JC013692
      18             : !
      19             : !  with some modifications.
      20             : !
      21             : !  For floe welding parameter and tensile mode parameter values, see
      22             : !
      23             : !    Roach, L. A., Smith, M. M., & Dean, S. M. (2018). Quantifying
      24             : !    growth of pancake sea ice floes using images from drifting buoys.
      25             : !    Journal of Geophysical Research: Oceans, 123(4), 2851-2866.
      26             : !    doi: 10.1002/2017JC013693
      27             : !
      28             : !  Variable naming convention:
      29             : !  for k = 1, nfsd and n = 1, ncat
      30             : !    afsdn(k,n) = trcrn(:,:,nt_nfsd+k-1,n,:)
      31             : !    afsd (k) is per thickness category or averaged over n
      32             : !    afs is the associated scalar value for (k,n)
      33             : !
      34             : !  authors: Lettie Roach, VUW/NIWA
      35             : !           C. M. Bitz, UW
      36             : !
      37             : !  2016: CMB started
      38             : !  2016-8: LR worked on most of it
      39             : !  2019: ECH ported to Icepack
      40             : 
      41             : !-----------------------------------------------------------------
      42             : 
      43             :       module icepack_fsd
      44             : 
      45             :       use icepack_kinds
      46             :       use icepack_parameters, only: c0, c1, c2, c4, p01, p1, p5, puny
      47             :       use icepack_parameters, only: pi, floeshape, wave_spec, bignum, gravit, rhoi
      48             :       use icepack_tracers, only: nt_fsd, tr_fsd
      49             :       use icepack_warnings, only: warnstr, icepack_warnings_add
      50             :       use icepack_warnings, only: icepack_warnings_setabort, icepack_warnings_aborted
      51             : 
      52             :       implicit none
      53             : 
      54             :       private
      55             :       public :: icepack_init_fsd_bounds, icepack_init_fsd, icepack_cleanup_fsd, &
      56             :          fsd_lateral_growth, fsd_add_new_ice, fsd_weld_thermo, get_subdt_fsd
      57             : 
      58             :       real(kind=dbl_kind), dimension(:), allocatable ::  &
      59             :          floe_rad_h,         & ! fsd size higher bound in m (radius)   ! LCOV_EXCL_LINE
      60             :          floe_area_l,        & ! fsd area at lower bound (m^2)   ! LCOV_EXCL_LINE
      61             :          floe_area_h,        & ! fsd area at higher bound (m^2)   ! LCOV_EXCL_LINE
      62             :          floe_area_c,        & ! fsd area at bin centre (m^2)   ! LCOV_EXCL_LINE
      63             :          floe_area_binwidth    ! floe area bin width (m^2)
      64             : 
      65             :       integer(kind=int_kind), dimension(:,:), allocatable, public ::  &
      66             :          iweld                 ! floe size categories that can combine
      67             :                                ! during welding (dimensionless)
      68             : 
      69             : !=======================================================================
      70             : 
      71             :       contains
      72             : 
      73             : !=======================================================================
      74             : !  Note that radius widths cannot be larger than twice previous
      75             : !  category width or floe welding will not have an effect
      76             : !
      77             : !  Note also that the bound of the lowest floe size category is used
      78             : !  to define the lead region width and the domain spacing for wave fracture
      79             : !
      80             : !autodocument_start icepack_init_fsd_bounds
      81             : !  Initialize ice fsd bounds (call whether or not restarting)
      82             : !  Define the bounds, midpoints and widths of floe size
      83             : !  categories in area and radius
      84             : !
      85             : !  authors: Lettie Roach, NIWA/VUW and C. M. Bitz, UW
      86             : 
      87           0 :       subroutine icepack_init_fsd_bounds(nfsd, &
      88             :          floe_rad_l,    &  ! fsd size lower bound in m (radius)   ! LCOV_EXCL_LINE
      89             :          floe_rad_c,    &  ! fsd size bin centre in m (radius)   ! LCOV_EXCL_LINE
      90             :          floe_binwidth, &  ! fsd size bin width in m (radius)   ! LCOV_EXCL_LINE
      91             :          c_fsd_range,   &  ! string for history output   ! LCOV_EXCL_LINE
      92             :          write_diags    )  ! flag for writing diagnostics
      93             : 
      94             :       integer (kind=int_kind), intent(in) :: &
      95             :          nfsd              ! number of floe size categories
      96             : 
      97             :       real(kind=dbl_kind), dimension(:), intent(inout) ::  &
      98             :          floe_rad_l,    &  ! fsd size lower bound in m (radius)   ! LCOV_EXCL_LINE
      99             :          floe_rad_c,    &  ! fsd size bin centre in m (radius)   ! LCOV_EXCL_LINE
     100             :          floe_binwidth     ! fsd size bin width in m (radius)
     101             : 
     102             :       character (len=35), intent(out) :: &
     103             :          c_fsd_range(nfsd) ! string for history output
     104             : 
     105             :       logical (kind=log_kind), intent(in), optional :: &
     106             :          write_diags       ! write diags flag
     107             : 
     108             : !autodocument_end
     109             : 
     110             :       ! local variables
     111             : 
     112             :       integer (kind=int_kind) :: n, m, k
     113             :       integer (kind=int_kind) :: ierr
     114             : 
     115           0 :       real (kind=dbl_kind) :: test
     116             : 
     117             :       real (kind=dbl_kind), dimension (0:nfsd) :: &
     118           0 :          floe_rad
     119             : 
     120             :       real (kind=dbl_kind), dimension(:), allocatable :: &
     121           0 :          lims
     122             : 
     123             :       character(len=8) :: c_fsd1,c_fsd2
     124             :       character(len=2) :: c_nf
     125             :       character(len=*), parameter :: subname='(icepack_init_fsd_bounds)'
     126             : 
     127           0 :       if (nfsd.eq.24) then
     128             : 
     129           0 :          allocate(lims(24+1))
     130             : 
     131             :          lims = (/ 6.65000000e-02,   5.31030847e+00,   1.42865861e+01,   2.90576686e+01, &
     132             :                    5.24122136e+01,   8.78691405e+01,   1.39518470e+02,   2.11635752e+02, &   ! LCOV_EXCL_LINE
     133             :                    3.08037274e+02,   4.31203059e+02,   5.81277225e+02,   7.55141047e+02, &   ! LCOV_EXCL_LINE
     134             :                    9.45812834e+02,   1.34354446e+03,   1.82265364e+03,   2.47261361e+03, &   ! LCOV_EXCL_LINE
     135             :                    3.35434988e+03,   4.55051413e+03,   6.17323164e+03,   8.37461170e+03, &   ! LCOV_EXCL_LINE
     136             :                    1.13610059e+04,   1.54123510e+04,   2.09084095e+04,   2.83643675e+04, &   ! LCOV_EXCL_LINE
     137           0 :                    3.84791270e+04 /)
     138             : 
     139           0 :       elseif (nfsd.eq.16) then
     140             : 
     141           0 :          allocate(lims(16+1))
     142             : 
     143             :          lims = (/ 6.65000000e-02,   5.31030847e+00,   1.42865861e+01,   2.90576686e+01, &
     144             :                    5.24122136e+01,   8.78691405e+01,   1.39518470e+02,   2.11635752e+02, &   ! LCOV_EXCL_LINE
     145             :                    3.08037274e+02,   4.31203059e+02,   5.81277225e+02,   7.55141047e+02, &   ! LCOV_EXCL_LINE
     146             :                    9.45812834e+02,   1.34354446e+03,   1.82265364e+03,   2.47261361e+03, &   ! LCOV_EXCL_LINE
     147           0 :                    3.35434988e+03 /)
     148             : 
     149           0 :       else if (nfsd.eq.12) then
     150             : 
     151           0 :          allocate(lims(12+1))
     152             : 
     153             :          lims = (/ 6.65000000e-02,   5.31030847e+00,   1.42865861e+01,   2.90576686e+01, &
     154             :                    5.24122136e+01,   8.78691405e+01,   1.39518470e+02,   2.11635752e+02, &   ! LCOV_EXCL_LINE
     155             :                    3.08037274e+02,   4.31203059e+02,   5.81277225e+02,   7.55141047e+02, &   ! LCOV_EXCL_LINE
     156           0 :                    9.45812834e+02 /)
     157             : 
     158           0 :       else if (nfsd.eq.1) then ! default case
     159             : 
     160           0 :          allocate(lims(1+1))
     161             : 
     162           0 :          lims = (/ 6.65000000e-02,   3.0e+02 /)
     163             : 
     164             :       else
     165             : 
     166             :          call icepack_warnings_add(subname//&
     167           0 :             ' floe size categories not defined for nfsd')
     168           0 :          call icepack_warnings_setabort(.true.,__FILE__,__LINE__)
     169           0 :          return
     170             : 
     171             :       end if
     172             : 
     173             :       allocate(                                                   &
     174             :          floe_rad_h          (nfsd), & ! fsd size higher bound in m (radius)   ! LCOV_EXCL_LINE
     175             :          floe_area_l         (nfsd), & ! fsd area at lower bound (m^2)   ! LCOV_EXCL_LINE
     176             :          floe_area_h         (nfsd), & ! fsd area at higher bound (m^2)   ! LCOV_EXCL_LINE
     177             :          floe_area_c         (nfsd), & ! fsd area at bin centre (m^2)   ! LCOV_EXCL_LINE
     178             :          floe_area_binwidth  (nfsd), & ! floe area bin width (m^2)   ! LCOV_EXCL_LINE
     179             :          iweld         (nfsd, nfsd), & ! fsd categories that can weld   ! LCOV_EXCL_LINE
     180           0 :          stat=ierr)
     181           0 :       if (ierr/=0) then
     182           0 :          call icepack_warnings_add(subname//' Out of Memory fsd')
     183           0 :          call icepack_warnings_setabort(.true.,__FILE__,__LINE__)
     184           0 :          return
     185             :       endif
     186             : 
     187           0 :       floe_rad_l = lims(1:nfsd  )
     188           0 :       floe_rad_h = lims(2:nfsd+1)
     189           0 :       floe_rad_c = (floe_rad_h+floe_rad_l)/c2
     190             : 
     191           0 :       floe_area_l = c4*floeshape*floe_rad_l**2
     192           0 :       floe_area_c = c4*floeshape*floe_rad_c**2
     193           0 :       floe_area_h = c4*floeshape*floe_rad_h**2
     194             : 
     195           0 :       floe_binwidth = floe_rad_h - floe_rad_l
     196             : 
     197           0 :       floe_area_binwidth = floe_area_h - floe_area_l
     198             : 
     199             :       ! floe size categories that can combine during welding
     200           0 :       iweld(:,:) = -999
     201           0 :       do n = 1, nfsd
     202           0 :       do m = 1, nfsd
     203           0 :          test = floe_area_c(n) + floe_area_c(m)
     204           0 :          do k = 1, nfsd-1
     205           0 :             if ((test >= floe_area_l(k)) .and. (test < floe_area_h(k))) &
     206           0 :                   iweld(n,m) = k
     207             :          end do
     208           0 :          if (test >= floe_area_l(nfsd)) iweld(n,m) = nfsd
     209             :       end do
     210             :       end do
     211             : 
     212           0 :       if (allocated(lims)) deallocate(lims)
     213             : 
     214             :       ! write fsd bounds
     215           0 :       floe_rad(0) = floe_rad_l(1)
     216           0 :       do n = 1, nfsd
     217           0 :          floe_rad(n) = floe_rad_h(n)
     218             :          ! Save character string to write to history file
     219           0 :          write (c_nf, '(i2)') n
     220           0 :          write (c_fsd1, '(f7.3)') floe_rad(n-1)
     221           0 :          write (c_fsd2, '(f7.3)') floe_rad(n)
     222           0 :          c_fsd_range(n)=c_fsd1//'m < fsd Cat '//c_nf//' < '//c_fsd2//'m'
     223             :       enddo
     224             : 
     225           0 :       if (present(write_diags)) then
     226           0 :       if (write_diags) then
     227           0 :          write(warnstr,*) ' '
     228           0 :          call icepack_warnings_add(warnstr)
     229           0 :          write(warnstr,*) subname
     230           0 :          call icepack_warnings_add(warnstr)
     231           0 :          write(warnstr,*) 'floe_rad(n-1) < fsd Cat n < floe_rad(n)'
     232           0 :          call icepack_warnings_add(warnstr)
     233           0 :          do n = 1, nfsd
     234           0 :             write(warnstr,*) floe_rad(n-1),' < fsd Cat ',n, ' < ',floe_rad(n)
     235           0 :             call icepack_warnings_add(warnstr)
     236             :          enddo
     237           0 :          write(warnstr,*) ' '
     238           0 :          call icepack_warnings_add(warnstr)
     239             :       endif
     240             :       endif
     241             : 
     242           0 :       end subroutine icepack_init_fsd_bounds
     243             : 
     244             : !=======================================================================
     245             : !  When growing from no-ice conditions, initialize to zero.
     246             : !  This allows the FSD to emerge, as described in Roach, Horvat et al. (2018)
     247             : !
     248             : !  Otherwise initalize with a power law, following Perovich
     249             : !  & Jones (2014). The basin-wide applicability of such a
     250             : !  prescribed power law has not yet been tested.
     251             : !
     252             : !  Perovich, D. K., & Jones, K. F. (2014). The seasonal evolution of
     253             : !  sea ice floe size distribution. Journal of Geophysical Research: Oceans,
     254             : !  119(12), 8767–8777. doi:10.1002/2014JC010136
     255             : !
     256             : !autodocument_start icepack_init_fsd
     257             : !
     258             : !  Initialize the FSD
     259             : !
     260             : !  authors: Lettie Roach, NIWA/VUW
     261             : 
     262           0 :       subroutine icepack_init_fsd(nfsd, ice_ic, &
     263             :          floe_rad_c,    &  ! fsd size bin centre in m (radius)   ! LCOV_EXCL_LINE
     264             :          floe_binwidth, &  ! fsd size bin width in m (radius)   ! LCOV_EXCL_LINE
     265           0 :          afsd)             ! floe size distribution tracer
     266             : 
     267             :       integer(kind=int_kind), intent(in) :: &
     268             :          nfsd
     269             : 
     270             :       character(len=char_len_long), intent(in) :: &
     271             :          ice_ic            ! method of ice cover initialization
     272             : 
     273             :       real(kind=dbl_kind), dimension(:), intent(inout) ::  &
     274             :          floe_rad_c,    &  ! fsd size bin centre in m (radius)   ! LCOV_EXCL_LINE
     275             :          floe_binwidth     ! fsd size bin width in m (radius)
     276             : 
     277             :       real (kind=dbl_kind), dimension (:), intent(inout) :: &
     278             :          afsd              ! floe size tracer: fraction distribution of floes
     279             : 
     280             : !autodocument_end
     281             : 
     282             :       ! local variables
     283             : 
     284           0 :       real (kind=dbl_kind) :: alpha, totfrac
     285             : 
     286             :       integer (kind=int_kind) :: k
     287             : 
     288             :       real  (kind=dbl_kind), dimension (nfsd) :: &
     289           0 :          num_fsd           ! number distribution of floes
     290             : 
     291           0 :       if (trim(ice_ic) == 'none') then
     292             : 
     293           0 :          afsd(:) = c0
     294             : 
     295             :       else            ! Perovich (2014)
     296             : 
     297             :          ! fraction of ice in each floe size and thickness category
     298             :          ! same for ALL cells (even where no ice) initially
     299           0 :          alpha = 2.1_dbl_kind
     300           0 :          totfrac = c0                                   ! total fraction of floes
     301           0 :          do k = 1, nfsd
     302           0 :             num_fsd(k) = (2*floe_rad_c(k))**(-alpha-c1) ! number distribution of floes
     303           0 :             afsd   (k) = num_fsd(k)*floe_area_c(k)*floe_binwidth(k) ! fraction distribution of floes
     304           0 :             totfrac = totfrac + afsd(k)
     305             :          enddo
     306           0 :          afsd = afsd/totfrac                    ! normalize
     307             : 
     308             :       endif ! ice_ic
     309             : 
     310           0 :       end subroutine icepack_init_fsd
     311             : 
     312             : !=======================================================================
     313             : !autodocument_start icepack_cleanup_fsd
     314             : !
     315             : !  Clean up small values and renormalize
     316             : !
     317             : !  authors:  Elizabeth Hunke, LANL
     318             : !
     319           0 :       subroutine icepack_cleanup_fsd (ncat, nfsd, afsdn)
     320             : 
     321             :       integer (kind=int_kind), intent(in) :: &
     322             :          ncat           , & ! number of thickness categories   ! LCOV_EXCL_LINE
     323             :          nfsd               ! number of floe size categories
     324             : 
     325             :       real (kind=dbl_kind), dimension(:,:), intent(inout) :: &
     326             :          afsdn              ! floe size distribution tracer
     327             : 
     328             : !autodocument_end
     329             :       ! local variables
     330             : 
     331             :       integer (kind=int_kind) :: &
     332             :          n                  ! thickness category index
     333             : 
     334             :       character(len=*), parameter :: subname='(icepack_cleanup_fsd)'
     335             : 
     336             : 
     337           0 :       if (tr_fsd) then
     338             : 
     339           0 :          do n = 1, ncat
     340           0 :             call icepack_cleanup_fsdn(nfsd, afsdn(:,n))
     341           0 :             if (icepack_warnings_aborted(subname)) return
     342             :          enddo
     343             : 
     344             :       endif ! tr_fsd
     345             : 
     346             :       end subroutine icepack_cleanup_fsd
     347             : 
     348             : !=======================================================================
     349             : !
     350             : !  Clean up small values and renormalize -- per category
     351             : !
     352             : !  authors:  Elizabeth Hunke, LANL
     353             : !
     354             : 
     355           0 :       subroutine icepack_cleanup_fsdn (nfsd, afsd)
     356             : 
     357             :       integer (kind=int_kind), intent(in) :: &
     358             :          nfsd               ! number of floe size categories
     359             : 
     360             :       real (kind=dbl_kind), dimension(:), intent(inout) :: &
     361             :          afsd               ! floe size distribution tracer
     362             : 
     363             :       ! local variables
     364             : 
     365             :       integer (kind=int_kind) :: &
     366             :          k                  ! floe size category index
     367             : 
     368             :       real (kind=dbl_kind) :: &
     369           0 :          tot
     370             : 
     371           0 :       do k = 1, nfsd
     372           0 :          if (afsd(k) < puny) afsd(k) = c0
     373             :       enddo
     374             : 
     375           0 :       tot = sum(afsd(:))
     376           0 :       if (tot > puny) then
     377           0 :          do k = 1, nfsd
     378           0 :             afsd(k) = afsd(k) / tot ! normalize
     379             :          enddo
     380             :       else ! represents ice-free cell, so set to zero
     381           0 :          afsd(:) = c0
     382             :       endif
     383             : 
     384           0 :       end subroutine icepack_cleanup_fsdn
     385             : 
     386             : !=======================================================================
     387             : !
     388             : !  Given the joint ice thickness and floe size distribution, calculate
     389             : !  the lead region and the total lateral surface area following Horvat
     390             : !  and Tziperman (2015).
     391             : !
     392             : !  authors: Lettie Roach, NIWA/VUW
     393             : 
     394           0 :       subroutine partition_area (ncat,       nfsd,      &
     395             :                                  floe_rad_c, aice,      &   ! LCOV_EXCL_LINE
     396             :                                  aicen,      vicen,     &   ! LCOV_EXCL_LINE
     397             :                                  afsdn,      lead_area, &   ! LCOV_EXCL_LINE
     398             :                                  latsurf_area)
     399             : 
     400             :       integer (kind=int_kind), intent(in) :: &
     401             :          ncat           , & ! number of thickness categories   ! LCOV_EXCL_LINE
     402             :          nfsd               ! number of floe size categories
     403             : 
     404             :       real (kind=dbl_kind), dimension(:), intent(in) ::  &
     405             :          floe_rad_c         ! fsd size bin centre in m (radius)
     406             : 
     407             :       real (kind=dbl_kind), intent(in) :: &
     408             :          aice               ! ice concentration
     409             : 
     410             :       real (kind=dbl_kind), dimension(:), intent(in) :: &
     411             :          aicen          , & ! fractional area of ice   ! LCOV_EXCL_LINE
     412             :          vicen              ! volume per unit area of ice (m)
     413             : 
     414             :       real (kind=dbl_kind), dimension(:,:), intent(in) :: &
     415             :          afsdn              ! floe size distribution tracer
     416             : 
     417             :       real (kind=dbl_kind), intent(out) :: &
     418             :          lead_area      , & ! the fractional area of the lead region   ! LCOV_EXCL_LINE
     419             :          latsurf_area       ! the area covered by lateral surface of floes
     420             : 
     421             :       ! local variables
     422             : 
     423             :       integer (kind=int_kind) :: &
     424             :          n              , & ! thickness category index   ! LCOV_EXCL_LINE
     425             :          k                  ! floe size index
     426             : 
     427             :       real (kind=dbl_kind) :: &
     428             :          width_leadreg, &   ! width of lead region (m)   ! LCOV_EXCL_LINE
     429           0 :          thickness          ! actual thickness of ice in thickness cat (m)
     430             : 
     431             :       !-----------------------------------------------------------------
     432             :       ! Initialize
     433             :       !-----------------------------------------------------------------
     434           0 :       lead_area    = c0
     435           0 :       latsurf_area = c0
     436             : 
     437             :       ! Set the width of the lead region to be the smallest
     438             :       ! floe size category, as per Horvat & Tziperman (2015)
     439           0 :       width_leadreg = floe_rad_c(1)
     440             : 
     441             :       ! Only calculate these areas where there is some ice
     442           0 :       if (aice > puny) then
     443             : 
     444             :          ! lead area = sum of areas of annuli around all floes
     445           0 :          do n = 1, ncat
     446           0 :             do k = 1, nfsd
     447           0 :                lead_area = lead_area + aicen(n) * afsdn(k,n) &
     448             :                          * (c2*width_leadreg    /floe_rad_c(k)     &   ! LCOV_EXCL_LINE
     449           0 :                              + width_leadreg**2/floe_rad_c(k)**2)
     450             :             enddo ! k
     451             :          enddo    ! n
     452             : 
     453             :          ! cannot be greater than the open water fraction
     454           0 :          lead_area=MIN(lead_area, c1-aice)
     455           0 :          if (lead_area < c0) then
     456           0 :             if (lead_area < -puny) then
     457             : !               stop 'lead_area lt0 in partition_area'
     458             :             else
     459           0 :                lead_area=MAX(lead_area,c0)
     460             :             end if
     461             :          end if
     462             : 
     463             :          ! Total fractional lateral surface area in each grid (per unit ocean area)
     464           0 :          do n = 1, ncat
     465           0 :             thickness = c0
     466           0 :             if (aicen(n) > c0) thickness = vicen(n)/aicen(n)
     467             : 
     468           0 :             do k = 1, nfsd
     469             :                latsurf_area = latsurf_area &
     470           0 :                    + afsdn(k,n) * aicen(n) * c2 * thickness/floe_rad_c(k)
     471             :             end do
     472             :          end do
     473             : 
     474             :          ! check
     475             : !         if (latsurf_area < c0) stop 'negative latsurf_area'
     476             : !         if (latsurf_area /= latsurf_area) stop 'latsurf_area NaN'
     477             : 
     478             :       end if ! aice
     479             : 
     480           0 :       end subroutine partition_area
     481             : 
     482             : !=======================================================================
     483             : !
     484             : !  Lateral growth at the edges of floes
     485             : !
     486             : !  Compute the portion of new ice growth that occurs at the edges of
     487             : !  floes. The remainder will grow as new ice frazil ice in open water
     488             : !  (away from floes).
     489             : !
     490             : !  See Horvat & Tziperman (2015) and Roach, Horvat et al. (2018).
     491             : !
     492             : !  authors: Lettie Roach, NIWA/VUW
     493             : !
     494           0 :       subroutine fsd_lateral_growth (ncat,      nfsd,         &
     495             :                                      dt,        aice,         &   ! LCOV_EXCL_LINE
     496             :                                      aicen,     vicen,        &   ! LCOV_EXCL_LINE
     497             :                                      vi0new,                  &   ! LCOV_EXCL_LINE
     498             :                                      frazil,    floe_rad_c,   &   ! LCOV_EXCL_LINE
     499             :                                      afsdn,                   &   ! LCOV_EXCL_LINE
     500             :                                      lead_area, latsurf_area, &   ! LCOV_EXCL_LINE
     501             :                                      G_radial,  d_an_latg,    &   ! LCOV_EXCL_LINE
     502             :                                      tot_latg)
     503             : 
     504             :       integer (kind=int_kind), intent(in) :: &
     505             :          ncat           , & ! number of thickness categories   ! LCOV_EXCL_LINE
     506             :          nfsd               ! number of floe size categories
     507             : 
     508             :       real (kind=dbl_kind), intent(in) :: &
     509             :          dt             , & ! time step (s)   ! LCOV_EXCL_LINE
     510             :          aice               ! total concentration of ice
     511             : 
     512             :       real (kind=dbl_kind), dimension (:), intent(in) :: &
     513             :          aicen          , & ! concentration of ice   ! LCOV_EXCL_LINE
     514             :          vicen              ! volume per unit area of ice          (m)
     515             : 
     516             :       real (kind=dbl_kind), dimension(:,:), intent(in) :: &
     517             :          afsdn              ! floe size distribution tracer
     518             : 
     519             :       real (kind=dbl_kind), intent(inout) :: &
     520             :          vi0new         , & ! volume of new ice added to cat 1 (m)   ! LCOV_EXCL_LINE
     521             :          frazil             ! frazil ice growth        (m/step-->cm/day)
     522             : 
     523             :       ! floe size distribution
     524             :       real (kind=dbl_kind), dimension (:), intent(in) :: &
     525             :          floe_rad_c         ! fsd size bin centre in m (radius)
     526             : 
     527             :       real (kind=dbl_kind), dimension(ncat), intent(out) :: &
     528             :          d_an_latg          ! change in aicen occuring due to lateral growth
     529             : 
     530             :       real (kind=dbl_kind), intent(out) :: &
     531             :          G_radial       , & ! lateral melt rate (m/s)   ! LCOV_EXCL_LINE
     532             :          tot_latg           ! total change in aice due to
     533             :                             ! lateral growth at the edges of floes
     534             : 
     535             :       ! local variables
     536             :       integer (kind=int_kind) :: &
     537             :          n, k               ! ice category indices
     538             : 
     539             :       real (kind=dbl_kind) :: &
     540           0 :          vi0new_lat         ! volume of new ice added laterally to FSD (m)
     541             : 
     542             :       real (kind=dbl_kind), intent(out) :: &
     543             :          lead_area      , & ! the fractional area of the lead region   ! LCOV_EXCL_LINE
     544             :          latsurf_area       ! the area covered by lateral surface of floes
     545             : 
     546             :       character(len=*),parameter :: subname='(fsd_lateral_growth)'
     547             : 
     548           0 :       lead_area    = c0
     549           0 :       latsurf_area = c0
     550           0 :       G_radial     = c0
     551           0 :       tot_latg     = c0
     552           0 :       d_an_latg    = c0
     553             : 
     554             :       ! partition volume into lateral growth and frazil
     555             :       call partition_area (ncat,       nfsd,      &
     556             :                            floe_rad_c, aice,      &   ! LCOV_EXCL_LINE
     557             :                            aicen,      vicen,     &   ! LCOV_EXCL_LINE
     558             :                            afsdn,      lead_area, &   ! LCOV_EXCL_LINE
     559           0 :                            latsurf_area)
     560           0 :       if (icepack_warnings_aborted(subname)) return
     561             : 
     562           0 :       vi0new_lat = c0
     563           0 :       if (latsurf_area > puny) then
     564           0 :          vi0new_lat = vi0new * lead_area / (c1 + aice/latsurf_area)
     565             :       end if
     566             : 
     567             :       ! for history/diagnostics
     568           0 :       frazil = vi0new - vi0new_lat
     569             : 
     570             :       ! lateral growth increment
     571           0 :       if (vi0new_lat > puny) then
     572           0 :          G_radial = vi0new_lat/dt
     573           0 :          do n = 1, ncat
     574             : 
     575           0 :             do k = 1, nfsd
     576           0 :                d_an_latg(n) = d_an_latg(n) &
     577           0 :                             + c2*aicen(n)*afsdn(k,n)*G_radial*dt/floe_rad_c(k)
     578             :             end do
     579             :          end do ! n
     580             : 
     581             :          ! cannot expand ice laterally beyond lead region
     582           0 :          if (SUM(d_an_latg(:)).ge.lead_area) then
     583           0 :              d_an_latg(:) = d_an_latg(:)/SUM(d_an_latg(:))
     584           0 :              d_an_latg(:) = d_an_latg(:)*lead_area
     585             :          end if
     586             : 
     587             :       endif ! vi0new_lat > 0
     588             : 
     589             :       ! Use remaining ice volume as in standard model,
     590             :       ! but ice cannot grow into the area that has grown laterally
     591           0 :       vi0new = vi0new - vi0new_lat
     592           0 :       tot_latg = SUM(d_an_latg(:))
     593             : 
     594             :       end subroutine fsd_lateral_growth
     595             : 
     596             : !=======================================================================
     597             : !
     598             : !  Evolve the FSD subject to lateral growth and the growth of new ice
     599             : !  in thickness category 1.
     600             : !
     601             : !  If ocean surface wave forcing is provided, the floe size of new ice
     602             : !  (grown away from floe edges) can computed from the wave field
     603             : !  based on the tensile (stretching) stress limitation following
     604             : !  Shen et al. (2001). Otherwise, new floes all grow in the smallest
     605             : !  floe size category, representing pancake ice formation.
     606             : !
     607             : !  Shen, H., Ackley, S., & Hopkins, M. (2001). A conceptual model
     608             : !  for pancake-ice formation in a wave field.
     609             : !  Annals of Glaciology, 33, 361-367. doi:10.3189/172756401781818239
     610             : !
     611             : !  authors: Lettie Roach, NIWA/VUW
     612             : !
     613           0 :       subroutine fsd_add_new_ice (ncat, n,    nfsd,          &
     614             :                                   dt,         ai0new,        &   ! LCOV_EXCL_LINE
     615             :                                   d_an_latg,  d_an_newi,     &   ! LCOV_EXCL_LINE
     616             :                                   floe_rad_c, floe_binwidth, &   ! LCOV_EXCL_LINE
     617             :                                   G_radial,   area2,         &   ! LCOV_EXCL_LINE
     618             :                                   wave_sig_ht,               &   ! LCOV_EXCL_LINE
     619             :                                   wave_spectrum,             &   ! LCOV_EXCL_LINE
     620             :                                   wavefreq,                  &   ! LCOV_EXCL_LINE
     621             :                                   dwavefreq,                 &   ! LCOV_EXCL_LINE
     622             :                                   d_afsd_latg,               &   ! LCOV_EXCL_LINE
     623             :                                   d_afsd_newi,               &   ! LCOV_EXCL_LINE
     624             :                                   afsdn,      aicen_init,    &   ! LCOV_EXCL_LINE
     625           0 :                                   aicen,      trcrn)
     626             : 
     627             :       integer (kind=int_kind), intent(in) :: &
     628             :          n          , & ! thickness category number   ! LCOV_EXCL_LINE
     629             :          ncat       , & ! number of thickness categories   ! LCOV_EXCL_LINE
     630             :          nfsd           ! number of floe size categories
     631             : 
     632             :       real (kind=dbl_kind), intent(in) :: &
     633             :          dt         , & ! time step (s)   ! LCOV_EXCL_LINE
     634             :          ai0new     , & ! area of new ice added to cat 1   ! LCOV_EXCL_LINE
     635             :          G_radial   , & ! lateral melt rate (m/s)   ! LCOV_EXCL_LINE
     636             :          wave_sig_ht    ! wave significant height (everywhere) (m)
     637             : 
     638             :       real (kind=dbl_kind), dimension(:), intent(in)  :: &
     639             :          wave_spectrum  ! ocean surface wave spectrum as a function of frequency
     640             :                         ! power spectral density of surface elevation, E(f) (units m^2 s)
     641             : 
     642             :       real(kind=dbl_kind), dimension(:), intent(in) :: &
     643             :          wavefreq   , & ! wave frequencies (s^-1)   ! LCOV_EXCL_LINE
     644             :          dwavefreq      ! wave frequency bin widths (s^-1)
     645             : 
     646             :       real (kind=dbl_kind), dimension(:), intent(in) :: &
     647             :          d_an_latg  , & ! change in aicen due to lateral growth   ! LCOV_EXCL_LINE
     648             :          d_an_newi      ! change in aicen due to frazil ice formation
     649             : 
     650             :       real (kind=dbl_kind), dimension (:), intent(in) :: &
     651             :          aicen_init , & ! fractional area of ice   ! LCOV_EXCL_LINE
     652             :          aicen      , & ! after update   ! LCOV_EXCL_LINE
     653             :          floe_rad_c , & ! fsd size bin centre in m (radius)   ! LCOV_EXCL_LINE
     654             :          floe_binwidth  ! fsd size bin width in m (radius)
     655             : 
     656             :       real (kind=dbl_kind), dimension (:,:), intent(in) :: &
     657             :          afsdn          ! floe size distribution tracer
     658             : 
     659             :       real (kind=dbl_kind), dimension (:), intent(in) :: &
     660             :          area2          ! area after lateral growth, before new ice formation
     661             : 
     662             :       real (kind=dbl_kind), dimension (:,:), intent(inout) :: &
     663             :          trcrn          ! ice tracers
     664             : 
     665             :       real (kind=dbl_kind), dimension(:), intent(inout) :: &
     666             :                         ! change in floe size distribution (area)
     667             :          d_afsd_latg, & ! due to fsd lateral growth
     668             :          d_afsd_newi    ! new ice formation
     669             : 
     670             :       integer (kind=int_kind) :: &
     671             :          k, &              ! floe size category index   ! LCOV_EXCL_LINE
     672             :          new_size, &       ! index for floe size of new ice   ! LCOV_EXCL_LINE
     673             :          nsubt             ! number of subtimesteps
     674             : 
     675             :       real (kind=dbl_kind) :: &
     676           0 :          elapsed_t, subdt  ! elapsed time, subtimestep (s)
     677             : 
     678             :       real (kind=dbl_kind), dimension (nfsd,ncat) :: &
     679           0 :          afsdn_latg     ! fsd after lateral growth
     680             : 
     681             :       real (kind=dbl_kind), dimension (nfsd) :: &
     682             :          dafsd_tmp,  &  ! tmp FSD   ! LCOV_EXCL_LINE
     683             :          df_flx     , & ! finite differences for fsd   ! LCOV_EXCL_LINE
     684           0 :          afsd_ni        ! fsd after new ice added
     685             : 
     686             :       real (kind=dbl_kind), dimension(nfsd+1) :: &
     687           0 :          f_flx          ! finite differences in floe size
     688             : 
     689             :       character(len=*),parameter :: subname='(fsd_add_new_ice)'
     690             : 
     691           0 :       afsdn_latg(:,n) = afsdn(:,n)  ! default
     692             : 
     693           0 :       if (d_an_latg(n) > puny) then ! lateral growth
     694             : 
     695             :          ! adaptive timestep
     696           0 :          elapsed_t = c0
     697           0 :          nsubt = 0
     698             : 
     699           0 :          DO WHILE (elapsed_t.lt.dt)
     700             : 
     701           0 :              nsubt = nsubt + 1
     702           0 :              if (nsubt.gt.100) then
     703           0 :                 write(warnstr,*) subname,'latg not converging'
     704           0 :                 call icepack_warnings_add(warnstr)
     705             :              endif
     706             : 
     707             :              ! finite differences
     708           0 :              df_flx(:) = c0 ! NB could stay zero if all in largest FS cat
     709           0 :              f_flx (:) = c0
     710           0 :              do k = 2, nfsd
     711           0 :                 f_flx(k) = G_radial * afsdn_latg(k-1,n) / floe_binwidth(k-1)
     712             :              end do
     713           0 :              do k = 1, nfsd
     714           0 :                 df_flx(k) = f_flx(k+1) - f_flx(k)
     715             :              end do
     716             : 
     717           0 :              dafsd_tmp(:) = c0
     718           0 :              do k = 1, nfsd
     719           0 :                 dafsd_tmp(k) = (-df_flx(k) + c2 * G_radial * afsdn_latg(k,n) &
     720           0 :                             * (c1/floe_rad_c(k) - SUM(afsdn_latg(:,n)/floe_rad_c(:))) )
     721             : 
     722             :              end do
     723             : 
     724             :             ! timestep required for this
     725           0 :             subdt = get_subdt_fsd(nfsd, afsdn_latg(:,n), dafsd_tmp(:))
     726           0 :             subdt = MIN(subdt, dt)
     727             : 
     728             :             ! update fsd and elapsed time
     729           0 :             afsdn_latg(:,n) = afsdn_latg(:,n) + subdt*dafsd_tmp(:)
     730           0 :             elapsed_t = elapsed_t + subdt
     731             : 
     732             :          END DO
     733             : 
     734           0 :          call icepack_cleanup_fsdn (nfsd, afsdn_latg(:,n))
     735           0 :          if (icepack_warnings_aborted(subname)) return
     736           0 :          trcrn(nt_fsd:nt_fsd+nfsd-1,n) = afsdn_latg(:,n)
     737             : 
     738             :       end if ! lat growth
     739             : 
     740           0 :       new_size = nfsd
     741           0 :       if (n == 1) then
     742             :          ! add new frazil ice to smallest thickness
     743           0 :          if (d_an_newi(n) > puny) then
     744             : 
     745           0 :              afsd_ni(:) = c0
     746             : 
     747           0 :             if (SUM(afsdn_latg(:,n)) > puny) then ! fsd exists
     748             : 
     749           0 :                if (wave_spec) then
     750           0 :                   if (wave_sig_ht > puny) then
     751           0 :                      call wave_dep_growth (nfsd, wave_spectrum, &
     752             :                                            wavefreq, dwavefreq, &   ! LCOV_EXCL_LINE
     753           0 :                                            new_size)
     754           0 :                      if (icepack_warnings_aborted(subname)) return
     755             :                   end if
     756             : 
     757             :                   ! grow in new_size category
     758           0 :                   afsd_ni(new_size) = (afsdn_latg(new_size,n)*area2(n) + ai0new) &
     759           0 :                                                           / (area2(n) + ai0new)
     760           0 :                   do k = 1, new_size-1  ! diminish other floe cats accordingly
     761           0 :                      afsd_ni(k) = afsdn_latg(k,n)*area2(n) / (area2(n) + ai0new)
     762             :                   end do
     763           0 :                   do k = new_size+1, nfsd  ! diminish other floe cats accordingly
     764           0 :                      afsd_ni(k) = afsdn_latg(k,n)*area2(n) / (area2(n) + ai0new)
     765             :                   end do
     766             : 
     767             :                else ! grow in smallest floe size category
     768           0 :                   afsd_ni(1) = (afsdn_latg(1,n)*area2(n) + ai0new) &
     769           0 :                                              / (area2(n) + ai0new)
     770           0 :                   do k = 2, nfsd  ! diminish other floe cats accordingly
     771           0 :                      afsd_ni(k) = afsdn_latg(k,n)*area2(n) / (area2(n)+ai0new)
     772             :                   enddo
     773             :                end if ! wave spec
     774             : 
     775             :             else ! no fsd, so entirely new ice
     776             : 
     777           0 :                if (wave_spec) then
     778           0 :                   if (wave_sig_ht > puny) then
     779           0 :                      call wave_dep_growth (nfsd, wave_spectrum, &
     780             :                                            wavefreq, dwavefreq, &   ! LCOV_EXCL_LINE
     781           0 :                                            new_size)
     782           0 :                      if (icepack_warnings_aborted(subname)) return
     783             :                   end if
     784             : 
     785           0 :                   afsd_ni(new_size) = c1
     786             :                else
     787           0 :                   afsd_ni(1) = c1
     788             :                endif      ! wave forcing
     789             : 
     790             :             endif ! entirely new ice or not
     791             : 
     792           0 :             trcrn(nt_fsd:nt_fsd+nfsd-1,n) = afsd_ni(:)
     793           0 :             call icepack_cleanup_fsdn (nfsd, trcrn(nt_fsd:nt_fsd+nfsd-1,n))
     794           0 :             if (icepack_warnings_aborted(subname)) return
     795             :          endif ! d_an_newi > puny
     796             :       endif    ! n = 1
     797             : 
     798             :       ! history/diagnostics
     799           0 :       do k = 1, nfsd
     800             :          ! sum over n
     801           0 :          d_afsd_latg(k) = d_afsd_latg(k) &
     802             :                 + area2(n)*afsdn_latg(k,n) & ! after latg   ! LCOV_EXCL_LINE
     803           0 :                 - aicen_init(n)*afsdn(k,n) ! at start
     804           0 :          d_afsd_newi(k) = d_afsd_newi(k) &
     805             :                 + aicen(n)*trcrn(nt_fsd+k-1,n) & ! after latg and newi   ! LCOV_EXCL_LINE
     806           0 :                 - area2(n)*afsdn_latg(k,n) ! after latg
     807             :       enddo    ! k
     808             : 
     809             :       end subroutine fsd_add_new_ice
     810             : 
     811             : !=======================================================================
     812             : !
     813             : !  Given a wave spectrum, calculate size of new floes based on
     814             : !  tensile failure, following Shen et al. (2001)
     815             : !
     816             : !  The tensile mode parameter is based on in-situ measurements
     817             : !  by Roach, Smith & Dean (2018).
     818             : !
     819             : !  authors: Lettie Roach, NIWA/VUW
     820             : !
     821           0 :       subroutine wave_dep_growth (nfsd, local_wave_spec, &
     822             :                                   wavefreq, dwavefreq, &   ! LCOV_EXCL_LINE
     823             :                                   new_size)
     824             : 
     825             :       integer (kind=int_kind), intent(in) :: &
     826             :          nfsd            ! number of floe size categories
     827             : 
     828             :       real (kind=dbl_kind), dimension(:), intent(in) :: &
     829             :          local_wave_spec ! ocean surface wave spectrum as a function of frequency
     830             :                          ! power spectral density of surface elevation, E(f) (units m^2 s)
     831             :                          ! dimension set in ice_forcing
     832             : 
     833             :       real(kind=dbl_kind), dimension(:), intent(in) :: &
     834             :          wavefreq,     & ! wave frequencies (s^-1)   ! LCOV_EXCL_LINE
     835             :          dwavefreq       ! wave frequency bin widths (s^-1)
     836             : 
     837             :       integer (kind=int_kind), intent(out) :: &
     838             :          new_size        ! index of floe size category in which new floes will grow
     839             : 
     840             :       ! local variables
     841             :       real (kind=dbl_kind), parameter :: &
     842             :          tensile_param = 0.167_dbl_kind ! tensile mode parameter (kg m^-1 s^-2)
     843             :                                         ! value from Roach, Smith & Dean (2018)
     844             : 
     845             :       real (kind=dbl_kind)  :: &
     846             :          w_amp,       & ! wave amplitude (m)   ! LCOV_EXCL_LINE
     847             :          f_peak,      & ! peak frequency (s^-1)   ! LCOV_EXCL_LINE
     848           0 :          r_max          ! floe radius (m)
     849             : 
     850             :       integer (kind=int_kind) :: k
     851             : 
     852           0 :       w_amp = c2* SQRT(SUM(local_wave_spec*dwavefreq))   ! sig wave amplitude
     853           0 :       f_peak = wavefreq(MAXLOC(local_wave_spec, DIM=1))  ! peak frequency
     854             : 
     855             :       ! tensile failure
     856           0 :       if (w_amp > puny .and. f_peak > puny) then
     857           0 :          r_max = p5*SQRT(tensile_param*gravit/(pi**5*rhoi*w_amp*2))/f_peak**2
     858             :       else
     859           0 :          r_max = bignum
     860             :       end if
     861             : 
     862           0 :       new_size = nfsd
     863           0 :       do k = nfsd-1, 1, -1
     864           0 :          if (r_max <= floe_rad_h(k)) new_size = k
     865             :       end do
     866             : 
     867           0 :       end subroutine wave_dep_growth
     868             : 
     869             : !=======================================================================
     870             : !
     871             : !  Floes are perimitted to weld together in freezing conditions, according
     872             : !  to their geometric probability of overlap if placed randomly on the
     873             : !  domain. The rate per unit area c_weld is the total number
     874             : !  of floes that weld with another, per square meter, per unit time, in the
     875             : !  case of a fully covered ice surface (aice=1), equal to twice the reduction
     876             : !  in total floe number. See Roach, Smith & Dean (2018).
     877             : !
     878             : !
     879             : !  authors: Lettie Roach, NIWA/VUW
     880             : !
     881             : 
     882           0 :       subroutine fsd_weld_thermo (ncat,  nfsd,   &
     883             :                                   dt,    frzmlt, &   ! LCOV_EXCL_LINE
     884             :                                   aicen, trcrn,  &   ! LCOV_EXCL_LINE
     885           0 :                                   d_afsd_weld)
     886             : 
     887             :       integer (kind=int_kind), intent(in) :: &
     888             :          ncat       , & ! number of thickness categories   ! LCOV_EXCL_LINE
     889             :          nfsd           ! number of floe size categories
     890             : 
     891             :       real (kind=dbl_kind), intent(in) :: &
     892             :          dt             ! time step (s)
     893             : 
     894             :       real (kind=dbl_kind), dimension (:), intent(in) :: &
     895             :          aicen          ! ice concentration
     896             : 
     897             :       real (kind=dbl_kind), intent(in) :: &
     898             :          frzmlt         ! freezing/melting potential (W/m^2)
     899             : 
     900             :       real (kind=dbl_kind), dimension (:,:), intent(inout) :: &
     901             :          trcrn          ! ice tracers
     902             : 
     903             :       real (kind=dbl_kind), dimension (:), intent(inout) :: &
     904             :          d_afsd_weld    ! change in fsd due to welding
     905             : 
     906             :       ! local variables
     907             :       real (kind=dbl_kind), parameter :: &
     908             :          aminweld = p1  ! minimum ice concentration likely to weld
     909             : 
     910             :       real (kind=dbl_kind), parameter :: &
     911             :          c_weld = 1.0e-8_dbl_kind
     912             :                         ! constant of proportionality for welding
     913             :                         ! total number of floes that weld with another, per square meter,
     914             :                         ! per unit time, in the case of a fully covered ice surface
     915             :                         ! units m^-2 s^-1, see documentation for details
     916             : 
     917             :       integer (kind=int_kind) :: &
     918             :         n           , & ! thickness category index   ! LCOV_EXCL_LINE
     919             :         k, i, j         ! floe size category indices
     920             : 
     921             :       real (kind=dbl_kind), dimension(nfsd,ncat) :: &
     922           0 :          afsdn          ! floe size distribution tracer
     923             : 
     924             :       real (kind=dbl_kind), dimension(nfsd,ncat) :: &
     925           0 :          d_afsdn_weld   ! change in afsdn due to welding
     926             : 
     927             :       real (kind=dbl_kind), dimension(nfsd) :: &
     928             :          stability  , & ! check for stability   ! LCOV_EXCL_LINE
     929             :          nfsd_tmp   , & ! number fsd   ! LCOV_EXCL_LINE
     930             :          afsd_init  , & ! initial values   ! LCOV_EXCL_LINE
     931             :          afsd_tmp   , & ! work array   ! LCOV_EXCL_LINE
     932           0 :          gain, loss     ! welding tendencies
     933             : 
     934             :       real(kind=dbl_kind) :: &
     935             :          kern       , & ! kernel   ! LCOV_EXCL_LINE
     936             :          subdt      , & ! subcycling time step for stability (s)   ! LCOV_EXCL_LINE
     937           0 :          elapsed_t      ! elapsed subcycling time
     938             : 
     939             :       character(len=*), parameter :: subname='(fsd_weld_thermo)'
     940             : 
     941             : 
     942           0 :       afsdn  (:,:) = c0
     943           0 :       afsd_init(:) = c0
     944           0 :       stability    = c0
     945             : 
     946           0 :       do n = 1, ncat
     947             : 
     948           0 :          d_afsd_weld (:)   = c0
     949           0 :          d_afsdn_weld(:,n) = c0
     950           0 :          afsdn(:,n) = trcrn(nt_fsd:nt_fsd+nfsd-1,n)
     951           0 :          call icepack_cleanup_fsdn (nfsd, afsdn(:,n))
     952           0 :          if (icepack_warnings_aborted(subname)) return
     953             : 
     954             :          ! If there is some ice in the lower (nfsd-1) categories
     955             :          ! and there is freezing potential
     956             :          if ((frzmlt > puny) .and. &               ! freezing potential
     957             :              (aicen(n) > aminweld) .and. &         ! low concentrations unlikely to weld   ! LCOV_EXCL_LINE
     958           0 :              (SUM(afsdn(1:nfsd-1,n)) > puny)) then ! some ice in nfsd-1 categories
     959             : 
     960           0 :             afsd_init(:) = afsdn(:,n)     ! save initial values
     961           0 :             afsd_tmp (:) = afsd_init(:)   ! work array
     962             : 
     963             :             ! in case of minor numerical errors
     964           0 :             WHERE(afsd_tmp < puny) afsd_tmp = c0
     965           0 :             afsd_tmp = afsd_tmp/SUM(afsd_tmp)
     966             : 
     967             :             ! adaptive sub-timestep
     968           0 :             elapsed_t = c0
     969           0 :             DO WHILE (elapsed_t < dt)
     970             : 
     971             :                ! calculate sub timestep
     972           0 :                nfsd_tmp = afsd_tmp/floe_area_c
     973           0 :                WHERE (afsd_tmp > puny) &
     974           0 :                   stability = nfsd_tmp/(c_weld*afsd_tmp*aicen(n))
     975           0 :                WHERE (stability < puny) stability = bignum
     976           0 :                subdt = MINVAL(stability)
     977           0 :                subdt = MIN(subdt,dt)
     978             : 
     979           0 :                loss(:) = c0
     980           0 :                gain(:) = c0
     981             : 
     982           0 :                do i = 1, nfsd ! consider loss from this category
     983           0 :                do j = 1, nfsd ! consider all interaction partners
     984           0 :                    k = iweld(i,j) ! product of i+j
     985           0 :                    if (k > i) then
     986           0 :                        kern = c_weld * floe_area_c(i) * aicen(n)
     987           0 :                        loss(i) = loss(i) + kern*afsd_tmp(i)*afsd_tmp(j)
     988           0 :                        gain(k) = gain(k) + kern*afsd_tmp(i)*afsd_tmp(j)
     989             :                    end if
     990             :                end do
     991             :                end do
     992             : 
     993             :                ! does largest category lose?
     994             : !               if (loss(nfsd) > puny) stop 'weld, largest cat losing'
     995             : !               if (gain(1) > puny) stop 'weld, smallest cat gaining'
     996             : 
     997             :                ! update afsd
     998           0 :                afsd_tmp(:) = afsd_tmp(:) + subdt*(gain(:) - loss(:))
     999             : 
    1000             :                ! in case of minor numerical errors
    1001           0 :                WHERE(afsd_tmp < puny) afsd_tmp = c0
    1002           0 :                afsd_tmp = afsd_tmp/SUM(afsd_tmp)
    1003             : 
    1004             :                ! update time
    1005           0 :                elapsed_t = elapsed_t + subdt
    1006             : 
    1007             :                ! stop if all in largest floe size cat
    1008           0 :                if (afsd_tmp(nfsd) > (c1-puny)) exit
    1009             : 
    1010             :             END DO ! time
    1011             : 
    1012           0 :             afsdn(:,n) = afsd_tmp(:)
    1013           0 :             call icepack_cleanup_fsdn (nfsd, afsdn(:,n))
    1014           0 :             if (icepack_warnings_aborted(subname)) return
    1015             : 
    1016           0 :             do k = 1, nfsd
    1017           0 :                trcrn(nt_fsd+k-1,n) = afsdn(k,n)
    1018             :                ! history/diagnostics
    1019           0 :                d_afsdn_weld(k,n) = afsdn(k,n) - afsd_init(k)
    1020             :             enddo
    1021             :          endif ! try to weld
    1022             :       enddo    ! ncat
    1023             : 
    1024             :       ! history/diagnostics
    1025           0 :       do k = 1, nfsd
    1026           0 :          d_afsd_weld(k) = c0
    1027           0 :          do n = 1, ncat
    1028           0 :             d_afsd_weld(k) = d_afsd_weld(k) + aicen(n)*d_afsdn_weld(k,n)
    1029             :          end do ! n
    1030             :       end do    ! k
    1031             : 
    1032             :       end subroutine fsd_weld_thermo
    1033             : 
    1034             : !=======================================================================
    1035             : !
    1036             : !  Adaptive timestepping (process agnostic)
    1037             : !  See reference: Horvat & Tziperman (2017) JGR, Appendix A
    1038             : !
    1039             : !  authors: 2018 Lettie Roach, NIWA/VUW
    1040             : !
    1041             : !
    1042           0 :       function get_subdt_fsd(nfsd, afsd_init, d_afsd) &
    1043           0 :                               result(subdt)
    1044             : 
    1045             :       integer (kind=int_kind), intent(in) :: &
    1046             :          nfsd       ! number of floe size categories
    1047             : 
    1048             :       real (kind=dbl_kind), dimension (nfsd), intent(in) :: &
    1049             :          afsd_init, d_afsd ! floe size distribution tracer
    1050             : 
    1051             :       ! output
    1052             :       real (kind=dbl_kind) :: &
    1053             :          subdt ! subcycle timestep (s)
    1054             : 
    1055             :       ! local variables
    1056             :       real (kind=dbl_kind), dimension (nfsd) :: &
    1057           0 :          check_dt ! to compute subcycle timestep (s)
    1058             : 
    1059             :       integer (kind=int_kind) :: k
    1060             : 
    1061           0 :       check_dt(:) = bignum
    1062           0 :       do k = 1, nfsd
    1063           0 :           if (d_afsd(k) >  puny) check_dt(k) = (1-afsd_init(k))/d_afsd(k)
    1064           0 :           if (d_afsd(k) < -puny) check_dt(k) = afsd_init(k)/ABS(d_afsd(k))
    1065             :       end do
    1066             : 
    1067           0 :       subdt = MINVAL(check_dt)
    1068             : 
    1069           0 :       end function get_subdt_fsd
    1070             : 
    1071             : 
    1072             : !=======================================================================
    1073             : 
    1074             :       end module icepack_fsd
    1075             : 
    1076             : !=======================================================================
    1077             : 

Generated by: LCOV version 1.14-6-g40580cd