LCOV - code coverage report
Current view: top level - icepack/columnphysics - icepack_fsd.F90 (source / functions) Coverage Total Hit
Test: 250115-172326:736c1771a8:7:first,quick,base,travis,io,gridsys,unittest Lines: 88.70 % 301 267
Test Date: 2025-01-15 16:42:12 Functions: 100.00 % 10 10

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

Generated by: LCOV version 2.0-1