! SUMMA - Structure for Unifying Multiple Modeling Alternatives ! Copyright (C) 2014-2020 NCAR/RAL; University of Saskatchewan; University of Washington ! ! This file is part of SUMMA ! ! For more information see: http://www.ral.ucar.edu/projects/summa ! ! This program is free software: you can redistribute it and/or modify ! it under the terms of the GNU General Public License as published by ! the Free Software Foundation, either version 3 of the License, or ! (at your option) any later version. ! ! This program is distributed in the hope that it will be useful, ! but WITHOUT ANY WARRANTY; without even the implied warranty of ! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! GNU General Public License for more details. ! ! You should have received a copy of the GNU General Public License ! along with this program. If not, see <http://www.gnu.org/licenses/>. module snwDensify_module ! data types USE nrtype ! model constants USE multiconst,only:& Tfreeze, & ! freezing point of pure water (K) iden_ice, & ! intrinsic density of ice (kg m-3) iden_air, & ! intrinsic density of air (kg m-3) iden_water ! intrinsic density of liquid water (kg m-3) ! privacy implicit none private public::snwDensify contains ! ************************************************************************************************ ! public subroutine snwDensify: compute change in snow density over the time step ! ************************************************************************************************ subroutine snwDensify(& ! intent(in): variables dt, & ! intent(in): time step (s) nSnow, & ! intent(in): number of snow layers mLayerTemp, & ! intent(in): temperature of each layer (K) mLayerMeltFreeze, & ! intent(in): volumnetric melt in each layer (kg m-3) ! intent(in): parameters densScalGrowth, & ! intent(in): density scaling factor for grain growth (kg-1 m3) tempScalGrowth, & ! intent(in): temperature scaling factor for grain growth (K-1) grainGrowthRate, & ! intent(in): rate of grain growth (s-1) densScalOvrbdn, & ! intent(in): density scaling factor for overburden pressure (kg-1 m3) tempScalOvrbdn, & ! intent(in): temperature scaling factor for overburden pressure (K-1) baseViscosity, & ! intent(in): viscosity coefficient at T=T_frz and snow density=0 (kg m-2 s) ! intent(inout): state variables mLayerDepth, & ! intent(inout): depth of each layer (m) mLayerVolFracLiqNew, & ! intent(inout): volumetric fraction of liquid water after itertations (-) mLayerVolFracIceNew, & ! intent(inout): volumetric fraction of ice after itertations (-) ! output: error control err,message) ! intent(out): error control ! ----------------------------------------------------------------------------------------------------------------------------------------- ! compute change in snow density over the time step implicit none ! intent(in): variables real(dp),intent(in) :: dt ! time step (seconds) integer(i4b),intent(in) :: nSnow ! number of snow layers real(dp),intent(in) :: mLayerTemp(:) ! temperature of each snow layer after iterations (K) real(dp),intent(in) :: mLayerMeltFreeze(:) ! volumetric melt in each layer (kg m-3) ! intent(in): parameters real(dp),intent(in) :: densScalGrowth ! density scaling factor for grain growth (kg-1 m3) real(dp),intent(in) :: tempScalGrowth ! temperature scaling factor for grain growth (K-1) real(dp),intent(in) :: grainGrowthRate ! rate of grain growth (s-1) real(dp),intent(in) :: densScalOvrbdn ! density scaling factor for overburden pressure (kg-1 m3) real(dp),intent(in) :: tempScalOvrbdn ! temperature scaling factor for overburden pressure (K-1) real(dp),intent(in) :: baseViscosity ! viscosity coefficient at T=T_frz and snow density=0 (kg m-2 s) ! intent(inout): state variables real(dp),intent(inout) :: mLayerDepth(:) ! depth of each layer (m) real(dp),intent(inout) :: mLayerVolFracLiqNew(:) ! volumetric fraction of liquid water in each snow layer after iterations (-) real(dp),intent(inout) :: mLayerVolFracIceNew(:) ! volumetric fraction of ice in each snow layer after iterations (-) ! intent(out): error control integer(i4b),intent(out) :: err ! error code character(*),intent(out) :: message ! error message ! ----------------------------------------------------------------------------------------------------------------------------------------- ! define local variables integer(i4b) :: iSnow ! index of snow layers real(dp) :: chi1,chi2,chi3,chi4,chi5 ! multipliers in the densification algorithm (-) real(dp) :: halfWeight ! half of the weight of the current snow layer (kg m-2) real(dp) :: weightSnow ! total weight of snow above the current snow layer (kg m-2) real(dp) :: CR_grainGrowth ! compaction rate for grain growth (s-1) real(dp) :: CR_ovrvdnPress ! compaction rate associated with over-burden pressure (s-1) real(dp) :: CR_metamorph ! compaction rate for metamorphism (s-1) real(dp) :: massIceOld ! mass of ice in the snow layer (kg m-2) real(dp) :: massLiqOld ! mass of liquid water in the snow layer (kg m-2) real(dp) :: scalarDepthNew ! updated layer depth (m) real(dp) :: scalarDepthMin ! minimum layer depth (m) real(dp) :: volFracIceLoss ! volumetric fraction of ice lost due to melt and sublimation (-) real(dp), dimension(nSnow) :: mLayerVolFracAirNew ! volumetric fraction of air in each layer after compaction (-) real(dp),parameter :: snwden_min=100._dp ! minimum snow density for reducing metamorphism rate (kg m-3) real(dp),parameter :: snwDensityMax=550._dp ! maximum snow density for collapse under melt (kg m-3) real(dp),parameter :: wetSnowThresh=0.01_dp ! threshold to discriminate between "wet" and "dry" snow real(dp),parameter :: minLayerDensity=40._dp ! minimum snow density allowed for any layer (kg m-3) ! ----------------------------------------------------------------------------------------------------------------------------------------- ! initialize error control err=0; message="snwDensify/" ! NOTE: still need to process the case of "snow without a layer" if(nSnow==0)return ! initialize the weight of snow above each layer (kg m-2) weightSnow = 0._dp ! loop through snow layers do iSnow=1,nSnow ! print starting density !write(*,'(a,1x,i4,1x,f9.3)') 'b4 compact: iSnow, density = ', iSnow, mLayerVolFracIceNew(iSnow)*iden_ice ! save mass of liquid water and ice (mass does not change) massIceOld = iden_ice*mLayerVolFracIceNew(iSnow)*mLayerDepth(iSnow) ! (kg m-2) massLiqOld = iden_water*mLayerVolFracLiqNew(iSnow)*mLayerDepth(iSnow) ! (kg m-2) ! *** compute the compaction associated with grain growth (s-1) ! compute the base rate of grain growth (-) if(mLayerVolFracIceNew(iSnow)*iden_ice <snwden_min) chi1=1._dp if(mLayerVolFracIceNew(iSnow)*iden_ice>=snwden_min) chi1=exp(-densScalGrowth*(mLayerVolFracIceNew(iSnow)*iden_ice - snwden_min)) ! compute the reduction of grain growth under colder snow temperatures (-) chi2 = exp(-tempScalGrowth*(Tfreeze - mLayerTemp(iSnow))) ! compute the acceleration of grain growth in the presence of liquid water (-) if(mLayerVolFracLiqNew(iSnow) > wetSnowThresh)then; chi3=2._dp ! snow is "wet" else; chi3=1._dp; end if ! snow is "dry" ! compute the compaction associated with grain growth (s-1) CR_grainGrowth = grainGrowthRate*chi1*chi2*chi3 ! **** compute the compaction associated with over-burden pressure (s-1) ! compute the weight imposed on the current layer (kg m-2) halfWeight = (massIceOld + massLiqOld)/2._dp ! there is some over-burden pressure from the layer itself weightSnow = weightSnow + halfweight ! add half of the weight from the current layer ! compute the increase in compaction under colder snow temperatures (-) chi4 = exp(-tempScalOvrbdn*(Tfreeze - mLayerTemp(iSnow))) ! compute the increase in compaction under low density snow (-) chi5 = exp(-densScalOvrbdn*mLayerVolFracIceNew(iSnow)*iden_ice) ! compute the compaction associated with over-burden pressure (s-1) CR_ovrvdnPress = (weightSnow/baseViscosity)*chi4*chi5 ! update the snow weight with the halfWeight not yet used weightSnow = weightSnow + halfweight ! add half of the weight from the current layer ! *** compute the compaction rate associated with snow melt (s-1) ! NOTE: loss of ice due to snowmelt is implicit, so can be updated directly if(iden_ice*mLayerVolFracIceNew(iSnow) < snwDensityMax)then ! only collapse layers if below a critical density ! (compute volumetric losses of ice due to melt and sublimation) volFracIceLoss = max(0._dp,mLayerMeltFreeze(iSnow)/iden_ice) ! volumetric fraction of ice lost due to melt (-) ! (adjust snow depth to account for cavitation) scalarDepthNew = mLayerDepth(iSnow) * mLayerVolFracIceNew(iSnow)/(mLayerVolFracIceNew(iSnow) + volFracIceLoss) !print*, 'volFracIceLoss = ', volFracIceLoss else scalarDepthNew = mLayerDepth(iSnow) end if ! compute the total compaction rate associated with metamorphism CR_metamorph = CR_grainGrowth + CR_ovrvdnPress ! update depth due to metamorphism (implicit solution) ! Ensure that the new depth is in line with the maximum amount of compaction that ! can occur given the masses of ice and liquid in the layer scalarDepthNew = scalarDepthNew/(1._dp + CR_metamorph*dt) scalarDepthMin = (massIceOld / iden_ice) + (massLiqOld / iden_water) mLayerDepth(iSnow) = max(scalarDepthMin, scalarDepthNew) ! check that depth is reasonable if(mLayerDepth(iSnow) < 0._dp)then write(*,'(a,1x,i4,1x,10(f12.5,1x))') 'iSnow, dt, density,massIceOld, massLiqOld = ', iSnow, dt, mLayerVolFracIceNew(iSnow)*iden_ice, massIceOld, massLiqOld write(*,'(a,1x,i4,1x,10(f12.5,1x))') 'iSnow, mLayerDepth(iSnow), scalarDepthNew, mLayerVolFracIceNew(iSnow), mLayerMeltFreeze(iSnow), CR_grainGrowth*dt, CR_ovrvdnPress*dt = ', & iSnow, mLayerDepth(iSnow), scalarDepthNew, mLayerVolFracIceNew(iSnow), mLayerMeltFreeze(iSnow), CR_grainGrowth*dt, CR_ovrvdnPress*dt endif ! update volumetric ice and liquid water content mLayerVolFracIceNew(iSnow) = massIceOld/(mLayerDepth(iSnow)*iden_ice) mLayerVolFracLiqNew(iSnow) = massLiqOld/(mLayerDepth(iSnow)*iden_water) mLayerVolFracAirNew(iSnow) = 1.0_dp - mLayerVolFracIceNew(iSnow) - mLayerVolFracLiqNew(iSnow) !write(*,'(a,1x,i4,1x,f9.3)') 'after compact: iSnow, density = ', iSnow, mLayerVolFracIceNew(iSnow)*iden_ice !if(mLayerMeltFreeze(iSnow) > 20._dp) pause 'meaningful melt' end do ! looping through snow layers ! check depth if(any(mLayerDepth(1:nSnow) < 0._dp))then do iSnow=1,nSnow write(*,'(a,1x,i4,1x,4(f12.5,1x))') 'iSnow, mLayerDepth(iSnow)', iSnow, mLayerDepth(iSnow) end do message=trim(message)//'unreasonable value for snow depth' err=20; return end if ! check for low/high snow density if(any(mLayerVolFracIceNew(1:nSnow)*iden_ice + mLayerVolFracLiqNew(1:nSnow)*iden_water + mLayerVolFracAirNew(1:nSnow)*iden_air < minLayerDensity) .or. & any(mLayerVolFracIceNew(1:nSnow) + mLayerVolFracLiqNew(1:nSnow) + mLayerVolFracAirNew(1:nSnow) > 1._dp))then do iSnow=1,nSnow write(*,*) 'iSnow, volFracIce, density = ', iSnow, mLayerVolFracIceNew(iSnow), mLayerVolFracIceNew(iSnow)*iden_ice end do message=trim(message)//'unreasonable value for snow density' err=20; return end if end subroutine snwDensify end module snwDensify_module