From 9859fae4853bd134bcb65daf79a641e494351af2 Mon Sep 17 00:00:00 2001 From: Kyle <kyle.c.klenk@gmail.com> Date: Mon, 29 Aug 2022 19:45:15 +0000 Subject: [PATCH] added lookupStruct to op_splittin --- .../hru_actor_subroutine_wrappers.hpp | 1 + build/makefile_sundials | 3 +- build/source/actors/hru_actor/cppwrap_hru.f90 | 5 + build/source/actors/hru_actor/hru_actor.cpp | 1 + build/source/driver/SummaActors_modelRun.f90 | 6 +- build/source/engine/coupled_em.f90 | 970 +++++++++--------- build/source/engine/opSplittin.f90 | 3 + .../engine/sundials/computSnowDepth.f90 | 150 +++ .../engine/{ => sundials}/t2enthalpy.f90 | 0 9 files changed, 666 insertions(+), 473 deletions(-) create mode 100644 build/source/engine/sundials/computSnowDepth.f90 rename build/source/engine/{ => sundials}/t2enthalpy.f90 (100%) diff --git a/build/includes/hru_actor/hru_actor_subroutine_wrappers.hpp b/build/includes/hru_actor/hru_actor_subroutine_wrappers.hpp index fa1e20a..e85004e 100644 --- a/build/includes/hru_actor/hru_actor_subroutine_wrappers.hpp +++ b/build/includes/hru_actor/hru_actor_subroutine_wrappers.hpp @@ -57,6 +57,7 @@ extern "C" { void* indxStruct, void* mparStruct, void* progStruct, void* diagStruct, void* fluxStruct, // basin-average structures void* bvarStruct, + void* lookupStruct, double* fracJulDay, double* tmZoneOffsetFracDay, int* yearLength, // misc int* flag, double* dt, int* dt_int_factor, int* err); diff --git a/build/makefile_sundials b/build/makefile_sundials index 25b13bd..1c35e58 100644 --- a/build/makefile_sundials +++ b/build/makefile_sundials @@ -130,6 +130,7 @@ SUMMA_SOLVER= \ eval8summa.f90 \ summaSolve.f90 \ systemSolv.f90 \ + sundials/computSnowDepth.f90 \ varSubstep.f90 \ opSplittin.f90 \ coupled_em.f90 @@ -202,7 +203,7 @@ NOAHMP = $(patsubst %, $(NOAHMP_DIR)/%, $(SUMMA_NOAHMP)) SUMMA_MODRUN = \ indexState.f90 \ getVectorz.f90 \ - t2enthalpy.f90 \ + sundials/t2enthalpy.f90 \ updateVars.f90 \ var_derive.f90 \ read_forcingActors.f90 \ diff --git a/build/source/actors/hru_actor/cppwrap_hru.f90 b/build/source/actors/hru_actor/cppwrap_hru.f90 index baededc..a4a507e 100644 --- a/build/source/actors/hru_actor/cppwrap_hru.f90 +++ b/build/source/actors/hru_actor/cppwrap_hru.f90 @@ -176,6 +176,7 @@ subroutine RunPhysics(& handle_fluxStruct, & ! x%var(:)%dat -- model fluxes ! basin-average structures handle_bvarStruct, & ! x%var(:)%dat -- basin-average variables + handle_lookupStruct, & fracJulDay, & tmZoneOffsetFracDay, & yearLength, & @@ -205,6 +206,7 @@ subroutine RunPhysics(& type(c_ptr), intent(in), value :: handle_fluxStruct ! model fluxes ! basin-average structures type(c_ptr), intent(in), value :: handle_bvarStruct ! basin-average variables + type(c_ptr), intent(in), value :: handle_lookupStruct ! lookup tables real(c_double),intent(inout) :: fracJulDay real(c_double),intent(inout) :: tmZoneOffsetFracDay integer(c_int),intent(inout) :: yearLength @@ -227,6 +229,7 @@ subroutine RunPhysics(& type(var_dlength),pointer :: fluxStruct ! model fluxes ! basin-average structures type(var_dlength),pointer :: bvarStruct ! basin-average variables + type(zLookup), pointer :: lookupStruct ! lookup tables character(len=256) :: message call c_f_pointer(handle_timeStruct, timeStruct) @@ -239,6 +242,7 @@ subroutine RunPhysics(& call c_f_pointer(handle_diagStruct, diagStruct) call c_f_pointer(handle_fluxStruct, fluxStruct) call c_f_pointer(handle_bvarStruct, bvarStruct) + call c_f_pointer(handle_lookupStruct, lookupStruct) call SummaActors_runPhysics(& @@ -257,6 +261,7 @@ subroutine RunPhysics(& fluxStruct, & ! x%var(:)%dat -- model fluxes ! basin-average structures bvarStruct, & ! x%var(:)%dat -- basin-average variables + lookupStruct, & fracJulDay, & tmZoneOffsetFracDay, & yearLength, & diff --git a/build/source/actors/hru_actor/hru_actor.cpp b/build/source/actors/hru_actor/hru_actor.cpp index c8f0620..7e82180 100644 --- a/build/source/actors/hru_actor/hru_actor.cpp +++ b/build/source/actors/hru_actor/hru_actor.cpp @@ -277,6 +277,7 @@ int Run_HRU(stateful_actor<hru_state>* self) { self->state.handle_diagStruct, self->state.handle_fluxStruct, self->state.handle_bvarStruct, + self->state.handle_lookupStruct, &self->state.fracJulDay, &self->state.tmZoneOffsetFracDay, &self->state.yearLength, diff --git a/build/source/driver/SummaActors_modelRun.f90 b/build/source/driver/SummaActors_modelRun.f90 index d5a48b3..6f8f66a 100755 --- a/build/source/driver/SummaActors_modelRun.f90 +++ b/build/source/driver/SummaActors_modelRun.f90 @@ -28,7 +28,8 @@ USE data_types,only:& var_d, & ! x%var(:) (dp) var_ilength, & ! x%var(:)%dat (i4b) var_dlength, & ! x%var(:)%dat (dp) - var_dlength_array ! x%struc(:)%dat (dp) + var_dlength_array, & ! x%struc(:)%dat (dp) + zLookup ! access missing values USE globalData,only:integerMissing ! missing integer USE globalData,only:realMissing ! missing double precision number @@ -94,6 +95,7 @@ contains fluxStruct, & ! x%var(:)%dat -- model fluxes ! basin-average structures bvarStruct, & ! x%var(:)%dat -- basin-average variables + lookupStruct, & fracJulDay, & tmZoneOffsetFracDay,& yearLength, & @@ -140,6 +142,7 @@ contains type(var_dlength),intent(inout) :: fluxStruct ! model fluxes ! basin-average structures type(var_dlength),intent(inout) :: bvarStruct ! basin-average variables + type(zLookup),intent(inout) :: lookupStruct real(dp),intent(inout) :: fracJulDay real(dp),intent(inout) :: tmZoneOffsetFracDay integer(i4b),intent(inout) :: yearLength @@ -319,6 +322,7 @@ endif forcStruct, & ! intent(in): model forcing data mparStruct, & ! intent(in): model parameters bvarStruct, & ! intent(in): basin-average model variables + lookupStruct, & ! data structures (input-output) indxStruct, & ! intent(inout): model indices progStruct, & ! intent(inout): model prognostic variables for a local HRU diff --git a/build/source/engine/coupled_em.f90 b/build/source/engine/coupled_em.f90 index 964bb2e..2b01f52 100755 --- a/build/source/engine/coupled_em.f90 +++ b/build/source/engine/coupled_em.f90 @@ -36,7 +36,8 @@ USE data_types,only:& var_i, & ! x%var(:) (i4b) var_d, & ! x%var(:) (dp) var_ilength, & ! x%var(:)%dat (i4b) - var_dlength ! x%var(:)%dat (dp) + var_dlength, & ! x%var(:)%dat (dp) + zLookup ! named variables for parent structures USE var_lookup,only:iLookDECISIONS ! named variables for elements of the decision structure @@ -111,6 +112,7 @@ subroutine coupled_em(& forc_data, & ! intent(in): model forcing data mpar_data, & ! intent(in): model parameters bvar_data, & ! intent(in): basin-average variables + lookup_data, & ! intent(in): lookup tables ! data structures (input-output) indx_data, & ! intent(inout): model indices prog_data, & ! intent(inout): prognostic variables for a local HRU @@ -139,6 +141,7 @@ subroutine coupled_em(& USE tempAdjust_module,only:tempAdjust ! adjust snow temperature associated with new snowfall USE snwDensify_module,only:snwDensify ! snow densification (compaction and cavitation) USE var_derive_module,only:calcHeight ! module to calculate height at layer interfaces and layer mid-point + USE computSnowDepth_module,only:computSnowDepth ! look-up values for the numerical method USE mDecisions_module,only: & iterative, & ! iterative @@ -160,6 +163,7 @@ subroutine coupled_em(& type(var_d),intent(in) :: forc_data ! model forcing data type(var_dlength),intent(in) :: mpar_data ! model parameters type(var_dlength),intent(in) :: bvar_data ! basin-average model variables + type(zLookup),intent(in) :: lookup_data ! lookup tables ! data structures (input-output) type(var_ilength),intent(inout) :: indx_data ! state vector geometry type(var_dlength),intent(inout) :: prog_data ! prognostic variables for a local HRU @@ -241,13 +245,20 @@ subroutine coupled_em(& real(dp), allocatable :: liqSnowInit(:) ! volumetric liquid water conetnt of snow at the start of the time step real(dp), allocatable :: liqSoilInit(:) ! soil moisture at the start of the time step ! sundials addition - logical(lgt) :: sundials=.false. + logical(lgt) :: sundials=.true. logical(lgt) :: tooMuchSublim ! flag to denote that there was too much sublimation in a given time step ! ---------------------------------------------------------------------------------------------------------------------------------------------- ! initialize error control err=0; message="coupled_em/" + print*, "*******" + print*, "*******" + print*, "*******" + print*, "Sundials = ", sundials + print*, "*******" + print*, "*******" + print*, "*******" ! This is the start of a data step for a local HRU @@ -830,15 +841,15 @@ subroutine coupled_em(& end if end if ! nsnow == 0 - ! *** solve model equations... - ! ---------------------------- + ! *** solve model equations... + ! ---------------------------- - ! save input step - dtSave = dt_sub - !write(*,'(a,1x,3(f12.5,1x))') trim(message)//'before opSplittin: dt_init, dt_sub, dt_solv = ', dt_init, dt_sub, dt_solv + ! save input step + dtSave = dt_sub + !write(*,'(a,1x,3(f12.5,1x))') trim(message)//'before opSplittin: dt_init, dt_sub, dt_solv = ', dt_init, dt_sub, dt_solv - ! get the new solution - call opSplittin(& + ! get the new solution + call opSplittin(& ! input: model control nSnow, & ! intent(in): number of snow layers nSoil, & ! intent(in): number of soil layers @@ -857,6 +868,7 @@ subroutine coupled_em(& diag_data, & ! intent(inout): model diagnostic variables for a local HRU flux_data, & ! intent(inout): model fluxes for a local HRU bvar_data, & ! intent(in): model variables for the local basin + lookup_data, & ! intent(in): lookup tables model_decisions, & ! intent(in): model decisions ! output: model control dtMultiplier, & ! intent(out): substep multiplier (-) @@ -865,93 +877,93 @@ subroutine coupled_em(& ixSolution, & ! intent(out): solution method used in this iteration err,cmessage) ! intent(out): error code and error message - ! check for all errors (error recovery within opSplittin) - if(err/=0)then - err=20 - message=trim(message)//trim(cmessage) - print*, message - return - end if + ! check for all errors (error recovery within opSplittin) + if(err/=0)then + err=20 + message=trim(message)//trim(cmessage) + print*, message + return + end if - ! process the flag for too much melt - if(tooMuchMelt)then - stepFailure = .true. - doLayerMerge = .true. - else - doLayerMerge = .false. - endif + ! process the flag for too much melt + if(tooMuchMelt)then + stepFailure = .true. + doLayerMerge = .true. + else + doLayerMerge = .false. + endif - ! handle special case of the step failure - ! NOTE: need to revert back to the previous state vector that we were happy with and reduce the time step - ! TODO: ask isn't this what the actors program does without the code block below - if(stepFailure)then + ! handle special case of the step failure + ! NOTE: need to revert back to the previous state vector that we were happy with and reduce the time step + ! TODO: ask isn't this what the actors program does without the code block below + if(stepFailure)then - ! halve step - dt_sub = dtSave/2._dp + ! halve step + dt_sub = dtSave/2._dp - ! check that the step is not tiny - if(dt_sub < minstep)then - print*,ixSolution - print*, 'dtSave, dt_sub', dtSave, dt_sub - message=trim(message)//'length of the coupled step is below the minimum step length' - err=20; return - endif + ! check that the step is not tiny + if(dt_sub < minstep)then + print*,ixSolution + print*, 'dtSave, dt_sub', dtSave, dt_sub + message=trim(message)//'length of the coupled step is below the minimum step length' + err=20; return + endif - ! try again - cycle substeps + ! try again + cycle substeps - endif + endif - ! update first step - firstSubStep=.false. - - ! *** remove ice due to sublimation... - ! -------------------------------------------------------------- - sublime: associate(& - scalarCanopySublimation => flux_data%var(iLookFLUX%scalarCanopySublimation)%dat(1), & ! sublimation from the vegetation canopy (kg m-2 s-1) - scalarSnowSublimation => flux_data%var(iLookFLUX%scalarSnowSublimation)%dat(1), & ! sublimation from the snow surface (kg m-2 s-1) - scalarLatHeatCanopyEvap => flux_data%var(iLookFLUX%scalarLatHeatCanopyEvap)%dat(1), & ! latent heat flux for evaporation from the canopy to the canopy air space (W m-2) - scalarSenHeatCanopy => flux_data%var(iLookFLUX%scalarSenHeatCanopy)%dat(1), & ! sensible heat flux from the canopy to the canopy air space (W m-2) - scalarLatHeatGround => flux_data%var(iLookFLUX%scalarLatHeatGround)%dat(1), & ! latent heat flux from ground surface below vegetation (W m-2) - scalarSenHeatGround => flux_data%var(iLookFLUX%scalarSenHeatGround)%dat(1), & ! sensible heat flux from ground surface below vegetation (W m-2) - scalarCanopyLiq => prog_data%var(iLookPROG%scalarCanopyLiq)%dat(1), & ! liquid water stored on the vegetation canopy (kg m-2) - scalarCanopyIce => prog_data%var(iLookPROG%scalarCanopyIce)%dat(1), & ! ice stored on the vegetation canopy (kg m-2) - mLayerVolFracIce => prog_data%var(iLookPROG%mLayerVolFracIce)%dat, & ! volumetric fraction of ice in the snow+soil domain (-) - mLayerVolFracLiq => prog_data%var(iLookPROG%mLayerVolFracLiq)%dat, & ! volumetric fraction of liquid water in the snow+soil domain (-) - mLayerDepth => prog_data%var(iLookPROG%mLayerDepth)%dat & ! depth of each snow+soil layer (m) - ) ! associations to variables in data structures - - ! * compute change in canopy ice content due to sublimation... - ! ------------------------------------------------------------ - if(computeVegFlux)then + ! update first step + firstSubStep=.false. + + ! *** remove ice due to sublimation... + ! -------------------------------------------------------------- + sublime: associate(& + scalarCanopySublimation => flux_data%var(iLookFLUX%scalarCanopySublimation)%dat(1), & ! sublimation from the vegetation canopy (kg m-2 s-1) + scalarSnowSublimation => flux_data%var(iLookFLUX%scalarSnowSublimation)%dat(1), & ! sublimation from the snow surface (kg m-2 s-1) + scalarLatHeatCanopyEvap => flux_data%var(iLookFLUX%scalarLatHeatCanopyEvap)%dat(1), & ! latent heat flux for evaporation from the canopy to the canopy air space (W m-2) + scalarSenHeatCanopy => flux_data%var(iLookFLUX%scalarSenHeatCanopy)%dat(1), & ! sensible heat flux from the canopy to the canopy air space (W m-2) + scalarLatHeatGround => flux_data%var(iLookFLUX%scalarLatHeatGround)%dat(1), & ! latent heat flux from ground surface below vegetation (W m-2) + scalarSenHeatGround => flux_data%var(iLookFLUX%scalarSenHeatGround)%dat(1), & ! sensible heat flux from ground surface below vegetation (W m-2) + scalarCanopyLiq => prog_data%var(iLookPROG%scalarCanopyLiq)%dat(1), & ! liquid water stored on the vegetation canopy (kg m-2) + scalarCanopyIce => prog_data%var(iLookPROG%scalarCanopyIce)%dat(1), & ! ice stored on the vegetation canopy (kg m-2) + mLayerVolFracIce => prog_data%var(iLookPROG%mLayerVolFracIce)%dat, & ! volumetric fraction of ice in the snow+soil domain (-) + mLayerVolFracLiq => prog_data%var(iLookPROG%mLayerVolFracLiq)%dat, & ! volumetric fraction of liquid water in the snow+soil domain (-) + mLayerDepth => prog_data%var(iLookPROG%mLayerDepth)%dat & ! depth of each snow+soil layer (m) + ) ! associations to variables in data structures + + ! * compute change in canopy ice content due to sublimation... + ! ------------------------------------------------------------ + if(computeVegFlux)then - ! remove mass of ice on the canopy - scalarCanopyIce = scalarCanopyIce + scalarCanopySublimation*dt_sub + ! remove mass of ice on the canopy + scalarCanopyIce = scalarCanopyIce + scalarCanopySublimation*dt_sub - ! if removed all ice, take the remaining sublimation from water - if(scalarCanopyIce < 0._dp)then - scalarCanopyLiq = scalarCanopyLiq + scalarCanopyIce - scalarCanopyIce = 0._dp - endif + ! if removed all ice, take the remaining sublimation from water + if(scalarCanopyIce < 0._dp)then + scalarCanopyLiq = scalarCanopyLiq + scalarCanopyIce + scalarCanopyIce = 0._dp + endif - ! modify fluxes if there is insufficient canopy water to support the converged sublimation rate over the time step dt_sub - if(scalarCanopyLiq < 0._dp)then - ! --> superfluous sublimation flux - superflousSub = -scalarCanopyLiq/dt_sub ! kg m-2 s-1 - superflousNrg = superflousSub*LH_sub ! W m-2 (J m-2 s-1) - ! --> update fluxes and states - scalarCanopySublimation = scalarCanopySublimation + superflousSub - scalarLatHeatCanopyEvap = scalarLatHeatCanopyEvap + superflousNrg - scalarSenHeatCanopy = scalarSenHeatCanopy - superflousNrg - scalarCanopyLiq = 0._dp - endif + ! modify fluxes if there is insufficient canopy water to support the converged sublimation rate over the time step dt_sub + if(scalarCanopyLiq < 0._dp)then + ! --> superfluous sublimation flux + superflousSub = -scalarCanopyLiq/dt_sub ! kg m-2 s-1 + superflousNrg = superflousSub*LH_sub ! W m-2 (J m-2 s-1) + ! --> update fluxes and states + scalarCanopySublimation = scalarCanopySublimation + superflousSub + scalarLatHeatCanopyEvap = scalarLatHeatCanopyEvap + superflousNrg + scalarSenHeatCanopy = scalarSenHeatCanopy - superflousNrg + scalarCanopyLiq = 0._dp + endif - end if ! (if computing the vegetation flux) + end if ! (if computing the vegetation flux) - !********** SUNDIALS ADDITION ***************** - if (sundials) then - call computSnowDepth(& + !********** SUNDIALS ADDITION ***************** + if (sundials) then + call computSnowDepth(& dt_sub, & ! intent(in) nSnow, & ! intent(in) scalarSnowSublimation, & ! intent(in) @@ -965,218 +977,219 @@ subroutine coupled_em(& mLayerDepth, & ! intent(inout) ! error control err,message) ! intent(out): error control - if(err/=0)then - err=55 - print*, "computSnowDepth", message - return - end if - - ! process the flag for too much sublimation - if(tooMuchSublim)then - stepFailure = .true. - doLayerMerge = .true. - else - doLayerMerge = .false. - endif - - ! handle special case of the step failure - ! NOTE: need to revert back to the previous state vector that we were happy with and reduce the time step - if(stepFailure)then - ! halve step - dt_sub = dtSave/2._rkind - ! check that the step is not tiny - if(dt_sub < minstep)then - print*,ixSolution - print*, 'dtSave, dt_sub', dtSave, dt_sub - message=trim(message)//'length of the coupled step is below the minimum step length' - err=20 + if(err/=0)then + err=55 + print*, "computSnowDepth", message return + end if + + ! process the flag for too much sublimation + if(tooMuchSublim)then + stepFailure = .true. + doLayerMerge = .true. + else + doLayerMerge = .false. endif + + ! handle special case of the step failure + ! NOTE: need to revert back to the previous state vector that we were happy with and reduce the time step + if(stepFailure)then + ! halve step + dt_sub = dtSave/2._rkind + ! check that the step is not tiny + if(dt_sub < minstep)then + print*,ixSolution + print*, 'dtSave, dt_sub', dtSave, dt_sub + message=trim(message)//'length of the coupled step is below the minimum step length' + err=20 + return + endif - ! try again - cycle substeps - endif + ! try again + cycle substeps + endif - ! end associate sublime + ! end associate sublime - ! update coordinate variables - call calcHeight(& + ! update coordinate variables + call calcHeight(& ! input/output: data structures indx_data, & ! intent(in): layer type prog_data, & ! intent(inout): model variables for a local HRU ! output: error control err,cmessage) - if(err/=0)then - err=20 - message=trim(message)//trim(cmessage) - return - end if + if(err/=0)then + err=20 + message=trim(message)//trim(cmessage) + return + end if - ! recompute snow depth and SWE - if(nSnow > 0)then - prog_data%var(iLookPROG%scalarSnowDepth)%dat(1) = sum( prog_data%var(iLookPROG%mLayerDepth)%dat(1:nSnow)) - prog_data%var(iLookPROG%scalarSWE)%dat(1) = sum( (prog_data%var(iLookPROG%mLayerVolFracLiq)%dat(1:nSnow)*iden_water + & + ! recompute snow depth and SWE + if(nSnow > 0)then + prog_data%var(iLookPROG%scalarSnowDepth)%dat(1) = sum( prog_data%var(iLookPROG%mLayerDepth)%dat(1:nSnow)) + prog_data%var(iLookPROG%scalarSWE)%dat(1) = sum( (prog_data%var(iLookPROG%mLayerVolFracLiq)%dat(1:nSnow)*iden_water + & prog_data%var(iLookPROG%mLayerVolFracIce)%dat(1:nSnow)*iden_ice) & * prog_data%var(iLookPROG%mLayerDepth)%dat(1:nSnow) ) - end if - - ! increment fluxes - dt_wght = dt_sub/data_step ! define weight applied to each sub-step - do iVar=1,size(averageFlux_meta) - flux_mean%var(iVar)%dat(:) = flux_mean%var(iVar)%dat(:) + flux_data%var(averageFlux_meta(iVar)%ixParent)%dat(:)*dt_wght - end do - - ! increment change in storage associated with the surface melt pond (kg m-2) - if(nSnow==0) sfcMeltPond = sfcMeltPond + prog_data%var(iLookPROG%scalarSfcMeltPond)%dat(1) - - ! increment soil compression (kg m-2) - totalSoilCompress = totalSoilCompress + diag_data%var(iLookDIAG%scalarSoilCompress)%dat(1) ! total soil compression over whole layer (kg m-2) - !********** END SUNDIALS ADDITION ***************** - else ! Non - Sundials version - ! * compute change in ice content of the top snow layer due to sublimation... - ! --------------------------------------------------------------------------- - ! NOTE: this is done BEFORE densification - if(nSnow > 0)then ! snow layers exist - - ! try to remove ice from the top layer - iSnow=1 - - ! save the mass of liquid water (kg m-2) - massLiquid = mLayerDepth(iSnow)*mLayerVolFracLiq(iSnow)*iden_water - - ! add/remove the depth of snow gained/lost by frost/sublimation (m) - ! NOTE: assume constant density - mLayerDepth(iSnow) = mLayerDepth(iSnow) + dt_sub*scalarSnowSublimation/(mLayerVolFracIce(iSnow)*iden_ice) - - ! check that we did not remove the entire layer - if(mLayerDepth(iSnow) < verySmall)then - stepFailure = .true. - doLayerMerge = .true. - dt_sub = max(dtSave/2._dp, minstep) - cycle substeps - else - stepFailure = .false. - doLayerMerge = .false. - endif - - ! update the volumetric fraction of liquid water - mLayerVolFracLiq(iSnow) = massLiquid / (mLayerDepth(iSnow)*iden_water) - - ! no snow - else - - ! no snow: check that sublimation is zero - if(abs(scalarSnowSublimation) > verySmall)then - message=trim(message)//'sublimation of snow has been computed when no snow exists' - print*, message - err=20; return end if - end if ! (if snow layers exist) + ! increment fluxes + dt_wght = dt_sub/data_step ! define weight applied to each sub-step + do iVar=1,size(averageFlux_meta) + flux_mean%var(iVar)%dat(:) = flux_mean%var(iVar)%dat(:) + flux_data%var(averageFlux_meta(iVar)%ixParent)%dat(:)*dt_wght + end do - ! end associate sublime + ! increment change in storage associated with the surface melt pond (kg m-2) + if(nSnow==0) sfcMeltPond = sfcMeltPond + prog_data%var(iLookPROG%scalarSfcMeltPond)%dat(1) - ! *** account for compaction and cavitation in the snowpack... - ! ------------------------------------------------------------ - if(nSnow>0)then - call snwDensify(& - ! intent(in): variables - dt_sub, & ! intent(in): time step (s) - indx_data%var(iLookINDEX%nSnow)%dat(1), & ! intent(in): number of snow layers - prog_data%var(iLookPROG%mLayerTemp)%dat(1:nSnow), & ! intent(in): temperature of each layer (K) - diag_data%var(iLookDIAG%mLayerMeltFreeze)%dat(1:nSnow), & ! intent(in): volumetric melt in each layer (kg m-3) - ! intent(in): parameters - mpar_data%var(iLookPARAM%densScalGrowth)%dat(1), & ! intent(in): density scaling factor for grain growth (kg-1 m3) - mpar_data%var(iLookPARAM%tempScalGrowth)%dat(1), & ! intent(in): temperature scaling factor for grain growth (K-1) - mpar_data%var(iLookPARAM%grainGrowthRate)%dat(1), & ! intent(in): rate of grain growth (s-1) - mpar_data%var(iLookPARAM%densScalOvrbdn)%dat(1), & ! intent(in): density scaling factor for overburden pressure (kg-1 m3) - mpar_data%var(iLookPARAM%tempScalOvrbdn)%dat(1), & ! intent(in): temperature scaling factor for overburden pressure (K-1) - mpar_data%var(iLookPARAM%baseViscosity)%dat(1), & ! intent(in): viscosity coefficient at T=T_frz and snow density=0 (kg m-2 s) - ! intent(inout): state variables - prog_data%var(iLookPROG%mLayerDepth)%dat(1:nSnow), & ! intent(inout): depth of each layer (m) - prog_data%var(iLookPROG%mLayerVolFracLiq)%dat(1:nSnow), & ! intent(inout): volumetric fraction of liquid water after itertations (-) - prog_data%var(iLookPROG%mLayerVolFracIce)%dat(1:nSnow), & ! intent(inout): volumetric fraction of ice after itertations (-) + ! increment soil compression (kg m-2) + totalSoilCompress = totalSoilCompress + diag_data%var(iLookDIAG%scalarSoilCompress)%dat(1) ! total soil compression over whole layer (kg m-2) + !********** END SUNDIALS ADDITION ***************** + else ! Non - Sundials version + ! * compute change in ice content of the top snow layer due to sublimation... + ! --------------------------------------------------------------------------- + ! NOTE: this is done BEFORE densification + if(nSnow > 0)then ! snow layers exist + + ! try to remove ice from the top layer + iSnow=1 + + ! save the mass of liquid water (kg m-2) + massLiquid = mLayerDepth(iSnow)*mLayerVolFracLiq(iSnow)*iden_water + + ! add/remove the depth of snow gained/lost by frost/sublimation (m) + ! NOTE: assume constant density + mLayerDepth(iSnow) = mLayerDepth(iSnow) + dt_sub*scalarSnowSublimation/(mLayerVolFracIce(iSnow)*iden_ice) + + ! check that we did not remove the entire layer + if(mLayerDepth(iSnow) < verySmall)then + stepFailure = .true. + doLayerMerge = .true. + dt_sub = max(dtSave/2._dp, minstep) + cycle substeps + else + stepFailure = .false. + doLayerMerge = .false. + endif + + ! update the volumetric fraction of liquid water + mLayerVolFracLiq(iSnow) = massLiquid / (mLayerDepth(iSnow)*iden_water) + + ! no snow + else + + ! no snow: check that sublimation is zero + if(abs(scalarSnowSublimation) > verySmall)then + message=trim(message)//'sublimation of snow has been computed when no snow exists' + print*, message + err=20; return + end if + + end if ! (if snow layers exist) + + ! end associate sublime + + ! *** account for compaction and cavitation in the snowpack... + ! ------------------------------------------------------------ + if(nSnow>0)then + call snwDensify(& + ! intent(in): variables + dt_sub, & ! intent(in): time step (s) + indx_data%var(iLookINDEX%nSnow)%dat(1), & ! intent(in): number of snow layers + prog_data%var(iLookPROG%mLayerTemp)%dat(1:nSnow), & ! intent(in): temperature of each layer (K) + diag_data%var(iLookDIAG%mLayerMeltFreeze)%dat(1:nSnow), & ! intent(in): volumetric melt in each layer (kg m-3) + ! intent(in): parameters + mpar_data%var(iLookPARAM%densScalGrowth)%dat(1), & ! intent(in): density scaling factor for grain growth (kg-1 m3) + mpar_data%var(iLookPARAM%tempScalGrowth)%dat(1), & ! intent(in): temperature scaling factor for grain growth (K-1) + mpar_data%var(iLookPARAM%grainGrowthRate)%dat(1), & ! intent(in): rate of grain growth (s-1) + mpar_data%var(iLookPARAM%densScalOvrbdn)%dat(1), & ! intent(in): density scaling factor for overburden pressure (kg-1 m3) + mpar_data%var(iLookPARAM%tempScalOvrbdn)%dat(1), & ! intent(in): temperature scaling factor for overburden pressure (K-1) + mpar_data%var(iLookPARAM%baseViscosity)%dat(1), & ! intent(in): viscosity coefficient at T=T_frz and snow density=0 (kg m-2 s) + ! intent(inout): state variables + prog_data%var(iLookPROG%mLayerDepth)%dat(1:nSnow), & ! intent(inout): depth of each layer (m) + prog_data%var(iLookPROG%mLayerVolFracLiq)%dat(1:nSnow), & ! intent(inout): volumetric fraction of liquid water after itertations (-) + prog_data%var(iLookPROG%mLayerVolFracIce)%dat(1:nSnow), & ! intent(inout): volumetric fraction of ice after itertations (-) + ! output: error control + err,cmessage) ! intent(out): error control + if(err/=0)then + err=55 + message=trim(message)//trim(cmessage) + print*, message + return + end if + + end if ! if snow layers exist + + ! update coordinate variables + call calcHeight(& + ! input/output: data structures + indx_data, & ! intent(in): layer type + prog_data, & ! intent(inout): model variables for a local HRU ! output: error control - err,cmessage) ! intent(out): error control + err,cmessage) if(err/=0)then - err=55 + err=20 message=trim(message)//trim(cmessage) print*, message return end if + + ! recompute snow depth and SWE + if(nSnow > 0)then + prog_data%var(iLookPROG%scalarSnowDepth)%dat(1) = sum( prog_data%var(iLookPROG%mLayerDepth)%dat(1:nSnow)) + prog_data%var(iLookPROG%scalarSWE)%dat(1) = sum( (prog_data%var(iLookPROG%mLayerVolFracLiq)%dat(1:nSnow)*iden_water + & + prog_data%var(iLookPROG%mLayerVolFracIce)%dat(1:nSnow)*iden_ice) & + * prog_data%var(iLookPROG%mLayerDepth)%dat(1:nSnow) ) + end if + + ! increment fluxes + dt_wght = dt_sub/data_step ! define weight applied to each sub-step + do iVar=1,size(averageFlux_meta) + flux_mean%var(iVar)%dat(:) = flux_mean%var(iVar)%dat(:) + flux_data%var(averageFlux_meta(iVar)%ixParent)%dat(:)*dt_wght + end do + + ! increment change in storage associated with the surface melt pond (kg m-2) + if(nSnow==0) sfcMeltPond = sfcMeltPond + prog_data%var(iLookPROG%scalarSfcMeltPond)%dat(1) + + ! increment soil compression (kg m-2) + totalSoilCompress = totalSoilCompress + diag_data%var(iLookDIAG%scalarSoilCompress)%dat(1) ! total soil compression over whole layer (kg m-2) - end if ! if snow layers exist - - ! update coordinate variables - call calcHeight(& - ! input/output: data structures - indx_data, & ! intent(in): layer type - prog_data, & ! intent(inout): model variables for a local HRU - ! output: error control - err,cmessage) - if(err/=0)then - err=20 - message=trim(message)//trim(cmessage) - print*, message - return - end if - - ! recompute snow depth and SWE - if(nSnow > 0)then - prog_data%var(iLookPROG%scalarSnowDepth)%dat(1) = sum( prog_data%var(iLookPROG%mLayerDepth)%dat(1:nSnow)) - prog_data%var(iLookPROG%scalarSWE)%dat(1) = sum( (prog_data%var(iLookPROG%mLayerVolFracLiq)%dat(1:nSnow)*iden_water + & - prog_data%var(iLookPROG%mLayerVolFracIce)%dat(1:nSnow)*iden_ice) & - * prog_data%var(iLookPROG%mLayerDepth)%dat(1:nSnow) ) - end if - - ! increment fluxes - dt_wght = dt_sub/data_step ! define weight applied to each sub-step - do iVar=1,size(averageFlux_meta) - flux_mean%var(iVar)%dat(:) = flux_mean%var(iVar)%dat(:) + flux_data%var(averageFlux_meta(iVar)%ixParent)%dat(:)*dt_wght - end do - - ! increment change in storage associated with the surface melt pond (kg m-2) - if(nSnow==0) sfcMeltPond = sfcMeltPond + prog_data%var(iLookPROG%scalarSfcMeltPond)%dat(1) - - ! increment soil compression (kg m-2) - totalSoilCompress = totalSoilCompress + diag_data%var(iLookDIAG%scalarSoilCompress)%dat(1) ! total soil compression over whole layer (kg m-2) - - end if ! sundials - end associate sublime + end if ! sundials + end associate sublime - ! **************************************************************************************************** - ! *** END MAIN SOLVER ******************************************************************************** - ! **************************************************************************************************** + ! **************************************************************************************************** + ! *** END MAIN SOLVER ******************************************************************************** + ! **************************************************************************************************** - ! increment sub-step - dt_solv = dt_solv + dt_sub + ! increment sub-step + dt_solv = dt_solv + dt_sub - ! save the time step to initialize the subsequent step - if(dt_solv<data_step .or. nsub==1) dt_init = dt_sub + ! save the time step to initialize the subsequent step + if(dt_solv<data_step .or. nsub==1) dt_init = dt_sub - ! check - if(globalPrintFlag)& - write(*,'(a,1x,3(f18.5,1x))') 'dt_sub, dt_solv, data_step: ', dt_sub, dt_solv, data_step + ! check + if(globalPrintFlag)& + write(*,'(a,1x,3(f18.5,1x))') 'dt_sub, dt_solv, data_step: ', dt_sub, dt_solv, data_step - ! check that we have completed the sub-step - if(dt_solv >= data_step-verySmall) then - exit substeps - endif + ! check that we have completed the sub-step + if(dt_solv >= data_step-verySmall) then + exit substeps + endif - ! adjust length of the sub-step (make sure that we don't exceed the step) - dt_sub = min(data_step - dt_solv, dt_sub) - !print*, 'dt_sub = ', dt_sub + ! adjust length of the sub-step (make sure that we don't exceed the step) + ! TODO: This is different in Ashley's code + dt_sub = min(data_step - dt_solv, dt_sub) + !print*, 'dt_sub = ', dt_sub - end do substeps ! (sub-step loop) - !print*, 'PAUSE: completed time step'; read(*,*) + end do substeps ! (sub-step loop) + !print*, 'PAUSE: completed time step'; read(*,*) - ! *** add snowfall to the snowpack... - ! ----------------------------------- + ! *** add snowfall to the snowpack... + ! ----------------------------------- - ! add new snowfall to the snowpack - ! NOTE: This needs to be done AFTER the call to canopySnow, since throughfall and unloading are computed in canopySnow - call newsnwfall(& + ! add new snowfall to the snowpack + ! NOTE: This needs to be done AFTER the call to canopySnow, since throughfall and unloading are computed in canopySnow + call newsnwfall(& ! input: model control data_step, & ! time step (seconds) (nSnow > 0), & ! logical flag if snow layers exist @@ -1195,35 +1208,45 @@ subroutine coupled_em(& prog_data%var(iLookPROG%mLayerVolFracLiq)%dat(1), & ! volumetric fraction of liquid water of the top layer (-) ! output: error control err,cmessage) ! error control - if(err/=0)then; err=30; message=trim(message)//trim(cmessage); return; end if + if(err/=0)then + err=30 + message=trim(message)//trim(cmessage) + print*,message + return + end if - ! re-compute snow depth and SWE - if(nSnow > 0)then - prog_data%var(iLookPROG%scalarSnowDepth)%dat(1) = sum( prog_data%var(iLookPROG%mLayerDepth)%dat(1:nSnow)) - prog_data%var(iLookPROG%scalarSWE)%dat(1) = sum( (prog_data%var(iLookPROG%mLayerVolFracLiq)%dat(1:nSnow)*iden_water + & + ! re-compute snow depth and SWE + if(nSnow > 0)then + prog_data%var(iLookPROG%scalarSnowDepth)%dat(1) = sum( prog_data%var(iLookPROG%mLayerDepth)%dat(1:nSnow)) + prog_data%var(iLookPROG%scalarSWE)%dat(1) = sum( (prog_data%var(iLookPROG%mLayerVolFracLiq)%dat(1:nSnow)*iden_water + & prog_data%var(iLookPROG%mLayerVolFracIce)%dat(1:nSnow)*iden_ice) & * prog_data%var(iLookPROG%mLayerDepth)%dat(1:nSnow) ) - end if - !print*, 'SWE after snowfall = ', prog_data%var(iLookPROG%scalarSWE)%dat(1) + end if + !print*, 'SWE after snowfall = ', prog_data%var(iLookPROG%scalarSWE)%dat(1) - ! re-assign dimension lengths - nSnow = count(indx_data%var(iLookINDEX%layerType)%dat==iname_snow) - nSoil = count(indx_data%var(iLookINDEX%layerType)%dat==iname_soil) - nLayers = nSnow+nSoil + ! re-assign dimension lengths + nSnow = count(indx_data%var(iLookINDEX%layerType)%dat==iname_snow) + nSoil = count(indx_data%var(iLookINDEX%layerType)%dat==iname_soil) + nLayers = nSnow+nSoil - ! update coordinate variables - call calcHeight(& + ! update coordinate variables + call calcHeight(& ! input/output: data structures indx_data, & ! intent(in): layer type prog_data, & ! intent(inout): model variables for a local HRU ! output: error control err,cmessage) - if(err/=0)then; err=20; message=trim(message)//trim(cmessage); return; end if + if(err/=0)then + err=20 + message=trim(message)//trim(cmessage) + print*, message + return + end if - ! overwrite flux_data with flux_mean (returns timestep-average fluxes for scalar variables) - do iVar=1,size(averageFlux_meta) - flux_data%var(averageFlux_meta(iVar)%ixParent)%dat(:) = flux_mean%var(iVar)%dat(:) - end do + ! overwrite flux_data with flux_mean (returns timestep-average fluxes for scalar variables) + do iVar=1,size(averageFlux_meta) + flux_data%var(averageFlux_meta(iVar)%ixParent)%dat(:) = flux_mean%var(iVar)%dat(:) + end do ! *********************************************************************************************************************************** ! *********************************************************************************************************************************** @@ -1237,209 +1260,214 @@ subroutine coupled_em(& ! save the average compression and melt pond storage in the data structures prog_data%var(iLookPROG%scalarSfcMeltPond)%dat(1) = sfcMeltPond - ! associate local variables with information in the data structures - associate(& - ! model forcing - scalarSnowfall => flux_mean%var(childFLUX_MEAN(iLookFLUX%scalarSnowfall) )%dat(1) ,& ! computed snowfall rate (kg m-2 s-1) - scalarRainfall => flux_mean%var(childFLUX_MEAN(iLookFLUX%scalarRainfall) )%dat(1) ,& ! computed rainfall rate (kg m-2 s-1) - ! canopy fluxes - averageThroughfallSnow => flux_mean%var(childFLUX_MEAN(iLookFLUX%scalarThroughfallSnow) )%dat(1) ,& ! snow that reaches the ground without ever touching the canopy (kg m-2 s-1) - averageThroughfallRain => flux_mean%var(childFLUX_MEAN(iLookFLUX%scalarThroughfallRain) )%dat(1) ,& ! rain that reaches the ground without ever touching the canopy (kg m-2 s-1) - averageCanopySnowUnloading => flux_mean%var(childFLUX_MEAN(iLookFLUX%scalarCanopySnowUnloading))%dat(1) ,& ! unloading of snow from the vegetion canopy (kg m-2 s-1) - averageCanopyLiqDrainage => flux_mean%var(childFLUX_MEAN(iLookFLUX%scalarCanopyLiqDrainage) )%dat(1) ,& ! drainage of liquid water from the vegetation canopy (kg m-2 s-1) - averageCanopySublimation => flux_mean%var(childFLUX_MEAN(iLookFLUX%scalarCanopySublimation) )%dat(1) ,& ! canopy sublimation/frost (kg m-2 s-1) - averageCanopyEvaporation => flux_mean%var(childFLUX_MEAN(iLookFLUX%scalarCanopyEvaporation) )%dat(1) ,& ! canopy evaporation/condensation (kg m-2 s-1) - ! snow fluxes - averageSnowSublimation => flux_mean%var(childFLUX_MEAN(iLookFLUX%scalarSnowSublimation) )%dat(1) ,& ! sublimation from the snow surface (kg m-2 s-1) - averageSnowDrainage => flux_mean%var(childFLUX_MEAN(iLookFLUX%scalarSnowDrainage) )%dat(1) ,& ! drainage from the bottom of the snowpack (m s-1) - ! soil fluxes - averageSoilInflux => flux_mean%var(childFLUX_MEAN(iLookFLUX%scalarInfiltration) )%dat(1) ,& ! influx of water at the top of the soil profile (m s-1) - averageSoilDrainage => flux_mean%var(childFLUX_MEAN(iLookFLUX%scalarSoilDrainage) )%dat(1) ,& ! drainage from the bottom of the soil profile (m s-1) - averageSoilBaseflow => flux_mean%var(childFLUX_MEAN(iLookFLUX%scalarSoilBaseflow) )%dat(1) ,& ! total baseflow from throughout the soil profile (m s-1) - averageGroundEvaporation => flux_mean%var(childFLUX_MEAN(iLookFLUX%scalarGroundEvaporation) )%dat(1) ,& ! soil evaporation (kg m-2 s-1) - averageCanopyTranspiration => flux_mean%var(childFLUX_MEAN(iLookFLUX%scalarCanopyTranspiration))%dat(1) ,& ! canopy transpiration (kg m-2 s-1) - ! state variables in the vegetation canopy - scalarCanopyLiq => prog_data%var(iLookPROG%scalarCanopyLiq)%dat(1) ,& ! canopy liquid water (kg m-2) - scalarCanopyIce => prog_data%var(iLookPROG%scalarCanopyIce)%dat(1) ,& ! canopy ice content (kg m-2) - ! state variables in the soil domain - mLayerDepth => prog_data%var(iLookPROG%mLayerDepth)%dat(nSnow+1:nLayers) ,& ! depth of each soil layer (m) - mLayerVolFracIce => prog_data%var(iLookPROG%mLayerVolFracIce)%dat(nSnow+1:nLayers) ,& ! volumetric ice content in each soil layer (-) - mLayerVolFracLiq => prog_data%var(iLookPROG%mLayerVolFracLiq)%dat(nSnow+1:nLayers) ,& ! volumetric liquid water content in each soil layer (-) - scalarAquiferStorage => prog_data%var(iLookPROG%scalarAquiferStorage)%dat(1) ,& ! aquifer storage (m) - ! error tolerance - absConvTol_liquid => mpar_data%var(iLookPARAM%absConvTol_liquid)%dat(1) ,& ! absolute convergence tolerance for vol frac liq water (-) - scalarTotalSoilIce => diag_data%var(iLookDIAG%scalarTotalSoilIce)%dat(1) ,& ! total ice in the soil column (kg m-2) - scalarTotalSoilLiq => diag_data%var(iLookDIAG%scalarTotalSoilLiq)%dat(1) & ! total liquid water in the soil column (kg m-2) - ) ! (association of local variables with information in the data structures - - ! ----- - ! * balance checks for the canopy... - ! ---------------------------------- - - ! if computing the vegetation flux - if(computeVegFlux)then - - ! canopy water balance - balanceCanopyWater1 = scalarCanopyLiq + scalarCanopyIce - - ! balance checks for the canopy - ! NOTE: need to put the balance checks in the sub-step loop so that we can re-compute if necessary - scalarCanopyWatBalError = balanceCanopyWater1 - (balanceCanopyWater0 + (scalarSnowfall - averageThroughfallSnow)*data_step + (scalarRainfall - averageThroughfallRain)*data_step & - - averageCanopySnowUnloading*data_step - averageCanopyLiqDrainage*data_step + averageCanopySublimation*data_step + averageCanopyEvaporation*data_step) - if(abs(scalarCanopyWatBalError) > absConvTol_liquid*iden_water*10._dp)then - print*, '** canopy water balance error:' - write(*,'(a,1x,f20.10)') 'data_step = ', data_step - write(*,'(a,1x,f20.10)') 'balanceCanopyWater0 = ', balanceCanopyWater0 - write(*,'(a,1x,f20.10)') 'balanceCanopyWater1 = ', balanceCanopyWater1 - write(*,'(a,1x,f20.10)') 'scalarSnowfall = ', scalarSnowfall - write(*,'(a,1x,f20.10)') 'scalarRainfall = ', scalarRainfall - write(*,'(a,1x,f20.10)') '(scalarSnowfall - averageThroughfallSnow) = ', (scalarSnowfall - averageThroughfallSnow)!*data_step - write(*,'(a,1x,f20.10)') '(scalarRainfall - averageThroughfallRain) = ', (scalarRainfall - averageThroughfallRain)!*data_step - write(*,'(a,1x,f20.10)') 'averageCanopySnowUnloading = ', averageCanopySnowUnloading!*data_step - write(*,'(a,1x,f20.10)') 'averageCanopyLiqDrainage = ', averageCanopyLiqDrainage!*data_step - write(*,'(a,1x,f20.10)') 'averageCanopySublimation = ', averageCanopySublimation!*data_step - write(*,'(a,1x,f20.10)') 'averageCanopyEvaporation = ', averageCanopyEvaporation!*data_step - write(*,'(a,1x,f20.10)') 'scalarCanopyWatBalError = ', scalarCanopyWatBalError - message=trim(message)//'canopy hydrology does not balance' - err=20; return - end if + ! associate local variables with information in the data structures + associate(& + ! model forcing + scalarSnowfall => flux_mean%var(childFLUX_MEAN(iLookFLUX%scalarSnowfall) )%dat(1) ,& ! computed snowfall rate (kg m-2 s-1) + scalarRainfall => flux_mean%var(childFLUX_MEAN(iLookFLUX%scalarRainfall) )%dat(1) ,& ! computed rainfall rate (kg m-2 s-1) + ! canopy fluxes + averageThroughfallSnow => flux_mean%var(childFLUX_MEAN(iLookFLUX%scalarThroughfallSnow) )%dat(1) ,& ! snow that reaches the ground without ever touching the canopy (kg m-2 s-1) + averageThroughfallRain => flux_mean%var(childFLUX_MEAN(iLookFLUX%scalarThroughfallRain) )%dat(1) ,& ! rain that reaches the ground without ever touching the canopy (kg m-2 s-1) + averageCanopySnowUnloading => flux_mean%var(childFLUX_MEAN(iLookFLUX%scalarCanopySnowUnloading))%dat(1) ,& ! unloading of snow from the vegetion canopy (kg m-2 s-1) + averageCanopyLiqDrainage => flux_mean%var(childFLUX_MEAN(iLookFLUX%scalarCanopyLiqDrainage) )%dat(1) ,& ! drainage of liquid water from the vegetation canopy (kg m-2 s-1) + averageCanopySublimation => flux_mean%var(childFLUX_MEAN(iLookFLUX%scalarCanopySublimation) )%dat(1) ,& ! canopy sublimation/frost (kg m-2 s-1) + averageCanopyEvaporation => flux_mean%var(childFLUX_MEAN(iLookFLUX%scalarCanopyEvaporation) )%dat(1) ,& ! canopy evaporation/condensation (kg m-2 s-1) + ! snow fluxes + averageSnowSublimation => flux_mean%var(childFLUX_MEAN(iLookFLUX%scalarSnowSublimation) )%dat(1) ,& ! sublimation from the snow surface (kg m-2 s-1) + averageSnowDrainage => flux_mean%var(childFLUX_MEAN(iLookFLUX%scalarSnowDrainage) )%dat(1) ,& ! drainage from the bottom of the snowpack (m s-1) + ! soil fluxes + averageSoilInflux => flux_mean%var(childFLUX_MEAN(iLookFLUX%scalarInfiltration) )%dat(1) ,& ! influx of water at the top of the soil profile (m s-1) + averageSoilDrainage => flux_mean%var(childFLUX_MEAN(iLookFLUX%scalarSoilDrainage) )%dat(1) ,& ! drainage from the bottom of the soil profile (m s-1) + averageSoilBaseflow => flux_mean%var(childFLUX_MEAN(iLookFLUX%scalarSoilBaseflow) )%dat(1) ,& ! total baseflow from throughout the soil profile (m s-1) + averageGroundEvaporation => flux_mean%var(childFLUX_MEAN(iLookFLUX%scalarGroundEvaporation) )%dat(1) ,& ! soil evaporation (kg m-2 s-1) + averageCanopyTranspiration => flux_mean%var(childFLUX_MEAN(iLookFLUX%scalarCanopyTranspiration))%dat(1) ,& ! canopy transpiration (kg m-2 s-1) + ! state variables in the vegetation canopy + scalarCanopyLiq => prog_data%var(iLookPROG%scalarCanopyLiq)%dat(1) ,& ! canopy liquid water (kg m-2) + scalarCanopyIce => prog_data%var(iLookPROG%scalarCanopyIce)%dat(1) ,& ! canopy ice content (kg m-2) + ! state variables in the soil domain + mLayerDepth => prog_data%var(iLookPROG%mLayerDepth)%dat(nSnow+1:nLayers) ,& ! depth of each soil layer (m) + mLayerVolFracIce => prog_data%var(iLookPROG%mLayerVolFracIce)%dat(nSnow+1:nLayers) ,& ! volumetric ice content in each soil layer (-) + mLayerVolFracLiq => prog_data%var(iLookPROG%mLayerVolFracLiq)%dat(nSnow+1:nLayers) ,& ! volumetric liquid water content in each soil layer (-) + scalarAquiferStorage => prog_data%var(iLookPROG%scalarAquiferStorage)%dat(1) ,& ! aquifer storage (m) + ! error tolerance + absConvTol_liquid => mpar_data%var(iLookPARAM%absConvTol_liquid)%dat(1) ,& ! absolute convergence tolerance for vol frac liq water (-) + scalarTotalSoilIce => diag_data%var(iLookDIAG%scalarTotalSoilIce)%dat(1) ,& ! total ice in the soil column (kg m-2) + scalarTotalSoilLiq => diag_data%var(iLookDIAG%scalarTotalSoilLiq)%dat(1) & ! total liquid water in the soil column (kg m-2) + ) ! (association of local variables with information in the data structures - endif ! if computing the vegetation flux + ! ----- + ! * balance checks for the canopy... + ! ---------------------------------- - ! ----- - ! * balance checks for SWE... - ! --------------------------- + ! if computing the vegetation flux + if(computeVegFlux)then - ! recompute snow depth (m) and SWE (kg m-2) - if(nSnow > 0)then - prog_data%var(iLookPROG%scalarSnowDepth)%dat(1) = sum( prog_data%var(iLookPROG%mLayerDepth)%dat(1:nSnow)) - prog_data%var(iLookPROG%scalarSWE)%dat(1) = sum( (prog_data%var(iLookPROG%mLayerVolFracLiq)%dat(1:nSnow)*iden_water + & - prog_data%var(iLookPROG%mLayerVolFracIce)%dat(1:nSnow)*iden_ice) & - * prog_data%var(iLookPROG%mLayerDepth)%dat(1:nSnow) ) - end if - - ! check the individual layers - if(printBalance .and. nSnow>0)then - write(*,'(a,1x,10(f12.8,1x))') 'liqSnowInit = ', liqSnowInit - write(*,'(a,1x,10(f12.8,1x))') 'volFracLiq = ', prog_data%var(iLookPROG%mLayerVolFracLiq)%dat(1:nSnow) - write(*,'(a,1x,10(f12.8,1x))') 'iLayerLiqFluxSnow = ', flux_data%var(iLookFLUX%iLayerLiqFluxSnow)%dat*iden_water*data_step - write(*,'(a,1x,10(f12.8,1x))') 'mLayerLiqFluxSnow = ', flux_data%var(iLookFLUX%mLayerLiqFluxSnow)%dat*data_step - write(*,'(a,1x,10(f12.8,1x))') 'change volFracLiq = ', prog_data%var(iLookPROG%mLayerVolFracLiq)%dat(1:nSnow) - liqSnowInit - deallocate(liqSnowInit, stat=err) - if(err/=0)then - message=trim(message)//'unable to deallocate space for the initial volumetric liquid water content of snow' - err=20; return + ! canopy water balance + balanceCanopyWater1 = scalarCanopyLiq + scalarCanopyIce + + ! balance checks for the canopy + ! NOTE: need to put the balance checks in the sub-step loop so that we can re-compute if necessary + scalarCanopyWatBalError = balanceCanopyWater1 - (balanceCanopyWater0 + (scalarSnowfall - averageThroughfallSnow)*data_step + (scalarRainfall - averageThroughfallRain)*data_step & + - averageCanopySnowUnloading*data_step - averageCanopyLiqDrainage*data_step + averageCanopySublimation*data_step + averageCanopyEvaporation*data_step) + if(abs(scalarCanopyWatBalError) > absConvTol_liquid*iden_water*10._dp)then + print*, '** canopy water balance error:' + write(*,'(a,1x,f20.10)') 'data_step = ', data_step + write(*,'(a,1x,f20.10)') 'balanceCanopyWater0 = ', balanceCanopyWater0 + write(*,'(a,1x,f20.10)') 'balanceCanopyWater1 = ', balanceCanopyWater1 + write(*,'(a,1x,f20.10)') 'scalarSnowfall = ', scalarSnowfall + write(*,'(a,1x,f20.10)') 'scalarRainfall = ', scalarRainfall + write(*,'(a,1x,f20.10)') '(scalarSnowfall - averageThroughfallSnow) = ', (scalarSnowfall - averageThroughfallSnow)!*data_step + write(*,'(a,1x,f20.10)') '(scalarRainfall - averageThroughfallRain) = ', (scalarRainfall - averageThroughfallRain)!*data_step + write(*,'(a,1x,f20.10)') 'averageCanopySnowUnloading = ', averageCanopySnowUnloading!*data_step + write(*,'(a,1x,f20.10)') 'averageCanopyLiqDrainage = ', averageCanopyLiqDrainage!*data_step + write(*,'(a,1x,f20.10)') 'averageCanopySublimation = ', averageCanopySublimation!*data_step + write(*,'(a,1x,f20.10)') 'averageCanopyEvaporation = ', averageCanopyEvaporation!*data_step + write(*,'(a,1x,f20.10)') 'scalarCanopyWatBalError = ', scalarCanopyWatBalError + message=trim(message)//'canopy hydrology does not balance' + print*, message + err=20; return + end if + + endif ! if computing the vegetation flux + + ! ----- + ! * balance checks for SWE... + ! --------------------------- + + ! recompute snow depth (m) and SWE (kg m-2) + if(nSnow > 0)then + prog_data%var(iLookPROG%scalarSnowDepth)%dat(1) = sum( prog_data%var(iLookPROG%mLayerDepth)%dat(1:nSnow)) + prog_data%var(iLookPROG%scalarSWE)%dat(1) = sum( (prog_data%var(iLookPROG%mLayerVolFracLiq)%dat(1:nSnow)*iden_water + & + prog_data%var(iLookPROG%mLayerVolFracIce)%dat(1:nSnow)*iden_ice) & + * prog_data%var(iLookPROG%mLayerDepth)%dat(1:nSnow) ) + end if + + ! check the individual layers + if(printBalance .and. nSnow>0)then + write(*,'(a,1x,10(f12.8,1x))') 'liqSnowInit = ', liqSnowInit + write(*,'(a,1x,10(f12.8,1x))') 'volFracLiq = ', prog_data%var(iLookPROG%mLayerVolFracLiq)%dat(1:nSnow) + write(*,'(a,1x,10(f12.8,1x))') 'iLayerLiqFluxSnow = ', flux_data%var(iLookFLUX%iLayerLiqFluxSnow)%dat*iden_water*data_step + write(*,'(a,1x,10(f12.8,1x))') 'mLayerLiqFluxSnow = ', flux_data%var(iLookFLUX%mLayerLiqFluxSnow)%dat*data_step + write(*,'(a,1x,10(f12.8,1x))') 'change volFracLiq = ', prog_data%var(iLookPROG%mLayerVolFracLiq)%dat(1:nSnow) - liqSnowInit + deallocate(liqSnowInit, stat=err) + if(err/=0)then + message=trim(message)//'unable to deallocate space for the initial volumetric liquid water content of snow' + print*, message + err=20; return + endif endif - endif - - ! check SWE - if(nSnow>0)then - effSnowfall = averageThroughfallSnow + averageCanopySnowUnloading - effRainfall = averageThroughfallRain + averageCanopyLiqDrainage - newSWE = prog_data%var(iLookPROG%scalarSWE)%dat(1) - delSWE = newSWE - (oldSWE - sfcMeltPond) - massBalance = delSWE - (effSnowfall + effRainfall + averageSnowSublimation - averageSnowDrainage*iden_water)*data_step - if(abs(massBalance) > 1.d-6)then - print*, 'nSnow = ', nSnow - print*, 'nSub = ', nSub - write(*,'(a,1x,f20.10)') 'data_step = ', data_step - write(*,'(a,1x,f20.10)') 'oldSWE = ', oldSWE - write(*,'(a,1x,f20.10)') 'newSWE = ', newSWE - write(*,'(a,1x,f20.10)') 'delSWE = ', delSWE - write(*,'(a,1x,f20.10)') 'effRainfall = ', effRainfall*data_step - write(*,'(a,1x,f20.10)') 'effSnowfall = ', effSnowfall*data_step - write(*,'(a,1x,f20.10)') 'sublimation = ', averageSnowSublimation*data_step - write(*,'(a,1x,f20.10)') 'snwDrainage = ', averageSnowDrainage*iden_water*data_step - write(*,'(a,1x,f20.10)') 'sfcMeltPond = ', sfcMeltPond - write(*,'(a,1x,f20.10)') 'massBalance = ', massBalance - message=trim(message)//'SWE does not balance' - err=20; return - endif ! if failed mass balance check - endif ! if snow layers exist - - ! ----- - ! * balance checks for soil... - ! ---------------------------- - - ! compute the liquid water and ice content at the end of the time step - scalarTotalSoilLiq = sum(iden_water*mLayerVolFracLiq(1:nSoil)*mLayerDepth(1:nSoil)) - scalarTotalSoilIce = sum(iden_water*mLayerVolFracIce(1:nSoil)*mLayerDepth(1:nSoil)) ! NOTE: no expansion of soil, hence use iden_water - - ! get the total water in the soil (liquid plus ice) at the end of the time step (kg m-2) - balanceSoilWater1 = scalarTotalSoilLiq + scalarTotalSoilIce - - ! get the total aquifer storage at the start of the time step (kg m-2) - balanceAquifer1 = scalarAquiferStorage*iden_water - - ! get the input and output to/from the soil zone (kg m-2) - balanceSoilInflux = averageSoilInflux*iden_water*data_step - balanceSoilBaseflow = averageSoilBaseflow*iden_water*data_step - balanceSoilDrainage = averageSoilDrainage*iden_water*data_step - balanceSoilET = (averageCanopyTranspiration + averageGroundEvaporation)*data_step - - ! check the individual layers - if(printBalance)then - write(*,'(a,1x,10(f12.8,1x))') 'liqSoilInit = ', liqSoilInit - write(*,'(a,1x,10(f12.8,1x))') 'volFracLiq = ', mLayerVolFracLiq - write(*,'(a,1x,10(f12.8,1x))') 'iLayerLiqFluxSoil = ', flux_data%var(iLookFLUX%iLayerLiqFluxSoil)%dat*iden_water*data_step - write(*,'(a,1x,10(f12.8,1x))') 'mLayerLiqFluxSoil = ', flux_data%var(iLookFLUX%mLayerLiqFluxSoil)%dat*data_step - write(*,'(a,1x,10(f12.8,1x))') 'change volFracLiq = ', mLayerVolFracLiq - liqSoilInit - deallocate(liqSoilInit, stat=err) - if(err/=0)then - message=trim(message)//'unable to deallocate space for the initial soil moisture' - err=20; return + + ! check SWE + if(nSnow>0)then + effSnowfall = averageThroughfallSnow + averageCanopySnowUnloading + effRainfall = averageThroughfallRain + averageCanopyLiqDrainage + newSWE = prog_data%var(iLookPROG%scalarSWE)%dat(1) + delSWE = newSWE - (oldSWE - sfcMeltPond) + massBalance = delSWE - (effSnowfall + effRainfall + averageSnowSublimation - averageSnowDrainage*iden_water)*data_step + if(abs(massBalance) > 1.d-6)then + print*, 'nSnow = ', nSnow + print*, 'nSub = ', nSub + write(*,'(a,1x,f20.10)') 'data_step = ', data_step + write(*,'(a,1x,f20.10)') 'oldSWE = ', oldSWE + write(*,'(a,1x,f20.10)') 'newSWE = ', newSWE + write(*,'(a,1x,f20.10)') 'delSWE = ', delSWE + write(*,'(a,1x,f20.10)') 'effRainfall = ', effRainfall*data_step + write(*,'(a,1x,f20.10)') 'effSnowfall = ', effSnowfall*data_step + write(*,'(a,1x,f20.10)') 'sublimation = ', averageSnowSublimation*data_step + write(*,'(a,1x,f20.10)') 'snwDrainage = ', averageSnowDrainage*iden_water*data_step + write(*,'(a,1x,f20.10)') 'sfcMeltPond = ', sfcMeltPond + write(*,'(a,1x,f20.10)') 'massBalance = ', massBalance + message=trim(message)//'SWE does not balance' + print*,message + err=20; return + endif ! if failed mass balance check + endif ! if snow layers exist + + ! ----- + ! * balance checks for soil... + ! ---------------------------- + + ! compute the liquid water and ice content at the end of the time step + scalarTotalSoilLiq = sum(iden_water*mLayerVolFracLiq(1:nSoil)*mLayerDepth(1:nSoil)) + scalarTotalSoilIce = sum(iden_water*mLayerVolFracIce(1:nSoil)*mLayerDepth(1:nSoil)) ! NOTE: no expansion of soil, hence use iden_water + + ! get the total water in the soil (liquid plus ice) at the end of the time step (kg m-2) + balanceSoilWater1 = scalarTotalSoilLiq + scalarTotalSoilIce + + ! get the total aquifer storage at the start of the time step (kg m-2) + balanceAquifer1 = scalarAquiferStorage*iden_water + + ! get the input and output to/from the soil zone (kg m-2) + balanceSoilInflux = averageSoilInflux*iden_water*data_step + balanceSoilBaseflow = averageSoilBaseflow*iden_water*data_step + balanceSoilDrainage = averageSoilDrainage*iden_water*data_step + balanceSoilET = (averageCanopyTranspiration + averageGroundEvaporation)*data_step + + ! check the individual layers + if(printBalance)then + write(*,'(a,1x,10(f12.8,1x))') 'liqSoilInit = ', liqSoilInit + write(*,'(a,1x,10(f12.8,1x))') 'volFracLiq = ', mLayerVolFracLiq + write(*,'(a,1x,10(f12.8,1x))') 'iLayerLiqFluxSoil = ', flux_data%var(iLookFLUX%iLayerLiqFluxSoil)%dat*iden_water*data_step + write(*,'(a,1x,10(f12.8,1x))') 'mLayerLiqFluxSoil = ', flux_data%var(iLookFLUX%mLayerLiqFluxSoil)%dat*data_step + write(*,'(a,1x,10(f12.8,1x))') 'change volFracLiq = ', mLayerVolFracLiq - liqSoilInit + deallocate(liqSoilInit, stat=err) + if(err/=0)then + message=trim(message)//'unable to deallocate space for the initial soil moisture' + err=20; return + print*, message + endif endif - endif - - ! check the soil water balance - scalarSoilWatBalError = balanceSoilWater1 - (balanceSoilWater0 + (balanceSoilInflux + balanceSoilET - balanceSoilBaseflow - balanceSoilDrainage - totalSoilCompress) ) - if(abs(scalarSoilWatBalError) > absConvTol_liquid*iden_water*10._dp)then ! NOTE: kg m-2, so need coarse tolerance to account for precision issues - write(*,*) 'solution method = ', ixSolution - write(*,'(a,1x,f20.10)') 'data_step = ', data_step - write(*,'(a,1x,f20.10)') 'totalSoilCompress = ', totalSoilCompress - write(*,'(a,1x,f20.10)') 'scalarTotalSoilLiq = ', scalarTotalSoilLiq - write(*,'(a,1x,f20.10)') 'scalarTotalSoilIce = ', scalarTotalSoilIce - write(*,'(a,1x,f20.10)') 'balanceSoilWater0 = ', balanceSoilWater0 - write(*,'(a,1x,f20.10)') 'balanceSoilWater1 = ', balanceSoilWater1 - write(*,'(a,1x,f20.10)') 'balanceSoilInflux = ', balanceSoilInflux - write(*,'(a,1x,f20.10)') 'balanceSoilBaseflow = ', balanceSoilBaseflow - write(*,'(a,1x,f20.10)') 'balanceSoilDrainage = ', balanceSoilDrainage - write(*,'(a,1x,f20.10)') 'balanceSoilET = ', balanceSoilET - write(*,'(a,1x,f20.10)') 'scalarSoilWatBalError = ', scalarSoilWatBalError - write(*,'(a,1x,f20.10)') 'scalarSoilWatBalError = ', scalarSoilWatBalError/iden_water - write(*,'(a,1x,f20.10)') 'absConvTol_liquid = ', absConvTol_liquid - ! error control - message=trim(message)//'soil hydrology does not balance' - err=20; return - end if - ! end association of local variables with information in the data structures - end associate + ! check the soil water balance + scalarSoilWatBalError = balanceSoilWater1 - (balanceSoilWater0 + (balanceSoilInflux + balanceSoilET - balanceSoilBaseflow - balanceSoilDrainage - totalSoilCompress) ) + if(abs(scalarSoilWatBalError) > absConvTol_liquid*iden_water*10._dp)then ! NOTE: kg m-2, so need coarse tolerance to account for precision issues + write(*,*) 'solution method = ', ixSolution + write(*,'(a,1x,f20.10)') 'data_step = ', data_step + write(*,'(a,1x,f20.10)') 'totalSoilCompress = ', totalSoilCompress + write(*,'(a,1x,f20.10)') 'scalarTotalSoilLiq = ', scalarTotalSoilLiq + write(*,'(a,1x,f20.10)') 'scalarTotalSoilIce = ', scalarTotalSoilIce + write(*,'(a,1x,f20.10)') 'balanceSoilWater0 = ', balanceSoilWater0 + write(*,'(a,1x,f20.10)') 'balanceSoilWater1 = ', balanceSoilWater1 + write(*,'(a,1x,f20.10)') 'balanceSoilInflux = ', balanceSoilInflux + write(*,'(a,1x,f20.10)') 'balanceSoilBaseflow = ', balanceSoilBaseflow + write(*,'(a,1x,f20.10)') 'balanceSoilDrainage = ', balanceSoilDrainage + write(*,'(a,1x,f20.10)') 'balanceSoilET = ', balanceSoilET + write(*,'(a,1x,f20.10)') 'scalarSoilWatBalError = ', scalarSoilWatBalError + write(*,'(a,1x,f20.10)') 'scalarSoilWatBalError = ', scalarSoilWatBalError/iden_water + write(*,'(a,1x,f20.10)') 'absConvTol_liquid = ', absConvTol_liquid + ! error control + message=trim(message)//'soil hydrology does not balance' + print*, message + err=20; return + end if - ! end association to canopy depth - end associate canopy + ! end association of local variables with information in the data structures + end associate - ! Save the total soil water (Liquid+Ice) - diag_data%var(iLookDIAG%scalarTotalSoilWat)%dat(1) = balanceSoilWater1 - ! save the surface temperature (just to make things easier to visualize) - prog_data%var(iLookPROG%scalarSurfaceTemp)%dat(1) = prog_data%var(iLookPROG%mLayerTemp)%dat(1) + ! end association to canopy depth + end associate canopy - ! overwrite flux data with the timestep-average value - if(.not.backwardsCompatibility)then - do iVar=1,size(flux_mean%var) - flux_data%var(averageFlux_meta(iVar)%ixParent)%dat = flux_mean%var(iVar)%dat - end do - end if + ! Save the total soil water (Liquid+Ice) + diag_data%var(iLookDIAG%scalarTotalSoilWat)%dat(1) = balanceSoilWater1 + ! save the surface temperature (just to make things easier to visualize) + prog_data%var(iLookPROG%scalarSurfaceTemp)%dat(1) = prog_data%var(iLookPROG%mLayerTemp)%dat(1) + + ! overwrite flux data with the timestep-average value + if(.not.backwardsCompatibility)then + do iVar=1,size(flux_mean%var) + flux_data%var(averageFlux_meta(iVar)%ixParent)%dat = flux_mean%var(iVar)%dat + end do + end if - iLayer = nSnow+1 - !print*, 'nsub, mLayerTemp(iLayer), mLayerVolFracIce(iLayer) = ', nsub, mLayerTemp(iLayer), mLayerVolFracIce(iLayer) - !print*, 'nsub = ', nsub - if(nsub>50000)then - write(message,'(a,i0)') trim(cmessage)//'number of sub-steps > 50000 for HRU ', indxHRU - err=20; return - end if + iLayer = nSnow+1 + !print*, 'nsub, mLayerTemp(iLayer), mLayerVolFracIce(iLayer) = ', nsub, mLayerTemp(iLayer), mLayerVolFracIce(iLayer) + !print*, 'nsub = ', nsub + if(nsub>50000)then + write(message,'(a,i0)') trim(cmessage)//'number of sub-steps > 50000 for HRU ', indxHRU + err=20; return + end if - end subroutine coupled_em +end subroutine coupled_em ! ********************************************************************************************************* diff --git a/build/source/engine/opSplittin.f90 b/build/source/engine/opSplittin.f90 index 38a175d..e329f62 100755 --- a/build/source/engine/opSplittin.f90 +++ b/build/source/engine/opSplittin.f90 @@ -100,6 +100,7 @@ USE data_types,only:& var_flagVec, & ! data vector with variable length dimension (i4b) var_ilength, & ! data vector with variable length dimension (i4b) var_dlength, & ! data vector with variable length dimension (dp) + zLookup, & model_options ! defines the model decisions ! look-up values for the choice of groundwater representation (local-column, or single-basin) @@ -183,6 +184,7 @@ contains diag_data, & ! intent(inout): model diagnostic variables for a local HRU flux_data, & ! intent(inout): model fluxes for a local HRU bvar_data, & ! intent(in): model variables for the local basin + lookup_data, & ! intent(in): lookup tables model_decisions,& ! intent(in): model decisions ! output: model control dtMultiplier, & ! intent(out): substep multiplier (-) @@ -223,6 +225,7 @@ contains type(var_dlength),intent(inout) :: diag_data ! diagnostic variables for a local HRU type(var_dlength),intent(inout) :: flux_data ! model fluxes for a local HRU type(var_dlength),intent(in) :: bvar_data ! model variables for the local basin + type(zLookup),intent(in) :: lookup_data ! lookup tables type(model_options),intent(in) :: model_decisions(:) ! model decisions ! output: model control real(dp),intent(out) :: dtMultiplier ! substep multiplier (-) diff --git a/build/source/engine/sundials/computSnowDepth.f90 b/build/source/engine/sundials/computSnowDepth.f90 new file mode 100644 index 0000000..9332798 --- /dev/null +++ b/build/source/engine/sundials/computSnowDepth.f90 @@ -0,0 +1,150 @@ +module computSnowDepth_module + +! data types +USE nrtype + +! physical constants +USE multiconst,only:& + Tfreeze, & ! temperature at freezing (K) + LH_fus, & ! latent heat of fusion (J kg-1) + LH_sub, & ! latent heat of sublimation (J kg-1) + iden_ice, & ! intrinsic density of ice (kg m-3) + iden_water ! intrinsic density of liquid water (kg m-3) + +! data types +USE data_types,only:& + var_i, & ! x%var(:) (i4b) + var_d, & ! x%var(:) (rkind) + var_ilength, & ! x%var(:)%dat (i4b) + var_dlength, & ! x%var(:)%dat (rkind) + zLookup ! x%z(:)%var(:)%lookup(:) (rkind) + +! named variables for parent structures +USE var_lookup,only:iLookDECISIONS ! named variables for elements of the decision structure +USE var_lookup,only:iLookPROG ! named variables for structure elements +USE var_lookup,only:iLookDIAG ! named variables for structure elements +USE var_lookup,only:iLookFLUX ! named variables for structure elements +USE var_lookup,only:iLookPARAM ! named variables for structure elements +USE var_lookup,only:iLookINDEX ! named variables for structure elements +USE globalData,only:iname_snow ! named variables for snow +USE globalData,only:iname_soil ! named variables for soil + + +! privacy +implicit none +private +public::computSnowDepth + +real(rkind),parameter :: verySmall=1.e-6_rkind ! used as an additive constant to check if substantial difference among real numbers + +contains + + ! ************************************************************************************************ + ! public subroutine computSnowDepth: compute snow depth for one sub timestep + ! ************************************************************************************************ + subroutine computSnowDepth(& + dt_sub, & + nSnow, & ! intent(in) + scalarSnowSublimation, & ! intent(in) + mLayerVolFracLiq, & ! intent(inout) + mLayerVolFracIce, & ! intent(inout) + mLayerTemp, & ! intent(in) + mLayerMeltFreeze, & ! intent(in) + mpar_data, & ! intent(in) + ! output + tooMuchSublim, & ! intent(out): flag to denote that there was too much sublimation in a given time step + mLayerDepth, & ! intent(inout) + ! error control + err,message) ! intent(out): error control + + USE snwDensify_module,only:snwDensify ! snow densification (compaction and cavitation) + + implicit none + real(qp),intent(in) :: dt_sub + integer(i4b),intent(in) :: nSnow ! number of snow layers + real(rkind),intent(in) :: scalarSnowSublimation + real(rkind),intent(inout) :: mLayerVolFracLiq(:) + real(rkind),intent(inout) :: mLayerVolFracIce(:) + real(rkind),intent(in) :: mLayerTemp(:) + real(rkind),intent(in) :: mLayerMeltFreeze(:) + type(var_dlength),intent(in) :: mpar_data ! model parameters + logical(lgt) :: tooMuchSublim ! flag to denote that there was too much sublimation in a given time step + real(rkind),intent(inout) :: mLayerDepth(:) + + integer(i4b),intent(out) :: err ! error code + character(*),intent(out) :: message ! error message + + ! local variables + character(len=256) :: cmessage ! error message + integer(i4b) :: iSnow ! index of snow layers + real(rkind) :: massLiquid ! mass liquid water (kg m-2) + + ! * compute change in ice content of the top snow layer due to sublimation... + ! --------------------------------------------------------------------------- + ! initialize the flags + tooMuchSublim=.false. ! too much sublimination (merge snow layers) + ! NOTE: this is done BEFORE densification + if(nSnow > 0)then ! snow layers exist + + ! try to remove ice from the top layer + iSnow=1 + + ! save the mass of liquid water (kg m-2) + massLiquid = mLayerDepth(iSnow)*mLayerVolFracLiq(iSnow)*iden_water + + ! add/remove the depth of snow gained/lost by frost/sublimation (m) + ! NOTE: assume constant density + mLayerDepth(iSnow) = mLayerDepth(iSnow) + dt_sub*scalarSnowSublimation/(mLayerVolFracIce(iSnow)*iden_ice) + + ! check that we did not remove the entire layer + if(mLayerDepth(iSnow) < verySmall)then + tooMuchSublim=.true. + return + endif + + ! update the volumetric fraction of liquid water + mLayerVolFracLiq(iSnow) = massLiquid / (mLayerDepth(iSnow)*iden_water) + + ! no snow + else + + ! no snow: check that sublimation is zero + if(abs(scalarSnowSublimation) > verySmall)then + message=trim(message)//'sublimation of snow has been computed when no snow exists' + err=20; return + end if + + end if ! (if snow layers exist) + + + ! *** account for compaction and cavitation in the snowpack... + ! ------------------------------------------------------------ + if(nSnow>0)then + call snwDensify(& + ! intent(in): variables + dt_sub, & ! intent(in): time step (s) + nSnow, & ! intent(in): number of snow layers + mLayerTemp(1:nSnow), & ! intent(in): temperature of each layer (K) + mLayerMeltFreeze(1:nSnow), & ! intent(in): volumetric melt in each layer (kg m-3) + ! intent(in): parameters + mpar_data%var(iLookPARAM%densScalGrowth)%dat(1), & ! intent(in): density scaling factor for grain growth (kg-1 m3) + mpar_data%var(iLookPARAM%tempScalGrowth)%dat(1), & ! intent(in): temperature scaling factor for grain growth (K-1) + mpar_data%var(iLookPARAM%grainGrowthRate)%dat(1), & ! intent(in): rate of grain growth (s-1) + mpar_data%var(iLookPARAM%densScalOvrbdn)%dat(1), & ! intent(in): density scaling factor for overburden pressure (kg-1 m3) + mpar_data%var(iLookPARAM%tempScalOvrbdn)%dat(1), & ! intent(in): temperature scaling factor for overburden pressure (K-1) + mpar_data%var(iLookPARAM%baseViscosity)%dat(1), & ! intent(in): viscosity coefficient at T=T_frz and snow density=0 (kg m-2 s) + ! intent(inout): state variables + mLayerDepth(1:nSnow), & ! intent(inout): depth of each layer (m) + mLayerVolFracLiq(1:nSnow), & ! intent(inout): volumetric fraction of liquid water after itertations (-) + mLayerVolFracIce(1:nSnow), & ! intent(inout): volumetric fraction of ice after itertations (-) + ! output: error control + err,cmessage) ! intent(out): error control + if(err/=0)then; err=55; message=trim(message)//trim(cmessage); return; end if + end if ! if snow layers exist + + + end subroutine computSnowDepth + + +end module computSnowDepth_module + diff --git a/build/source/engine/t2enthalpy.f90 b/build/source/engine/sundials/t2enthalpy.f90 similarity index 100% rename from build/source/engine/t2enthalpy.f90 rename to build/source/engine/sundials/t2enthalpy.f90 -- GitLab