! SUMMA - Structure for Unifying Multiple Modeling Alternatives ! Copyright (C) 2014-2020 NCAR/RAL; University of Saskatchewan; University of Washington ! ! This file is part of SUMMA ! ! For more information see: http://www.ral.ucar.edu/projects/summa ! ! This program is free software: you can redistribute it and/or modify ! it under the terms of the GNU General Public License as published by ! the Free Software Foundation, either version 3 of the License, or ! (at your option) any later version. ! ! This program is distributed in the hope that it will be useful, ! but WITHOUT ANY WARRANTY; without even the implied warranty of ! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! GNU General Public License for more details. ! ! You should have received a copy of the GNU General Public License ! along with this program. If not, see <http://www.gnu.org/licenses/>. module mDecisions_module USE data_types,only: var_i USE nrtype USE var_lookup, only: maxvarDecisions ! maximum number of decisions implicit none private public::mDecisions ! look-up values for the choice of function for the soil moisture control on stomatal resistance integer(i4b),parameter,public :: NoahType = 1 ! thresholded linear function of volumetric liquid water content integer(i4b),parameter,public :: CLM_Type = 2 ! thresholded linear function of matric head integer(i4b),parameter,public :: SiB_Type = 3 ! exponential of the log of matric head ! look-up values for the choice of stomatal resistance formulation integer(i4b),parameter,public :: BallBerry = 1 ! Ball-Berry integer(i4b),parameter,public :: Jarvis = 2 ! Jarvis integer(i4b),parameter,public :: simpleResistance = 3 ! simple resistance formulation integer(i4b),parameter,public :: BallBerryFlex = 4 ! flexible Ball-Berry scheme integer(i4b),parameter,public :: BallBerryTest = 5 ! flexible Ball-Berry scheme (testing) ! look-up values to define leaf temperature controls on photosynthesis + stomatal resistance integer(i4b),parameter,public :: q10Func = 11 ! the q10 function used in CLM4 and Noah-MP integer(i4b),parameter,public :: Arrhenius = 12 ! the Arrhenious functions used in CLM5 and Cable ! look-up values to define humidity controls on stomatal resistance integer(i4b),parameter,public :: humidLeafSurface = 21 ! humidity at the leaf surface [Bonan et al., 2011] integer(i4b),parameter,public :: scaledHyperbolic = 22 ! scaled hyperbolic function [Leuning et al., 1995] ! look-up values to define the electron transport function (dependence of photosynthesis on PAR) integer(i4b),parameter,public :: linear = 31 ! linear function used in CLM4 and Noah-MP integer(i4b),parameter,public :: linearJmax = 32 ! linear jmax function used in Cable [Wang et al., Ag Forest Met 1998, eq D5] integer(i4b),parameter,public :: quadraticJmax = 33 ! the quadratic Jmax function, used in SSiB and CLM5 ! look up values to define the use of CO2 compensation point to calculate stomatal resistance integer(i4b),parameter,public :: origBWB = 41 ! the original BWB approach integer(i4b),parameter,public :: Leuning = 42 ! the Leuning approach ! look up values to define the iterative numerical solution method used in the Ball-Berry stomatal resistance parameterization integer(i4b),parameter,public :: NoahMPsolution = 51 ! the NoahMP solution (and CLM4): fixed point iteration; max 3 iterations integer(i4b),parameter,public :: newtonRaphson = 52 ! full Newton-Raphson iterative solution to convergence ! look up values to define the controls on carbon assimilation integer(i4b),parameter,public :: colimitation = 61 ! enable colimitation, as described by Collatz et al. (1991) and Sellers et al. (1996) integer(i4b),parameter,public :: minFunc = 62 ! do not enable colimitation: use minimum of the three controls on carbon assimilation ! look up values to define the scaling of photosynthesis from the leaves to the canopy integer(i4b),parameter,public :: constantScaling = 71 ! constant scaling factor integer(i4b),parameter,public :: laiScaling = 72 ! exponential function of LAI (Leuning, Plant Cell Env 1995: "Scaling from..." [eq 9]) ! look-up values for the choice of numerical method integer(i4b),parameter,public :: iterative = 81 ! iterative integer(i4b),parameter,public :: nonIterative = 82 ! non-iterative integer(i4b),parameter,public :: iterSurfEnergyBal = 83 ! iterate only on the surface energy balance ! look-up values for method used to compute derivative integer(i4b),parameter,public :: numerical = 91 ! numerical solution integer(i4b),parameter,public :: analytical = 92 ! analytical solution ! look-up values for method used to determine LAI and SAI integer(i4b),parameter,public :: monthlyTable = 101 ! LAI/SAI taken directly from a monthly table for different vegetation classes integer(i4b),parameter,public :: specified = 102 ! LAI/SAI computed from green vegetation fraction and winterSAI and summerLAI parameters ! look-up values for the choice of the canopy interception parameterization integer(i4b),parameter,public :: sparseCanopy = 111 ! fraction of rainfall that never hits the canopy (throughfall); drainage above threshold integer(i4b),parameter,public :: storageFunc = 112 ! throughfall a function of canopy storage; 100% throughfall when canopy is at capacity integer(i4b),parameter,public :: unDefined = 113 ! option is undefined (backwards compatibility) ! look-up values for the form of Richards' equation integer(i4b),parameter,public :: moisture = 121 ! moisture-based form of Richards' equation integer(i4b),parameter,public :: mixdform = 122 ! mixed form of Richards' equation ! look-up values for the choice of groundwater parameterization integer(i4b),parameter,public :: qbaseTopmodel = 131 ! TOPMODEL-ish baseflow parameterization integer(i4b),parameter,public :: bigBucket = 132 ! a big bucket (lumped aquifer model) integer(i4b),parameter,public :: noExplicit = 133 ! no explicit groundwater parameterization ! look-up values for the choice of hydraulic conductivity profile integer(i4b),parameter,public :: constant = 141 ! constant hydraulic conductivity with depth integer(i4b),parameter,public :: powerLaw_profile = 142 ! power-law profile ! look-up values for the choice of boundary conditions for thermodynamics integer(i4b),parameter,public :: prescribedTemp = 151 ! prescribed temperature integer(i4b),parameter,public :: energyFlux = 152 ! energy flux integer(i4b),parameter,public :: zeroFlux = 153 ! zero flux ! look-up values for the choice of boundary conditions for hydrology integer(i4b),parameter,public :: liquidFlux = 161 ! liquid water flux integer(i4b),parameter,public :: prescribedHead = 162 ! prescribed head (volumetric liquid water content for mixed form of Richards' eqn) integer(i4b),parameter,public :: funcBottomHead = 163 ! function of matric head in the lower-most layer integer(i4b),parameter,public :: freeDrainage = 164 ! free drainage ! look-up values for the choice of parameterization for vegetation roughness length and displacement height integer(i4b),parameter,public :: Raupach_BLM1994 = 171 ! Raupach (BLM 1994) "Simplified expressions..." integer(i4b),parameter,public :: CM_QJRMS1988 = 172 ! Choudhury and Monteith (QJRMS 1988) "A four layer model for the heat budget..." integer(i4b),parameter,public :: vegTypeTable = 173 ! constant parameters dependent on the vegetation type ! look-up values for the choice of parameterization for the rooting profile integer(i4b),parameter,public :: powerLaw = 181 ! simple power-law rooting profile integer(i4b),parameter,public :: doubleExp = 182 ! the double exponential function of Xeng et al. (JHM 2001) ! look-up values for the choice of parameterization for canopy emissivity integer(i4b),parameter,public :: simplExp = 191 ! simple exponential function integer(i4b),parameter,public :: difTrans = 192 ! parameterized as a function of diffuse transmissivity ! look-up values for the choice of parameterization for snow interception integer(i4b),parameter,public :: stickySnow = 201 ! maximum interception capacity an increasing function of temerature integer(i4b),parameter,public :: lightSnow = 202 ! maximum interception capacity an inverse function of new snow density ! look-up values for the choice of wind profile integer(i4b),parameter,public :: exponential = 211 ! exponential wind profile extends to the surface integer(i4b),parameter,public :: logBelowCanopy = 212 ! logarithmic profile below the vegetation canopy ! look-up values for the choice of stability function integer(i4b),parameter,public :: standard = 221 ! standard MO similarity, a la Anderson (1976) integer(i4b),parameter,public :: louisInversePower = 222 ! Louis (1979) inverse power function integer(i4b),parameter,public :: mahrtExponential = 223 ! Mahrt (1987) exponential ! look-up values for the choice of canopy shortwave radiation method integer(i4b),parameter,public :: noah_mp = 231 ! full Noah-MP implementation (including albedo) integer(i4b),parameter,public :: CLM_2stream = 232 ! CLM 2-stream model (see CLM documentation) integer(i4b),parameter,public :: UEB_2stream = 233 ! UEB 2-stream model (Mahat and Tarboton, WRR 2011) integer(i4b),parameter,public :: NL_scatter = 234 ! Simplified method Nijssen and Lettenmaier (JGR 1999) integer(i4b),parameter,public :: BeersLaw = 235 ! Beer's Law (as implemented in VIC) ! look-up values for the choice of albedo representation integer(i4b),parameter,public :: constantDecay = 241 ! constant decay (e.g., VIC, CLASS) integer(i4b),parameter,public :: variableDecay = 242 ! variable decay (e.g., BATS approach, with destructive metamorphism + soot content) ! look-up values for the choice of compaction routine integer(i4b),parameter,public :: constantSettlement = 251 ! constant settlement rate integer(i4b),parameter,public :: andersonEmpirical = 252 ! semi-empirical method of Anderson (1976) ! look-up values for the choice of method to combine and sub-divide snow layers integer(i4b),parameter,public :: sameRulesAllLayers = 261 ! same combination/sub-division rules applied to all layers integer(i4b),parameter,public :: rulesDependLayerIndex= 262 ! combination/sub-dividion rules depend on layer index ! look-up values for the choice of thermal conductivity representation for snow integer(i4b),parameter,public :: Yen1965 = 271 ! Yen (1965) integer(i4b),parameter,public :: Mellor1977 = 272 ! Mellor (1977) integer(i4b),parameter,public :: Jordan1991 = 273 ! Jordan (1991) integer(i4b),parameter,public :: Smirnova2000 = 274 ! Smirnova et al. (2000) ! look-up values for the choice of thermal conductivityi representation for soil integer(i4b),parameter,public :: funcSoilWet = 281 ! function of soil wetness integer(i4b),parameter,public :: mixConstit = 282 ! mixture of constituents integer(i4b),parameter,public :: hanssonVZJ = 283 ! test case for the mizoguchi lab experiment, Hansson et al. VZJ 2004 ! look-up values for the choice of method for the spatial representation of groundwater integer(i4b),parameter,public :: localColumn = 291 ! separate groundwater representation in each local soil column integer(i4b),parameter,public :: singleBasin = 292 ! single groundwater store over the entire basin ! look-up values for the choice of sub-grid routing method integer(i4b),parameter,public :: timeDelay = 301 ! time-delay histogram integer(i4b),parameter,public :: qInstant = 302 ! instantaneous routing ! look-up values for the choice of new snow density method integer(i4b),parameter,public :: constDens = 311 ! Constant new snow density integer(i4b),parameter,public :: anderson = 312 ! Anderson 1976 integer(i4b),parameter,public :: hedAndPom = 313 ! Hedstrom and Pomeroy (1998), expoential increase integer(i4b),parameter,public :: pahaut_76 = 314 ! Pahaut 1976, wind speed dependent (derived from Col de Porte, French Alps) ! look-up values for the choice of snow unloading from the canopy integer(i4b),parameter,public :: meltDripUnload = 321 ! Hedstrom and Pomeroy (1998), Storck et al 2002 (snowUnloadingCoeff & ratioDrip2Unloading) integer(i4b),parameter,public :: windUnload = 322 ! Roesch et al 2001, formulate unloading based on wind and temperature ! ----------------------------------------------------------------------------------------------------------- contains ! ************************************************************************************************ ! public subroutine mDecisions: save model decisions as named integers ! ************************************************************************************************ subroutine mDecisions(numSteps,err,message) ! model time structures USE multiconst,only:secprday ! number of seconds in a day USE var_lookup,only:iLookTIME ! named variables that identify indices in the time structures USE globalData,only:dJulianStart ! julian day of start time of simulation USE globalData,only:dJulianFinsh ! julian day of end time of simulation USE globalData,only:startTime,finshTime,refTime USE globalData,only:refJulday ! julian day of start time of simulation USE globalData,only:refJulday ! julian day of end time of simulation USE globalData,only:data_step ! length of data step (s) USE globalData,only:numtim ! the number of timesteps in the model ! model decision structures USE globaldata,only:model_decisions ! model decision structure USE var_lookup,only:iLookDECISIONS ! named variables for elements of the decision structure ! forcing metadata USE globalData,only:forc_meta ! metadata structures USE var_lookup,only:iLookFORCE ! named variables to define structure elements ! Noah-MP decision structures USE noahmp_globals,only:DVEG ! decision for dynamic vegetation USE noahmp_globals,only:OPT_RAD ! decision for canopy radiation USE noahmp_globals,only:OPT_ALB ! decision for snow albedo ! time utility programs USE time_utils_module,only:extractTime ! extract time info from units string USE time_utils_module,only:compjulday ! compute the julian day USE time_utils_module,only:fracDay ! compute fractional day USE summaActors_FileManager,only: SIM_START_TM, SIM_END_TM ! time info from control file module implicit none ! define output integer(i4b),intent(inout) :: numSteps integer(i4b),intent(out) :: err ! error code character(*),intent(out) :: message ! error message ! define local variables character(len=256) :: cmessage ! error message for downwind routine real(dp) :: dsec,dsec_tz ! second ! initialize error control err=0;message='mDecisions/' ! ------------------------------------------------------------------------------------------------- ! ------------------------------------------------------------------------------------------------- ! read information from model decisions file, and populate model decisions structure call readoption(err,cmessage) if(err/=0)then; err=20; message=trim(message)//trim(cmessage); return; end if ! ------------------------------------------------------------------------------------------------- ! put reference time information into the time structures call extractTime(forc_meta(iLookFORCE%time)%varunit, & ! date-time string refTime%var(iLookTIME%iyyy), & ! year refTime%var(iLookTIME%im), & ! month refTime%var(iLookTIME%id), & ! day refTime%var(iLookTIME%ih), & ! hour refTime%var(iLookTIME%imin), & ! minute dsec, & ! second refTime%var(iLookTIME%ih_tz), & ! time zone hour refTime%var(iLookTIME%imin_tz), & ! time zone minute dsec_tz, & ! time zone seconds err,cmessage) ! error control if(err/=0)then; err=20; message=trim(message)//trim(cmessage); return; end if ! compute the julian date (fraction of day) for the reference time call compjulday(& refTime%var(iLookTIME%iyyy), & ! year refTime%var(iLookTIME%im), & ! month refTime%var(iLookTIME%id), & ! day refTime%var(iLookTIME%ih), & ! hour refTime%var(iLookTIME%imin), & ! minute 0._dp, & ! second refJulday, & ! julian date for the start of the simulation err, cmessage) ! error control if(err/=0)then; err=20; message=trim(message)//trim(cmessage); return; end if ! put simulation start time information into the time structures call extractTime(trim(SIM_START_TM), & ! date-time string startTime%var(iLookTIME%iyyy), & ! year startTime%var(iLookTIME%im), & ! month startTime%var(iLookTIME%id), & ! day startTime%var(iLookTIME%ih), & ! hour startTime%var(iLookTIME%imin), & ! minute dsec, & ! second startTime%var(iLookTIME%ih_tz), & ! time zone hour startTime%var(iLookTIME%imin_tz), & ! time zone minnute dsec_tz, & ! time zone seconds err,cmessage) ! error control if(err/=0)then; err=20; message=trim(message)//trim(cmessage); return; end if ! compute the julian date (fraction of day) for the start of the simulation call compjulday(& startTime%var(iLookTIME%iyyy), & ! year startTime%var(iLookTIME%im), & ! month startTime%var(iLookTIME%id), & ! day startTime%var(iLookTIME%ih), & ! hour startTime%var(iLookTIME%imin), & ! minute 0._dp, & ! second dJulianStart, & ! julian date for the start of the simulation err, cmessage) ! error control if(err/=0)then; err=20; message=trim(message)//trim(cmessage); return; end if ! put simulation end time information into the time structures call extractTime(trim(SIM_END_TM), & ! date-time string finshTime%var(iLookTIME%iyyy), & ! year finshTime%var(iLookTIME%im), & ! month finshTime%var(iLookTIME%id), & ! day finshTime%var(iLookTIME%ih), & ! hour finshTime%var(iLookTIME%imin), & ! minute dsec, & ! second finshTime%var(iLookTIME%ih_tz), & ! time zone hour finshTime%var(iLookTIME%imin_tz), & ! time zone minnute dsec_tz, & ! time zone seconds err,cmessage) ! error control if(err/=0)then; err=20; message=trim(message)//trim(cmessage); return; end if ! compute the julian date (fraction of day) for the end of the simulation call compjulday(& finshTime%var(iLookTIME%iyyy), & ! year finshTime%var(iLookTIME%im), & ! month finshTime%var(iLookTIME%id), & ! day finshTime%var(iLookTIME%ih), & ! hour finshTime%var(iLookTIME%imin), & ! minute 0._dp, & ! second dJulianFinsh, & ! julian date for the end of the simulation err, cmessage) ! error control if(err/=0)then; err=20; message=trim(message)//trim(cmessage); return; end if ! check start and finish time ! write(*,'(a,i4,1x,4(i2,1x))') 'startTime: iyyy, im, id, ih, imin = ', startTime%var(1:5) ! write(*,'(a,i4,1x,4(i2,1x))') 'finshTime: iyyy, im, id, ih, imin = ', finshTime%var(1:5) ! check that simulation end time is > start time if(dJulianFinsh < dJulianStart)then; err=20; message=trim(message)//'end time of simulation occurs before start time'; return; end if ! initialize the old time vector (time from the previous time step) ! oldTime%var(:) = startTime%var(:) ! compute the number of time steps numSteps = nint( (dJulianFinsh - dJulianStart)*secprday/data_step ) + 1 numTim = numSteps ! write(*,'(a,1x,i10)') 'number of time steps = ', numSteps ! ------------------------------------------------------------------------------------------------- ! set Noah-MP options DVEG=3 ! option for dynamic vegetation OPT_RAD=3 ! option for canopy radiation OPT_ALB=2 ! option for snow albedo ! set zero option for thee category tables ! NOTE: we want to keep track of these decisions, but not used in the physics routines model_decisions(iLookDECISIONS%soilCatTbl)%iDecision = 0 model_decisions(iLookDECISIONS%vegeParTbl)%iDecision = 0 ! identify the choice of function for the soil moisture control on stomatal resistance select case(trim(model_decisions(iLookDECISIONS%soilStress)%cDecision)) case('NoahType'); model_decisions(iLookDECISIONS%soilStress)%iDecision = NoahType ! thresholded linear function of volumetric liquid water content case('CLM_Type'); model_decisions(iLookDECISIONS%soilStress)%iDecision = CLM_Type ! thresholded linear function of matric head case('SiB_Type'); model_decisions(iLookDECISIONS%soilStress)%iDecision = SiB_Type ! exponential of the log of matric head case default err=10; message=trim(message)//"unknown soil moisture function [option="//trim(model_decisions(iLookDECISIONS%soilStress)%cDecision)//"]"; return end select ! identify the choice of function for stomatal resistance select case(trim(model_decisions(iLookDECISIONS%stomResist)%cDecision)) case('BallBerry' ); model_decisions(iLookDECISIONS%stomResist)%iDecision = BallBerry ! Ball-Berry case('Jarvis' ); model_decisions(iLookDECISIONS%stomResist)%iDecision = Jarvis ! Jarvis case('simpleResistance' ); model_decisions(iLookDECISIONS%stomResist)%iDecision = simpleResistance ! simple resistance formulation case('BallBerryFlex' ); model_decisions(iLookDECISIONS%stomResist)%iDecision = BallBerryFlex ! flexible Ball-Berry scheme case('BallBerryTest' ); model_decisions(iLookDECISIONS%stomResist)%iDecision = BallBerryTest ! flexible Ball-Berry scheme (testing) case default err=10; message=trim(message)//"unknown stomatal resistance function [option="//trim(model_decisions(iLookDECISIONS%stomResist)%cDecision)//"]"; return end select ! identify the leaf temperature controls on photosynthesis + stomatal resistance if(model_decisions(iLookDECISIONS%stomResist)%iDecision >= BallBerryFlex)then select case(trim(model_decisions(iLookDECISIONS%bbTempFunc)%cDecision)) case('q10Func' ); model_decisions(iLookDECISIONS%bbTempFunc)%iDecision = q10Func case('Arrhenius' ); model_decisions(iLookDECISIONS%bbTempFunc)%iDecision = Arrhenius case default err=10; message=trim(message)//"unknown leaf temperature function [option="//trim(model_decisions(iLookDECISIONS%bbTempFunc)%cDecision)//"]"; return end select end if ! identify the humidity controls on stomatal resistance if(model_decisions(iLookDECISIONS%stomResist)%iDecision >= BallBerryFlex)then select case(trim(model_decisions(iLookDECISIONS%bbHumdFunc)%cDecision)) case('humidLeafSurface' ); model_decisions(iLookDECISIONS%bbHumdFunc)%iDecision = humidLeafSurface case('scaledHyperbolic' ); model_decisions(iLookDECISIONS%bbHumdFunc)%iDecision = scaledHyperbolic case default err=10; message=trim(message)//"unknown humidity function [option="//trim(model_decisions(iLookDECISIONS%bbHumdFunc)%cDecision)//"]"; return end select end if ! identify functions for electron transport function (dependence of photosynthesis on PAR) if(model_decisions(iLookDECISIONS%stomResist)%iDecision >= BallBerryFlex)then select case(trim(model_decisions(iLookDECISIONS%bbElecFunc)%cDecision)) case('linear' ); model_decisions(iLookDECISIONS%bbElecFunc)%iDecision = linear case('linearJmax' ); model_decisions(iLookDECISIONS%bbElecFunc)%iDecision = linearJmax case('quadraticJmax' ); model_decisions(iLookDECISIONS%bbElecFunc)%iDecision = quadraticJmax case default err=10; message=trim(message)//"unknown electron transport function [option="//trim(model_decisions(iLookDECISIONS%bbElecFunc)%cDecision)//"]"; return end select end if ! identify the use of the co2 compensation point in the stomatal conductance calaculations if(model_decisions(iLookDECISIONS%stomResist)%iDecision >= BallBerryFlex)then select case(trim(model_decisions(iLookDECISIONS%bbCO2point)%cDecision)) case('origBWB' ); model_decisions(iLookDECISIONS%bbCO2point)%iDecision = origBWB case('Leuning' ); model_decisions(iLookDECISIONS%bbCO2point)%iDecision = Leuning case default err=10; message=trim(message)//"unknown option for the co2 compensation point [option="//trim(model_decisions(iLookDECISIONS%bbCO2point)%cDecision)//"]"; return end select end if ! identify the iterative numerical solution method used in the Ball-Berry stomatal resistance parameterization if(model_decisions(iLookDECISIONS%stomResist)%iDecision >= BallBerryFlex)then select case(trim(model_decisions(iLookDECISIONS%bbNumerics)%cDecision)) case('NoahMPsolution' ); model_decisions(iLookDECISIONS%bbNumerics)%iDecision = NoahMPsolution ! the NoahMP solution (and CLM4): fixed point iteration; max 3 iterations case('newtonRaphson' ); model_decisions(iLookDECISIONS%bbNumerics)%iDecision = newtonRaphson ! full Newton-Raphson iterative solution to convergence case default err=10; message=trim(message)//"unknown option for the Ball-Berry numerical solution [option="//trim(model_decisions(iLookDECISIONS%bbNumerics)%cDecision)//"]"; return end select end if ! identify the controls on carbon assimilation if(model_decisions(iLookDECISIONS%stomResist)%iDecision >= BallBerryFlex)then select case(trim(model_decisions(iLookDECISIONS%bbAssimFnc)%cDecision)) case('colimitation' ); model_decisions(iLookDECISIONS%bbAssimFnc)%iDecision = colimitation ! enable colimitation, as described by Collatz et al. (1991) and Sellers et al. (1996) case('minFunc' ); model_decisions(iLookDECISIONS%bbAssimFnc)%iDecision = minFunc ! do not enable colimitation: use minimum of the three controls on carbon assimilation case default err=10; message=trim(message)//"unknown option for the controls on carbon assimilation [option="//trim(model_decisions(iLookDECISIONS%bbAssimFnc)%cDecision)//"]"; return end select end if ! identify the scaling of photosynthesis from the leaf to the canopy if(model_decisions(iLookDECISIONS%stomResist)%iDecision >= BallBerryFlex)then select case(trim(model_decisions(iLookDECISIONS%bbCanIntg8)%cDecision)) case('constantScaling' ); model_decisions(iLookDECISIONS%bbCanIntg8)%iDecision = constantScaling ! constant scaling factor case('laiScaling' ); model_decisions(iLookDECISIONS%bbCanIntg8)%iDecision = laiScaling ! exponential function of LAI (Leuning, Plant Cell Env 1995: "Scaling from..." [eq 9]) case default err=10; message=trim(message)//"unknown option for scaling of photosynthesis from the leaf to the canopy [option="//trim(model_decisions(iLookDECISIONS%bbCanIntg8)%cDecision)//"]"; return end select end if ! identify the numerical method select case(trim(model_decisions(iLookDECISIONS%num_method)%cDecision)) case('itertive'); model_decisions(iLookDECISIONS%num_method)%iDecision = iterative ! iterative case('non_iter'); model_decisions(iLookDECISIONS%num_method)%iDecision = nonIterative ! non-iterative case('itersurf'); model_decisions(iLookDECISIONS%num_method)%iDecision = iterSurfEnergyBal ! iterate only on the surface energy balance case default err=10; message=trim(message)//"unknown numerical method [option="//trim(model_decisions(iLookDECISIONS%num_method)%cDecision)//"]"; return end select ! identify the method used to calculate flux derivatives select case(trim(model_decisions(iLookDECISIONS%fDerivMeth)%cDecision)) case('numericl'); model_decisions(iLookDECISIONS%fDerivMeth)%iDecision = numerical ! numerical case('analytic'); model_decisions(iLookDECISIONS%fDerivMeth)%iDecision = analytical ! analytical case default err=10; message=trim(message)//"unknown method used to calculate flux derivatives [option="//trim(model_decisions(iLookDECISIONS%fDerivMeth)%cDecision)//"]"; return end select ! identify the method used to determine LAI and SAI select case(trim(model_decisions(iLookDECISIONS%LAI_method)%cDecision)) case('monTable'); model_decisions(iLookDECISIONS%LAI_method)%iDecision = monthlyTable ! LAI/SAI taken directly from a monthly table for different vegetation classes case('specified'); model_decisions(iLookDECISIONS%LAI_method)%iDecision = specified ! LAI/SAI computed from green vegetation fraction and winterSAI and summerLAI parameters case default err=10; message=trim(message)//"unknown method to determine LAI and SAI [option="//trim(model_decisions(iLookDECISIONS%LAI_method)%cDecision)//"]"; return end select ! identify the canopy interception parameterization select case(trim(model_decisions(iLookDECISIONS%cIntercept)%cDecision)) case('notPopulatedYet'); model_decisions(iLookDECISIONS%cIntercept)%iDecision = unDefined case('sparseCanopy'); model_decisions(iLookDECISIONS%cIntercept)%iDecision = sparseCanopy case('storageFunc'); model_decisions(iLookDECISIONS%cIntercept)%iDecision = storageFunc case default err=10; message=trim(message)//"unknown canopy interception parameterization [option="//trim(model_decisions(iLookDECISIONS%cIntercept)%cDecision)//"]"; return end select ! identify the form of Richards' equation select case(trim(model_decisions(iLookDECISIONS%f_Richards)%cDecision)) case('moisture'); model_decisions(iLookDECISIONS%f_Richards)%iDecision = moisture ! moisture-based form case('mixdform'); model_decisions(iLookDECISIONS%f_Richards)%iDecision = mixdform ! mixed form case default err=10; message=trim(message)//"unknown form of Richards' equation [option="//trim(model_decisions(iLookDECISIONS%f_Richards)%cDecision)//"]"; return end select ! identify the groundwater parameterization select case(trim(model_decisions(iLookDECISIONS%groundwatr)%cDecision)) case('qTopmodl'); model_decisions(iLookDECISIONS%groundwatr)%iDecision = qbaseTopmodel ! TOPMODEL-ish baseflow parameterization case('bigBuckt'); model_decisions(iLookDECISIONS%groundwatr)%iDecision = bigBucket ! a big bucket (lumped aquifer model) case('noXplict'); model_decisions(iLookDECISIONS%groundwatr)%iDecision = noExplicit ! no explicit groundwater parameterization case default err=10; message=trim(message)//"unknown groundwater parameterization [option="//trim(model_decisions(iLookDECISIONS%groundwatr)%cDecision)//"]"; return end select ! identify the hydraulic conductivity profile select case(trim(model_decisions(iLookDECISIONS%hc_profile)%cDecision)) case('constant'); model_decisions(iLookDECISIONS%hc_profile)%iDecision = constant ! constant hydraulic conductivity with depth case('pow_prof'); model_decisions(iLookDECISIONS%hc_profile)%iDecision = powerLaw_profile ! power-law profile case default err=10; message=trim(message)//"unknown hydraulic conductivity profile [option="//trim(model_decisions(iLookDECISIONS%hc_profile)%cDecision)//"]"; return end select ! identify the upper boundary conditions for thermodynamics select case(trim(model_decisions(iLookDECISIONS%bcUpprTdyn)%cDecision)) case('presTemp'); model_decisions(iLookDECISIONS%bcUpprTdyn)%iDecision = prescribedTemp ! prescribed temperature case('nrg_flux'); model_decisions(iLookDECISIONS%bcUpprTdyn)%iDecision = energyFlux ! energy flux case('zeroFlux'); model_decisions(iLookDECISIONS%bcUpprTdyn)%iDecision = zeroFlux ! zero flux case default err=10; message=trim(message)//"unknown upper boundary conditions for thermodynamics [option="//trim(model_decisions(iLookDECISIONS%bcUpprTdyn)%cDecision)//"]"; return end select ! identify the lower boundary conditions for thermodynamics select case(trim(model_decisions(iLookDECISIONS%bcLowrTdyn)%cDecision)) case('presTemp'); model_decisions(iLookDECISIONS%bcLowrTdyn)%iDecision = prescribedTemp ! prescribed temperature case('zeroFlux'); model_decisions(iLookDECISIONS%bcLowrTdyn)%iDecision = zeroFlux ! zero flux case default err=10; message=trim(message)//"unknown lower boundary conditions for thermodynamics [option="//trim(model_decisions(iLookDECISIONS%bcLowrTdyn)%cDecision)//"]"; return end select ! identify the upper boundary conditions for soil hydrology select case(trim(model_decisions(iLookDECISIONS%bcUpprSoiH)%cDecision)) case('presHead'); model_decisions(iLookDECISIONS%bcUpprSoiH)%iDecision = prescribedHead ! prescribed head (volumetric liquid water content for mixed form of Richards' eqn) case('liq_flux'); model_decisions(iLookDECISIONS%bcUpprSoiH)%iDecision = liquidFlux ! liquid water flux case default err=10; message=trim(message)//"unknown upper boundary conditions for soil hydrology [option="//trim(model_decisions(iLookDECISIONS%bcUpprSoiH)%cDecision)//"]"; return end select ! identify the lower boundary conditions for soil hydrology select case(trim(model_decisions(iLookDECISIONS%bcLowrSoiH)%cDecision)) case('presHead'); model_decisions(iLookDECISIONS%bcLowrSoiH)%iDecision = prescribedHead ! prescribed head (volumetric liquid water content for mixed form of Richards' eqn) case('bottmPsi'); model_decisions(iLookDECISIONS%bcLowrSoiH)%iDecision = funcBottomHead ! function of matric head in the lower-most layer case('drainage'); model_decisions(iLookDECISIONS%bcLowrSoiH)%iDecision = freeDrainage ! free drainage case('zeroFlux'); model_decisions(iLookDECISIONS%bcLowrSoiH)%iDecision = zeroFlux ! zero flux case default err=10; message=trim(message)//"unknown lower boundary conditions for soil hydrology [option="//trim(model_decisions(iLookDECISIONS%bcLowrSoiH)%cDecision)//"]"; return end select ! identify the choice of parameterization for vegetation roughness length and displacement height select case(trim(model_decisions(iLookDECISIONS%veg_traits)%cDecision)) case('Raupach_BLM1994'); model_decisions(iLookDECISIONS%veg_traits)%iDecision = Raupach_BLM1994 ! Raupach (BLM 1994) "Simplified expressions..." case('CM_QJRMS1988' ); model_decisions(iLookDECISIONS%veg_traits)%iDecision = CM_QJRMS1988 ! Choudhury and Monteith (QJRMS 1998) "A four layer model for the heat budget..." case('vegTypeTable' ); model_decisions(iLookDECISIONS%veg_traits)%iDecision = vegTypeTable ! constant parameters dependent on the vegetation type case default err=10; message=trim(message)//"unknown parameterization for vegetation roughness length and displacement height [option="//trim(model_decisions(iLookDECISIONS%veg_traits)%cDecision)//"]"; return end select ! identify the choice of parameterization for the rooting profile ! NOTE: for backwards compatibility select powerLaw if rooting profile is undefined select case(trim(model_decisions(iLookDECISIONS%rootProfil)%cDecision)) case('powerLaw','notPopulatedYet'); model_decisions(iLookDECISIONS%rootProfil)%iDecision = powerLaw ! simple power-law rooting profile case('doubleExp'); model_decisions(iLookDECISIONS%rootProfil)%iDecision = doubleExp ! the double exponential function of Xeng et al. (JHM 2001) case default err=10; message=trim(message)//"unknown parameterization for rooting profile [option="//trim(model_decisions(iLookDECISIONS%rootProfil)%cDecision)//"]"; return end select ! identify the choice of parameterization for canopy emissivity select case(trim(model_decisions(iLookDECISIONS%canopyEmis)%cDecision)) case('simplExp'); model_decisions(iLookDECISIONS%canopyEmis)%iDecision = simplExp ! simple exponential function case('difTrans'); model_decisions(iLookDECISIONS%canopyEmis)%iDecision = difTrans ! parameterized as a function of diffuse transmissivity case default err=10; message=trim(message)//"unknown parameterization for canopy emissivity [option="//trim(model_decisions(iLookDECISIONS%canopyEmis)%cDecision)//"]"; return end select ! choice of parameterization for snow interception select case(trim(model_decisions(iLookDECISIONS%snowIncept)%cDecision)) case('stickySnow'); model_decisions(iLookDECISIONS%snowIncept)%iDecision = stickySnow ! maximum interception capacity an increasing function of temerature case('lightSnow' ); model_decisions(iLookDECISIONS%snowIncept)%iDecision = lightSnow ! maximum interception capacity an inverse function of new snow density case default err=10; message=trim(message)//"unknown option for snow interception capacity[option="//trim(model_decisions(iLookDECISIONS%snowIncept)%cDecision)//"]"; return end select ! identify the choice of wind profile select case(trim(model_decisions(iLookDECISIONS%windPrfile)%cDecision)) case('exponential' ); model_decisions(iLookDECISIONS%windPrfile)%iDecision = exponential ! exponential wind profile extends to the surface case('logBelowCanopy'); model_decisions(iLookDECISIONS%windPrfile)%iDecision = logBelowCanopy ! logarithmic profile below the vegetation canopy case default err=10; message=trim(message)//"unknown option for choice of wind profile[option="//trim(model_decisions(iLookDECISIONS%windPrfile)%cDecision)//"]"; return end select ! identify the choice of atmospheric stability function select case(trim(model_decisions(iLookDECISIONS%astability)%cDecision)) case('standard'); model_decisions(iLookDECISIONS%astability)%iDecision = standard ! standard MO similarity, a la Anderson (1976) case('louisinv'); model_decisions(iLookDECISIONS%astability)%iDecision = louisInversePower ! Louis (1979) inverse power function case('mahrtexp'); model_decisions(iLookDECISIONS%astability)%iDecision = mahrtExponential ! Mahrt (1987) exponential case default err=10; message=trim(message)//"unknown stability function [option="//trim(model_decisions(iLookDECISIONS%astability)%cDecision)//"]"; return end select ! choice of canopy shortwave radiation method select case(trim(model_decisions(iLookDECISIONS%canopySrad)%cDecision)) case('noah_mp' ); model_decisions(iLookDECISIONS%canopySrad)%iDecision = noah_mp ! full Noah-MP implementation (including albedo) case('CLM_2stream'); model_decisions(iLookDECISIONS%canopySrad)%iDecision = CLM_2stream ! CLM 2-stream model (see CLM documentation) case('UEB_2stream'); model_decisions(iLookDECISIONS%canopySrad)%iDecision = UEB_2stream ! UEB 2-stream model (Mahat and Tarboton, WRR 2011) case('NL_scatter' ); model_decisions(iLookDECISIONS%canopySrad)%iDecision = NL_scatter ! Simplified method Nijssen and Lettenmaier (JGR 1999) case('BeersLaw' ); model_decisions(iLookDECISIONS%canopySrad)%iDecision = BeersLaw ! Beer's Law (as implemented in VIC) case default err=10; message=trim(message)//"unknown canopy radiation method [option="//trim(model_decisions(iLookDECISIONS%canopySrad)%cDecision)//"]"; return end select ! choice of albedo representation select case(trim(model_decisions(iLookDECISIONS%alb_method)%cDecision)) case('conDecay'); model_decisions(iLookDECISIONS%alb_method)%iDecision = constantDecay ! constant decay (e.g., VIC, CLASS) case('varDecay'); model_decisions(iLookDECISIONS%alb_method)%iDecision = variableDecay ! variable decay (e.g., BATS approach, with destructive metamorphism + soot content) case default err=10; message=trim(message)//"unknown option for snow albedo [option="//trim(model_decisions(iLookDECISIONS%alb_method)%cDecision)//"]"; return end select ! choice of snow compaction routine select case(trim(model_decisions(iLookDECISIONS%compaction)%cDecision)) case('consettl'); model_decisions(iLookDECISIONS%compaction)%iDecision = constantSettlement ! constant settlement rate case('anderson'); model_decisions(iLookDECISIONS%compaction)%iDecision = andersonEmpirical ! semi-empirical method of Anderson (1976) case default err=10; message=trim(message)//"unknown option for snow compaction [option="//trim(model_decisions(iLookDECISIONS%compaction)%cDecision)//"]"; return end select ! choice of method to combine and sub-divide snow layers select case(trim(model_decisions(iLookDECISIONS%snowLayers)%cDecision)) case('jrdn1991'); model_decisions(iLookDECISIONS%snowLayers)%iDecision = sameRulesAllLayers ! SNTHERM option: same combination/sub-dividion rules applied to all layers case('CLM_2010'); model_decisions(iLookDECISIONS%snowLayers)%iDecision = rulesDependLayerIndex ! CLM option: combination/sub-dividion rules depend on layer index case default err=10; message=trim(message)//"unknown option for combination/sub-division of snow layers [option="//trim(model_decisions(iLookDECISIONS%snowLayers)%cDecision)//"]"; return end select ! choice of thermal conductivity representation for snow select case(trim(model_decisions(iLookDECISIONS%thCondSnow)%cDecision)) case('tyen1965'); model_decisions(iLookDECISIONS%thCondSnow)%iDecision = Yen1965 ! Yen (1965) case('melr1977'); model_decisions(iLookDECISIONS%thCondSnow)%iDecision = Mellor1977 ! Mellor (1977) case('jrdn1991'); model_decisions(iLookDECISIONS%thCondSnow)%iDecision = Jordan1991 ! Jordan (1991) case('smnv2000'); model_decisions(iLookDECISIONS%thCondSnow)%iDecision = Smirnova2000 ! Smirnova et al. (2000) case default err=10; message=trim(message)//"unknown option for thermal conductivity of snow [option="//trim(model_decisions(iLookDECISIONS%thCondSnow)%cDecision)//"]"; return end select ! choice of thermal conductivity representation for soil select case(trim(model_decisions(iLookDECISIONS%thCondSoil)%cDecision)) case('funcSoilWet'); model_decisions(iLookDECISIONS%thCondSoil)%iDecision = funcSoilWet ! function of soil wetness case('mixConstit' ); model_decisions(iLookDECISIONS%thCondSoil)%iDecision = mixConstit ! mixture of constituents case('hanssonVZJ' ); model_decisions(iLookDECISIONS%thCondSoil)%iDecision = hanssonVZJ ! test case for the mizoguchi lab experiment, Hansson et al. VZJ 2004 case default err=10; message=trim(message)//"unknown option for thermal conductivity of soil [option="//trim(model_decisions(iLookDECISIONS%thCondSoil)%cDecision)//"]"; return end select ! choice of method for the spatial representation of groundwater select case(trim(model_decisions(iLookDECISIONS%spatial_gw)%cDecision)) case('localColumn'); model_decisions(iLookDECISIONS%spatial_gw)%iDecision = localColumn ! separate groundwater in each local soil column case('singleBasin'); model_decisions(iLookDECISIONS%spatial_gw)%iDecision = singleBasin ! single groundwater store over the entire basin case default err=10; message=trim(message)//"unknown option for spatial representation of groundwater [option="//trim(model_decisions(iLookDECISIONS%spatial_gw)%cDecision)//"]"; return end select ! choice of routing method select case(trim(model_decisions(iLookDECISIONS%subRouting)%cDecision)) case('timeDlay'); model_decisions(iLookDECISIONS%subRouting)%iDecision = timeDelay ! time-delay histogram case('qInstant'); model_decisions(iLookDECISIONS%subRouting)%iDecision = qInstant ! instantaneous routing case default err=10; message=trim(message)//"unknown option for sub-grid routing [option="//trim(model_decisions(iLookDECISIONS%subRouting)%cDecision)//"]"; return end select ! choice of new snow density ! NOTE: use hedAndPom as the default, where density method is undefined (not populated yet) select case(trim(model_decisions(iLookDECISIONS%snowDenNew)%cDecision)) case('hedAndPom','notPopulatedYet'); model_decisions(iLookDECISIONS%snowDenNew)%iDecision = hedAndPom ! Hedstrom and Pomeroy (1998), expoential increase case('anderson'); model_decisions(iLookDECISIONS%snowDenNew)%iDecision = anderson ! Anderson 1976 case('pahaut_76'); model_decisions(iLookDECISIONS%snowDenNew)%iDecision = pahaut_76 ! Pahaut 1976, wind speed dependent (derived from Col de Porte, French Alps) case('constDens'); model_decisions(iLookDECISIONS%snowDenNew)%iDecision = constDens ! Constant new snow density case default err=10; message=trim(message)//"unknown option for new snow density [option="//trim(model_decisions(iLookDECISIONS%snowDenNew)%cDecision)//"]"; return end select ! choice of snow unloading from canopy select case(trim(model_decisions(iLookDECISIONS%snowUnload)%cDecision)) case('meltDripUnload','notPopulatedYet'); model_decisions(iLookDECISIONS%snowUnload)%iDecision = meltDripUnload ! Hedstrom and Pomeroy (1998), Storck et al 2002 (snowUnloadingCoeff & ratioDrip2Unloading) case('windUnload'); model_decisions(iLookDECISIONS%snowUnload)%iDecision = windUnload ! Roesch et al 2001, formulate unloading based on wind and temperature case default err=10; message=trim(message)//"unknown option for snow unloading [option="//trim(model_decisions(iLookDECISIONS%snowUnload)%cDecision)//"]"; return end select ! ----------------------------------------------------------------------------------------------------------------------------------------------- ! check for consistency among options ! ----------------------------------------------------------------------------------------------------------------------------------------------- ! check there is prescribedHead for soil hydrology when zeroFlux or prescribedTemp for thermodynamics !select case(model_decisions(iLookDECISIONS%bcUpprTdyn)%iDecision) ! case(prescribedTemp,zeroFlux) ! if(model_decisions(iLookDECISIONS%bcUpprSoiH)%iDecision /= prescribedHead)then ! message=trim(message)//'upper boundary condition for soil hydology must be presHead with presTemp and zeroFlux options for thermodynamics' ! err=20; return ! end if !end select ! check there is prescribedTemp or zeroFlux for thermodynamics when using prescribedHead for soil hydrology !select case(model_decisions(iLookDECISIONS%bcUpprSoiH)%iDecision) ! case(prescribedHead) ! ! check that upper boundary condition for thermodynamics is presTemp or zeroFlux ! select case(model_decisions(iLookDECISIONS%bcUpprTdyn)%iDecision) ! case(prescribedTemp,zeroFlux) ! do nothing: this is OK ! case default ! message=trim(message)//'upper boundary condition for thermodynamics must be presTemp or zeroFlux with presHead option for soil hydology' ! err=20; return ! end select !end select ! check zero flux lower boundary for topmodel baseflow option select case(model_decisions(iLookDECISIONS%groundwatr)%iDecision) case(qbaseTopmodel) if(model_decisions(iLookDECISIONS%bcLowrSoiH)%iDecision /= zeroFlux)then message=trim(message)//'lower boundary condition for soil hydology must be zeroFlux with qbaseTopmodel option for groundwater' err=20; return end if end select ! check power-law profile is selected when using topmodel baseflow option select case(model_decisions(iLookDECISIONS%groundwatr)%iDecision) case(qbaseTopmodel) if(model_decisions(iLookDECISIONS%hc_profile)%iDecision /= powerLaw_profile)then message=trim(message)//'power-law transmissivity profile must be selected when using topmodel baseflow option' err=20; return end if end select ! check bigBucket groundwater option is used when for spatial groundwater is singleBasin if(model_decisions(iLookDECISIONS%spatial_gw)%iDecision == singleBasin)then if(model_decisions(iLookDECISIONS%groundwatr)%iDecision /= bigBucket)then message=trim(message)//'groundwater parameterization must be bigBucket when using singleBasin for spatial_gw' err=20; return end if end if ! ensure that the LAI seaonality option is switched off (this was a silly idea, in retrospect) !if(model_decisions(iLookDECISIONS%LAI_method)%iDecision == specified)then ! message=trim(message)//'parameterization of LAI in terms of seasonal cycle of green veg fraction was a silly idea '& ! //' -- the LAI_method option ["specified"] is no longer supported' ! err=20; return !end if end subroutine mDecisions ! ************************************************************************************************ ! private subroutine readoption: read information from model decisions file ! ************************************************************************************************ subroutine readoption(err,message) ! used to read information from model decisions file USE ascii_util_module,only:file_open ! open file USE ascii_util_module,only:linewidth ! max character number for one line USE ascii_util_module,only:get_vlines ! get a vector of non-comment lines USE summaActors_FileManager,only:SETTINGS_PATH ! path for metadata files USE summaActors_FileManager,only:M_DECISIONS ! definition of modeling options USE get_ixname_module,only:get_ixdecisions ! identify index of named variable USE globalData,only:model_decisions ! model decision structure implicit none ! define output integer(i4b),intent(out) :: err ! error code character(*),intent(out) :: message ! error message ! define local variables character(len=256) :: cmessage ! error message for downwind routine character(LEN=256) :: infile ! input filename integer(i4b) :: unt ! file unit (free unit output from file_open) character(LEN=linewidth),allocatable :: charline(:) ! vector of character strings integer(i4b) :: nDecisions ! number of model decisions integer(i4b) :: iDecision ! index of model decisions character(len=32) :: decision ! name of model decision character(len=32) :: option ! option for model decision integer(i4b) :: iVar ! index of the decision in the data structure ! Start procedure here err=0; message='readoption/' ! build filename infile = trim(SETTINGS_PATH)//trim(M_DECISIONS) ! write(*,'(2(a,1x))') 'decisions file = ', trim(infile) ! open file call file_open(trim(infile),unt,err,cmessage) if(err/=0)then; message=trim(message)//trim(cmessage); return; end if ! get a list of character strings from non-comment lines call get_vlines(unt,charline,err,cmessage) if(err/=0)then; message=trim(message)//trim(cmessage); return; end if ! close the file unit close(unt) ! get the number of model decisions nDecisions = size(charline) ! populate the model decisions structure do iDecision=1,nDecisions ! extract name of decision and the decision selected read(charline(iDecision),*,iostat=err) option, decision if (err/=0) then; err=30; message=trim(message)//"errorReadLine"; return; end if ! get the index of the decision in the data structure iVar = get_ixdecisions(trim(option)) ! write(*,'(i4,1x,a)') iDecision, trim(option)//': '//trim(decision) if(iVar<=0)then; err=40; message=trim(message)//"cannotFindDecisionIndex[name='"//trim(option)//"']"; return; end if ! populate the model decisions structure model_decisions(iVar)%cOption = trim(option) model_decisions(iVar)%cDecision = trim(decision) end do end subroutine readoption end module mDecisions_module