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

            Line data    Source code
       1              : !=======================================================================
       2              : !
       3              : ! snow redistribution and metamorphism
       4              : !
       5              : ! authors Elizabeth Hunke, LANL
       6              : !         Nicole Jeffery, LANL
       7              : !
       8              :       module icepack_snow
       9              : 
      10              :       use icepack_kinds
      11              :       use icepack_parameters, only: puny, p1, p5, c0, c1, c4, c10, c100, pi
      12              :       use icepack_parameters, only: rhos, rhow, rhoi, rhofresh, snwgrain
      13              :       use icepack_parameters, only: snwlvlfac, Tffresh, cp_ice, Lfresh
      14              :       use icepack_parameters, only: snwredist, rsnw_fall, rsnw_tmax, rhosnew
      15              :       use icepack_parameters, only: rhosmin, rhosmax, windmin, drhosdwind
      16              :       use icepack_parameters, only: isnw_T, isnw_Tgrd, isnw_rhos
      17              :       use icepack_parameters, only: snowage_rhos, snowage_Tgrd, snowage_T
      18              :       use icepack_parameters, only: snowage_tau, snowage_kappa, snowage_drdt0
      19              :       use icepack_parameters, only: snw_aging_table, use_smliq_pnd
      20              :       use icepack_tracers, only: ncat, nilyr, nslyr
      21              : 
      22              :       use icepack_therm_shared, only: icepack_ice_temperature
      23              :       use icepack_therm_shared, only: adjust_enthalpy
      24              : 
      25              :       use icepack_warnings, only: icepack_warnings_add, icepack_warnings_setabort
      26              :       use icepack_warnings, only: icepack_warnings_aborted
      27              : 
      28              :       implicit none
      29              :       private
      30              : 
      31              :       public :: icepack_step_snow, drain_snow, icepack_init_snow
      32              : 
      33              :       real (kind=dbl_kind), parameter, public :: &
      34              :          S_r  = 0.033_dbl_kind, & ! irreducible saturation (Anderson 1976)   ! LCOV_EXCL_LINE
      35              :          S_wet= 4.22e5_dbl_kind  ! wet metamorphism parameter (um^3/s)
      36              :                                   ! = 1.e18 * 4.22e-13 (Oleson 2010)
      37              : 
      38              :       real (kind=dbl_kind) :: &
      39              :          min_rhos, &   ! snowtable axis data, assumes linear data   ! LCOV_EXCL_LINE
      40              :          del_rhos, &   ! LCOV_EXCL_LINE
      41              :          min_Tgrd, &   ! LCOV_EXCL_LINE
      42              :          del_Tgrd, &   ! LCOV_EXCL_LINE
      43              :          min_T   , &   ! LCOV_EXCL_LINE
      44              :          del_T
      45              : 
      46              :       logical (kind=log_kind) :: &
      47              :          lin_rhos = .false., &  ! flag to specify whether the snowtable dimensions are linear   ! LCOV_EXCL_LINE
      48              :          lin_Tgrd = .false., &  ! this will allow quick lookup   ! LCOV_EXCL_LINE
      49              :          lin_T    = .false.
      50              : 
      51              : !=======================================================================
      52              : 
      53              :       contains
      54              : 
      55              : !=======================================================================
      56              : !autodocument_start icepack_init_snow
      57              : ! Updates snow tracers
      58              : !
      59              : ! authors: Elizabeth C. Hunke, LANL
      60              : !          Nicole Jeffery, LANL
      61              : 
      62          332 :       subroutine icepack_init_snow
      63              : 
      64              : !autodocument_end
      65              : 
      66              :       ! local variables
      67              : 
      68              :       integer (kind=int_kind) :: n
      69              : 
      70              :       character (len=*),parameter :: subname='(icepack_init_snow)'
      71              : 
      72              :       !-----------------------------------------------------------------
      73              :       ! Snow metamorphism lookup table
      74              :       !-----------------------------------------------------------------
      75              : 
      76              :       ! if snw_aging_table = 'snicar'
      77              :       ! best-fit parameters are read from a table (netcdf)
      78              :       ! snowage_tau, snowage_kappa, snowage_drdt0
      79              :       !  11 temperatures from 223.15 to 273.15 K by 5.0
      80              :       !  31 temperature gradients from 0 to 300 K/m by 10
      81              :       !   8 snow densities from 50 to 400 kg/m3 by 50
      82              : 
      83              :       ! if snw_aging_table = 'test'
      84              :       ! for testing Icepack without netcdf,
      85              :       ! use a subsampled, hard-coded table
      86              :       !   5 temperatures from 243.15 by 5.0 K
      87              :       !   5 temperature gradients from 0 to 40 K/m by 10
      88              :       !   1 snow density at 300 kg/m3
      89              : 
      90              :       ! if snw_aging_table = 'file'
      91              :       ! all data has to be passed into icepack_parameters
      92              : 
      93          332 :       if (snwgrain) then
      94          328 :          if (trim(snw_aging_table) == 'snicar') then ! read netcdf file
      95            0 :             isnw_rhos  =  8   ! maxiumum snow density index
      96            0 :             isnw_Tgrd  = 31   ! maxiumum temperature gradient index
      97            0 :             isnw_T     = 11   ! maxiumum temperature index
      98            0 :             min_rhos   =  50.0_dbl_kind  ! snowtable dimension data
      99            0 :             del_rhos   =  50.0_dbl_kind
     100            0 :             lin_rhos   = .true.
     101            0 :             min_Tgrd   =   0.0_dbl_kind
     102            0 :             del_Tgrd   =  10.0_dbl_kind
     103            0 :             lin_Tgrd   = .true.
     104            0 :             min_T      = 223.15_dbl_kind
     105            0 :             del_T      =   5.0_dbl_kind
     106            0 :             lin_T      = .true.
     107              :             ! check if these are already allocated/set, if so, make sure size is OK
     108            0 :             if (allocated(snowage_tau))   then
     109              :                if (size(snowage_tau,dim=1) /= isnw_rhos .or. &
     110            0 :                    size(snowage_tau,dim=2) /= isnw_Tgrd .or. &   ! LCOV_EXCL_LINE
     111              :                    size(snowage_tau,dim=3) /= isnw_T   ) then
     112            0 :                   call icepack_warnings_setabort(.true.,__FILE__,__LINE__)
     113            0 :                   call icepack_warnings_add(subname//'ERROR: snowage_tau size snw_aging_table=snicar')
     114            0 :                   return
     115              :                endif
     116              :             else
     117            0 :                allocate (snowage_tau  (isnw_rhos,isnw_Tgrd,isnw_T))
     118              :             endif
     119              : 
     120            0 :             if (allocated(snowage_kappa)) then
     121              :                if (size(snowage_kappa,dim=1) /= isnw_rhos .or. &
     122            0 :                    size(snowage_kappa,dim=2) /= isnw_Tgrd .or. &   ! LCOV_EXCL_LINE
     123              :                    size(snowage_kappa,dim=3) /= isnw_T   ) then
     124            0 :                   call icepack_warnings_setabort(.true.,__FILE__,__LINE__)
     125            0 :                   call icepack_warnings_add(subname//'ERROR: snowage_kappa size snw_aging_table=snicar')
     126            0 :                   return
     127              :                endif
     128              :             else
     129            0 :                allocate (snowage_kappa(isnw_rhos,isnw_Tgrd,isnw_T))
     130              :             endif
     131              : 
     132            0 :             if (allocated(snowage_drdt0)) then
     133              :                if (size(snowage_drdt0,dim=1) /= isnw_rhos .or. &
     134            0 :                    size(snowage_drdt0,dim=2) /= isnw_Tgrd .or. &   ! LCOV_EXCL_LINE
     135              :                    size(snowage_drdt0,dim=3) /= isnw_T   ) then
     136            0 :                   call icepack_warnings_setabort(.true.,__FILE__,__LINE__)
     137            0 :                   call icepack_warnings_add(subname//'ERROR: snowage_drdt0 size snw_aging_table=snicar')
     138            0 :                   return
     139              :                endif
     140              :             else
     141            0 :                allocate (snowage_drdt0(isnw_rhos,isnw_Tgrd,isnw_T))
     142              :             endif
     143              : 
     144            0 :             if (allocated(snowage_rhos))  deallocate(snowage_rhos)
     145            0 :             if (allocated(snowage_Tgrd))  deallocate(snowage_Tgrd)
     146            0 :             if (allocated(snowage_T))     deallocate(snowage_T)
     147            0 :             allocate (snowage_rhos (isnw_rhos))
     148            0 :             allocate (snowage_Tgrd (isnw_Tgrd))
     149            0 :             allocate (snowage_T    (isnw_T))
     150            0 :             do n = 1, isnw_rhos
     151            0 :                snowage_rhos(n) = min_rhos + real((n-1),dbl_kind)*del_rhos
     152              :             enddo
     153            0 :             do n = 1, isnw_Tgrd
     154            0 :                snowage_Tgrd(n) = min_Tgrd + real((n-1),dbl_kind)*del_Tgrd
     155              :             enddo
     156            0 :             do n = 1, isnw_T
     157            0 :                snowage_T(n) = min_T + real((n-1),dbl_kind)*del_T
     158              :             enddo
     159              : 
     160          328 :          elseif (trim(snw_aging_table) == 'file') then
     161          328 :             isnw_rhos  =  -1  ! maxiumum snow density index
     162          328 :             isnw_Tgrd  =  -1  ! maxiumum temperature gradient index
     163          328 :             isnw_T     =  -1  ! maxiumum temperature index
     164              : 
     165            0 :          elseif (trim(snw_aging_table) == 'test') then
     166            0 :             isnw_rhos  =  1   ! maxiumum snow density index
     167            0 :             isnw_Tgrd  =  5   ! maxiumum temperature gradient index
     168            0 :             isnw_T     =  5   ! maxiumum temperature index
     169            0 :             min_rhos   = 300.0_dbl_kind  ! snowtable dimension data
     170            0 :             del_rhos   =  50.0_dbl_kind
     171            0 :             lin_rhos   = .true.
     172            0 :             min_Tgrd   =   0.0_dbl_kind
     173            0 :             del_Tgrd   =  10.0_dbl_kind
     174            0 :             lin_Tgrd   = .true.
     175            0 :             min_T      = 243.15_dbl_kind
     176            0 :             del_T      =   5.0_dbl_kind
     177            0 :             lin_T      = .true.
     178            0 :             if (allocated(snowage_tau))   deallocate(snowage_tau)
     179            0 :             if (allocated(snowage_kappa)) deallocate(snowage_kappa)
     180            0 :             if (allocated(snowage_drdt0)) deallocate(snowage_drdt0)
     181            0 :             if (allocated(snowage_rhos))  deallocate(snowage_rhos)
     182            0 :             if (allocated(snowage_Tgrd))  deallocate(snowage_Tgrd)
     183            0 :             if (allocated(snowage_T))     deallocate(snowage_T)
     184            0 :             allocate (snowage_tau  (isnw_rhos,isnw_Tgrd,isnw_T))
     185            0 :             allocate (snowage_kappa(isnw_rhos,isnw_Tgrd,isnw_T))
     186            0 :             allocate (snowage_drdt0(isnw_rhos,isnw_Tgrd,isnw_T))
     187            0 :             allocate (snowage_rhos (isnw_rhos))
     188            0 :             allocate (snowage_Tgrd (isnw_Tgrd))
     189            0 :             allocate (snowage_T    (isnw_T))
     190            0 :             do n = 1, isnw_rhos
     191            0 :                snowage_rhos(n) = min_rhos + real((n-1),dbl_kind)*del_rhos
     192              :             enddo
     193            0 :             do n = 1, isnw_Tgrd
     194            0 :                snowage_Tgrd(n) = min_Tgrd + real((n-1),dbl_kind)*del_Tgrd
     195              :             enddo
     196            0 :             do n = 1, isnw_T
     197            0 :                snowage_T(n) = min_T + real((n-1),dbl_kind)*del_T
     198              :             enddo
     199              : 
     200              :             ! Subset of dry snow aging parameters
     201              :             snowage_tau = reshape((/ &
     202              :             3.34947394_dbl_kind, 4.02124159_dbl_kind,    4.03328223_dbl_kind, &   ! LCOV_EXCL_LINE
     203              :             3.02686921_dbl_kind, 2.14125851_dbl_kind,    3.97008737_dbl_kind, &   ! LCOV_EXCL_LINE
     204              :             4.72725821_dbl_kind, 3.65313459_dbl_kind,    2.41198936_dbl_kind,  &   ! LCOV_EXCL_LINE
     205              :             2.53065623e-1_dbl_kind, 4.60286630_dbl_kind, 4.99721440_dbl_kind, &   ! LCOV_EXCL_LINE
     206              :             3.29168191_dbl_kind, 2.66426779e-1_dbl_kind, 9.15830596e-5_dbl_kind, &   ! LCOV_EXCL_LINE
     207              :             5.33186128_dbl_kind, 4.90833452_dbl_kind,    1.55269141_dbl_kind, &   ! LCOV_EXCL_LINE
     208              :             1.31225526e-3_dbl_kind,  9.36078196e-4_dbl_kind, 6.25428631_dbl_kind, &   ! LCOV_EXCL_LINE
     209              :             5.04394794_dbl_kind, 2.92857366e-3_dbl_kind, 9.01488751e-3_dbl_kind,  &   ! LCOV_EXCL_LINE
     210              :             1.19037046e-2_dbl_kind/), &   ! LCOV_EXCL_LINE
     211            0 :             (/isnw_rhos,isnw_Tgrd,isnw_T/))
     212              : 
     213              :             snowage_kappa = reshape((/ &
     214              :             0.60824438, 0.56442972, 0.5527807,  0.64299537, 0.77672359, &   ! LCOV_EXCL_LINE
     215              :             0.57105932, 0.52791041, 0.59868076, 0.7487191,  1.57946877, &   ! LCOV_EXCL_LINE
     216              :             0.54236508, 0.52458285, 0.65520877, 1.52356017, 4.37789838, &   ! LCOV_EXCL_LINE
     217              :             0.51449138, 0.54494334, 0.91628508, 3.28847035, 3.64418487, &   ! LCOV_EXCL_LINE
     218              :             0.48538708, 0.55386601, 2.81247103, 2.72445522, 2.8230216/), &   ! LCOV_EXCL_LINE
     219            0 :             (/isnw_rhos,isnw_Tgrd,isnw_T/))
     220              : 
     221              :             snowage_drdt0 = reshape((/ &
     222              :             1.26597871, 1.26602416, 1.26613263, 1.26620414, 1.26629424, &   ! LCOV_EXCL_LINE
     223              :             1.92418877, 1.92430063, 1.92445964, 1.92451557, 1.92469806, &   ! LCOV_EXCL_LINE
     224              :             2.79086547, 2.79147315, 2.79137562, 2.79150846, 2.79216439, &   ! LCOV_EXCL_LINE
     225              :             3.85605846, 3.85668001, 3.85844559, 3.86073682, 3.863199, &   ! LCOV_EXCL_LINE
     226              :             5.0861907,  5.08765668, 5.09200195, 5.09665276, 5.10079895/), &   ! LCOV_EXCL_LINE
     227            0 :             (/isnw_rhos,isnw_Tgrd,isnw_T/))
     228              :          else
     229            0 :             call icepack_warnings_setabort(.true.,__FILE__,__LINE__)
     230            0 :             call icepack_warnings_add(subname//'ERROR: snw_aging_table value')
     231            0 :             return
     232              :          endif
     233              :       endif
     234              : 
     235              :       end subroutine icepack_init_snow
     236              : 
     237              : !=======================================================================
     238              : !autodocument_start icepack_step_snow
     239              : ! Updates snow tracers
     240              : !
     241              : ! authors: Elizabeth C. Hunke, LANL
     242              : !          Nicole Jeffery, LANL
     243              : 
     244     75584640 :       subroutine icepack_step_snow(dt,                   &
     245              :                                    wind,      aice,      &   ! LCOV_EXCL_LINE
     246     75584640 :                                    aicen,     vicen,     &   ! LCOV_EXCL_LINE
     247    151169280 :                                    vsnon,     Tsfc,      &   ! LCOV_EXCL_LINE
     248     75584640 :                                    zqin1,     zSin1,     &   ! LCOV_EXCL_LINE
     249     75584640 :                                    zqsn,                 &   ! LCOV_EXCL_LINE
     250     75584640 :                                    alvl,      vlvl,      &   ! LCOV_EXCL_LINE
     251     75584640 :                                    smice,     smliq,     &   ! LCOV_EXCL_LINE
     252    151169280 :                                    rsnw,      rhos_cmpn, &   ! LCOV_EXCL_LINE
     253              :                                    fresh,     fhocn,     &   ! LCOV_EXCL_LINE
     254              :                                    fsloss,    fsnow)
     255              : 
     256              :       real (kind=dbl_kind), intent(in) :: &
     257              :          dt     , & ! time step   ! LCOV_EXCL_LINE
     258              :          wind   , & ! wind speed (m/s)   ! LCOV_EXCL_LINE
     259              :          fsnow  , & ! snowfall rate (kg m-2 s-1)   ! LCOV_EXCL_LINE
     260              :          aice       ! ice area fraction
     261              : 
     262              :       real (kind=dbl_kind), dimension(:), intent(in) :: &
     263              :          aicen, & ! ice area fraction   ! LCOV_EXCL_LINE
     264              :          vicen, & ! ice volume (m)   ! LCOV_EXCL_LINE
     265              :          Tsfc , & ! surface temperature (C)   ! LCOV_EXCL_LINE
     266              :          zqin1, & ! ice upper layer enthalpy   ! LCOV_EXCL_LINE
     267              :          zSin1, & ! ice upper layer salinity   ! LCOV_EXCL_LINE
     268              :          alvl,  & ! level ice area tracer   ! LCOV_EXCL_LINE
     269              :          vlvl     ! level ice volume tracer
     270              : 
     271              :       real (kind=dbl_kind), intent(inout) :: &
     272              :          fresh    , & ! fresh water flux to ocean (kg/m^2/s)   ! LCOV_EXCL_LINE
     273              :          fhocn    , & ! net heat flux to ocean (W/m^2)   ! LCOV_EXCL_LINE
     274              :          fsloss       ! rate of snow loss to leads (kg/m^2/s)
     275              : 
     276              :       real (kind=dbl_kind), dimension(:), intent(inout) :: &
     277              :          vsnon    ! snow volume (m)
     278              : 
     279              :       real (kind=dbl_kind), dimension(:,:), intent(inout) :: &
     280              :          zqsn     , & ! snow enthalpy (J/m^3)   ! LCOV_EXCL_LINE
     281              :          smice    , & ! tracer for mass of ice in snow (kg/m^3)   ! LCOV_EXCL_LINE
     282              :          smliq    , & ! tracer for mass of liquid in snow (kg/m^3)   ! LCOV_EXCL_LINE
     283              :          rsnw     , & ! snow grain radius (10^-6 m)   ! LCOV_EXCL_LINE
     284              :          rhos_cmpn    ! effective snow density: compaction (kg/m^3)
     285              : 
     286              : !autodocument_end
     287              : 
     288              :       ! local variables
     289              : 
     290              :       integer (kind=int_kind) :: k, n
     291              : 
     292              :       real (kind=dbl_kind), dimension(ncat) :: &
     293    151169280 :          zTin1, & ! ice upper layer temperature (C)   ! LCOV_EXCL_LINE
     294    151169280 :          hsn  , & ! snow thickness (m)   ! LCOV_EXCL_LINE
     295     75584640 :          hin      ! ice thickness
     296              : 
     297              :       real (kind=dbl_kind) :: &
     298              :          vsno,  & ! snow volume (m)   ! LCOV_EXCL_LINE
     299              :          tmp1, tmp2
     300              : 
     301              :       character (len=*),parameter :: subname='(icepack_step_snow)'
     302              : 
     303              :       !-----------------------------------------------------------------
     304              :       ! Initialize effective snow density (compaction) for new snow
     305              :       !-----------------------------------------------------------------
     306              : 
     307     75584640 :       if (snwredist(1:3) == 'ITD') then
     308     51156000 :          do n = 1, ncat
     309    264306000 :             do k = 1, nslyr
     310    255780000 :                if (rhos_cmpn(k,n) < rhosmin) rhos_cmpn(k,n) = rhosnew
     311              :             enddo
     312              :          enddo
     313              :       endif
     314              : 
     315              :       !-----------------------------------------------------------------
     316              :       ! Redistribute snow based on wind
     317              :       !-----------------------------------------------------------------
     318              : 
     319     75584640 :       vsno = c0
     320    453507840 :       do n = 1, ncat
     321    453507840 :          vsno = vsno + vsnon(n)
     322              :       enddo
     323     75584640 :       tmp1 = rhos*vsno + fresh*dt
     324              : 
     325     75584640 :       if (snwredist(1:3) == 'ITD' .and. aice > puny) then
     326              :          call snow_redist(dt,                  &
     327              :                           wind,     aicen(:),  &   ! LCOV_EXCL_LINE
     328              :                           vicen(:), vsnon(:),  &   ! LCOV_EXCL_LINE
     329              :                           zqsn(:,:),           &   ! LCOV_EXCL_LINE
     330              :                           alvl(:),  vlvl(:),   &   ! LCOV_EXCL_LINE
     331              :                           fresh,    fhocn,     &   ! LCOV_EXCL_LINE
     332              :                           fsloss,   rhos_cmpn, &   ! LCOV_EXCL_LINE
     333      1408266 :                           fsnow)
     334      1408266 :          if (icepack_warnings_aborted(subname)) return
     335              :       endif
     336              : 
     337     75584640 :       vsno = c0
     338    453507840 :       do n = 1, ncat
     339    453507840 :          vsno = vsno + vsnon(n)
     340              :       enddo
     341     75584640 :       tmp2 = rhos*vsno + fresh*dt
     342              : 
     343              :       ! check conservation
     344     75584640 :       if (abs(tmp1-tmp2)>puny) then
     345            0 :          call icepack_warnings_setabort(.true.,__FILE__,__LINE__)
     346            0 :          call icepack_warnings_add(subname//'ERROR: snow redistribution')
     347              :       endif
     348              : 
     349              :       !-----------------------------------------------------------------
     350              :       ! Adjust snow grain radius
     351              :       !-----------------------------------------------------------------
     352              : 
     353     75584640 :       if (snwgrain) then
     354    451837440 :          do n = 1, ncat
     355    376531200 :             zTin1(n) = c0
     356    376531200 :             hsn  (n) = c0
     357    376531200 :             hin  (n) = c0
     358    451837440 :             if (aicen(n) > puny) then
     359     34034187 :                zTin1(n) = icepack_ice_temperature(zqin1(n), zSin1(n))
     360     34034187 :                hsn(n)   = vsnon(n)/aicen(n)
     361     34034187 :                hin(n)   = vicen(n)/aicen(n)
     362              :             endif
     363              :          enddo
     364              : 
     365              :          call update_snow_radius (dt,                &
     366              :                                   rsnw,       hin,   &   ! LCOV_EXCL_LINE
     367              :                                   Tsfc,       zTin1, &   ! LCOV_EXCL_LINE
     368              :                                   hsn,        zqsn,  &   ! LCOV_EXCL_LINE
     369     75306240 :                                   smice,      smliq)
     370     75306240 :          if (icepack_warnings_aborted(subname)) return
     371              :       endif
     372              : 
     373              :       end subroutine icepack_step_snow
     374              : 
     375              : !=======================================================================
     376              : 
     377              : ! Snow redistribution by wind, based on O. Lecomte Ph.D. (2014).
     378              : ! The original formulation:
     379              : ! Snow in suspension depends on wind speed, density and the standard
     380              : ! deviation of the ice thickness distribution. Snow is redistributed
     381              : ! among ice categories proportionally to the category areas.
     382              : !
     383              : ! Namelist option snwredist = 'ITDrdg' modifies the approach to use
     384              : ! the level and ridged ice tracers:
     385              : ! As above, but use the standard deviation of the level and ridged
     386              : ! ice thickness distribution for snow in suspension, and redistribute
     387              : ! based on ridged ice area.
     388              : !
     389              : ! convention:
     390              : ! volume, mass and energy include factor of ain
     391              : ! thickness does not
     392              : 
     393      1408266 :       subroutine snow_redist(dt, wind, ain, vin, vsn, zqsn, &
     394      1408266 :          alvl, vlvl, fresh, fhocn, fsloss, rhos_cmpn, fsnow)
     395              : 
     396              :       real (kind=dbl_kind), intent(in) :: &
     397              :          dt        , & ! time step (s)   ! LCOV_EXCL_LINE
     398              :          wind      , & ! wind speed (m/s)   ! LCOV_EXCL_LINE
     399              :          fsnow         ! snowfall rate (kg m-2 s-1)
     400              : 
     401              :       real (kind=dbl_kind), dimension(:), intent(in) :: &
     402              :          ain       , & ! ice area fraction   ! LCOV_EXCL_LINE
     403              :          vin       , & ! ice volume (m)   ! LCOV_EXCL_LINE
     404              :          alvl      , & ! level ice area tracer   ! LCOV_EXCL_LINE
     405              :          vlvl          ! level ice volume tracer
     406              : 
     407              :       real (kind=dbl_kind), intent(inout) :: &
     408              :          fresh     , & ! fresh water flux to ocean (kg/m^2/s)   ! LCOV_EXCL_LINE
     409              :          fhocn     , & ! net heat flux to ocean (W/m^2)   ! LCOV_EXCL_LINE
     410              :          fsloss        ! rate of snow loss to leads (kg/m^2/s)
     411              : 
     412              :       real (kind=dbl_kind), dimension(:), intent(inout) :: &
     413              :          vsn           ! snow volume (m)
     414              : 
     415              :       real (kind=dbl_kind), dimension(:,:), intent(inout) :: &
     416              :          zqsn      , & ! snow enthalpy (J/m^3)   ! LCOV_EXCL_LINE
     417              :          rhos_cmpn     ! effective snow density: compaction (kg/m^3)
     418              : 
     419              :       ! local variables
     420              : 
     421              :       integer (kind=int_kind) :: &
     422              :          n         , & ! category index   ! LCOV_EXCL_LINE
     423              :          k             ! layer index
     424              : 
     425              :       integer (kind=int_kind), dimension(ncat) :: &
     426      2816532 :          klyr          ! layer index
     427              : 
     428              :       real (kind=dbl_kind), parameter :: &
     429              :          refsd   = c1            , & ! standard deviation reference   ! LCOV_EXCL_LINE
     430              :          gamma   = 1.e-5_dbl_kind    ! tuning coefficient
     431              : 
     432              :       real (kind=dbl_kind) :: &
     433              :          Vseas     , & ! critical seasonal wind speed (m/s)   ! LCOV_EXCL_LINE
     434              :          ITDsd     , & ! standard deviation of ITD   ! LCOV_EXCL_LINE
     435              :          flost     , & ! fraction of snow lost in leads   ! LCOV_EXCL_LINE
     436              :          alost     , & ! effective lead area for snow lost in leads   ! LCOV_EXCL_LINE
     437              :          suma      , & ! sum of ice area over categories   ! LCOV_EXCL_LINE
     438              :          sumv      , & ! sum of ice volume over categories (m)   ! LCOV_EXCL_LINE
     439              :          summ      , & ! sum of snow mass over categories (kg/m^2)   ! LCOV_EXCL_LINE
     440              :          sumq      , & ! sum of snow enthalpy over categories (kg/m^2)   ! LCOV_EXCL_LINE
     441              :          msusp     , & ! potential mass of snow in suspension (kg/m^2)   ! LCOV_EXCL_LINE
     442              :          msnw_susp , & ! mass of snow in suspension (kg/m^2)   ! LCOV_EXCL_LINE
     443              :          esnw_susp , & ! energy of snow in suspension (J/m^2)   ! LCOV_EXCL_LINE
     444              :          asnw_lvl  , & ! mass of snow redeposited on level ice (kg/m^2)   ! LCOV_EXCL_LINE
     445              :          e_redeptmp, & ! redeposited energy (J/m^2)   ! LCOV_EXCL_LINE
     446              :          dhsn      , & ! change in snow depth (m)   ! LCOV_EXCL_LINE
     447              :          dmp       , & ! mass difference in previous layer (kg/m^2)   ! LCOV_EXCL_LINE
     448              :          hslyr     , & ! snow layer thickness (m)   ! LCOV_EXCL_LINE
     449              :          hslab     , & ! new snow thickness (m)   ! LCOV_EXCL_LINE
     450              :          drhos     , & ! change in snow density due to compaction (kg/m^3)   ! LCOV_EXCL_LINE
     451              :          mlost     , & ! mass of suspended snow lost in leads (kg/m^2)   ! LCOV_EXCL_LINE
     452              :          elost     , & ! energy of suspended snow lost in leads (J/m^2)   ! LCOV_EXCL_LINE
     453              :          de        , & ! change in energy (J/m^2)   ! LCOV_EXCL_LINE
     454              :          al, ar    , & ! areas of level and ridged ice   ! LCOV_EXCL_LINE
     455              :          hlvl, hrdg, & ! thicknesses of level and ridged ice   ! LCOV_EXCL_LINE
     456              :          tmp1, tmp2, & ! temporary values   ! LCOV_EXCL_LINE
     457              :          tmp3, tmp4, & ! temporary values   ! LCOV_EXCL_LINE
     458              :          tmp5      , & ! temporary values   ! LCOV_EXCL_LINE
     459              :          work          ! temporary value
     460              : 
     461              :       real (kind=dbl_kind), dimension(ncat) :: &
     462      2816532 :          sfac      , & ! temporary for snwlvlfac   ! LCOV_EXCL_LINE
     463      1408266 :          ardg      , & ! ridged ice area tracer   ! LCOV_EXCL_LINE
     464      2816532 :          m_erosion , & ! eroded mass (kg/m^2)   ! LCOV_EXCL_LINE
     465      2816532 :          e_erosion , & ! eroded energy (J/m^2)   ! LCOV_EXCL_LINE
     466      2816532 :          m_redep   , & ! redeposited mass (kg/m^2)   ! LCOV_EXCL_LINE
     467      2816532 :          e_redep   , & ! redeposited energy (J/m^2)   ! LCOV_EXCL_LINE
     468      2816532 :          vsn_init  , & ! initial volume (m)   ! LCOV_EXCL_LINE
     469      2816532 :          esn_init  , & ! initial energy (J/m^2)   ! LCOV_EXCL_LINE
     470      2816532 :          esn_final , & ! final energy (J/m^2)   ! LCOV_EXCL_LINE
     471      2816532 :          atmp      , & ! temporary variable for ain, for debugging convenience   ! LCOV_EXCL_LINE
     472      2816532 :          hin       , & ! ice thickness (m)   ! LCOV_EXCL_LINE
     473      2816532 :          hsn       , & ! snow depth (m)   ! LCOV_EXCL_LINE
     474      2816532 :          hsn_new       ! new snow depth (m)
     475              : 
     476              :       real (kind=dbl_kind), dimension (nslyr) :: &
     477      2816532 :          dzs             ! snow layer thickness after redistribution (m)
     478              : 
     479              :       real (kind=dbl_kind), dimension (nslyr+1) :: &
     480      2816532 :          zs1         , & ! depth of snow layer boundaries (m)   ! LCOV_EXCL_LINE
     481      1408266 :          zs2             ! adjusted depths, with equal hslyr (m)
     482              : 
     483              :       character (len=*),parameter :: subname='(snow_redist)'
     484              : 
     485              :       !-----------------------------------------------------------------
     486              :       ! Conservation checks
     487              :       !-----------------------------------------------------------------
     488              : 
     489      1408266 :       tmp1 = c0
     490      1408266 :       tmp3 = c0
     491      8449596 :       do n = 1, ncat
     492              :          ! mass conservation check
     493      7041330 :          tmp1 = tmp1 + vsn(n)
     494      7041330 :          vsn_init(n) = vsn(n)
     495      7041330 :          esn_init(n) = c0
     496              :          ! energy conservation check
     497     43656246 :          do k = 1, nslyr
     498     35206650 :             tmp3 = tmp3 + vsn(n)*zqsn(k,n)/nslyr
     499     42247980 :             esn_init(n) = esn_init(n) + vsn(n)*zqsn(k,n)/nslyr
     500              :          enddo
     501              :       enddo
     502              : 
     503              :       !-----------------------------------------------------------------
     504              :       ! category thickness and sums
     505              :       !-----------------------------------------------------------------
     506              : 
     507      8449596 :       hin(:) = c0
     508      8449596 :       hsn(:) = c0
     509      1408266 :       suma = c0
     510      1408266 :       sumv = c0
     511      8449596 :       do n = 1, ncat
     512      7041330 :          atmp(n) = ain(n)
     513      7041330 :          if (atmp(n) > puny) then
     514      6841157 :             hin(n) = vin(n)/atmp(n)
     515      6841157 :             hsn(n) = vsn(n)/atmp(n)
     516              :          endif
     517      7041330 :          hsn_new(n) = hsn(n)
     518      7041330 :          suma = suma + atmp(n)
     519      7041330 :          sumv = sumv + vin(n)
     520              :          ! maintain positive definite enthalpy
     521     43656246 :          do k = 1, nslyr
     522     42247980 :             zqsn(k,n) = min(zqsn(k,n) + Lfresh*rhos, c0)
     523              :          enddo
     524              :       enddo ! ncat
     525              : 
     526              :       !-----------------------------------------------------------------
     527              :       ! standard deviation of ice thickness distribution
     528              :       !-----------------------------------------------------------------
     529              : 
     530      1408266 :       work = c0
     531      1408266 :       asnw_lvl = c0
     532      1408266 :       if (trim(snwredist) == 'ITDrdg') then  ! use level and ridged ice
     533      8449596 :          do n = 1, ncat
     534      7041330 :             ardg(n) = c1 - alvl(n) ! ridged ice tracer
     535      7041330 :             al = alvl(n) * atmp(n) ! level
     536      7041330 :             ar = ardg(n) * atmp(n) ! ridged
     537      7041330 :             hlvl = c0
     538      7041330 :             hrdg = c0
     539      7041330 :             if (al > puny) hlvl = vin(n)*vlvl(n)/al
     540      7041330 :             if (ar > puny) hrdg = vin(n)*(c1-vlvl(n))/ar
     541      7041330 :             work = work + al*(hlvl - sumv)**2 + ar*(hrdg - sumv)**2
     542              : 
     543              :             ! for redeposition of snow on level ice
     544      7041330 :             sfac(n) = snwlvlfac
     545      7041330 :             if (ardg(n) > c0) sfac(n) = min(snwlvlfac, alvl(n)/ardg(n))
     546      8449596 :             asnw_lvl = asnw_lvl + al - sfac(n)*ar
     547              :          enddo
     548      1408266 :          asnw_lvl = asnw_lvl/suma
     549              : !      else ! snwredist = 'ITDsd'             ! use standard ITD
     550              : !         do n = 1, ncat
     551              : !            work = work + atmp(n)*(hin(n) - sumv)**2
     552              : !         enddo
     553              :       endif
     554      1408266 :       ITDsd = sqrt(work)
     555              : 
     556              :       !-----------------------------------------------------------------
     557              :       ! fraction of suspended snow lost in leads
     558              :       !-----------------------------------------------------------------
     559              : 
     560      1408266 :       flost = (c1 - suma) * exp(-ITDsd/refsd)
     561              : !      flost = c0 ! echmod for testing
     562      1408266 :       alost =  c1 - suma  * (c1-flost)
     563              : 
     564              :       !-----------------------------------------------------------------
     565              :       ! suspended snow
     566              :       !-----------------------------------------------------------------
     567              : 
     568      1408266 :       msusp = c0
     569      8449596 :       do n = 1, ncat
     570              :          ! critical seasonal wind speed needed to compact snow to density rhos
     571      7041330 :          Vseas = (rhos_cmpn(1,n) - 44.6_dbl_kind)/174.0_dbl_kind ! use top layer
     572      7041330 :          Vseas = max(Vseas, c0)
     573              :          ! maximum mass per unit area of snow in suspension (kg/m^2)
     574      7041330 :          if (ITDsd > puny) &
     575              :             msusp = msusp + atmp(n)*gamma*dt*max(wind-Vseas,c0) &   ! LCOV_EXCL_LINE
     576      8447086 :                   * (rhosmax-rhos_cmpn(1,n))/(rhosmax*ITDsd)
     577              :       enddo
     578              : 
     579              :       !-----------------------------------------------------------------
     580              :       ! erosion
     581              :       !-----------------------------------------------------------------
     582              : 
     583      1408266 :       msnw_susp = c0
     584      1408266 :       esnw_susp = c0
     585      8449596 :       klyr(:) = 1
     586      8449596 :       do n = 1, ncat
     587      7041330 :          m_erosion(n) = c0                             ! mass
     588      7041330 :          e_erosion(n) = c0                             ! energy
     589      8449596 :          if (atmp(n) > puny) then
     590      6841157 :             m_erosion(n) = min(msusp, rhos*vsn(n))
     591      6841157 :             if (m_erosion(n) > puny) then
     592      6078402 :                summ = c0
     593      6078402 :                dmp = m_erosion(n)
     594     36470412 :                do k = 1, nslyr
     595     36470412 :                   if (dmp > c0) then
     596     14592069 :                      dhsn = min(hsn(n)/nslyr, dmp/(rhos*atmp(n)))
     597     14592069 :                      msnw_susp  = msnw_susp  + dhsn*rhos*atmp(n) ! total mass in suspension
     598     14592069 :                      hsn_new(n) = hsn_new(n) - dhsn
     599     14592069 :                      e_erosion(n) = e_erosion(n) + dhsn*zqsn(k,n)*atmp(n)
     600     14592069 :                      klyr(n) = k                        ! number of affected layers
     601     14592069 :                      summ = summ + rhos*vsn(n)/nslyr    ! mass, partial sum
     602     14592069 :                      dmp = max(m_erosion(n) - summ, c0)
     603              :                   endif ! dmp
     604              :                enddo
     605      6078402 :                esnw_susp = esnw_susp + e_erosion(n)     ! total energy in suspension
     606              :             endif
     607              :          endif
     608              :       enddo
     609              : 
     610              :       !-----------------------------------------------------------------
     611              :       ! redeposition
     612              :       !-----------------------------------------------------------------
     613              : 
     614      8449596 :       do n = 1, ncat
     615      7041330 :          if (trim(snwredist) == 'ITDrdg') then  ! use level and ridged ice
     616      7041330 :             work = atmp(n)*(c1-flost)*(ardg(n)*(c1+sfac(n)) + asnw_lvl)
     617              :          else                                   ! use standard ITD
     618            0 :             work = atmp(n)*(c1-flost)
     619              :          endif
     620      7041330 :          m_redep(n) = msnw_susp*work    ! mass
     621      7041330 :          e_redep(n) = c0
     622      7041330 :          e_redeptmp = esnw_susp*work    ! energy
     623              : 
     624              :          ! change in snow depth
     625      7041330 :          dhsn = c0
     626      7041330 :          if (atmp(n) > puny) then
     627      6841157 :             dhsn = m_redep(n) / (rhos*atmp(n))
     628              : 
     629      6841157 :             if (abs(dhsn) > c0) then
     630              : 
     631      6194092 :                e_redep(n) = e_redeptmp
     632      6194092 :                vsn(n) = (hsn_new(n)+dhsn)*atmp(n)
     633              : 
     634              :                ! change in snow energy
     635      6194092 :                de = e_redeptmp / klyr(n)
     636              :                ! spread among affected layers
     637      6194092 :                sumq = c0
     638     20901851 :                do k = 1, klyr(n)
     639              :                   zqsn(k,n) = (atmp(n)*hsn_new(n)*zqsn(k,n) + de) &
     640     14707759 :                             / (vsn(n))  ! factor of nslyr cancels out
     641              : 
     642     20901851 :                   if (zqsn(k,n) > c0) then
     643           45 :                      sumq = sumq + zqsn(k,n)
     644           45 :                      zqsn(k,n) = c0
     645              :                   endif
     646              : 
     647              :                enddo ! klyr
     648      6194092 :                zqsn(klyr(n),n) = min(zqsn(klyr(n),n) + sumq, c0) ! may lose energy here
     649              : 
     650              :       !-----------------------------------------------------------------
     651              :       ! Conserving energy, compute the enthalpy of the new equal layers
     652              :       !-----------------------------------------------------------------
     653              : 
     654      6194092 :                if (nslyr > 1) then
     655              : 
     656     37164552 :                   dzs(:) = hsn(n) / real(nslyr,kind=dbl_kind) ! old layer thickness
     657     20901851 :                   do k = 1, klyr(n)
     658     20901851 :                      dzs(k) = dzs(k) + dhsn / klyr(n)         ! old layer thickness (updated)
     659              :                   enddo
     660      6194092 :                   hsn_new(n) = hsn_new(n) + dhsn
     661      6194092 :                   hslyr  = hsn_new(n) / real(nslyr,kind=dbl_kind) ! new layer thickness
     662              : 
     663      6194092 :                   zs1(1) = c0
     664      6194092 :                   zs1(1+nslyr) = hsn_new(n)
     665              : 
     666      6194092 :                   zs2(1) = c0
     667      6194092 :                   zs2(1+nslyr) = hsn_new(n)
     668              : 
     669     30970460 :                   do k = 1, nslyr-1
     670     24776368 :                      zs1(k+1) = zs1(k) + dzs(k) ! old layer depths (unequal thickness)
     671     30970460 :                      zs2(k+1) = zs2(k) + hslyr  ! new layer depths (equal thickness)
     672              :                   enddo
     673              : 
     674              :                   call adjust_enthalpy (nslyr,              &
     675              :                                         zs1(:), zs2(:),     &   ! LCOV_EXCL_LINE
     676              :                                         hslyr , hsn_new(n), &   ! LCOV_EXCL_LINE
     677      6194092 :                                         zqsn(:,n))
     678      6194092 :                   if (icepack_warnings_aborted(subname)) return
     679              :                else
     680            0 :                   hsn_new(n) = hsn_new(n) + dhsn
     681              :                endif   ! nslyr > 1
     682              :             endif      ! |dhsn| > puny
     683              :          endif         ! ain > puny
     684              : 
     685              :          ! maintain positive definite enthalpy
     686     43656246 :          do k = 1, nslyr
     687     42247980 :             zqsn(k,n) = zqsn(k,n) - Lfresh*rhos
     688              :          enddo
     689              :       enddo ! ncat
     690              : 
     691              :       !-----------------------------------------------------------------
     692              :       ! mass of suspended snow lost in leads
     693              :       !-----------------------------------------------------------------
     694      1408266 :       mlost = msnw_susp*alost
     695      1408266 :       fsloss = fsloss + mlost / dt
     696              : 
     697              :       !-----------------------------------------------------------------
     698              :       ! mass conservation check
     699              :       !-----------------------------------------------------------------
     700              : 
     701      1408266 :       tmp2 = c0
     702      8449596 :       do n = 1, ncat
     703      8449596 :          tmp2 = tmp2 + vsn(n)
     704              :       enddo
     705              : 
     706      1408266 :       if (tmp2 > tmp1) then  ! correct roundoff error
     707        21192 :          vsn(:) = vsn(:) * tmp1/tmp2
     708         3532 :          tmp2 = c0
     709        21192 :          do n = 1, ncat
     710        21192 :             tmp2 = tmp2 + vsn(n)
     711              :          enddo
     712              :       endif
     713              : 
     714      1408266 :       if (tmp2 < tmp1) fresh = fresh + rhos*(tmp1-tmp2)/dt
     715              : 
     716      1408266 :       tmp2 = tmp2 + (mlost/rhos)
     717              : 
     718      1408266 :       if (abs(tmp1-tmp2) > puny) then
     719            0 :          call icepack_warnings_setabort(.true.,__FILE__,__LINE__)
     720            0 :          call icepack_warnings_add(subname//'ERROR: snow redistribution mass conservation error')
     721              : !         write(warning,*)'mass conservation error in snow_redist', tmp1, tmp2
     722              : !         write(warning,*)'klyr',klyr
     723              : !         write(warning,*)'ain',atmp(:)
     724              : !         write(warning,*)'vsn final',vsn(:)
     725              : !         write(warning,*)'vsn init',vsn_init(:)
     726              : !         write(warning,*)'rhos*vsn init',rhos*vsn_init(:)
     727              : !         write(warning,*)'m_erosion',m_erosion(:)
     728              : !         write(warning,*)'m_redep',m_redep(:)
     729              : !         write(warning,*)'mlost',mlost
     730              : !         write(warning,*)'v_erosion',m_erosion(:)/rhos
     731              : !         write(warning,*)'v_redep',m_redep(:)/rhos
     732              : !         write(warning,*)'v lost',mlost/rhos
     733              : !         write(warning,*)'hsn',hsn(:)
     734              : !         write(warning,*)'hsn_new',hsn_new(:)
     735              : !         write(warning,*)'vsn_new',hsn_new(:)*atmp(:)
     736              : !         write(warning,*)'lost',suma,flost,alost,msnw_susp
     737              :       endif
     738              : 
     739              :       !-----------------------------------------------------------------
     740              :       ! energy conservation check
     741              :       !-----------------------------------------------------------------
     742              : 
     743      1408266 :       tmp4 = c0
     744      1408266 :       tmp5 = c0
     745      8449596 :       esn_final(:) = c0
     746      8449596 :       do n = 1, ncat
     747     42247980 :          do k = 1, nslyr
     748     35206650 :             tmp4 = tmp4 + vsn(n)*zqsn(k,n)/nslyr
     749     42247980 :             esn_final(n) = esn_final(n) + vsn(n)*zqsn(k,n)/nslyr
     750              :          enddo
     751      8449596 :          tmp5 = tmp5 - e_erosion(n) + e_redep(n)
     752              :       enddo
     753      1408266 :       tmp5 = tmp5 + esnw_susp*alost
     754              : 
     755              :       !-----------------------------------------------------------------
     756              :       ! energy of suspended snow lost in leads
     757              :       !-----------------------------------------------------------------
     758      1408266 :       elost = tmp3 - tmp4
     759      1408266 :       fhocn = fhocn + elost / dt
     760              : 
     761      1408266 :       if (abs(tmp5) > nslyr*Lfresh*puny) then
     762            0 :          call icepack_warnings_setabort(.true.,__FILE__,__LINE__)
     763            0 :          call icepack_warnings_add(subname//'ERROR: snow redistribution energy conservation error')
     764              : !         write(warning,*)'energy conservation error in snow_redist', tmp3, tmp4, tmp5
     765              : !         write(warning,*)'klyr',klyr
     766              : !         write(warning,*)'ain',atmp(:)
     767              : !         write(warning,*)'vsn final',vsn(:)
     768              : !         write(warning,*)'vsn init',vsn_init(:)
     769              : !         write(warning,*)'rhos*vsn init',rhos*vsn_init(:)
     770              : !         write(warning,*)'m_erosion',m_erosion(:)
     771              : !         write(warning,*)'m_redep',m_redep(:)
     772              : !         write(warning,*)'mlost',mlost
     773              : !         write(warning,*)'v_erosion',m_erosion(:)/rhos
     774              : !         write(warning,*)'v_redep',m_redep(:)/rhos
     775              : !         write(warning,*)'v lost',mlost/rhos
     776              : !         write(warning,*)'hsn',hsn(:)
     777              : !         write(warning,*)'hsn_new',hsn_new(:)
     778              : !         write(warning,*)'vsn_new',hsn_new(:)*atmp(:)
     779              : !         write(warning,*)'lost',suma,flost,alost,msnw_susp
     780              : !         write(warning,*)'tmp3(1)', (vsn(1)*zqsn(k,1)/nslyr,k=1,nslyr)
     781              : !         write(warning,*)'esn init',esn_init(:)
     782              : !         write(warning,*)'esn final',esn_final(:)
     783              : !         write(warning,*)'e_erosion',e_erosion(:)
     784              : !         write(warning,*)'e_redep',e_redep(:)
     785              : !         write(warning,*)'elost',elost,esnw_susp*alost,Lfresh*mlost
     786              : !         write(warning,*)'esnw_susp',esnw_susp
     787              :       endif
     788              : 
     789              :       !-----------------------------------------------------------------
     790              :       ! wind compaction
     791              :       !-----------------------------------------------------------------
     792              : 
     793      8449596 :       do n = 1, ncat
     794      8449596 :          if (vsn(n) > puny) then
     795              :             ! compact freshly fallen or redistributed snow
     796      5883527 :             drhos = drhosdwind * max(wind - windmin, c0)
     797      5883527 :             hslab = c0
     798      5883527 :             if (fsnow > c0) &
     799      3555907 :                hslab = max(min(fsnow*dt/(rhos+drhos), hsn_new(n)-hsn(n)), c0)
     800      5883527 :             hslyr = hsn_new(n) / real(nslyr,kind=dbl_kind)
     801     35301162 :             do k = 1, nslyr
     802     29417635 :                work = hslab - hslyr * real(k-1,kind=dbl_kind)
     803     29417635 :                work = max(c0, min(hslyr, work))
     804     29417635 :                rhos_cmpn(k,n) = rhos_cmpn(k,n) + drhos*work/hslyr
     805     35301162 :                rhos_cmpn(k,n) = min(rhos_cmpn(k,n), rhosmax)
     806              :             enddo
     807              :          endif
     808              :       enddo
     809              : 
     810              :       end subroutine snow_redist
     811              : 
     812              : !=======================================================================
     813              : 
     814              : !  Snow grain metamorphism
     815              : 
     816     75306240 :       subroutine update_snow_radius (dt, rsnw, hin, &
     817     75306240 :                                      Tsfc, zTin, hsn, zqsn, smice, smliq)
     818              : 
     819              :       real (kind=dbl_kind), intent(in) :: &
     820              :          dt           ! time step
     821              : 
     822              :       real (kind=dbl_kind), dimension(ncat), intent(in) :: &
     823              :          zTin     , & ! surface ice temperature (oC)   ! LCOV_EXCL_LINE
     824              :          Tsfc     , & ! surface temperature (oC)   ! LCOV_EXCL_LINE
     825              :          hin      , & ! ice thickness (m)   ! LCOV_EXCL_LINE
     826              :          hsn          ! snow thickness (m)
     827              : 
     828              :       real (kind=dbl_kind), dimension(nslyr,ncat), intent(in) :: &
     829              :          zqsn         ! enthalpy of snow (J m-3)
     830              : 
     831              :       real (kind=dbl_kind), dimension(nslyr,ncat), intent(inout) :: &
     832              :          rsnw         ! snow grain radius
     833              : 
     834              :       real (kind=dbl_kind), dimension(nslyr,ncat), intent(inout) :: &
     835              :          smice    , & ! tracer for mass of ice in snow (kg/m^3)   ! LCOV_EXCL_LINE
     836              :          smliq        ! tracer for mass of liquid in snow (kg/m^3)
     837              : 
     838              :       ! local temporary variables
     839              : 
     840              :       integer (kind=int_kind) :: k, n
     841              : 
     842              :       real (kind=dbl_kind), dimension(nslyr) :: &
     843    150612480 :          drsnw_wet, & ! wet metamorphism (10^-6 m)   ! LCOV_EXCL_LINE
     844     75306240 :          drsnw_dry    ! dry (temperature gradient) metamorphism (10^-6 m)
     845              : 
     846              :       character (len=*),parameter :: subname='(update_snow_radius)'
     847              : 
     848    451837440 :       do n = 1, ncat
     849              : 
     850    451837440 :          if (hsn(n) > puny .and. hin(n) > puny) then
     851              : 
     852    186470610 :             drsnw_dry(:) = c0
     853    186470610 :             drsnw_wet(:) = c0
     854              : 
     855              :       !-----------------------------------------------------------------
     856              :       ! dry metamorphism
     857              :       !-----------------------------------------------------------------
     858              :             call snow_dry_metamorph (dt, rsnw(:,n), &
     859              :                                      drsnw_dry, zqsn(:,n), Tsfc(n), &   ! LCOV_EXCL_LINE
     860     31078435 :                                      zTin(n), hsn(n), hin(n))
     861     31078435 :             if (icepack_warnings_aborted(subname)) return
     862              : 
     863              :       !-----------------------------------------------------------------
     864              :       ! wet metamorphism
     865              :       !-----------------------------------------------------------------
     866    186470610 :             do k = 1,nslyr
     867              :                call snow_wet_metamorph (dt, drsnw_wet(k), rsnw(k,n), &
     868    155392175 :                                         smice(k,n), smliq(k,n))
     869    155392175 :                if (icepack_warnings_aborted(subname)) return
     870    186470610 :                rsnw(k,n) = min(rsnw_tmax, rsnw(k,n) + drsnw_dry(k) + drsnw_wet(k))
     871              :             enddo
     872              : 
     873              :          else ! hsn or hin < puny
     874   2072716590 :             do k = 1,nslyr
     875              :                ! rsnw_fall < rsnw < rsnw_tmax
     876   1727263825 :                rsnw (k,n) = max(rsnw_fall, min(rsnw_tmax, rsnw(k,n)))
     877   1727263825 :                smice(k,n) = rhos
     878   2072716590 :                smliq(k,n) = c0
     879              :             enddo
     880              :          endif ! hsn, hin
     881              :       enddo
     882              : 
     883              :       end subroutine update_snow_radius
     884              : 
     885              : !=======================================================================
     886              : 
     887              : !  Snow grain metamorphism
     888              : 
     889     31078435 :       subroutine snow_dry_metamorph (dt, rsnw, drsnw_dry, zqsn, &
     890              :                                      Tsfc, zTin1, hsn, hin)
     891              : 
     892              :       ! Vapor redistribution: Method is to retrieve 3 best-fit parameters that
     893              :       ! depend on snow temperature, temperature gradient, and density,
     894              :       ! that are derived from the microphysical model described in:
     895              :       ! Flanner and Zender (2006), Linking snowpack microphysics and albedo
     896              :       ! evolution, J. Geophys. Res., 111, D12208, doi:10.1029/2005JD006834.
     897              :       ! The parametric equation has the form:
     898              :       ! dr/dt = drdt_0*(tau/(dr_fresh+tau))^(1/kappa), where:
     899              :       !   r is the effective radius,
     900              :       !   tau and kappa are best-fit parameters,
     901              :       !   drdt_0 is the initial rate of change of effective radius, and
     902              :       !   dr_fresh is the difference between the current and fresh snow states
     903              :       !   (r_current - r_fresh).
     904              : 
     905              :       real (kind=dbl_kind), intent(in) :: &
     906              :          dt                    ! time step (s)
     907              : 
     908              :       real (kind=dbl_kind), dimension(nslyr), intent(in) :: &
     909              :          rsnw,   & ! snow grain radius (10^-6 m)   ! LCOV_EXCL_LINE
     910              :          zqsn      ! snow enthalpy  (J m-3)
     911              : 
     912              :       real (kind=dbl_kind), dimension(nslyr), intent(inout) :: &
     913              :          drsnw_dry ! change due to snow aging (10^-6 m)
     914              : 
     915              :       real (kind=dbl_kind), intent(in) :: &
     916              :          Tsfc,   & ! surface temperature (C)   ! LCOV_EXCL_LINE
     917              :          zTin1,  & ! top ice layer temperature (C)   ! LCOV_EXCL_LINE
     918              :          hsn,    & ! snow thickness (m)   ! LCOV_EXCL_LINE
     919              :          hin       ! ice thickness (m)
     920              : 
     921              :       ! local temporary variables
     922              : 
     923              :       integer (kind=int_kind) :: k
     924              : 
     925              :       integer (kind=int_kind) :: &
     926              :          T_idx,    & ! temperature index   ! LCOV_EXCL_LINE
     927              :          Tgrd_idx, & ! temperature gradient index   ! LCOV_EXCL_LINE
     928              :          rhos_idx    ! density index
     929              : 
     930              :       real (kind=dbl_kind), dimension(nslyr):: &
     931     93235305 :          zdTdz,   & ! temperature gradient (K/s)   ! LCOV_EXCL_LINE
     932     31078435 :          zTsn       ! snow temperature (C)
     933              : 
     934              :       real (kind=dbl_kind) :: &
     935              :          bst_tau,   & ! snow aging parameter retrieved from lookup table [hour]   ! LCOV_EXCL_LINE
     936              :          bst_kappa, & ! snow aging parameter retrieved from lookup table [unitless]   ! LCOV_EXCL_LINE
     937              :          bst_drdt0, & ! snow aging parameter retrieved from lookup table [um hr-1]   ! LCOV_EXCL_LINE
     938              :          dr_fresh,  & ! change in snow radius from fresh (10^-6 m)   ! LCOV_EXCL_LINE
     939              :          dzs,       & ! snow layer thickness (m)   ! LCOV_EXCL_LINE
     940              :          dzi,       & ! ice layer thickness (m)   ! LCOV_EXCL_LINE
     941              :          dz           ! dzs + dzi (m)
     942              : 
     943              :       logical (kind=log_kind), save :: &
     944              :          first_call = .true.   ! first call flag
     945              : 
     946              :       character (char_len) :: &
     947              :          string                ! generic string for writing messages
     948              : 
     949              :       character (len=*),parameter :: subname='(snow_dry_metamorph)'
     950              : 
     951              :       !-----------------------------------------------------------------
     952              :       ! On the first call, check that the table is setup properly
     953              :       ! Check sizes of 1D and 3D data
     954              :       ! Check that the 1D data is regularly spaced and set min, del, and lin values
     955              :       ! for each 1D variable.  This info will be used later for the table lookup.
     956              :       !-----------------------------------------------------------------
     957              : 
     958     31078435 :       if (first_call) then
     959              :          if (isnw_rhos < 1 .or. isnw_Tgrd < 1 .or. isnw_T < 1 .or. &
     960              :              size(snowage_rhos)  /= isnw_rhos .or. &   ! LCOV_EXCL_LINE
     961              :              size(snowage_Tgrd)  /= isnw_Tgrd .or. &   ! LCOV_EXCL_LINE
     962              :              size(snowage_T)     /= isnw_T    .or. &   ! LCOV_EXCL_LINE
     963              :              size(snowage_tau)   /= isnw_rhos*isnw_Tgrd*isnw_T .or. &   ! LCOV_EXCL_LINE
     964         2790 :              size(snowage_kappa) /= isnw_rhos*isnw_Tgrd*isnw_T .or. &   ! LCOV_EXCL_LINE
     965              :              size(snowage_drdt0) /= isnw_rhos*isnw_Tgrd*isnw_T) then
     966            0 :             write(string,'(a,3i4)') subname//' snowtable size1 = ',isnw_rhos, isnw_Tgrd, isnw_T
     967            0 :             call icepack_warnings_add(string)
     968            0 :             write(string,'(a,3i4)') subname//' snowtable size2 = ',size(snowage_rhos),size(snowage_Tgrd),size(snowage_T)
     969            0 :             call icepack_warnings_add(string)
     970            0 :             write(string,'(a,3i9)') subname//' snowtable size3 = ',size(snowage_tau),size(snowage_kappa),size(snowage_drdt0)
     971            0 :             call icepack_warnings_add(string)
     972            0 :             call icepack_warnings_setabort(.true.,__FILE__,__LINE__)
     973            0 :             call icepack_warnings_add(subname//'ERROR: arrays sizes error')
     974            0 :             return
     975              :          endif
     976          279 :          call snowtable_check_dimension(snowage_rhos, min_rhos, del_rhos, lin_rhos)
     977          279 :          if (icepack_warnings_aborted(subname)) return
     978          279 :          call snowtable_check_dimension(snowage_Tgrd, min_Tgrd, del_Tgrd, lin_Tgrd)
     979          279 :          if (icepack_warnings_aborted(subname)) return
     980          279 :          call snowtable_check_dimension(snowage_T   , min_T   , del_T   , lin_T   )
     981          279 :          if (icepack_warnings_aborted(subname)) return
     982              :       endif
     983              : 
     984              :       !-----------------------------------------------------------------
     985              :       ! Needed for variable snow density not currently modeled
     986              :       ! calculate density based on liquid and ice content of snow
     987              :       !-----------------------------------------------------------------
     988              : 
     989    186470610 :       drsnw_dry(:) = c0
     990    186470610 :       zTsn(:) = c0
     991    186470610 :       zdTdz(:) = c0
     992              : 
     993     31078435 :       dzs = hsn/real(nslyr,kind=dbl_kind)
     994     31078435 :       dzi = hin/real(nilyr,kind=dbl_kind)
     995     31078435 :       dz  = dzs + dzi
     996              : 
     997     31078435 :       zTsn(1)  = (Lfresh + zqsn(1)/rhos)/cp_ice
     998     31078435 :       if (nslyr == 1) then
     999              :          zdTdz(1) = min(c10*isnw_Tgrd, &
    1000              : !ech refactored            abs((zTsn(1)*dzi+zTin1*dzs)/(dzs+dzi+puny) - Tsfc)/(hsn+puny))
    1001            0 :             abs(zTsn(1)*dzi + zTin1*dzs - Tsfc*dz)/(dz*hsn+puny))
    1002              :       else
    1003    155392175 :          do k = 2, nslyr
    1004    124313740 :             zTsn(k) = (Lfresh + zqsn(k)/rhos)/cp_ice
    1005    124313740 :             if (k == 2) then
    1006     31078435 :                zdTdz(k-1) = abs((zTsn(k-1)+zTsn(k))*p5 - Tsfc)/(dzs+puny)
    1007              :             else
    1008     93235305 :                zdTdz(k-1) = abs (zTsn(k-2)-zTsn(k))*p5        /(dzs+puny)
    1009              :             endif
    1010    155392175 :             zdTdz(k-1) = min(c10*isnw_Tgrd,zdTdz(k-1))
    1011              :          enddo
    1012              : !ech refactored         zdTdz(nslyr) = abs((zTsn(nslyr)*dzi + zTin1*dzs)/(dzs + dzi+puny) &
    1013              : !ech refactored                          - (zTsn(nslyr) + zTsn(nslyr-1))*p5) / (dzs+puny)
    1014              :          zdTdz(nslyr) = abs((zTsn(nslyr)*dzi + zTin1*dzs) &
    1015     31078435 :                           - (zTsn(nslyr) + zTsn(nslyr-1))*p5*dz) / (dz*dzs+puny)
    1016     31078435 :          zdTdz(nslyr) = min(c10*isnw_Tgrd, zdTdz(nslyr))
    1017              :       endif
    1018              : 
    1019    186470610 :       do k = 1, nslyr
    1020              : 
    1021              :          !-----------------------------------------------------------------
    1022              :          ! best-fit table indices:
    1023              :          ! Will abort if 1D data is not regularly spaced (lin_* flag must be true)
    1024              :          ! Leave option for doing a search into non regularly spaced 1D data in the future
    1025              :          ! via a binary search or similar.
    1026              :          !-----------------------------------------------------------------
    1027              : 
    1028    155392175 :          if (lin_rhos) then
    1029    155392175 :             rhos_idx = nint(   (rhos             - min_rhos) / del_rhos, kind=int_kind) + 1
    1030              :          else
    1031            0 :             call icepack_warnings_setabort(.true.,__FILE__,__LINE__)
    1032            0 :             call icepack_warnings_add(subname//'ERROR: nonlinear lookup table for rhos not supported yet')
    1033            0 :             return
    1034              :          endif
    1035              : 
    1036    155392175 :          if (lin_Tgrd) then
    1037    155392175 :             Tgrd_idx = nint(   (zdTdz(k)         - min_Tgrd) / del_Tgrd, kind=int_kind) + 1
    1038              :          else
    1039            0 :             call icepack_warnings_setabort(.true.,__FILE__,__LINE__)
    1040            0 :             call icepack_warnings_add(subname//'ERROR: nonlinear lookup table for Tgrd not supported yet')
    1041            0 :             return
    1042              :          endif
    1043              : 
    1044    155392175 :          if (lin_T) then
    1045    155392175 :             T_idx    = nint(abs(zTsn(k)+ Tffresh - min_T   ) / del_T   , kind=int_kind) + 1
    1046              :          else
    1047            0 :             call icepack_warnings_setabort(.true.,__FILE__,__LINE__)
    1048            0 :             call icepack_warnings_add(subname//'ERROR: nonlinear lookup table for T not supported yet')
    1049            0 :             return
    1050              :          endif
    1051              : 
    1052              :          ! boundary check:
    1053    155392175 :          rhos_idx = min(isnw_rhos, max(1,rhos_idx))
    1054    155392175 :          Tgrd_idx = min(isnw_Tgrd, max(1,Tgrd_idx))
    1055    155392175 :          T_idx    = min(isnw_T   , max(1,T_idx   ))
    1056              : 
    1057    155392175 :          bst_tau   = snowage_tau  (rhos_idx,Tgrd_idx,T_idx)
    1058    155392175 :          bst_kappa = snowage_kappa(rhos_idx,Tgrd_idx,T_idx)
    1059    155392175 :          bst_drdt0 = snowage_drdt0(rhos_idx,Tgrd_idx,T_idx)
    1060              : 
    1061              :          ! change in snow effective radius, using best-fit parameters
    1062    155392175 :          dr_fresh = max(c0,rsnw(k)-rsnw_fall)
    1063              :          drsnw_dry(k) = (bst_drdt0*(bst_tau/(dr_fresh+bst_tau))**(1/bst_kappa))&
    1064    186470610 :                       * (dt/3600.0_dbl_kind)
    1065              :       enddo
    1066              : 
    1067     31078435 :       first_call = .false.
    1068              : 
    1069              :       end subroutine snow_dry_metamorph
    1070              : 
    1071              : !=======================================================================
    1072              : 
    1073              : !  Snow grain metamorphism
    1074              : 
    1075    155392175 :       subroutine snow_wet_metamorph (dt, dr_wet, rsnw, smice, smliq)
    1076              :     !
    1077              :     ! Liquid water redistribution: Apply the grain growth function from:
    1078              :     !   Brun, E. (1989), Investigation of wet-snow metamorphism in respect of
    1079              :     !   liquid-water content, Annals of Glaciology, 13, 22-26.
    1080              :     !   There are two parameters that describe the grain growth rate as
    1081              :     !   a function of snow liquid water content (LWC). The "LWC=0" parameter
    1082              :     !   is zeroed here because we are accounting for dry snowing with a
    1083              :     !   different representation
    1084              :     !
    1085              :       real (kind=dbl_kind), intent(in) :: &
    1086              :          dt                    ! time step
    1087              : 
    1088              :       real (kind=dbl_kind), intent(in) :: &
    1089              :          rsnw , & ! snow grain radius (10^-6 m)   ! LCOV_EXCL_LINE
    1090              :          smice, & ! snow ice density (kg/m^3)   ! LCOV_EXCL_LINE
    1091              :          smliq    ! snow liquid density (kg/m^3)
    1092              : 
    1093              :       real (kind=dbl_kind), intent(inout) :: &
    1094              :          dr_wet
    1095              : 
    1096              :       real (kind=dbl_kind) :: &
    1097              :          fliq  ! liquid mass fraction
    1098              : 
    1099              :       character (len=*),parameter :: subname='(snow_wet_metamorph)'
    1100              : 
    1101    155392175 :       dr_wet = c0
    1102    155392175 :       fliq = c1
    1103    155392175 :       if (smice + smliq > c0 .and. rsnw > c0) then
    1104    155392175 :          fliq = min(smliq/(smice + smliq),p1)
    1105    155392175 :          dr_wet = S_wet * fliq**3*dt/(c4*pi*rsnw**2)
    1106              :       endif
    1107              : 
    1108    155392175 :       end subroutine snow_wet_metamorph
    1109              : 
    1110              : !=======================================================================
    1111              : 
    1112              : !  Analyze 1D array for regular spacing for snow table lookup
    1113              : !  and set the min, del, and lin values.
    1114              : !  Tolerance for regular spacing set at 1.0e-8 * typical array value
    1115              : 
    1116          837 :       subroutine snowtable_check_dimension(array, min_fld, del_fld, lin_fld)
    1117              : 
    1118              :       real (kind=dbl_kind), intent(in), dimension(:) :: &
    1119              :          array      ! array to check
    1120              : 
    1121              :       real (kind=dbl_kind), intent(inout) :: &
    1122              :          min_fld, & ! min value if linear   ! LCOV_EXCL_LINE
    1123              :          del_fld    ! delta value if linear
    1124              : 
    1125              :       logical (kind=log_kind), intent(inout) :: &
    1126              :          lin_fld    ! linear flag
    1127              : 
    1128              :       ! local temporary variables
    1129              : 
    1130              :       integer (kind=int_kind) :: n, asize
    1131              : 
    1132              :       real (kind=dbl_kind) :: tolerance   ! tolerance for linear checking
    1133              : 
    1134              :       character (len=*),parameter :: subname='(snowtable_check_dimension)'
    1135              : 
    1136          837 :       asize = size(array)
    1137              : 
    1138          837 :       if (asize == 1) then
    1139            0 :          min_fld = array(1)
    1140            0 :          del_fld = array(1)  ! arbitrary
    1141            0 :          lin_fld = .true.
    1142              :       else
    1143          837 :          lin_fld = .true.
    1144          837 :          min_fld = array(1)
    1145          837 :          del_fld = array(2) - array(1)
    1146          837 :          tolerance = 1.0e-08_dbl_kind * max(abs(array(1)),abs(array(2)))  ! relative to typical value
    1147        13113 :          do n = 3,asize
    1148        13113 :             if (abs(array(n) - array(n-1) - del_fld) > tolerance) lin_fld = .false.
    1149              :          enddo
    1150              :       endif
    1151              : 
    1152          837 :       end subroutine snowtable_check_dimension
    1153              : 
    1154              : !=======================================================================
    1155              : 
    1156              : !  Conversions between ice mass, liquid water mass in snow
    1157              : 
    1158    263998560 :       subroutine drain_snow (vsnon, aicen, &
    1159    263998560 :                              massice, massliq, meltsliq)
    1160              : 
    1161              :       real (kind=dbl_kind), intent(in) :: &
    1162              :          vsnon,  & ! snow volume (m)   ! LCOV_EXCL_LINE
    1163              :          aicen     ! aice area fraction
    1164              : 
    1165              :       real (kind=dbl_kind), intent(inout) :: &
    1166              :          meltsliq  ! total liquid content (kg/m^2)
    1167              : 
    1168              :       real (kind=dbl_kind), dimension(nslyr), intent(in) :: &
    1169              :          massice   ! mass of ice in snow (kg/m^2)
    1170              : 
    1171              :       real (kind=dbl_kind), dimension(nslyr), intent(inout) :: &
    1172              :          massliq   ! mass of liquid in snow (kg/m^2)
    1173              : 
    1174              :       ! local temporary variables
    1175              : 
    1176              :       integer (kind=int_kind) ::  k
    1177              : 
    1178              :       real (kind=dbl_kind) :: &
    1179              :          hslyr,  & ! snow layer thickness (m)   ! LCOV_EXCL_LINE
    1180              :          hsn,    & ! snow thickness (m)   ! LCOV_EXCL_LINE
    1181              :          sliq      ! snow liquid content (kg/m^2)
    1182              : 
    1183              :       real (kind=dbl_kind), dimension(nslyr) :: &
    1184    527997120 :          dlin    , & ! liquid mass into the layer from above (kg/m^2)   ! LCOV_EXCL_LINE
    1185    527997120 :          dlout   , & ! liquid mass out of the layer (kg/m^2)   ! LCOV_EXCL_LINE
    1186    527997120 :          phi_liq , & ! volumetric liquid fraction   ! LCOV_EXCL_LINE
    1187    527997120 :          phi_ice     ! volumetric ice fraction
    1188              : 
    1189              :       character (len=*), parameter :: subname='(drain_snow)'
    1190              : 
    1191    263998560 :       hsn = c0
    1192    263998560 :       sliq = c0
    1193    263998560 :       if (aicen > c0) hsn = vsnon/aicen
    1194    263998560 :       if (hsn > puny) then
    1195    178480800 :          dlin (:) = c0
    1196    178480800 :          dlout(:) = c0
    1197     29746800 :          hslyr    = hsn / real(nslyr,kind=dbl_kind)
    1198    178480800 :          do k = 1, nslyr
    1199    148734000 :             massliq(k) = massliq(k) + dlin(k)   ! add liquid in from layer above
    1200    148734000 :             phi_ice(k) = min(c1, massice(k) / (rhoi    *hslyr))
    1201    148734000 :             phi_liq(k) =         massliq(k) / (rhofresh*hslyr)
    1202    148734000 :             dlout(k)   = max(c0, (phi_liq(k) - S_r*(c1-phi_ice(k))) * rhofresh * hslyr)
    1203    148734000 :             massliq(k) = massliq(k) - dlout(k)
    1204    178480800 :             if (k < nslyr) then
    1205    118987200 :                dlin(k+1) = dlout(k)
    1206              :             else
    1207     29746800 :                sliq = dlout(nslyr) ! this (re)initializes meltsliq
    1208              :             endif
    1209              :          enddo
    1210              :       else
    1211    234251760 :          sliq = meltsliq  ! computed in thickness_changes
    1212              :       endif
    1213    263998560 :       if (use_smliq_pnd) meltsliq = sliq
    1214              : 
    1215    263998560 :       end subroutine drain_snow
    1216              : 
    1217              : !=======================================================================
    1218              : 
    1219              :       end module icepack_snow
    1220              : 
    1221              : !=======================================================================
        

Generated by: LCOV version 2.0-1