diff --git a/build/source/driver/SummaActors_modelRun.f90 b/build/source/driver/SummaActors_modelRun.f90 index 3310197b9d4d11d891122068989d35fb0189b288..d5a48b3cbba85cce465a8ab9b7f11e2b48d98a7a 100755 --- a/build/source/driver/SummaActors_modelRun.f90 +++ b/build/source/driver/SummaActors_modelRun.f90 @@ -187,7 +187,11 @@ contains fracJulDay, & yearLength, & err,cmessage) ! intent(out): error control - if(err/=0)then; message=trim(message)//trim(cmessage); return; endif + if(err/=0)then + message=trim(message)//trim(cmessage) + print*, message + return + endif ! save the flag for computing the vegetation fluxes if(computeVegFluxFlag) computeVegFlux = yes @@ -215,7 +219,7 @@ contains bvarStruct%var(iLookBVAR%basin__SurfaceRunoff)%dat(1) = 0._dp ! surface runoff (m s-1) bvarStruct%var(iLookBVAR%basin__SoilDrainage)%dat(1) = 0._dp bvarStruct%var(iLookBVAR%basin__ColumnOutflow)%dat(1) = 0._dp ! outflow from all "outlet" HRUs (those with no downstream HRU) - bvarStruct%var(iLookBVAR%basin__TotalRunoff)%dat(1) = 0._dp + bvarStruct%var(iLookBVAR%basin__TotalRunoff)%dat(1) = 0._dp ! initialize baseflow variables bvarStruct%var(iLookBVAR%basin__AquiferRecharge)%dat(1) = 0._dp ! recharge to the aquifer (m s-1) @@ -244,6 +248,7 @@ contains allocate(zSoilReverseSign(nSoil),stat=err) if(err/=0)then message=trim(message)//'problem allocating space for zSoilReverseSign' + print*, message err=20; return endif zSoilReverseSign(:) = -progStruct%var(iLookPROG%iLayerHeight)%dat(nSnow+1:nLayers) @@ -262,6 +267,7 @@ contains deallocate(zSoilReverseSign,stat=err) if(err/=0)then message=trim(message)//'problem deallocating space for zSoilReverseSign' + print*, message err=20; return endif @@ -290,7 +296,12 @@ contains fluxStruct, & ! data structure of model fluxes tmZoneOffsetFracDay,& err,cmessage) ! error control - if(err/=0)then; err=20; message=trim(message)//trim(cmessage); return; endif + if(err/=0)then + err=20 + message=trim(message)//trim(cmessage) + print*, message + return +endif ! initialize the number of flux calls diagStruct%var(iLookDIAG%numFluxCalls)%dat(1) = 0._dp diff --git a/build/source/engine/coupled_em.f90 b/build/source/engine/coupled_em.f90 index de184bfdf69ef4679b9053bcf18412e36fdeae80..964bb2ea1f72cec4260ad3672e1bc5f1ba777bf6 100755 --- a/build/source/engine/coupled_em.f90 +++ b/build/source/engine/coupled_em.f90 @@ -120,333 +120,371 @@ subroutine coupled_em(& yearLength, & ! error control err,message) ! intent(out): error control - ! structure allocations - USE allocspace4chm_module,only:allocLocal ! allocate local data structures - USE allocspace4chm_module,only:resizeData ! clone a data structure - ! preliminary subroutines - USE vegPhenlgy_module,only:vegPhenlgy ! compute vegetation phenology - USE vegNrgFlux_module,only:wettedFrac ! compute wetted fraction of the canopy (used in sw radiation fluxes) - USE snowAlbedo_module,only:snowAlbedo ! compute snow albedo - USE vegSWavRad_module,only:vegSWavRad ! compute canopy sw radiation fluxes - USE canopySnow_module,only:canopySnow ! compute interception and unloading of snow from the vegetation canopy - USE volicePack_module,only:newsnwfall ! compute change in the top snow layer due to throughfall and unloading - USE volicePack_module,only:volicePack ! merge and sub-divide snow layers, if necessary - USE diagn_evar_module,only:diagn_evar ! compute diagnostic energy variables -- thermal conductivity and heat capacity - ! the model solver - USE indexState_module,only:indexState ! define indices for all model state variables and layers - USE opSplittin_module,only:opSplittin ! solve the system of thermodynamic and hydrology equations for a given substep - ! additional subroutines - 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 - ! look-up values for the numerical method - USE mDecisions_module,only: & - iterative, & ! iterative - nonIterative, & ! non-iterative - iterSurfEnergyBal ! iterate only on the surface energy balance - ! look-up values for the maximum interception capacity - USE mDecisions_module,only: & - stickySnow, & ! maximum interception capacity an increasing function of temerature - lightSnow ! maximum interception capacity an inverse function of new snow density - implicit none - ! model control - integer(4),intent(in) :: indxHRU ! hruId - real(dp),intent(inout) :: dt_init ! used to initialize the size of the sub-step - integer(i4b),intent(in) :: dt_init_factor ! Used to adjust the length of the timestep in the event of a failure - logical(lgt),intent(inout) :: computeVegFlux ! flag to indicate if we are computing fluxes over vegetation (.false. means veg is buried with snow) - ! data structures (input) - type(var_i),intent(in) :: type_data ! type of vegetation and soil - type(var_d),intent(in) :: attr_data ! spatial attributes - 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 - ! 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 - 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 - real(dp),intent(inout) :: fracJulDay - integer(i4b),intent(inout) :: yearLength - ! error control - integer(i4b),intent(out) :: err ! error code - character(*),intent(out) :: message ! error message - ! ===================================================================================================================================================== - ! ===================================================================================================================================================== - ! local variables - character(len=256) :: cmessage ! error message - integer(i4b) :: nSnow ! number of snow layers - integer(i4b) :: nSoil ! number of soil layers - integer(i4b) :: nLayers ! total number of layers - integer(i4b) :: nState ! total number of state variables - real(dp) :: dtSave ! length of last input model sub-step (seconds) - real(dp) :: dt_sub ! length of model sub-step (seconds) - real(dp) :: dt_wght ! weight applied to model sub-step (dt_sub/data_step) - real(dp) :: dt_solv ! seconds in the data step that have been completed - real(dp) :: dtMultiplier ! time step multiplier (-) based on what happenned in "opSplittin" - real(dp) :: minstep,maxstep ! minimum and maximum time step length (seconds) - integer(i4b) :: nsub ! number of substeps - logical(lgt) :: computeVegFluxOld ! flag to indicate if we are computing fluxes over vegetation on the previous sub step - logical(lgt) :: includeAquifer ! flag to denote that an aquifer is included - logical(lgt) :: modifiedLayers ! flag to denote that snow layers were modified - logical(lgt) :: modifiedVegState ! flag to denote that vegetation states were modified - type(var_dlength) :: flux_mean ! timestep-average model fluxes for a local HRU - integer(i4b) :: nLayersRoots ! number of soil layers that contain roots - real(dp) :: exposedVAI ! exposed vegetation area index - real(dp) :: dCanopyWetFraction_dWat ! derivative in wetted fraction w.r.t. canopy total water (kg-1 m2) - real(dp) :: dCanopyWetFraction_dT ! derivative in wetted fraction w.r.t. canopy temperature (K-1) - real(dp),parameter :: varNotUsed1=-9999._dp ! variables used to calculate derivatives (not needed here) - real(dp),parameter :: varNotUsed2=-9999._dp ! variables used to calculate derivatives (not needed here) - integer(i4b) :: iSnow ! index of snow layers - integer(i4b) :: iLayer ! index of model layers - real(dp) :: massLiquid ! mass liquid water (kg m-2) - real(dp) :: superflousSub ! superflous sublimation (kg m-2 s-1) - real(dp) :: superflousNrg ! superflous energy that cannot be used for sublimation (W m-2 [J m-2 s-1]) - integer(i4b) :: ixSolution ! solution method used by opSplitting - logical(lgt) :: firstSubStep ! flag to denote if the first time step - logical(lgt) :: stepFailure ! flag to denote the need to reduce length of the coupled step and try again - logical(lgt) :: tooMuchMelt ! flag to denote that there was too much melt in a given time step - logical(lgt) :: doLayerMerge ! flag to denote the need to merge snow layers - logical(lgt) :: pauseFlag ! flag to pause execution - logical(lgt),parameter :: backwardsCompatibility=.true. ! flag to denote a desire to ensure backwards compatibility with previous branches. - type(var_ilength) :: indx_temp ! temporary model index variables - type(var_dlength) :: prog_temp ! temporary model prognostic variables - type(var_dlength) :: diag_temp ! temporary model diagnostic variables - ! check SWE - real(dp) :: oldSWE ! SWE at the start of the substep - real(dp) :: newSWE ! SWE at the end of the substep - real(dp) :: delSWE ! change in SWE over the subtep - real(dp) :: effRainfall ! effective rainfall (kg m-2 s-1) - real(dp) :: effSnowfall ! effective snowfall (kg m-2 s-1) - real(dp) :: sfcMeltPond ! surface melt pond (kg m-2) - real(dp) :: massBalance ! mass balance error (kg m-2) - ! balance checks - integer(i4b) :: iVar ! loop through model variables - real(dp) :: totalSoilCompress ! total soil compression (kg m-2) - real(dp) :: scalarCanopyWatBalError ! water balance error for the vegetation canopy (kg m-2) - real(dp) :: scalarSoilWatBalError ! water balance error (kg m-2) - real(dp) :: scalarInitCanopyLiq ! initial liquid water on the vegetation canopy (kg m-2) - real(dp) :: scalarInitCanopyIce ! initial ice on the vegetation canopy (kg m-2) - real(dp) :: balanceCanopyWater0 ! total water stored in the vegetation canopy at the start of the step (kg m-2) - real(dp) :: balanceCanopyWater1 ! total water stored in the vegetation canopy at the end of the step (kg m-2) - real(dp) :: balanceSoilWater0 ! total soil storage at the start of the step (kg m-2) - real(dp) :: balanceSoilWater1 ! total soil storage at the end of the step (kg m-2) - real(dp) :: balanceSoilInflux ! input to the soil zone - real(dp) :: balanceSoilBaseflow ! output from the soil zone - real(dp) :: balanceSoilDrainage ! output from the soil zone - real(dp) :: balanceSoilET ! output from the soil zone - real(dp) :: balanceAquifer0 ! total aquifer storage at the start of the step (kg m-2) - real(dp) :: balanceAquifer1 ! total aquifer storage at the end of the step (kg m-2) - ! test balance checks - logical(lgt), parameter :: printBalance=.false. ! flag to print the balance checks - 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 - ! ---------------------------------------------------------------------------------------------------------------------------------------------- - ! initialize error control - err=0; message="coupled_em/" + ! structure allocations + USE allocspace4chm_module,only:allocLocal ! allocate local data structures + USE allocspace4chm_module,only:resizeData ! clone a data structure + ! preliminary subroutines + USE vegPhenlgy_module,only:vegPhenlgy ! compute vegetation phenology + USE vegNrgFlux_module,only:wettedFrac ! compute wetted fraction of the canopy (used in sw radiation fluxes) + USE snowAlbedo_module,only:snowAlbedo ! compute snow albedo + USE vegSWavRad_module,only:vegSWavRad ! compute canopy sw radiation fluxes + USE canopySnow_module,only:canopySnow ! compute interception and unloading of snow from the vegetation canopy + USE volicePack_module,only:newsnwfall ! compute change in the top snow layer due to throughfall and unloading + USE volicePack_module,only:volicePack ! merge and sub-divide snow layers, if necessary + USE diagn_evar_module,only:diagn_evar ! compute diagnostic energy variables -- thermal conductivity and heat capacity + ! the model solver + USE indexState_module,only:indexState ! define indices for all model state variables and layers + USE opSplittin_module,only:opSplittin ! solve the system of thermodynamic and hydrology equations for a given substep + ! additional subroutines + 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 + ! look-up values for the numerical method + USE mDecisions_module,only: & + iterative, & ! iterative + nonIterative, & ! non-iterative + iterSurfEnergyBal ! iterate only on the surface energy balance + ! look-up values for the maximum interception capacity + USE mDecisions_module,only: & + stickySnow, & ! maximum interception capacity an increasing function of temerature + lightSnow ! maximum interception capacity an inverse function of new snow density + implicit none + ! model control + integer(4),intent(in) :: indxHRU ! hruId + real(dp),intent(inout) :: dt_init ! used to initialize the size of the sub-step + integer(i4b),intent(in) :: dt_init_factor ! Used to adjust the length of the timestep in the event of a failure + logical(lgt),intent(inout) :: computeVegFlux ! flag to indicate if we are computing fluxes over vegetation (.false. means veg is buried with snow) + ! data structures (input) + type(var_i),intent(in) :: type_data ! type of vegetation and soil + type(var_d),intent(in) :: attr_data ! spatial attributes + 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 + ! 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 + 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 + real(dp),intent(inout) :: fracJulDay + integer(i4b),intent(inout) :: yearLength + ! error control + integer(i4b),intent(out) :: err ! error code + character(*),intent(out) :: message ! error message + ! ===================================================================================================================================================== + ! ===================================================================================================================================================== + ! local variables + character(len=256) :: cmessage ! error message + integer(i4b) :: nSnow ! number of snow layers + integer(i4b) :: nSoil ! number of soil layers + integer(i4b) :: nLayers ! total number of layers + integer(i4b) :: nState ! total number of state variables + real(dp) :: dtSave ! length of last input model sub-step (seconds) + real(dp) :: dt_sub ! length of model sub-step (seconds) + real(dp) :: dt_wght ! weight applied to model sub-step (dt_sub/data_step) + real(dp) :: dt_solv ! seconds in the data step that have been completed + real(dp) :: dtMultiplier ! time step multiplier (-) based on what happenned in "opSplittin" + real(dp) :: minstep,maxstep ! minimum and maximum time step length (seconds) + integer(i4b) :: nsub ! number of substeps + logical(lgt) :: computeVegFluxOld ! flag to indicate if we are computing fluxes over vegetation on the previous sub step + logical(lgt) :: includeAquifer ! flag to denote that an aquifer is included + logical(lgt) :: modifiedLayers ! flag to denote that snow layers were modified + logical(lgt) :: modifiedVegState ! flag to denote that vegetation states were modified + type(var_dlength) :: flux_mean ! timestep-average model fluxes for a local HRU + integer(i4b) :: nLayersRoots ! number of soil layers that contain roots + real(dp) :: exposedVAI ! exposed vegetation area index + real(dp) :: dCanopyWetFraction_dWat ! derivative in wetted fraction w.r.t. canopy total water (kg-1 m2) + real(dp) :: dCanopyWetFraction_dT ! derivative in wetted fraction w.r.t. canopy temperature (K-1) + real(dp),parameter :: varNotUsed1=-9999._dp ! variables used to calculate derivatives (not needed here) + real(dp),parameter :: varNotUsed2=-9999._dp ! variables used to calculate derivatives (not needed here) + integer(i4b) :: iSnow ! index of snow layers + integer(i4b) :: iLayer ! index of model layers + real(dp) :: massLiquid ! mass liquid water (kg m-2) + real(dp) :: superflousSub ! superflous sublimation (kg m-2 s-1) + real(dp) :: superflousNrg ! superflous energy that cannot be used for sublimation (W m-2 [J m-2 s-1]) + integer(i4b) :: ixSolution ! solution method used by opSplitting + logical(lgt) :: firstSubStep ! flag to denote if the first time step + logical(lgt) :: stepFailure ! flag to denote the need to reduce length of the coupled step and try again + logical(lgt) :: tooMuchMelt ! flag to denote that there was too much melt in a given time step + logical(lgt) :: doLayerMerge ! flag to denote the need to merge snow layers + logical(lgt) :: pauseFlag ! flag to pause execution + logical(lgt),parameter :: backwardsCompatibility=.true. ! flag to denote a desire to ensure backwards compatibility with previous branches. + type(var_ilength) :: indx_temp ! temporary model index variables + type(var_dlength) :: prog_temp ! temporary model prognostic variables + type(var_dlength) :: diag_temp ! temporary model diagnostic variables + ! check SWE + real(dp) :: oldSWE ! SWE at the start of the substep + real(dp) :: newSWE ! SWE at the end of the substep + real(dp) :: delSWE ! change in SWE over the subtep + real(dp) :: effRainfall ! effective rainfall (kg m-2 s-1) + real(dp) :: effSnowfall ! effective snowfall (kg m-2 s-1) + real(dp) :: sfcMeltPond ! surface melt pond (kg m-2) + real(dp) :: massBalance ! mass balance error (kg m-2) + ! balance checks + integer(i4b) :: iVar ! loop through model variables + real(dp) :: totalSoilCompress ! total soil compression (kg m-2) + real(dp) :: scalarCanopyWatBalError ! water balance error for the vegetation canopy (kg m-2) + real(dp) :: scalarSoilWatBalError ! water balance error (kg m-2) + real(dp) :: scalarInitCanopyLiq ! initial liquid water on the vegetation canopy (kg m-2) + real(dp) :: scalarInitCanopyIce ! initial ice on the vegetation canopy (kg m-2) + real(dp) :: balanceCanopyWater0 ! total water stored in the vegetation canopy at the start of the step (kg m-2) + real(dp) :: balanceCanopyWater1 ! total water stored in the vegetation canopy at the end of the step (kg m-2) + real(dp) :: balanceSoilWater0 ! total soil storage at the start of the step (kg m-2) + real(dp) :: balanceSoilWater1 ! total soil storage at the end of the step (kg m-2) + real(dp) :: balanceSoilInflux ! input to the soil zone + real(dp) :: balanceSoilBaseflow ! output from the soil zone + real(dp) :: balanceSoilDrainage ! output from the soil zone + real(dp) :: balanceSoilET ! output from the soil zone + real(dp) :: balanceAquifer0 ! total aquifer storage at the start of the step (kg m-2) + real(dp) :: balanceAquifer1 ! total aquifer storage at the end of the step (kg m-2) + ! test balance checks + logical(lgt), parameter :: printBalance=.false. ! flag to print the balance checks + 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) :: tooMuchSublim ! flag to denote that there was too much sublimation in a given time step + + + ! ---------------------------------------------------------------------------------------------------------------------------------------------- + ! initialize error control + err=0; message="coupled_em/" ! This is the start of a data step for a local HRU - ! check that the decision is supported - if(model_decisions(iLookDECISIONS%groundwatr)%iDecision==bigBucket .and. & - model_decisions(iLookDECISIONS%spatial_gw)%iDecision/=localColumn)then - message=trim(message)//'expect "spatial_gw" decision to equal localColumn when "groundwatr" decision is bigBucket' - err=20; return - endif - - ! check if the aquifer is included - includeAquifer = (model_decisions(iLookDECISIONS%groundwatr)%iDecision==bigBucket) - - ! initialize the numerix tracking variables - indx_data%var(iLookINDEX%numberFluxCalc )%dat(1) = 0 ! number of flux calculations (-) - indx_data%var(iLookINDEX%numberStateSplit )%dat(1) = 0 ! number of state splitting solutions (-) - indx_data%var(iLookINDEX%numberDomainSplitNrg )%dat(1) = 0 ! number of domain splitting solutions for energy (-) - indx_data%var(iLookINDEX%numberDomainSplitMass)%dat(1) = 0 ! number of domain splitting solutions for mass (-) - indx_data%var(iLookINDEX%numberScalarSolutions)%dat(1) = 0 ! number of scalar solutions (-) - - ! link canopy depth to the information in the data structure - canopy: associate(canopyDepth => diag_data%var(iLookDIAG%scalarCanopyDepth)%dat(1) ) ! intent(out): [dp] canopy depth (m) + ! check that the decision is supported + if(model_decisions(iLookDECISIONS%groundwatr)%iDecision==bigBucket .and. & + model_decisions(iLookDECISIONS%spatial_gw)%iDecision/=localColumn)then + message=trim(message)//'expect "spatial_gw" decision to equal localColumn when "groundwatr" decision is bigBucket' + err=20; return + endif + ! check if the aquifer is included + includeAquifer = (model_decisions(iLookDECISIONS%groundwatr)%iDecision==bigBucket) + + ! initialize the numerix tracking variables + indx_data%var(iLookINDEX%numberFluxCalc )%dat(1) = 0 ! number of flux calculations (-) + indx_data%var(iLookINDEX%numberStateSplit )%dat(1) = 0 ! number of state splitting solutions (-) + indx_data%var(iLookINDEX%numberDomainSplitNrg )%dat(1) = 0 ! number of domain splitting solutions for energy (-) + indx_data%var(iLookINDEX%numberDomainSplitMass)%dat(1) = 0 ! number of domain splitting solutions for mass (-) + indx_data%var(iLookINDEX%numberScalarSolutions)%dat(1) = 0 ! number of scalar solutions (-) + + ! link canopy depth to the information in the data structure + canopy: associate(canopyDepth => diag_data%var(iLookDIAG%scalarCanopyDepth)%dat(1) ) ! intent(out): [dp] canopy depth (m) + - ! start by NOT pausing - pauseFlag=.false. + ! start by NOT pausing + pauseFlag=.false. - ! start by assuming that the step is successful - stepFailure = .false. - doLayerMerge = .false. + ! start by assuming that the step is successful + stepFailure = .false. + doLayerMerge = .false. - ! initialize flags to modify the veg layers or modify snow layers - modifiedLayers = .false. ! flag to denote that snow layers were modified - modifiedVegState = .false. ! flag to denote that vegetation states were modified + ! initialize flags to modify the veg layers or modify snow layers + modifiedLayers = .false. ! flag to denote that snow layers were modified + modifiedVegState = .false. ! flag to denote that vegetation states were modified - ! define the first step - firstSubStep = .true. + ! define the first step + firstSubStep = .true. - ! count the number of snow and soil layers - ! NOTE: need to re-compute the number of snow and soil layers at the start of each sub-step because the number of layers may change - ! (nSnow and nSoil are shared in the data structure) - nSnow = count(indx_data%var(iLookINDEX%layerType)%dat==iname_snow) - nSoil = count(indx_data%var(iLookINDEX%layerType)%dat==iname_soil) + ! count the number of snow and soil layers + ! NOTE: need to re-compute the number of snow and soil layers at the start of each sub-step because the number of layers may change + ! (nSnow and nSoil are shared in the data structure) + nSnow = count(indx_data%var(iLookINDEX%layerType)%dat==iname_snow) + nSoil = count(indx_data%var(iLookINDEX%layerType)%dat==iname_soil) - ! compute the total number of snow and soil layers - nLayers = nSnow + nSoil - + ! compute the total number of snow and soil layers + nLayers = nSnow + nSoil + ! create temporary data structures for prognostic variables - call resizeData(prog_meta(:),prog_data,prog_temp,err=err,message=cmessage) - if(err/=0)then; err=20; message=trim(message)//trim(cmessage); return; endif + call resizeData(prog_meta(:),prog_data,prog_temp,err=err,message=cmessage) + if(err/=0)then + err=20 + message=trim(message)//trim(cmessage) + print*, message + return + endif - ! create temporary data structures for diagnostic variables - call resizeData(diag_meta(:),diag_data,diag_temp,err=err,message=cmessage) - if(err/=0)then; err=20; message=trim(message)//trim(cmessage); return; endif + ! create temporary data structures for diagnostic variables + call resizeData(diag_meta(:),diag_data,diag_temp,err=err,message=cmessage) + if(err/=0)then + err=20 + message=trim(message)//trim(cmessage) + print*, message + return + endif - ! create temporary data structures for index variables - call resizeData(indx_meta(:),indx_data,indx_temp,err=err,message=cmessage) - if(err/=0)then; err=20; message=trim(message)//trim(cmessage); return; endif + ! create temporary data structures for index variables + call resizeData(indx_meta(:),indx_data,indx_temp,err=err,message=cmessage) + if(err/=0)then + err=20 + message=trim(message)//trim(cmessage) + print*, message + return + endif - ! allocate space for the local fluxes - call allocLocal(averageFlux_meta(:)%var_info,flux_mean,nSnow,nSoil,err,cmessage) - if(err/=0)then; err=20; message=trim(message)//trim(cmessage); return; end if + ! allocate space for the local fluxes + call allocLocal(averageFlux_meta(:)%var_info,flux_mean,nSnow,nSoil,err,cmessage) + if(err/=0)then + err=20 + message=trim(message)//trim(cmessage) + print*, message + return + end if - ! initialize compression and surface melt pond - sfcMeltPond = 0._dp ! change in storage associated with the surface melt pond (kg m-2) - totalSoilCompress = 0._dp ! change in soil storage associated with compression of the matrix (kg m-2) + ! initialize compression and surface melt pond + sfcMeltPond = 0._dp ! change in storage associated with the surface melt pond (kg m-2) + totalSoilCompress = 0._dp ! change in soil storage associated with compression of the matrix (kg m-2) - ! initialize mean fluxes - do iVar=1,size(averageFlux_meta) - flux_mean%var(iVar)%dat(:) = 0._dp - end do + ! initialize mean fluxes + do iVar=1,size(averageFlux_meta) + flux_mean%var(iVar)%dat(:) = 0._dp + end do - ! associate local variables with information in the data structures - associate(& - ! 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) - 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) - scalarTotalSoilWat => diag_data%var(iLookDIAG%scalarTotalSoilWat)%dat(1) & ! total water in the soil column (kg m-2) - ) ! (association of local variables with information in the data structures - - ! save the liquid water and ice on the vegetation canopy - scalarInitCanopyLiq = scalarCanopyLiq ! initial liquid water on the vegetation canopy (kg m-2) - scalarInitCanopyIce = scalarCanopyIce ! initial ice on the vegetation canopy (kg m-2) - - ! compute total soil moisture and ice at the *START* of the step (kg m-2) - scalarTotalSoilLiq = sum(iden_water*mLayerVolFracLiq(1:nSoil)*mLayerDepth(1:nSoil)) - scalarTotalSoilIce = sum(iden_water*mLayerVolFracIce(1:nSoil)*mLayerDepth(1:nSoil)) ! NOTE: no expansion and hence use iden_water - - ! compute storage of water in the canopy and the soil - balanceCanopyWater0 = scalarCanopyLiq + scalarCanopyIce - balanceSoilWater0 = scalarTotalSoilLiq + scalarTotalSoilIce - - ! get the total aquifer storage at the start of the time step (kg m-2) - balanceAquifer0 = scalarAquiferStorage*iden_water - - ! save liquid water content - if(printBalance)then - allocate(liqSnowInit(nSnow), liqSoilInit(nSoil), stat=err) - if(err/=0)then - message=trim(message)//'unable to allocate space for the initial vectors' - err=20; return + ! associate local variables with information in the data structures + associate(& + ! 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) + 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) + scalarTotalSoilWat => diag_data%var(iLookDIAG%scalarTotalSoilWat)%dat(1) & ! total water in the soil column (kg m-2) + ) ! (association of local variables with information in the data structures + + ! save the liquid water and ice on the vegetation canopy + scalarInitCanopyLiq = scalarCanopyLiq ! initial liquid water on the vegetation canopy (kg m-2) + scalarInitCanopyIce = scalarCanopyIce ! initial ice on the vegetation canopy (kg m-2) + + ! compute total soil moisture and ice at the *START* of the step (kg m-2) + scalarTotalSoilLiq = sum(iden_water*mLayerVolFracLiq(1:nSoil)*mLayerDepth(1:nSoil)) + scalarTotalSoilIce = sum(iden_water*mLayerVolFracIce(1:nSoil)*mLayerDepth(1:nSoil)) ! NOTE: no expansion and hence use iden_water + + ! compute storage of water in the canopy and the soil + balanceCanopyWater0 = scalarCanopyLiq + scalarCanopyIce + balanceSoilWater0 = scalarTotalSoilLiq + scalarTotalSoilIce + + ! get the total aquifer storage at the start of the time step (kg m-2) + balanceAquifer0 = scalarAquiferStorage*iden_water + + ! save liquid water content + if(printBalance)then + allocate(liqSnowInit(nSnow), liqSoilInit(nSoil), stat=err) + if(err/=0)then + message=trim(message)//'unable to allocate space for the initial vectors' + print*,message + err=20; + return + endif + if(nSnow>0) liqSnowInit = prog_data%var(iLookPROG%mLayerVolFracLiq)%dat(1:nSnow) + liqSoilInit = mLayerVolFracLiq endif - if(nSnow>0) liqSnowInit = prog_data%var(iLookPROG%mLayerVolFracLiq)%dat(1:nSnow) - liqSoilInit = mLayerVolFracLiq - endif - - ! end association of local variables with information in the data structures - end associate - - ! short-cut to the algorithmic control parameters - ! NOTE - temporary assignment of minstep to foce something reasonable - minstep = 10._dp ! mpar_data%var(iLookPARAM%minstep)%dat(1) ! minimum time step (s) - maxstep = mpar_data%var(iLookPARAM%maxstep)%dat(1) ! maximum time step (s) - !print*, 'minstep, maxstep = ', minstep, maxstep + ! end association of local variables with information in the data structures + end associate + - ! compute the number of layers with roots - nLayersRoots = count(prog_data%var(iLookPROG%iLayerHeight)%dat(nSnow:nLayers-1) < mpar_data%var(iLookPARAM%rootingDepth)%dat(1)-verySmall) - if(nLayersRoots == 0)then - message=trim(message)//'no roots within the soil profile' - err=20; return - end if + ! short-cut to the algorithmic control parameters + ! NOTE - temporary assignment of minstep to foce something reasonable + minstep = 10._dp ! mpar_data%var(iLookPARAM%minstep)%dat(1) ! minimum time step (s) + maxstep = mpar_data%var(iLookPARAM%maxstep)%dat(1) ! maximum time step (s) + !print*, 'minstep, maxstep = ', minstep, maxstep + + ! compute the number of layers with roots + nLayersRoots = count(prog_data%var(iLookPROG%iLayerHeight)%dat(nSnow:nLayers-1) < mpar_data%var(iLookPARAM%rootingDepth)%dat(1)-verySmall) + if(nLayersRoots == 0)then + message=trim(message)//'no roots within the soil profile' + print*, message + err=20; return + end if - ! define the foliage nitrogen factor - diag_data%var(iLookDIAG%scalarFoliageNitrogenFactor)%dat(1) = 1._dp ! foliage nitrogen concentration (1.0 = saturated) + ! define the foliage nitrogen factor + diag_data%var(iLookDIAG%scalarFoliageNitrogenFactor)%dat(1) = 1._dp ! foliage nitrogen concentration (1.0 = saturated) - ! save SWE - oldSWE = prog_data%var(iLookPROG%scalarSWE)%dat(1) - !print*, 'nSnow = ', nSnow - !print*, 'oldSWE = ', oldSWE + ! save SWE + oldSWE = prog_data%var(iLookPROG%scalarSWE)%dat(1) + !print*, 'nSnow = ', nSnow + !print*, 'oldSWE = ', oldSWE - ! *** compute phenology... - ! ------------------------ - + ! *** compute phenology... + ! ------------------------ + - ! compute the temperature of the root zone: used in vegetation phenology - diag_data%var(iLookDIAG%scalarRootZoneTemp)%dat(1) = sum(prog_data%var(iLookPROG%mLayerTemp)%dat(nSnow+1:nSnow+nLayersRoots)) / real(nLayersRoots, kind(dp)) + ! compute the temperature of the root zone: used in vegetation phenology + diag_data%var(iLookDIAG%scalarRootZoneTemp)%dat(1) = sum(prog_data%var(iLookPROG%mLayerTemp)%dat(nSnow+1:nSnow+nLayersRoots)) / real(nLayersRoots, kind(dp)) - ! remember if we compute the vegetation flux on the previous sub-step - computeVegFluxOld = computeVegFlux + ! remember if we compute the vegetation flux on the previous sub-step + computeVegFluxOld = computeVegFlux - ! compute the exposed LAI and SAI and whether veg is buried by snow - call vegPhenlgy(& - ! input/output: data structures - model_decisions, & ! intent(in): model decisions - type_data, & ! intent(in): type of vegetation and soil - attr_data, & ! intent(in): spatial attributes - mpar_data, & ! intent(in): model parameters - prog_data, & ! intent(in): model prognostic variables for a local HRU - diag_data, & ! intent(inout): model diagnostic variables for a local HRU - ! output - computeVegFlux, & ! intent(out): flag to indicate if we are computing fluxes over vegetation (.false. means veg is buried with snow) - canopyDepth, & ! intent(out): canopy depth (m) - exposedVAI, & ! intent(out): exposed vegetation area index (m2 m-2) - fracJulDay, & ! fractional julian days since the start of year - yearLength, & ! number of days in the current year - err,cmessage) ! intent(out): error control - if(err/=0)then; err=20; message=trim(message)//trim(cmessage); return; end if + ! compute the exposed LAI and SAI and whether veg is buried by snow + call vegPhenlgy(& + ! input/output: data structures + model_decisions, & ! intent(in): model decisions + type_data, & ! intent(in): type of vegetation and soil + attr_data, & ! intent(in): spatial attributes + mpar_data, & ! intent(in): model parameters + prog_data, & ! intent(in): model prognostic variables for a local HRU + diag_data, & ! intent(inout): model diagnostic variables for a local HRU + ! output + computeVegFlux, & ! intent(out): flag to indicate if we are computing fluxes over vegetation (.false. means veg is buried with snow) + canopyDepth, & ! intent(out): canopy depth (m) + exposedVAI, & ! intent(out): exposed vegetation area index (m2 m-2) + fracJulDay, & ! fractional julian days since the start of year + yearLength, & ! number of days in the current year + err,cmessage) ! intent(out): error control + if(err/=0)then + err=20 + message=trim(message)//trim(cmessage) + print*, message + return + end if - ! check - if(computeVegFlux)then - if(canopyDepth < epsilon(canopyDepth))then - message=trim(message)//'canopy depth is zero when computeVegFlux flag is .true.' - err=20; return + ! check + if(computeVegFlux)then + if(canopyDepth < epsilon(canopyDepth))then + message=trim(message)//'canopy depth is zero when computeVegFlux flag is .true.' + print*, message + err=20; return + endif endif - endif - ! flag the case where number of vegetation states has changed - modifiedVegState = (computeVegFlux.neqv.computeVegFluxOld) - - ! *** compute wetted canopy area... - ! --------------------------------- - - ! compute maximum canopy liquid water (kg m-2) - diag_data%var(iLookDIAG%scalarCanopyLiqMax)%dat(1) = mpar_data%var(iLookPARAM%refInterceptCapRain)%dat(1)*exposedVAI - - ! compute maximum canopy ice content (kg m-2) - ! NOTE 1: this is used to compute the snow fraction on the canopy, as used in *BOTH* the radiation AND canopy sublimation routines - ! NOTE 2: this is a different variable than the max ice used in the throughfall (snow interception) calculations - ! NOTE 3: use maximum per unit leaf area storage capacity for snow (kg m-2) - select case(model_decisions(iLookDECISIONS%snowIncept)%iDecision) - case(lightSnow); diag_data%var(iLookDIAG%scalarCanopyIceMax)%dat(1) = exposedVAI*mpar_data%var(iLookPARAM%refInterceptCapSnow)%dat(1) - case(stickySnow); diag_data%var(iLookDIAG%scalarCanopyIceMax)%dat(1) = exposedVAI*mpar_data%var(iLookPARAM%refInterceptCapSnow)%dat(1)*4._dp - case default; message=trim(message)//'unable to identify option for maximum branch interception capacity'; err=20; return - end select ! identifying option for maximum branch interception capacity - !print*, 'diag_data%var(iLookDIAG%scalarCanopyLiqMax)%dat(1) = ', diag_data%var(iLookDIAG%scalarCanopyLiqMax)%dat(1) - !print*, 'diag_data%var(iLookDIAG%scalarCanopyIceMax)%dat(1) = ', diag_data%var(iLookDIAG%scalarCanopyIceMax)%dat(1) - - ! compute wetted fraction of the canopy - ! NOTE: assume that the wetted fraction is constant over the substep for the radiation calculations - if(computeVegFlux)then + ! flag the case where number of vegetation states has changed + modifiedVegState = (computeVegFlux.neqv.computeVegFluxOld) + + ! *** compute wetted canopy area... + ! --------------------------------- + + ! compute maximum canopy liquid water (kg m-2) + diag_data%var(iLookDIAG%scalarCanopyLiqMax)%dat(1) = mpar_data%var(iLookPARAM%refInterceptCapRain)%dat(1)*exposedVAI + + ! compute maximum canopy ice content (kg m-2) + ! NOTE 1: this is used to compute the snow fraction on the canopy, as used in *BOTH* the radiation AND canopy sublimation routines + ! NOTE 2: this is a different variable than the max ice used in the throughfall (snow interception) calculations + ! NOTE 3: use maximum per unit leaf area storage capacity for snow (kg m-2) + select case(model_decisions(iLookDECISIONS%snowIncept)%iDecision) + case(lightSnow); diag_data%var(iLookDIAG%scalarCanopyIceMax)%dat(1) = exposedVAI*mpar_data%var(iLookPARAM%refInterceptCapSnow)%dat(1) + case(stickySnow); diag_data%var(iLookDIAG%scalarCanopyIceMax)%dat(1) = exposedVAI*mpar_data%var(iLookPARAM%refInterceptCapSnow)%dat(1)*4._dp + case default + message=trim(message)//'unable to identify option for maximum branch interception capacity' + print*, message + err=20 + return + end select ! identifying option for maximum branch interception capacity + !print*, 'diag_data%var(iLookDIAG%scalarCanopyLiqMax)%dat(1) = ', diag_data%var(iLookDIAG%scalarCanopyLiqMax)%dat(1) + !print*, 'diag_data%var(iLookDIAG%scalarCanopyIceMax)%dat(1) = ', diag_data%var(iLookDIAG%scalarCanopyIceMax)%dat(1) ! compute wetted fraction of the canopy - call wettedFrac(& + ! NOTE: assume that the wetted fraction is constant over the substep for the radiation calculations + if(computeVegFlux)then + + ! compute wetted fraction of the canopy + call wettedFrac(& ! input .false., & ! flag to denote if derivatives are required .false., & ! flag to denote if derivatives are calculated numerically @@ -464,73 +502,92 @@ subroutine coupled_em(& dCanopyWetFraction_dWat, & ! derivative in wetted fraction w.r.t. canopy liquid water content (kg-1 m2) dCanopyWetFraction_dT, & ! derivative in wetted fraction w.r.t. canopy liquid water content (kg-1 m2) err,cmessage) - if(err/=0)then; message=trim(message)//trim(cmessage); return; end if + if(err/=0)then + message=trim(message)//trim(cmessage) + print*, message + return + end if - ! vegetation is completely buried by snow (or no veg exists at all) - else - diag_data%var(iLookDIAG%scalarCanopyWetFraction)%dat(1) = 0._dp - dCanopyWetFraction_dWat = 0._dp - dCanopyWetFraction_dT = 0._dp - end if - + ! vegetation is completely buried by snow (or no veg exists at all) + else + diag_data%var(iLookDIAG%scalarCanopyWetFraction)%dat(1) = 0._dp + dCanopyWetFraction_dWat = 0._dp + dCanopyWetFraction_dT = 0._dp + end if + - ! *** compute snow albedo... - ! -------------------------- - ! NOTE: this should be done before the radiation calculations - ! NOTE: uses snowfall; should really use canopy throughfall + canopy unloading - call snowAlbedo(& - ! input: model control - data_step, & ! intent(in): model time step (s) - (nSnow > 0), & ! intent(in): logical flag to denote if snow is present - ! input/output: data structures - model_decisions, & ! intent(in): model decisions - mpar_data, & ! intent(in): model parameters - flux_data, & ! intent(in): model flux variables - diag_data, & ! intent(inout): model diagnostic variables for a local HRU - prog_data, & ! intent(inout): model prognostic variables for a local HRU - ! output: error control - err,cmessage) ! intent(out): error control - if(err/=0)then; err=20; message=trim(message)//trim(cmessage); return; end if + ! *** compute snow albedo... + ! -------------------------- + ! NOTE: this should be done before the radiation calculations + ! NOTE: uses snowfall; should really use canopy throughfall + canopy unloading + call snowAlbedo(& + ! input: model control + data_step, & ! intent(in): model time step (s) + (nSnow > 0), & ! intent(in): logical flag to denote if snow is present + ! input/output: data structures + model_decisions, & ! intent(in): model decisions + mpar_data, & ! intent(in): model parameters + flux_data, & ! intent(in): model flux variables + diag_data, & ! intent(inout): model diagnostic variables for a local HRU + prog_data, & ! intent(inout): model prognostic variables for a local HRU + ! output: error control + err,cmessage) ! intent(out): error control + if(err/=0)then + err=20 + message=trim(message)//trim(cmessage) + print*, message + return + end if - ! *** compute canopy sw radiation fluxes... - ! ----------------------------------------- - call vegSWavRad(& - data_step, & ! intent(in): time step (s) -- only used in Noah-MP radiation, to compute albedo - nSnow, & ! intent(in): number of snow layers - nSoil, & ! intent(in): number of soil layers - nLayers, & ! intent(in): total number of layers - computeVegFlux, & ! intent(in): logical flag to compute vegetation fluxes (.false. if veg buried by snow) - type_data, & ! intent(in): type of vegetation and soil - prog_data, & ! intent(inout): model prognostic variables for a local HRU - diag_data, & ! intent(inout): model diagnostic variables for a local HRU - flux_data, & ! intent(inout): model flux variables - err,cmessage) ! intent(out): error control - if(err/=0)then; err=20; message=trim(message)//trim(cmessage); return; end if + ! *** compute canopy sw radiation fluxes... + ! ----------------------------------------- + call vegSWavRad(& + data_step, & ! intent(in): time step (s) -- only used in Noah-MP radiation, to compute albedo + nSnow, & ! intent(in): number of snow layers + nSoil, & ! intent(in): number of soil layers + nLayers, & ! intent(in): total number of layers + computeVegFlux, & ! intent(in): logical flag to compute vegetation fluxes (.false. if veg buried by snow) + type_data, & ! intent(in): type of vegetation and soil + prog_data, & ! intent(inout): model prognostic variables for a local HRU + diag_data, & ! intent(inout): model diagnostic variables for a local HRU + flux_data, & ! intent(inout): model flux variables + err,cmessage) ! intent(out): error control + if(err/=0)then + err=20 + message=trim(message)//trim(cmessage) + print*, message + return + end if - ! *** compute canopy throughfall and unloading... - ! ----------------------------------------------- - ! NOTE 1: this needs to be done before solving the energy and liquid water equations, to account for the heat advected with precipitation (and throughfall/unloading) - ! NOTE 2: the unloading flux is computed using canopy drip (scalarCanopyLiqDrainage) from the previous time step - call canopySnow(& - ! input: model control - data_step, & ! intent(in): time step (seconds) - exposedVAI, & ! intent(in): exposed vegetation area index (m2 m-2) - computeVegFlux, & ! intent(in): flag to denote if computing energy flux over vegetation - ! input/output: data structures - model_decisions, & ! intent(in): model decisions - forc_data, & ! intent(in): model forcing data - mpar_data, & ! intent(in): model parameters - diag_data, & ! intent(in): model diagnostic variables for a local HRU - prog_data, & ! intent(inout): model prognostic variables for a local HRU - flux_data, & ! intent(inout): model flux variables - ! output: error control - err,cmessage) ! intent(out): error control - if(err/=0)then; err=20; message=trim(message)//trim(cmessage); return; end if + ! *** compute canopy throughfall and unloading... + ! ----------------------------------------------- + ! NOTE 1: this needs to be done before solving the energy and liquid water equations, to account for the heat advected with precipitation (and throughfall/unloading) + ! NOTE 2: the unloading flux is computed using canopy drip (scalarCanopyLiqDrainage) from the previous time step + call canopySnow(& + ! input: model control + data_step, & ! intent(in): time step (seconds) + exposedVAI, & ! intent(in): exposed vegetation area index (m2 m-2) + computeVegFlux, & ! intent(in): flag to denote if computing energy flux over vegetation + ! input/output: data structures + model_decisions, & ! intent(in): model decisions + forc_data, & ! intent(in): model forcing data + mpar_data, & ! intent(in): model parameters + diag_data, & ! intent(in): model diagnostic variables for a local HRU + prog_data, & ! intent(inout): model prognostic variables for a local HRU + flux_data, & ! intent(inout): model flux variables + ! output: error control + err,cmessage) ! intent(out): error control + if(err/=0)then + err=20 + message=trim(message)//trim(cmessage) + print*, message + return + end if - ! adjust canopy temperature to account for new snow - if(computeVegFlux)then ! logical flag to compute vegetation fluxes (.false. if veg buried by snow) - call tempAdjust(& + ! adjust canopy temperature to account for new snow + if(computeVegFlux)then ! logical flag to compute vegetation fluxes (.false. if veg buried by snow) + call tempAdjust(& ! input: derived parameters canopyDepth, & ! intent(in): canopy depth (m) ! input/output: data structures @@ -539,161 +596,199 @@ subroutine coupled_em(& diag_data, & ! intent(out): model diagnostic variables for a local HRU ! output: error control err,cmessage) ! intent(out): error control - 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 endif ! if computing fluxes over vegetation - ! initialize drainage and throughfall - ! NOTE 1: this needs to be done before solving the energy and liquid water equations, to account for the heat advected with precipitation - ! NOTE 2: this initialization needs to be done AFTER the call to canopySnow, since canopySnow uses canopy drip drom the previous time step - if(.not.computeVegFlux)then - flux_data%var(iLookFLUX%scalarThroughfallRain)%dat(1) = flux_data%var(iLookFLUX%scalarRainfall)%dat(1) - flux_data%var(iLookFLUX%scalarCanopyLiqDrainage)%dat(1) = 0._dp - else - flux_data%var(iLookFLUX%scalarThroughfallRain)%dat(1) = 0._dp - flux_data%var(iLookFLUX%scalarCanopyLiqDrainage)%dat(1) = 0._dp - end if - - ! **************************************************************************************************** - ! *** MAIN SOLVER ************************************************************************************ - ! **************************************************************************************************** - - ! initialize the length of the sub-step - dt_solv = 0._dp ! length of time step that has been completed (s) - dt_init = min(data_step,maxstep) / dt_init_factor ! initial substep length (s) - dt_sub = dt_init ! length of substep - dtSave = dt_init ! length of substep - - ! initialize the number of sub-steps - nsub=0 - - ! loop through sub-steps - substeps: do ! continuous do statement with exit clause (alternative to "while") - - ! print progress - !print*, '*** new substep' - !write(*,'(a,3(f11.4,1x))') 'dt_sub, dt_init = ', dt_sub, dt_init - - ! print progress - if(globalPrintFlag)then - write(*,'(a,1x,4(f13.5,1x))') ' start of step: dt_init, dt_sub, dt_solv, data_step: ', dt_init, dt_sub, dt_solv, data_step - print*, 'stepFailure = ', stepFailure - print*, 'before resizeData: nSnow, nSoil = ', nSnow, nSoil - endif - - ! increment the number of sub-steps - nsub = nsub+1 - - ! resize the "indx_data" structure - ! NOTE: this is necessary because the length of index variables depends on a given split - ! --> the resize here is overwritten later (in indexSplit) - ! --> admittedly ugly, and retained for now - if(stepFailure)then - call resizeData(indx_meta(:),indx_temp,indx_data,err=err,message=cmessage) - if(err/=0)then; err=20; message=trim(message)//trim(cmessage); return; endif + ! initialize drainage and throughfall + ! NOTE 1: this needs to be done before solving the energy and liquid water equations, to account for the heat advected with precipitation + ! NOTE 2: this initialization needs to be done AFTER the call to canopySnow, since canopySnow uses canopy drip drom the previous time step + if(.not.computeVegFlux)then + flux_data%var(iLookFLUX%scalarThroughfallRain)%dat(1) = flux_data%var(iLookFLUX%scalarRainfall)%dat(1) + flux_data%var(iLookFLUX%scalarCanopyLiqDrainage)%dat(1) = 0._dp else - call resizeData(indx_meta(:),indx_data,indx_temp,err=err,message=cmessage) - if(err/=0)then; err=20; message=trim(message)//trim(cmessage); return; endif - endif - - ! save/recover copies of index variables - do iVar=1,size(indx_data%var) - !print*, 'indx_meta(iVar)%varname = ', trim(indx_meta(iVar)%varname) - select case(stepFailure) - case(.false.); indx_temp%var(iVar)%dat(:) = indx_data%var(iVar)%dat(:) - case(.true.); indx_data%var(iVar)%dat(:) = indx_temp%var(iVar)%dat(:) - end select - end do ! looping through variables - - ! save/recover copies of prognostic variables - do iVar=1,size(prog_data%var) - !print*, 'prog_meta(iVar)%varname = ', trim(prog_meta(iVar)%varname) - select case(stepFailure) - case(.false.); prog_temp%var(iVar)%dat(:) = prog_data%var(iVar)%dat(:) - case(.true.); prog_data%var(iVar)%dat(:) = prog_temp%var(iVar)%dat(:) - end select - end do ! looping through variables - - ! save/recover copies of diagnostic variables - do iVar=1,size(diag_data%var) - select case(stepFailure) - case(.false.); diag_temp%var(iVar)%dat(:) = diag_data%var(iVar)%dat(:) - case(.true.); diag_data%var(iVar)%dat(:) = diag_temp%var(iVar)%dat(:) - end select - end do ! looping through variables - - ! 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 - - - ! *** merge/sub-divide snow layers... - ! ----------------------------------- - call volicePack(& - ! input/output: model data structures - doLayerMerge, & ! intent(in): flag to force merge of snow layers - model_decisions, & ! intent(in): model decisions - mpar_data, & ! intent(in): model parameters - indx_data, & ! intent(inout): type of each layer - prog_data, & ! intent(inout): model prognostic variables for a local HRU - diag_data, & ! intent(inout): model diagnostic variables for a local HRU - flux_data, & ! intent(inout): model fluxes for a local HRU - ! output - modifiedLayers, & ! intent(out): flag to denote that layers were modified - err,cmessage) ! intent(out): error control - if(err/=0)then; err=55; message=trim(message)//trim(cmessage); return; end if - - ! save the number of snow and soil layers - nSnow = indx_data%var(iLookINDEX%nSnow)%dat(1) - nSoil = indx_data%var(iLookINDEX%nSoil)%dat(1) - nLayers = indx_data%var(iLookINDEX%nLayers)%dat(1) - - - ! compute the indices for the model state variables - if(firstSubStep .or. modifiedVegState .or. modifiedLayers)then - call indexState(computeVegFlux, & ! intent(in): flag to denote if computing the vegetation flux - includeAquifer, & ! intent(in): flag to denote if included the aquifer - nSnow,nSoil,nLayers, & ! intent(in): number of snow and soil layers, and total number of layers - indx_data, & ! intent(inout): indices defining model states and layers - err,cmessage) ! intent(out): error control - if(err/=0)then; message=trim(message)//trim(cmessage); return; end if + flux_data%var(iLookFLUX%scalarThroughfallRain)%dat(1) = 0._dp + flux_data%var(iLookFLUX%scalarCanopyLiqDrainage)%dat(1) = 0._dp end if - ! recreate the temporary data structures - ! NOTE: resizeData(meta, old, new, ..) - if(modifiedVegState .or. modifiedLayers)then - - ! create temporary data structures for prognostic variables - call resizeData(prog_meta(:),prog_data,prog_temp,copy=.true.,err=err,message=cmessage) - if(err/=0)then; err=20; message=trim(message)//trim(cmessage); return; endif - - ! create temporary data structures for diagnostic variables - call resizeData(diag_meta(:),diag_data,diag_temp,copy=.true.,err=err,message=cmessage) - if(err/=0)then; err=20; message=trim(message)//trim(cmessage); return; endif - - ! create temporary data structures for index variables - call resizeData(indx_meta(:),indx_data,indx_temp,copy=.true.,err=err,message=cmessage) - if(err/=0)then; err=20; message=trim(message)//trim(cmessage); return; endif - - do iVar=1,size(indx_data%var) - !print*, 'indx_meta(iVar)%varname = ', trim(indx_meta(iVar)%varname) - select case(stepFailure) - case(.false.); indx_temp%var(iVar)%dat(:) = indx_data%var(iVar)%dat(:) - case(.true.); indx_data%var(iVar)%dat(:) = indx_temp%var(iVar)%dat(:) - end select - end do ! looping through variables + ! **************************************************************************************************** + ! *** MAIN SOLVER ************************************************************************************ + ! **************************************************************************************************** - endif ! if modified the states + ! initialize the length of the sub-step + dt_solv = 0._dp ! length of time step that has been completed (s) + dt_init = min(data_step,maxstep) / dt_init_factor ! initial substep length (s) + dt_sub = dt_init ! length of substep + dtSave = dt_init ! length of substep + + ! initialize the number of sub-steps + nsub=0 + + ! loop through sub-steps + substeps: do ! continuous do statement with exit clause (alternative to "while") + + ! print progress + !print*, '*** new substep' + !write(*,'(a,3(f11.4,1x))') 'dt_sub, dt_init = ', dt_sub, dt_init + + ! print progress + if(globalPrintFlag)then + write(*,'(a,1x,4(f13.5,1x))') ' start of step: dt_init, dt_sub, dt_solv, data_step: ', dt_init, dt_sub, dt_solv, data_step + print*, 'stepFailure = ', stepFailure + print*, 'before resizeData: nSnow, nSoil = ', nSnow, nSoil + endif + + ! increment the number of sub-steps + nsub = nsub+1 + + ! resize the "indx_data" structure + ! NOTE: this is necessary because the length of index variables depends on a given split + ! --> the resize here is overwritten later (in indexSplit) + ! --> admittedly ugly, and retained for now + if(stepFailure)then + call resizeData(indx_meta(:),indx_temp,indx_data,err=err,message=cmessage) + if(err/=0)then + err=20 + message=trim(message)//trim(cmessage) + print*, message + return + endif + else + call resizeData(indx_meta(:),indx_data,indx_temp,err=err,message=cmessage) + if(err/=0)then + err=20 + message=trim(message)//trim(cmessage) + print*, message + return + endif + endif + + ! save/recover copies of index variables + do iVar=1,size(indx_data%var) + !print*, 'indx_meta(iVar)%varname = ', trim(indx_meta(iVar)%varname) + select case(stepFailure) + case(.false.); indx_temp%var(iVar)%dat(:) = indx_data%var(iVar)%dat(:) + case(.true.); indx_data%var(iVar)%dat(:) = indx_temp%var(iVar)%dat(:) + end select + end do ! looping through variables + + ! save/recover copies of prognostic variables + do iVar=1,size(prog_data%var) + !print*, 'prog_meta(iVar)%varname = ', trim(prog_meta(iVar)%varname) + select case(stepFailure) + case(.false.); prog_temp%var(iVar)%dat(:) = prog_data%var(iVar)%dat(:) + case(.true.); prog_data%var(iVar)%dat(:) = prog_temp%var(iVar)%dat(:) + end select + end do ! looping through variables + + ! save/recover copies of diagnostic variables + do iVar=1,size(diag_data%var) + select case(stepFailure) + case(.false.); diag_temp%var(iVar)%dat(:) = diag_data%var(iVar)%dat(:) + case(.true.); diag_data%var(iVar)%dat(:) = diag_temp%var(iVar)%dat(:) + end select + end do ! looping through variables + + ! 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 + - ! define the number of state variables - nState = indx_data%var(iLookINDEX%nState)%dat(1) + ! *** merge/sub-divide snow layers... + ! ----------------------------------- + call volicePack(& + ! input/output: model data structures + doLayerMerge, & ! intent(in): flag to force merge of snow layers + model_decisions, & ! intent(in): model decisions + mpar_data, & ! intent(in): model parameters + indx_data, & ! intent(inout): type of each layer + prog_data, & ! intent(inout): model prognostic variables for a local HRU + diag_data, & ! intent(inout): model diagnostic variables for a local HRU + flux_data, & ! intent(inout): model fluxes for a local HRU + ! output + modifiedLayers, & ! intent(out): flag to denote that layers were modified + err,cmessage) ! intent(out): error control + if(err/=0)then + err=55 + message=trim(message)//trim(cmessage) + print*, message + return + end if + + ! save the number of snow and soil layers + nSnow = indx_data%var(iLookINDEX%nSnow)%dat(1) + nSoil = indx_data%var(iLookINDEX%nSoil)%dat(1) + nLayers = indx_data%var(iLookINDEX%nLayers)%dat(1) + + + ! compute the indices for the model state variables + if(firstSubStep .or. modifiedVegState .or. modifiedLayers)then + call indexState(computeVegFlux, & ! intent(in): flag to denote if computing the vegetation flux + includeAquifer, & ! intent(in): flag to denote if included the aquifer + nSnow,nSoil,nLayers, & ! intent(in): number of snow and soil layers, and total number of layers + indx_data, & ! intent(inout): indices defining model states and layers + err,cmessage) ! intent(out): error control + if(err/=0)then + message=trim(message)//trim(cmessage) + print*, message + return + end if + end if + + ! recreate the temporary data structures + ! NOTE: resizeData(meta, old, new, ..) + if(modifiedVegState .or. modifiedLayers)then + + ! create temporary data structures for prognostic variables + call resizeData(prog_meta(:),prog_data,prog_temp,copy=.true.,err=err,message=cmessage) + if(err/=0)then; + err=20 + message=trim(message)//trim(cmessage); + print*, message + return + endif + + ! create temporary data structures for diagnostic variables + call resizeData(diag_meta(:),diag_data,diag_temp,copy=.true.,err=err,message=cmessage) + if(err/=0)then + err=20 + message=trim(message)//trim(cmessage) + print*, message + return + endif + + ! create temporary data structures for index variables + call resizeData(indx_meta(:),indx_data,indx_temp,copy=.true.,err=err,message=cmessage) + if(err/=0)then + err=20 + message=trim(message)//trim(cmessage) + print*, message + return + endif + + do iVar=1,size(indx_data%var) + !print*, 'indx_meta(iVar)%varname = ', trim(indx_meta(iVar)%varname) + select case(stepFailure) + case(.false.); indx_temp%var(iVar)%dat(:) = indx_data%var(iVar)%dat(:) + case(.true.); indx_data%var(iVar)%dat(:) = indx_temp%var(iVar)%dat(:) + end select + end do ! looping through variables + + endif ! if modified the states + + ! define the number of state variables + nState = indx_data%var(iLookINDEX%nState)%dat(1) - ! *** compute diagnostic variables for each layer... - ! -------------------------------------------------- - ! NOTE: this needs to be done AFTER volicePack, since layers may have been sub-divided and/or merged - call diagn_evar(& + ! *** compute diagnostic variables for each layer... + ! -------------------------------------------------- + ! NOTE: this needs to be done AFTER volicePack, since layers may have been sub-divided and/or merged + call diagn_evar(& ! input: control variables computeVegFlux, & ! intent(in): flag to denote if computing the vegetation flux canopyDepth, & ! intent(in): canopy depth (m) @@ -704,15 +799,19 @@ subroutine coupled_em(& diag_data, & ! intent(inout): model diagnostic variables for a local HRU ! output: error control err,cmessage) ! intent(out): error control - if(err/=0)then; err=55; message=trim(message)//trim(cmessage); return; end if - - - ! *** compute melt of the "snow without a layer"... - ! ------------------------------------------------- - ! NOTE: forms a surface melt pond, which drains into the upper-most soil layer through the time step - ! (check for the special case of "snow without a layer") - if(nSnow==0)then - call implctMelt(& + if(err/=0)then + err=55; + message=trim(message)//trim(cmessage) + return + end if + + + ! *** compute melt of the "snow without a layer"... + ! ------------------------------------------------- + ! NOTE: forms a surface melt pond, which drains into the upper-most soil layer through the time step + ! (check for the special case of "snow without a layer") + if(nSnow==0)then + call implctMelt(& ! input/output: integrated snowpack properties prog_data%var(iLookPROG%scalarSWE)%dat(1), & ! intent(inout): snow water equivalent (kg m-2) prog_data%var(iLookPROG%scalarSnowDepth)%dat(1), & ! intent(inout): snow depth (m) @@ -723,8 +822,13 @@ subroutine coupled_em(& diag_data%var(iLookDIAG%mLayerVolHtCapBulk)%dat(nSnow+1),& ! intent(inout): surface layer volumetric heat capacity (J m-3 K-1) ! output: error control err,cmessage ) ! intent(out): error control - if(err/=0)then; err=20; message=trim(message)//trim(cmessage); return; end if - end if + if(err/=0)then + err=20 + message=trim(message)//trim(cmessage) + print*, message + return + end if + end if ! nsnow == 0 ! *** solve model equations... ! ---------------------------- @@ -762,34 +866,40 @@ subroutine coupled_em(& 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); return; end if + 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. + stepFailure = .true. + doLayerMerge = .true. else - doLayerMerge = .false. + 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 - ! 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 @@ -816,124 +926,224 @@ subroutine coupled_em(& ! ------------------------------------------------------------ if(computeVegFlux)then - ! 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 - - ! 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 + ! 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 + + ! 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) - ! * 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' - 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 (-) + !********** SUNDIALS ADDITION ***************** + if (sundials) then + call computSnowDepth(& + dt_sub, & ! intent(in) + nSnow, & ! intent(in) + scalarSnowSublimation, & ! intent(in) + mLayerVolFracLiq, & ! intent(inout) + mLayerVolFracIce, & ! intent(inout) + prog_data%var(iLookPROG%mLayerTemp)%dat, & ! intent(in) + diag_data%var(iLookDIAG%mLayerMeltFreeze)%dat,& ! 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 + 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 + + ! end associate sublime + + ! 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 + + ! 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) + + ! 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 - if(err/=0)then; err=55; message=trim(message)//trim(cmessage); 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) - 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 + & - 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 + 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) - ! 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) + end if ! sundials + end associate sublime - ! 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 MAIN SOLVER ******************************************************************************** diff --git a/build/source/engine/nr_utility.f90 b/build/source/engine/nr_utility.f90 index 238f90698ed855324ce91bbe557b0c387b19eb77..adc4d8be2c9bdd34bc6573d52861e7502c93f7b8 100755 --- a/build/source/engine/nr_utility.f90 +++ b/build/source/engine/nr_utility.f90 @@ -12,23 +12,6 @@ public::arth public::indexx contains - ! ************************************************************************************************* - ! * the arth function, used to build a vector of regularly spaced numbers - ! ************************************************************************************************* -! FUNCTION arth_r(first,increment,n) -! implicit none -! REAL(SP), INTENT(IN) :: first,increment -! INTEGER(I4B), INTENT(IN) :: n -! REAL(SP), DIMENSION(n) :: arth_r -! INTEGER(I4B) :: k -! arth_r(1)=first -! if(n>1)then -! do k=2,n -! arth_r(k) = arth_r(k-1) + increment -! end do -! end if -! END FUNCTION arth_r - ! ------------------------------------------------------------------------------------------------ FUNCTION arth_d(first,increment,n) implicit none REAL(rkind), INTENT(IN) :: first,increment