From 533df75d7ccb21588432c2633bd0d8fb76a7d200 Mon Sep 17 00:00:00 2001 From: Kyle <kyle.c.klenk@gmail.com> Date: Tue, 27 Sep 2022 20:11:45 +0000 Subject: [PATCH] copied file from summa --- build/source/engine/soilLiqFlx.f90 | 2 +- build/source/engine/vegNrgFlux.f90 | 6338 ++++++++++++++-------------- 2 files changed, 3103 insertions(+), 3237 deletions(-) diff --git a/build/source/engine/soilLiqFlx.f90 b/build/source/engine/soilLiqFlx.f90 index 520e9c3..e65e458 100644 --- a/build/source/engine/soilLiqFlx.f90 +++ b/build/source/engine/soilLiqFlx.f90 @@ -766,7 +766,7 @@ subroutine soilLiqFlx(& ! (use un-perturbed value) case default - s calarHydCondTrial = mLayerHydCond(nSoil) ! hydraulic conductivity at the mid-point of the lowest unsaturated soil layer (m s-1) + scalarHydCondTrial = mLayerHydCond(nSoil) ! hydraulic conductivity at the mid-point of the lowest unsaturated soil layer (m s-1) end select ! (re-computing hydraulic conductivity) diff --git a/build/source/engine/vegNrgFlux.f90 b/build/source/engine/vegNrgFlux.f90 index 63b68b1..1d42ffa 100644 --- a/build/source/engine/vegNrgFlux.f90 +++ b/build/source/engine/vegNrgFlux.f90 @@ -20,1941 +20,1848 @@ module vegNrgFlux_module - ! data types - USE nrtype - - ! derived types to define the data structures - USE data_types,only:& - var_i, & ! data vector (i4b) - var_d, & ! data vector (rkind) - var_ilength, & ! data vector with variable length dimension (i4b) - var_dlength, & ! data vector with variable length dimension (rkind) - model_options ! defines the model decisions - - ! indices that define elements of the data structures - USE var_lookup,only:iLookTYPE ! named variables for structure elements - USE var_lookup,only:iLookPROG ! named variables for structure elements - USE var_lookup,only:iLookDIAG ! named variables for structure elements - USE var_lookup,only:iLookFLUX ! named variables for structure elements - USE var_lookup,only:iLookFORCE ! named variables for structure elements - USE var_lookup,only:iLookPARAM ! named variables for structure elements - USE var_lookup,only:iLookINDEX ! named variables for structure elements - USE var_lookup,only:iLookBVAR ! named variables for structure elements - USE var_lookup,only:iLookDECISIONS ! named variables for elements of the decision structure - - ! constants - USE multiconst,only:gravity ! acceleration of gravity (m s-2) - USE multiconst,only:vkc ! von Karman's constant (-) - USE multiconst,only:w_ratio ! molecular ratio water to dry air (-) - USE multiconst,only:R_wv ! gas constant for water vapor (Pa K-1 m3 kg-1; J kg-1 K-1) - USE multiconst,only:Cp_air ! specific heat of air (J kg-1 K-1) - USE multiconst,only:Cp_ice ! specific heat of ice (J kg-1 K-1) - USE multiconst,only:Cp_soil ! specific heat of soil (J kg-1 K-1) - USE multiconst,only:Cp_water ! specific heat of liquid water (J kg-1 K-1) - USE multiconst,only:Tfreeze ! temperature at freezing (K) - USE multiconst,only:LH_fus ! latent heat of fusion (J kg-1) - USE multiconst,only:LH_vap ! latent heat of vaporization (J kg-1) - USE multiconst,only:LH_sub ! latent heat of sublimation (J kg-1) - USE multiconst,only:sb ! Stefan Boltzman constant (W m-2 K-4) - USE multiconst,only:iden_air ! intrinsic density of air (kg m-3) - USE multiconst,only:iden_ice ! intrinsic density of ice (kg m-3) - USE multiconst,only:iden_water ! intrinsic density of liquid water (kg m-3) - - ! look-up values for method used to compute derivative - USE mDecisions_module,only: & - numerical, & ! numerical solution - analytical ! analytical solution - - ! look-up values for choice of boundary conditions for thermodynamics - USE mDecisions_module,only: & - prescribedTemp, & ! prescribed temperature - energyFlux, & ! energy flux - zeroFlux ! zero flux - - ! look-up values for the choice of parameterization for vegetation roughness length and displacement height - USE mDecisions_module,only: & - Raupach_BLM1994, & ! Raupach (BLM 1994) "Simplified expressions..." - CM_QJRMS1988, & ! Choudhury and Monteith (QJRMS 1988) "A four layer model for the heat budget..." - vegTypeTable ! constant parameters dependent on the vegetation type - - ! look-up values for the choice of parameterization for canopy emissivity - USE mDecisions_module,only: & - simplExp, & ! simple exponential function - difTrans ! parameterized as a function of diffuse transmissivity - - ! look-up values for the choice of canopy wind profile - USE mDecisions_module,only: & - exponential, & ! exponential wind profile extends to the surface - logBelowCanopy ! logarithmic profile below the vegetation canopy - - ! look-up values for choice of stability function - USE mDecisions_module,only: & - standard, & ! standard MO similarity, a la Anderson (1976) - louisInversePower, & ! Louis (1979) inverse power function - mahrtExponential ! Mahrt (1987) exponential - - ! look-up values for the choice of groundwater representation (local-column, or single-basin) - USE mDecisions_module,only: & - localColumn, & ! separate groundwater representation in each local soil column - singleBasin ! single groundwater store over the entire basin - - ! ------------------------------------------------------------------------------------------------- - ! privacy - implicit none - private - public::vegNrgFlux - public::wettedFrac - ! dimensions - integer(i4b),parameter :: nBands=2 ! number of spectral bands for shortwave radiation - ! named variables - integer(i4b),parameter :: ist = 1 ! Surface type: IST=1 => soil; IST=2 => lake - integer(i4b),parameter :: isc = 4 ! Soil color type - integer(i4b),parameter :: ice = 0 ! Surface type: ICE=0 => soil; ICE=1 => sea-ice - ! spatial indices - integer(i4b),parameter :: iLoc = 1 ! i-location - integer(i4b),parameter :: jLoc = 1 ! j-location - ! algorithmic parameters - real(rkind),parameter :: missingValue=-9999._rkind ! missing value, used when diagnostic or state variables are undefined - real(rkind),parameter :: verySmall=1.e-6_rkind ! used as an additive constant to check if substantial difference among real numbers - real(rkind),parameter :: tinyVal=epsilon(1._rkind) ! used as an additive constant to check if substantial difference among real numbers - real(rkind),parameter :: mpe=1.e-6_rkind ! prevents overflow error if division by zero - real(rkind),parameter :: dx=1.e-11_rkind ! finite difference increment - ! control - logical(lgt) :: printflag ! flag to turn on printing - contains - - ! ******************************************************************************************************* - ! public subroutine vegNrgFlux: muster program to compute energy fluxes at vegetation and ground surfaces - ! ******************************************************************************************************* - subroutine vegNrgFlux(& - ! input: model control - firstSubStep, & ! intent(in): flag to indicate if we are processing the first sub-step - firstFluxCall, & ! intent(in): flag to indicate if we are processing the first flux call - computeVegFlux, & ! intent(in): flag to indicate if we need to compute fluxes over vegetation - requireLWBal, & ! intent(in): flag to indicate if we need longwave to be balanced - - ! input: model state variables - upperBoundTemp, & ! intent(in): temperature of the upper boundary (K) --> NOTE: use air temperature - canairTempTrial, & ! intent(in): trial value of the canopy air space temperature (K) - canopyTempTrial, & ! intent(in): trial value of canopy temperature (K) - groundTempTrial, & ! intent(in): trial value of ground temperature (K) - canopyIceTrial, & ! intent(in): trial value of mass of ice on the vegetation canopy (kg m-2) - canopyLiqTrial, & ! intent(in): trial value of mass of liquid water on the vegetation canopy (kg m-2) - - ! input: model derivatives - dCanLiq_dTcanopy, & ! intent(in): derivative in canopy liquid w.r.t. canopy temperature (kg m-2 K-1) - - ! input/output: data structures - type_data, & ! intent(in): type of vegetation and soil - forc_data, & ! intent(in): model forcing data - mpar_data, & ! intent(in): model parameters - indx_data, & ! intent(in): state vector geometry - prog_data, & ! intent(in): 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 - bvar_data, & ! intent(in): model variables for the local basin - model_decisions, & ! intent(in): model decisions - - ! output: liquid water fluxes associated with evaporation/transpiration (needed for coupling) - returnCanopyTranspiration, & ! intent(out): canopy transpiration (kg m-2 s-1) - returnCanopyEvaporation, & ! intent(out): canopy evaporation/condensation (kg m-2 s-1) - returnGroundEvaporation, & ! intent(out): ground evaporation/condensation -- below canopy or non-vegetated (kg m-2 s-1) - - ! output: fluxes - canairNetFlux, & ! intent(out): net energy flux for the canopy air space (W m-2) - canopyNetFlux, & ! intent(out): net energy flux for the vegetation canopy (W m-2) - groundNetFlux, & ! intent(out): net energy flux for the ground surface (W m-2) - - ! output: energy flux derivatives - dCanairNetFlux_dCanairTemp, & ! intent(out): derivative in net canopy air space flux w.r.t. canopy air temperature (W m-2 K-1) - dCanairNetFlux_dCanopyTemp, & ! intent(out): derivative in net canopy air space flux w.r.t. canopy temperature (W m-2 K-1) - dCanairNetFlux_dGroundTemp, & ! intent(out): derivative in net canopy air space flux w.r.t. ground temperature (W m-2 K-1) - dCanopyNetFlux_dCanairTemp, & ! intent(out): derivative in net canopy flux w.r.t. canopy air temperature (W m-2 K-1) - dCanopyNetFlux_dCanopyTemp, & ! intent(out): derivative in net canopy flux w.r.t. canopy temperature (W m-2 K-1) - dCanopyNetFlux_dGroundTemp, & ! intent(out): derivative in net canopy flux w.r.t. ground temperature (W m-2 K-1) - dGroundNetFlux_dCanairTemp, & ! intent(out): derivative in net ground flux w.r.t. canopy air temperature (W m-2 K-1) - dGroundNetFlux_dCanopyTemp, & ! intent(out): derivative in net ground flux w.r.t. canopy temperature (W m-2 K-1) - dGroundNetFlux_dGroundTemp, & ! intent(out): derivative in net ground flux w.r.t. ground temperature (W m-2 K-1) - - ! output liquid water flux derivarives (canopy evap) - dCanopyEvaporation_dCanWat, & ! intent(out): derivative in canopy evaporation w.r.t. canopy total water content (s-1) - dCanopyEvaporation_dTCanair, & ! intent(out): derivative in canopy evaporation w.r.t. canopy air temperature (kg m-2 s-1 K-1) - dCanopyEvaporation_dTCanopy, & ! intent(out): derivative in canopy evaporation w.r.t. canopy temperature (kg m-2 s-1 K-1) - dCanopyEvaporation_dTGround, & ! intent(out): derivative in canopy evaporation w.r.t. ground temperature (kg m-2 s-1 K-1) - - ! output: liquid water flux derivarives (ground evap) - dGroundEvaporation_dCanWat, & ! intent(out): derivative in ground evaporation w.r.t. canopy total water content (s-1) - dGroundEvaporation_dTCanair, & ! intent(out): derivative in ground evaporation w.r.t. canopy air temperature (kg m-2 s-1 K-1) - dGroundEvaporation_dTCanopy, & ! intent(out): derivative in ground evaporation w.r.t. canopy temperature (kg m-2 s-1 K-1) - dGroundEvaporation_dTGround, & ! intent(out): derivative in ground evaporation w.r.t. ground temperature (kg m-2 s-1 K-1) - - ! output: transpiration derivatives - dCanopyTrans_dCanWat, & ! intent(out): derivative in canopy transpiration w.r.t. canopy total water content (s-1) - dCanopyTrans_dTCanair, & ! intent(out): derivative in canopy transpiration w.r.t. canopy air temperature (kg m-2 s-1 K-1) - dCanopyTrans_dTCanopy, & ! intent(out): derivative in canopy transpiration w.r.t. canopy temperature (kg m-2 s-1 K-1) - dCanopyTrans_dTGround, & ! intent(out): derivative in canopy transpiration w.r.t. ground temperature (kg m-2 s-1 K-1) - - ! output: cross derivative terms - dCanopyNetFlux_dCanWat, & ! intent(out): derivative in net canopy fluxes w.r.t. canopy total water content (J kg-1 s-1) - dGroundNetFlux_dCanWat, & ! intent(out): derivative in net ground fluxes w.r.t. canopy total water content (J kg-1 s-1) - - ! output: error control - err,message) ! intent(out): error control - - ! utilities - USE expIntegral_module,only:expInt ! function to calculate the exponential integral - ! conversion functions - USE conv_funcs_module,only:satVapPress ! function to compute the saturated vapor pressure (Pa) - USE conv_funcs_module,only:getLatentHeatValue ! function to identify latent heat of vaporization/sublimation (J kg-1) - ! stomatal resistance - USE stomResist_module,only:stomResist ! subroutine to calculate stomatal resistance - ! phase changes - USE snow_utils_module,only:fracliquid ! compute fraction of liquid water at a given temperature - - ! compute energy and mass fluxes for vegetation - implicit none - - ! --------------------------------------------------------------------------------------- - ! * dummy variables - ! --------------------------------------------------------------------------------------- - ! input: model control - logical(lgt),intent(in) :: firstSubStep ! flag to indicate if we are processing the first sub-step - logical(lgt),intent(in) :: firstFluxCall ! flag to indicate if we are processing the first flux call - logical(lgt),intent(in) :: computeVegFlux ! flag to indicate if computing fluxes over vegetation - logical(lgt),intent(in) :: requireLWBal ! flag to indicate if we need longwave to be balanced - ! input: model state variables - real(rkind),intent(in) :: upperBoundTemp ! temperature of the upper boundary (K) --> NOTE: use air temperature - real(rkind),intent(in) :: canairTempTrial ! trial value of canopy air space temperature (K) - real(rkind),intent(in) :: canopyTempTrial ! trial value of canopy temperature (K) - real(rkind),intent(in) :: groundTempTrial ! trial value of ground temperature (K) - real(rkind),intent(in) :: canopyIceTrial ! trial value of mass of ice on the vegetation canopy (kg m-2) - real(rkind),intent(in) :: canopyLiqTrial ! trial value of mass of liquid water on the vegetation canopy (kg m-2) - - ! input: model derivatives - real(rkind),intent(in) :: dCanLiq_dTcanopy ! intent(in): derivative in canopy liquid w.r.t. canopy temperature (kg m-2 K-1) - - ! input/output: data structures - type(var_i),intent(in) :: type_data ! type of vegetation and soil - type(var_d),intent(in) :: forc_data ! model forcing data - type(var_dlength),intent(in) :: mpar_data ! model parameters - type(var_ilength),intent(in) :: indx_data ! state vector geometry - type(var_dlength),intent(in) :: 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 - type(var_dlength),intent(in) :: bvar_data ! model variables for the local basin - type(model_options),intent(in) :: model_decisions(:) ! model decisions - - ! output: liquid water fluxes associated with evaporation/transpiration (needed for coupling) - real(rkind),intent(out) :: returnCanopyTranspiration ! canopy transpiration (kg m-2 s-1) - real(rkind),intent(out) :: returnCanopyEvaporation ! canopy evaporation/condensation (kg m-2 s-1) - real(rkind),intent(out) :: returnGroundEvaporation ! ground evaporation/condensation -- below canopy or non-vegetated (kg m-2 s-1) - - ! output: fluxes - real(rkind),intent(out) :: canairNetFlux ! net energy flux for the canopy air space (W m-2) - real(rkind),intent(out) :: canopyNetFlux ! net energy flux for the vegetation canopy (W m-2) - real(rkind),intent(out) :: groundNetFlux ! net energy flux for the ground surface (W m-2) - - ! output: energy flux derivatives - real(rkind),intent(out) :: dCanairNetFlux_dCanairTemp ! derivative in net canopy air space flux w.r.t. canopy air temperature (W m-2 K-1) - real(rkind),intent(out) :: dCanairNetFlux_dCanopyTemp ! derivative in net canopy air space flux w.r.t. canopy temperature (W m-2 K-1) - real(rkind),intent(out) :: dCanairNetFlux_dGroundTemp ! derivative in net canopy air space flux w.r.t. ground temperature (W m-2 K-1) - real(rkind),intent(out) :: dCanopyNetFlux_dCanairTemp ! derivative in net canopy flux w.r.t. canopy air temperature (W m-2 K-1) - real(rkind),intent(out) :: dCanopyNetFlux_dCanopyTemp ! derivative in net canopy flux w.r.t. canopy temperature (W m-2 K-1) - real(rkind),intent(out) :: dCanopyNetFlux_dGroundTemp ! derivative in net canopy flux w.r.t. ground temperature (W m-2 K-1) - real(rkind),intent(out) :: dGroundNetFlux_dCanairTemp ! derivative in net ground flux w.r.t. canopy air temperature (W m-2 K-1) - real(rkind),intent(out) :: dGroundNetFlux_dCanopyTemp ! derivative in net ground flux w.r.t. canopy temperature (W m-2 K-1) - real(rkind),intent(out) :: dGroundNetFlux_dGroundTemp ! derivative in net ground flux w.r.t. ground temperature (W m-2 K-1) - - ! output: liquid flux derivatives (canopy evap) - real(rkind),intent(out) :: dCanopyEvaporation_dCanWat ! derivative in canopy evaporation w.r.t. canopy total water content (s-1) - real(rkind),intent(out) :: dCanopyEvaporation_dTCanair ! derivative in canopy evaporation w.r.t. canopy air temperature (kg m-2 s-1 K-1) - real(rkind),intent(out) :: dCanopyEvaporation_dTCanopy ! derivative in canopy evaporation w.r.t. canopy temperature (kg m-2 s-1 K-1) - real(rkind),intent(out) :: dCanopyEvaporation_dTGround ! derivative in canopy evaporation w.r.t. ground temperature (kg m-2 s-1 K-1) - - ! output: liquid flux derivatives (ground evap) - real(rkind),intent(out) :: dGroundEvaporation_dCanWat ! derivative in ground evaporation w.r.t. canopy total water content (s-1) - real(rkind),intent(out) :: dGroundEvaporation_dTCanair ! derivative in ground evaporation w.r.t. canopy air temperature (kg m-2 s-1 K-1) - real(rkind),intent(out) :: dGroundEvaporation_dTCanopy ! derivative in ground evaporation w.r.t. canopy temperature (kg m-2 s-1 K-1) - real(rkind),intent(out) :: dGroundEvaporation_dTGround ! derivative in ground evaporation w.r.t. ground temperature (kg m-2 s-1 K-1) - - ! output: transpiration derivatives - real(rkind),intent(out) :: dCanopyTrans_dCanWat ! intent(out): derivative in canopy transpiration w.r.t. canopy total water content (s-1) - real(rkind),intent(out) :: dCanopyTrans_dTCanair ! intent(out): derivative in canopy transpiration w.r.t. canopy air temperature (kg m-2 s-1 K-1) - real(rkind),intent(out) :: dCanopyTrans_dTCanopy ! intent(out): derivative in canopy transpiration w.r.t. canopy temperature (kg m-2 s-1 K-1) - real(rkind),intent(out) :: dCanopyTrans_dTGround ! intent(out): derivative in canopy transpiration w.r.t. ground temperature (kg m-2 s-1 K-1) - - ! output: cross derivative terms - real(rkind),intent(out) :: dCanopyNetFlux_dCanWat ! derivative in net canopy fluxes w.r.t. canopy total water content (J kg-1 s-1) - real(rkind),intent(out) :: dGroundNetFlux_dCanWat ! derivative in net ground fluxes w.r.t. canopy total water content (J kg-1 s-1) - - ! output: error control - integer(i4b),intent(out) :: err ! error code - character(*),intent(out) :: message ! error message - - ! --------------------------------------------------------------------------------------- - ! * local variables - ! --------------------------------------------------------------------------------------- - ! local (general) - character(LEN=256) :: cmessage ! error message of downwind routine - real(rkind) :: VAI ! vegetation area index (m2 m-2) - real(rkind) :: exposedVAI ! exposed vegetation area index (m2 m-2) - real(rkind) :: totalCanopyWater ! total water on the vegetation canopy (kg m-2) - real(rkind) :: scalarAquiferStorage ! aquifer storage (m) - - ! local (compute numerical derivatives) - integer(i4b),parameter :: unperturbed=1 ! named variable to identify the case of unperturbed state variables - integer(i4b),parameter :: perturbStateGround=2 ! named variable to identify the case where we perturb the ground temperature - integer(i4b),parameter :: perturbStateCanopy=3 ! named variable to identify the case where we perturb the canopy temperature - integer(i4b),parameter :: perturbStateCanair=4 ! named variable to identify the case where we perturb the canopy air temperature - integer(i4b),parameter :: perturbStateCanWat=5 ! named variable to identify the case where we perturb the canopy total water content - integer(i4b) :: itry ! index of flux evaluation - integer(i4b) :: nFlux ! number of flux evaluations - real(rkind) :: groundTemp ! value of ground temperature used in flux calculations (may be perturbed) - real(rkind) :: canopyTemp ! value of canopy temperature used in flux calculations (may be perturbed) - real(rkind) :: canairTemp ! value of canopy air temperature used in flux calculations (may be perturbed) - real(rkind) :: canopyWat ! value of canopy total water used in flux calculations (may be perturbed) - real(rkind) :: canopyLiq ! value of canopy liquid water used in flux calculations (may be perturbed) - real(rkind) :: canopyIce ! value of canopy ice used in flux calculations (may be perturbed) - real(rkind) :: try0,try1 ! trial values to evaluate specific derivatives (testing only) - - ! local (saturation vapor pressure of veg) - real(rkind) :: TV_celcius ! vegetaion temperature (C) - real(rkind) :: TG_celcius ! ground temperature (C) - real(rkind) :: dSVPCanopy_dCanopyTemp ! derivative in canopy saturated vapor pressure w.r.t. vegetation temperature (Pa/K) - real(rkind) :: dSVPGround_dGroundTemp ! derivative in ground saturated vapor pressure w.r.t. ground temperature (Pa/K) - - ! local (wetted canopy area) - real(rkind) :: fracLiquidCanopy ! fraction of liquid water in the canopy (-) - real(rkind) :: canopyWetFraction ! trial value of the canopy wetted fraction (-) - real(rkind) :: dCanopyWetFraction_dWat ! derivative in wetted fraction w.r.t. canopy total water (kg-1 m2) - real(rkind) :: dCanopyWetFraction_dT ! derivative in wetted fraction w.r.t. canopy temperature (K-1) - - ! local (longwave radiation) - real(rkind) :: expi ! exponential integral - real(rkind) :: scaleLAI ! scaled LAI (computing diffuse transmissivity) - real(rkind) :: diffuseTrans ! diffuse transmissivity (-) - real(rkind) :: groundEmissivity ! emissivity of the ground surface (-) - real(rkind),parameter :: vegEmissivity=0.98_rkind ! emissivity of vegetation (0.9665 in JULES) (-) - real(rkind),parameter :: soilEmissivity=0.98_rkind ! emmisivity of the soil (0.9665 in JULES) (-) - real(rkind),parameter :: snowEmissivity=0.99_rkind ! emissivity of snow (-) - real(rkind) :: dLWNetCanopy_dTCanopy ! derivative in net canopy radiation w.r.t. canopy temperature (W m-2 K-1) - real(rkind) :: dLWNetGround_dTGround ! derivative in net ground radiation w.r.t. ground temperature (W m-2 K-1) - real(rkind) :: dLWNetCanopy_dTGround ! derivative in net canopy radiation w.r.t. ground temperature (W m-2 K-1) - real(rkind) :: dLWNetGround_dTCanopy ! derivative in net ground radiation w.r.t. canopy temperature (W m-2 K-1) - - ! local (aerodynamic resistance) - real(rkind) :: scalarCanopyStabilityCorrection_old ! stability correction for the canopy (-) - real(rkind) :: scalarGroundStabilityCorrection_old ! stability correction for the ground surface (-) - - ! local (turbulent heat transfer) - real(rkind) :: z0Ground ! roughness length of the ground (ground below the canopy or non-vegetated surface) (m) - real(rkind) :: soilEvapFactor ! soil water control on evaporation from non-vegetated surfaces - real(rkind) :: soilRelHumidity_noSnow ! relative humidity in the soil pores [0-1] - real(rkind) :: scalarLeafConductance ! leaf conductance (m s-1) - real(rkind) :: scalarCanopyConductance ! canopy conductance (m s-1) - real(rkind) :: scalarGroundConductanceSH ! ground conductance for sensible heat (m s-1) - real(rkind) :: scalarGroundConductanceLH ! ground conductance for latent heat -- includes soil resistance (m s-1) - real(rkind) :: scalarEvapConductance ! conductance for evaporation (m s-1) - real(rkind) :: scalarTransConductance ! conductance for transpiration (m s-1) - real(rkind) :: scalarTotalConductanceSH ! total conductance for sensible heat (m s-1) - real(rkind) :: scalarTotalConductanceLH ! total conductance for latent heat (m s-1) - real(rkind) :: dGroundResistance_dTGround ! derivative in ground resistance w.r.t. ground temperature (s m-1 K-1) - real(rkind) :: dGroundResistance_dTCanopy ! derivative in ground resistance w.r.t. canopy temperature (s m-1 K-1) - real(rkind) :: dGroundResistance_dTCanair ! derivative in ground resistance w.r.t. canopy air temperature (s m-1 K-1) - real(rkind) :: dCanopyResistance_dTCanopy ! derivative in canopy resistance w.r.t. canopy temperature (s m-1 K-1) - real(rkind) :: dCanopyResistance_dTCanair ! derivative in canopy resistance w.r.t. canopy air temperature (s m-1 K-1) - real(rkind) :: turbFluxCanair ! total turbulent heat fluxes exchanged at the canopy air space (W m-2) - real(rkind) :: turbFluxCanopy ! total turbulent heat fluxes from the canopy to the canopy air space (W m-2) - real(rkind) :: turbFluxGround ! total turbulent heat fluxes from the ground to the canopy air space (W m-2) - - ! local (turbulent heat transfer -- compute numerical derivatives) - ! (temporary scalar resistances when states are perturbed) - real(rkind) :: trialLeafResistance ! mean leaf boundary layer resistance per unit leaf area (s m-1) - real(rkind) :: trialGroundResistance ! below canopy aerodynamic resistance (s m-1) - real(rkind) :: trialCanopyResistance ! above canopy aerodynamic resistance (s m-1) - real(rkind) :: notUsed_RiBulkCanopy ! bulk Richardson number for the canopy (-) - real(rkind) :: notUsed_RiBulkGround ! bulk Richardson number for the ground surface (-) - real(rkind) :: notUsed_z0Canopy ! roughness length of the vegetation canopy (m) - real(rkind) :: notUsed_WindReductionFactor ! canopy wind reduction factor (-) - real(rkind) :: notUsed_ZeroPlaneDisplacement ! zero plane displacement (m) - real(rkind) :: notUsed_scalarCanopyStabilityCorrection ! stability correction for the canopy (-) - real(rkind) :: notUsed_scalarGroundStabilityCorrection ! stability correction for the ground surface (-) - real(rkind) :: notUsed_EddyDiffusCanopyTop ! eddy diffusivity for heat at the top of the canopy (m2 s-1) - real(rkind) :: notUsed_FrictionVelocity ! friction velocity (m s-1) - real(rkind) :: notUsed_WindspdCanopyTop ! windspeed at the top of the canopy (m s-1) - real(rkind) :: notUsed_WindspdCanopyBottom ! windspeed at the height of the bottom of the canopy (m s-1) - real(rkind) :: notUsed_dGroundResistance_dTGround ! derivative in ground resistance w.r.t. ground temperature (s m-1 K-1) - real(rkind) :: notUsed_dGroundResistance_dTCanopy ! derivative in ground resistance w.r.t. canopy temperature (s m-1 K-1) - real(rkind) :: notUsed_dGroundResistance_dTCanair ! derivative in ground resistance w.r.t. canopy air temperature (s m-1 K-1) - real(rkind) :: notUsed_dCanopyResistance_dTCanopy ! derivative in canopy resistance w.r.t. canopy temperature (s m-1 K-1) - real(rkind) :: notUsed_dCanopyResistance_dTCanair ! derivative in canopy resistance w.r.t. canopy air temperature (s m-1 K-1) - - ! (fluxes after perturbations in model states -- canopy air space) - real(rkind) :: turbFluxCanair_dStateCanair ! turbulent exchange from the canopy air space to the atmosphere, after canopy air temperature is perturbed (W m-2) - real(rkind) :: turbFluxCanair_dStateCanopy ! turbulent exchange from the canopy air space to the atmosphere, after canopy temperature is perturbed (W m-2) - real(rkind) :: turbFluxCanair_dStateGround ! turbulent exchange from the canopy air space to the atmosphere, after ground temperature is perturbed (W m-2) - real(rkind) :: turbFluxCanair_dStateCanWat ! turbulent exchange from the canopy air space to the atmosphere, after canopy total water content is perturbed (W m-2) - ! (fluxes after perturbations in model states -- vegetation canopy) - real(rkind) :: turbFluxCanopy_dStateCanair ! total turbulent heat fluxes from the canopy to the canopy air space, after canopy air temperature is perturbed (W m-2) - real(rkind) :: turbFluxCanopy_dStateCanopy ! total turbulent heat fluxes from the canopy to the canopy air space, after canopy temperature is perturbed (W m-2) - real(rkind) :: turbFluxCanopy_dStateGround ! total turbulent heat fluxes from the canopy to the canopy air space, after ground temperature is perturbed (W m-2) - real(rkind) :: turbFluxCanopy_dStateCanWat ! total turbulent heat fluxes from the canopy to the canopy air space, after canopy total water content is perturbed (W m-2) - - ! (fluxes after perturbations in model states -- ground surface) - real(rkind) :: turbFluxGround_dStateCanair ! total turbulent heat fluxes from the ground to the canopy air space, after canopy air temperature is perturbed (W m-2) - real(rkind) :: turbFluxGround_dStateCanopy ! total turbulent heat fluxes from the ground to the canopy air space, after canopy temperature is perturbed (W m-2) - real(rkind) :: turbFluxGround_dStateGround ! total turbulent heat fluxes from the ground to the canopy air space, after ground temperature is perturbed (W m-2) - real(rkind) :: turbFluxGround_dStateCanWat ! total turbulent heat fluxes from the ground to the canopy air space, after canopy total water content is perturbed (W m-2) - - ! (fluxes after perturbations in model states -- canopy evaporation) - real(rkind) :: latHeatCanEvap_dStateCanair ! canopy evaporation after canopy air temperature is perturbed (W m-2) - real(rkind) :: latHeatCanEvap_dStateCanopy ! canopy evaporation after canopy temperature is perturbed (W m-2) - real(rkind) :: latHeatCanEvap_dStateGround ! canopy evaporation after ground temperature is perturbed (W m-2) - real(rkind) :: latHeatCanEvap_dStateCanWat ! canopy evaporation after canopy total water content is perturbed (W m-2) - - ! (flux derivatives -- canopy air space) - real(rkind) :: dTurbFluxCanair_dTCanair ! derivative in net canopy air space fluxes w.r.t. canopy air temperature (W m-2 K-1) - real(rkind) :: dTurbFluxCanair_dTCanopy ! derivative in net canopy air space fluxes w.r.t. canopy temperature (W m-2 K-1) - real(rkind) :: dTurbFluxCanair_dTGround ! derivative in net canopy air space fluxes w.r.t. ground temperature (W m-2 K-1) - real(rkind) :: dTurbFluxCanair_dCanWat ! derivative in net canopy air space fluxes w.r.t. canopy total water content (J kg-1 s-1) - - ! (flux derivatives -- vegetation canopy) - real(rkind) :: dTurbFluxCanopy_dTCanair ! derivative in net canopy turbulent fluxes w.r.t. canopy air temperature (W m-2 K-1) - real(rkind) :: dTurbFluxCanopy_dTCanopy ! derivative in net canopy turbulent fluxes w.r.t. canopy temperature (W m-2 K-1) - real(rkind) :: dTurbFluxCanopy_dTGround ! derivative in net canopy turbulent fluxes w.r.t. ground temperature (W m-2 K-1) - real(rkind) :: dTurbFluxCanopy_dCanWat ! derivative in net canopy turbulent fluxes w.r.t. canopy total water content (J kg-1 s-1) - - ! (flux derivatives -- ground surface) - real(rkind) :: dTurbFluxGround_dTCanair ! derivative in net ground turbulent fluxes w.r.t. canopy air temperature (W m-2 K-1) - real(rkind) :: dTurbFluxGround_dTCanopy ! derivative in net ground turbulent fluxes w.r.t. canopy temperature (W m-2 K-1) - real(rkind) :: dTurbFluxGround_dTGround ! derivative in net ground turbulent fluxes w.r.t. ground temperature (W m-2 K-1) - real(rkind) :: dTurbFluxGround_dCanWat ! derivative in net ground turbulent fluxes w.r.t. canopy total water content (J kg-1 s-1) - - ! (liquid water flux derivatives -- canopy evap) - real(rkind) :: dLatHeatCanopyEvap_dCanWat ! derivative in latent heat of canopy evaporation w.r.t. canopy total water content (W kg-1) - real(rkind) :: dLatHeatCanopyEvap_dTCanair ! derivative in latent heat of canopy evaporation w.r.t. canopy air temperature (W m-2 K-1) - real(rkind) :: dLatHeatCanopyEvap_dTCanopy ! derivative in latent heat of canopy evaporation w.r.t. canopy temperature (W m-2 K-1) - real(rkind) :: dLatHeatCanopyEvap_dTGround ! derivative in latent heat of canopy evaporation w.r.t. ground temperature (W m-2 K-1) - - ! (liquid water flux derivatives -- ground evap) - real(rkind) :: dLatHeatGroundEvap_dCanWat ! derivative in latent heat of ground evaporation w.r.t. canopy total water content (J kg-1 s-1) - real(rkind) :: dLatHeatGroundEvap_dTCanair ! derivative in latent heat of ground evaporation w.r.t. canopy air temperature (W m-2 K-1) - real(rkind) :: dLatHeatGroundEvap_dTCanopy ! derivative in latent heat of ground evaporation w.r.t. canopy temperature (W m-2 K-1) - real(rkind) :: dLatHeatGroundEvap_dTGround ! derivative in latent heat of ground evaporation w.r.t. ground temperature (W m-2 K-1) - - ! output: latent heat flux derivatives (canopy trans) - real(rkind) :: dLatHeatCanopyTrans_dCanWat ! derivative in the latent heat of canopy transpiration w.r.t. canopy total water (J kg-1 s-1) - real(rkind) :: dLatHeatCanopyTrans_dTCanair ! derivative in the latent heat of canopy transpiration w.r.t. canopy air temperature - real(rkind) :: dLatHeatCanopyTrans_dTCanopy ! derivative in the latent heat of canopy transpiration w.r.t. canopy temperature - real(rkind) :: dLatHeatCanopyTrans_dTGround ! derivative in the latent heat of canopy transpiration w.r.t. ground temperature - - ! --------------------------------------------------------------------------------------- - ! point to variables in the data structure - ! --------------------------------------------------------------------------------------- - associate(& - - ! input: model decisions - ix_bcUpprTdyn => model_decisions(iLookDECISIONS%bcUpprTdyn)%iDecision, & ! intent(in): [i4b] choice of upper boundary condition for thermodynamics - ixDerivMethod => model_decisions(iLookDECISIONS%fDerivMeth)%iDecision, & ! intent(in): [i4b] choice of method to compute derivatives - ix_veg_traits => model_decisions(iLookDECISIONS%veg_traits)%iDecision, & ! intent(in): [i4b] choice of parameterization for vegetation roughness length and displacement height - ix_canopyEmis => model_decisions(iLookDECISIONS%canopyEmis)%iDecision, & ! intent(in): [i4b] choice of parameterization for canopy emissivity - ix_windPrfile => model_decisions(iLookDECISIONS%windPrfile)%iDecision, & ! intent(in): [i4b] choice of canopy wind profile - ix_astability => model_decisions(iLookDECISIONS%astability)%iDecision, & ! intent(in): [i4b] choice of stability function - ix_soilStress => model_decisions(iLookDECISIONS%soilStress)%iDecision, & ! intent(in): [i4b] choice of function for the soil moisture control on stomatal resistance - ix_groundwatr => model_decisions(iLookDECISIONS%groundwatr)%iDecision, & ! intent(in): [i4b] choice of groundwater parameterization - ix_stomResist => model_decisions(iLookDECISIONS%stomResist)%iDecision, & ! intent(in): [i4b] choice of function for stomatal resistance - ix_spatial_gw => model_decisions(iLookDECISIONS%spatial_gw)%iDecision, & ! intent(in): [i4b] choice of groundwater representation (local, basin) - - ! input: layer geometry - nSnow => indx_data%var(iLookINDEX%nSnow)%dat(1), & ! intent(in): [i4b] number of snow layers - nSoil => indx_data%var(iLookINDEX%nSoil)%dat(1), & ! intent(in): [i4b] number of soil layers - nLayers => indx_data%var(iLookINDEX%nLayers)%dat(1), & ! intent(in): [i4b] total number of layers - - ! input: physical attributes - vegTypeIndex => type_data%var(iLookTYPE%vegTypeIndex), & ! intent(in): [i4b] vegetation type index - soilTypeIndex => type_data%var(iLookTYPE%soilTypeIndex), & ! intent(in): [i4b] soil type index - - ! input: vegetation parameters - heightCanopyTop => mpar_data%var(iLookPARAM%heightCanopyTop)%dat(1), & ! intent(in): [dp] height at the top of the vegetation canopy (m) - heightCanopyBottom => mpar_data%var(iLookPARAM%heightCanopyBottom)%dat(1), & ! intent(in): [dp] height at the bottom of the vegetation canopy (m) - canopyWettingFactor => mpar_data%var(iLookPARAM%canopyWettingFactor)%dat(1), & ! intent(in): [dp] maximum wetted fraction of the canopy (-) - canopyWettingExp => mpar_data%var(iLookPARAM%canopyWettingExp)%dat(1), & ! intent(in): [dp] exponent in canopy wetting function (-) - scalarCanopyIceMax => diag_data%var(iLookDIAG%scalarCanopyIceMax)%dat(1), & ! intent(in): [dp] maximum interception storage capacity for ice (kg m-2) - scalarCanopyLiqMax => diag_data%var(iLookDIAG%scalarCanopyLiqMax)%dat(1), & ! intent(in): [dp] maximum interception storage capacity for liquid water (kg m-2) - - ! input: vegetation phenology - scalarLAI => diag_data%var(iLookDIAG%scalarLAI)%dat(1), & ! intent(in): [dp] one-sided leaf area index (m2 m-2) - scalarSAI => diag_data%var(iLookDIAG%scalarSAI)%dat(1), & ! intent(in): [dp] one-sided stem area index (m2 m-2) - scalarExposedLAI => diag_data%var(iLookDIAG%scalarExposedLAI)%dat(1), & ! intent(in): [dp] exposed leaf area index after burial by snow (m2 m-2) - scalarExposedSAI => diag_data%var(iLookDIAG%scalarExposedSAI)%dat(1), & ! intent(in): [dp] exposed stem area index after burial by snow (m2 m-2) - scalarGrowingSeasonIndex => diag_data%var(iLookDIAG%scalarGrowingSeasonIndex)%dat(1), & ! intent(in): [dp] growing season index (0=off, 1=on) - scalarFoliageNitrogenFactor => diag_data%var(iLookDIAG%scalarFoliageNitrogenFactor)%dat(1), & ! intent(in): [dp] foliage nitrogen concentration (1.0 = saturated) - - ! input: aerodynamic resistance parameters - z0Snow => mpar_data%var(iLookPARAM%z0Snow)%dat(1), & ! intent(in): [dp] roughness length of snow (m) - z0Soil => mpar_data%var(iLookPARAM%z0Soil)%dat(1), & ! intent(in): [dp] roughness length of soil (m) - z0CanopyParam => mpar_data%var(iLookPARAM%z0Canopy)%dat(1), & ! intent(in): [dp] roughness length of the canopy (m) - zpdFraction => mpar_data%var(iLookPARAM%zpdFraction)%dat(1), & ! intent(in): [dp] zero plane displacement / canopy height (-) - critRichNumber => mpar_data%var(iLookPARAM%critRichNumber)%dat(1), & ! intent(in): [dp] critical value for the bulk Richardson number where turbulence ceases (-) - Louis79_bparam => mpar_data%var(iLookPARAM%Louis79_bparam)%dat(1), & ! intent(in): [dp] parameter in Louis (1979) stability function - Louis79_cStar => mpar_data%var(iLookPARAM%Louis79_cStar)%dat(1), & ! intent(in): [dp] parameter in Louis (1979) stability function - Mahrt87_eScale => mpar_data%var(iLookPARAM%Mahrt87_eScale)%dat(1), & ! intent(in): [dp] exponential scaling factor in the Mahrt (1987) stability function - windReductionParam => mpar_data%var(iLookPARAM%windReductionParam)%dat(1), & ! intent(in): [dp] canopy wind reduction parameter (-) - leafExchangeCoeff => mpar_data%var(iLookPARAM%leafExchangeCoeff)%dat(1), & ! intent(in): [dp] turbulent exchange coeff between canopy surface and canopy air ( m s-(1/2) ) - leafDimension => mpar_data%var(iLookPARAM%leafDimension)%dat(1), & ! intent(in): [dp] characteristic leaf dimension (m) - - ! input: soil stress parameters - theta_sat => mpar_data%var(iLookPARAM%theta_sat)%dat(1), & ! intent(in): [dp] soil porosity (-) - theta_res => mpar_data%var(iLookPARAM%theta_res)%dat(1), & ! intent(in): [dp] residual volumetric liquid water content (-) - plantWiltPsi => mpar_data%var(iLookPARAM%plantWiltPsi)%dat(1), & ! intent(in): [dp] matric head at wilting point (m) - soilStressParam => mpar_data%var(iLookPARAM%soilStressParam)%dat(1), & ! intent(in): [dp] parameter in the exponential soil stress function (-) - critSoilWilting => mpar_data%var(iLookPARAM%critSoilWilting)%dat(1), & ! intent(in): [dp] critical vol. liq. water content when plants are wilting (-) - critSoilTranspire => mpar_data%var(iLookPARAM%critSoilTranspire)%dat(1), & ! intent(in): [dp] critical vol. liq. water content when transpiration is limited (-) - critAquiferTranspire => mpar_data%var(iLookPARAM%critAquiferTranspire)%dat(1), & ! intent(in): [dp] critical aquifer storage value when transpiration is limited (m) - minStomatalResistance => mpar_data%var(iLookPARAM%minStomatalResistance)%dat(1), & ! intent(in): [dp] mimimum stomatal resistance (s m-1) - - ! snow parameters - snowfrz_scale => mpar_data%var(iLookPARAM%snowfrz_scale)%dat(1), & ! intent(in): [dp] scaling parameter for the snow freezing curve (K-1) - - ! input: forcing at the upper boundary - mHeight => diag_data%var(iLookDIAG%scalarAdjMeasHeight)%dat(1), & ! intent(in): [dp] measurement height (m) - airtemp => forc_data%var(iLookFORCE%airtemp), & ! intent(in): [dp] air temperature at some height above the surface (K) - windspd => forc_data%var(iLookFORCE%windspd), & ! intent(in): [dp] wind speed at some height above the surface (m s-1) - airpres => forc_data%var(iLookFORCE%airpres), & ! intent(in): [dp] air pressure at some height above the surface (Pa) - LWRadAtm => forc_data%var(iLookFORCE%LWRadAtm), & ! intent(in): [dp] downwelling longwave radiation at the upper boundary (W m-2) - scalarVPair => diag_data%var(iLookDIAG%scalarVPair)%dat(1), & ! intent(in): [dp] vapor pressure at some height above the surface (Pa) - scalarO2air => diag_data%var(iLookDIAG%scalarO2air)%dat(1), & ! intent(in): [dp] atmospheric o2 concentration (Pa) - scalarCO2air => diag_data%var(iLookDIAG%scalarCO2air)%dat(1), & ! intent(in): [dp] atmospheric co2 concentration (Pa) - scalarTwetbulb => diag_data%var(iLookDIAG%scalarTwetbulb)%dat(1), & ! intent(in): [dp] wetbulb temperature (K) - scalarRainfall => flux_data%var(iLookFLUX%scalarRainfall)%dat(1), & ! intent(in): [dp] computed rainfall rate (kg m-2 s-1) - scalarSnowfall => flux_data%var(iLookFLUX%scalarSnowfall)%dat(1), & ! intent(in): [dp] computed snowfall rate (kg m-2 s-1) - scalarThroughfallRain => flux_data%var(iLookFLUX%scalarThroughfallRain)%dat(1), & ! intent(in): [dp] rainfall through the vegetation canopy (kg m-2 s-1) - scalarThroughfallSnow => flux_data%var(iLookFLUX%scalarThroughfallSnow)%dat(1), & ! intent(in): [dp] snowfall through the vegetation canopy (kg m-2 s-1) - - ! input: water storage - ! NOTE: soil stress only computed at the start of the substep (firstFluxCall=.true.) - scalarSWE => prog_data%var(iLookPROG%scalarSWE)%dat(1), & ! intent(in): [dp] snow water equivalent on the ground (kg m-2) - scalarSnowDepth => prog_data%var(iLookPROG%scalarSnowDepth)%dat(1), & ! intent(in): [dp] snow depth on the ground surface (m) - mLayerVolFracLiq => prog_data%var(iLookPROG%mLayerVolFracLiq)%dat, & ! intent(in): [dp(:)] volumetric fraction of liquid water in each layer (-) - mLayerMatricHead => prog_data%var(iLookPROG%mLayerMatricHead)%dat, & ! intent(in): [dp(:)] matric head in each soil layer (m) - localAquiferStorage => prog_data%var(iLookPROG%scalarAquiferStorage)%dat(1), & ! intent(in): [dp] aquifer storage for the local column (m) - basinAquiferStorage => bvar_data%var(iLookBVAR%basin__AquiferStorage)%dat(1), & ! intent(in): [dp] aquifer storage for the single basin (m) - - ! input: shortwave radiation fluxes - scalarCanopySunlitLAI => diag_data%var(iLookDIAG%scalarCanopySunlitLAI)%dat(1), & ! intent(in): [dp] sunlit leaf area (-) - scalarCanopyShadedLAI => diag_data%var(iLookDIAG%scalarCanopyShadedLAI)%dat(1), & ! intent(in): [dp] shaded leaf area (-) - scalarCanopySunlitPAR => flux_data%var(iLookFLUX%scalarCanopySunlitPAR)%dat(1), & ! intent(in): [dp] average absorbed par for sunlit leaves (w m-2) - scalarCanopyShadedPAR => flux_data%var(iLookFLUX%scalarCanopyShadedPAR)%dat(1), & ! intent(in): [dp] average absorbed par for shaded leaves (w m-2) - scalarCanopyAbsorbedSolar => flux_data%var(iLookFLUX%scalarCanopyAbsorbedSolar)%dat(1), & ! intent(in): [dp] solar radiation absorbed by canopy (W m-2) - scalarGroundAbsorbedSolar => flux_data%var(iLookFLUX%scalarGroundAbsorbedSolar)%dat(1), & ! intent(in): [dp] solar radiation absorbed by ground (W m-2) - - ! output: fraction of wetted canopy area and fraction of snow on the ground - scalarCanopyWetFraction => diag_data%var(iLookDIAG%scalarCanopyWetFraction)%dat(1), & ! intent(out): [dp] fraction of canopy that is wet - scalarGroundSnowFraction => diag_data%var(iLookDIAG%scalarGroundSnowFraction)%dat(1), & ! intent(out): [dp] fraction of ground covered with snow (-) - - ! output: longwave radiation fluxes - scalarCanopyEmissivity => diag_data%var(iLookDIAG%scalarCanopyEmissivity)%dat(1), & ! intent(out): [dp] effective emissivity of the canopy (-) - scalarLWRadCanopy => flux_data%var(iLookFLUX%scalarLWRadCanopy)%dat(1), & ! intent(out): [dp] longwave radiation emitted from the canopy (W m-2) - scalarLWRadGround => flux_data%var(iLookFLUX%scalarLWRadGround)%dat(1), & ! intent(out): [dp] longwave radiation emitted at the ground surface (W m-2) - scalarLWRadUbound2Canopy => flux_data%var(iLookFLUX%scalarLWRadUbound2Canopy)%dat(1), & ! intent(out): [dp] downward atmospheric longwave radiation absorbed by the canopy (W m-2) - scalarLWRadUbound2Ground => flux_data%var(iLookFLUX%scalarLWRadUbound2Ground)%dat(1), & ! intent(out): [dp] downward atmospheric longwave radiation absorbed by the ground (W m-2) - scalarLWRadUbound2Ubound => flux_data%var(iLookFLUX%scalarLWRadUbound2Ubound)%dat(1), & ! intent(out): [dp] atmospheric radiation reflected by the ground and lost thru upper boundary (W m-2) - scalarLWRadCanopy2Ubound => flux_data%var(iLookFLUX%scalarLWRadCanopy2Ubound)%dat(1), & ! intent(out): [dp] longwave radiation emitted from canopy lost thru upper boundary (W m-2) - scalarLWRadCanopy2Ground => flux_data%var(iLookFLUX%scalarLWRadCanopy2Ground)%dat(1), & ! intent(out): [dp] longwave radiation emitted from canopy absorbed by the ground (W m-2) - scalarLWRadCanopy2Canopy => flux_data%var(iLookFLUX%scalarLWRadCanopy2Canopy)%dat(1), & ! intent(out): [dp] canopy longwave reflected from ground and absorbed by the canopy (W m-2) - scalarLWRadGround2Ubound => flux_data%var(iLookFLUX%scalarLWRadGround2Ubound)%dat(1), & ! intent(out): [dp] longwave radiation emitted from ground lost thru upper boundary (W m-2) - scalarLWRadGround2Canopy => flux_data%var(iLookFLUX%scalarLWRadGround2Canopy)%dat(1), & ! intent(out): [dp] longwave radiation emitted from ground and absorbed by the canopy (W m-2) - scalarLWNetCanopy => flux_data%var(iLookFLUX%scalarLWNetCanopy)%dat(1), & ! intent(out): [dp] net longwave radiation at the canopy (W m-2) - scalarLWNetGround => flux_data%var(iLookFLUX%scalarLWNetGround)%dat(1), & ! intent(out): [dp] net longwave radiation at the ground surface (W m-2) - scalarLWNetUbound => flux_data%var(iLookFLUX%scalarLWNetUbound)%dat(1), & ! intent(out): [dp] net longwave radiation at the upper boundary (W m-2) - - ! output: aerodynamic resistance - scalarZ0Canopy => diag_data%var(iLookDIAG%scalarZ0Canopy)%dat(1), & ! intent(out): [dp] roughness length of the canopy (m) - scalarWindReductionFactor => diag_data%var(iLookDIAG%scalarWindReductionFactor)%dat(1), & ! intent(out): [dp] canopy wind reduction factor (-) - scalarZeroPlaneDisplacement => diag_data%var(iLookDIAG%scalarZeroPlaneDisplacement)%dat(1), & ! intent(out): [dp] zero plane displacement (m) - scalarRiBulkCanopy => diag_data%var(iLookDIAG%scalarRiBulkCanopy)%dat(1), & ! intent(out): [dp] bulk Richardson number for the canopy (-) - scalarRiBulkGround => diag_data%var(iLookDIAG%scalarRiBulkGround)%dat(1), & ! intent(out): [dp] bulk Richardson number for the ground surface (-) - scalarEddyDiffusCanopyTop => flux_data%var(iLookFLUX%scalarEddyDiffusCanopyTop)%dat(1), & ! intent(out): [dp] eddy diffusivity for heat at the top of the canopy (m2 s-1) - scalarFrictionVelocity => flux_data%var(iLookFLUX%scalarFrictionVelocity)%dat(1), & ! intent(out): [dp] friction velocity (m s-1) - scalarWindspdCanopyTop => flux_data%var(iLookFLUX%scalarWindspdCanopyTop)%dat(1), & ! intent(out): [dp] windspeed at the top of the canopy (m s-1) - scalarWindspdCanopyBottom => flux_data%var(iLookFLUX%scalarWindspdCanopyBottom)%dat(1), & ! intent(out): [dp] windspeed at the height of the bottom of the canopy (m s-1) - scalarLeafResistance => flux_data%var(iLookFLUX%scalarLeafResistance)%dat(1), & ! intent(out): [dp] mean leaf boundary layer resistance per unit leaf area (s m-1) - scalarGroundResistance => flux_data%var(iLookFLUX%scalarGroundResistance)%dat(1), & ! intent(out): [dp] below canopy aerodynamic resistance (s m-1) - scalarCanopyResistance => flux_data%var(iLookFLUX%scalarCanopyResistance)%dat(1), & ! intent(out): [dp] above canopy aerodynamic resistance (s m-1) - - ! input/output: soil resistance -- intent(in) and intent(inout) because only called at the first flux call - mLayerRootDensity => diag_data%var(iLookDIAG%mLayerRootDensity)%dat, & ! intent(in): [dp] root density in each layer (-) - scalarAquiferRootFrac => diag_data%var(iLookDIAG%scalarAquiferRootFrac)%dat(1), & ! intent(in): [dp] fraction of roots below the lowest soil layer (-) - scalarTranspireLim => diag_data%var(iLookDIAG%scalarTranspireLim)%dat(1), & ! intent(inout): [dp] weighted average of the transpiration limiting factor (-) - mLayerTranspireLim => diag_data%var(iLookDIAG%mLayerTranspireLim)%dat, & ! intent(inout): [dp] transpiration limiting factor in each layer (-) - scalarTranspireLimAqfr => diag_data%var(iLookDIAG%scalarTranspireLimAqfr)%dat(1), & ! intent(inout): [dp] transpiration limiting factor for the aquifer (-) - scalarSoilRelHumidity => diag_data%var(iLookDIAG%scalarSoilRelHumidity)%dat(1), & ! intent(inout): [dp] relative humidity in the soil pores [0-1] - scalarSoilResistance => flux_data%var(iLookFLUX%scalarSoilResistance)%dat(1), & ! intent(inout): [dp] resistance from the soil (s m-1) - - ! input/output: stomatal resistance -- intent(inout) because only called at the first flux call - scalarStomResistSunlit => flux_data%var(iLookFLUX%scalarStomResistSunlit)%dat(1), & ! intent(inout): [dp] stomatal resistance for sunlit leaves (s m-1) - scalarStomResistShaded => flux_data%var(iLookFLUX%scalarStomResistShaded)%dat(1), & ! intent(inout): [dp] stomatal resistance for shaded leaves (s m-1) - scalarPhotosynthesisSunlit => flux_data%var(iLookFLUX%scalarPhotosynthesisSunlit)%dat(1), & ! intent(inout): [dp] sunlit photosynthesis (umolco2 m-2 s-1) - scalarPhotosynthesisShaded => flux_data%var(iLookFLUX%scalarPhotosynthesisShaded)%dat(1), & ! intent(inout): [dp] shaded photosynthesis (umolco2 m-2 s-1) - - ! output: turbulent heat fluxes - scalarLatHeatSubVapCanopy => diag_data%var(iLookDIAG%scalarLatHeatSubVapCanopy)%dat(1), & ! intent(inout): [dp] latent heat of sublimation/vaporization for the vegetation canopy (J kg-1) - scalarLatHeatSubVapGround => diag_data%var(iLookDIAG%scalarLatHeatSubVapGround)%dat(1), & ! intent(inout): [dp] latent heat of sublimation/vaporization for the ground surface (J kg-1) - scalarSatVP_canopyTemp => diag_data%var(iLookDIAG%scalarSatVP_CanopyTemp)%dat(1), & ! intent(out): [dp] saturation vapor pressure at the temperature of the vegetation canopy (Pa) - scalarSatVP_groundTemp => diag_data%var(iLookDIAG%scalarSatVP_GroundTemp)%dat(1), & ! intent(out): [dp] saturation vapor pressure at the temperature of the ground surface (Pa) - scalarSenHeatTotal => flux_data%var(iLookFLUX%scalarSenHeatTotal)%dat(1), & ! intent(out): [dp] sensible heat from the canopy air space to the atmosphere (W m-2) - scalarSenHeatCanopy => flux_data%var(iLookFLUX%scalarSenHeatCanopy)%dat(1), & ! intent(out): [dp] sensible heat flux from the canopy to the canopy air space (W m-2) - scalarSenHeatGround => flux_data%var(iLookFLUX%scalarSenHeatGround)%dat(1), & ! intent(out): [dp] sensible heat flux from ground surface below vegetation (W m-2) - scalarLatHeatTotal => flux_data%var(iLookFLUX%scalarLatHeatTotal)%dat(1), & ! intent(out): [dp] latent heat from the canopy air space to the atmosphere (W m-2) - scalarLatHeatCanopyEvap => flux_data%var(iLookFLUX%scalarLatHeatCanopyEvap)%dat(1), & ! intent(out): [dp] latent heat flux for evaporation from the canopy to the canopy air space (W m-2) - scalarLatHeatCanopyTrans => flux_data%var(iLookFLUX%scalarLatHeatCanopyTrans)%dat(1), & ! intent(out): [dp] latent heat flux for transpiration from the canopy to the canopy air space (W m-2) - scalarLatHeatGround => flux_data%var(iLookFLUX%scalarLatHeatGround)%dat(1), & ! intent(out): [dp] latent heat flux from ground surface below vegetation (W m-2) - - ! output: advective heat fluxes - scalarCanopyAdvectiveHeatFlux => flux_data%var(iLookFLUX%scalarCanopyAdvectiveHeatFlux)%dat(1), & ! intent(out): [dp] heat advected to the canopy surface with rain + snow (W m-2) - scalarGroundAdvectiveHeatFlux => flux_data%var(iLookFLUX%scalarGroundAdvectiveHeatFlux)%dat(1), & ! intent(out): [dp] heat advected to the ground surface with throughfall (W m-2) - - ! output: mass fluxes - scalarCanopySublimation => flux_data%var(iLookFLUX%scalarCanopySublimation)%dat(1), & ! intent(out): [dp] canopy sublimation/frost (kg m-2 s-1) - scalarSnowSublimation => flux_data%var(iLookFLUX%scalarSnowSublimation)%dat(1), & ! intent(out): [dp] snow sublimation/frost -- below canopy or non-vegetated (kg m-2 s-1) - - ! input/output: canopy air space variables - scalarVP_CanopyAir => diag_data%var(iLookDIAG%scalarVP_CanopyAir)%dat(1), & ! intent(inout): [dp] vapor pressure of the canopy air space (Pa) - scalarCanopyStabilityCorrection => diag_data%var(iLookDIAG%scalarCanopyStabilityCorrection)%dat(1),& ! intent(inout): [dp] stability correction for the canopy (-) - scalarGroundStabilityCorrection => diag_data%var(iLookDIAG%scalarGroundStabilityCorrection)%dat(1),& ! intent(inout): [dp] stability correction for the ground surface (-) - - ! output: liquid water fluxes - scalarCanopyTranspiration => flux_data%var(iLookFLUX%scalarCanopyTranspiration)%dat(1), & ! intent(out): [dp] canopy transpiration (kg m-2 s-1) - scalarCanopyEvaporation => flux_data%var(iLookFLUX%scalarCanopyEvaporation)%dat(1), & ! intent(out): [dp] canopy evaporation/condensation (kg m-2 s-1) - scalarGroundEvaporation => flux_data%var(iLookFLUX%scalarGroundEvaporation)%dat(1), & ! intent(out): [dp] ground evaporation/condensation -- below canopy or non-vegetated (kg m-2 s-1) - - ! output: derived fluxes - scalarTotalET => flux_data%var(iLookFLUX%scalarTotalET)%dat(1), & ! intent(out): [dp] total ET (kg m-2 s-1) - scalarNetRadiation => flux_data%var(iLookFLUX%scalarNetRadiation)%dat(1) & ! intent(out): [dp] net radiation (W m-2) - ) - ! --------------------------------------------------------------------------------------- - ! initialize error control - err=0; message="vegNrgFlux/" - - ! initialize printflag - printflag = .false. - - ! identify the type of boundary condition for thermodynamics - select case(ix_bcUpprTdyn) - +! data types +USE nrtype + +! derived types to define the data structures +USE data_types,only:& + var_i, & ! data vector (i4b) + var_d, & ! data vector (rkind) + var_ilength, & ! data vector with variable length dimension (i4b) + var_dlength, & ! data vector with variable length dimension (rkind) + model_options ! defines the model decisions + +! indices that define elements of the data structures +USE var_lookup,only:iLookTYPE ! named variables for structure elements +USE var_lookup,only:iLookPROG ! named variables for structure elements +USE var_lookup,only:iLookDIAG ! named variables for structure elements +USE var_lookup,only:iLookFLUX ! named variables for structure elements +USE var_lookup,only:iLookFORCE ! named variables for structure elements +USE var_lookup,only:iLookPARAM ! named variables for structure elements +USE var_lookup,only:iLookINDEX ! named variables for structure elements +USE var_lookup,only:iLookBVAR ! named variables for structure elements +USE var_lookup,only:iLookDECISIONS ! named variables for elements of the decision structure + +! constants +USE multiconst,only:gravity ! acceleration of gravity (m s-2) +USE multiconst,only:vkc ! von Karman's constant (-) +USE multiconst,only:w_ratio ! molecular ratio water to dry air (-) +USE multiconst,only:R_wv ! gas constant for water vapor (Pa K-1 m3 kg-1; J kg-1 K-1) +USE multiconst,only:Cp_air ! specific heat of air (J kg-1 K-1) +USE multiconst,only:Cp_ice ! specific heat of ice (J kg-1 K-1) +USE multiconst,only:Cp_soil ! specific heat of soil (J kg-1 K-1) +USE multiconst,only:Cp_water ! specific heat of liquid water (J kg-1 K-1) +USE multiconst,only:Tfreeze ! temperature at freezing (K) +USE multiconst,only:LH_fus ! latent heat of fusion (J kg-1) +USE multiconst,only:LH_vap ! latent heat of vaporization (J kg-1) +USE multiconst,only:LH_sub ! latent heat of sublimation (J kg-1) +USE multiconst,only:sb ! Stefan Boltzman constant (W m-2 K-4) +USE multiconst,only:iden_air ! intrinsic density of air (kg m-3) +USE multiconst,only:iden_ice ! intrinsic density of ice (kg m-3) +USE multiconst,only:iden_water ! intrinsic density of liquid water (kg m-3) + +! look-up values for method used to compute derivative +USE mDecisions_module,only: & + numerical, & ! numerical solution + analytical ! analytical solution + +! look-up values for choice of boundary conditions for thermodynamics +USE mDecisions_module,only: & + prescribedTemp, & ! prescribed temperature + energyFlux, & ! energy flux + zeroFlux ! zero flux + +! look-up values for the choice of parameterization for vegetation roughness length and displacement height +USE mDecisions_module,only: & + Raupach_BLM1994, & ! Raupach (BLM 1994) "Simplified expressions..." + CM_QJRMS1988, & ! Choudhury and Monteith (QJRMS 1988) "A four layer model for the heat budget..." + vegTypeTable ! constant parameters dependent on the vegetation type + +! look-up values for the choice of parameterization for canopy emissivity +USE mDecisions_module,only: & + simplExp, & ! simple exponential function + difTrans ! parameterized as a function of diffuse transmissivity + +! look-up values for the choice of canopy wind profile +USE mDecisions_module,only: & + exponential, & ! exponential wind profile extends to the surface + logBelowCanopy ! logarithmic profile below the vegetation canopy + +! look-up values for choice of stability function +USE mDecisions_module,only: & + standard, & ! standard MO similarity, a la Anderson (1976) + louisInversePower, & ! Louis (1979) inverse power function + mahrtExponential ! Mahrt (1987) exponential + +! look-up values for the choice of groundwater representation (local-column, or single-basin) +USE mDecisions_module,only: & + localColumn, & ! separate groundwater representation in each local soil column + singleBasin ! single groundwater store over the entire basin + +! ------------------------------------------------------------------------------------------------- +! privacy +implicit none +private +public::vegNrgFlux +public::wettedFrac +! dimensions +integer(i4b),parameter :: nBands=2 ! number of spectral bands for shortwave radiation +! named variables +integer(i4b),parameter :: ist = 1 ! Surface type: IST=1 => soil; IST=2 => lake +integer(i4b),parameter :: isc = 4 ! Soil color type +integer(i4b),parameter :: ice = 0 ! Surface type: ICE=0 => soil; ICE=1 => sea-ice +! spatial indices +integer(i4b),parameter :: iLoc = 1 ! i-location +integer(i4b),parameter :: jLoc = 1 ! j-location +! algorithmic parameters +real(rkind),parameter :: missingValue=-9999._rkind ! missing value, used when diagnostic or state variables are undefined +real(rkind),parameter :: verySmall=1.e-6_rkind ! used as an additive constant to check if substantial difference among real numbers +real(rkind),parameter :: tinyVal=epsilon(1._rkind) ! used as an additive constant to check if substantial difference among real numbers +real(rkind),parameter :: mpe=1.e-6_rkind ! prevents overflow error if division by zero +real(rkind),parameter :: dx=1.e-11_rkind ! finite difference increment +! control +logical(lgt) :: printflag ! flag to turn on printing +contains + +! ******************************************************************************************************* +! public subroutine vegNrgFlux: muster program to compute energy fluxes at vegetation and ground surfaces +! ******************************************************************************************************* +subroutine vegNrgFlux(& + ! input: model control + firstSubStep, & ! intent(in): flag to indicate if we are processing the first sub-step + firstFluxCall, & ! intent(in): flag to indicate if we are processing the first flux call + computeVegFlux, & ! intent(in): flag to indicate if we need to compute fluxes over vegetation + insideIDA, & ! intent(in): flag to indicate inside Sundials Solver (do not require longwave to be balanced) + + ! input: model state variables + upperBoundTemp, & ! intent(in): temperature of the upper boundary (K) --> NOTE: use air temperature + canairTempTrial, & ! intent(in): trial value of the canopy air space temperature (K) + canopyTempTrial, & ! intent(in): trial value of canopy temperature (K) + groundTempTrial, & ! intent(in): trial value of ground temperature (K) + canopyIceTrial, & ! intent(in): trial value of mass of ice on the vegetation canopy (kg m-2) + canopyLiqTrial, & ! intent(in): trial value of mass of liquid water on the vegetation canopy (kg m-2) + + ! input: model derivatives + dCanLiq_dTcanopy, & ! intent(in): derivative in canopy liquid w.r.t. canopy temperature (kg m-2 K-1) + + ! input/output: data structures + type_data, & ! intent(in): type of vegetation and soil + forc_data, & ! intent(in): model forcing data + mpar_data, & ! intent(in): model parameters + indx_data, & ! intent(in): state vector geometry + prog_data, & ! intent(in): 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 + bvar_data, & ! intent(in): model variables for the local basin + model_decisions, & ! intent(in): model decisions + + ! output: liquid water fluxes associated with evaporation/transpiration (needed for coupling) + returnCanopyTranspiration, & ! intent(out): canopy transpiration (kg m-2 s-1) + returnCanopyEvaporation, & ! intent(out): canopy evaporation/condensation (kg m-2 s-1) + returnGroundEvaporation, & ! intent(out): ground evaporation/condensation -- below canopy or non-vegetated (kg m-2 s-1) + + ! output: fluxes + canairNetFlux, & ! intent(out): net energy flux for the canopy air space (W m-2) + canopyNetFlux, & ! intent(out): net energy flux for the vegetation canopy (W m-2) + groundNetFlux, & ! intent(out): net energy flux for the ground surface (W m-2) + + ! output: energy flux derivatives + dCanairNetFlux_dCanairTemp, & ! intent(out): derivative in net canopy air space flux w.r.t. canopy air temperature (W m-2 K-1) + dCanairNetFlux_dCanopyTemp, & ! intent(out): derivative in net canopy air space flux w.r.t. canopy temperature (W m-2 K-1) + dCanairNetFlux_dGroundTemp, & ! intent(out): derivative in net canopy air space flux w.r.t. ground temperature (W m-2 K-1) + dCanopyNetFlux_dCanairTemp, & ! intent(out): derivative in net canopy flux w.r.t. canopy air temperature (W m-2 K-1) + dCanopyNetFlux_dCanopyTemp, & ! intent(out): derivative in net canopy flux w.r.t. canopy temperature (W m-2 K-1) + dCanopyNetFlux_dGroundTemp, & ! intent(out): derivative in net canopy flux w.r.t. ground temperature (W m-2 K-1) + dGroundNetFlux_dCanairTemp, & ! intent(out): derivative in net ground flux w.r.t. canopy air temperature (W m-2 K-1) + dGroundNetFlux_dCanopyTemp, & ! intent(out): derivative in net ground flux w.r.t. canopy temperature (W m-2 K-1) + dGroundNetFlux_dGroundTemp, & ! intent(out): derivative in net ground flux w.r.t. ground temperature (W m-2 K-1) + + ! output liquid water flux derivarives (canopy evap) + dCanopyEvaporation_dCanWat, & ! intent(out): derivative in canopy evaporation w.r.t. canopy total water content (s-1) + dCanopyEvaporation_dTCanair, & ! intent(out): derivative in canopy evaporation w.r.t. canopy air temperature (kg m-2 s-1 K-1) + dCanopyEvaporation_dTCanopy, & ! intent(out): derivative in canopy evaporation w.r.t. canopy temperature (kg m-2 s-1 K-1) + dCanopyEvaporation_dTGround, & ! intent(out): derivative in canopy evaporation w.r.t. ground temperature (kg m-2 s-1 K-1) + + ! output: liquid water flux derivarives (ground evap) + dGroundEvaporation_dCanWat, & ! intent(out): derivative in ground evaporation w.r.t. canopy total water content (s-1) + dGroundEvaporation_dTCanair, & ! intent(out): derivative in ground evaporation w.r.t. canopy air temperature (kg m-2 s-1 K-1) + dGroundEvaporation_dTCanopy, & ! intent(out): derivative in ground evaporation w.r.t. canopy temperature (kg m-2 s-1 K-1) + dGroundEvaporation_dTGround, & ! intent(out): derivative in ground evaporation w.r.t. ground temperature (kg m-2 s-1 K-1) + + ! output: transpiration derivatives + dCanopyTrans_dCanWat, & ! intent(out): derivative in canopy transpiration w.r.t. canopy total water content (s-1) + dCanopyTrans_dTCanair, & ! intent(out): derivative in canopy transpiration w.r.t. canopy air temperature (kg m-2 s-1 K-1) + dCanopyTrans_dTCanopy, & ! intent(out): derivative in canopy transpiration w.r.t. canopy temperature (kg m-2 s-1 K-1) + dCanopyTrans_dTGround, & ! intent(out): derivative in canopy transpiration w.r.t. ground temperature (kg m-2 s-1 K-1) + + ! output: cross derivative terms + dCanopyNetFlux_dCanWat, & ! intent(out): derivative in net canopy fluxes w.r.t. canopy total water content (J kg-1 s-1) + dGroundNetFlux_dCanWat, & ! intent(out): derivative in net ground fluxes w.r.t. canopy total water content (J kg-1 s-1) + + ! output: error control + err,message) ! intent(out): error control + + ! utilities + USE expIntegral_module,only:expInt ! function to calculate the exponential integral + ! conversion functions + USE conv_funcs_module,only:satVapPress ! function to compute the saturated vapor pressure (Pa) + USE conv_funcs_module,only:getLatentHeatValue ! function to identify latent heat of vaporization/sublimation (J kg-1) + ! stomatal resistance + USE stomResist_module,only:stomResist ! subroutine to calculate stomatal resistance + ! phase changes + USE snow_utils_module,only:fracliquid ! compute fraction of liquid water at a given temperature + + ! compute energy and mass fluxes for vegetation + implicit none + + ! --------------------------------------------------------------------------------------- + ! * dummy variables + ! --------------------------------------------------------------------------------------- + ! input: model control + logical(lgt),intent(in) :: firstSubStep ! flag to indicate if we are processing the first sub-step + logical(lgt),intent(in) :: firstFluxCall ! flag to indicate if we are processing the first flux call + logical(lgt),intent(in) :: computeVegFlux ! flag to indicate if computing fluxes over vegetation + logical(lgt),intent(in) :: insideIDA ! flag if inside Sundials solver + ! input: model state variables + real(rkind),intent(in) :: upperBoundTemp ! temperature of the upper boundary (K) --> NOTE: use air temperature + real(rkind),intent(in) :: canairTempTrial ! trial value of canopy air space temperature (K) + real(rkind),intent(in) :: canopyTempTrial ! trial value of canopy temperature (K) + real(rkind),intent(in) :: groundTempTrial ! trial value of ground temperature (K) + real(rkind),intent(in) :: canopyIceTrial ! trial value of mass of ice on the vegetation canopy (kg m-2) + real(rkind),intent(in) :: canopyLiqTrial ! trial value of mass of liquid water on the vegetation canopy (kg m-2) + + ! input: model derivatives + real(rkind),intent(in) :: dCanLiq_dTcanopy ! intent(in): derivative in canopy liquid w.r.t. canopy temperature (kg m-2 K-1) + + ! input/output: data structures + type(var_i),intent(in) :: type_data ! type of vegetation and soil + type(var_d),intent(in) :: forc_data ! model forcing data + type(var_dlength),intent(in) :: mpar_data ! model parameters + type(var_ilength),intent(in) :: indx_data ! state vector geometry + type(var_dlength),intent(in) :: 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 + type(var_dlength),intent(in) :: bvar_data ! model variables for the local basin + type(model_options),intent(in) :: model_decisions(:) ! model decisions + + ! output: liquid water fluxes associated with evaporation/transpiration (needed for coupling) + real(rkind),intent(out) :: returnCanopyTranspiration ! canopy transpiration (kg m-2 s-1) + real(rkind),intent(out) :: returnCanopyEvaporation ! canopy evaporation/condensation (kg m-2 s-1) + real(rkind),intent(out) :: returnGroundEvaporation ! ground evaporation/condensation -- below canopy or non-vegetated (kg m-2 s-1) + + ! output: fluxes + real(rkind),intent(out) :: canairNetFlux ! net energy flux for the canopy air space (W m-2) + real(rkind),intent(out) :: canopyNetFlux ! net energy flux for the vegetation canopy (W m-2) + real(rkind),intent(out) :: groundNetFlux ! net energy flux for the ground surface (W m-2) + + ! output: energy flux derivatives + real(rkind),intent(out) :: dCanairNetFlux_dCanairTemp ! derivative in net canopy air space flux w.r.t. canopy air temperature (W m-2 K-1) + real(rkind),intent(out) :: dCanairNetFlux_dCanopyTemp ! derivative in net canopy air space flux w.r.t. canopy temperature (W m-2 K-1) + real(rkind),intent(out) :: dCanairNetFlux_dGroundTemp ! derivative in net canopy air space flux w.r.t. ground temperature (W m-2 K-1) + real(rkind),intent(out) :: dCanopyNetFlux_dCanairTemp ! derivative in net canopy flux w.r.t. canopy air temperature (W m-2 K-1) + real(rkind),intent(out) :: dCanopyNetFlux_dCanopyTemp ! derivative in net canopy flux w.r.t. canopy temperature (W m-2 K-1) + real(rkind),intent(out) :: dCanopyNetFlux_dGroundTemp ! derivative in net canopy flux w.r.t. ground temperature (W m-2 K-1) + real(rkind),intent(out) :: dGroundNetFlux_dCanairTemp ! derivative in net ground flux w.r.t. canopy air temperature (W m-2 K-1) + real(rkind),intent(out) :: dGroundNetFlux_dCanopyTemp ! derivative in net ground flux w.r.t. canopy temperature (W m-2 K-1) + real(rkind),intent(out) :: dGroundNetFlux_dGroundTemp ! derivative in net ground flux w.r.t. ground temperature (W m-2 K-1) + + ! output: liquid flux derivatives (canopy evap) + real(rkind),intent(out) :: dCanopyEvaporation_dCanWat ! derivative in canopy evaporation w.r.t. canopy total water content (s-1) + real(rkind),intent(out) :: dCanopyEvaporation_dTCanair ! derivative in canopy evaporation w.r.t. canopy air temperature (kg m-2 s-1 K-1) + real(rkind),intent(out) :: dCanopyEvaporation_dTCanopy ! derivative in canopy evaporation w.r.t. canopy temperature (kg m-2 s-1 K-1) + real(rkind),intent(out) :: dCanopyEvaporation_dTGround ! derivative in canopy evaporation w.r.t. ground temperature (kg m-2 s-1 K-1) + + ! output: liquid flux derivatives (ground evap) + real(rkind),intent(out) :: dGroundEvaporation_dCanWat ! derivative in ground evaporation w.r.t. canopy total water content (s-1) + real(rkind),intent(out) :: dGroundEvaporation_dTCanair ! derivative in ground evaporation w.r.t. canopy air temperature (kg m-2 s-1 K-1) + real(rkind),intent(out) :: dGroundEvaporation_dTCanopy ! derivative in ground evaporation w.r.t. canopy temperature (kg m-2 s-1 K-1) + real(rkind),intent(out) :: dGroundEvaporation_dTGround ! derivative in ground evaporation w.r.t. ground temperature (kg m-2 s-1 K-1) + + ! output: transpiration derivatives + real(rkind),intent(out) :: dCanopyTrans_dCanWat ! intent(out): derivative in canopy transpiration w.r.t. canopy total water content (s-1) + real(rkind),intent(out) :: dCanopyTrans_dTCanair ! intent(out): derivative in canopy transpiration w.r.t. canopy air temperature (kg m-2 s-1 K-1) + real(rkind),intent(out) :: dCanopyTrans_dTCanopy ! intent(out): derivative in canopy transpiration w.r.t. canopy temperature (kg m-2 s-1 K-1) + real(rkind),intent(out) :: dCanopyTrans_dTGround ! intent(out): derivative in canopy transpiration w.r.t. ground temperature (kg m-2 s-1 K-1) + + ! output: cross derivative terms + real(rkind),intent(out) :: dCanopyNetFlux_dCanWat ! derivative in net canopy fluxes w.r.t. canopy total water content (J kg-1 s-1) + real(rkind),intent(out) :: dGroundNetFlux_dCanWat ! derivative in net ground fluxes w.r.t. canopy total water content (J kg-1 s-1) + + ! output: error control + integer(i4b),intent(out) :: err ! error code + character(*),intent(out) :: message ! error message + + ! --------------------------------------------------------------------------------------- + ! * local variables + ! --------------------------------------------------------------------------------------- + ! local (general) + character(LEN=256) :: cmessage ! error message of downwind routine + real(rkind) :: VAI ! vegetation area index (m2 m-2) + real(rkind) :: exposedVAI ! exposed vegetation area index (m2 m-2) + real(rkind) :: totalCanopyWater ! total water on the vegetation canopy (kg m-2) + real(rkind) :: scalarAquiferStorage ! aquifer storage (m) + + ! local (compute numerical derivatives) + integer(i4b),parameter :: unperturbed=1 ! named variable to identify the case of unperturbed state variables + integer(i4b),parameter :: perturbStateGround=2 ! named variable to identify the case where we perturb the ground temperature + integer(i4b),parameter :: perturbStateCanopy=3 ! named variable to identify the case where we perturb the canopy temperature + integer(i4b),parameter :: perturbStateCanair=4 ! named variable to identify the case where we perturb the canopy air temperature + integer(i4b),parameter :: perturbStateCanWat=5 ! named variable to identify the case where we perturb the canopy total water content + integer(i4b) :: itry ! index of flux evaluation + integer(i4b) :: nFlux ! number of flux evaluations + real(rkind) :: groundTemp ! value of ground temperature used in flux calculations (may be perturbed) + real(rkind) :: canopyTemp ! value of canopy temperature used in flux calculations (may be perturbed) + real(rkind) :: canairTemp ! value of canopy air temperature used in flux calculations (may be perturbed) + real(rkind) :: canopyWat ! value of canopy total water used in flux calculations (may be perturbed) + real(rkind) :: canopyLiq ! value of canopy liquid water used in flux calculations (may be perturbed) + real(rkind) :: canopyIce ! value of canopy ice used in flux calculations (may be perturbed) + real(rkind) :: try0,try1 ! trial values to evaluate specific derivatives (testing only) + + ! local (saturation vapor pressure of veg) + real(rkind) :: TV_celcius ! vegetaion temperature (C) + real(rkind) :: TG_celcius ! ground temperature (C) + real(rkind) :: dSVPCanopy_dCanopyTemp ! derivative in canopy saturated vapor pressure w.r.t. vegetation temperature (Pa/K) + real(rkind) :: dSVPGround_dGroundTemp ! derivative in ground saturated vapor pressure w.r.t. ground temperature (Pa/K) + + ! local (wetted canopy area) + real(rkind) :: fracLiquidCanopy ! fraction of liquid water in the canopy (-) + real(rkind) :: canopyWetFraction ! trial value of the canopy wetted fraction (-) + real(rkind) :: dCanopyWetFraction_dWat ! derivative in wetted fraction w.r.t. canopy total water (kg-1 m2) + real(rkind) :: dCanopyWetFraction_dT ! derivative in wetted fraction w.r.t. canopy temperature (K-1) + + ! local (longwave radiation) + real(rkind) :: expi ! exponential integral + real(rkind) :: scaleLAI ! scaled LAI (computing diffuse transmissivity) + real(rkind) :: diffuseTrans ! diffuse transmissivity (-) + real(rkind) :: groundEmissivity ! emissivity of the ground surface (-) + real(rkind),parameter :: vegEmissivity=0.98_rkind ! emissivity of vegetation (0.9665 in JULES) (-) + real(rkind),parameter :: soilEmissivity=0.98_rkind ! emmisivity of the soil (0.9665 in JULES) (-) + real(rkind),parameter :: snowEmissivity=0.99_rkind ! emissivity of snow (-) + real(rkind) :: dLWNetCanopy_dTCanopy ! derivative in net canopy radiation w.r.t. canopy temperature (W m-2 K-1) + real(rkind) :: dLWNetGround_dTGround ! derivative in net ground radiation w.r.t. ground temperature (W m-2 K-1) + real(rkind) :: dLWNetCanopy_dTGround ! derivative in net canopy radiation w.r.t. ground temperature (W m-2 K-1) + real(rkind) :: dLWNetGround_dTCanopy ! derivative in net ground radiation w.r.t. canopy temperature (W m-2 K-1) + + ! local (aerodynamic resistance) + real(rkind) :: scalarCanopyStabilityCorrection_old ! stability correction for the canopy (-) + real(rkind) :: scalarGroundStabilityCorrection_old ! stability correction for the ground surface (-) + + ! local (turbulent heat transfer) + real(rkind) :: z0Ground ! roughness length of the ground (ground below the canopy or non-vegetated surface) (m) + real(rkind) :: soilEvapFactor ! soil water control on evaporation from non-vegetated surfaces + real(rkind) :: soilRelHumidity_noSnow ! relative humidity in the soil pores [0-1] + real(rkind) :: scalarLeafConductance ! leaf conductance (m s-1) + real(rkind) :: scalarCanopyConductance ! canopy conductance (m s-1) + real(rkind) :: scalarGroundConductanceSH ! ground conductance for sensible heat (m s-1) + real(rkind) :: scalarGroundConductanceLH ! ground conductance for latent heat -- includes soil resistance (m s-1) + real(rkind) :: scalarEvapConductance ! conductance for evaporation (m s-1) + real(rkind) :: scalarTransConductance ! conductance for transpiration (m s-1) + real(rkind) :: scalarTotalConductanceSH ! total conductance for sensible heat (m s-1) + real(rkind) :: scalarTotalConductanceLH ! total conductance for latent heat (m s-1) + real(rkind) :: dGroundResistance_dTGround ! derivative in ground resistance w.r.t. ground temperature (s m-1 K-1) + real(rkind) :: dGroundResistance_dTCanopy ! derivative in ground resistance w.r.t. canopy temperature (s m-1 K-1) + real(rkind) :: dGroundResistance_dTCanair ! derivative in ground resistance w.r.t. canopy air temperature (s m-1 K-1) + real(rkind) :: dCanopyResistance_dTCanopy ! derivative in canopy resistance w.r.t. canopy temperature (s m-1 K-1) + real(rkind) :: dCanopyResistance_dTCanair ! derivative in canopy resistance w.r.t. canopy air temperature (s m-1 K-1) + real(rkind) :: turbFluxCanair ! total turbulent heat fluxes exchanged at the canopy air space (W m-2) + real(rkind) :: turbFluxCanopy ! total turbulent heat fluxes from the canopy to the canopy air space (W m-2) + real(rkind) :: turbFluxGround ! total turbulent heat fluxes from the ground to the canopy air space (W m-2) + + ! local (turbulent heat transfer -- compute numerical derivatives) + ! (temporary scalar resistances when states are perturbed) + real(rkind) :: trialLeafResistance ! mean leaf boundary layer resistance per unit leaf area (s m-1) + real(rkind) :: trialGroundResistance ! below canopy aerodynamic resistance (s m-1) + real(rkind) :: trialCanopyResistance ! above canopy aerodynamic resistance (s m-1) + real(rkind) :: notUsed_RiBulkCanopy ! bulk Richardson number for the canopy (-) + real(rkind) :: notUsed_RiBulkGround ! bulk Richardson number for the ground surface (-) + real(rkind) :: notUsed_z0Canopy ! roughness length of the vegetation canopy (m) + real(rkind) :: notUsed_WindReductionFactor ! canopy wind reduction factor (-) + real(rkind) :: notUsed_ZeroPlaneDisplacement ! zero plane displacement (m) + real(rkind) :: notUsed_scalarCanopyStabilityCorrection ! stability correction for the canopy (-) + real(rkind) :: notUsed_scalarGroundStabilityCorrection ! stability correction for the ground surface (-) + real(rkind) :: notUsed_EddyDiffusCanopyTop ! eddy diffusivity for heat at the top of the canopy (m2 s-1) + real(rkind) :: notUsed_FrictionVelocity ! friction velocity (m s-1) + real(rkind) :: notUsed_WindspdCanopyTop ! windspeed at the top of the canopy (m s-1) + real(rkind) :: notUsed_WindspdCanopyBottom ! windspeed at the height of the bottom of the canopy (m s-1) + real(rkind) :: notUsed_dGroundResistance_dTGround ! derivative in ground resistance w.r.t. ground temperature (s m-1 K-1) + real(rkind) :: notUsed_dGroundResistance_dTCanopy ! derivative in ground resistance w.r.t. canopy temperature (s m-1 K-1) + real(rkind) :: notUsed_dGroundResistance_dTCanair ! derivative in ground resistance w.r.t. canopy air temperature (s m-1 K-1) + real(rkind) :: notUsed_dCanopyResistance_dTCanopy ! derivative in canopy resistance w.r.t. canopy temperature (s m-1 K-1) + real(rkind) :: notUsed_dCanopyResistance_dTCanair ! derivative in canopy resistance w.r.t. canopy air temperature (s m-1 K-1) + + ! (fluxes after perturbations in model states -- canopy air space) + real(rkind) :: turbFluxCanair_dStateCanair ! turbulent exchange from the canopy air space to the atmosphere, after canopy air temperature is perturbed (W m-2) + real(rkind) :: turbFluxCanair_dStateCanopy ! turbulent exchange from the canopy air space to the atmosphere, after canopy temperature is perturbed (W m-2) + real(rkind) :: turbFluxCanair_dStateGround ! turbulent exchange from the canopy air space to the atmosphere, after ground temperature is perturbed (W m-2) + real(rkind) :: turbFluxCanair_dStateCanWat ! turbulent exchange from the canopy air space to the atmosphere, after canopy total water content is perturbed (W m-2) + ! (fluxes after perturbations in model states -- vegetation canopy) + real(rkind) :: turbFluxCanopy_dStateCanair ! total turbulent heat fluxes from the canopy to the canopy air space, after canopy air temperature is perturbed (W m-2) + real(rkind) :: turbFluxCanopy_dStateCanopy ! total turbulent heat fluxes from the canopy to the canopy air space, after canopy temperature is perturbed (W m-2) + real(rkind) :: turbFluxCanopy_dStateGround ! total turbulent heat fluxes from the canopy to the canopy air space, after ground temperature is perturbed (W m-2) + real(rkind) :: turbFluxCanopy_dStateCanWat ! total turbulent heat fluxes from the canopy to the canopy air space, after canopy total water content is perturbed (W m-2) + + ! (fluxes after perturbations in model states -- ground surface) + real(rkind) :: turbFluxGround_dStateCanair ! total turbulent heat fluxes from the ground to the canopy air space, after canopy air temperature is perturbed (W m-2) + real(rkind) :: turbFluxGround_dStateCanopy ! total turbulent heat fluxes from the ground to the canopy air space, after canopy temperature is perturbed (W m-2) + real(rkind) :: turbFluxGround_dStateGround ! total turbulent heat fluxes from the ground to the canopy air space, after ground temperature is perturbed (W m-2) + real(rkind) :: turbFluxGround_dStateCanWat ! total turbulent heat fluxes from the ground to the canopy air space, after canopy total water content is perturbed (W m-2) + + ! (fluxes after perturbations in model states -- canopy evaporation) + real(rkind) :: latHeatCanEvap_dStateCanair ! canopy evaporation after canopy air temperature is perturbed (W m-2) + real(rkind) :: latHeatCanEvap_dStateCanopy ! canopy evaporation after canopy temperature is perturbed (W m-2) + real(rkind) :: latHeatCanEvap_dStateGround ! canopy evaporation after ground temperature is perturbed (W m-2) + real(rkind) :: latHeatCanEvap_dStateCanWat ! canopy evaporation after canopy total water content is perturbed (W m-2) + + ! (flux derivatives -- canopy air space) + real(rkind) :: dTurbFluxCanair_dTCanair ! derivative in net canopy air space fluxes w.r.t. canopy air temperature (W m-2 K-1) + real(rkind) :: dTurbFluxCanair_dTCanopy ! derivative in net canopy air space fluxes w.r.t. canopy temperature (W m-2 K-1) + real(rkind) :: dTurbFluxCanair_dTGround ! derivative in net canopy air space fluxes w.r.t. ground temperature (W m-2 K-1) + real(rkind) :: dTurbFluxCanair_dCanWat ! derivative in net canopy air space fluxes w.r.t. canopy total water content (J kg-1 s-1) + + ! (flux derivatives -- vegetation canopy) + real(rkind) :: dTurbFluxCanopy_dTCanair ! derivative in net canopy turbulent fluxes w.r.t. canopy air temperature (W m-2 K-1) + real(rkind) :: dTurbFluxCanopy_dTCanopy ! derivative in net canopy turbulent fluxes w.r.t. canopy temperature (W m-2 K-1) + real(rkind) :: dTurbFluxCanopy_dTGround ! derivative in net canopy turbulent fluxes w.r.t. ground temperature (W m-2 K-1) + real(rkind) :: dTurbFluxCanopy_dCanWat ! derivative in net canopy turbulent fluxes w.r.t. canopy total water content (J kg-1 s-1) + + ! (flux derivatives -- ground surface) + real(rkind) :: dTurbFluxGround_dTCanair ! derivative in net ground turbulent fluxes w.r.t. canopy air temperature (W m-2 K-1) + real(rkind) :: dTurbFluxGround_dTCanopy ! derivative in net ground turbulent fluxes w.r.t. canopy temperature (W m-2 K-1) + real(rkind) :: dTurbFluxGround_dTGround ! derivative in net ground turbulent fluxes w.r.t. ground temperature (W m-2 K-1) + real(rkind) :: dTurbFluxGround_dCanWat ! derivative in net ground turbulent fluxes w.r.t. canopy total water content (J kg-1 s-1) + + ! (liquid water flux derivatives -- canopy evap) + real(rkind) :: dLatHeatCanopyEvap_dCanWat ! derivative in latent heat of canopy evaporation w.r.t. canopy total water content (W kg-1) + real(rkind) :: dLatHeatCanopyEvap_dTCanair ! derivative in latent heat of canopy evaporation w.r.t. canopy air temperature (W m-2 K-1) + real(rkind) :: dLatHeatCanopyEvap_dTCanopy ! derivative in latent heat of canopy evaporation w.r.t. canopy temperature (W m-2 K-1) + real(rkind) :: dLatHeatCanopyEvap_dTGround ! derivative in latent heat of canopy evaporation w.r.t. ground temperature (W m-2 K-1) + + ! (liquid water flux derivatives -- ground evap) + real(rkind) :: dLatHeatGroundEvap_dCanWat ! derivative in latent heat of ground evaporation w.r.t. canopy total water content (J kg-1 s-1) + real(rkind) :: dLatHeatGroundEvap_dTCanair ! derivative in latent heat of ground evaporation w.r.t. canopy air temperature (W m-2 K-1) + real(rkind) :: dLatHeatGroundEvap_dTCanopy ! derivative in latent heat of ground evaporation w.r.t. canopy temperature (W m-2 K-1) + real(rkind) :: dLatHeatGroundEvap_dTGround ! derivative in latent heat of ground evaporation w.r.t. ground temperature (W m-2 K-1) + + ! output: latent heat flux derivatives (canopy trans) + real(rkind) :: dLatHeatCanopyTrans_dCanWat ! derivative in the latent heat of canopy transpiration w.r.t. canopy total water (J kg-1 s-1) + real(rkind) :: dLatHeatCanopyTrans_dTCanair ! derivative in the latent heat of canopy transpiration w.r.t. canopy air temperature + real(rkind) :: dLatHeatCanopyTrans_dTCanopy ! derivative in the latent heat of canopy transpiration w.r.t. canopy temperature + real(rkind) :: dLatHeatCanopyTrans_dTGround ! derivative in the latent heat of canopy transpiration w.r.t. ground temperature + + ! --------------------------------------------------------------------------------------- + ! point to variables in the data structure + ! --------------------------------------------------------------------------------------- + associate(& + + ! input: model decisions + ix_bcUpprTdyn => model_decisions(iLookDECISIONS%bcUpprTdyn)%iDecision, & ! intent(in): [i4b] choice of upper boundary condition for thermodynamics + ixDerivMethod => model_decisions(iLookDECISIONS%fDerivMeth)%iDecision, & ! intent(in): [i4b] choice of method to compute derivatives + ix_veg_traits => model_decisions(iLookDECISIONS%veg_traits)%iDecision, & ! intent(in): [i4b] choice of parameterization for vegetation roughness length and displacement height + ix_canopyEmis => model_decisions(iLookDECISIONS%canopyEmis)%iDecision, & ! intent(in): [i4b] choice of parameterization for canopy emissivity + ix_windPrfile => model_decisions(iLookDECISIONS%windPrfile)%iDecision, & ! intent(in): [i4b] choice of canopy wind profile + ix_astability => model_decisions(iLookDECISIONS%astability)%iDecision, & ! intent(in): [i4b] choice of stability function + ix_soilStress => model_decisions(iLookDECISIONS%soilStress)%iDecision, & ! intent(in): [i4b] choice of function for the soil moisture control on stomatal resistance + ix_groundwatr => model_decisions(iLookDECISIONS%groundwatr)%iDecision, & ! intent(in): [i4b] choice of groundwater parameterization + ix_stomResist => model_decisions(iLookDECISIONS%stomResist)%iDecision, & ! intent(in): [i4b] choice of function for stomatal resistance + ix_spatial_gw => model_decisions(iLookDECISIONS%spatial_gw)%iDecision, & ! intent(in): [i4b] choice of groundwater representation (local, basin) + + ! input: layer geometry + nSnow => indx_data%var(iLookINDEX%nSnow)%dat(1), & ! intent(in): [i4b] number of snow layers + nSoil => indx_data%var(iLookINDEX%nSoil)%dat(1), & ! intent(in): [i4b] number of soil layers + nLayers => indx_data%var(iLookINDEX%nLayers)%dat(1), & ! intent(in): [i4b] total number of layers + + ! input: physical attributes + vegTypeIndex => type_data%var(iLookTYPE%vegTypeIndex), & ! intent(in): [i4b] vegetation type index + soilTypeIndex => type_data%var(iLookTYPE%soilTypeIndex), & ! intent(in): [i4b] soil type index + + ! input: vegetation parameters + heightCanopyTop => mpar_data%var(iLookPARAM%heightCanopyTop)%dat(1), & ! intent(in): [dp] height at the top of the vegetation canopy (m) + heightCanopyBottom => mpar_data%var(iLookPARAM%heightCanopyBottom)%dat(1), & ! intent(in): [dp] height at the bottom of the vegetation canopy (m) + canopyWettingFactor => mpar_data%var(iLookPARAM%canopyWettingFactor)%dat(1), & ! intent(in): [dp] maximum wetted fraction of the canopy (-) + canopyWettingExp => mpar_data%var(iLookPARAM%canopyWettingExp)%dat(1), & ! intent(in): [dp] exponent in canopy wetting function (-) + scalarCanopyIceMax => diag_data%var(iLookDIAG%scalarCanopyIceMax)%dat(1), & ! intent(in): [dp] maximum interception storage capacity for ice (kg m-2) + scalarCanopyLiqMax => diag_data%var(iLookDIAG%scalarCanopyLiqMax)%dat(1), & ! intent(in): [dp] maximum interception storage capacity for liquid water (kg m-2) + + ! input: vegetation phenology + scalarLAI => diag_data%var(iLookDIAG%scalarLAI)%dat(1), & ! intent(in): [dp] one-sided leaf area index (m2 m-2) + scalarSAI => diag_data%var(iLookDIAG%scalarSAI)%dat(1), & ! intent(in): [dp] one-sided stem area index (m2 m-2) + scalarExposedLAI => diag_data%var(iLookDIAG%scalarExposedLAI)%dat(1), & ! intent(in): [dp] exposed leaf area index after burial by snow (m2 m-2) + scalarExposedSAI => diag_data%var(iLookDIAG%scalarExposedSAI)%dat(1), & ! intent(in): [dp] exposed stem area index after burial by snow (m2 m-2) + scalarGrowingSeasonIndex => diag_data%var(iLookDIAG%scalarGrowingSeasonIndex)%dat(1), & ! intent(in): [dp] growing season index (0=off, 1=on) + scalarFoliageNitrogenFactor => diag_data%var(iLookDIAG%scalarFoliageNitrogenFactor)%dat(1), & ! intent(in): [dp] foliage nitrogen concentration (1.0 = saturated) + + ! input: aerodynamic resistance parameters + z0Snow => mpar_data%var(iLookPARAM%z0Snow)%dat(1), & ! intent(in): [dp] roughness length of snow (m) + z0Soil => mpar_data%var(iLookPARAM%z0Soil)%dat(1), & ! intent(in): [dp] roughness length of soil (m) + z0CanopyParam => mpar_data%var(iLookPARAM%z0Canopy)%dat(1), & ! intent(in): [dp] roughness length of the canopy (m) + zpdFraction => mpar_data%var(iLookPARAM%zpdFraction)%dat(1), & ! intent(in): [dp] zero plane displacement / canopy height (-) + critRichNumber => mpar_data%var(iLookPARAM%critRichNumber)%dat(1), & ! intent(in): [dp] critical value for the bulk Richardson number where turbulence ceases (-) + Louis79_bparam => mpar_data%var(iLookPARAM%Louis79_bparam)%dat(1), & ! intent(in): [dp] parameter in Louis (1979) stability function + Louis79_cStar => mpar_data%var(iLookPARAM%Louis79_cStar)%dat(1), & ! intent(in): [dp] parameter in Louis (1979) stability function + Mahrt87_eScale => mpar_data%var(iLookPARAM%Mahrt87_eScale)%dat(1), & ! intent(in): [dp] exponential scaling factor in the Mahrt (1987) stability function + windReductionParam => mpar_data%var(iLookPARAM%windReductionParam)%dat(1), & ! intent(in): [dp] canopy wind reduction parameter (-) + leafExchangeCoeff => mpar_data%var(iLookPARAM%leafExchangeCoeff)%dat(1), & ! intent(in): [dp] turbulent exchange coeff between canopy surface and canopy air ( m s-(1/2) ) + leafDimension => mpar_data%var(iLookPARAM%leafDimension)%dat(1), & ! intent(in): [dp] characteristic leaf dimension (m) + + ! input: soil stress parameters + theta_sat => mpar_data%var(iLookPARAM%theta_sat)%dat(1), & ! intent(in): [dp] soil porosity (-) + theta_res => mpar_data%var(iLookPARAM%theta_res)%dat(1), & ! intent(in): [dp] residual volumetric liquid water content (-) + plantWiltPsi => mpar_data%var(iLookPARAM%plantWiltPsi)%dat(1), & ! intent(in): [dp] matric head at wilting point (m) + soilStressParam => mpar_data%var(iLookPARAM%soilStressParam)%dat(1), & ! intent(in): [dp] parameter in the exponential soil stress function (-) + critSoilWilting => mpar_data%var(iLookPARAM%critSoilWilting)%dat(1), & ! intent(in): [dp] critical vol. liq. water content when plants are wilting (-) + critSoilTranspire => mpar_data%var(iLookPARAM%critSoilTranspire)%dat(1), & ! intent(in): [dp] critical vol. liq. water content when transpiration is limited (-) + critAquiferTranspire => mpar_data%var(iLookPARAM%critAquiferTranspire)%dat(1), & ! intent(in): [dp] critical aquifer storage value when transpiration is limited (m) + minStomatalResistance => mpar_data%var(iLookPARAM%minStomatalResistance)%dat(1), & ! intent(in): [dp] mimimum stomatal resistance (s m-1) + + ! snow parameters + snowfrz_scale => mpar_data%var(iLookPARAM%snowfrz_scale)%dat(1), & ! intent(in): [dp] scaling parameter for the snow freezing curve (K-1) + + ! input: forcing at the upper boundary + mHeight => diag_data%var(iLookDIAG%scalarAdjMeasHeight)%dat(1), & ! intent(in): [dp] measurement height (m) + airtemp => forc_data%var(iLookFORCE%airtemp), & ! intent(in): [dp] air temperature at some height above the surface (K) + windspd => forc_data%var(iLookFORCE%windspd), & ! intent(in): [dp] wind speed at some height above the surface (m s-1) + airpres => forc_data%var(iLookFORCE%airpres), & ! intent(in): [dp] air pressure at some height above the surface (Pa) + LWRadAtm => forc_data%var(iLookFORCE%LWRadAtm), & ! intent(in): [dp] downwelling longwave radiation at the upper boundary (W m-2) + scalarVPair => diag_data%var(iLookDIAG%scalarVPair)%dat(1), & ! intent(in): [dp] vapor pressure at some height above the surface (Pa) + scalarO2air => diag_data%var(iLookDIAG%scalarO2air)%dat(1), & ! intent(in): [dp] atmospheric o2 concentration (Pa) + scalarCO2air => diag_data%var(iLookDIAG%scalarCO2air)%dat(1), & ! intent(in): [dp] atmospheric co2 concentration (Pa) + scalarTwetbulb => diag_data%var(iLookDIAG%scalarTwetbulb)%dat(1), & ! intent(in): [dp] wetbulb temperature (K) + scalarRainfall => flux_data%var(iLookFLUX%scalarRainfall)%dat(1), & ! intent(in): [dp] computed rainfall rate (kg m-2 s-1) + scalarSnowfall => flux_data%var(iLookFLUX%scalarSnowfall)%dat(1), & ! intent(in): [dp] computed snowfall rate (kg m-2 s-1) + scalarThroughfallRain => flux_data%var(iLookFLUX%scalarThroughfallRain)%dat(1), & ! intent(in): [dp] rainfall through the vegetation canopy (kg m-2 s-1) + scalarThroughfallSnow => flux_data%var(iLookFLUX%scalarThroughfallSnow)%dat(1), & ! intent(in): [dp] snowfall through the vegetation canopy (kg m-2 s-1) + + ! input: water storage + ! NOTE: soil stress only computed at the start of the substep (firstFluxCall=.true.) + scalarSWE => prog_data%var(iLookPROG%scalarSWE)%dat(1), & ! intent(in): [dp] snow water equivalent on the ground (kg m-2) + scalarSnowDepth => prog_data%var(iLookPROG%scalarSnowDepth)%dat(1), & ! intent(in): [dp] snow depth on the ground surface (m) + mLayerVolFracLiq => prog_data%var(iLookPROG%mLayerVolFracLiq)%dat, & ! intent(in): [dp(:)] volumetric fraction of liquid water in each layer (-) + mLayerMatricHead => prog_data%var(iLookPROG%mLayerMatricHead)%dat, & ! intent(in): [dp(:)] matric head in each soil layer (m) + localAquiferStorage => prog_data%var(iLookPROG%scalarAquiferStorage)%dat(1), & ! intent(in): [dp] aquifer storage for the local column (m) + basinAquiferStorage => bvar_data%var(iLookBVAR%basin__AquiferStorage)%dat(1), & ! intent(in): [dp] aquifer storage for the single basin (m) + + ! input: shortwave radiation fluxes + scalarCanopySunlitLAI => diag_data%var(iLookDIAG%scalarCanopySunlitLAI)%dat(1), & ! intent(in): [dp] sunlit leaf area (-) + scalarCanopyShadedLAI => diag_data%var(iLookDIAG%scalarCanopyShadedLAI)%dat(1), & ! intent(in): [dp] shaded leaf area (-) + scalarCanopySunlitPAR => flux_data%var(iLookFLUX%scalarCanopySunlitPAR)%dat(1), & ! intent(in): [dp] average absorbed par for sunlit leaves (w m-2) + scalarCanopyShadedPAR => flux_data%var(iLookFLUX%scalarCanopyShadedPAR)%dat(1), & ! intent(in): [dp] average absorbed par for shaded leaves (w m-2) + scalarCanopyAbsorbedSolar => flux_data%var(iLookFLUX%scalarCanopyAbsorbedSolar)%dat(1), & ! intent(in): [dp] solar radiation absorbed by canopy (W m-2) + scalarGroundAbsorbedSolar => flux_data%var(iLookFLUX%scalarGroundAbsorbedSolar)%dat(1), & ! intent(in): [dp] solar radiation absorbed by ground (W m-2) + + ! output: fraction of wetted canopy area and fraction of snow on the ground + scalarCanopyWetFraction => diag_data%var(iLookDIAG%scalarCanopyWetFraction)%dat(1), & ! intent(out): [dp] fraction of canopy that is wet + scalarGroundSnowFraction => diag_data%var(iLookDIAG%scalarGroundSnowFraction)%dat(1), & ! intent(out): [dp] fraction of ground covered with snow (-) + + ! output: longwave radiation fluxes + scalarCanopyEmissivity => diag_data%var(iLookDIAG%scalarCanopyEmissivity)%dat(1), & ! intent(out): [dp] effective emissivity of the canopy (-) + scalarLWRadCanopy => flux_data%var(iLookFLUX%scalarLWRadCanopy)%dat(1), & ! intent(out): [dp] longwave radiation emitted from the canopy (W m-2) + scalarLWRadGround => flux_data%var(iLookFLUX%scalarLWRadGround)%dat(1), & ! intent(out): [dp] longwave radiation emitted at the ground surface (W m-2) + scalarLWRadUbound2Canopy => flux_data%var(iLookFLUX%scalarLWRadUbound2Canopy)%dat(1), & ! intent(out): [dp] downward atmospheric longwave radiation absorbed by the canopy (W m-2) + scalarLWRadUbound2Ground => flux_data%var(iLookFLUX%scalarLWRadUbound2Ground)%dat(1), & ! intent(out): [dp] downward atmospheric longwave radiation absorbed by the ground (W m-2) + scalarLWRadUbound2Ubound => flux_data%var(iLookFLUX%scalarLWRadUbound2Ubound)%dat(1), & ! intent(out): [dp] atmospheric radiation reflected by the ground and lost thru upper boundary (W m-2) + scalarLWRadCanopy2Ubound => flux_data%var(iLookFLUX%scalarLWRadCanopy2Ubound)%dat(1), & ! intent(out): [dp] longwave radiation emitted from canopy lost thru upper boundary (W m-2) + scalarLWRadCanopy2Ground => flux_data%var(iLookFLUX%scalarLWRadCanopy2Ground)%dat(1), & ! intent(out): [dp] longwave radiation emitted from canopy absorbed by the ground (W m-2) + scalarLWRadCanopy2Canopy => flux_data%var(iLookFLUX%scalarLWRadCanopy2Canopy)%dat(1), & ! intent(out): [dp] canopy longwave reflected from ground and absorbed by the canopy (W m-2) + scalarLWRadGround2Ubound => flux_data%var(iLookFLUX%scalarLWRadGround2Ubound)%dat(1), & ! intent(out): [dp] longwave radiation emitted from ground lost thru upper boundary (W m-2) + scalarLWRadGround2Canopy => flux_data%var(iLookFLUX%scalarLWRadGround2Canopy)%dat(1), & ! intent(out): [dp] longwave radiation emitted from ground and absorbed by the canopy (W m-2) + scalarLWNetCanopy => flux_data%var(iLookFLUX%scalarLWNetCanopy)%dat(1), & ! intent(out): [dp] net longwave radiation at the canopy (W m-2) + scalarLWNetGround => flux_data%var(iLookFLUX%scalarLWNetGround)%dat(1), & ! intent(out): [dp] net longwave radiation at the ground surface (W m-2) + scalarLWNetUbound => flux_data%var(iLookFLUX%scalarLWNetUbound)%dat(1), & ! intent(out): [dp] net longwave radiation at the upper boundary (W m-2) + + ! output: aerodynamic resistance + scalarZ0Canopy => diag_data%var(iLookDIAG%scalarZ0Canopy)%dat(1), & ! intent(out): [dp] roughness length of the canopy (m) + scalarWindReductionFactor => diag_data%var(iLookDIAG%scalarWindReductionFactor)%dat(1), & ! intent(out): [dp] canopy wind reduction factor (-) + scalarZeroPlaneDisplacement => diag_data%var(iLookDIAG%scalarZeroPlaneDisplacement)%dat(1), & ! intent(out): [dp] zero plane displacement (m) + scalarRiBulkCanopy => diag_data%var(iLookDIAG%scalarRiBulkCanopy)%dat(1), & ! intent(out): [dp] bulk Richardson number for the canopy (-) + scalarRiBulkGround => diag_data%var(iLookDIAG%scalarRiBulkGround)%dat(1), & ! intent(out): [dp] bulk Richardson number for the ground surface (-) + scalarEddyDiffusCanopyTop => flux_data%var(iLookFLUX%scalarEddyDiffusCanopyTop)%dat(1), & ! intent(out): [dp] eddy diffusivity for heat at the top of the canopy (m2 s-1) + scalarFrictionVelocity => flux_data%var(iLookFLUX%scalarFrictionVelocity)%dat(1), & ! intent(out): [dp] friction velocity (m s-1) + scalarWindspdCanopyTop => flux_data%var(iLookFLUX%scalarWindspdCanopyTop)%dat(1), & ! intent(out): [dp] windspeed at the top of the canopy (m s-1) + scalarWindspdCanopyBottom => flux_data%var(iLookFLUX%scalarWindspdCanopyBottom)%dat(1), & ! intent(out): [dp] windspeed at the height of the bottom of the canopy (m s-1) + scalarLeafResistance => flux_data%var(iLookFLUX%scalarLeafResistance)%dat(1), & ! intent(out): [dp] mean leaf boundary layer resistance per unit leaf area (s m-1) + scalarGroundResistance => flux_data%var(iLookFLUX%scalarGroundResistance)%dat(1), & ! intent(out): [dp] below canopy aerodynamic resistance (s m-1) + scalarCanopyResistance => flux_data%var(iLookFLUX%scalarCanopyResistance)%dat(1), & ! intent(out): [dp] above canopy aerodynamic resistance (s m-1) + + ! input/output: soil resistance -- intent(in) and intent(inout) because only called at the first flux call + mLayerRootDensity => diag_data%var(iLookDIAG%mLayerRootDensity)%dat, & ! intent(in): [dp] root density in each layer (-) + scalarAquiferRootFrac => diag_data%var(iLookDIAG%scalarAquiferRootFrac)%dat(1), & ! intent(in): [dp] fraction of roots below the lowest soil layer (-) + scalarTranspireLim => diag_data%var(iLookDIAG%scalarTranspireLim)%dat(1), & ! intent(inout): [dp] weighted average of the transpiration limiting factor (-) + mLayerTranspireLim => diag_data%var(iLookDIAG%mLayerTranspireLim)%dat, & ! intent(inout): [dp] transpiration limiting factor in each layer (-) + scalarTranspireLimAqfr => diag_data%var(iLookDIAG%scalarTranspireLimAqfr)%dat(1), & ! intent(inout): [dp] transpiration limiting factor for the aquifer (-) + scalarSoilRelHumidity => diag_data%var(iLookDIAG%scalarSoilRelHumidity)%dat(1), & ! intent(inout): [dp] relative humidity in the soil pores [0-1] + scalarSoilResistance => flux_data%var(iLookFLUX%scalarSoilResistance)%dat(1), & ! intent(inout): [dp] resistance from the soil (s m-1) + + ! input/output: stomatal resistance -- intent(inout) because only called at the first flux call + scalarStomResistSunlit => flux_data%var(iLookFLUX%scalarStomResistSunlit)%dat(1), & ! intent(inout): [dp] stomatal resistance for sunlit leaves (s m-1) + scalarStomResistShaded => flux_data%var(iLookFLUX%scalarStomResistShaded)%dat(1), & ! intent(inout): [dp] stomatal resistance for shaded leaves (s m-1) + scalarPhotosynthesisSunlit => flux_data%var(iLookFLUX%scalarPhotosynthesisSunlit)%dat(1), & ! intent(inout): [dp] sunlit photosynthesis (umolco2 m-2 s-1) + scalarPhotosynthesisShaded => flux_data%var(iLookFLUX%scalarPhotosynthesisShaded)%dat(1), & ! intent(inout): [dp] shaded photosynthesis (umolco2 m-2 s-1) + + ! output: turbulent heat fluxes + scalarLatHeatSubVapCanopy => diag_data%var(iLookDIAG%scalarLatHeatSubVapCanopy)%dat(1), & ! intent(inout): [dp] latent heat of sublimation/vaporization for the vegetation canopy (J kg-1) + scalarLatHeatSubVapGround => diag_data%var(iLookDIAG%scalarLatHeatSubVapGround)%dat(1), & ! intent(inout): [dp] latent heat of sublimation/vaporization for the ground surface (J kg-1) + scalarSatVP_canopyTemp => diag_data%var(iLookDIAG%scalarSatVP_CanopyTemp)%dat(1), & ! intent(out): [dp] saturation vapor pressure at the temperature of the vegetation canopy (Pa) + scalarSatVP_groundTemp => diag_data%var(iLookDIAG%scalarSatVP_GroundTemp)%dat(1), & ! intent(out): [dp] saturation vapor pressure at the temperature of the ground surface (Pa) + scalarSenHeatTotal => flux_data%var(iLookFLUX%scalarSenHeatTotal)%dat(1), & ! intent(out): [dp] sensible heat from the canopy air space to the atmosphere (W m-2) + scalarSenHeatCanopy => flux_data%var(iLookFLUX%scalarSenHeatCanopy)%dat(1), & ! intent(out): [dp] sensible heat flux from the canopy to the canopy air space (W m-2) + scalarSenHeatGround => flux_data%var(iLookFLUX%scalarSenHeatGround)%dat(1), & ! intent(out): [dp] sensible heat flux from ground surface below vegetation (W m-2) + scalarLatHeatTotal => flux_data%var(iLookFLUX%scalarLatHeatTotal)%dat(1), & ! intent(out): [dp] latent heat from the canopy air space to the atmosphere (W m-2) + scalarLatHeatCanopyEvap => flux_data%var(iLookFLUX%scalarLatHeatCanopyEvap)%dat(1), & ! intent(out): [dp] latent heat flux for evaporation from the canopy to the canopy air space (W m-2) + scalarLatHeatCanopyTrans => flux_data%var(iLookFLUX%scalarLatHeatCanopyTrans)%dat(1), & ! intent(out): [dp] latent heat flux for transpiration from the canopy to the canopy air space (W m-2) + scalarLatHeatGround => flux_data%var(iLookFLUX%scalarLatHeatGround)%dat(1), & ! intent(out): [dp] latent heat flux from ground surface below vegetation (W m-2) + + ! output: advective heat fluxes + scalarCanopyAdvectiveHeatFlux => flux_data%var(iLookFLUX%scalarCanopyAdvectiveHeatFlux)%dat(1), & ! intent(out): [dp] heat advected to the canopy surface with rain + snow (W m-2) + scalarGroundAdvectiveHeatFlux => flux_data%var(iLookFLUX%scalarGroundAdvectiveHeatFlux)%dat(1), & ! intent(out): [dp] heat advected to the ground surface with throughfall (W m-2) + + ! output: mass fluxes + scalarCanopySublimation => flux_data%var(iLookFLUX%scalarCanopySublimation)%dat(1), & ! intent(out): [dp] canopy sublimation/frost (kg m-2 s-1) + scalarSnowSublimation => flux_data%var(iLookFLUX%scalarSnowSublimation)%dat(1), & ! intent(out): [dp] snow sublimation/frost -- below canopy or non-vegetated (kg m-2 s-1) + + ! input/output: canopy air space variables + scalarVP_CanopyAir => diag_data%var(iLookDIAG%scalarVP_CanopyAir)%dat(1), & ! intent(inout): [dp] vapor pressure of the canopy air space (Pa) + scalarCanopyStabilityCorrection => diag_data%var(iLookDIAG%scalarCanopyStabilityCorrection)%dat(1),& ! intent(inout): [dp] stability correction for the canopy (-) + scalarGroundStabilityCorrection => diag_data%var(iLookDIAG%scalarGroundStabilityCorrection)%dat(1),& ! intent(inout): [dp] stability correction for the ground surface (-) + + ! output: liquid water fluxes + scalarCanopyTranspiration => flux_data%var(iLookFLUX%scalarCanopyTranspiration)%dat(1), & ! intent(out): [dp] canopy transpiration (kg m-2 s-1) + scalarCanopyEvaporation => flux_data%var(iLookFLUX%scalarCanopyEvaporation)%dat(1), & ! intent(out): [dp] canopy evaporation/condensation (kg m-2 s-1) + scalarGroundEvaporation => flux_data%var(iLookFLUX%scalarGroundEvaporation)%dat(1), & ! intent(out): [dp] ground evaporation/condensation -- below canopy or non-vegetated (kg m-2 s-1) + + ! output: derived fluxes + scalarTotalET => flux_data%var(iLookFLUX%scalarTotalET)%dat(1), & ! intent(out): [dp] total ET (kg m-2 s-1) + scalarNetRadiation => flux_data%var(iLookFLUX%scalarNetRadiation)%dat(1) & ! intent(out): [dp] net radiation (W m-2) + ) + ! --------------------------------------------------------------------------------------- + ! initialize error control + err=0; message="vegNrgFlux/" + + ! initialize printflag + printflag = .false. + + ! identify the type of boundary condition for thermodynamics + select case(ix_bcUpprTdyn) + ! ***** ! (1) DIRICHLET OR ZERO FLUX BOUNDARY CONDITION... ! ************************************************ - + ! NOTE: Vegetation fluxes are not computed in this case - + ! ** prescribed temperature or zero flux at the upper boundary of the snow-soil system case(prescribedTemp,zeroFlux) - - ! derived fluxes - scalarTotalET = 0._rkind ! total ET (kg m-2 s-1) - scalarNetRadiation = 0._rkind ! net radiation (W m-2) - ! liquid water fluxes associated with evaporation/transpiration - scalarCanopyTranspiration = 0._rkind ! canopy transpiration (kg m-2 s-1) - scalarCanopyEvaporation = 0._rkind ! canopy evaporation/condensation (kg m-2 s-1) - scalarGroundEvaporation = 0._rkind ! ground evaporation/condensation -- below canopy or non-vegetated (kg m-2 s-1) - ! solid water fluxes associated with sublimation/frost - scalarCanopySublimation = 0._rkind ! sublimation from the vegetation canopy ((kg m-2 s-1) - scalarSnowSublimation = 0._rkind ! sublimation from the snow surface ((kg m-2 s-1) - ! set canopy fluxes to zero (no canopy) - canairNetFlux = 0._rkind ! net energy flux for the canopy air space (W m-2) - canopyNetFlux = 0._rkind ! net energy flux for the vegetation canopy (W m-2) - ! set canopy derivatives to zero - dCanairNetFlux_dCanairTemp = 0._rkind ! derivative in net canopy air space flux w.r.t. canopy air temperature (W m-2 K-1) - dCanairNetFlux_dCanopyTemp = 0._rkind ! derivative in net canopy air space flux w.r.t. canopy temperature (W m-2 K-1) - dCanairNetFlux_dGroundTemp = 0._rkind ! derivative in net canopy air space flux w.r.t. ground temperature (W m-2 K-1) - dCanopyNetFlux_dCanairTemp = 0._rkind ! derivative in net canopy flux w.r.t. canopy air temperature (W m-2 K-1) - dCanopyNetFlux_dCanopyTemp = 0._rkind ! derivative in net canopy flux w.r.t. canopy temperature (W m-2 K-1) - dCanopyNetFlux_dGroundTemp = 0._rkind ! derivative in net canopy flux w.r.t. ground temperature (W m-2 K-1) - dGroundNetFlux_dCanairTemp = 0._rkind ! derivative in net ground flux w.r.t. canopy air temperature (W m-2 K-1) - dGroundNetFlux_dCanopyTemp = 0._rkind ! derivative in net ground flux w.r.t. canopy temperature (W m-2 K-1) - ! set liquid flux derivatives to zero (canopy evap) - dCanopyEvaporation_dCanWat = 0._rkind ! derivative in canopy evaporation w.r.t. canopy total water content (s-1) - dCanopyEvaporation_dTCanair= 0._rkind ! derivative in canopy evaporation w.r.t. canopy air temperature (kg m-2 s-1 K-1) - dCanopyEvaporation_dTCanopy= 0._rkind ! derivative in canopy evaporation w.r.t. canopy temperature (kg m-2 s-1 K-1) - dCanopyEvaporation_dTGround= 0._rkind ! derivative in canopy evaporation w.r.t. ground temperature (kg m-2 s-1 K-1) - ! set liquid flux derivatives to zero (ground evap) - dGroundEvaporation_dCanWat = 0._rkind ! derivative in ground evaporation w.r.t. canopy total water content (s-1) - dGroundEvaporation_dTCanair= 0._rkind ! derivative in ground evaporation w.r.t. canopy air temperature (kg m-2 s-1 K-1) - dGroundEvaporation_dTCanopy= 0._rkind ! derivative in ground evaporation w.r.t. canopy temperature (kg m-2 s-1 K-1) - dGroundEvaporation_dTGround= 0._rkind ! derivative in ground evaporation w.r.t. ground temperature (kg m-2 s-1 K-1) - ! set transpiration derivatives to zero - dCanopyTrans_dCanWat = 0._rkind ! derivative in canopy transpiration w.r.t. canopy total water content (s-1) - dCanopyTrans_dTCanair= 0._rkind ! derivative in canopy transpiration w.r.t. canopy air temperature (kg m-2 s-1 K-1) - dCanopyTrans_dTCanopy= 0._rkind ! derivative in canopy transpiration w.r.t. canopy temperature (kg m-2 s-1 K-1) - dCanopyTrans_dTGround= 0._rkind ! derivative in canopy transpiration w.r.t. ground temperature (kg m-2 s-1 K-1) - - ! compute fluxes and derivatives -- separate approach for prescribed temperature and zero flux, - if(ix_bcUpprTdyn == prescribedTemp)then - ! compute ground net flux (W m-2) - groundNetFlux = -diag_data%var(iLookDIAG%iLayerThermalC)%dat(0)*(groundTempTrial - upperBoundTemp)/(prog_data%var(iLookPROG%mLayerDepth)%dat(1)*0.5_rkind) - ! compute derivative in net ground flux w.r.t. ground temperature (W m-2 K-1) inside soil and snow (ssd) energy flux routine - ! dGroundNetFlux_dGroundTemp = missingValue - elseif(ix_bcUpprTdyn == zeroFlux)then - groundNetFlux = 0._rkind - ! dGroundNetFlux_dGroundTemp = missingValue - else - err=20; message=trim(message)//'unable to identify upper boundary condition for thermodynamics: expect the case to be prescribedTemp or zeroFlux'; return - end if - - ! ***** - ! (2) NEUMANN BOUNDARY CONDITION... - ! ********************************* - - ! NOTE 1: This is the main routine for calculating vegetation fluxes - ! NOTE 2: This routine also calculates surface fluxes for the case where vegetation is buried with snow (or bare soil) - - ! ******************************************************************************************************************************************************************* - ! ******************************************************************************************************************************************************************* - ! ***** PRELIMINARIES ********************************************************************************************************************************************** - ! ******************************************************************************************************************************************************************* - ! ******************************************************************************************************************************************************************* - + + ! derived fluxes + scalarTotalET = 0._rkind ! total ET (kg m-2 s-1) + scalarNetRadiation = 0._rkind ! net radiation (W m-2) + ! liquid water fluxes associated with evaporation/transpiration + scalarCanopyTranspiration = 0._rkind ! canopy transpiration (kg m-2 s-1) + scalarCanopyEvaporation = 0._rkind ! canopy evaporation/condensation (kg m-2 s-1) + scalarGroundEvaporation = 0._rkind ! ground evaporation/condensation -- below canopy or non-vegetated (kg m-2 s-1) + ! solid water fluxes associated with sublimation/frost + scalarCanopySublimation = 0._rkind ! sublimation from the vegetation canopy ((kg m-2 s-1) + scalarSnowSublimation = 0._rkind ! sublimation from the snow surface ((kg m-2 s-1) + ! set canopy fluxes to zero (no canopy) + canairNetFlux = 0._rkind ! net energy flux for the canopy air space (W m-2) + canopyNetFlux = 0._rkind ! net energy flux for the vegetation canopy (W m-2) + ! set canopy derivatives to zero + dCanairNetFlux_dCanairTemp = 0._rkind ! derivative in net canopy air space flux w.r.t. canopy air temperature (W m-2 K-1) + dCanairNetFlux_dCanopyTemp = 0._rkind ! derivative in net canopy air space flux w.r.t. canopy temperature (W m-2 K-1) + dCanairNetFlux_dGroundTemp = 0._rkind ! derivative in net canopy air space flux w.r.t. ground temperature (W m-2 K-1) + dCanopyNetFlux_dCanairTemp = 0._rkind ! derivative in net canopy flux w.r.t. canopy air temperature (W m-2 K-1) + dCanopyNetFlux_dCanopyTemp = 0._rkind ! derivative in net canopy flux w.r.t. canopy temperature (W m-2 K-1) + dCanopyNetFlux_dGroundTemp = 0._rkind ! derivative in net canopy flux w.r.t. ground temperature (W m-2 K-1) + dGroundNetFlux_dCanairTemp = 0._rkind ! derivative in net ground flux w.r.t. canopy air temperature (W m-2 K-1) + dGroundNetFlux_dCanopyTemp = 0._rkind ! derivative in net ground flux w.r.t. canopy temperature (W m-2 K-1) + ! set liquid flux derivatives to zero (canopy evap) + dCanopyEvaporation_dCanWat = 0._rkind ! derivative in canopy evaporation w.r.t. canopy total water content (s-1) + dCanopyEvaporation_dTCanair= 0._rkind ! derivative in canopy evaporation w.r.t. canopy air temperature (kg m-2 s-1 K-1) + dCanopyEvaporation_dTCanopy= 0._rkind ! derivative in canopy evaporation w.r.t. canopy temperature (kg m-2 s-1 K-1) + dCanopyEvaporation_dTGround= 0._rkind ! derivative in canopy evaporation w.r.t. ground temperature (kg m-2 s-1 K-1) + ! set liquid flux derivatives to zero (ground evap) + dGroundEvaporation_dCanWat = 0._rkind ! derivative in ground evaporation w.r.t. canopy total water content (s-1) + dGroundEvaporation_dTCanair= 0._rkind ! derivative in ground evaporation w.r.t. canopy air temperature (kg m-2 s-1 K-1) + dGroundEvaporation_dTCanopy= 0._rkind ! derivative in ground evaporation w.r.t. canopy temperature (kg m-2 s-1 K-1) + dGroundEvaporation_dTGround= 0._rkind ! derivative in ground evaporation w.r.t. ground temperature (kg m-2 s-1 K-1) + ! set transpiration derivatives to zero + dCanopyTrans_dCanWat = 0._rkind ! derivative in canopy transpiration w.r.t. canopy total water content (s-1) + dCanopyTrans_dTCanair= 0._rkind ! derivative in canopy transpiration w.r.t. canopy air temperature (kg m-2 s-1 K-1) + dCanopyTrans_dTCanopy= 0._rkind ! derivative in canopy transpiration w.r.t. canopy temperature (kg m-2 s-1 K-1) + dCanopyTrans_dTGround= 0._rkind ! derivative in canopy transpiration w.r.t. ground temperature (kg m-2 s-1 K-1) + + ! compute fluxes and derivatives -- separate approach for prescribed temperature and zero flux, + if(ix_bcUpprTdyn == prescribedTemp)then + ! compute ground net flux (W m-2) + groundNetFlux = -diag_data%var(iLookDIAG%iLayerThermalC)%dat(0)*(groundTempTrial - upperBoundTemp)/(prog_data%var(iLookPROG%mLayerDepth)%dat(1)*0.5_rkind) + ! compute derivative in net ground flux w.r.t. ground temperature (W m-2 K-1) inside soil and snow (ssd) energy flux routine + ! dGroundNetFlux_dGroundTemp = missingValue + elseif(ix_bcUpprTdyn == zeroFlux)then + groundNetFlux = 0._rkind + ! dGroundNetFlux_dGroundTemp = missingValue + else + err=20; message=trim(message)//'unable to identify upper boundary condition for thermodynamics: expect the case to be prescribedTemp or zeroFlux'; return + end if + + ! ***** + ! (2) NEUMANN BOUNDARY CONDITION... + ! ********************************* + + ! NOTE 1: This is the main routine for calculating vegetation fluxes + ! NOTE 2: This routine also calculates surface fluxes for the case where vegetation is buried with snow (or bare soil) + + ! ******************************************************************************************************************************************************************* + ! ******************************************************************************************************************************************************************* + ! ***** PRELIMINARIES ********************************************************************************************************************************************** + ! ******************************************************************************************************************************************************************* + ! ******************************************************************************************************************************************************************* + ! * flux boundary condition case(energyFlux) - - ! identify the appropriate groundwater variable - select case(ix_spatial_gw) - case(singleBasin); scalarAquiferStorage = basinAquiferStorage - case(localColumn); scalarAquiferStorage = localAquiferStorage - case default; err=20; message=trim(message)//'unable to identify spatial representation of groundwater'; return - end select ! (modify the groundwater representation for this single-column implementation) - - ! set canopy stability corrections to the previous values - scalarCanopyStabilityCorrection_old = scalarCanopyStabilityCorrection ! stability correction for the canopy (-) - scalarGroundStabilityCorrection_old = scalarGroundStabilityCorrection ! stability correction for the ground surface (-) - - ! initialize variables to compute stomatal resistance - if(firstFluxCall .and. firstSubStep)then - ! vapor pressure in the canopy air space initialized as vapor pressure of air above the vegetation canopy - ! NOTE: this is needed for the stomatal resistance calculations - if(scalarVP_CanopyAir < 0._rkind)then - scalarVP_CanopyAir = scalarVPair - 1._rkind ! "small" offset used to assist in checking initial derivative calculations + + ! identify the appropriate groundwater variable + select case(ix_spatial_gw) + case(singleBasin); scalarAquiferStorage = basinAquiferStorage + case(localColumn); scalarAquiferStorage = localAquiferStorage + case default; err=20; message=trim(message)//'unable to identify spatial representation of groundwater'; return + end select ! (modify the groundwater representation for this single-column implementation) + + ! set canopy stability corrections to the previous values + scalarCanopyStabilityCorrection_old = scalarCanopyStabilityCorrection ! stability correction for the canopy (-) + scalarGroundStabilityCorrection_old = scalarGroundStabilityCorrection ! stability correction for the ground surface (-) + + ! initialize variables to compute stomatal resistance + if(firstFluxCall .and. firstSubStep)then + ! vapor pressure in the canopy air space initialized as vapor pressure of air above the vegetation canopy + ! NOTE: this is needed for the stomatal resistance calculations + if(scalarVP_CanopyAir < 0._rkind)then + scalarVP_CanopyAir = scalarVPair - 1._rkind ! "small" offset used to assist in checking initial derivative calculations + end if end if - end if - - ! set latent heat of sublimation/vaporization for canopy and ground surface (Pa/K) - ! NOTE: variables are constant over the substep, to simplify relating energy and mass fluxes - if(firstFluxCall)then - scalarLatHeatSubVapCanopy = getLatentHeatValue(canopyTempTrial) - ! case when there is snow on the ground (EXCLUDE "snow without a layer" -- in this case, evaporate from the soil) - if(nSnow > 0)then - if(groundTempTrial > Tfreeze)then; err=20; message=trim(message)//'do not expect ground temperature > 0 when snow is on the ground'; return; end if - scalarLatHeatSubVapGround = LH_sub ! sublimation from snow - scalarGroundSnowFraction = 1._rkind - ! case when the ground is snow-free - else - scalarLatHeatSubVapGround = LH_vap ! evaporation of water in the soil pores: this occurs even if frozen because of super-cooled water - scalarGroundSnowFraction = 0._rkind - end if ! (if there is snow on the ground) - end if ! (if the first flux call) - !write(*,'(a,1x,10(f30.10,1x))') 'groundTempTrial, scalarLatHeatSubVapGround = ', groundTempTrial, scalarLatHeatSubVapGround - - ! compute the roughness length of the ground (ground below the canopy or non-vegetated surface) - z0Ground = z0soil*(1._rkind - scalarGroundSnowFraction) + z0Snow*scalarGroundSnowFraction ! roughness length (m) - - ! compute the total vegetation area index (leaf plus stem) - VAI = scalarLAI + scalarSAI ! vegetation area index - exposedVAI = scalarExposedLAI + scalarExposedSAI ! exposed vegetation area index - - ! compute emissivity of the canopy (-) - if(computeVegFlux)then - select case(ix_canopyEmis) - ! *** simple exponential function - case(simplExp) - scalarCanopyEmissivity = 1._rkind - exp(-exposedVAI) ! effective emissivity of the canopy (-) - ! *** canopy emissivity parameterized as a function of diffuse transmissivity - case(difTrans) - ! compute the exponential integral - scaleLAI = 0.5_rkind*exposedVAI - expi = expInt(scaleLAI) - ! compute diffuse transmissivity (-) - diffuseTrans = (1._rkind - scaleLAI)*exp(-scaleLAI) + (scaleLAI**2._rkind)*expi - ! compute the canopy emissivity - scalarCanopyEmissivity = (1._rkind - diffuseTrans)*vegEmissivity - ! *** check we found the correct option - case default - err=20; message=trim(message)//'unable to identify option for canopy emissivity'; return - end select - end if - - ! ensure canopy longwave fluxes are zero when not computing canopy fluxes - if(.not.computeVegFlux) scalarCanopyEmissivity=0._rkind - - ! compute emissivity of the ground surface (-) - groundEmissivity = scalarGroundSnowFraction*snowEmissivity + (1._rkind - scalarGroundSnowFraction)*soilEmissivity ! emissivity of the ground surface (-) - - ! compute the fraction of canopy that is wet - ! NOTE: we either sublimate or evaporate over the entire substep - if(computeVegFlux)then - - ! compute the fraction of liquid water in the canopy (-) - totalCanopyWater = canopyLiqTrial + canopyIceTrial - if(totalCanopyWater > tiny(1.0_rkind))then - fracLiquidCanopy = canopyLiqTrial / (canopyLiqTrial + canopyIceTrial) - else - fracLiquidCanopy = 0._rkind + + ! set latent heat of sublimation/vaporization for canopy and ground surface (Pa/K) + ! NOTE: variables are constant over the substep, to simplify relating energy and mass fluxes + if(firstFluxCall)then + scalarLatHeatSubVapCanopy = getLatentHeatValue(canopyTempTrial) + ! case when there is snow on the ground (EXCLUDE "snow without a layer" -- in this case, evaporate from the soil) + if(nSnow > 0)then + if(groundTempTrial > Tfreeze)then; err=20; message=trim(message)//'do not expect ground temperature > 0 when snow is on the ground'; return; end if + scalarLatHeatSubVapGround = LH_sub ! sublimation from snow + scalarGroundSnowFraction = 1._rkind + ! case when the ground is snow-free + else + scalarLatHeatSubVapGround = LH_vap ! evaporation of water in the soil pores: this occurs even if frozen because of super-cooled water + scalarGroundSnowFraction = 0._rkind + end if ! (if there is snow on the ground) + end if ! (if the first flux call) + + ! compute the roughness length of the ground (ground below the canopy or non-vegetated surface) + z0Ground = z0soil*(1._rkind - scalarGroundSnowFraction) + z0Snow*scalarGroundSnowFraction ! roughness length (m) + + ! compute the total vegetation area index (leaf plus stem) + VAI = scalarLAI + scalarSAI ! vegetation area index + exposedVAI = scalarExposedLAI + scalarExposedSAI ! exposed vegetation area index + + ! compute emissivity of the canopy (-) + if(computeVegFlux)then + select case(ix_canopyEmis) + ! *** simple exponential function + case(simplExp) + scalarCanopyEmissivity = 1._rkind - exp(-exposedVAI) ! effective emissivity of the canopy (-) + ! *** canopy emissivity parameterized as a function of diffuse transmissivity + case(difTrans) + ! compute the exponential integral + scaleLAI = 0.5_rkind*exposedVAI + expi = expInt(scaleLAI) + ! compute diffuse transmissivity (-) + diffuseTrans = (1._rkind - scaleLAI)*exp(-scaleLAI) + (scaleLAI**2._rkind)*expi + ! compute the canopy emissivity + scalarCanopyEmissivity = (1._rkind - diffuseTrans)*vegEmissivity + ! *** check we found the correct option + case default + err=20; message=trim(message)//'unable to identify option for canopy emissivity'; return + end select end if - - ! get wetted fraction and derivatives - call wettedFrac(& - ! input - .true., & ! flag to denote if derivative is desired - (ixDerivMethod == numerical), & ! flag to denote that numerical derivatives are required (otherwise, analytical derivatives are calculated) - (scalarLatHeatSubVapCanopy > LH_vap+verySmall), & ! flag to denote if the canopy is frozen - dCanLiq_dTcanopy, & ! derivative in canopy liquid w.r.t. canopy temperature (kg m-2 K-1) - fracLiquidCanopy, & ! fraction of liquid water on the canopy (-) - canopyLiqTrial, & ! canopy liquid water (kg m-2) - canopyIceTrial, & ! canopy ice (kg m-2) - scalarCanopyLiqMax, & ! maximum canopy liquid water (kg m-2) - scalarCanopyIceMax, & ! maximum canopy ice content (kg m-2) - canopyWettingFactor, & ! maximum wetted fraction of the canopy (-) - canopyWettingExp, & ! exponent in canopy wetting function (-) - ! output - scalarCanopyWetFraction, & ! canopy wetted fraction (-) - dCanopyWetFraction_dWat, & ! derivative in wetted fraction w.r.t. canopy total water (kg-1 m2) - dCanopyWetFraction_dT, & ! derivative in wetted fraction w.r.t. canopy temperature (K-1) - err,cmessage) - if(err/=0)then; message=trim(message)//trim(cmessage); return; end if - - else - scalarCanopyWetFraction = 0._rkind ! canopy wetted fraction (-) - dCanopyWetFraction_dWat = 0._rkind ! derivative in wetted fraction w.r.t. canopy total water (kg-1 m2) - dCanopyWetFraction_dT = 0._rkind ! derivative in wetted fraction w.r.t. canopy temperature (K-1) - end if - !write(*,'(a,1x,L1,1x,f25.15,1x))') 'computeVegFlux, scalarCanopyWetFraction = ', computeVegFlux, scalarCanopyWetFraction - !print*, 'dCanopyWetFraction_dWat = ', dCanopyWetFraction_dWat - !print*, 'dCanopyWetFraction_dT = ', dCanopyWetFraction_dT - !print*, 'canopyLiqTrial = ', canopyLiqTrial - !print*, 'canopyIceTrial = ', canopyIceTrial - !print*, 'scalarCanopyLiqMax = ', scalarCanopyLiqMax - !print*, 'scalarCanopyIceMax = ', scalarCanopyIceMax - - ! ******************************************************************************************************************************************************************* - ! ******************************************************************************************************************************************************************* - ! ***** AERODYNAMIC RESISTANCE ***************************************************************************************************************************************** - ! ******************************************************************************************************************************************************************* - ! ******************************************************************************************************************************************************************* - - ! NOTE: compute for all iterations - - ! compute aerodynamic resistances - ! Refs: Choudhury and Monteith (4-layer model for heat budget of homogenous surfaces; QJRMS, 1988) - ! Niu and Yang (Canopy effects on snow processes; JGR, 2004) - ! Mahat et al. (Below-canopy turbulence in a snowmelt model, WRR, 2012) - call aeroResist(& - ! input: model control - computeVegFlux, & ! intent(in): logical flag to compute vegetation fluxes (.false. if veg buried by snow) - (ixDerivMethod == analytical), & ! intent(in): logical flag if would like to compute analytical derivaties - ix_veg_traits, & ! intent(in): choice of parameterization for vegetation roughness length and displacement height - ix_windPrfile, & ! intent(in): choice of canopy wind profile - ix_astability, & ! intent(in): choice of stability function - ! input: above-canopy forcing data - mHeight, & ! intent(in): measurement height (m) - airtemp, & ! intent(in): air temperature at some height above the surface (K) - windspd, & ! intent(in): wind speed at some height above the surface (m s-1) - ! input: canopy and ground temperature - canairTempTrial, & ! intent(in): temperature of the canopy air space (K) - groundTempTrial, & ! intent(in): temperature of the ground surface (K) - ! input: diagnostic variables - exposedVAI, & ! intent(in): exposed vegetation area index -- leaf plus stem (m2 m-2) - scalarSnowDepth, & ! intent(in): snow depth (m) - ! input: parameters - z0Ground, & ! intent(in): roughness length of the ground (below canopy or non-vegetated surface [snow]) (m) - z0CanopyParam, & ! intent(in): roughness length of the canopy (m) - zpdFraction, & ! intent(in): zero plane displacement / canopy height (-) - critRichNumber, & ! intent(in): critical value for the bulk Richardson number where turbulence ceases (-) - Louis79_bparam, & ! intent(in): parameter in Louis (1979) stability function - Mahrt87_eScale, & ! intent(in): exponential scaling factor in the Mahrt (1987) stability function - windReductionParam, & ! intent(in): canopy wind reduction parameter (-) - leafExchangeCoeff, & ! intent(in): turbulent exchange coeff between canopy surface and canopy air ( m s-(1/2) ) - leafDimension, & ! intent(in): characteristic leaf dimension (m) - heightCanopyTop, & ! intent(in): height at the top of the vegetation canopy (m) - heightCanopyBottom, & ! intent(in): height at the bottom of the vegetation canopy (m) - ! output: stability corrections - scalarRiBulkCanopy, & ! intent(out): bulk Richardson number for the canopy (-) - scalarRiBulkGround, & ! intent(out): bulk Richardson number for the ground surface (-) - scalarCanopyStabilityCorrection, & ! intent(out): stability correction for the canopy (-) - scalarGroundStabilityCorrection, & ! intent(out): stability correction for the ground surface (-) - ! output: scalar resistances - scalarZ0Canopy, & ! intent(out): roughness length of the canopy (m) - scalarWindReductionFactor, & ! intent(out): canopy wind reduction factor (-) - scalarZeroPlaneDisplacement, & ! intent(out): zero plane displacement (m) - scalarEddyDiffusCanopyTop, & ! intent(out): eddy diffusivity for heat at the top of the canopy (m2 s-1) - scalarFrictionVelocity, & ! intent(out): friction velocity (m s-1) - scalarWindspdCanopyTop, & ! intent(out): windspeed at the top of the canopy (m s-1) - scalarWindspdCanopyBottom, & ! intent(out): windspeed at the height of the bottom of the canopy (m s-1) - scalarLeafResistance, & ! intent(out): mean leaf boundary layer resistance per unit leaf area (s m-1) - scalarGroundResistance, & ! intent(out): below canopy aerodynamic resistance (s m-1) - scalarCanopyResistance, & ! intent(out): above canopy aerodynamic resistance (s m-1) - ! output: derivatives in scalar resistances - dGroundResistance_dTGround, & ! intent(out): derivative in ground resistance w.r.t. ground temperature (s m-1 K-1) - dGroundResistance_dTCanopy, & ! intent(out): derivative in ground resistance w.r.t. canopy temperature (s m-1 K-1) - dGroundResistance_dTCanair, & ! intent(out): derivative in ground resistance w.r.t. canopy air temperature (s m-1 K-1) - dCanopyResistance_dTCanopy, & ! intent(out): derivative in canopy resistance w.r.t. canopy temperature (s m-1 K-1) - dCanopyResistance_dTCanair, & ! intent(out): derivative in canopy resistance w.r.t. canopy air temperature (s m-1 K-1) - ! output: error control - err,cmessage ) ! intent(out): error control - if(err/=0)then; message=trim(message)//trim(cmessage); return; end if - !print*, scalarLeafResistance, & ! mean leaf boundary layer resistance per unit leaf area (s m-1) - ! scalarGroundResistance, & ! below canopy aerodynamic resistance (s m-1) - ! scalarCanopyResistance, & ! above canopy aerodynamic resistance (s m-1) - ! '(leaf, ground, canopy)' - - ! ******************************************************************************************************************************************************************* - ! ******************************************************************************************************************************************************************* - ! ***** STOMATAL RESISTANCE ***************************************************************************************************************************************** - ! ******************************************************************************************************************************************************************* - ! ******************************************************************************************************************************************************************* - - ! stomatal resistance is constant over the SUBSTEP - ! NOTE: This is a simplification, as stomatal resistance does depend on canopy temperature - ! This "short-cut" made because: - ! (1) computations are expensive; - ! (2) derivative calculations are rather complex (iterations within the Ball-Berry routine); and - ! (3) stomatal resistance does not change rapidly - if(firstFluxCall)then - - ! compute the saturation vapor pressure for vegetation temperature - TV_celcius = canopyTempTrial - Tfreeze - call satVapPress(TV_celcius, scalarSatVP_CanopyTemp, dSVPCanopy_dCanopyTemp) - - ! compute soil moisture factor controlling stomatal resistance - call soilResist(& - ! input (model decisions) - ix_soilStress, & ! intent(in): choice of function for the soil moisture control on stomatal resistance - ix_groundwatr, & ! intent(in): groundwater parameterization - ! input (state variables) - mLayerMatricHead(1:nSoil), & ! intent(in): matric head in each soil layer (m) - mLayerVolFracLiq(nSnow+1:nLayers), & ! intent(in): volumetric fraction of liquid water in each soil layer (-) - scalarAquiferStorage, & ! intent(in): aquifer storage (m) - ! input (diagnostic variables) - mLayerRootDensity(1:nSoil), & ! intent(in): root density in each layer (-) - scalarAquiferRootFrac, & ! intent(in): fraction of roots below the lowest soil layer (-) - ! input (parameters) - plantWiltPsi, & ! intent(in): matric head at wilting point (m) - soilStressParam, & ! intent(in): parameter in the exponential soil stress function (-) - critSoilWilting, & ! intent(in): critical vol. liq. water content when plants are wilting (-) - critSoilTranspire, & ! intent(in): critical vol. liq. water content when transpiration is limited (-) - critAquiferTranspire, & ! intent(in): critical aquifer storage value when transpiration is limited (m) - ! output - scalarTranspireLim, & ! intent(out): weighted average of the transpiration limiting factor (-) - mLayerTranspireLim(1:nSoil), & ! intent(out): transpiration limiting factor in each layer (-) - scalarTranspireLimAqfr, & ! intent(out): transpiration limiting factor for the aquifer (-) - err,cmessage ) ! intent(out): error control - if(err/=0)then; message=trim(message)//trim(cmessage); return; end if - !print*, 'weighted average of the soil moiture factor controlling stomatal resistance (-) = ', scalarTranspireLim - - !write(*,'(a,1x,10(f20.10,1x))') 'canopyTempTrial, scalarSatVP_CanopyTemp, scalarVP_CanopyAir = ', & - ! canopyTempTrial, scalarSatVP_CanopyTemp, scalarVP_CanopyAir - - ! compute stomatal resistance - call stomResist(& - ! input (state and diagnostic variables) - canopyTempTrial, & ! intent(in): temperature of the vegetation canopy (K) - scalarSatVP_CanopyTemp, & ! intent(in): saturation vapor pressure at the temperature of the veg canopy (Pa) - scalarVP_CanopyAir, & ! intent(in): canopy air vapor pressure (Pa) - ! input: data structures - type_data, & ! intent(in): type of vegetation and soil - forc_data, & ! intent(in): model forcing data - mpar_data, & ! intent(in): model parameters - model_decisions, & ! intent(in): model decisions - ! input-output: data structures - diag_data, & ! intent(inout): model diagnostic variables for a local HRU - flux_data, & ! intent(inout): model fluxes for a local HRU - ! output: error control - err,cmessage ) ! intent(out): error control - if(err/=0)then; message=trim(message)//trim(cmessage); return; end if - - end if ! (if the first flux call in a given sub-step) - - - ! ******************************************************************************************************************************************************************* - ! ******************************************************************************************************************************************************************* - ! ***** LONGWAVE RADIATION ***************************************************************************************************************************************** - ! ******************************************************************************************************************************************************************* - ! ******************************************************************************************************************************************************************* - - ! compute canopy longwave radiation balance - call longwaveBal(& - ! input: model control - ixDerivMethod, & ! intent(in): method used to calculate flux derivatives - computeVegFlux, & ! intent(in): flag to compute fluxes over vegetation - requireLWBal, & ! intent(in): flag to indicate if we need longwave to be balanced - ! input: canopy and ground temperature - canopyTempTrial, & ! intent(in): temperature of the vegetation canopy (K) - groundTempTrial, & ! intent(in): temperature of the ground surface (K) - ! input: canopy and ground emissivity - scalarCanopyEmissivity, & ! intent(in): canopy emissivity (-) - groundEmissivity, & ! intent(in): ground emissivity (-) - ! input: forcing - LWRadAtm, & ! intent(in): downwelling longwave radiation at the upper boundary (W m-2) - ! output: emitted radiation from the canopy and ground - scalarLWRadCanopy, & ! intent(out): longwave radiation emitted from the canopy (W m-2) - scalarLWRadGround, & ! intent(out): longwave radiation emitted at the ground surface (W m-2) - ! output: individual fluxes - scalarLWRadUbound2Canopy, & ! intent(out): downward atmospheric longwave radiation absorbed by the canopy (W m-2) - scalarLWRadUbound2Ground, & ! intent(out): downward atmospheric longwave radiation absorbed by the ground (W m-2) - scalarLWRadUbound2Ubound, & ! intent(out): atmospheric radiation reflected by the ground and lost thru upper boundary (W m-2) - scalarLWRadCanopy2Ubound, & ! intent(out): longwave radiation emitted from canopy lost thru upper boundary (W m-2) - scalarLWRadCanopy2Ground, & ! intent(out): longwave radiation emitted from canopy absorbed by the ground (W m-2) - scalarLWRadCanopy2Canopy, & ! intent(out): canopy longwave reflected from ground and absorbed by the canopy (W m-2) - scalarLWRadGround2Ubound, & ! intent(out): longwave radiation emitted from ground lost thru upper boundary (W m-2) - scalarLWRadGround2Canopy, & ! intent(out): longwave radiation emitted from ground and absorbed by the canopy (W m-2) - ! output: net fluxes - scalarLWNetCanopy, & ! intent(out): net longwave radiation at the canopy (W m-2) - scalarLWNetGround, & ! intent(out): net longwave radiation at the ground surface (W m-2) - scalarLWNetUbound, & ! intent(out): net longwave radiation at the upper boundary (W m-2) - ! output: flux derivatives - dLWNetCanopy_dTCanopy, & ! intent(out): derivative in net canopy radiation w.r.t. canopy temperature (W m-2 K-1) - dLWNetGround_dTGround, & ! intent(out): derivative in net ground radiation w.r.t. ground temperature (W m-2 K-1) - dLWNetCanopy_dTGround, & ! intent(out): derivative in net canopy radiation w.r.t. ground temperature (W m-2 K-1) - dLWNetGround_dTCanopy, & ! intent(out): derivative in net ground radiation w.r.t. canopy temperature (W m-2 K-1) - ! output: error control - err,cmessage ) ! intent(out): error control - if(err/=0)then; message=trim(message)//trim(cmessage); return; end if - !print*, 'dLWNetCanopy_dTGround = ', dLWNetCanopy_dTGround - - - ! ******************************************************************************************************************************************************************* - ! ******************************************************************************************************************************************************************* - ! ***** TURBULENT HEAT FLUXES ************************************************************************************************************************************** - ! ******************************************************************************************************************************************************************* - ! ******************************************************************************************************************************************************************* - - ! check the need to compute numerical derivatives - if(ixDerivMethod == numerical)then - nFlux=5 ! compute the derivatives using one-sided finite differences - else - nFlux=1 ! compute analytical derivatives - end if - - ! either one or multiple flux calls, depending on if using analytical or numerical derivatives - do itry=nFlux,1,-1 ! (work backwards to ensure all computed fluxes come from the un-perturbed case) - - ! ------------------------------------------------------------------------------------- - ! state perturbations for numerical deriavtives with one-sided finite differences - ! note: no perturbations performed using analytical derivatives (nFlux=1) - ! ------------------------------------------------------------------------------------- - - ! initialize for unperturbed state - canopyWetFraction = scalarCanopyWetFraction - - ! identify the type of perturbation - select case(itry) - - ! un-perturbed case - case(unperturbed) - groundTemp = groundTempTrial - canopyTemp = canopyTempTrial - canairTemp = canairTempTrial - canopyWat = totalCanopyWater - - ! perturb ground temperature - case(perturbStateGround) - groundTemp = groundTempTrial + dx - canopyTemp = canopyTempTrial - canairTemp = canairTempTrial - canopyWat = totalCanopyWater - - ! perturb canopy temperature - case(perturbStateCanopy) - groundTemp = groundTempTrial - canopyTemp = canopyTempTrial + dx - canairTemp = canairTempTrial - canopyWat = totalCanopyWater - - ! perturb canopy air temperature - case(perturbStateCanair) - groundTemp = groundTempTrial - canopyTemp = canopyTempTrial - canairTemp = canairTempTrial + dx - canopyWat = totalCanopyWater - - ! perturb canopy total water content - case(perturbStateCanWat) - groundTemp = groundTempTrial - canopyTemp = canopyTempTrial - canairTemp = canairTempTrial - canopyWat = totalCanopyWater + dx - - ! check for an unknown perturbation - case default; err=10; message=trim(message)//"unknown perturbation"; return - - end select ! (type of perturbation) - - ! perturbations in canopy total water content affect canopy wetted fraction - if(itry == perturbStateCanopy .OR. itry == perturbStateCanWat)then - - ! recalculate liquid and ice from total water - fracLiquidCanopy = fracliquid(canopyTemp,snowfrz_scale) - canopyLiq = fracLiquidCanopy*canopyWat - canopyIce = (1._rkind - fracLiquidCanopy)*canopyWat - - if(computeVegFlux)then + + ! ensure canopy longwave fluxes are zero when not computing canopy fluxes + if(.not.computeVegFlux) scalarCanopyEmissivity=0._rkind + + ! compute emissivity of the ground surface (-) + groundEmissivity = scalarGroundSnowFraction*snowEmissivity + (1._rkind - scalarGroundSnowFraction)*soilEmissivity ! emissivity of the ground surface (-) + + ! compute the fraction of canopy that is wet + ! NOTE: we either sublimate or evaporate over the entire substep + if(computeVegFlux)then + + ! compute the fraction of liquid water in the canopy (-) + totalCanopyWater = canopyLiqTrial + canopyIceTrial + if(totalCanopyWater > tiny(1.0_rkind))then + fracLiquidCanopy = canopyLiqTrial / (canopyLiqTrial + canopyIceTrial) + else + fracLiquidCanopy = 0._rkind + end if + + ! get wetted fraction and derivatives call wettedFrac(& ! input - .false., & ! flag to denote if derivative is desired + .true., & ! flag to denote if derivative is desired (ixDerivMethod == numerical), & ! flag to denote that numerical derivatives are required (otherwise, analytical derivatives are calculated) (scalarLatHeatSubVapCanopy > LH_vap+verySmall), & ! flag to denote if the canopy is frozen dCanLiq_dTcanopy, & ! derivative in canopy liquid w.r.t. canopy temperature (kg m-2 K-1) fracLiquidCanopy, & ! fraction of liquid water on the canopy (-) - canopyLiq, & ! canopy liquid water (kg m-2) - canopyIce, & ! canopy ice (kg m-2) + canopyLiqTrial, & ! canopy liquid water (kg m-2) + canopyIceTrial, & ! canopy ice (kg m-2) scalarCanopyLiqMax, & ! maximum canopy liquid water (kg m-2) scalarCanopyIceMax, & ! maximum canopy ice content (kg m-2) canopyWettingFactor, & ! maximum wetted fraction of the canopy (-) canopyWettingExp, & ! exponent in canopy wetting function (-) ! output - canopyWetFraction, & ! canopy wetted fraction (-) - dCanopyWetFraction_dWat, & ! derivative in wetted fraction w.r.t. canopy liquid water (kg-1 m2) + scalarCanopyWetFraction, & ! canopy wetted fraction (-) + dCanopyWetFraction_dWat, & ! derivative in wetted fraction w.r.t. canopy total water (kg-1 m2) dCanopyWetFraction_dT, & ! derivative in wetted fraction w.r.t. canopy temperature (K-1) err,cmessage) if(err/=0)then; message=trim(message)//trim(cmessage); return; end if - - else - canopyWetFraction = 0._rkind - end if ! (desired computing vegetation flux) - - end if ! (re-computing wetted fraction for perturbed cases) - !print*, 'wetted fraction derivative = ', (canopyWetFraction - scalarCanopyWetFraction)/dx - !pause - - ! compute the saturation vapor pressure for vegetation temperature - ! NOTE: saturated vapor pressure derivatives don't seem that accurate.... - TV_celcius = canopyTemp - Tfreeze - call satVapPress(TV_celcius, scalarSatVP_CanopyTemp, dSVPCanopy_dCanopyTemp) - - ! compute the saturation vapor pressure for ground temperature - ! NOTE: saturated vapor pressure derivatives don't seem that accurate.... - TG_celcius = groundTemp - Tfreeze - call satVapPress(TG_celcius, scalarSatVP_GroundTemp, dSVPGround_dGroundTemp) - - ! ------------------------------------------------------------------------------------- - ! calculation block (unperturbed fluxes returned [computed last]) - ! ------------------------------------------------------------------------------------- - - ! re-compute aerodynamic resistances for perturbed cases - ! NOTE: unperturbed fluxes computed earlier, and not over-written - if(itry /= unperturbed)then - call aeroResist(& - ! input: model control - computeVegFlux, & ! intent(in): logical flag to compute vegetation fluxes (.false. if veg buried by snow) - .false., & ! intent(in): logical flag if would like to compute analytical derivaties - ix_veg_traits, & ! intent(in): choice of parameterization for vegetation roughness length and displacement height - ix_windPrfile, & ! intent(in): choice of canopy wind profile - ix_astability, & ! intent(in): choice of stability function - ! input: above-canopy forcing data - mHeight, & ! intent(in): measurement height (m) - airtemp, & ! intent(in): air temperature at some height above the surface (K) - windspd, & ! intent(in): wind speed at some height above the surface (m s-1) - ! input: temperature (canopy, ground, canopy air space) - canairTemp, & ! intent(in): temperature of the canopy air space (K) - groundTemp, & ! intent(in): ground temperature (K) - ! input: diagnostic variables - exposedVAI, & ! intent(in): exposed vegetation area index -- leaf plus stem (m2 m-2) - scalarSnowDepth, & ! intent(in): snow depth (m) - ! input: parameters - z0Ground, & ! intent(in): roughness length of the ground (below canopy or non-vegetated surface [snow]) (m) - z0CanopyParam, & ! intent(in): roughness length of the canopy (m) - zpdFraction, & ! intent(in): zero plane displacement / canopy height (-) - critRichNumber, & ! intent(in): critical value for the bulk Richardson number where turbulence ceases (-) - Louis79_bparam, & ! intent(in): parameter in Louis (1979) stability function - Mahrt87_eScale, & ! intent(in): exponential scaling factor in the Mahrt (1987) stability function - windReductionParam, & ! intent(in): canopy wind reduction parameter (-) - leafExchangeCoeff, & ! intent(in): turbulent exchange coeff between canopy surface and canopy air ( m s-(1/2) ) - leafDimension, & ! intent(in): characteristic leaf dimension (m) - heightCanopyTop, & ! intent(in): height at the top of the vegetation canopy (m) - heightCanopyBottom, & ! intent(in): height at the bottom of the vegetation canopy (m) - ! output: stability corrections - notUsed_RiBulkCanopy, & ! intent(out): bulk Richardson number for the canopy (-) - notUsed_RiBulkGround, & ! intent(out): bulk Richardson number for the ground surface (-) - notUsed_scalarCanopyStabilityCorrection, & ! intent(out): stability correction for the canopy (-) - notUsed_scalarGroundStabilityCorrection, & ! intent(out): stability correction for the ground surface (-) - ! output: scalar resistances - notUsed_z0Canopy, & ! intent(out): roughness length of the canopy (m) - notUsed_WindReductionFactor, & ! intent(out): canopy wind reduction factor (-) - notUsed_ZeroPlaneDisplacement, & ! intent(out): zero plane displacement (m) - notUsed_EddyDiffusCanopyTop, & ! intent(out): eddy diffusivity for heat at the top of the canopy (m2 s-1) - notUsed_FrictionVelocity, & ! intent(out): friction velocity (m s-1) - notUsed_WindspdCanopyTop, & ! intent(out): windspeed at the top of the canopy (m s-1) - notUsed_WindspdCanopyBottom, & ! intent(out): windspeed at the height of the bottom of the canopy (m s-1) - trialLeafResistance, & ! intent(out): mean leaf boundary layer resistance per unit leaf area (s m-1) - trialGroundResistance, & ! intent(out): below canopy aerodynamic resistance (s m-1) - trialCanopyResistance, & ! intent(out): above canopy aerodynamic resistance (s m-1) - ! output: derivatives in scalar resistances - notUsed_dGroundResistance_dTGround, & ! intent(out): derivative in ground resistance w.r.t. ground temperature (s m-1 K-1) - notUsed_dGroundResistance_dTCanopy, & ! intent(out): derivative in ground resistance w.r.t. canopy temperature (s m-1 K-1) - notUsed_dGroundResistance_dTCanair, & ! intent(out): derivative in ground resistance w.r.t. canopy air temperature (s m-1 K-1) - notUsed_dCanopyResistance_dTCanopy, & ! intent(out): derivative in canopy resistance w.r.t. canopy temperature (s m-1 K-1) - notUsed_dCanopyResistance_dTCanair, & ! intent(out): derivative in canopy resistance w.r.t. canopy air temperature (s m-1 K-1) - ! output: error control - err,cmessage ) ! intent(out): error control - if(err/=0)then; message=trim(message)//trim(cmessage); return; end if - - - ! assign scalar resistances for un-perturbed cases + else - trialLeafResistance = scalarLeafResistance - trialGroundResistance = scalarGroundResistance - trialCanopyResistance = scalarCanopyResistance - - end if ! (re-computing resistances for perturbed cases) - !print*, 'trialLeafResistance = ', trialLeafResistance - !print*, 'trialGroundResistance = ', trialGroundResistance - !print*, 'trialCanopyResistance = ', trialCanopyResistance - - ! compute the relative humidity in the top soil layer and the resistance at the ground surface - ! NOTE: computations are based on start-of-step values, so only compute for the first flux call - if(firstFluxCall)then - ! (soil water evaporation factor [0-1]) - soilEvapFactor = mLayerVolFracLiq(nSnow+1)/(theta_sat - theta_res) - ! (resistance from the soil [s m-1]) - scalarSoilResistance = scalarGroundSnowFraction*1._rkind + (1._rkind - scalarGroundSnowFraction)*EXP(8.25_rkind - 4.225_rkind*soilEvapFactor) ! Sellers (1992) - !scalarSoilResistance = scalarGroundSnowFraction*0._rkind + (1._rkind - scalarGroundSnowFraction)*exp(8.25_rkind - 6.0_rkind*soilEvapFactor) ! Niu adjustment to decrease resitance for wet soil - ! (relative humidity in the soil pores [0-1]) - if(mLayerMatricHead(1) > -1.e+6_rkind)then ! avoid problems with numerical precision when soil is very dry - soilRelHumidity_noSnow = exp( (mLayerMatricHead(1)*gravity) / (groundTemp*R_wv) ) - else - soilRelHumidity_noSnow = 0._rkind - end if ! (if matric head is very low) - scalarSoilRelHumidity = scalarGroundSnowFraction*1._rkind + (1._rkind - scalarGroundSnowFraction)*soilRelHumidity_noSnow - !print*, 'mLayerMatricHead(1), scalarSoilRelHumidity = ', mLayerMatricHead(1), scalarSoilRelHumidity - end if ! (if the first flux call) - - ! compute turbulent heat fluxes - call turbFluxes(& + scalarCanopyWetFraction = 0._rkind ! canopy wetted fraction (-) + dCanopyWetFraction_dWat = 0._rkind ! derivative in wetted fraction w.r.t. canopy total water (kg-1 m2) + dCanopyWetFraction_dT = 0._rkind ! derivative in wetted fraction w.r.t. canopy temperature (K-1) + end if + + ! ******************************************************************************************************************************************************************* + ! ******************************************************************************************************************************************************************* + ! ***** AERODYNAMIC RESISTANCE ***************************************************************************************************************************************** + ! ******************************************************************************************************************************************************************* + ! ******************************************************************************************************************************************************************* + + ! NOTE: compute for all iterations + + ! compute aerodynamic resistances + ! Refs: Choudhury and Monteith (4-layer model for heat budget of homogenous surfaces; QJRMS, 1988) + ! Niu and Yang (Canopy effects on snow processes; JGR, 2004) + ! Mahat et al. (Below-canopy turbulence in a snowmelt model, WRR, 2012) + call aeroResist(& ! input: model control - computeVegFlux, & ! intent(in): logical flag to compute vegetation fluxes (.false. if veg buried by snow) - ixDerivMethod, & ! intent(in): method used to calculate flux derivatives + computeVegFlux, & ! intent(in): logical flag to compute vegetation fluxes (.false. if veg buried by snow) + (ixDerivMethod == analytical), & ! intent(in): logical flag if would like to compute analytical derivaties + ix_veg_traits, & ! intent(in): choice of parameterization for vegetation roughness length and displacement height + ix_windPrfile, & ! intent(in): choice of canopy wind profile + ix_astability, & ! intent(in): choice of stability function ! input: above-canopy forcing data - airtemp, & ! intent(in): air temperature at some height above the surface (K) - airpres, & ! intent(in): air pressure of the air above the vegetation canopy (Pa) - scalarVPair, & ! intent(in): vapor pressure of the air above the vegetation canopy (Pa) - ! input: latent heat of sublimation/vaporization - scalarLatHeatSubVapCanopy, & ! intent(in): latent heat of sublimation/vaporization for the vegetation canopy (J kg-1) - scalarLatHeatSubVapGround, & ! intent(in): latent heat of sublimation/vaporization for the ground surface (J kg-1) - ! input: canopy/ground temperature and saturated vapor pressure - canairTemp, & ! intent(in): temperature of the canopy air space (K) - canopyTemp, & ! intent(in): canopy temperature (K) - groundTemp, & ! intent(in): ground temperature (K) - scalarSatVP_CanopyTemp, & ! intent(in): saturation vapor pressure at the temperature of the veg canopy (Pa) - scalarSatVP_GroundTemp, & ! intent(in): saturation vapor pressure at the temperature of the ground (Pa) - dSVPCanopy_dCanopyTemp, & ! intent(in): derivative in canopy saturation vapor pressure w.r.t. canopy temperature (Pa K-1) - dSVPGround_dGroundTemp, & ! intent(in): derivative in ground saturation vapor pressure w.r.t. ground temperature (Pa K-1) + mHeight, & ! intent(in): measurement height (m) + airtemp, & ! intent(in): air temperature at some height above the surface (K) + windspd, & ! intent(in): wind speed at some height above the surface (m s-1) + ! input: canopy and ground temperature + canairTempTrial, & ! intent(in): temperature of the canopy air space (K) + groundTempTrial, & ! intent(in): temperature of the ground surface (K) ! input: diagnostic variables - exposedVAI, & ! intent(in): exposed vegetation area index -- leaf plus stem (m2 m-2) - canopyWetFraction, & ! intent(in): trial value for the fraction of canopy that is wet [0-1] - dCanopyWetFraction_dWat, & ! intent(in): derivative in the canopy wetted fraction w.r.t. total water content (kg-1 m-2) - dCanopyWetFraction_dT, & ! intent(in): derivative in wetted fraction w.r.t. canopy temperature (K-1) - scalarCanopySunlitLAI, & ! intent(in): sunlit leaf area (-) - scalarCanopyShadedLAI, & ! intent(in): shaded leaf area (-) - scalarSoilRelHumidity, & ! intent(in): relative humidity in the soil pores [0-1] - scalarSoilResistance, & ! intent(in): resistance from the soil (s m-1) - trialLeafResistance, & ! intent(in): mean leaf boundary layer resistance per unit leaf area (s m-1) - trialGroundResistance, & ! intent(in): below canopy aerodynamic resistance (s m-1) - trialCanopyResistance, & ! intent(in): above canopy aerodynamic resistance (s m-1) - scalarStomResistSunlit, & ! intent(in): stomatal resistance for sunlit leaves (s m-1) - scalarStomResistShaded, & ! intent(in): stomatal resistance for shaded leaves (s m-1) - ! input: derivatives in scalar resistances - dGroundResistance_dTGround, & ! intent(in): derivative in ground resistance w.r.t. ground temperature (s m-1 K-1) - dGroundResistance_dTCanopy, & ! intent(in): derivative in ground resistance w.r.t. canopy temperature (s m-1 K-1) - dGroundResistance_dTCanair, & ! intent(in): derivative in ground resistance w.r.t. canopy air temperature (s m-1 K-1) - dCanopyResistance_dTCanopy, & ! intent(in): derivative in canopy resistance w.r.t. canopy temperature (s m-1 K-1) - dCanopyResistance_dTCanair, & ! intent(in): derivative in canopy resistance w.r.t. canopy air temperature (s m-1 K-1) - ! output: conductances (used to check derivative calculations) - scalarLeafConductance, & ! intent(out): leaf conductance (m s-1) - scalarCanopyConductance, & ! intent(out): canopy conductance (m s-1) - scalarGroundConductanceSH, & ! intent(out): ground conductance for sensible heat (m s-1) - scalarGroundConductanceLH, & ! intent(out): ground conductance for latent heat -- includes soil resistance (m s-1) - scalarEvapConductance, & ! intent(out): conductance for evaporation (m s-1) - scalarTransConductance, & ! intent(out): conductance for transpiration (m s-1) - scalarTotalConductanceSH, & ! intent(out): total conductance for sensible heat (m s-1) - scalarTotalConductanceLH, & ! intent(out): total conductance for latent heat (m s-1) - ! output: canopy air space variables - scalarVP_CanopyAir, & ! intent(out): vapor pressure of the canopy air space (Pa) - ! output: fluxes from the vegetation canopy - scalarSenHeatCanopy, & ! intent(out): sensible heat flux from the canopy to the canopy air space (W m-2) - scalarLatHeatCanopyEvap, & ! intent(out): latent heat flux associated with evaporation from the canopy to the canopy air space (W m-2) - scalarLatHeatCanopyTrans, & ! intent(out): latent heat flux associated with transpiration from the canopy to the canopy air space (W m-2) - ! output: fluxes from non-vegetated surfaces (ground surface below vegetation, bare ground, or snow covered vegetation) - scalarSenHeatGround, & ! intent(out): sensible heat flux from ground surface below vegetation, bare ground, or snow covered vegetation (W m-2) - scalarLatHeatGround, & ! intent(out): latent heat flux from ground surface below vegetation, bare ground, or snow covered vegetation (W m-2) - ! output: total heat fluxes to the atmosphere - scalarSenHeatTotal, & ! intent(out): total sensible heat flux to the atmosphere (W m-2) - scalarLatHeatTotal, & ! intent(out): total latent heat flux to the atmosphere (W m-2) - ! output: net fluxes - turbFluxCanair, & ! intent(out): net turbulent heat fluxes at the canopy air space (W m-2) - turbFluxCanopy, & ! intent(out): net turbulent heat fluxes at the canopy (W m-2) - turbFluxGround, & ! intent(out): net turbulent heat fluxes at the ground surface (W m-2) - ! output: energy flux derivatives - dTurbFluxCanair_dTCanair, & ! intent(out): derivative in net canopy air space fluxes w.r.t. canopy air temperature (W m-2 K-1) - dTurbFluxCanair_dTCanopy, & ! intent(out): derivative in net canopy air space fluxes w.r.t. canopy temperature (W m-2 K-1) - dTurbFluxCanair_dTGround, & ! intent(out): derivative in net canopy air space fluxes w.r.t. ground temperature (W m-2 K-1) - dTurbFluxCanopy_dTCanair, & ! intent(out): derivative in net canopy turbulent fluxes w.r.t. canopy air temperature (W m-2 K-1) - dTurbFluxCanopy_dTCanopy, & ! intent(out): derivative in net canopy turbulent fluxes w.r.t. canopy temperature (W m-2 K-1) - dTurbFluxCanopy_dTGround, & ! intent(out): derivative in net canopy turbulent fluxes w.r.t. ground temperature (W m-2 K-1) - dTurbFluxGround_dTCanair, & ! intent(out): derivative in net ground turbulent fluxes w.r.t. canopy air temperature (W m-2 K-1) - dTurbFluxGround_dTCanopy, & ! intent(out): derivative in net ground turbulent fluxes w.r.t. canopy temperature (W m-2 K-1) - dTurbFluxGround_dTGround, & ! intent(out): derivative in net ground turbulent fluxes w.r.t. ground temperature (W m-2 K-1) - ! output: liquid flux derivatives (canopy evap) - dLatHeatCanopyEvap_dCanWat, & ! intent(out): derivative in latent heat of canopy evaporation w.r.t. canopy total water content (W kg-1) - dLatHeatCanopyEvap_dTCanair, & ! intent(out): derivative in latent heat of canopy evaporation w.r.t. canopy air temperature (W m-2 K-1) - dLatHeatCanopyEvap_dTCanopy, & ! intent(out): derivative in latent heat of canopy evaporation w.r.t. canopy temperature (W m-2 K-1) - dLatHeatCanopyEvap_dTGround, & ! intent(out): derivative in latent heat of canopy evaporation w.r.t. ground temperature (W m-2 K-1) - ! output: liquid flux derivatives (ground evap) - dLatHeatGroundEvap_dCanWat, & ! intent(out): derivative in latent heat of ground evaporation w.r.t. canopy total water content (J kg-1 s-1) - dLatHeatGroundEvap_dTCanair, & ! intent(out): derivative in latent heat of ground evaporation w.r.t. canopy air temperature - dLatHeatGroundEvap_dTCanopy, & ! intent(out): derivative in latent heat of ground evaporation w.r.t. canopy temperature - dLatHeatGroundEvap_dTGround, & ! intent(out): derivative in latent heat of ground evaporation w.r.t. ground temperature - ! output: latent heat flux derivatives (canopy trans) - dLatHeatCanopyTrans_dCanWat, & ! intent(out): derivative in the latent heat of canopy transpiration w.r.t. canopy total water (J kg-1 s-1) - dLatHeatCanopyTrans_dTCanair, & ! intent(out): derivative in the latent heat of canopy transpiration w.r.t. canopy air temperature - dLatHeatCanopyTrans_dTCanopy, & ! intent(out): derivative in the latent heat of canopy transpiration w.r.t. canopy temperature - dLatHeatCanopyTrans_dTGround, & ! intent(out): derivative in the latent heat of canopy transpiration w.r.t. ground temperature - ! output: cross derivatives - dTurbFluxCanair_dCanWat, & ! intent(out): derivative in net canopy air space fluxes w.r.t. canopy total water content (J kg-1 s-1) - dTurbFluxCanopy_dCanWat, & ! intent(out): derivative in net canopy turbulent fluxes w.r.t. canopy total water content (J kg-1 s-1) - dTurbFluxGround_dCanWat, & ! intent(out): derivative in net ground turbulent fluxes w.r.t. canopy total water content (J kg-1 s-1) + exposedVAI, & ! intent(in): exposed vegetation area index -- leaf plus stem (m2 m-2) + scalarSnowDepth, & ! intent(in): snow depth (m) + ! input: parameters + z0Ground, & ! intent(in): roughness length of the ground (below canopy or non-vegetated surface [snow]) (m) + z0CanopyParam, & ! intent(in): roughness length of the canopy (m) + zpdFraction, & ! intent(in): zero plane displacement / canopy height (-) + critRichNumber, & ! intent(in): critical value for the bulk Richardson number where turbulence ceases (-) + Louis79_bparam, & ! intent(in): parameter in Louis (1979) stability function + Mahrt87_eScale, & ! intent(in): exponential scaling factor in the Mahrt (1987) stability function + windReductionParam, & ! intent(in): canopy wind reduction parameter (-) + leafExchangeCoeff, & ! intent(in): turbulent exchange coeff between canopy surface and canopy air ( m s-(1/2) ) + leafDimension, & ! intent(in): characteristic leaf dimension (m) + heightCanopyTop, & ! intent(in): height at the top of the vegetation canopy (m) + heightCanopyBottom, & ! intent(in): height at the bottom of the vegetation canopy (m) + ! output: stability corrections + scalarRiBulkCanopy, & ! intent(out): bulk Richardson number for the canopy (-) + scalarRiBulkGround, & ! intent(out): bulk Richardson number for the ground surface (-) + scalarCanopyStabilityCorrection, & ! intent(out): stability correction for the canopy (-) + scalarGroundStabilityCorrection, & ! intent(out): stability correction for the ground surface (-) + ! output: scalar resistances + scalarZ0Canopy, & ! intent(out): roughness length of the canopy (m) + scalarWindReductionFactor, & ! intent(out): canopy wind reduction factor (-) + scalarZeroPlaneDisplacement, & ! intent(out): zero plane displacement (m) + scalarEddyDiffusCanopyTop, & ! intent(out): eddy diffusivity for heat at the top of the canopy (m2 s-1) + scalarFrictionVelocity, & ! intent(out): friction velocity (m s-1) + scalarWindspdCanopyTop, & ! intent(out): windspeed at the top of the canopy (m s-1) + scalarWindspdCanopyBottom, & ! intent(out): windspeed at the height of the bottom of the canopy (m s-1) + scalarLeafResistance, & ! intent(out): mean leaf boundary layer resistance per unit leaf area (s m-1) + scalarGroundResistance, & ! intent(out): below canopy aerodynamic resistance (s m-1) + scalarCanopyResistance, & ! intent(out): above canopy aerodynamic resistance (s m-1) + ! output: derivatives in scalar resistances + dGroundResistance_dTGround, & ! intent(out): derivative in ground resistance w.r.t. ground temperature (s m-1 K-1) + dGroundResistance_dTCanopy, & ! intent(out): derivative in ground resistance w.r.t. canopy temperature (s m-1 K-1) + dGroundResistance_dTCanair, & ! intent(out): derivative in ground resistance w.r.t. canopy air temperature (s m-1 K-1) + dCanopyResistance_dTCanopy, & ! intent(out): derivative in canopy resistance w.r.t. canopy temperature (s m-1 K-1) + dCanopyResistance_dTCanair, & ! intent(out): derivative in canopy resistance w.r.t. canopy air temperature (s m-1 K-1) ! output: error control - err,cmessage ) ! intent(out): error control + err,cmessage ) ! intent(out): error control if(err/=0)then; message=trim(message)//trim(cmessage); return; end if - - !write(*,'(a,f25.15)') 'scalarSenHeatTotal = ', scalarSenHeatTotal - !write(*,'(a,f25.15)') 'scalarSenHeatCanopy = ', scalarSenHeatCanopy - !write(*,'(a,f25.15)') 'scalarLatHeatCanopyEvap = ', scalarLatHeatCanopyEvap - !write(*,'(a,f25.15)') 'scalarLatHeatCanopyTrans = ', scalarLatHeatCanopyTrans - - !print*, 'scalarSenHeatGround = ', scalarSenHeatGround - !print*, 'scalarLatHeatGround = ', scalarLatHeatGround - - !notUsed_scalarCanopyStabilityCorrection ! stability correction for the canopy (-) - !notUsed_scalarGroundStabilityCorrection ! stability correction for the ground surface (-) - !notUsed_EddyDiffusCanopyTop ! eddy diffusivity for heat at the top of the canopy (m2 s-1) - !notUsed_FrictionVelocity ! friction velocity (m s-1) - !notUsed_WindspdCanopyTop ! windspeed at the top of the canopy (m s-1) - !notUsed_WindspdCanopyBottom ! windspeed at the height of the bottom of the canopy (m s-1) - !trialLeafResistance ! mean leaf boundary layer resistance per unit leaf area (s m-1) - !trialGroundResistance ! below canopy aerodynamic resistance (s m-1) - !trialCanopyResistance ! above canopy aerodynamic resistance (s m-1) - - ! save perturbed fluxes + + ! ******************************************************************************************************************************************************************* + ! ******************************************************************************************************************************************************************* + ! ***** STOMATAL RESISTANCE ***************************************************************************************************************************************** + ! ******************************************************************************************************************************************************************* + ! ******************************************************************************************************************************************************************* + + ! stomatal resistance is constant over the SUBSTEP + ! NOTE: This is a simplification, as stomatal resistance does depend on canopy temperature + ! This "short-cut" made because: + ! (1) computations are expensive; + ! (2) derivative calculations are rather complex (iterations within the Ball-Berry routine); and + ! (3) stomatal resistance does not change rapidly + if(firstFluxCall)then + + ! compute the saturation vapor pressure for vegetation temperature + TV_celcius = canopyTempTrial - Tfreeze + call satVapPress(TV_celcius, scalarSatVP_CanopyTemp, dSVPCanopy_dCanopyTemp) + + ! compute soil moisture factor controlling stomatal resistance + call soilResist(& + ! input (model decisions) + ix_soilStress, & ! intent(in): choice of function for the soil moisture control on stomatal resistance + ix_groundwatr, & ! intent(in): groundwater parameterization + ! input (state variables) + mLayerMatricHead(1:nSoil), & ! intent(in): matric head in each soil layer (m) + mLayerVolFracLiq(nSnow+1:nLayers), & ! intent(in): volumetric fraction of liquid water in each soil layer (-) + scalarAquiferStorage, & ! intent(in): aquifer storage (m) + ! input (diagnostic variables) + mLayerRootDensity(1:nSoil), & ! intent(in): root density in each layer (-) + scalarAquiferRootFrac, & ! intent(in): fraction of roots below the lowest soil layer (-) + ! input (parameters) + plantWiltPsi, & ! intent(in): matric head at wilting point (m) + soilStressParam, & ! intent(in): parameter in the exponential soil stress function (-) + critSoilWilting, & ! intent(in): critical vol. liq. water content when plants are wilting (-) + critSoilTranspire, & ! intent(in): critical vol. liq. water content when transpiration is limited (-) + critAquiferTranspire, & ! intent(in): critical aquifer storage value when transpiration is limited (m) + ! output + scalarTranspireLim, & ! intent(out): weighted average of the transpiration limiting factor (-) + mLayerTranspireLim(1:nSoil), & ! intent(out): transpiration limiting factor in each layer (-) + scalarTranspireLimAqfr, & ! intent(out): transpiration limiting factor for the aquifer (-) + err,cmessage ) ! intent(out): error control + if(err/=0)then; message=trim(message)//trim(cmessage); return; end if + + ! compute stomatal resistance + call stomResist(& + ! input (state and diagnostic variables) + canopyTempTrial, & ! intent(in): temperature of the vegetation canopy (K) + scalarSatVP_CanopyTemp, & ! intent(in): saturation vapor pressure at the temperature of the veg canopy (Pa) + scalarVP_CanopyAir, & ! intent(in): canopy air vapor pressure (Pa) + ! input: data structures + type_data, & ! intent(in): type of vegetation and soil + forc_data, & ! intent(in): model forcing data + mpar_data, & ! intent(in): model parameters + model_decisions, & ! intent(in): model decisions + ! input-output: data structures + diag_data, & ! intent(inout): model diagnostic variables for a local HRU + flux_data, & ! intent(inout): model fluxes for a local HRU + ! output: error control + err,cmessage ) ! intent(out): error control + if(err/=0)then; message=trim(message)//trim(cmessage); return; end if + + end if ! (if the first flux call in a given sub-step) + + + ! ******************************************************************************************************************************************************************* + ! ******************************************************************************************************************************************************************* + ! ***** LONGWAVE RADIATION ***************************************************************************************************************************************** + ! ******************************************************************************************************************************************************************* + ! ******************************************************************************************************************************************************************* + + ! compute canopy longwave radiation balance + call longwaveBal(& + ! input: model control + ixDerivMethod, & ! intent(in): method used to calculate flux derivatives + computeVegFlux, & ! intent(in): flag to compute fluxes over vegetation + insideIDA, & ! intent(in): flag to indicate inside Sundials Solver (do not require longwave to be balanced) + ! input: canopy and ground temperature + canopyTempTrial, & ! intent(in): temperature of the vegetation canopy (K) + groundTempTrial, & ! intent(in): temperature of the ground surface (K) + ! input: canopy and ground emissivity + scalarCanopyEmissivity, & ! intent(in): canopy emissivity (-) + groundEmissivity, & ! intent(in): ground emissivity (-) + ! input: forcing + LWRadAtm, & ! intent(in): downwelling longwave radiation at the upper boundary (W m-2) + ! output: emitted radiation from the canopy and ground + scalarLWRadCanopy, & ! intent(out): longwave radiation emitted from the canopy (W m-2) + scalarLWRadGround, & ! intent(out): longwave radiation emitted at the ground surface (W m-2) + ! output: individual fluxes + scalarLWRadUbound2Canopy, & ! intent(out): downward atmospheric longwave radiation absorbed by the canopy (W m-2) + scalarLWRadUbound2Ground, & ! intent(out): downward atmospheric longwave radiation absorbed by the ground (W m-2) + scalarLWRadUbound2Ubound, & ! intent(out): atmospheric radiation reflected by the ground and lost thru upper boundary (W m-2) + scalarLWRadCanopy2Ubound, & ! intent(out): longwave radiation emitted from canopy lost thru upper boundary (W m-2) + scalarLWRadCanopy2Ground, & ! intent(out): longwave radiation emitted from canopy absorbed by the ground (W m-2) + scalarLWRadCanopy2Canopy, & ! intent(out): canopy longwave reflected from ground and absorbed by the canopy (W m-2) + scalarLWRadGround2Ubound, & ! intent(out): longwave radiation emitted from ground lost thru upper boundary (W m-2) + scalarLWRadGround2Canopy, & ! intent(out): longwave radiation emitted from ground and absorbed by the canopy (W m-2) + ! output: net fluxes + scalarLWNetCanopy, & ! intent(out): net longwave radiation at the canopy (W m-2) + scalarLWNetGround, & ! intent(out): net longwave radiation at the ground surface (W m-2) + scalarLWNetUbound, & ! intent(out): net longwave radiation at the upper boundary (W m-2) + ! output: flux derivatives + dLWNetCanopy_dTCanopy, & ! intent(out): derivative in net canopy radiation w.r.t. canopy temperature (W m-2 K-1) + dLWNetGround_dTGround, & ! intent(out): derivative in net ground radiation w.r.t. ground temperature (W m-2 K-1) + dLWNetCanopy_dTGround, & ! intent(out): derivative in net canopy radiation w.r.t. ground temperature (W m-2 K-1) + dLWNetGround_dTCanopy, & ! intent(out): derivative in net ground radiation w.r.t. canopy temperature (W m-2 K-1) + ! output: error control + err,cmessage ) ! intent(out): error control + if(err/=0)then; message=trim(message)//trim(cmessage); return; end if + + + ! ******************************************************************************************************************************************************************* + ! ******************************************************************************************************************************************************************* + ! ***** TURBULENT HEAT FLUXES ************************************************************************************************************************************** + ! ******************************************************************************************************************************************************************* + ! ******************************************************************************************************************************************************************* + + ! check the need to compute numerical derivatives if(ixDerivMethod == numerical)then - select case(itry) ! (select type of perturbation) - case(unperturbed) - try0 = turbFluxGround - exit - case(perturbStateCanair) - turbFluxCanair_dStateCanair = turbFluxCanair ! turbulent exchange from the canopy air space to the atmosphere (W m-2) - turbFluxCanopy_dStateCanair = turbFluxCanopy ! total turbulent heat fluxes from the canopy to the canopy air space (W m-2) - turbFluxGround_dStateCanair = turbFluxGround ! total turbulent heat fluxes from the ground to the canopy air space (W m-2) - latHeatCanEvap_dStateCanair = scalarLatHeatCanopyEvap ! perturbed value for the latent heat associated with canopy evaporation (W m-2) - case(perturbStateCanopy) - turbFluxCanair_dStateCanopy = turbFluxCanair ! turbulent exchange from the canopy air space to the atmosphere (W m-2) - turbFluxCanopy_dStateCanopy = turbFluxCanopy ! total turbulent heat fluxes from the canopy to the canopy air space (W m-2) - turbFluxGround_dStateCanopy = turbFluxGround ! total turbulent heat fluxes from the ground to the canopy air space (W m-2) - latHeatCanEvap_dStateCanopy = scalarLatHeatCanopyEvap ! perturbed value for the latent heat associated with canopy evaporation (W m-2) - case(perturbStateGround) - try1 = turbFluxGround - turbFluxCanair_dStateGround = turbFluxCanair ! turbulent exchange from the canopy air space to the atmosphere (W m-2) - turbFluxCanopy_dStateGround = turbFluxCanopy ! total turbulent heat fluxes from the canopy to the canopy air space (W m-2) - turbFluxGround_dStateGround = turbFluxGround ! total turbulent heat fluxes from the ground to the canopy air space (W m-2) - latHeatCanEvap_dStateGround = scalarLatHeatCanopyEvap ! perturbed value for the latent heat associated with canopy evaporation (W m-2) - case(perturbStateCanWat) - turbFluxCanair_dStateCanWat = turbFluxCanair ! turbulent exchange from the canopy air space to the atmosphere (W m-2) - turbFluxCanopy_dStateCanWat = turbFluxCanopy ! total turbulent heat fluxes from the canopy to the canopy air space (W m-2) - turbFluxGround_dStateCanWat = turbFluxGround ! total turbulent heat fluxes from the ground to the canopy air space (W m-2) - latHeatCanEvap_dStateCanWat = scalarLatHeatCanopyEvap ! perturbed value for the latent heat associated with canopy evaporation (W m-2) - case default; err=10; message=trim(message)//"unknown perturbation"; return - end select ! (type of perturbation) - end if ! (if numerical) - - end do ! (looping through different flux perturbations) - - ! test derivative - !if(ixDerivMethod == numerical) print*, 'try0, try1 = ', try0, try1 - !if(ixDerivMethod == numerical) print*, 'derivative = ', (ixDerivMethod == numerical), (try1 - try0)/dx - !if(ixDerivMethod == analytical) print*, 'derivative = ', (ixDerivMethod == numerical), dTurbFluxGround_dTGround - !pause - - ! compute numerical derivatives - if(ixDerivMethod == numerical)then - ! derivatives w.r.t. canopy air temperature - dTurbFluxCanair_dTCanair = (turbFluxCanair_dStateCanair - turbFluxCanair) / dx ! derivative in net canopy air space fluxes w.r.t. canopy air temperature (W m-2 K-1) - dTurbFluxCanopy_dTCanair = (turbFluxCanopy_dStateCanair - turbFluxCanopy) / dx ! derivative in net canopy turbulent fluxes w.r.t. canopy air temperature (W m-2 K-1) - dTurbFluxGround_dTCanair = (turbFluxGround_dStateCanair - turbFluxGround) / dx ! derivative in net ground turbulent fluxes w.r.t. canopy air temperature (W m-2 K-1) - dLatHeatCanopyEvap_dTCanair = (latHeatCanEvap_dStateCanair - scalarLatHeatCanopyEvap) / dx ! derivative in latent heat of canopy evaporation w.r.t. canopy air temperature (W m-2 K-1) - ! derivatives w.r.t. canopy temperature - dTurbFluxCanair_dTCanopy = (turbFluxCanair_dStateCanopy - turbFluxCanair) / dx ! derivative in net canopy air space fluxes w.r.t. canopy temperature (W m-2 K-1) - dTurbFluxCanopy_dTCanopy = (turbFluxCanopy_dStateCanopy - turbFluxCanopy) / dx ! derivative in net canopy turbulent fluxes w.r.t. canopy temperature (W m-2 K-1) - dTurbFluxGround_dTCanopy = (turbFluxGround_dStateCanopy - turbFluxGround) / dx ! derivative in net ground turbulent fluxes w.r.t. canopy temperature (W m-2 K-1) - dLatHeatCanopyEvap_dTCanopy = (latHeatCanEvap_dStateCanopy - scalarLatHeatCanopyEvap) / dx ! derivative in latent heat of canopy evaporation w.r.t. canopy temperature (W m-2 K-1) - ! derivatives w.r.t. ground temperature - dTurbFluxCanair_dTGround = (turbFluxCanair_dStateGround - turbFluxCanair) / dx ! derivative in net canopy air space fluxes w.r.t. ground temperature (W m-2 K-1) - dTurbFluxCanopy_dTGround = (turbFluxCanopy_dStateGround - turbFluxCanopy) / dx ! derivative in net canopy turbulent fluxes w.r.t. ground temperature (W m-2 K-1) - dTurbFluxGround_dTGround = (turbFluxGround_dStateGround - turbFluxGround) / dx ! derivative in net ground turbulent fluxes w.r.t. ground temperature (W m-2 K-1) - dLatHeatCanopyEvap_dTGround = (latHeatCanEvap_dStateGround - scalarLatHeatCanopyEvap) / dx ! derivative in latent heat of canopy evaporation w.r.t. ground temperature (W m-2 K-1) - ! derivatives w.r.t. canopy total water content - dTurbFluxCanair_dCanWat = (turbFluxCanair_dStateCanWat - turbFluxCanair) / dx ! derivative in net canopy air space fluxes w.r.t. canopy total water content (J kg-1 s-1) - dTurbFluxCanopy_dCanWat = (turbFluxCanopy_dStateCanWat - turbFluxCanopy) / dx ! derivative in net canopy turbulent fluxes w.r.t. canopy total water content (J kg-1 s-1) - dTurbFluxGround_dCanWat = (turbFluxGround_dStateCanWat - turbFluxGround) / dx ! derivative in net ground turbulent fluxes w.r.t. canopy total water content (J kg-1 s-1) - dLatHeatCanopyEvap_dCanWat = (latHeatCanEvap_dStateCanWat - scalarLatHeatCanopyEvap) / dx ! derivative in latent heat of canopy evaporation w.r.t. canopy total water content (J kg-1 s-1) - end if - !if(heightCanopyBottom < scalarSnowDepth+z0Ground) pause 'bottom of the canopy is covered' - - ! test - !print*, (ixDerivMethod == numerical) - !print*, 'dTurbFluxCanair_dTCanair = ', dTurbFluxCanair_dTCanair - !print*, 'dTurbFluxCanair_dTCanopy = ', dTurbFluxCanair_dTCanopy - !print*, 'dTurbFluxCanair_dTGround = ', dTurbFluxCanair_dTGround - !print*, 'dTurbFluxCanopy_dTCanair = ', dTurbFluxCanopy_dTCanair - !print*, 'dTurbFluxCanopy_dTCanopy = ', dTurbFluxCanopy_dTCanopy - !print*, 'dTurbFluxCanopy_dTGround = ', dTurbFluxCanopy_dTGround - !print*, 'dTurbFluxGround_dTCanair = ', dTurbFluxGround_dTCanair - !print*, 'dTurbFluxGround_dTCanopy = ', dTurbFluxGround_dTCanopy - !print*, 'dTurbFluxGround_dTGround = ', dTurbFluxGround_dTGround - !print*, 'dLatHeatCanopyEvap_dCanWat = ', dLatHeatCanopyEvap_dCanWat - !print*, 'dLatHeatCanopyEvap_dTCanair = ', dLatHeatCanopyEvap_dTCanair - !print*, 'dLatHeatCanopyEvap_dTCanopy = ', dLatHeatCanopyEvap_dTCanopy - !print*, 'dLatHeatCanopyEvap_dTGround = ', dLatHeatCanopyEvap_dTGround - !print*, 'dTurbFluxCanair_dCanWat = ', dTurbFluxCanair_dCanWat - !print*, 'dTurbFluxCanopy_dCanWat = ', dTurbFluxCanopy_dCanWat - !print*, 'dTurbFluxGround_dCanWat = ', dTurbFluxGround_dCanWat - !print*, '*****' - !pause - - !print*, 'scalarRainfall, scalarThroughfallRain, scalarSnowfall, scalarThroughfallSnow, canopyTempTrial, scalarTwetbulb = ', & - ! scalarRainfall, scalarThroughfallRain, scalarSnowfall, scalarThroughfallSnow, canopyTempTrial, scalarTwetbulb - - ! compute the heat advected with precipitation (W m-2) - ! NOTE: fluxes are in kg m-2 s-1, so no need to use density of water/ice here - scalarCanopyAdvectiveHeatFlux = -Cp_water*(scalarRainfall - scalarThroughfallRain)*(canopyTempTrial - scalarTwetbulb) + & - (-Cp_ice)*(scalarSnowfall - scalarThroughfallSnow)*(canopyTempTrial - scalarTwetbulb) - scalarGroundAdvectiveHeatFlux = -Cp_water*scalarThroughfallRain*(groundTempTrial - scalarTwetbulb) + & - (-Cp_ice)*scalarThroughfallSnow*(groundTempTrial - scalarTwetbulb) !+ & - ! (-Cp_water)*scalarCanopyLiqDrainage *(groundTempTrial - canopyTempTrial) + & - ! (-Cp_ice) *scalarCanopySnowUnloading*(groundTempTrial - canopyTempTrial) - !print*, 'scalarRainfall, scalarThroughfallRain, scalarSnowfall, scalarThroughfallSnow = ', scalarRainfall, scalarThroughfallRain, scalarSnowfall, scalarThroughfallSnow - !print*, 'scalarCanopyAdvectiveHeatFlux, scalarGroundAdvectiveHeatFlux = ', scalarCanopyAdvectiveHeatFlux, scalarGroundAdvectiveHeatFlux - - ! compute the mass flux associated with transpiration and evaporation/sublimation (J m-2 s-1 --> kg m-2 s-1) - ! NOTE: remove water from the snow on the ground in preference to removing water from the water in soil pores - !print*, 'scalarLatHeatCanopyTrans = ', scalarLatHeatCanopyTrans - !print*, 'scalarLatHeatGround = ', scalarLatHeatGround - ! (canopy transpiration/sublimation) - if(scalarLatHeatSubVapCanopy > LH_vap+verySmall)then ! sublimation - scalarCanopyEvaporation = 0._rkind - scalarCanopySublimation = scalarLatHeatCanopyEvap/LH_sub - if(scalarLatHeatCanopyTrans > 0._rkind)then ! flux directed towards the veg - scalarCanopySublimation = scalarCanopySublimation + scalarLatHeatCanopyTrans/LH_sub ! frost - scalarCanopyTranspiration = 0._rkind + nFlux=5 ! compute the derivatives using one-sided finite differences else - scalarCanopyTranspiration = scalarLatHeatCanopyTrans/LH_vap ! transpiration is always vapor + nFlux=1 ! compute analytical derivatives end if - ! (canopy transpiration/evaporation) - else ! evaporation - scalarCanopyEvaporation = scalarLatHeatCanopyEvap/LH_vap - scalarCanopySublimation = 0._rkind - if(scalarLatHeatCanopyTrans > 0._rkind)then ! flux directed towards the veg - scalarCanopyEvaporation = scalarCanopyEvaporation + scalarLatHeatCanopyTrans/LH_vap - scalarCanopyTranspiration = 0._rkind + + ! either one or multiple flux calls, depending on if using analytical or numerical derivatives + do itry=nFlux,1,-1 ! (work backwards to ensure all computed fluxes come from the un-perturbed case) + + ! ------------------------------------------------------------------------------------- + ! state perturbations for numerical deriavtives with one-sided finite differences + ! note: no perturbations performed using analytical derivatives (nFlux=1) + ! ------------------------------------------------------------------------------------- + + ! initialize for unperturbed state + canopyWetFraction = scalarCanopyWetFraction + + ! identify the type of perturbation + select case(itry) + + ! un-perturbed case + case(unperturbed) + groundTemp = groundTempTrial + canopyTemp = canopyTempTrial + canairTemp = canairTempTrial + canopyWat = totalCanopyWater + + ! perturb ground temperature + case(perturbStateGround) + groundTemp = groundTempTrial + dx + canopyTemp = canopyTempTrial + canairTemp = canairTempTrial + canopyWat = totalCanopyWater + + ! perturb canopy temperature + case(perturbStateCanopy) + groundTemp = groundTempTrial + canopyTemp = canopyTempTrial + dx + canairTemp = canairTempTrial + canopyWat = totalCanopyWater + + ! perturb canopy air temperature + case(perturbStateCanair) + groundTemp = groundTempTrial + canopyTemp = canopyTempTrial + canairTemp = canairTempTrial + dx + canopyWat = totalCanopyWater + + ! perturb canopy total water content + case(perturbStateCanWat) + groundTemp = groundTempTrial + canopyTemp = canopyTempTrial + canairTemp = canairTempTrial + canopyWat = totalCanopyWater + dx + + ! check for an unknown perturbation + case default; err=10; message=trim(message)//"unknown perturbation"; return + + end select ! (type of perturbation) + + ! perturbations in canopy total water content affect canopy wetted fraction + if(itry == perturbStateCanopy .OR. itry == perturbStateCanWat)then + + ! recalculate liquid and ice from total water + fracLiquidCanopy = fracliquid(canopyTemp,snowfrz_scale) + canopyLiq = fracLiquidCanopy*canopyWat + canopyIce = (1._rkind - fracLiquidCanopy)*canopyWat + + if(computeVegFlux)then + call wettedFrac(& + ! input + .false., & ! flag to denote if derivative is desired + (ixDerivMethod == numerical), & ! flag to denote that numerical derivatives are required (otherwise, analytical derivatives are calculated) + (scalarLatHeatSubVapCanopy > LH_vap+verySmall), & ! flag to denote if the canopy is frozen + dCanLiq_dTcanopy, & ! derivative in canopy liquid w.r.t. canopy temperature (kg m-2 K-1) + fracLiquidCanopy, & ! fraction of liquid water on the canopy (-) + canopyLiq, & ! canopy liquid water (kg m-2) + canopyIce, & ! canopy ice (kg m-2) + scalarCanopyLiqMax, & ! maximum canopy liquid water (kg m-2) + scalarCanopyIceMax, & ! maximum canopy ice content (kg m-2) + canopyWettingFactor, & ! maximum wetted fraction of the canopy (-) + canopyWettingExp, & ! exponent in canopy wetting function (-) + ! output + canopyWetFraction, & ! canopy wetted fraction (-) + dCanopyWetFraction_dWat, & ! derivative in wetted fraction w.r.t. canopy liquid water (kg-1 m2) + dCanopyWetFraction_dT, & ! derivative in wetted fraction w.r.t. canopy temperature (K-1) + err,cmessage) + if(err/=0)then; message=trim(message)//trim(cmessage); return; end if + + else + canopyWetFraction = 0._rkind + end if ! (desired computing vegetation flux) + + end if ! (re-computing wetted fraction for perturbed cases) + + ! compute the saturation vapor pressure for vegetation temperature + ! NOTE: saturated vapor pressure derivatives don't seem that accurate.... + TV_celcius = canopyTemp - Tfreeze + call satVapPress(TV_celcius, scalarSatVP_CanopyTemp, dSVPCanopy_dCanopyTemp) + + ! compute the saturation vapor pressure for ground temperature + ! NOTE: saturated vapor pressure derivatives don't seem that accurate.... + TG_celcius = groundTemp - Tfreeze + call satVapPress(TG_celcius, scalarSatVP_GroundTemp, dSVPGround_dGroundTemp) + + ! ------------------------------------------------------------------------------------- + ! calculation block (unperturbed fluxes returned [computed last]) + ! ------------------------------------------------------------------------------------- + + ! re-compute aerodynamic resistances for perturbed cases + ! NOTE: unperturbed fluxes computed earlier, and not over-written + if(itry /= unperturbed)then + call aeroResist(& + ! input: model control + computeVegFlux, & ! intent(in): logical flag to compute vegetation fluxes (.false. if veg buried by snow) + .false., & ! intent(in): logical flag if would like to compute analytical derivaties + ix_veg_traits, & ! intent(in): choice of parameterization for vegetation roughness length and displacement height + ix_windPrfile, & ! intent(in): choice of canopy wind profile + ix_astability, & ! intent(in): choice of stability function + ! input: above-canopy forcing data + mHeight, & ! intent(in): measurement height (m) + airtemp, & ! intent(in): air temperature at some height above the surface (K) + windspd, & ! intent(in): wind speed at some height above the surface (m s-1) + ! input: temperature (canopy, ground, canopy air space) + canairTemp, & ! intent(in): temperature of the canopy air space (K) + groundTemp, & ! intent(in): ground temperature (K) + ! input: diagnostic variables + exposedVAI, & ! intent(in): exposed vegetation area index -- leaf plus stem (m2 m-2) + scalarSnowDepth, & ! intent(in): snow depth (m) + ! input: parameters + z0Ground, & ! intent(in): roughness length of the ground (below canopy or non-vegetated surface [snow]) (m) + z0CanopyParam, & ! intent(in): roughness length of the canopy (m) + zpdFraction, & ! intent(in): zero plane displacement / canopy height (-) + critRichNumber, & ! intent(in): critical value for the bulk Richardson number where turbulence ceases (-) + Louis79_bparam, & ! intent(in): parameter in Louis (1979) stability function + Mahrt87_eScale, & ! intent(in): exponential scaling factor in the Mahrt (1987) stability function + windReductionParam, & ! intent(in): canopy wind reduction parameter (-) + leafExchangeCoeff, & ! intent(in): turbulent exchange coeff between canopy surface and canopy air ( m s-(1/2) ) + leafDimension, & ! intent(in): characteristic leaf dimension (m) + heightCanopyTop, & ! intent(in): height at the top of the vegetation canopy (m) + heightCanopyBottom, & ! intent(in): height at the bottom of the vegetation canopy (m) + ! output: stability corrections + notUsed_RiBulkCanopy, & ! intent(out): bulk Richardson number for the canopy (-) + notUsed_RiBulkGround, & ! intent(out): bulk Richardson number for the ground surface (-) + notUsed_scalarCanopyStabilityCorrection, & ! intent(out): stability correction for the canopy (-) + notUsed_scalarGroundStabilityCorrection, & ! intent(out): stability correction for the ground surface (-) + ! output: scalar resistances + notUsed_z0Canopy, & ! intent(out): roughness length of the canopy (m) + notUsed_WindReductionFactor, & ! intent(out): canopy wind reduction factor (-) + notUsed_ZeroPlaneDisplacement, & ! intent(out): zero plane displacement (m) + notUsed_EddyDiffusCanopyTop, & ! intent(out): eddy diffusivity for heat at the top of the canopy (m2 s-1) + notUsed_FrictionVelocity, & ! intent(out): friction velocity (m s-1) + notUsed_WindspdCanopyTop, & ! intent(out): windspeed at the top of the canopy (m s-1) + notUsed_WindspdCanopyBottom, & ! intent(out): windspeed at the height of the bottom of the canopy (m s-1) + trialLeafResistance, & ! intent(out): mean leaf boundary layer resistance per unit leaf area (s m-1) + trialGroundResistance, & ! intent(out): below canopy aerodynamic resistance (s m-1) + trialCanopyResistance, & ! intent(out): above canopy aerodynamic resistance (s m-1) + ! output: derivatives in scalar resistances + notUsed_dGroundResistance_dTGround, & ! intent(out): derivative in ground resistance w.r.t. ground temperature (s m-1 K-1) + notUsed_dGroundResistance_dTCanopy, & ! intent(out): derivative in ground resistance w.r.t. canopy temperature (s m-1 K-1) + notUsed_dGroundResistance_dTCanair, & ! intent(out): derivative in ground resistance w.r.t. canopy air temperature (s m-1 K-1) + notUsed_dCanopyResistance_dTCanopy, & ! intent(out): derivative in canopy resistance w.r.t. canopy temperature (s m-1 K-1) + notUsed_dCanopyResistance_dTCanair, & ! intent(out): derivative in canopy resistance w.r.t. canopy air temperature (s m-1 K-1) + ! output: error control + err,cmessage ) ! intent(out): error control + if(err/=0)then; message=trim(message)//trim(cmessage); return; end if + + + ! assign scalar resistances for un-perturbed cases + else + trialLeafResistance = scalarLeafResistance + trialGroundResistance = scalarGroundResistance + trialCanopyResistance = scalarCanopyResistance + + end if ! (re-computing resistances for perturbed cases) + + + ! compute the relative humidity in the top soil layer and the resistance at the ground surface + ! NOTE: computations are based on start-of-step values, so only compute for the first flux call + if(firstFluxCall)then + ! (soil water evaporation factor [0-1]) + soilEvapFactor = mLayerVolFracLiq(nSnow+1)/(theta_sat - theta_res) + ! (resistance from the soil [s m-1]) + scalarSoilResistance = scalarGroundSnowFraction*1._rkind + (1._rkind - scalarGroundSnowFraction)*EXP(8.25_rkind - 4.225_rkind*soilEvapFactor) ! Sellers (1992) + !scalarSoilResistance = scalarGroundSnowFraction*0._rkind + (1._rkind - scalarGroundSnowFraction)*exp(8.25_rkind - 6.0_rkind*soilEvapFactor) ! Niu adjustment to decrease resitance for wet soil + ! (relative humidity in the soil pores [0-1]) + if(mLayerMatricHead(1) > -1.e+6_rkind)then ! avoid problems with numerical precision when soil is very dry + soilRelHumidity_noSnow = exp( (mLayerMatricHead(1)*gravity) / (groundTemp*R_wv) ) + else + soilRelHumidity_noSnow = 0._rkind + end if ! (if matric head is very low) + scalarSoilRelHumidity = scalarGroundSnowFraction*1._rkind + (1._rkind - scalarGroundSnowFraction)*soilRelHumidity_noSnow + end if ! (if the first flux call) + + ! compute turbulent heat fluxes + call turbFluxes(& + ! input: model control + computeVegFlux, & ! intent(in): logical flag to compute vegetation fluxes (.false. if veg buried by snow) + ixDerivMethod, & ! intent(in): method used to calculate flux derivatives + ! input: above-canopy forcing data + airtemp, & ! intent(in): air temperature at some height above the surface (K) + airpres, & ! intent(in): air pressure of the air above the vegetation canopy (Pa) + scalarVPair, & ! intent(in): vapor pressure of the air above the vegetation canopy (Pa) + ! input: latent heat of sublimation/vaporization + scalarLatHeatSubVapCanopy, & ! intent(in): latent heat of sublimation/vaporization for the vegetation canopy (J kg-1) + scalarLatHeatSubVapGround, & ! intent(in): latent heat of sublimation/vaporization for the ground surface (J kg-1) + ! input: canopy/ground temperature and saturated vapor pressure + canairTemp, & ! intent(in): temperature of the canopy air space (K) + canopyTemp, & ! intent(in): canopy temperature (K) + groundTemp, & ! intent(in): ground temperature (K) + scalarSatVP_CanopyTemp, & ! intent(in): saturation vapor pressure at the temperature of the veg canopy (Pa) + scalarSatVP_GroundTemp, & ! intent(in): saturation vapor pressure at the temperature of the ground (Pa) + dSVPCanopy_dCanopyTemp, & ! intent(in): derivative in canopy saturation vapor pressure w.r.t. canopy temperature (Pa K-1) + dSVPGround_dGroundTemp, & ! intent(in): derivative in ground saturation vapor pressure w.r.t. ground temperature (Pa K-1) + ! input: diagnostic variables + exposedVAI, & ! intent(in): exposed vegetation area index -- leaf plus stem (m2 m-2) + canopyWetFraction, & ! intent(in): trial value for the fraction of canopy that is wet [0-1] + dCanopyWetFraction_dWat, & ! intent(in): derivative in the canopy wetted fraction w.r.t. total water content (kg-1 m-2) + dCanopyWetFraction_dT, & ! intent(in): derivative in wetted fraction w.r.t. canopy temperature (K-1) + scalarCanopySunlitLAI, & ! intent(in): sunlit leaf area (-) + scalarCanopyShadedLAI, & ! intent(in): shaded leaf area (-) + scalarSoilRelHumidity, & ! intent(in): relative humidity in the soil pores [0-1] + scalarSoilResistance, & ! intent(in): resistance from the soil (s m-1) + trialLeafResistance, & ! intent(in): mean leaf boundary layer resistance per unit leaf area (s m-1) + trialGroundResistance, & ! intent(in): below canopy aerodynamic resistance (s m-1) + trialCanopyResistance, & ! intent(in): above canopy aerodynamic resistance (s m-1) + scalarStomResistSunlit, & ! intent(in): stomatal resistance for sunlit leaves (s m-1) + scalarStomResistShaded, & ! intent(in): stomatal resistance for shaded leaves (s m-1) + ! input: derivatives in scalar resistances + dGroundResistance_dTGround, & ! intent(in): derivative in ground resistance w.r.t. ground temperature (s m-1 K-1) + dGroundResistance_dTCanopy, & ! intent(in): derivative in ground resistance w.r.t. canopy temperature (s m-1 K-1) + dGroundResistance_dTCanair, & ! intent(in): derivative in ground resistance w.r.t. canopy air temperature (s m-1 K-1) + dCanopyResistance_dTCanopy, & ! intent(in): derivative in canopy resistance w.r.t. canopy temperature (s m-1 K-1) + dCanopyResistance_dTCanair, & ! intent(in): derivative in canopy resistance w.r.t. canopy air temperature (s m-1 K-1) + ! output: conductances (used to check derivative calculations) + scalarLeafConductance, & ! intent(out): leaf conductance (m s-1) + scalarCanopyConductance, & ! intent(out): canopy conductance (m s-1) + scalarGroundConductanceSH, & ! intent(out): ground conductance for sensible heat (m s-1) + scalarGroundConductanceLH, & ! intent(out): ground conductance for latent heat -- includes soil resistance (m s-1) + scalarEvapConductance, & ! intent(out): conductance for evaporation (m s-1) + scalarTransConductance, & ! intent(out): conductance for transpiration (m s-1) + scalarTotalConductanceSH, & ! intent(out): total conductance for sensible heat (m s-1) + scalarTotalConductanceLH, & ! intent(out): total conductance for latent heat (m s-1) + ! output: canopy air space variables + scalarVP_CanopyAir, & ! intent(out): vapor pressure of the canopy air space (Pa) + ! output: fluxes from the vegetation canopy + scalarSenHeatCanopy, & ! intent(out): sensible heat flux from the canopy to the canopy air space (W m-2) + scalarLatHeatCanopyEvap, & ! intent(out): latent heat flux associated with evaporation from the canopy to the canopy air space (W m-2) + scalarLatHeatCanopyTrans, & ! intent(out): latent heat flux associated with transpiration from the canopy to the canopy air space (W m-2) + ! output: fluxes from non-vegetated surfaces (ground surface below vegetation, bare ground, or snow covered vegetation) + scalarSenHeatGround, & ! intent(out): sensible heat flux from ground surface below vegetation, bare ground, or snow covered vegetation (W m-2) + scalarLatHeatGround, & ! intent(out): latent heat flux from ground surface below vegetation, bare ground, or snow covered vegetation (W m-2) + ! output: total heat fluxes to the atmosphere + scalarSenHeatTotal, & ! intent(out): total sensible heat flux to the atmosphere (W m-2) + scalarLatHeatTotal, & ! intent(out): total latent heat flux to the atmosphere (W m-2) + ! output: net fluxes + turbFluxCanair, & ! intent(out): net turbulent heat fluxes at the canopy air space (W m-2) + turbFluxCanopy, & ! intent(out): net turbulent heat fluxes at the canopy (W m-2) + turbFluxGround, & ! intent(out): net turbulent heat fluxes at the ground surface (W m-2) + ! output: energy flux derivatives + dTurbFluxCanair_dTCanair, & ! intent(out): derivative in net canopy air space fluxes w.r.t. canopy air temperature (W m-2 K-1) + dTurbFluxCanair_dTCanopy, & ! intent(out): derivative in net canopy air space fluxes w.r.t. canopy temperature (W m-2 K-1) + dTurbFluxCanair_dTGround, & ! intent(out): derivative in net canopy air space fluxes w.r.t. ground temperature (W m-2 K-1) + dTurbFluxCanopy_dTCanair, & ! intent(out): derivative in net canopy turbulent fluxes w.r.t. canopy air temperature (W m-2 K-1) + dTurbFluxCanopy_dTCanopy, & ! intent(out): derivative in net canopy turbulent fluxes w.r.t. canopy temperature (W m-2 K-1) + dTurbFluxCanopy_dTGround, & ! intent(out): derivative in net canopy turbulent fluxes w.r.t. ground temperature (W m-2 K-1) + dTurbFluxGround_dTCanair, & ! intent(out): derivative in net ground turbulent fluxes w.r.t. canopy air temperature (W m-2 K-1) + dTurbFluxGround_dTCanopy, & ! intent(out): derivative in net ground turbulent fluxes w.r.t. canopy temperature (W m-2 K-1) + dTurbFluxGround_dTGround, & ! intent(out): derivative in net ground turbulent fluxes w.r.t. ground temperature (W m-2 K-1) + ! output: liquid flux derivatives (canopy evap) + dLatHeatCanopyEvap_dCanWat, & ! intent(out): derivative in latent heat of canopy evaporation w.r.t. canopy total water content (W kg-1) + dLatHeatCanopyEvap_dTCanair, & ! intent(out): derivative in latent heat of canopy evaporation w.r.t. canopy air temperature (W m-2 K-1) + dLatHeatCanopyEvap_dTCanopy, & ! intent(out): derivative in latent heat of canopy evaporation w.r.t. canopy temperature (W m-2 K-1) + dLatHeatCanopyEvap_dTGround, & ! intent(out): derivative in latent heat of canopy evaporation w.r.t. ground temperature (W m-2 K-1) + ! output: liquid flux derivatives (ground evap) + dLatHeatGroundEvap_dCanWat, & ! intent(out): derivative in latent heat of ground evaporation w.r.t. canopy total water content (J kg-1 s-1) + dLatHeatGroundEvap_dTCanair, & ! intent(out): derivative in latent heat of ground evaporation w.r.t. canopy air temperature + dLatHeatGroundEvap_dTCanopy, & ! intent(out): derivative in latent heat of ground evaporation w.r.t. canopy temperature + dLatHeatGroundEvap_dTGround, & ! intent(out): derivative in latent heat of ground evaporation w.r.t. ground temperature + ! output: latent heat flux derivatives (canopy trans) + dLatHeatCanopyTrans_dCanWat, & ! intent(out): derivative in the latent heat of canopy transpiration w.r.t. canopy total water (J kg-1 s-1) + dLatHeatCanopyTrans_dTCanair, & ! intent(out): derivative in the latent heat of canopy transpiration w.r.t. canopy air temperature + dLatHeatCanopyTrans_dTCanopy, & ! intent(out): derivative in the latent heat of canopy transpiration w.r.t. canopy temperature + dLatHeatCanopyTrans_dTGround, & ! intent(out): derivative in the latent heat of canopy transpiration w.r.t. ground temperature + ! output: cross derivatives + dTurbFluxCanair_dCanWat, & ! intent(out): derivative in net canopy air space fluxes w.r.t. canopy total water content (J kg-1 s-1) + dTurbFluxCanopy_dCanWat, & ! intent(out): derivative in net canopy turbulent fluxes w.r.t. canopy total water content (J kg-1 s-1) + dTurbFluxGround_dCanWat, & ! intent(out): derivative in net ground turbulent fluxes w.r.t. canopy total water content (J kg-1 s-1) + ! output: error control + err,cmessage ) ! intent(out): error control + if(err/=0)then; message=trim(message)//trim(cmessage); return; end if + + + !notUsed_scalarCanopyStabilityCorrection ! stability correction for the canopy (-) + !notUsed_scalarGroundStabilityCorrection ! stability correction for the ground surface (-) + !notUsed_EddyDiffusCanopyTop ! eddy diffusivity for heat at the top of the canopy (m2 s-1) + !notUsed_FrictionVelocity ! friction velocity (m s-1) + !notUsed_WindspdCanopyTop ! windspeed at the top of the canopy (m s-1) + !notUsed_WindspdCanopyBottom ! windspeed at the height of the bottom of the canopy (m s-1) + !trialLeafResistance ! mean leaf boundary layer resistance per unit leaf area (s m-1) + !trialGroundResistance ! below canopy aerodynamic resistance (s m-1) + !trialCanopyResistance ! above canopy aerodynamic resistance (s m-1) + + ! save perturbed fluxes + if(ixDerivMethod == numerical)then + select case(itry) ! (select type of perturbation) + case(unperturbed) + try0 = turbFluxGround + exit + case(perturbStateCanair) + turbFluxCanair_dStateCanair = turbFluxCanair ! turbulent exchange from the canopy air space to the atmosphere (W m-2) + turbFluxCanopy_dStateCanair = turbFluxCanopy ! total turbulent heat fluxes from the canopy to the canopy air space (W m-2) + turbFluxGround_dStateCanair = turbFluxGround ! total turbulent heat fluxes from the ground to the canopy air space (W m-2) + latHeatCanEvap_dStateCanair = scalarLatHeatCanopyEvap ! perturbed value for the latent heat associated with canopy evaporation (W m-2) + case(perturbStateCanopy) + turbFluxCanair_dStateCanopy = turbFluxCanair ! turbulent exchange from the canopy air space to the atmosphere (W m-2) + turbFluxCanopy_dStateCanopy = turbFluxCanopy ! total turbulent heat fluxes from the canopy to the canopy air space (W m-2) + turbFluxGround_dStateCanopy = turbFluxGround ! total turbulent heat fluxes from the ground to the canopy air space (W m-2) + latHeatCanEvap_dStateCanopy = scalarLatHeatCanopyEvap ! perturbed value for the latent heat associated with canopy evaporation (W m-2) + case(perturbStateGround) + try1 = turbFluxGround + turbFluxCanair_dStateGround = turbFluxCanair ! turbulent exchange from the canopy air space to the atmosphere (W m-2) + turbFluxCanopy_dStateGround = turbFluxCanopy ! total turbulent heat fluxes from the canopy to the canopy air space (W m-2) + turbFluxGround_dStateGround = turbFluxGround ! total turbulent heat fluxes from the ground to the canopy air space (W m-2) + latHeatCanEvap_dStateGround = scalarLatHeatCanopyEvap ! perturbed value for the latent heat associated with canopy evaporation (W m-2) + case(perturbStateCanWat) + turbFluxCanair_dStateCanWat = turbFluxCanair ! turbulent exchange from the canopy air space to the atmosphere (W m-2) + turbFluxCanopy_dStateCanWat = turbFluxCanopy ! total turbulent heat fluxes from the canopy to the canopy air space (W m-2) + turbFluxGround_dStateCanWat = turbFluxGround ! total turbulent heat fluxes from the ground to the canopy air space (W m-2) + latHeatCanEvap_dStateCanWat = scalarLatHeatCanopyEvap ! perturbed value for the latent heat associated with canopy evaporation (W m-2) + case default; err=10; message=trim(message)//"unknown perturbation"; return + end select ! (type of perturbation) + end if ! (if numerical) + + end do ! (looping through different flux perturbations) + + + ! compute numerical derivatives + if(ixDerivMethod == numerical)then + ! derivatives w.r.t. canopy air temperature + dTurbFluxCanair_dTCanair = (turbFluxCanair_dStateCanair - turbFluxCanair) / dx ! derivative in net canopy air space fluxes w.r.t. canopy air temperature (W m-2 K-1) + dTurbFluxCanopy_dTCanair = (turbFluxCanopy_dStateCanair - turbFluxCanopy) / dx ! derivative in net canopy turbulent fluxes w.r.t. canopy air temperature (W m-2 K-1) + dTurbFluxGround_dTCanair = (turbFluxGround_dStateCanair - turbFluxGround) / dx ! derivative in net ground turbulent fluxes w.r.t. canopy air temperature (W m-2 K-1) + dLatHeatCanopyEvap_dTCanair = (latHeatCanEvap_dStateCanair - scalarLatHeatCanopyEvap) / dx ! derivative in latent heat of canopy evaporation w.r.t. canopy air temperature (W m-2 K-1) + ! derivatives w.r.t. canopy temperature + dTurbFluxCanair_dTCanopy = (turbFluxCanair_dStateCanopy - turbFluxCanair) / dx ! derivative in net canopy air space fluxes w.r.t. canopy temperature (W m-2 K-1) + dTurbFluxCanopy_dTCanopy = (turbFluxCanopy_dStateCanopy - turbFluxCanopy) / dx ! derivative in net canopy turbulent fluxes w.r.t. canopy temperature (W m-2 K-1) + dTurbFluxGround_dTCanopy = (turbFluxGround_dStateCanopy - turbFluxGround) / dx ! derivative in net ground turbulent fluxes w.r.t. canopy temperature (W m-2 K-1) + dLatHeatCanopyEvap_dTCanopy = (latHeatCanEvap_dStateCanopy - scalarLatHeatCanopyEvap) / dx ! derivative in latent heat of canopy evaporation w.r.t. canopy temperature (W m-2 K-1) + ! derivatives w.r.t. ground temperature + dTurbFluxCanair_dTGround = (turbFluxCanair_dStateGround - turbFluxCanair) / dx ! derivative in net canopy air space fluxes w.r.t. ground temperature (W m-2 K-1) + dTurbFluxCanopy_dTGround = (turbFluxCanopy_dStateGround - turbFluxCanopy) / dx ! derivative in net canopy turbulent fluxes w.r.t. ground temperature (W m-2 K-1) + dTurbFluxGround_dTGround = (turbFluxGround_dStateGround - turbFluxGround) / dx ! derivative in net ground turbulent fluxes w.r.t. ground temperature (W m-2 K-1) + dLatHeatCanopyEvap_dTGround = (latHeatCanEvap_dStateGround - scalarLatHeatCanopyEvap) / dx ! derivative in latent heat of canopy evaporation w.r.t. ground temperature (W m-2 K-1) + ! derivatives w.r.t. canopy total water content + dTurbFluxCanair_dCanWat = (turbFluxCanair_dStateCanWat - turbFluxCanair) / dx ! derivative in net canopy air space fluxes w.r.t. canopy total water content (J kg-1 s-1) + dTurbFluxCanopy_dCanWat = (turbFluxCanopy_dStateCanWat - turbFluxCanopy) / dx ! derivative in net canopy turbulent fluxes w.r.t. canopy total water content (J kg-1 s-1) + dTurbFluxGround_dCanWat = (turbFluxGround_dStateCanWat - turbFluxGround) / dx ! derivative in net ground turbulent fluxes w.r.t. canopy total water content (J kg-1 s-1) + dLatHeatCanopyEvap_dCanWat = (latHeatCanEvap_dStateCanWat - scalarLatHeatCanopyEvap) / dx ! derivative in latent heat of canopy evaporation w.r.t. canopy total water content (J kg-1 s-1) + end if + + + ! compute the heat advected with precipitation (W m-2) + ! NOTE: fluxes are in kg m-2 s-1, so no need to use density of water/ice here + scalarCanopyAdvectiveHeatFlux = -Cp_water*(scalarRainfall - scalarThroughfallRain)*(canopyTempTrial - scalarTwetbulb) + & + (-Cp_ice)*(scalarSnowfall - scalarThroughfallSnow)*(canopyTempTrial - scalarTwetbulb) + scalarGroundAdvectiveHeatFlux = -Cp_water*scalarThroughfallRain*(groundTempTrial - scalarTwetbulb) + & + (-Cp_ice)*scalarThroughfallSnow*(groundTempTrial - scalarTwetbulb) + + + ! compute the mass flux associated with transpiration and evaporation/sublimation (J m-2 s-1 --> kg m-2 s-1) + ! NOTE: remove water from the snow on the ground in preference to removing water from the water in soil pores + + ! (canopy transpiration/sublimation) + if(scalarLatHeatSubVapCanopy > LH_vap+verySmall)then ! sublimation + scalarCanopyEvaporation = 0._rkind + scalarCanopySublimation = scalarLatHeatCanopyEvap/LH_sub + if(scalarLatHeatCanopyTrans > 0._rkind)then ! flux directed towards the veg + scalarCanopySublimation = scalarCanopySublimation + scalarLatHeatCanopyTrans/LH_sub ! frost + scalarCanopyTranspiration = 0._rkind + else + scalarCanopyTranspiration = scalarLatHeatCanopyTrans/LH_vap ! transpiration is always vapor + end if + ! (canopy transpiration/evaporation) + else ! evaporation + scalarCanopyEvaporation = scalarLatHeatCanopyEvap/LH_vap + scalarCanopySublimation = 0._rkind + if(scalarLatHeatCanopyTrans > 0._rkind)then ! flux directed towards the veg + scalarCanopyEvaporation = scalarCanopyEvaporation + scalarLatHeatCanopyTrans/LH_vap + scalarCanopyTranspiration = 0._rkind + else + scalarCanopyTranspiration = scalarLatHeatCanopyTrans/LH_vap + end if + end if + ! (ground evaporation/sublimation) + if(scalarLatHeatSubVapGround > LH_vap+verySmall)then ! sublimation + ! NOTE: this should only occur when we have formed snow layers, so check + if(nSnow == 0)then; err=20; message=trim(message)//'only expect snow sublimation when we have formed some snow layers'; return; end if + scalarGroundEvaporation = 0._rkind ! ground evaporation is zero once the snowpack has formed + scalarSnowSublimation = scalarLatHeatGround/LH_sub else - scalarCanopyTranspiration = scalarLatHeatCanopyTrans/LH_vap + ! NOTE: this should only occur when we have no snow layers, so check + if(nSnow > 0)then; err=20; message=trim(message)//'only expect ground evaporation when there are no snow layers'; return; end if + scalarGroundEvaporation = scalarLatHeatGround/LH_vap + scalarSnowSublimation = 0._rkind ! no sublimation from snow if no snow layers have formed end if - end if - ! (ground evaporation/sublimation) - if(scalarLatHeatSubVapGround > LH_vap+verySmall)then ! sublimation - ! NOTE: this should only occur when we have formed snow layers, so check - if(nSnow == 0)then; err=20; message=trim(message)//'only expect snow sublimation when we have formed some snow layers'; return; end if - scalarGroundEvaporation = 0._rkind ! ground evaporation is zero once the snowpack has formed - scalarSnowSublimation = scalarLatHeatGround/LH_sub - else - ! NOTE: this should only occur when we have no snow layers, so check - if(nSnow > 0)then; err=20; message=trim(message)//'only expect ground evaporation when there are no snow layers'; return; end if - scalarGroundEvaporation = scalarLatHeatGround/LH_vap - scalarSnowSublimation = 0._rkind ! no sublimation from snow if no snow layers have formed - end if - !print*, 'scalarSnowSublimation, scalarLatHeatGround = ', scalarSnowSublimation, scalarLatHeatGround - - !print*, 'canopyWetFraction, scalarCanopyEvaporation = ', canopyWetFraction, scalarCanopyEvaporation - - ! ******************************************************************************************************************************************************************* - ! ******************************************************************************************************************************************************************* - ! ***** AND STITCH EVERYTHING TOGETHER ***************************************************************************************************************************** - ! ******************************************************************************************************************************************************************* - ! ******************************************************************************************************************************************************************* - - ! compute derived fluxes - scalarTotalET = scalarGroundEvaporation + scalarCanopyEvaporation + scalarCanopyTranspiration - scalarNetRadiation = scalarCanopyAbsorbedSolar + scalarLWNetCanopy + scalarGroundAbsorbedSolar + scalarLWNetGround - - ! compute net fluxes at the canopy and ground surface - canairNetFlux = turbFluxCanair - canopyNetFlux = scalarCanopyAbsorbedSolar + scalarLWNetCanopy + turbFluxCanopy + scalarCanopyAdvectiveHeatFlux - groundNetFlux = scalarGroundAbsorbedSolar + scalarLWNetGround + turbFluxGround + scalarGroundAdvectiveHeatFlux - !write(*,'(a,1x,10(e17.10,1x))') 'canopyNetFlux, groundNetFlux, scalarLWNetCanopy, turbFluxCanopy, turbFluxGround, scalarLWNetGround, scalarCanopyAdvectiveHeatFlux = ', & - ! canopyNetFlux, groundNetFlux, scalarLWNetCanopy, turbFluxCanopy, turbFluxGround, scalarLWNetGround, scalarCanopyAdvectiveHeatFlux - !write(*,'(a,1x,10(e20.14,1x))') 'groundNetFlux, scalarGroundAbsorbedSolar, scalarLWNetGround, turbFluxGround, scalarGroundAdvectiveHeatFlux = ', & - ! groundNetFlux, scalarGroundAbsorbedSolar, scalarLWNetGround, turbFluxGround, scalarGroundAdvectiveHeatFlux - - ! compute the energy derivatives - dCanairNetFlux_dCanairTemp = dTurbFluxCanair_dTCanair - dCanairNetFlux_dCanopyTemp = dTurbFluxCanair_dTCanopy - dCanairNetFlux_dGroundTemp = dTurbFluxCanair_dTGround - dCanopyNetFlux_dCanairTemp = dTurbFluxCanopy_dTCanair - dCanopyNetFlux_dCanopyTemp = dLWNetCanopy_dTCanopy + dTurbFluxCanopy_dTCanopy - Cp_water*(scalarRainfall - scalarThroughfallRain) - Cp_ice*(scalarSnowfall - scalarThroughfallSnow) - dCanopyNetFlux_dGroundTemp = dLWNetCanopy_dTGround + dTurbFluxCanopy_dTGround - dGroundNetFlux_dCanairTemp = dTurbFluxGround_dTCanair - dGroundNetFlux_dCanopyTemp = dLWNetGround_dTCanopy + dTurbFluxGround_dTCanopy - dGroundNetFlux_dGroundTemp = dLWNetGround_dTGround + dTurbFluxGround_dTGround - Cp_water*scalarThroughfallRain - Cp_ice*scalarThroughfallSnow - - ! check if evaporation or sublimation - if(scalarLatHeatSubVapCanopy < LH_vap+verySmall)then ! evaporation - - ! compute the liquid water derivarives - dCanopyEvaporation_dCanWat = dLatHeatCanopyEvap_dCanWat/LH_vap ! (s-1) - dCanopyEvaporation_dTCanair = dLatHeatCanopyEvap_dTCanair/LH_vap ! (kg m-2 s-1 K-1) - dCanopyEvaporation_dTCanopy = dLatHeatCanopyEvap_dTCanopy/LH_vap ! (kg m-2 s-1 K-1) - dCanopyEvaporation_dTGround = dLatHeatCanopyEvap_dTGround/LH_vap ! (kg m-2 s-1 K-1) - - ! sublimation - else - dCanopyEvaporation_dCanWat = 0._rkind ! (s-1) - dCanopyEvaporation_dTCanair = 0._rkind ! (kg m-2 s-1 K-1) - dCanopyEvaporation_dTCanopy = 0._rkind ! (kg m-2 s-1 K-1) - dCanopyEvaporation_dTGround = 0._rkind ! (kg m-2 s-1 K-1) - end if - - ! transpiration - if(scalarLatHeatCanopyTrans > 0._rkind)then ! flux directed towards the veg - dCanopyTrans_dCanWat = 0._rkind - dCanopyTrans_dTCanair= 0._rkind - dCanopyTrans_dTCanopy= 0._rkind - dCanopyTrans_dTGround= 0._rkind + + + ! ******************************************************************************************************************************************************************* + ! ******************************************************************************************************************************************************************* + ! ***** AND STITCH EVERYTHING TOGETHER ***************************************************************************************************************************** + ! ******************************************************************************************************************************************************************* + ! ******************************************************************************************************************************************************************* + + ! compute derived fluxes + scalarTotalET = scalarGroundEvaporation + scalarCanopyEvaporation + scalarCanopyTranspiration + scalarNetRadiation = scalarCanopyAbsorbedSolar + scalarLWNetCanopy + scalarGroundAbsorbedSolar + scalarLWNetGround + + ! compute net fluxes at the canopy and ground surface + canairNetFlux = turbFluxCanair + canopyNetFlux = scalarCanopyAbsorbedSolar + scalarLWNetCanopy + turbFluxCanopy + scalarCanopyAdvectiveHeatFlux + groundNetFlux = scalarGroundAbsorbedSolar + scalarLWNetGround + turbFluxGround + scalarGroundAdvectiveHeatFlux + + ! compute the energy derivatives + dCanairNetFlux_dCanairTemp = dTurbFluxCanair_dTCanair + dCanairNetFlux_dCanopyTemp = dTurbFluxCanair_dTCanopy + dCanairNetFlux_dGroundTemp = dTurbFluxCanair_dTGround + dCanopyNetFlux_dCanairTemp = dTurbFluxCanopy_dTCanair + dCanopyNetFlux_dCanopyTemp = dLWNetCanopy_dTCanopy + dTurbFluxCanopy_dTCanopy - Cp_water*(scalarRainfall - scalarThroughfallRain) - Cp_ice*(scalarSnowfall - scalarThroughfallSnow) + dCanopyNetFlux_dGroundTemp = dLWNetCanopy_dTGround + dTurbFluxCanopy_dTGround + dGroundNetFlux_dCanairTemp = dTurbFluxGround_dTCanair + dGroundNetFlux_dCanopyTemp = dLWNetGround_dTCanopy + dTurbFluxGround_dTCanopy + dGroundNetFlux_dGroundTemp = dLWNetGround_dTGround + dTurbFluxGround_dTGround - Cp_water*scalarThroughfallRain - Cp_ice*scalarThroughfallSnow + + ! check if evaporation or sublimation + if(scalarLatHeatSubVapCanopy < LH_vap+verySmall)then ! evaporation + + ! compute the liquid water derivarives + dCanopyEvaporation_dCanWat = dLatHeatCanopyEvap_dCanWat/LH_vap ! (s-1) + dCanopyEvaporation_dTCanair = dLatHeatCanopyEvap_dTCanair/LH_vap ! (kg m-2 s-1 K-1) + dCanopyEvaporation_dTCanopy = dLatHeatCanopyEvap_dTCanopy/LH_vap ! (kg m-2 s-1 K-1) + dCanopyEvaporation_dTGround = dLatHeatCanopyEvap_dTGround/LH_vap ! (kg m-2 s-1 K-1) + + ! sublimation else - dCanopyTrans_dCanWat= dLatHeatCanopyTrans_dCanWat/LH_vap ! transpiration is always vapor - dCanopyTrans_dTCanair= dLatHeatCanopyTrans_dTCanair/LH_vap - dCanopyTrans_dTCanopy= dLatHeatCanopyTrans_dTCanopy/LH_vap - dCanopyTrans_dTGround= dLatHeatCanopyTrans_dTGround/LH_vap + dCanopyEvaporation_dCanWat = 0._rkind ! (s-1) + dCanopyEvaporation_dTCanair = 0._rkind ! (kg m-2 s-1 K-1) + dCanopyEvaporation_dTCanopy = 0._rkind ! (kg m-2 s-1 K-1) + dCanopyEvaporation_dTGround = 0._rkind ! (kg m-2 s-1 K-1) end if - - - ! compute the liquid water derivarives (ground evap) - dGroundEvaporation_dCanWat = dLatHeatGroundEvap_dCanWat/LH_vap ! (s-1) - dGroundEvaporation_dTCanair = dLatHeatGroundEvap_dTCanair/LH_vap ! (kg m-2 s-1 K-1) - dGroundEvaporation_dTCanopy = dLatHeatGroundEvap_dTCanopy/LH_vap ! (kg m-2 s-1 K-1) - dGroundEvaporation_dTGround = dLatHeatGroundEvap_dTGround/LH_vap ! (kg m-2 s-1 K-1) - - ! compute the cross derivative terms (only related to turbulent fluxes; specifically canopy evaporation and transpiration) - dCanopyNetFlux_dCanWat = dTurbFluxCanopy_dCanWat ! derivative in net canopy fluxes w.r.t. canopy total water content (J kg-1 s-1) - dGroundNetFlux_dCanWat = dTurbFluxGround_dCanWat ! derivative in net ground fluxes w.r.t. canopy total water content (J kg-1 s-1) - - !print*, (ixDerivMethod == numerical) - !print*, 'dGroundNetFlux_dCanairTemp = ', dGroundNetFlux_dCanairTemp - !print*, 'dCanopyNetFlux_dCanopyTemp = ', dCanopyNetFlux_dCanopyTemp - !print*, 'dGroundNetFlux_dCanopyTemp = ', dGroundNetFlux_dCanopyTemp - !print*, 'dCanopyNetFlux_dGroundTemp = ', dCanopyNetFlux_dGroundTemp - !print*, 'dGroundNetFlux_dGroundTemp = ', dGroundNetFlux_dGroundTemp - !print*, 'dLWNetCanopy_dTGround = ', dLWNetCanopy_dTGround - !print*, 'dTurbFluxCanopy_dTGround = ', dTurbFluxCanopy_dTGround - !pause - + + ! transpiration + if(scalarLatHeatCanopyTrans > 0._rkind)then ! flux directed towards the veg + dCanopyTrans_dCanWat = 0._rkind + dCanopyTrans_dTCanair= 0._rkind + dCanopyTrans_dTCanopy= 0._rkind + dCanopyTrans_dTGround= 0._rkind + else + dCanopyTrans_dCanWat= dLatHeatCanopyTrans_dCanWat/LH_vap ! transpiration is always vapor + dCanopyTrans_dTCanair= dLatHeatCanopyTrans_dTCanair/LH_vap + dCanopyTrans_dTCanopy= dLatHeatCanopyTrans_dTCanopy/LH_vap + dCanopyTrans_dTGround= dLatHeatCanopyTrans_dTGround/LH_vap + end if + + + ! compute the liquid water derivarives (ground evap) + dGroundEvaporation_dCanWat = dLatHeatGroundEvap_dCanWat/LH_vap ! (s-1) + dGroundEvaporation_dTCanair = dLatHeatGroundEvap_dTCanair/LH_vap ! (kg m-2 s-1 K-1) + dGroundEvaporation_dTCanopy = dLatHeatGroundEvap_dTCanopy/LH_vap ! (kg m-2 s-1 K-1) + dGroundEvaporation_dTGround = dLatHeatGroundEvap_dTGround/LH_vap ! (kg m-2 s-1 K-1) + + ! compute the cross derivative terms (only related to turbulent fluxes; specifically canopy evaporation and transpiration) + dCanopyNetFlux_dCanWat = dTurbFluxCanopy_dCanWat ! derivative in net canopy fluxes w.r.t. canopy total water content (J kg-1 s-1) + dGroundNetFlux_dCanWat = dTurbFluxGround_dCanWat ! derivative in net ground fluxes w.r.t. canopy total water content (J kg-1 s-1) + ! * check case default; err=10; message=trim(message)//'unable to identify upper boundary condition for thermodynamics'; return - - ! end case statement - end select ! upper boundary condition for thermodynamics - - ! return liquid fluxes (needed for coupling) - returnCanopyTranspiration = scalarCanopyTranspiration ! canopy transpiration (kg m-2 s-1) - returnCanopyEvaporation = scalarCanopyEvaporation ! canopy evaporation/condensation (kg m-2 s-1) - returnGroundEvaporation = scalarGroundEvaporation ! ground evaporation/condensation -- below canopy or non-vegetated (kg m-2 s-1) - - ! end associations - end associate - - - end subroutine vegNrgFlux - - - ! ******************************************************************************************************* - ! public subroutine wettedFrac: compute wetted fraction of the canopy - ! ******************************************************************************************************* - subroutine wettedFrac(& - ! input - deriv, & ! flag to denote if derivative is desired - derNum, & ! flag to denote that numerical derivatives are required (otherwise, analytical derivatives are calculated) - frozen, & ! flag to denote if the canopy is frozen - dLiq_dT, & ! derivative in canopy liquid w.r.t. canopy temperature (kg m-2 K-1) - fracLiq, & ! fraction of liquid water on the canopy (-) - canopyLiq, & ! canopy liquid water (kg m-2) - canopyIce, & ! canopy ice (kg m-2) - canopyLiqMax, & ! maximum canopy liquid water (kg m-2) - canopyIceMax, & ! maximum canopy ice content (kg m-2) - canopyWettingFactor, & ! maximum wetted fraction of the canopy (-) - canopyWettingExp, & ! exponent in canopy wetting function (-) - ! output - canopyWetFraction, & ! canopy wetted fraction (-) - dCanopyWetFraction_dWat,& ! derivative in wetted fraction w.r.t. canopy total water (kg-1 m2) - dCanopyWetFraction_dT, & ! derivative in wetted fraction w.r.t. canopy temperature (K-1) - err,message) ! error control - implicit none - ! input - logical(lgt),intent(in) :: deriv ! flag to denote if derivative is desired - logical(lgt),intent(in) :: derNum ! flag to denote that numerical derivatives are required (otherwise, analytical derivatives are calculated) - logical(lgt),intent(in) :: frozen ! flag to denote if the canopy is frozen - real(rkind),intent(in) :: dLiq_dT ! derivative in canopy liquid w.r.t. canopy temperature (kg m-2 K-1) - real(rkind),intent(in) :: fracLiq ! fraction of liquid water on the canopy (-) - real(rkind),intent(in) :: canopyLiq ! canopy liquid water (kg m-2) - real(rkind),intent(in) :: canopyIce ! canopy ice (kg m-2) - real(rkind),intent(in) :: canopyLiqMax ! maximum canopy liquid water (kg m-2) - real(rkind),intent(in) :: canopyIceMax ! maximum canopy ice content (kg m-2) - real(rkind),intent(in) :: canopyWettingFactor ! maximum wetted fraction of the canopy (-) - real(rkind),intent(in) :: canopyWettingExp ! exponent in canopy wetting function (-) - ! output - real(rkind),intent(out) :: canopyWetFraction ! canopy wetted fraction (-) - real(rkind),intent(out) :: dCanopyWetFraction_dWat ! derivative in wetted fraction w.r.t. canopy total water (kg-1 m2) - real(rkind),intent(out) :: dCanopyWetFraction_dT ! derivative in wetted fraction w.r.t. canopy temperature (K-1) - ! output: error control - integer(i4b),intent(out) :: err ! error code - character(*),intent(out) :: message ! error message - ! local variables - logical(lgt),parameter :: smoothing=.true. ! flag to denote that smoothing is required - real(rkind) :: canopyWetFractionPert ! canopy wetted fraction after state perturbations (-) - real(rkind) :: canopyWetFractionDeriv ! derivative in wetted fraction w.r.t. canopy liquid water (kg-1 m2) - ! ----------------------------------------------------------------------------------------------------------------------------------------------- - ! initialize error control - err=0; message='wettedFrac/' - - ! compute case where the canopy is frozen - if(frozen)then - ! compute fraction of liquid water on the canopy - call wetFraction((deriv .and. .not.derNum),smoothing,canopyIce,canopyIceMax,canopyWettingFactor,canopyWettingExp,canopyWetFraction,canopyWetFractionDeriv) - ! compute numerical derivative, if derivative is desired - if(deriv.and.derNum)then - call wetFraction((deriv .and. .not.derNum),smoothing,canopyIce+dx,canopyIceMax,canopyWettingFactor,canopyWettingExp,canopyWetFractionPert,canopyWetFractionDeriv) - canopyWetFractionDeriv = (canopyWetFractionPert - canopyWetFraction)/dx - end if - ! scale derivative by the fraction of water - ! NOTE: dIce/dWat = (1._rkind - fracLiq), hence dWet/dWat = dIce/dWat . dWet/dLiq - dCanopyWetFraction_dWat = canopyWetFractionDeriv*(1._rkind - fracLiq) - dCanopyWetFraction_dT = -canopyWetFractionDeriv*dLiq_dT ! NOTE: dIce/dT = -dLiq/dT - return - end if - - ! compute fraction of liquid water on the canopy - ! NOTE: if(.not.deriv) canopyWetFractionDeriv = 0._rkind - call wetFraction((deriv .and. .not.derNum),smoothing,canopyLiq,canopyLiqMax,canopyWettingFactor,canopyWettingExp,canopyWetFraction,canopyWetFractionDeriv) - - ! compute numerical derivative - if(deriv.and.derNum)then - call wetFraction((deriv .and. .not.derNum),smoothing,canopyLiq+dx,canopyLiqMax,canopyWettingFactor,canopyWettingExp,canopyWetFractionPert,canopyWetFractionDeriv) + + ! end case statement + end select ! upper boundary condition for thermodynamics + + ! return liquid fluxes (needed for coupling) + returnCanopyTranspiration = scalarCanopyTranspiration ! canopy transpiration (kg m-2 s-1) + returnCanopyEvaporation = scalarCanopyEvaporation ! canopy evaporation/condensation (kg m-2 s-1) + returnGroundEvaporation = scalarGroundEvaporation ! ground evaporation/condensation -- below canopy or non-vegetated (kg m-2 s-1) + + ! end associations + end associate + +end subroutine vegNrgFlux + + +! ******************************************************************************************************* +! public subroutine wettedFrac: compute wetted fraction of the canopy +! ******************************************************************************************************* +subroutine wettedFrac(& + ! input + deriv, & ! flag to denote if derivative is desired + derNum, & ! flag to denote that numerical derivatives are required (otherwise, analytical derivatives are calculated) + frozen, & ! flag to denote if the canopy is frozen + dLiq_dT, & ! derivative in canopy liquid w.r.t. canopy temperature (kg m-2 K-1) + fracLiq, & ! fraction of liquid water on the canopy (-) + canopyLiq, & ! canopy liquid water (kg m-2) + canopyIce, & ! canopy ice (kg m-2) + canopyLiqMax, & ! maximum canopy liquid water (kg m-2) + canopyIceMax, & ! maximum canopy ice content (kg m-2) + canopyWettingFactor, & ! maximum wetted fraction of the canopy (-) + canopyWettingExp, & ! exponent in canopy wetting function (-) + ! output + canopyWetFraction, & ! canopy wetted fraction (-) + dCanopyWetFraction_dWat,& ! derivative in wetted fraction w.r.t. canopy total water (kg-1 m2) + dCanopyWetFraction_dT, & ! derivative in wetted fraction w.r.t. canopy temperature (K-1) + err,message) ! error control + implicit none + ! input + logical(lgt),intent(in) :: deriv ! flag to denote if derivative is desired + logical(lgt),intent(in) :: derNum ! flag to denote that numerical derivatives are required (otherwise, analytical derivatives are calculated) + logical(lgt),intent(in) :: frozen ! flag to denote if the canopy is frozen + real(rkind),intent(in) :: dLiq_dT ! derivative in canopy liquid w.r.t. canopy temperature (kg m-2 K-1) + real(rkind),intent(in) :: fracLiq ! fraction of liquid water on the canopy (-) + real(rkind),intent(in) :: canopyLiq ! canopy liquid water (kg m-2) + real(rkind),intent(in) :: canopyIce ! canopy ice (kg m-2) + real(rkind),intent(in) :: canopyLiqMax ! maximum canopy liquid water (kg m-2) + real(rkind),intent(in) :: canopyIceMax ! maximum canopy ice content (kg m-2) + real(rkind),intent(in) :: canopyWettingFactor ! maximum wetted fraction of the canopy (-) + real(rkind),intent(in) :: canopyWettingExp ! exponent in canopy wetting function (-) + ! output + real(rkind),intent(out) :: canopyWetFraction ! canopy wetted fraction (-) + real(rkind),intent(out) :: dCanopyWetFraction_dWat ! derivative in wetted fraction w.r.t. canopy total water (kg-1 m2) + real(rkind),intent(out) :: dCanopyWetFraction_dT ! derivative in wetted fraction w.r.t. canopy temperature (K-1) + ! output: error control + integer(i4b),intent(out) :: err ! error code + character(*),intent(out) :: message ! error message + ! local variables + logical(lgt),parameter :: smoothing=.true. ! flag to denote that smoothing is required + real(rkind) :: canopyWetFractionPert ! canopy wetted fraction after state perturbations (-) + real(rkind) :: canopyWetFractionDeriv ! derivative in wetted fraction w.r.t. canopy liquid water (kg-1 m2) + ! ----------------------------------------------------------------------------------------------------------------------------------------------- + ! initialize error control + err=0; message='wettedFrac/' + + ! compute case where the canopy is frozen + if(frozen)then + ! compute fraction of liquid water on the canopy + call wetFraction((deriv .and. .not.derNum),smoothing,canopyIce,canopyIceMax,canopyWettingFactor,canopyWettingExp,canopyWetFraction,canopyWetFractionDeriv) + ! compute numerical derivative, if derivative is desired + if(deriv.and.derNum)then + call wetFraction((deriv .and. .not.derNum),smoothing,canopyIce+dx,canopyIceMax,canopyWettingFactor,canopyWettingExp,canopyWetFractionPert,canopyWetFractionDeriv) canopyWetFractionDeriv = (canopyWetFractionPert - canopyWetFraction)/dx - end if - - ! scale derivative by the fraction of water - ! NOTE: dLiq/dWat = fracLiq, hence dWet/dWat = dLiq/dWat . dWet/dLiq - dCanopyWetFraction_dWat = canopyWetFractionDeriv*fracLiq - dCanopyWetFraction_dT = canopyWetFractionDeriv*dLiq_dT - - ! test - !write(*,'(a,1x,2(L1,1x),10(f20.10,1x))') 'deriv, derNum, canopyWetFraction, canopyWetFractionDeriv = ', deriv, derNum, canopyWetFraction, canopyWetFractionDeriv - !if(deriv) pause 'testing canopy wet fraction' - - end subroutine wettedFrac - - - ! ******************************************************************************************************* - ! private subroutine wetFraction: compute fraction of canopy covered with liquid water - ! ******************************************************************************************************* - subroutine wetFraction(derDesire,smoothing,canopyLiq,canopyMax,canopyWettingFactor,canopyWettingExp,canopyWetFraction,canopyWetFractionDeriv) - implicit none - ! dummy variables - logical(lgt),intent(in) :: derDesire ! flag to denote if analytical derivatives are desired - logical(lgt),intent(in) :: smoothing ! flag to denote if smoothing is required - real(rkind),intent(in) :: canopyLiq ! liquid water content (kg m-2) - real(rkind),intent(in) :: canopyMax ! liquid water content (kg m-2) - real(rkind),intent(in) :: canopyWettingFactor ! maximum wetted fraction of the canopy (-) - real(rkind),intent(in) :: canopyWettingExp ! exponent in canopy wetting function (-) - - real(rkind),intent(out) :: canopyWetFraction ! canopy wetted fraction (-) - real(rkind),intent(out) :: canopyWetFractionDeriv ! derivative in wetted fraction w.r.t. canopy liquid water (kg-1 m2) - ! local variables - real(rkind) :: relativeCanopyWater ! water stored on vegetation canopy, expressed as a fraction of maximum storage (-) - real(rkind) :: rawCanopyWetFraction ! initial value of the canopy wet fraction (before smoothing) - real(rkind) :: rawWetFractionDeriv ! derivative in canopy wet fraction w.r.t. storage (kg-1 m2) - real(rkind) :: smoothFunc ! smoothing function used to improve numerical stability at times with limited water storage (-) - real(rkind) :: smoothFuncDeriv ! derivative in the smoothing function w.r.t.canopy storage (kg-1 m2) - real(rkind) :: verySmall=epsilon(1._rkind) ! a very small number - ! -------------------------------------------------------------------------------------------------------------- - - ! compute relative canopy water - relativeCanopyWater = canopyLiq/canopyMax - !write(*,'(a,1x,e20.10,1x,2(f20.10,1x))') 'relativeCanopyWater, canopyLiq, canopyMax = ', relativeCanopyWater, canopyLiq, canopyMax - - ! compute an initial value of the canopy wet fraction - ! - canopy below value where canopy is 100% wet - if(relativeCanopyWater < 1._rkind)then - rawCanopyWetFraction = canopyWettingFactor*(relativeCanopyWater**canopyWettingExp) - if(derDesire .and. relativeCanopyWater>verySmall)then - rawWetFractionDeriv = (canopyWettingFactor*canopyWettingExp/canopyMax)*relativeCanopyWater**(canopyWettingExp - 1._rkind) - else - rawWetFractionDeriv = 0._rkind - end if - - ! - canopy is at capacity (canopyWettingFactor) - else - rawCanopyWetFraction = canopyWettingFactor - rawWetFractionDeriv = 0._rkind - end if - - ! smooth canopy wetted fraction - if(smoothing)then - call logisticSmoother(derDesire,canopyLiq,smoothFunc,smoothFuncDeriv) - canopyWetFraction = rawCanopyWetFraction*smoothFunc ! logistic smoother - else - canopyWetFraction = rawCanopyWetFraction - canopyWetFractionDeriv = rawWetFractionDeriv - end if - - ! compute derivative (product rule) - if(derDesire .and. smoothing)then ! NOTE: raw derivative is used if not smoothing - canopyWetFractionDeriv = rawWetFractionDeriv*smoothFunc + rawCanopyWetFraction*smoothFuncDeriv - else - canopyWetFractionDeriv = 0._rkind - end if - - end subroutine wetFraction - - - ! ******************************************************************************************************* - ! private subroutine logisticSmoother: compute the smoothing function - ! ******************************************************************************************************* - subroutine logisticSmoother(derDesire,canopyLiq,smoothFunc,smoothFuncDeriv) - implicit none - ! dummy variables - logical(lgt),intent(in) :: derDesire ! flag to denote if analytical derivatives are desired - real(rkind),intent(in) :: canopyLiq ! liquid water content (kg m-2) - real(rkind),intent(out) :: smoothFunc ! smoothing function (-) - real(rkind),intent(out) :: smoothFuncDeriv ! derivative in smoothing function (kg-1 m-2) - ! local variables - real(rkind) :: xArg ! argument used in the smoothing function (-) - real(rkind) :: expX ! exp(-xArg) -- used multiple times - real(rkind),parameter :: smoothThresh=0.01_rkind ! mid-point of the smoothing function (kg m-2) - real(rkind),parameter :: smoothScale=0.001_rkind ! scaling factor for the smoothing function (kg m-2) - real(rkind),parameter :: xLimit=50._rkind ! don't compute exponents for > xLimit - ! -------------------------------------------------------------------------------------------------------------- - ! compute argument in the smoothing function - xArg = (canopyLiq - smoothThresh)/smoothScale - - ! only compute smoothing function for small exponents - if(xArg > -xLimit .and. xArg < xLimit)then ! avoid huge exponents - expX = exp(-xarg) ! (also used in the derivative) - smoothFunc = 1._rkind / (1._rkind + expX) ! (logistic smoother) - if(derDesire)then - smoothFuncDeriv = expX / (smoothScale * (1._rkind + expX)**2._rkind) ! (derivative in the smoothing function) - else - smoothFuncDeriv = 0._rkind - end if - - ! outside limits: special case of smooth exponents - else - if(xArg < 0._rkind)then; smoothFunc = 0._rkind ! xArg < -xLimit - else; smoothFunc = 1._rkind ! xArg > xLimit - end if + end if + ! scale derivative by the fraction of water + ! NOTE: dIce/dWat = (1._rkind - fracLiq), hence dWet/dWat = dIce/dWat . dWet/dLiq + dCanopyWetFraction_dWat = canopyWetFractionDeriv*(1._rkind - fracLiq) + dCanopyWetFraction_dT = -canopyWetFractionDeriv*dLiq_dT ! NOTE: dIce/dT = -dLiq/dT + return + end if + + ! compute fraction of liquid water on the canopy + ! NOTE: if(.not.deriv) canopyWetFractionDeriv = 0._rkind + call wetFraction((deriv .and. .not.derNum),smoothing,canopyLiq,canopyLiqMax,canopyWettingFactor,canopyWettingExp,canopyWetFraction,canopyWetFractionDeriv) + + ! compute numerical derivative + if(deriv.and.derNum)then + call wetFraction((deriv .and. .not.derNum),smoothing,canopyLiq+dx,canopyLiqMax,canopyWettingFactor,canopyWettingExp,canopyWetFractionPert,canopyWetFractionDeriv) + canopyWetFractionDeriv = (canopyWetFractionPert - canopyWetFraction)/dx + end if + + ! scale derivative by the fraction of water + ! NOTE: dLiq/dWat = fracLiq, hence dWet/dWat = dLiq/dWat . dWet/dLiq + dCanopyWetFraction_dWat = canopyWetFractionDeriv*fracLiq + dCanopyWetFraction_dT = canopyWetFractionDeriv*dLiq_dT + +end subroutine wettedFrac + + +! ******************************************************************************************************* +! private subroutine wetFraction: compute fraction of canopy covered with liquid water +! ******************************************************************************************************* +subroutine wetFraction(derDesire,smoothing,canopyLiq,canopyMax,canopyWettingFactor,canopyWettingExp,canopyWetFraction,canopyWetFractionDeriv) + implicit none + ! dummy variables + logical(lgt),intent(in) :: derDesire ! flag to denote if analytical derivatives are desired + logical(lgt),intent(in) :: smoothing ! flag to denote if smoothing is required + real(rkind),intent(in) :: canopyLiq ! liquid water content (kg m-2) + real(rkind),intent(in) :: canopyMax ! liquid water content (kg m-2) + real(rkind),intent(in) :: canopyWettingFactor ! maximum wetted fraction of the canopy (-) + real(rkind),intent(in) :: canopyWettingExp ! exponent in canopy wetting function (-) + + real(rkind),intent(out) :: canopyWetFraction ! canopy wetted fraction (-) + real(rkind),intent(out) :: canopyWetFractionDeriv ! derivative in wetted fraction w.r.t. canopy liquid water (kg-1 m2) + ! local variables + real(rkind) :: relativeCanopyWater ! water stored on vegetation canopy, expressed as a fraction of maximum storage (-) + real(rkind) :: rawCanopyWetFraction ! initial value of the canopy wet fraction (before smoothing) + real(rkind) :: rawWetFractionDeriv ! derivative in canopy wet fraction w.r.t. storage (kg-1 m2) + real(rkind) :: smoothFunc ! smoothing function used to improve numerical stability at times with limited water storage (-) + real(rkind) :: smoothFuncDeriv ! derivative in the smoothing function w.r.t.canopy storage (kg-1 m2) + real(rkind) :: verySmall=epsilon(1._rkind) ! a very small number + ! -------------------------------------------------------------------------------------------------------------- + + ! compute relative canopy water + relativeCanopyWater = canopyLiq/canopyMax + + ! compute an initial value of the canopy wet fraction + ! - canopy below value where canopy is 100% wet + if(relativeCanopyWater < 1._rkind)then + rawCanopyWetFraction = canopyWettingFactor*(relativeCanopyWater**canopyWettingExp) + if(derDesire .and. relativeCanopyWater>verySmall)then + rawWetFractionDeriv = (canopyWettingFactor*canopyWettingExp/canopyMax)*relativeCanopyWater**(canopyWettingExp - 1._rkind) + else + rawWetFractionDeriv = 0._rkind + end if + + ! - canopy is at capacity (canopyWettingFactor) + else + rawCanopyWetFraction = canopyWettingFactor + rawWetFractionDeriv = 0._rkind + end if + + ! smooth canopy wetted fraction + if(smoothing)then + call logisticSmoother(derDesire,canopyLiq,smoothFunc,smoothFuncDeriv) + canopyWetFraction = rawCanopyWetFraction*smoothFunc ! logistic smoother + else + canopyWetFraction = rawCanopyWetFraction + canopyWetFractionDeriv = rawWetFractionDeriv + end if + + ! compute derivative (product rule) + if(derDesire .and. smoothing)then ! NOTE: raw derivative is used if not smoothing + canopyWetFractionDeriv = rawWetFractionDeriv*smoothFunc + rawCanopyWetFraction*smoothFuncDeriv + else + canopyWetFractionDeriv = 0._rkind + end if + +end subroutine wetFraction + + +! ******************************************************************************************************* +! private subroutine logisticSmoother: compute the smoothing function +! ******************************************************************************************************* +subroutine logisticSmoother(derDesire,canopyLiq,smoothFunc,smoothFuncDeriv) + implicit none + ! dummy variables + logical(lgt),intent(in) :: derDesire ! flag to denote if analytical derivatives are desired + real(rkind),intent(in) :: canopyLiq ! liquid water content (kg m-2) + real(rkind),intent(out) :: smoothFunc ! smoothing function (-) + real(rkind),intent(out) :: smoothFuncDeriv ! derivative in smoothing function (kg-1 m-2) + ! local variables + real(rkind) :: xArg ! argument used in the smoothing function (-) + real(rkind) :: expX ! exp(-xArg) -- used multiple times + real(rkind),parameter :: smoothThresh=0.01_rkind ! mid-point of the smoothing function (kg m-2) + real(rkind),parameter :: smoothScale=0.001_rkind ! scaling factor for the smoothing function (kg m-2) + real(rkind),parameter :: xLimit=50._rkind ! don't compute exponents for > xLimit + ! -------------------------------------------------------------------------------------------------------------- + ! compute argument in the smoothing function + xArg = (canopyLiq - smoothThresh)/smoothScale + + ! only compute smoothing function for small exponents + if(xArg > -xLimit .and. xArg < xLimit)then ! avoid huge exponents + expX = exp(-xarg) ! (also used in the derivative) + smoothFunc = 1._rkind / (1._rkind + expX) ! (logistic smoother) + if(derDesire)then + smoothFuncDeriv = expX / (smoothScale * (1._rkind + expX)**2._rkind) ! (derivative in the smoothing function) + else smoothFuncDeriv = 0._rkind - end if ! check for huge exponents - - end subroutine logisticSmoother - ! -------------------------------------------------------------------------------------------------------------- - - - ! ******************************************************************************************************* - ! private subroutine longwaveBal: compute longwave radiation balance at the canopy and ground surface - ! ******************************************************************************************************* - subroutine longwaveBal(& - ! input: model control - ixDerivMethod, & ! intent(in): choice of method used to compute derivative (analytical or numerical) - computeVegFlux, & ! intent(in): flag to compute fluxes over vegetati - requireLWBal, & ! intent(in): flag to indicate if we need longwave to be balanced - ! input: canopy and ground temperature - canopyTemp, & ! intent(in): canopy temperature (K) - groundTemp, & ! intent(in): ground temperature (K) - ! input: canopy and ground emissivity - emc, & ! intent(in): canopy emissivity (-) - emg, & ! intent(in): ground emissivity (-) - ! input: forcing - LWRadUbound, & ! intent(in): downwelling longwave radiation at the upper boundary (W m-2) - ! output: sources - LWRadCanopy, & ! intent(out): longwave radiation emitted from the canopy (W m-2) - LWRadGround, & ! intent(out): longwave radiation emitted at the ground surface (W m-2) - ! output: individual fluxes - LWRadUbound2Canopy, & ! intent(out): downward atmospheric longwave radiation absorbed by the canopy (W m-2) - LWRadUbound2Ground, & ! intent(out): downward atmospheric longwave radiation absorbed by the ground (W m-2) - LWRadUbound2Ubound, & ! intent(out): atmospheric radiation reflected by the ground and lost thru upper boundary (W m-2) - LWRadCanopy2Ubound, & ! intent(out): longwave radiation emitted from canopy lost thru upper boundary (W m-2) - LWRadCanopy2Ground, & ! intent(out): longwave radiation emitted from canopy absorbed by the ground (W m-2) - LWRadCanopy2Canopy, & ! intent(out): canopy longwave reflected from ground and absorbed by the canopy (W m-2) - LWRadGround2Ubound, & ! intent(out): longwave radiation emitted from ground lost thru upper boundary (W m-2) - LWRadGround2Canopy, & ! intent(out): longwave radiation emitted from ground and absorbed by the canopy (W m-2) - ! output: net fluxes - LWNetCanopy, & ! intent(out): net longwave radiation at the canopy (W m-2) - LWNetGround, & ! intent(out): net longwave radiation at the ground surface (W m-2) - LWNetUbound, & ! intent(out): net longwave radiation at the upper boundary (W m-2) - ! output: flux derivatives - dLWNetCanopy_dTCanopy, & ! intent(out): derivative in net canopy radiation w.r.t. canopy temperature (W m-2 K-1) - dLWNetGround_dTGround, & ! intent(out): derivative in net ground radiation w.r.t. ground temperature (W m-2 K-1) - dLWNetCanopy_dTGround, & ! intent(out): derivative in net canopy radiation w.r.t. ground temperature (W m-2 K-1) - dLWNetGround_dTCanopy, & ! intent(out): derivative in net ground radiation w.r.t. canopy temperature (W m-2 K-1) - ! output: error control - err,message ) ! intent(out): error control - ! ----------------------------------------------------------------------------------------------------------------------------------------------- - implicit none - ! input: model control - integer(i4b),intent(in) :: ixDerivMethod ! choice of method used to compute derivative (analytical or numerical) - logical(lgt),intent(in) :: computeVegFlux ! flag to indicate if computing fluxes over vegetation - logical(lgt),intent(in) :: requireLWBal ! flag to indicate if we need longwave to be balanced - ! input: canopy and ground temperature - real(rkind),intent(in) :: canopyTemp ! canopy temperature (K) - real(rkind),intent(in) :: groundTemp ! ground temperature (K) - ! input: canopy and ground emissivity - real(rkind),intent(in) :: emc ! canopy emissivity (-) - real(rkind),intent(in) :: emg ! ground emissivity (-) - ! input: forcing - real(rkind),intent(in) :: LWRadUbound ! downwelling longwave radiation at the upper boundary (W m-2) - ! output: sources - real(rkind),intent(out) :: LWRadCanopy ! longwave radiation emitted from the canopy (W m-2) - real(rkind),intent(out) :: LWRadGround ! longwave radiation emitted at the ground surface (W m-2) - ! output: individual fluxes - real(rkind),intent(out) :: LWRadUbound2Canopy ! downward atmospheric longwave radiation absorbed by the canopy (W m-2) - real(rkind),intent(out) :: LWRadUbound2Ground ! downward atmospheric longwave radiation absorbed by the ground (W m-2) - real(rkind),intent(out) :: LWRadUbound2Ubound ! atmospheric radiation reflected by the ground and lost thru upper boundary (W m-2) - real(rkind),intent(out) :: LWRadCanopy2Ubound ! longwave radiation emitted from canopy lost thru upper boundary (W m-2) - real(rkind),intent(out) :: LWRadCanopy2Ground ! longwave radiation emitted from canopy absorbed by the ground (W m-2) - real(rkind),intent(out) :: LWRadCanopy2Canopy ! canopy longwave reflected from ground and absorbed by the canopy (W m-2) - real(rkind),intent(out) :: LWRadGround2Ubound ! longwave radiation emitted from ground lost thru upper boundary (W m-2) - real(rkind),intent(out) :: LWRadGround2Canopy ! longwave radiation emitted from ground and absorbed by the canopy (W m-2) - ! output: net fluxes - real(rkind),intent(out) :: LWNetCanopy ! net longwave radiation at the canopy (W m-2) - real(rkind),intent(out) :: LWNetGround ! net longwave radiation at the ground surface (W m-2) - real(rkind),intent(out) :: LWNetUbound ! net longwave radiation at the upper boundary (W m-2) - ! output: flux derivatives - real(rkind),intent(out) :: dLWNetCanopy_dTCanopy ! derivative in net canopy radiation w.r.t. canopy temperature (W m-2 K-1) - real(rkind),intent(out) :: dLWNetGround_dTGround ! derivative in net ground radiation w.r.t. ground temperature (W m-2 K-1) - real(rkind),intent(out) :: dLWNetCanopy_dTGround ! derivative in net canopy radiation w.r.t. ground temperature (W m-2 K-1) - real(rkind),intent(out) :: dLWNetGround_dTCanopy ! derivative in net ground radiation w.r.t. canopy temperature (W m-2 K-1) - ! output: error control - integer(i4b),intent(out) :: err ! error code - character(*),intent(out) :: message ! error message - ! ----------------------------------------------------------------------------------------------------------------------------------------------- - ! local variables - integer(i4b),parameter :: unperturbed=1 ! named variable to identify the case of unperturbed state variables - integer(i4b),parameter :: perturbStateCanopy=2 ! named variable to identify the case where we perturb the canopy temperature - integer(i4b),parameter :: perturbStateGround=3 ! named variable to identify the case where we perturb the ground temperature - integer(i4b) :: itry ! index of flux evaluation - integer(i4b) :: nFlux ! number of flux evaluations - real(rkind) :: TCan ! value of canopy temperature used in flux calculations (may be perturbed) - real(rkind) :: TGnd ! value of ground temperature used in flux calculations (may be perturbed) - real(rkind) :: fluxBalance ! check energy closure (W m-2) - real(rkind),parameter :: fluxTolerance=1.e-10_rkind ! tolerance for energy closure (W m-2) - real(rkind) :: dLWRadCanopy_dTCanopy ! derivative in emitted radiation at the canopy w.r.t. canopy temperature - real(rkind) :: dLWRadGround_dTGround ! derivative in emitted radiation at the ground w.r.t. ground temperature - real(rkind) :: LWNetCanopy_dStateCanopy ! net lw canopy flux after perturbation in canopy temperature - real(rkind) :: LWNetGround_dStateCanopy ! net lw ground flux after perturbation in canopy temperature - real(rkind) :: LWNetCanopy_dStateGround ! net lw canopy flux after perturbation in ground temperature - real(rkind) :: LWNetGround_dStateGround ! net lw ground flux after perturbation in ground temperature - ! ----------------------------------------------------------------------------------------------------------------------------------------------- - ! initialize error control - err=0; message='longwaveBal/' - - ! check the need to compute numerical derivatives - if(ixDerivMethod==numerical)then - nFlux=3 ! compute the derivatives using one-sided finite differences - else - nFlux=1 ! compute analytical derivatives - end if - - ! either one or multiple flux calls, depending on if using analytical or numerical derivatives - do itry=nFlux,1,-1 ! (work backwards to ensure all computed fluxes come from the un-perturbed case) - - !print*, 'perturbation: ', (itry==unperturbed), (itry==perturbStateCanopy), (itry==perturbStateGround) - - ! ------------------------------------------------------------------------------------- - ! state perturbations for numerical deriavtives with one-sided finite differences - ! note: no perturbations performed using analytical derivatives (nFlux=1) - ! ------------------------------------------------------------------------------------- - - ! identify the type of perturbation - select case(itry) - - ! un-perturbed case - case(unperturbed) + end if + + ! outside limits: special case of smooth exponents + else + if(xArg < 0._rkind)then; smoothFunc = 0._rkind ! xArg < -xLimit + else; smoothFunc = 1._rkind ! xArg > xLimit + end if + smoothFuncDeriv = 0._rkind + end if ! check for huge exponents + +end subroutine logisticSmoother + ! -------------------------------------------------------------------------------------------------------------- + + +! ******************************************************************************************************* +! private subroutine longwaveBal: compute longwave radiation balance at the canopy and ground surface +! ******************************************************************************************************* +subroutine longwaveBal(& + ! input: model control + ixDerivMethod, & ! intent(in): choice of method used to compute derivative (analytical or numerical) + computeVegFlux, & ! intent(in): flag to compute fluxes over vegetati + insideIDA, & ! intent(in): flag to indicate inside Sundials Solver (do not require longwave to be balanced) + ! input: canopy and ground temperature + canopyTemp, & ! intent(in): canopy temperature (K) + groundTemp, & ! intent(in): ground temperature (K) + ! input: canopy and ground emissivity + emc, & ! intent(in): canopy emissivity (-) + emg, & ! intent(in): ground emissivity (-) + ! input: forcing + LWRadUbound, & ! intent(in): downwelling longwave radiation at the upper boundary (W m-2) + ! output: sources + LWRadCanopy, & ! intent(out): longwave radiation emitted from the canopy (W m-2) + LWRadGround, & ! intent(out): longwave radiation emitted at the ground surface (W m-2) + ! output: individual fluxes + LWRadUbound2Canopy, & ! intent(out): downward atmospheric longwave radiation absorbed by the canopy (W m-2) + LWRadUbound2Ground, & ! intent(out): downward atmospheric longwave radiation absorbed by the ground (W m-2) + LWRadUbound2Ubound, & ! intent(out): atmospheric radiation reflected by the ground and lost thru upper boundary (W m-2) + LWRadCanopy2Ubound, & ! intent(out): longwave radiation emitted from canopy lost thru upper boundary (W m-2) + LWRadCanopy2Ground, & ! intent(out): longwave radiation emitted from canopy absorbed by the ground (W m-2) + LWRadCanopy2Canopy, & ! intent(out): canopy longwave reflected from ground and absorbed by the canopy (W m-2) + LWRadGround2Ubound, & ! intent(out): longwave radiation emitted from ground lost thru upper boundary (W m-2) + LWRadGround2Canopy, & ! intent(out): longwave radiation emitted from ground and absorbed by the canopy (W m-2) + ! output: net fluxes + LWNetCanopy, & ! intent(out): net longwave radiation at the canopy (W m-2) + LWNetGround, & ! intent(out): net longwave radiation at the ground surface (W m-2) + LWNetUbound, & ! intent(out): net longwave radiation at the upper boundary (W m-2) + ! output: flux derivatives + dLWNetCanopy_dTCanopy, & ! intent(out): derivative in net canopy radiation w.r.t. canopy temperature (W m-2 K-1) + dLWNetGround_dTGround, & ! intent(out): derivative in net ground radiation w.r.t. ground temperature (W m-2 K-1) + dLWNetCanopy_dTGround, & ! intent(out): derivative in net canopy radiation w.r.t. ground temperature (W m-2 K-1) + dLWNetGround_dTCanopy, & ! intent(out): derivative in net ground radiation w.r.t. canopy temperature (W m-2 K-1) + ! output: error control + err,message ) ! intent(out): error control + ! ----------------------------------------------------------------------------------------------------------------------------------------------- + implicit none + ! input: model control + integer(i4b),intent(in) :: ixDerivMethod ! choice of method used to compute derivative (analytical or numerical) + logical(lgt),intent(in) :: computeVegFlux ! flag to indicate if computing fluxes over vegetation + logical(lgt),intent(in) :: insideIDA ! flag if inside Sundials solver + ! input: canopy and ground temperature + real(rkind),intent(in) :: canopyTemp ! canopy temperature (K) + real(rkind),intent(in) :: groundTemp ! ground temperature (K) + ! input: canopy and ground emissivity + real(rkind),intent(in) :: emc ! canopy emissivity (-) + real(rkind),intent(in) :: emg ! ground emissivity (-) + ! input: forcing + real(rkind),intent(in) :: LWRadUbound ! downwelling longwave radiation at the upper boundary (W m-2) + ! output: sources + real(rkind),intent(out) :: LWRadCanopy ! longwave radiation emitted from the canopy (W m-2) + real(rkind),intent(out) :: LWRadGround ! longwave radiation emitted at the ground surface (W m-2) + ! output: individual fluxes + real(rkind),intent(out) :: LWRadUbound2Canopy ! downward atmospheric longwave radiation absorbed by the canopy (W m-2) + real(rkind),intent(out) :: LWRadUbound2Ground ! downward atmospheric longwave radiation absorbed by the ground (W m-2) + real(rkind),intent(out) :: LWRadUbound2Ubound ! atmospheric radiation reflected by the ground and lost thru upper boundary (W m-2) + real(rkind),intent(out) :: LWRadCanopy2Ubound ! longwave radiation emitted from canopy lost thru upper boundary (W m-2) + real(rkind),intent(out) :: LWRadCanopy2Ground ! longwave radiation emitted from canopy absorbed by the ground (W m-2) + real(rkind),intent(out) :: LWRadCanopy2Canopy ! canopy longwave reflected from ground and absorbed by the canopy (W m-2) + real(rkind),intent(out) :: LWRadGround2Ubound ! longwave radiation emitted from ground lost thru upper boundary (W m-2) + real(rkind),intent(out) :: LWRadGround2Canopy ! longwave radiation emitted from ground and absorbed by the canopy (W m-2) + ! output: net fluxes + real(rkind),intent(out) :: LWNetCanopy ! net longwave radiation at the canopy (W m-2) + real(rkind),intent(out) :: LWNetGround ! net longwave radiation at the ground surface (W m-2) + real(rkind),intent(out) :: LWNetUbound ! net longwave radiation at the upper boundary (W m-2) + ! output: flux derivatives + real(rkind),intent(out) :: dLWNetCanopy_dTCanopy ! derivative in net canopy radiation w.r.t. canopy temperature (W m-2 K-1) + real(rkind),intent(out) :: dLWNetGround_dTGround ! derivative in net ground radiation w.r.t. ground temperature (W m-2 K-1) + real(rkind),intent(out) :: dLWNetCanopy_dTGround ! derivative in net canopy radiation w.r.t. ground temperature (W m-2 K-1) + real(rkind),intent(out) :: dLWNetGround_dTCanopy ! derivative in net ground radiation w.r.t. canopy temperature (W m-2 K-1) + ! output: error control + integer(i4b),intent(out) :: err ! error code + character(*),intent(out) :: message ! error message + ! ----------------------------------------------------------------------------------------------------------------------------------------------- + ! local variables + integer(i4b),parameter :: unperturbed=1 ! named variable to identify the case of unperturbed state variables + integer(i4b),parameter :: perturbStateCanopy=2 ! named variable to identify the case where we perturb the canopy temperature + integer(i4b),parameter :: perturbStateGround=3 ! named variable to identify the case where we perturb the ground temperature + integer(i4b) :: itry ! index of flux evaluation + integer(i4b) :: nFlux ! number of flux evaluations + real(rkind) :: TCan ! value of canopy temperature used in flux calculations (may be perturbed) + real(rkind) :: TGnd ! value of ground temperature used in flux calculations (may be perturbed) + real(rkind) :: fluxBalance ! check energy closure (W m-2) + real(rkind),parameter :: fluxTolerance=1.e-10_rkind ! tolerance for energy closure (W m-2) + real(rkind) :: dLWRadCanopy_dTCanopy ! derivative in emitted radiation at the canopy w.r.t. canopy temperature + real(rkind) :: dLWRadGround_dTGround ! derivative in emitted radiation at the ground w.r.t. ground temperature + real(rkind) :: LWNetCanopy_dStateCanopy ! net lw canopy flux after perturbation in canopy temperature + real(rkind) :: LWNetGround_dStateCanopy ! net lw ground flux after perturbation in canopy temperature + real(rkind) :: LWNetCanopy_dStateGround ! net lw canopy flux after perturbation in ground temperature + real(rkind) :: LWNetGround_dStateGround ! net lw ground flux after perturbation in ground temperature + ! ----------------------------------------------------------------------------------------------------------------------------------------------- + ! initialize error control + err=0; message='longwaveBal/' + + ! check the need to compute numerical derivatives + if(ixDerivMethod==numerical)then + nFlux=3 ! compute the derivatives using one-sided finite differences + else + nFlux=1 ! compute analytical derivatives + end if + + ! either one or multiple flux calls, depending on if using analytical or numerical derivatives + do itry=nFlux,1,-1 ! (work backwards to ensure all computed fluxes come from the un-perturbed case) + + ! ------------------------------------------------------------------------------------- + ! state perturbations for numerical deriavtives with one-sided finite differences + ! note: no perturbations performed using analytical derivatives (nFlux=1) + ! ------------------------------------------------------------------------------------- + + ! identify the type of perturbation + select case(itry) + + ! un-perturbed case + case(unperturbed) TCan = canopyTemp TGnd = groundTemp - - ! perturb canopy temperature - case(perturbStateCanopy) + + ! perturb canopy temperature + case(perturbStateCanopy) TCan = canopyTemp + dx TGnd = groundTemp - - ! perturb ground temperature - case(perturbStateGround) + + ! perturb ground temperature + case(perturbStateGround) TCan = canopyTemp TGnd = groundTemp + dx - - ! check for an unknown perturbation - case default; err=10; message=trim(message)//"unknown perturbation"; return - - end select ! (type of perturbation) - - ! ------------------------------------------------------------------------------------- - ! calculation block (unperturbed fluxes returned [computed last]) - ! ------------------------------------------------------------------------------------- - ! NOTE: emc should be set to zero when not computing canopy fluxes - - ! compute longwave fluxes from canopy and the ground - if(computeVegFlux)then - LWRadCanopy = emc*sb*TCan**4._rkind ! longwave radiation emitted from the canopy (W m-2) - else - LWRadCanopy = 0._rkind - end if - LWRadGround = emg*sb*TGnd**4._rkind ! longwave radiation emitted at the ground surface (W m-2) - - ! compute fluxes originating from the atmosphere - LWRadUbound2Canopy = (emc + (1._rkind - emc)*(1._rkind - emg)*emc)*LWRadUbound ! downward atmospheric longwave radiation absorbed by the canopy (W m-2) - LWRadUbound2Ground = (1._rkind - emc)*emg*LWRadUbound ! downward atmospheric longwave radiation absorbed by the ground (W m-2) - LWRadUbound2Ubound = (1._rkind - emc)*(1._rkind - emg)*(1._rkind - emc)*LWRadUbound ! atmospheric radiation reflected by the ground and lost thru upper boundary (W m-2) - - ! compute fluxes originating from the canopy - LWRadCanopy2Ubound = (1._rkind + (1._rkind - emc)*(1._rkind - emg))*LWRadCanopy ! longwave radiation emitted from canopy lost thru upper boundary (W m-2) - LWRadCanopy2Ground = emg*LWRadCanopy ! longwave radiation emitted from canopy absorbed by the ground (W m-2) - LWRadCanopy2Canopy = emc*(1._rkind - emg)*LWRadCanopy ! canopy longwave reflected from ground and absorbed by the canopy (W m-2) - - ! compute fluxes originating from the ground surface - LWRadGround2Ubound = (1._rkind - emc)*LWRadGround ! longwave radiation emitted from ground lost thru upper boundary (W m-2) - LWRadGround2Canopy = emc*LWRadGround ! longwave radiation emitted from ground and absorbed by the canopy (W m-2) - - ! compute net longwave radiation (W m-2) - LWNetCanopy = LWRadUbound2Canopy + LWRadGround2Canopy + LWRadCanopy2Canopy - 2._rkind*LWRadCanopy ! canopy - LWNetGround = LWRadUbound2Ground + LWRadCanopy2Ground - LWRadGround ! ground surface - LWNetUbound = LWRadUbound - LWRadUbound2Ubound - LWRadCanopy2Ubound - LWRadGround2Ubound ! upper boundary - - !print*, 'LWRadCanopy = ', LWRadCanopy - !print*, 'LWRadGround = ', LWRadGround - - !print*, 'LWNetCanopy = ', LWNetCanopy - !print*, 'LWNetGround = ', LWNetGround - !print*, 'LWNetUbound = ', LWNetUbound - - ! check the flux balance - if(requireLWBal)then - fluxBalance = LWNetUbound - (LWNetCanopy + LWNetGround) - if(abs(fluxBalance) > fluxTolerance)then + + ! check for an unknown perturbation + case default; err=10; message=trim(message)//"unknown perturbation"; return + + end select ! (type of perturbation) + + ! ------------------------------------------------------------------------------------- + ! calculation block (unperturbed fluxes returned [computed last]) + ! ------------------------------------------------------------------------------------- + ! NOTE: emc should be set to zero when not computing canopy fluxes + + ! compute longwave fluxes from canopy and the ground + if(computeVegFlux)then + LWRadCanopy = emc*sb*TCan**4._rkind ! longwave radiation emitted from the canopy (W m-2) + else + LWRadCanopy = 0._rkind + end if + LWRadGround = emg*sb*TGnd**4._rkind ! longwave radiation emitted at the ground surface (W m-2) + + ! compute fluxes originating from the atmosphere + LWRadUbound2Canopy = (emc + (1._rkind - emc)*(1._rkind - emg)*emc)*LWRadUbound ! downward atmospheric longwave radiation absorbed by the canopy (W m-2) + LWRadUbound2Ground = (1._rkind - emc)*emg*LWRadUbound ! downward atmospheric longwave radiation absorbed by the ground (W m-2) + LWRadUbound2Ubound = (1._rkind - emc)*(1._rkind - emg)*(1._rkind - emc)*LWRadUbound ! atmospheric radiation reflected by the ground and lost thru upper boundary (W m-2) + + ! compute fluxes originating from the canopy + LWRadCanopy2Ubound = (1._rkind + (1._rkind - emc)*(1._rkind - emg))*LWRadCanopy ! longwave radiation emitted from canopy lost thru upper boundary (W m-2) + LWRadCanopy2Ground = emg*LWRadCanopy ! longwave radiation emitted from canopy absorbed by the ground (W m-2) + LWRadCanopy2Canopy = emc*(1._rkind - emg)*LWRadCanopy ! canopy longwave reflected from ground and absorbed by the canopy (W m-2) + + ! compute fluxes originating from the ground surface + LWRadGround2Ubound = (1._rkind - emc)*LWRadGround ! longwave radiation emitted from ground lost thru upper boundary (W m-2) + LWRadGround2Canopy = emc*LWRadGround ! longwave radiation emitted from ground and absorbed by the canopy (W m-2) + + ! compute net longwave radiation (W m-2) + LWNetCanopy = LWRadUbound2Canopy + LWRadGround2Canopy + LWRadCanopy2Canopy - 2._rkind*LWRadCanopy ! canopy + LWNetGround = LWRadUbound2Ground + LWRadCanopy2Ground - LWRadGround ! ground surface + LWNetUbound = LWRadUbound - LWRadUbound2Ubound - LWRadCanopy2Ubound - LWRadGround2Ubound ! upper boundary + + ! check the flux balance + if(.not.insideIDA)then + fluxBalance = LWNetUbound - (LWNetCanopy + LWNetGround) + if(abs(fluxBalance) > fluxTolerance)then print*, 'fluxBalance = ', fluxBalance print*, 'emg, emc = ', emg, emc print*, 'TCan, TGnd = ', TCan, TGnd @@ -1974,239 +1881,239 @@ module vegNrgFlux_module print*, 'LWNetUbound = ', LWNetUbound message=trim(message)//'flux imbalance' err=20; return - end if end if - - ! -------------------------------------------------------------------------------------- - ! save perturbed fluxes to calculate numerical derivatives (one-sided finite difference) - ! -------------------------------------------------------------------------------------- - if(ixDerivMethod==numerical)then - select case(itry) ! (select type of perturbation) + end if + + ! -------------------------------------------------------------------------------------- + ! save perturbed fluxes to calculate numerical derivatives (one-sided finite difference) + ! -------------------------------------------------------------------------------------- + if(ixDerivMethod==numerical)then + select case(itry) ! (select type of perturbation) case(unperturbed); exit case(perturbStateCanopy) - LWNetCanopy_dStateCanopy = LWNetCanopy - LWNetGround_dStateCanopy = LWNetGround + LWNetCanopy_dStateCanopy = LWNetCanopy + LWNetGround_dStateCanopy = LWNetGround case(perturbStateGround) - LWNetCanopy_dStateGround = LWNetCanopy - LWNetGround_dStateGround = LWNetGround + LWNetCanopy_dStateGround = LWNetCanopy + LWNetGround_dStateGround = LWNetGround case default; err=10; message=trim(message)//"unknown perturbation"; return - end select ! (type of perturbation) - end if ! (if numerical) - - end do ! looping through different perturbations - - ! ------------------------------------------------------------------------------------- - ! compute derivatives - ! ------------------------------------------------------------------------------------- - select case(ixDerivMethod) - - ! ***** analytical derivatives - case(analytical) - ! compute initial derivatives - dLWRadCanopy_dTCanopy = 4._rkind*emc*sb*TCan**3._rkind - dLWRadGround_dTGround = 4._rkind*emg*sb*TGnd**3._rkind - ! compute analytical derivatives - dLWNetCanopy_dTCanopy = (emc*(1._rkind - emg) - 2._rkind)*dLWRadCanopy_dTCanopy ! derivative in net canopy radiation w.r.t. canopy temperature (W m-2 K-1) - dLWNetGround_dTGround = -dLWRadGround_dTGround ! derivative in net ground radiation w.r.t. ground temperature (W m-2 K-1) - dLWNetCanopy_dTGround = emc*dLWRadGround_dTGround ! derivative in net canopy radiation w.r.t. ground temperature (W m-2 K-1) - dLWNetGround_dTCanopy = emg*dLWRadCanopy_dTCanopy ! derivative in net ground radiation w.r.t. canopy temperature (W m-2 K-1) - - ! ***** numerical derivatives - case(numerical) - ! compute numerical derivatives (one-sided finite differences) - dLWNetCanopy_dTCanopy = (LWNetCanopy_dStateCanopy - LWNetCanopy)/dx ! derivative in net canopy radiation w.r.t. canopy temperature (W m-2 K-1) - dLWNetGround_dTGround = (LWNetGround_dStateGround - LWNetGround)/dx ! derivative in net ground radiation w.r.t. ground temperature (W m-2 K-1) - dLWNetCanopy_dTGround = (LWNetCanopy_dStateGround - LWNetCanopy)/dx ! derivative in net canopy radiation w.r.t. ground temperature (W m-2 K-1) - dLWNetGround_dTCanopy = (LWNetGround_dStateCanopy - LWNetGround)/dx ! derivative in net ground radiation w.r.t. canopy temperature (W m-2 K-1) - - ! ***** error check - case default; err=10; message=trim(message)//"unknown method to calculate derivatives"; return - - end select ! (type of method to calculate derivatives) - - end subroutine longwaveBal - - - ! ******************************************************************************************************* - ! private subroutine aeroResist: compute aerodynamic resistances - ! ******************************************************************************************************* - subroutine aeroResist(& - ! input: model control - computeVegFlux, & ! intent(in): logical flag to compute vegetation fluxes (.false. if veg buried by snow) - derivDesired, & ! intent(in): flag to indicate if analytical derivatives are desired - ixVegTraits, & ! intent(in): choice of parameterization for vegetation roughness length and displacement height - ixWindProfile, & ! intent(in): choice of canopy wind profile - ixStability, & ! intent(in): choice of stability function - ! input: above-canopy forcing data - mHeight, & ! intent(in): measurement height (m) - airtemp, & ! intent(in): air temperature at some height above the surface (K) - windspd, & ! intent(in): wind speed at some height above the surface (m s-1) - ! input: temperature (canopy, ground, canopy air space) - canairTemp, & ! intent(in): temperature of the canopy air space (K) - groundTemp, & ! intent(in): ground temperature (K) - ! input: diagnostic variables - exposedVAI, & ! intent(in): exposed vegetation area index -- leaf plus stem (m2 m-2) - snowDepth, & ! intent(in): snow depth (m) - ! input: parameters - z0Ground, & ! intent(in): roughness length of the ground (below canopy or non-vegetated surface [snow]) (m) - z0CanopyParam, & ! intent(in): roughness length of the canopy (m) - zpdFraction, & ! intent(in): zero plane displacement / canopy height (-) - critRichNumber, & ! intent(in): critical value for the bulk Richardson number where turbulence ceases (-) - Louis79_bparam, & ! intent(in): parameter in Louis (1979) stability function - Mahrt87_eScale, & ! intent(in): exponential scaling factor in the Mahrt (1987) stability function - windReductionParam, & ! intent(in): canopy wind reduction parameter (-) - leafExchangeCoeff, & ! intent(in): turbulent exchange coeff between canopy surface and canopy air ( m s-(1/2) ) - leafDimension, & ! intent(in): characteristic leaf dimension (m) - heightCanopyTop, & ! intent(in): height at the top of the vegetation canopy (m) - heightCanopyBottom, & ! intent(in): height at the bottom of the vegetation canopy (m) - ! output: stability corrections - RiBulkCanopy, & ! intent(out): bulk Richardson number for the canopy (-) - RiBulkGround, & ! intent(out): bulk Richardson number for the ground surface (-) - canopyStabilityCorrection, & ! intent(out): stability correction for the canopy (-) - groundStabilityCorrection, & ! intent(out): stability correction for the ground surface (-) - ! output: scalar resistances - z0Canopy, & ! intent(out): roughness length of the canopy (m) - windReductionFactor, & ! intent(out): canopy wind reduction factor (-) - zeroPlaneDisplacement, & ! intent(out): zero plane displacement (m) - eddyDiffusCanopyTop, & ! intent(out): eddy diffusivity for heat at the top of the canopy (m2 s-1) - frictionVelocity, & ! intent(out): friction velocity (m s-1) - windspdCanopyTop, & ! intent(out): windspeed at the top of the canopy (m s-1) - windspdCanopyBottom, & ! intent(out): windspeed at the height of the bottom of the canopy (m s-1) - leafResistance, & ! intent(out): mean leaf boundary layer resistance per unit leaf area (s m-1) - groundResistance, & ! intent(out): below canopy aerodynamic resistance (s m-1) - canopyResistance, & ! intent(out): above canopy aerodynamic resistance (s m-1) - ! output: derivatives in scalar resistances - dGroundResistance_dTGround, & ! intent(out): derivative in ground resistance w.r.t. ground temperature (s m-1 K-1) - dGroundResistance_dTCanopy, & ! intent(out): derivative in ground resistance w.r.t. canopy temperature (s m-1 K-1) - dGroundResistance_dTCanair, & ! intent(out): derivative in ground resistance w.r.t. canopy air temperature (s m-1 K-1) - dCanopyResistance_dTCanopy, & ! intent(out): derivative in canopy resistance w.r.t. canopy temperature (s m-1 K-1) - dCanopyResistance_dTCanair, & ! intent(out): derivative in canopy resistance w.r.t. canopy air temperature (s m-1 K-1) - ! output: error control - err,message ) ! intent(out): error control - ! ----------------------------------------------------------------------------------------------------------------------------------------- - ! compute aerodynamic resistances - ! Refs: Choudhury and Monteith (4-layer model for heat budget of homogenous surfaces; QJRMS, 1988) - ! Niu and Yang (Canopy effects on snow processes; JGR, 2004) - ! Mahat et al. (Below-canopy turbulence in a snowmelt model, WRR, 2012) - implicit none - ! input: model control - logical(lgt),intent(in) :: computeVegFlux ! logical flag to compute vegetation fluxes (.false. if veg buried by snow) - logical(lgt),intent(in) :: derivDesired ! logical flag to indicate if analytical derivatives are desired - integer(i4b),intent(in) :: ixVegTraits ! choice of parameterization for vegetation roughness length and displacement height - integer(i4b),intent(in) :: ixWindProfile ! choice of canopy wind profile - integer(i4b),intent(in) :: ixStability ! choice of stability function - ! input: above-canopy forcing data - real(rkind),intent(in) :: mHeight ! measurement height (m) - real(rkind),intent(in) :: airtemp ! air temperature at some height above the surface (K) - real(rkind),intent(in) :: windspd ! wind speed at some height above the surface (m s-1) - ! input: temperature (canopy, ground, canopy air space) - real(rkind),intent(in) :: canairTemp ! temperature of the canopy air space (K) - real(rkind),intent(in) :: groundTemp ! ground temperature (K) - ! input: diagnostic variables - real(rkind),intent(in) :: exposedVAI ! exposed vegetation area index -- leaf plus stem (m2 m-2) - real(rkind),intent(in) :: snowDepth ! snow depth (m) - ! input: parameters - real(rkind),intent(in) :: z0Ground ! roughness length of the ground (below canopy or non-vegetated surface [snow]) (m) - real(rkind),intent(in) :: z0CanopyParam ! roughness length of the canopy (m) - real(rkind),intent(in) :: zpdFraction ! zero plane displacement / canopy height (-) - real(rkind),intent(in) :: critRichNumber ! critical value for the bulk Richardson number where turbulence ceases (-) - real(rkind),intent(in) :: Louis79_bparam ! parameter in Louis (1979) stability function - real(rkind),intent(in) :: Mahrt87_eScale ! exponential scaling factor in the Mahrt (1987) stability function - real(rkind),intent(in) :: windReductionParam ! canopy wind reduction parameter (-) - real(rkind),intent(in) :: leafExchangeCoeff ! turbulent exchange coeff between canopy surface and canopy air ( m s-(1/2) ) - real(rkind),intent(in) :: leafDimension ! characteristic leaf dimension (m) - real(rkind),intent(in) :: heightCanopyTop ! height at the top of the vegetation canopy (m) - real(rkind),intent(in) :: heightCanopyBottom ! height at the bottom of the vegetation canopy (m) - ! output: stability corrections - real(rkind),intent(out) :: RiBulkCanopy ! bulk Richardson number for the canopy (-) - real(rkind),intent(out) :: RiBulkGround ! bulk Richardson number for the ground surface (-) - real(rkind),intent(out) :: canopyStabilityCorrection ! stability correction for the canopy (-) - real(rkind),intent(out) :: groundStabilityCorrection ! stability correction for the ground surface (-) - ! output: scalar resistances - real(rkind),intent(out) :: z0Canopy ! roughness length of the vegetation canopy (m) - real(rkind),intent(out) :: windReductionFactor ! canopy wind reduction factor (-) - real(rkind),intent(out) :: zeroPlaneDisplacement ! zero plane displacement (m) - real(rkind),intent(out) :: eddyDiffusCanopyTop ! eddy diffusivity for heat at the top of the canopy (m2 s-1) - real(rkind),intent(out) :: frictionVelocity ! friction velocity (m s-1) - real(rkind),intent(out) :: windspdCanopyTop ! windspeed at the top of the canopy (m s-1) - real(rkind),intent(out) :: windspdCanopyBottom ! windspeed at the height of the bottom of the canopy (m s-1) - real(rkind),intent(out) :: leafResistance ! mean leaf boundary layer resistance per unit leaf area (s m-1) - real(rkind),intent(out) :: groundResistance ! below canopy aerodynamic resistance (s m-1) - real(rkind),intent(out) :: canopyResistance ! above canopy aerodynamic resistance (s m-1) - ! output: derivatives in scalar resistances - real(rkind),intent(out) :: dGroundResistance_dTGround ! derivative in ground resistance w.r.t. ground temperature (s m-1 K-1) - real(rkind),intent(out) :: dGroundResistance_dTCanopy ! derivative in ground resistance w.r.t. canopy temperature (s m-1 K-1) - real(rkind),intent(out) :: dGroundResistance_dTCanair ! derivative in ground resistance w.r.t. canopy air temperature (s m-1 K-1) - real(rkind),intent(out) :: dCanopyResistance_dTCanopy ! derivative in canopy resistance w.r.t. canopy temperature (s m-1 K-1) - real(rkind),intent(out) :: dCanopyResistance_dTCanair ! derivative in canopy resistance w.r.t. canopy air temperature (s m-1 K-1) - ! output: error control - integer(i4b),intent(out) :: err ! error code - character(*),intent(out) :: message ! error message - ! ----------------------------------------------------------------------------------------------------------------------------------------- - ! local variables: general - character(LEN=256) :: cmessage ! error message of downwind routine - ! local variables: vegetation roughness and dispalcement height - real(rkind),parameter :: oneThird=1._rkind/3._rkind ! 1/3 - real(rkind),parameter :: twoThirds=2._rkind/3._rkind ! 2/3 - real(rkind),parameter :: C_r = 0.3 ! roughness element drag coefficient (-) from Raupach (BLM, 1994) - real(rkind),parameter :: C_s = 0.003_rkind ! substrate surface drag coefficient (-) from Raupach (BLM, 1994) - real(rkind),parameter :: approxDragCoef_max = 0.3_rkind ! maximum value of the approximate drag coefficient (-) from Raupach (BLM, 1994) - real(rkind),parameter :: psi_h = 0.193_rkind ! roughness sub-layer influence function (-) from Raupach (BLM, 1994) - real(rkind),parameter :: c_d1 = 7.5_rkind ! scaling parameter used to define displacement height (-) from Raupach (BLM, 1994) - real(rkind),parameter :: cd_CM = 0.2_rkind ! mean drag coefficient for individual leaves (-) from Choudhury and Monteith (QJRMS, 1988) - real(rkind) :: funcLAI ! temporary variable to calculate zero plane displacement for the canopy - real(rkind) :: fracCanopyHeight ! zero plane displacement expressed as a fraction of canopy height - real(rkind) :: approxDragCoef ! approximate drag coefficient used in the computation of canopy roughness length (-) - ! local variables: resistance - real(rkind) :: canopyExNeut ! surface-atmosphere exchange coefficient under neutral conditions (-) - real(rkind) :: groundExNeut ! surface-atmosphere exchange coefficient under neutral conditions (-) - real(rkind) :: sfc2AtmExchangeCoeff_canopy ! surface-atmosphere exchange coefficient after stability corrections (-) - real(rkind) :: groundResistanceNeutral ! ground resistance under neutral conditions (s m-1) - real(rkind) :: windConvFactor_fv ! factor to convert friction velocity to wind speed at top of canopy (-) - real(rkind) :: windConvFactor ! factor to convert wind speed at top of canopy to wind speed at a given height in the canopy (-) - real(rkind) :: referenceHeight ! z0Canopy+zeroPlaneDisplacement (m) - real(rkind) :: windspdRefHeight ! windspeed at the reference height (m/s) - real(rkind) :: heightAboveGround ! height above the snow surface (m) - real(rkind) :: heightCanopyTopAboveSnow ! height at the top of the vegetation canopy relative to snowpack (m) - real(rkind) :: heightCanopyBottomAboveSnow ! height at the bottom of the vegetation canopy relative to snowpack (m) - real(rkind),parameter :: xTolerance=0.1_rkind ! tolerance to handle the transition from exponential to log-below canopy - ! local variables: derivatives - real(rkind) :: dFV_dT ! derivative in friction velocity w.r.t. canopy air temperature - real(rkind) :: dED_dT ! derivative in eddy diffusivity at the top of the canopy w.r.t. canopy air temperature - real(rkind) :: dGR_dT ! derivative in neutral ground resistance w.r.t. canopy air temperature - real(rkind) :: tmp1,tmp2 ! temporary variables used in calculation of ground resistance - real(rkind) :: dCanopyStabilityCorrection_dRich ! derivative in stability correction w.r.t. Richardson number for the canopy (-) - real(rkind) :: dGroundStabilityCorrection_dRich ! derivative in stability correction w.r.t. Richardson number for the ground surface (-) - real(rkind) :: dCanopyStabilityCorrection_dAirTemp ! (not used) derivative in stability correction w.r.t. air temperature (K-1) - real(rkind) :: dGroundStabilityCorrection_dAirTemp ! (not used) derivative in stability correction w.r.t. air temperature (K-1) - real(rkind) :: dCanopyStabilityCorrection_dCasTemp ! derivative in canopy stability correction w.r.t. canopy air space temperature (K-1) - real(rkind) :: dGroundStabilityCorrection_dCasTemp ! derivative in ground stability correction w.r.t. canopy air space temperature (K-1) - real(rkind) :: dGroundStabilityCorrection_dSfcTemp ! derivative in ground stability correction w.r.t. surface temperature (K-1) - real(rkind) :: singleLeafConductance ! leaf boundary layer conductance (m s-1) - real(rkind) :: canopyLeafConductance ! leaf boundary layer conductance -- scaled up to the canopy (m s-1) - real(rkind) :: leaf2CanopyScaleFactor ! factor to scale from the leaf to the canopy [m s-(1/2)] - ! ----------------------------------------------------------------------------------------------------------------------------------------- - ! initialize error control - err=0; message='aeroResist/' - - ! check that measurement height is above the top of the canopy - if(mHeight < heightCanopyTop)then - err=20; message=trim(message)//'measurement height is below the top of the canopy'; return - end if - - ! ----------------------------------------------------------------------------------------------------------------------------------------- - ! * compute vegetation poperties (could be done at the same time as phenology.. does not have to be in the flux routine!) - if(computeVegFlux) then ! (if vegetation is exposed) - - ! ***** identify zero plane displacement, roughness length, and surface temperature for the canopy (m) - ! First, calculate new coordinate system above snow - use these to scale wind profiles and resistances - ! NOTE: the new coordinate system makes zeroPlaneDisplacement and z0Canopy consistent - heightCanopyTopAboveSnow = heightCanopyTop - snowDepth - heightCanopyBottomAboveSnow = max(heightCanopyBottom - snowDepth, 0.0_rkind) - select case(ixVegTraits) - - ! Raupach (BLM 1994) "Simplified expressions..." - case(Raupach_BLM1994) + end select ! (type of perturbation) + end if ! (if numerical) + + end do ! looping through different perturbations + + ! ------------------------------------------------------------------------------------- + ! compute derivatives + ! ------------------------------------------------------------------------------------- + select case(ixDerivMethod) + + ! ***** analytical derivatives + case(analytical) + ! compute initial derivatives + dLWRadCanopy_dTCanopy = 4._rkind*emc*sb*TCan**3._rkind + dLWRadGround_dTGround = 4._rkind*emg*sb*TGnd**3._rkind + ! compute analytical derivatives + dLWNetCanopy_dTCanopy = (emc*(1._rkind - emg) - 2._rkind)*dLWRadCanopy_dTCanopy ! derivative in net canopy radiation w.r.t. canopy temperature (W m-2 K-1) + dLWNetGround_dTGround = -dLWRadGround_dTGround ! derivative in net ground radiation w.r.t. ground temperature (W m-2 K-1) + dLWNetCanopy_dTGround = emc*dLWRadGround_dTGround ! derivative in net canopy radiation w.r.t. ground temperature (W m-2 K-1) + dLWNetGround_dTCanopy = emg*dLWRadCanopy_dTCanopy ! derivative in net ground radiation w.r.t. canopy temperature (W m-2 K-1) + + ! ***** numerical derivatives + case(numerical) + ! compute numerical derivatives (one-sided finite differences) + dLWNetCanopy_dTCanopy = (LWNetCanopy_dStateCanopy - LWNetCanopy)/dx ! derivative in net canopy radiation w.r.t. canopy temperature (W m-2 K-1) + dLWNetGround_dTGround = (LWNetGround_dStateGround - LWNetGround)/dx ! derivative in net ground radiation w.r.t. ground temperature (W m-2 K-1) + dLWNetCanopy_dTGround = (LWNetCanopy_dStateGround - LWNetCanopy)/dx ! derivative in net canopy radiation w.r.t. ground temperature (W m-2 K-1) + dLWNetGround_dTCanopy = (LWNetGround_dStateCanopy - LWNetGround)/dx ! derivative in net ground radiation w.r.t. canopy temperature (W m-2 K-1) + + ! ***** error check + case default; err=10; message=trim(message)//"unknown method to calculate derivatives"; return + + end select ! (type of method to calculate derivatives) + +end subroutine longwaveBal + + +! ******************************************************************************************************* +! private subroutine aeroResist: compute aerodynamic resistances +! ******************************************************************************************************* +subroutine aeroResist(& + ! input: model control + computeVegFlux, & ! intent(in): logical flag to compute vegetation fluxes (.false. if veg buried by snow) + derivDesired, & ! intent(in): flag to indicate if analytical derivatives are desired + ixVegTraits, & ! intent(in): choice of parameterization for vegetation roughness length and displacement height + ixWindProfile, & ! intent(in): choice of canopy wind profile + ixStability, & ! intent(in): choice of stability function + ! input: above-canopy forcing data + mHeight, & ! intent(in): measurement height (m) + airtemp, & ! intent(in): air temperature at some height above the surface (K) + windspd, & ! intent(in): wind speed at some height above the surface (m s-1) + ! input: temperature (canopy, ground, canopy air space) + canairTemp, & ! intent(in): temperature of the canopy air space (K) + groundTemp, & ! intent(in): ground temperature (K) + ! input: diagnostic variables + exposedVAI, & ! intent(in): exposed vegetation area index -- leaf plus stem (m2 m-2) + snowDepth, & ! intent(in): snow depth (m) + ! input: parameters + z0Ground, & ! intent(in): roughness length of the ground (below canopy or non-vegetated surface [snow]) (m) + z0CanopyParam, & ! intent(in): roughness length of the canopy (m) + zpdFraction, & ! intent(in): zero plane displacement / canopy height (-) + critRichNumber, & ! intent(in): critical value for the bulk Richardson number where turbulence ceases (-) + Louis79_bparam, & ! intent(in): parameter in Louis (1979) stability function + Mahrt87_eScale, & ! intent(in): exponential scaling factor in the Mahrt (1987) stability function + windReductionParam, & ! intent(in): canopy wind reduction parameter (-) + leafExchangeCoeff, & ! intent(in): turbulent exchange coeff between canopy surface and canopy air ( m s-(1/2) ) + leafDimension, & ! intent(in): characteristic leaf dimension (m) + heightCanopyTop, & ! intent(in): height at the top of the vegetation canopy (m) + heightCanopyBottom, & ! intent(in): height at the bottom of the vegetation canopy (m) + ! output: stability corrections + RiBulkCanopy, & ! intent(out): bulk Richardson number for the canopy (-) + RiBulkGround, & ! intent(out): bulk Richardson number for the ground surface (-) + canopyStabilityCorrection, & ! intent(out): stability correction for the canopy (-) + groundStabilityCorrection, & ! intent(out): stability correction for the ground surface (-) + ! output: scalar resistances + z0Canopy, & ! intent(out): roughness length of the canopy (m) + windReductionFactor, & ! intent(out): canopy wind reduction factor (-) + zeroPlaneDisplacement, & ! intent(out): zero plane displacement (m) + eddyDiffusCanopyTop, & ! intent(out): eddy diffusivity for heat at the top of the canopy (m2 s-1) + frictionVelocity, & ! intent(out): friction velocity (m s-1) + windspdCanopyTop, & ! intent(out): windspeed at the top of the canopy (m s-1) + windspdCanopyBottom, & ! intent(out): windspeed at the height of the bottom of the canopy (m s-1) + leafResistance, & ! intent(out): mean leaf boundary layer resistance per unit leaf area (s m-1) + groundResistance, & ! intent(out): below canopy aerodynamic resistance (s m-1) + canopyResistance, & ! intent(out): above canopy aerodynamic resistance (s m-1) + ! output: derivatives in scalar resistances + dGroundResistance_dTGround, & ! intent(out): derivative in ground resistance w.r.t. ground temperature (s m-1 K-1) + dGroundResistance_dTCanopy, & ! intent(out): derivative in ground resistance w.r.t. canopy temperature (s m-1 K-1) + dGroundResistance_dTCanair, & ! intent(out): derivative in ground resistance w.r.t. canopy air temperature (s m-1 K-1) + dCanopyResistance_dTCanopy, & ! intent(out): derivative in canopy resistance w.r.t. canopy temperature (s m-1 K-1) + dCanopyResistance_dTCanair, & ! intent(out): derivative in canopy resistance w.r.t. canopy air temperature (s m-1 K-1) + ! output: error control + err,message ) ! intent(out): error control + ! ----------------------------------------------------------------------------------------------------------------------------------------- + ! compute aerodynamic resistances + ! Refs: Choudhury and Monteith (4-layer model for heat budget of homogenous surfaces; QJRMS, 1988) + ! Niu and Yang (Canopy effects on snow processes; JGR, 2004) + ! Mahat et al. (Below-canopy turbulence in a snowmelt model, WRR, 2012) + implicit none + ! input: model control + logical(lgt),intent(in) :: computeVegFlux ! logical flag to compute vegetation fluxes (.false. if veg buried by snow) + logical(lgt),intent(in) :: derivDesired ! logical flag to indicate if analytical derivatives are desired + integer(i4b),intent(in) :: ixVegTraits ! choice of parameterization for vegetation roughness length and displacement height + integer(i4b),intent(in) :: ixWindProfile ! choice of canopy wind profile + integer(i4b),intent(in) :: ixStability ! choice of stability function + ! input: above-canopy forcing data + real(rkind),intent(in) :: mHeight ! measurement height (m) + real(rkind),intent(in) :: airtemp ! air temperature at some height above the surface (K) + real(rkind),intent(in) :: windspd ! wind speed at some height above the surface (m s-1) + ! input: temperature (canopy, ground, canopy air space) + real(rkind),intent(in) :: canairTemp ! temperature of the canopy air space (K) + real(rkind),intent(in) :: groundTemp ! ground temperature (K) + ! input: diagnostic variables + real(rkind),intent(in) :: exposedVAI ! exposed vegetation area index -- leaf plus stem (m2 m-2) + real(rkind),intent(in) :: snowDepth ! snow depth (m) + ! input: parameters + real(rkind),intent(in) :: z0Ground ! roughness length of the ground (below canopy or non-vegetated surface [snow]) (m) + real(rkind),intent(in) :: z0CanopyParam ! roughness length of the canopy (m) + real(rkind),intent(in) :: zpdFraction ! zero plane displacement / canopy height (-) + real(rkind),intent(in) :: critRichNumber ! critical value for the bulk Richardson number where turbulence ceases (-) + real(rkind),intent(in) :: Louis79_bparam ! parameter in Louis (1979) stability function + real(rkind),intent(in) :: Mahrt87_eScale ! exponential scaling factor in the Mahrt (1987) stability function + real(rkind),intent(in) :: windReductionParam ! canopy wind reduction parameter (-) + real(rkind),intent(in) :: leafExchangeCoeff ! turbulent exchange coeff between canopy surface and canopy air ( m s-(1/2) ) + real(rkind),intent(in) :: leafDimension ! characteristic leaf dimension (m) + real(rkind),intent(in) :: heightCanopyTop ! height at the top of the vegetation canopy (m) + real(rkind),intent(in) :: heightCanopyBottom ! height at the bottom of the vegetation canopy (m) + ! output: stability corrections + real(rkind),intent(out) :: RiBulkCanopy ! bulk Richardson number for the canopy (-) + real(rkind),intent(out) :: RiBulkGround ! bulk Richardson number for the ground surface (-) + real(rkind),intent(out) :: canopyStabilityCorrection ! stability correction for the canopy (-) + real(rkind),intent(out) :: groundStabilityCorrection ! stability correction for the ground surface (-) + ! output: scalar resistances + real(rkind),intent(out) :: z0Canopy ! roughness length of the vegetation canopy (m) + real(rkind),intent(out) :: windReductionFactor ! canopy wind reduction factor (-) + real(rkind),intent(out) :: zeroPlaneDisplacement ! zero plane displacement (m) + real(rkind),intent(out) :: eddyDiffusCanopyTop ! eddy diffusivity for heat at the top of the canopy (m2 s-1) + real(rkind),intent(out) :: frictionVelocity ! friction velocity (m s-1) + real(rkind),intent(out) :: windspdCanopyTop ! windspeed at the top of the canopy (m s-1) + real(rkind),intent(out) :: windspdCanopyBottom ! windspeed at the height of the bottom of the canopy (m s-1) + real(rkind),intent(out) :: leafResistance ! mean leaf boundary layer resistance per unit leaf area (s m-1) + real(rkind),intent(out) :: groundResistance ! below canopy aerodynamic resistance (s m-1) + real(rkind),intent(out) :: canopyResistance ! above canopy aerodynamic resistance (s m-1) + ! output: derivatives in scalar resistances + real(rkind),intent(out) :: dGroundResistance_dTGround ! derivative in ground resistance w.r.t. ground temperature (s m-1 K-1) + real(rkind),intent(out) :: dGroundResistance_dTCanopy ! derivative in ground resistance w.r.t. canopy temperature (s m-1 K-1) + real(rkind),intent(out) :: dGroundResistance_dTCanair ! derivative in ground resistance w.r.t. canopy air temperature (s m-1 K-1) + real(rkind),intent(out) :: dCanopyResistance_dTCanopy ! derivative in canopy resistance w.r.t. canopy temperature (s m-1 K-1) + real(rkind),intent(out) :: dCanopyResistance_dTCanair ! derivative in canopy resistance w.r.t. canopy air temperature (s m-1 K-1) + ! output: error control + integer(i4b),intent(out) :: err ! error code + character(*),intent(out) :: message ! error message + ! ----------------------------------------------------------------------------------------------------------------------------------------- + ! local variables: general + character(LEN=256) :: cmessage ! error message of downwind routine + ! local variables: vegetation roughness and dispalcement height + real(rkind),parameter :: oneThird=1._rkind/3._rkind ! 1/3 + real(rkind),parameter :: twoThirds=2._rkind/3._rkind ! 2/3 + real(rkind),parameter :: C_r = 0.3 ! roughness element drag coefficient (-) from Raupach (BLM, 1994) + real(rkind),parameter :: C_s = 0.003_rkind ! substrate surface drag coefficient (-) from Raupach (BLM, 1994) + real(rkind),parameter :: approxDragCoef_max = 0.3_rkind ! maximum value of the approximate drag coefficient (-) from Raupach (BLM, 1994) + real(rkind),parameter :: psi_h = 0.193_rkind ! roughness sub-layer influence function (-) from Raupach (BLM, 1994) + real(rkind),parameter :: c_d1 = 7.5_rkind ! scaling parameter used to define displacement height (-) from Raupach (BLM, 1994) + real(rkind),parameter :: cd_CM = 0.2_rkind ! mean drag coefficient for individual leaves (-) from Choudhury and Monteith (QJRMS, 1988) + real(rkind) :: funcLAI ! temporary variable to calculate zero plane displacement for the canopy + real(rkind) :: fracCanopyHeight ! zero plane displacement expressed as a fraction of canopy height + real(rkind) :: approxDragCoef ! approximate drag coefficient used in the computation of canopy roughness length (-) + ! local variables: resistance + real(rkind) :: canopyExNeut ! surface-atmosphere exchange coefficient under neutral conditions (-) + real(rkind) :: groundExNeut ! surface-atmosphere exchange coefficient under neutral conditions (-) + real(rkind) :: sfc2AtmExchangeCoeff_canopy ! surface-atmosphere exchange coefficient after stability corrections (-) + real(rkind) :: groundResistanceNeutral ! ground resistance under neutral conditions (s m-1) + real(rkind) :: windConvFactor_fv ! factor to convert friction velocity to wind speed at top of canopy (-) + real(rkind) :: windConvFactor ! factor to convert wind speed at top of canopy to wind speed at a given height in the canopy (-) + real(rkind) :: referenceHeight ! z0Canopy+zeroPlaneDisplacement (m) + real(rkind) :: windspdRefHeight ! windspeed at the reference height (m/s) + real(rkind) :: heightAboveGround ! height above the snow surface (m) + real(rkind) :: heightCanopyTopAboveSnow ! height at the top of the vegetation canopy relative to snowpack (m) + real(rkind) :: heightCanopyBottomAboveSnow ! height at the bottom of the vegetation canopy relative to snowpack (m) + real(rkind),parameter :: xTolerance=0.1_rkind ! tolerance to handle the transition from exponential to log-below canopy + ! local variables: derivatives + real(rkind) :: dFV_dT ! derivative in friction velocity w.r.t. canopy air temperature + real(rkind) :: dED_dT ! derivative in eddy diffusivity at the top of the canopy w.r.t. canopy air temperature + real(rkind) :: dGR_dT ! derivative in neutral ground resistance w.r.t. canopy air temperature + real(rkind) :: tmp1,tmp2 ! temporary variables used in calculation of ground resistance + real(rkind) :: dCanopyStabilityCorrection_dRich ! derivative in stability correction w.r.t. Richardson number for the canopy (-) + real(rkind) :: dGroundStabilityCorrection_dRich ! derivative in stability correction w.r.t. Richardson number for the ground surface (-) + real(rkind) :: dCanopyStabilityCorrection_dAirTemp ! (not used) derivative in stability correction w.r.t. air temperature (K-1) + real(rkind) :: dGroundStabilityCorrection_dAirTemp ! (not used) derivative in stability correction w.r.t. air temperature (K-1) + real(rkind) :: dCanopyStabilityCorrection_dCasTemp ! derivative in canopy stability correction w.r.t. canopy air space temperature (K-1) + real(rkind) :: dGroundStabilityCorrection_dCasTemp ! derivative in ground stability correction w.r.t. canopy air space temperature (K-1) + real(rkind) :: dGroundStabilityCorrection_dSfcTemp ! derivative in ground stability correction w.r.t. surface temperature (K-1) + real(rkind) :: singleLeafConductance ! leaf boundary layer conductance (m s-1) + real(rkind) :: canopyLeafConductance ! leaf boundary layer conductance -- scaled up to the canopy (m s-1) + real(rkind) :: leaf2CanopyScaleFactor ! factor to scale from the leaf to the canopy [m s-(1/2)] + ! ----------------------------------------------------------------------------------------------------------------------------------------- + ! initialize error control + err=0; message='aeroResist/' + + ! check that measurement height is above the top of the canopy + if(mHeight < heightCanopyTop)then + err=20; message=trim(message)//'measurement height is below the top of the canopy'; return + end if + + ! ----------------------------------------------------------------------------------------------------------------------------------------- + ! * compute vegetation poperties (could be done at the same time as phenology.. does not have to be in the flux routine!) + if(computeVegFlux) then ! (if vegetation is exposed) + + ! ***** identify zero plane displacement, roughness length, and surface temperature for the canopy (m) + ! First, calculate new coordinate system above snow - use these to scale wind profiles and resistances + ! NOTE: the new coordinate system makes zeroPlaneDisplacement and z0Canopy consistent + heightCanopyTopAboveSnow = heightCanopyTop - snowDepth + heightCanopyBottomAboveSnow = max(heightCanopyBottom - snowDepth, 0.0_rkind) + select case(ixVegTraits) + + ! Raupach (BLM 1994) "Simplified expressions..." + case(Raupach_BLM1994) ! (compute zero-plane displacement) funcLAI = sqrt(c_d1*exposedVAI) fracCanopyHeight = -(1._rkind - exp(-funcLAI))/funcLAI + 1._rkind @@ -2214,1151 +2121,1110 @@ module vegNrgFlux_module ! (coupute roughness length of the veg canopy) approxDragCoef = min( sqrt(C_s + C_r*exposedVAI/2._rkind), approxDragCoef_max) z0Canopy = (1._rkind - fracCanopyHeight) * exp(-vkc*approxDragCoef - psi_h) * (heightCanopyTopAboveSnow-heightCanopyBottomAboveSnow) - - ! Choudhury and Monteith (QJRMS 1988) "A four layer model for the heat budget..." - case(CM_QJRMS1988) + + ! Choudhury and Monteith (QJRMS 1988) "A four layer model for the heat budget..." + case(CM_QJRMS1988) funcLAI = cd_CM*exposedVAI zeroPlaneDisplacement = 1.1_rkind*heightCanopyTopAboveSnow*log(1._rkind + funcLAI**0.25_rkind) if(funcLAI < 0.2_rkind)then - z0Canopy = z0Ground + 0.3_rkind*heightCanopyTopAboveSnow*funcLAI**0.5_rkind + z0Canopy = z0Ground + 0.3_rkind*heightCanopyTopAboveSnow*funcLAI**0.5_rkind else - z0Canopy = 0.3_rkind*heightCanopyTopAboveSnow*(1._rkind - zeroPlaneDisplacement/heightCanopyTopAboveSnow) + z0Canopy = 0.3_rkind*heightCanopyTopAboveSnow*(1._rkind - zeroPlaneDisplacement/heightCanopyTopAboveSnow) end if - - ! constant parameters dependent on the vegetation type - case(vegTypeTable) + + ! constant parameters dependent on the vegetation type + case(vegTypeTable) zeroPlaneDisplacement = zpdFraction*heightCanopyTopAboveSnow ! zero-plane displacement (m) z0Canopy = z0CanopyParam ! roughness length of the veg canopy (m) - - ! check - case default + + ! check + case default err=10; message=trim(message)//"unknown parameterization for vegetation roughness length and displacement height"; return - - end select ! vegetation traits (z0, zpd) - - ! check zero plane displacement - if(zeroPlaneDisplacement < heightCanopyBottomAboveSnow)then - write(*,'(a,1x,10(f12.5,1x))') 'heightCanopyTop, snowDepth, heightCanopyTopAboveSnow, heightCanopyBottomAboveSnow, exposedVAI = ', & - heightCanopyTop, snowDepth, heightCanopyTopAboveSnow, heightCanopyBottomAboveSnow, exposedVAI - message=trim(message)//'zero plane displacement is below the canopy bottom' - err=20; return - endif - - ! check measurement height - if(mHeight < zeroPlaneDisplacement)then; err=20; message=trim(message)//'measurement height is below the displacement height'; return; end if - if(mHeight < z0Canopy)then; err=20; message=trim(message)//'measurement height is below the roughness length'; return; end if - - ! ----------------------------------------------------------------------------------------------------------------------------------------- - ! ----------------------------------------------------------------------------------------------------------------------------------------- - ! * compute resistance for the case where the canopy is exposed - ! compute the stability correction for resistance from canopy air space to air above the canopy (-) - call aStability(& - ! input - derivDesired, & ! input: logical flag to compute analytical derivatives - ixStability, & ! input: choice of stability function - ! input: forcing data, diagnostic and state variables - mHeight, & ! input: measurement height (m) - airTemp, & ! input: air temperature above the canopy (K) - canairTemp, & ! input: temperature of the canopy air space (K) - windspd, & ! input: wind speed above the canopy (m s-1) - ! input: stability parameters - critRichNumber, & ! input: critical value for the bulk Richardson number where turbulence ceases (-) - Louis79_bparam, & ! input: parameter in Louis (1979) stability function - Mahrt87_eScale, & ! input: exponential scaling factor in the Mahrt (1987) stability function - ! output - RiBulkCanopy, & ! output: bulk Richardson number (-) - canopyStabilityCorrection, & ! output: stability correction for turbulent heat fluxes (-) - dCanopyStabilityCorrection_dRich, & ! output: derivative in stability correction w.r.t. Richardson number for the canopy (-) - dCanopyStabilityCorrection_dAirTemp, & ! output: (not used) derivative in stability correction w.r.t. air temperature (K-1) - dCanopyStabilityCorrection_dCasTemp, & ! output: derivative in stability correction w.r.t. canopy air space temperature (K-1) - err, cmessage ) ! output: error control - if(err/=0)then; message=trim(message)//trim(cmessage); return; end if - - ! compute turbulent exchange coefficient (-) - canopyExNeut = (vkc**2._rkind) / ( log((mHeight - zeroPlaneDisplacement)/z0Canopy))**2._rkind ! coefficient under conditions of neutral stability - sfc2AtmExchangeCoeff_canopy = canopyExNeut*canopyStabilityCorrection ! after stability corrections - - ! compute the friction velocity (m s-1) - frictionVelocity = windspd * sqrt(sfc2AtmExchangeCoeff_canopy) - - ! compute the above-canopy resistance (s m-1) - canopyResistance = 1._rkind/(sfc2AtmExchangeCoeff_canopy*windspd) - if(canopyResistance < 0._rkind)then; err=20; message=trim(message)//'canopy resistance < 0'; return; end if - - ! compute windspeed at the top of the canopy above snow depth (m s-1) - ! NOTE: stability corrections cancel out - windConvFactor_fv = log((heightCanopyTopAboveSnow - zeroPlaneDisplacement)/z0Canopy) / log((mHeight - snowDepth - zeroPlaneDisplacement)/z0Canopy) - windspdCanopyTop = windspd*windConvFactor_fv - - ! compute the windspeed reduction - ! Refs: Norman et al. (Ag. Forest Met., 1995) -- citing Goudriaan (1977 manuscript "crop micrometeorology: a simulation study", Wageningen). - windReductionFactor = windReductionParam * exposedVAI**twoThirds * (heightCanopyTopAboveSnow - heightCanopyBottomAboveSnow)**oneThird / leafDimension**oneThird - - ! compute windspeed at the height z0Canopy+zeroPlaneDisplacement (m s-1) - referenceHeight = z0Canopy+zeroPlaneDisplacement - windConvFactor = exp(-windReductionFactor*(1._rkind - (referenceHeight/heightCanopyTopAboveSnow))) - windspdRefHeight = windspdCanopyTop*windConvFactor - - ! compute windspeed at the bottom of the canopy relative to the snow depth (m s-1) - windConvFactor = exp(-windReductionFactor*(1._rkind - (heightCanopyBottomAboveSnow/heightCanopyTopAboveSnow))) - windspdCanopyBottom = windspdCanopyTop*windConvFactor - - ! compute the leaf boundary layer resistance (s m-1) - singleLeafConductance = leafExchangeCoeff*sqrt(windspdCanopyTop/leafDimension) - leaf2CanopyScaleFactor = (2._rkind/windReductionFactor) * (1._rkind - exp(-windReductionFactor/2._rkind)) ! factor to scale from the leaf to the canopy - canopyLeafConductance = singleLeafConductance*leaf2CanopyScaleFactor - leafResistance = 1._rkind/(canopyLeafConductance) - if(leafResistance < 0._rkind)then; err=20; message=trim(message)//'leaf resistance < 0'; return; end if - - ! compute eddy diffusivity for heat at the top of the canopy (m2 s-1) - ! Note: use of friction velocity here includes stability adjustments - ! Note: max used to avoid dividing by zero - eddyDiffusCanopyTop = max(vkc*FrictionVelocity*(heightCanopyTopAboveSnow - zeroPlaneDisplacement), mpe) - - ! compute the resistance between the surface and canopy air UNDER NEUTRAL CONDITIONS (s m-1) - - ! case 1: assume exponential profile extends from the snow depth plus surface roughness length to the displacement height plus vegetation roughness - if(ixWindProfile==exponential .or. heightCanopyBottomAboveSnow<z0Ground+xTolerance)then - - ! compute the neutral ground resistance - tmp1 = exp(-windReductionFactor* z0Ground/heightCanopyTopAboveSnow) - tmp2 = exp(-windReductionFactor*(z0Canopy+zeroPlaneDisplacement)/heightCanopyTopAboveSnow) - groundResistanceNeutral = ( heightCanopyTopAboveSnow*exp(windReductionFactor) / (windReductionFactor*eddyDiffusCanopyTop) ) * (tmp1 - tmp2) ! s m-1 - - ! case 2: logarithmic profile from snow depth plus roughness height to bottom of the canopy - ! NOTE: heightCanopyBottomAboveSnow>z0Ground+xTolerance - else - - ! compute the neutral ground resistance - ! (first, component between heightCanopyBottomAboveSnow and z0Canopy+zeroPlaneDisplacement) - tmp1 = exp(-windReductionFactor* heightCanopyBottomAboveSnow/heightCanopyTopAboveSnow) - tmp2 = exp(-windReductionFactor*(z0Canopy+zeroPlaneDisplacement)/heightCanopyTopAboveSnow) - groundResistanceNeutral = ( heightCanopyTopAboveSnow*exp(windReductionFactor) / (windReductionFactor*eddyDiffusCanopyTop) ) * (tmp1 - tmp2) - ! (add log-below-canopy component) - groundResistanceNeutral = groundResistanceNeutral + (1._rkind/(max(0.1_rkind,windspdCanopyBottom)*vkc**2._rkind))*(log(heightCanopyBottomAboveSnow/z0Ground))**2._rkind - - endif ! switch between exponential profile and log-below-canopy - - ! compute the stability correction for resistance from the ground to the canopy air space (-) - ! NOTE: here we are interested in the windspeed at height z0Canopy+zeroPlaneDisplacement - call aStability(& - ! input - derivDesired, & ! input: logical flag to compute analytical derivatives - ixStability, & ! input: choice of stability function - ! input: forcing data, diagnostic and state variables - referenceHeight, & ! input: height of the canopy air space temperature/wind (m) - canairTemp, & ! input: temperature of the canopy air space (K) - groundTemp, & ! input: temperature of the ground surface (K) - max(0.1_rkind,windspdRefHeight), & ! input: wind speed at height z0Canopy+zeroPlaneDisplacement (m s-1) - ! input: stability parameters - critRichNumber, & ! input: critical value for the bulk Richardson number where turbulence ceases (-) - Louis79_bparam, & ! input: parameter in Louis (1979) stability function - Mahrt87_eScale, & ! input: exponential scaling factor in the Mahrt (1987) stability function - ! output - RiBulkGround, & ! output: bulk Richardson number (-) - groundStabilityCorrection, & ! output: stability correction for turbulent heat fluxes (-) - dGroundStabilityCorrection_dRich, & ! output: derivative in stability correction w.r.t. Richardson number for the canopy (-) - dGroundStabilityCorrection_dCasTemp, & ! output: derivative in stability correction w.r.t. canopy air space temperature (K-1) - dGroundStabilityCorrection_dSfcTemp, & ! output: derivative in stability correction w.r.t. surface temperature (K-1) - err, cmessage ) ! output: error control - if(err/=0)then; message=trim(message)//trim(cmessage); return; end if - - ! compute the ground resistance - groundResistance = groundResistanceNeutral / groundStabilityCorrection - if(groundResistance < 0._rkind)then; err=20; message=trim(message)//'ground resistance < 0 [vegetation is present]'; return; end if - - ! ----------------------------------------------------------------------------------------------------------------------------------------- - ! ----------------------------------------------------------------------------------------------------------------------------------------- - ! * compute resistance for the case without a canopy (bare ground, or canopy completely buried with snow) - else - - ! no canopy, so set huge resistances (not used) - canopyResistance = 1.e12_rkind ! not used: huge resistance, so conductance is essentially zero - leafResistance = 1.e12_rkind ! not used: huge resistance, so conductance is essentially zero - - ! check that measurement height above the ground surface is above the roughness length - if(mHeight < snowDepth+z0Ground)then; err=20; message=trim(message)//'measurement height < snow depth + roughness length'; return; end if - - ! compute the resistance between the surface and canopy air UNDER NEUTRAL CONDITIONS (s m-1) - groundExNeut = (vkc**2._rkind) / ( log((mHeight - snowDepth)/z0Ground)**2._rkind) ! turbulent transfer coefficient under conditions of neutral stability (-) - groundResistanceNeutral = 1._rkind / (groundExNeut*windspd) - - ! define height above the snow surface - heightAboveGround = mHeight - snowDepth - - ! check that measurement height above the ground surface is above the roughness length - if(heightAboveGround < z0Ground)then - print*, 'z0Ground = ', z0Ground - print*, 'mHeight = ', mHeight - print*, 'snowDepth = ', snowDepth - print*, 'heightAboveGround = ', heightAboveGround - message=trim(message)//'height above ground < roughness length [likely due to snow accumulation]' - err=20; return - end if - - ! compute ground stability correction - call aStability(& - ! input - derivDesired, & ! input: logical flag to compute analytical derivatives - ixStability, & ! input: choice of stability function - ! input: forcing data, diagnostic and state variables - heightAboveGround, & ! input: measurement height above the ground surface (m) - airtemp, & ! input: temperature above the ground surface (K) - groundTemp, & ! input: trial value of surface temperature -- "surface" is either canopy or ground (K) - windspd, & ! input: wind speed above the ground surface (m s-1) - ! input: stability parameters - critRichNumber, & ! input: critical value for the bulk Richardson number where turbulence ceases (-) - Louis79_bparam, & ! input: parameter in Louis (1979) stability function - Mahrt87_eScale, & ! input: exponential scaling factor in the Mahrt (1987) stability function - ! output - RiBulkGround, & ! output: bulk Richardson number (-) - groundStabilityCorrection, & ! output: stability correction for turbulent heat fluxes (-) - dGroundStabilityCorrection_dRich, & ! output: derivative in stability correction w.r.t. Richardson number for the ground surface (-) - dGroundStabilityCorrection_dAirTemp, & ! output: (not used) derivative in stability correction w.r.t. air temperature (K-1) - dGroundStabilityCorrection_dSfcTemp, & ! output: derivative in stability correction w.r.t. surface temperature (K-1) - err, cmessage ) ! output: error control - if(err/=0)then; message=trim(message)//trim(cmessage); return; end if - - ! compute the ground resistance (after stability corrections) - groundResistance = groundResistanceNeutral/groundStabilityCorrection - if(groundResistance < 0._rkind)then; err=20; message=trim(message)//'ground resistance < 0 [no vegetation]'; return; end if - - ! set all canopy variables to missing (no canopy!) - z0Canopy = missingValue ! roughness length of the vegetation canopy (m) - RiBulkCanopy = missingValue ! bulk Richardson number for the canopy (-) - windReductionFactor = missingValue ! canopy wind reduction factor (-) - zeroPlaneDisplacement = missingValue ! zero plane displacement (m) - canopyStabilityCorrection = missingValue ! stability correction for the canopy (-) - eddyDiffusCanopyTop = missingValue ! eddy diffusivity for heat at the top of the canopy (m2 s-1) - frictionVelocity = missingValue ! friction velocity (m s-1) - windspdCanopyTop = missingValue ! windspeed at the top of the canopy (m s-1) - windspdCanopyBottom = missingValue ! windspeed at the height of the bottom of the canopy (m s-1) - - end if ! (if no canopy) - - ! ----------------------------------------------------------------------------------------------------------------------------------------- - ! ----------------------------------------------------------------------------------------------------------------------------------------- - ! ----------------------------------------------------------------------------------------------------------------------------------------- - ! ----------------------------------------------------------------------------------------------------------------------------------------- - ! * compute derivatives - if(derivDesired)then ! if analytical derivatives are desired - - ! derivatives for the vegetation canopy - if(computeVegFlux) then ! (if vegetation is exposed) - - ! ***** compute derivatives w.r.t. canopy temperature - ! NOTE: derivatives are zero because using canopy air space temperature - dCanopyResistance_dTCanopy = 0._rkind ! derivative in canopy resistance w.r.t. canopy temperature (s m-1 K-1) - dGroundResistance_dTCanopy = 0._rkind ! derivative in ground resistance w.r.t. canopy temperature (s m-1 K-1) - - ! ***** compute derivatives w.r.t. ground temperature (s m-1 K-1) - dGroundResistance_dTGround = -(groundResistanceNeutral*dGroundStabilityCorrection_dSfcTemp)/(groundStabilityCorrection**2._rkind) - - ! ***** compute derivatives w.r.t. temperature of the canopy air space (s m-1 K-1) - ! derivative in canopy resistance w.r.t. canopy air temperature (s m-1 K-1) - dCanopyResistance_dTCanair = -dCanopyStabilityCorrection_dCasTemp/(windspd*canopyExNeut*canopyStabilityCorrection**2._rkind) - ! derivative in ground resistance w.r.t. canopy air temperature (s m-1 K-1) - ! (compute derivative in NEUTRAL ground resistance w.r.t. canopy air temperature (s m-1 K-1)) - dFV_dT = windspd*canopyExNeut*dCanopyStabilityCorrection_dCasTemp/(sqrt(sfc2AtmExchangeCoeff_canopy)*2._rkind) ! d(frictionVelocity)/d(canopy air temperature) - dED_dT = dFV_dT*vkc*(heightCanopyTopAboveSnow - zeroPlaneDisplacement) ! d(eddyDiffusCanopyTop)d(canopy air temperature) - dGR_dT = -dED_dT*(tmp1 - tmp2)*heightCanopyTopAboveSnow*exp(windReductionFactor) / (windReductionFactor*eddyDiffusCanopyTop**2._rkind) ! d(groundResistanceNeutral)/d(canopy air temperature) - ! (stitch everything together -- product rule) - dGroundResistance_dTCanair = dGR_dT/groundStabilityCorrection - groundResistanceNeutral*dGroundStabilityCorrection_dCasTemp/(groundStabilityCorrection**2._rkind) - + + end select ! vegetation traits (z0, zpd) + + ! check zero plane displacement + if(zeroPlaneDisplacement < heightCanopyBottomAboveSnow)then + write(*,'(a,1x,10(f12.5,1x))') 'heightCanopyTop, snowDepth, heightCanopyTopAboveSnow, heightCanopyBottomAboveSnow, exposedVAI = ', & + heightCanopyTop, snowDepth, heightCanopyTopAboveSnow, heightCanopyBottomAboveSnow, exposedVAI + message=trim(message)//'zero plane displacement is below the canopy bottom' + err=20; return + endif + + ! check measurement height + if(mHeight < zeroPlaneDisplacement)then; err=20; message=trim(message)//'measurement height is below the displacement height'; return; end if + if(mHeight < z0Canopy)then; err=20; message=trim(message)//'measurement height is below the roughness length'; return; end if + + ! ----------------------------------------------------------------------------------------------------------------------------------------- + ! ----------------------------------------------------------------------------------------------------------------------------------------- + ! * compute resistance for the case where the canopy is exposed + ! compute the stability correction for resistance from canopy air space to air above the canopy (-) + call aStability(& + ! input + derivDesired, & ! input: logical flag to compute analytical derivatives + ixStability, & ! input: choice of stability function + ! input: forcing data, diagnostic and state variables + mHeight, & ! input: measurement height (m) + airTemp, & ! input: air temperature above the canopy (K) + canairTemp, & ! input: temperature of the canopy air space (K) + windspd, & ! input: wind speed above the canopy (m s-1) + ! input: stability parameters + critRichNumber, & ! input: critical value for the bulk Richardson number where turbulence ceases (-) + Louis79_bparam, & ! input: parameter in Louis (1979) stability function + Mahrt87_eScale, & ! input: exponential scaling factor in the Mahrt (1987) stability function + ! output + RiBulkCanopy, & ! output: bulk Richardson number (-) + canopyStabilityCorrection, & ! output: stability correction for turbulent heat fluxes (-) + dCanopyStabilityCorrection_dRich, & ! output: derivative in stability correction w.r.t. Richardson number for the canopy (-) + dCanopyStabilityCorrection_dAirTemp, & ! output: (not used) derivative in stability correction w.r.t. air temperature (K-1) + dCanopyStabilityCorrection_dCasTemp, & ! output: derivative in stability correction w.r.t. canopy air space temperature (K-1) + err, cmessage ) ! output: error control + if(err/=0)then; message=trim(message)//trim(cmessage); return; end if + + ! compute turbulent exchange coefficient (-) + canopyExNeut = (vkc**2._rkind) / ( log((mHeight - zeroPlaneDisplacement)/z0Canopy))**2._rkind ! coefficient under conditions of neutral stability + sfc2AtmExchangeCoeff_canopy = canopyExNeut*canopyStabilityCorrection ! after stability corrections + + ! compute the friction velocity (m s-1) + frictionVelocity = windspd * sqrt(sfc2AtmExchangeCoeff_canopy) + + ! compute the above-canopy resistance (s m-1) + canopyResistance = 1._rkind/(sfc2AtmExchangeCoeff_canopy*windspd) + if(canopyResistance < 0._rkind)then; err=20; message=trim(message)//'canopy resistance < 0'; return; end if + + ! compute windspeed at the top of the canopy above snow depth (m s-1) + ! NOTE: stability corrections cancel out + windConvFactor_fv = log((heightCanopyTopAboveSnow - zeroPlaneDisplacement)/z0Canopy) / log((mHeight - snowDepth - zeroPlaneDisplacement)/z0Canopy) + windspdCanopyTop = windspd*windConvFactor_fv + + ! compute the windspeed reduction + ! Refs: Norman et al. (Ag. Forest Met., 1995) -- citing Goudriaan (1977 manuscript "crop micrometeorology: a simulation study", Wageningen). + windReductionFactor = windReductionParam * exposedVAI**twoThirds * (heightCanopyTopAboveSnow - heightCanopyBottomAboveSnow)**oneThird / leafDimension**oneThird + + ! compute windspeed at the height z0Canopy+zeroPlaneDisplacement (m s-1) + referenceHeight = z0Canopy+zeroPlaneDisplacement + windConvFactor = exp(-windReductionFactor*(1._rkind - (referenceHeight/heightCanopyTopAboveSnow))) + windspdRefHeight = windspdCanopyTop*windConvFactor + + ! compute windspeed at the bottom of the canopy relative to the snow depth (m s-1) + windConvFactor = exp(-windReductionFactor*(1._rkind - (heightCanopyBottomAboveSnow/heightCanopyTopAboveSnow))) + windspdCanopyBottom = windspdCanopyTop*windConvFactor + + ! compute the leaf boundary layer resistance (s m-1) + singleLeafConductance = leafExchangeCoeff*sqrt(windspdCanopyTop/leafDimension) + leaf2CanopyScaleFactor = (2._rkind/windReductionFactor) * (1._rkind - exp(-windReductionFactor/2._rkind)) ! factor to scale from the leaf to the canopy + canopyLeafConductance = singleLeafConductance*leaf2CanopyScaleFactor + leafResistance = 1._rkind/(canopyLeafConductance) + if(leafResistance < 0._rkind)then; err=20; message=trim(message)//'leaf resistance < 0'; return; end if + + ! compute eddy diffusivity for heat at the top of the canopy (m2 s-1) + ! Note: use of friction velocity here includes stability adjustments + ! Note: max used to avoid dividing by zero + eddyDiffusCanopyTop = max(vkc*FrictionVelocity*(heightCanopyTopAboveSnow - zeroPlaneDisplacement), mpe) + + ! compute the resistance between the surface and canopy air UNDER NEUTRAL CONDITIONS (s m-1) + + ! case 1: assume exponential profile extends from the snow depth plus surface roughness length to the displacement height plus vegetation roughness + if(ixWindProfile==exponential .or. heightCanopyBottomAboveSnow<z0Ground+xTolerance)then + + ! compute the neutral ground resistance + tmp1 = exp(-windReductionFactor* z0Ground/heightCanopyTopAboveSnow) + tmp2 = exp(-windReductionFactor*(z0Canopy+zeroPlaneDisplacement)/heightCanopyTopAboveSnow) + groundResistanceNeutral = ( heightCanopyTopAboveSnow*exp(windReductionFactor) / (windReductionFactor*eddyDiffusCanopyTop) ) * (tmp1 - tmp2) ! s m-1 + + ! case 2: logarithmic profile from snow depth plus roughness height to bottom of the canopy + ! NOTE: heightCanopyBottomAboveSnow>z0Ground+xTolerance + else + + ! compute the neutral ground resistance + ! (first, component between heightCanopyBottomAboveSnow and z0Canopy+zeroPlaneDisplacement) + tmp1 = exp(-windReductionFactor* heightCanopyBottomAboveSnow/heightCanopyTopAboveSnow) + tmp2 = exp(-windReductionFactor*(z0Canopy+zeroPlaneDisplacement)/heightCanopyTopAboveSnow) + groundResistanceNeutral = ( heightCanopyTopAboveSnow*exp(windReductionFactor) / (windReductionFactor*eddyDiffusCanopyTop) ) * (tmp1 - tmp2) + ! (add log-below-canopy component) + groundResistanceNeutral = groundResistanceNeutral + (1._rkind/(max(0.1_rkind,windspdCanopyBottom)*vkc**2._rkind))*(log(heightCanopyBottomAboveSnow/z0Ground))**2._rkind + + endif ! switch between exponential profile and log-below-canopy + + ! compute the stability correction for resistance from the ground to the canopy air space (-) + ! NOTE: here we are interested in the windspeed at height z0Canopy+zeroPlaneDisplacement + call aStability(& + ! input + derivDesired, & ! input: logical flag to compute analytical derivatives + ixStability, & ! input: choice of stability function + ! input: forcing data, diagnostic and state variables + referenceHeight, & ! input: height of the canopy air space temperature/wind (m) + canairTemp, & ! input: temperature of the canopy air space (K) + groundTemp, & ! input: temperature of the ground surface (K) + max(0.1_rkind,windspdRefHeight), & ! input: wind speed at height z0Canopy+zeroPlaneDisplacement (m s-1) + ! input: stability parameters + critRichNumber, & ! input: critical value for the bulk Richardson number where turbulence ceases (-) + Louis79_bparam, & ! input: parameter in Louis (1979) stability function + Mahrt87_eScale, & ! input: exponential scaling factor in the Mahrt (1987) stability function + ! output + RiBulkGround, & ! output: bulk Richardson number (-) + groundStabilityCorrection, & ! output: stability correction for turbulent heat fluxes (-) + dGroundStabilityCorrection_dRich, & ! output: derivative in stability correction w.r.t. Richardson number for the canopy (-) + dGroundStabilityCorrection_dCasTemp, & ! output: derivative in stability correction w.r.t. canopy air space temperature (K-1) + dGroundStabilityCorrection_dSfcTemp, & ! output: derivative in stability correction w.r.t. surface temperature (K-1) + err, cmessage ) ! output: error control + if(err/=0)then; message=trim(message)//trim(cmessage); return; end if + + ! compute the ground resistance + groundResistance = groundResistanceNeutral / groundStabilityCorrection + if(groundResistance < 0._rkind)then; err=20; message=trim(message)//'ground resistance < 0 [vegetation is present]'; return; end if + + ! ----------------------------------------------------------------------------------------------------------------------------------------- + ! ----------------------------------------------------------------------------------------------------------------------------------------- + ! * compute resistance for the case without a canopy (bare ground, or canopy completely buried with snow) + else + + ! no canopy, so set huge resistances (not used) + canopyResistance = 1.e12_rkind ! not used: huge resistance, so conductance is essentially zero + leafResistance = 1.e12_rkind ! not used: huge resistance, so conductance is essentially zero + + ! check that measurement height above the ground surface is above the roughness length + if(mHeight < snowDepth+z0Ground)then; err=20; message=trim(message)//'measurement height < snow depth + roughness length'; return; end if + + ! compute the resistance between the surface and canopy air UNDER NEUTRAL CONDITIONS (s m-1) + groundExNeut = (vkc**2._rkind) / ( log((mHeight - snowDepth)/z0Ground)**2._rkind) ! turbulent transfer coefficient under conditions of neutral stability (-) + groundResistanceNeutral = 1._rkind / (groundExNeut*windspd) + + ! define height above the snow surface + heightAboveGround = mHeight - snowDepth + + ! check that measurement height above the ground surface is above the roughness length + if(heightAboveGround < z0Ground)then + print*, 'z0Ground = ', z0Ground + print*, 'mHeight = ', mHeight + print*, 'snowDepth = ', snowDepth + print*, 'heightAboveGround = ', heightAboveGround + message=trim(message)//'height above ground < roughness length [likely due to snow accumulation]' + err=20; return + end if + + ! compute ground stability correction + call aStability(& + ! input + derivDesired, & ! input: logical flag to compute analytical derivatives + ixStability, & ! input: choice of stability function + ! input: forcing data, diagnostic and state variables + heightAboveGround, & ! input: measurement height above the ground surface (m) + airtemp, & ! input: temperature above the ground surface (K) + groundTemp, & ! input: trial value of surface temperature -- "surface" is either canopy or ground (K) + windspd, & ! input: wind speed above the ground surface (m s-1) + ! input: stability parameters + critRichNumber, & ! input: critical value for the bulk Richardson number where turbulence ceases (-) + Louis79_bparam, & ! input: parameter in Louis (1979) stability function + Mahrt87_eScale, & ! input: exponential scaling factor in the Mahrt (1987) stability function + ! output + RiBulkGround, & ! output: bulk Richardson number (-) + groundStabilityCorrection, & ! output: stability correction for turbulent heat fluxes (-) + dGroundStabilityCorrection_dRich, & ! output: derivative in stability correction w.r.t. Richardson number for the ground surface (-) + dGroundStabilityCorrection_dAirTemp, & ! output: (not used) derivative in stability correction w.r.t. air temperature (K-1) + dGroundStabilityCorrection_dSfcTemp, & ! output: derivative in stability correction w.r.t. surface temperature (K-1) + err, cmessage ) ! output: error control + if(err/=0)then; message=trim(message)//trim(cmessage); return; end if + + ! compute the ground resistance (after stability corrections) + groundResistance = groundResistanceNeutral/groundStabilityCorrection + if(groundResistance < 0._rkind)then; err=20; message=trim(message)//'ground resistance < 0 [no vegetation]'; return; end if + + ! set all canopy variables to missing (no canopy!) + z0Canopy = missingValue ! roughness length of the vegetation canopy (m) + RiBulkCanopy = missingValue ! bulk Richardson number for the canopy (-) + windReductionFactor = missingValue ! canopy wind reduction factor (-) + zeroPlaneDisplacement = missingValue ! zero plane displacement (m) + canopyStabilityCorrection = missingValue ! stability correction for the canopy (-) + eddyDiffusCanopyTop = missingValue ! eddy diffusivity for heat at the top of the canopy (m2 s-1) + frictionVelocity = missingValue ! friction velocity (m s-1) + windspdCanopyTop = missingValue ! windspeed at the top of the canopy (m s-1) + windspdCanopyBottom = missingValue ! windspeed at the height of the bottom of the canopy (m s-1) + + end if ! (if no canopy) + + ! ----------------------------------------------------------------------------------------------------------------------------------------- + ! ----------------------------------------------------------------------------------------------------------------------------------------- + ! ----------------------------------------------------------------------------------------------------------------------------------------- + ! ----------------------------------------------------------------------------------------------------------------------------------------- + ! * compute derivatives + if(derivDesired)then ! if analytical derivatives are desired + + ! derivatives for the vegetation canopy + if(computeVegFlux) then ! (if vegetation is exposed) + + ! ***** compute derivatives w.r.t. canopy temperature + ! NOTE: derivatives are zero because using canopy air space temperature + dCanopyResistance_dTCanopy = 0._rkind ! derivative in canopy resistance w.r.t. canopy temperature (s m-1 K-1) + dGroundResistance_dTCanopy = 0._rkind ! derivative in ground resistance w.r.t. canopy temperature (s m-1 K-1) + + ! ***** compute derivatives w.r.t. ground temperature (s m-1 K-1) + dGroundResistance_dTGround = -(groundResistanceNeutral*dGroundStabilityCorrection_dSfcTemp)/(groundStabilityCorrection**2._rkind) + + ! ***** compute derivatives w.r.t. temperature of the canopy air space (s m-1 K-1) + ! derivative in canopy resistance w.r.t. canopy air temperature (s m-1 K-1) + dCanopyResistance_dTCanair = -dCanopyStabilityCorrection_dCasTemp/(windspd*canopyExNeut*canopyStabilityCorrection**2._rkind) + ! derivative in ground resistance w.r.t. canopy air temperature (s m-1 K-1) + ! (compute derivative in NEUTRAL ground resistance w.r.t. canopy air temperature (s m-1 K-1)) + dFV_dT = windspd*canopyExNeut*dCanopyStabilityCorrection_dCasTemp/(sqrt(sfc2AtmExchangeCoeff_canopy)*2._rkind) ! d(frictionVelocity)/d(canopy air temperature) + dED_dT = dFV_dT*vkc*(heightCanopyTopAboveSnow - zeroPlaneDisplacement) ! d(eddyDiffusCanopyTop)d(canopy air temperature) + dGR_dT = -dED_dT*(tmp1 - tmp2)*heightCanopyTopAboveSnow*exp(windReductionFactor) / (windReductionFactor*eddyDiffusCanopyTop**2._rkind) ! d(groundResistanceNeutral)/d(canopy air temperature) + ! (stitch everything together -- product rule) + dGroundResistance_dTCanair = dGR_dT/groundStabilityCorrection - groundResistanceNeutral*dGroundStabilityCorrection_dCasTemp/(groundStabilityCorrection**2._rkind) + ! ***** compute resistances for non-vegetated surfaces (e.g., snow) - else - - ! set canopy derivatives to zero (non-vegetated, remember) - dCanopyResistance_dTCanopy = 0._rkind - dGroundResistance_dTCanopy = 0._rkind - - ! compute derivatives for ground resistance - dGroundResistance_dTGround = -dGroundStabilityCorrection_dSfcTemp/(windspd*groundExNeut*groundStabilityCorrection**2._rkind) - - end if ! (switch between vegetated and non-vegetated surfaces) - - ! * analytical derivatives not desired - else - dGroundResistance_dTGround = missingValue - dGroundResistance_dTCanopy = missingValue - dCanopyResistance_dTCanopy = missingValue - end if - - ! test - !print*, 'dGroundResistance_dTGround = ', dGroundResistance_dTGround - !print*, 'dGroundResistance_dTCanopy = ', dGroundResistance_dTCanopy - !print*, 'dCanopyResistance_dTCanopy = ', dCanopyResistance_dTCanopy - !pause 'in aeroResist' - - end subroutine aeroResist - - - ! ******************************************************************************************************* - ! private subroutine soilResist: compute soil moisture factor controlling stomatal resistance - ! ******************************************************************************************************* - subroutine soilResist(& - ! input (model decisions) - ixSoilResist, & ! intent(in): choice of function for the soil moisture control on stomatal resistance - ixGroundwater, & ! intent(in): choice of groundwater representation - ! input (state variables) - mLayerMatricHead, & ! intent(in): matric head in each layer (m) - mLayerVolFracLiq, & ! intent(in): volumetric fraction of liquid water in each layer - scalarAquiferStorage, & ! intent(in): aquifer storage (m) - ! input (diagnostic variables) - mLayerRootDensity, & ! intent(in): root density in each layer (-) - scalarAquiferRootFrac, & ! intent(in): fraction of roots below the lowest unsaturated layer (-) - ! input (parameters) - plantWiltPsi, & ! intent(in): matric head at wilting point (m) - soilStressParam, & ! intent(in): parameter in the exponential soil stress function (-) - critSoilWilting, & ! intent(in): critical vol. liq. water content when plants are wilting (-) - critSoilTranspire, & ! intent(in): critical vol. liq. water content when transpiration is limited (-) - critAquiferTranspire, & ! intent(in): critical aquifer storage value when transpiration is limited (m) - ! output - wAvgTranspireLimitFac, & ! intent(out): weighted average of the transpiration limiting factor (-) - mLayerTranspireLimitFac, & ! intent(out): transpiration limiting factor in each layer (-) - aquiferTranspireLimitFac, & ! intent(out): transpiration limiting factor for the aquifer (-) - err,message) ! intent(out): error control - ! ----------------------------------------------------------------------------------------------------------------------------------------- - USE mDecisions_module, only: NoahType,CLM_Type,SiB_Type ! options for the choice of function for the soil moisture control on stomatal resistance - USE mDecisions_module, only: bigBucket ! named variable that defines the "bigBucket" groundwater parameterization - implicit none - ! input (model decisions) - integer(i4b),intent(in) :: ixSoilResist ! choice of function for the soil moisture control on stomatal resistance - integer(i4b),intent(in) :: ixGroundwater ! choice of groundwater representation - ! input (variables) - real(rkind),intent(in) :: mLayerMatricHead(:) ! matric head in each layer (m) - real(rkind),intent(in) :: mLayerVolFracLiq(:) ! volumetric fraction of liquid water in each layer (-) - real(rkind),intent(in) :: scalarAquiferStorage ! aquifer storage (m) - ! input (diagnostic variables) - real(rkind),intent(in) :: mLayerRootDensity(:) ! root density in each layer (-) - real(rkind),intent(in) :: scalarAquiferRootFrac ! fraction of roots below the lowest unsaturated layer (-) - ! input (parameters) - real(rkind),intent(in) :: plantWiltPsi ! matric head at wilting point (m) - real(rkind),intent(in) :: soilStressParam ! parameter in the exponential soil stress function (-) - real(rkind),intent(in) :: critSoilWilting ! critical vol. liq. water content when plants are wilting (-) - real(rkind),intent(in) :: critSoilTranspire ! critical vol. liq. water content when transpiration is limited (-) - real(rkind),intent(in) :: critAquiferTranspire ! critical aquifer storage value when transpiration is limited (m) - ! output - real(rkind),intent(out) :: wAvgTranspireLimitFac ! intent(out): weighted average of the transpiration limiting factor (-) - real(rkind),intent(out) :: mLayerTranspireLimitFac(:) ! intent(out): transpiration limiting factor in each layer (-) - real(rkind),intent(out) :: aquiferTranspireLimitFac ! intent(out): transpiration limiting factor for the aquifer (-) - integer(i4b),intent(out) :: err ! error code - character(*),intent(out) :: message ! error message - ! local variables - real(rkind) :: gx ! stress function for the soil layers - real(rkind),parameter :: verySmall=epsilon(gx) ! a very small number - integer(i4b) :: iLayer ! index of soil layer - ! initialize error control - err=0; message='soilResist/' - - ! ** compute the factor limiting transpiration for each soil layer (-) - wAvgTranspireLimitFac = 0._rkind ! (initialize the weighted average) - do iLayer=1,size(mLayerMatricHead) - ! compute the soil stress function - select case(ixSoilResist) - case(NoahType) ! thresholded linear function of volumetric liquid water content + else + + ! set canopy derivatives to zero (non-vegetated, remember) + dCanopyResistance_dTCanopy = 0._rkind + dGroundResistance_dTCanopy = 0._rkind + + ! compute derivatives for ground resistance + dGroundResistance_dTGround = -dGroundStabilityCorrection_dSfcTemp/(windspd*groundExNeut*groundStabilityCorrection**2._rkind) + + end if ! (switch between vegetated and non-vegetated surfaces) + + ! * analytical derivatives not desired + else + dGroundResistance_dTGround = missingValue + dGroundResistance_dTCanopy = missingValue + dCanopyResistance_dTCanopy = missingValue + end if + +end subroutine aeroResist + + +! ******************************************************************************************************* +! private subroutine soilResist: compute soil moisture factor controlling stomatal resistance +! ******************************************************************************************************* +subroutine soilResist(& + ! input (model decisions) + ixSoilResist, & ! intent(in): choice of function for the soil moisture control on stomatal resistance + ixGroundwater, & ! intent(in): choice of groundwater representation + ! input (state variables) + mLayerMatricHead, & ! intent(in): matric head in each layer (m) + mLayerVolFracLiq, & ! intent(in): volumetric fraction of liquid water in each layer + scalarAquiferStorage, & ! intent(in): aquifer storage (m) + ! input (diagnostic variables) + mLayerRootDensity, & ! intent(in): root density in each layer (-) + scalarAquiferRootFrac, & ! intent(in): fraction of roots below the lowest unsaturated layer (-) + ! input (parameters) + plantWiltPsi, & ! intent(in): matric head at wilting point (m) + soilStressParam, & ! intent(in): parameter in the exponential soil stress function (-) + critSoilWilting, & ! intent(in): critical vol. liq. water content when plants are wilting (-) + critSoilTranspire, & ! intent(in): critical vol. liq. water content when transpiration is limited (-) + critAquiferTranspire, & ! intent(in): critical aquifer storage value when transpiration is limited (m) + ! output + wAvgTranspireLimitFac, & ! intent(out): weighted average of the transpiration limiting factor (-) + mLayerTranspireLimitFac, & ! intent(out): transpiration limiting factor in each layer (-) + aquiferTranspireLimitFac, & ! intent(out): transpiration limiting factor for the aquifer (-) + err,message) ! intent(out): error control + ! ----------------------------------------------------------------------------------------------------------------------------------------- + USE mDecisions_module, only: NoahType,CLM_Type,SiB_Type ! options for the choice of function for the soil moisture control on stomatal resistance + USE mDecisions_module, only: bigBucket ! named variable that defines the "bigBucket" groundwater parameterization + implicit none + ! input (model decisions) + integer(i4b),intent(in) :: ixSoilResist ! choice of function for the soil moisture control on stomatal resistance + integer(i4b),intent(in) :: ixGroundwater ! choice of groundwater representation + ! input (variables) + real(rkind),intent(in) :: mLayerMatricHead(:) ! matric head in each layer (m) + real(rkind),intent(in) :: mLayerVolFracLiq(:) ! volumetric fraction of liquid water in each layer (-) + real(rkind),intent(in) :: scalarAquiferStorage ! aquifer storage (m) + ! input (diagnostic variables) + real(rkind),intent(in) :: mLayerRootDensity(:) ! root density in each layer (-) + real(rkind),intent(in) :: scalarAquiferRootFrac ! fraction of roots below the lowest unsaturated layer (-) + ! input (parameters) + real(rkind),intent(in) :: plantWiltPsi ! matric head at wilting point (m) + real(rkind),intent(in) :: soilStressParam ! parameter in the exponential soil stress function (-) + real(rkind),intent(in) :: critSoilWilting ! critical vol. liq. water content when plants are wilting (-) + real(rkind),intent(in) :: critSoilTranspire ! critical vol. liq. water content when transpiration is limited (-) + real(rkind),intent(in) :: critAquiferTranspire ! critical aquifer storage value when transpiration is limited (m) + ! output + real(rkind),intent(out) :: wAvgTranspireLimitFac ! intent(out): weighted average of the transpiration limiting factor (-) + real(rkind),intent(out) :: mLayerTranspireLimitFac(:) ! intent(out): transpiration limiting factor in each layer (-) + real(rkind),intent(out) :: aquiferTranspireLimitFac ! intent(out): transpiration limiting factor for the aquifer (-) + integer(i4b),intent(out) :: err ! error code + character(*),intent(out) :: message ! error message + ! local variables + real(rkind) :: gx ! stress function for the soil layers + real(rkind),parameter :: verySmall=epsilon(gx) ! a very small number + integer(i4b) :: iLayer ! index of soil layer + ! initialize error control + err=0; message='soilResist/' + + ! ** compute the factor limiting transpiration for each soil layer (-) + wAvgTranspireLimitFac = 0._rkind ! (initialize the weighted average) + do iLayer=1,size(mLayerMatricHead) + ! compute the soil stress function + select case(ixSoilResist) + case(NoahType) ! thresholded linear function of volumetric liquid water content gx = (mLayerVolFracLiq(iLayer) - critSoilWilting) / (critSoilTranspire - critSoilWilting) - case(CLM_Type) ! thresholded linear function of matric head + case(CLM_Type) ! thresholded linear function of matric head if(mLayerMatricHead(iLayer) > plantWiltPsi)then - gx = 1._rkind - mLayerMatricHead(iLayer)/plantWiltPsi + gx = 1._rkind - mLayerMatricHead(iLayer)/plantWiltPsi else - gx = 0._rkind + gx = 0._rkind end if - case(SiB_Type) ! exponential of the log of matric head + case(SiB_Type) ! exponential of the log of matric head if(mLayerMatricHead(iLayer) < 0._rkind)then ! (unsaturated) - gx = 1._rkind - exp( -soilStressParam * ( log(plantWiltPsi/mLayerMatricHead(iLayer)) ) ) + gx = 1._rkind - exp( -soilStressParam * ( log(plantWiltPsi/mLayerMatricHead(iLayer)) ) ) else ! (saturated) - gx = 1._rkind + gx = 1._rkind end if - case default ! check identified the option + case default ! check identified the option err=20; message=trim(message)//'cannot identify option for soil resistance'; return - end select - ! save the factor for the given layer (ensure between zero and one) - mLayerTranspireLimitFac(iLayer) = min( max(verySmall,gx), 1._rkind) - ! compute the weighted average (weighted by root density) - wAvgTranspireLimitFac = wAvgTranspireLimitFac + mLayerTranspireLimitFac(iLayer)*mLayerRootDensity(iLayer) - end do ! (looping through soil layers) - - ! ** compute the factor limiting evaporation in the aquifer - if(scalarAquiferRootFrac > verySmall)then - ! check that aquifer root fraction is allowed - if(ixGroundwater /= bigBucket)then - message=trim(message)//'aquifer evaporation only allowed for the big groundwater bucket -- increase the soil depth to account for roots' - err=20; return - end if - ! compute the factor limiting evaporation for the aquifer - aquiferTranspireLimitFac = min(scalarAquiferStorage/critAquiferTranspire, 1._rkind) - else ! (if there are roots in the aquifer) - aquiferTranspireLimitFac = 0._rkind - end if - - ! compute the weighted average (weighted by root density) - wAvgTranspireLimitFac = wAvgTranspireLimitFac + aquiferTranspireLimitFac*scalarAquiferRootFrac - - end subroutine soilResist - - - ! ******************************************************************************** - ! private subroutine turbFluxes: compute turbulent heat fluxes - ! ******************************************************************************** - subroutine turbFluxes(& - ! input: model control - computeVegFlux, & ! intent(in): logical flag to compute vegetation fluxes (.false. if veg buried by snow) - ixDerivMethod, & ! intent(in): choice of method used to compute derivative (analytical or numerical) - ! input: above-canopy forcing data - airtemp, & ! intent(in): air temperature at some height above the surface (K) - airpres, & ! intent(in): air pressure of the air above the vegetation canopy (Pa) - VPair, & ! intent(in): vapor pressure of the air above the vegetation canopy (Pa) - ! input: latent heat of sublimation/vaporization - latHeatSubVapCanopy, & ! intent(in): latent heat of sublimation/vaporization for the vegetation canopy (J kg-1) - latHeatSubVapGround, & ! intent(in): latent heat of sublimation/vaporization for the ground surface (J kg-1) - ! input: canopy and ground temperature - canairTemp, & ! intent(in): temperature of the canopy air space (K) - canopyTemp, & ! intent(in): canopy temperature (K) - groundTemp, & ! intent(in): ground temperature (K) - satVP_CanopyTemp, & ! intent(in): saturation vapor pressure at the temperature of the veg canopy (Pa) - satVP_GroundTemp, & ! intent(in): saturation vapor pressure at the temperature of the ground (Pa) - dSVPCanopy_dCanopyTemp, & ! intent(in): derivative in canopy saturation vapor pressure w.r.t. canopy temperature (Pa K-1) - dSVPGround_dGroundTemp, & ! intent(in): derivative in ground saturation vapor pressure w.r.t. ground temperature (Pa K-1) - ! input: diagnostic variables - exposedVAI, & ! intent(in): exposed vegetation area index -- leaf plus stem (m2 m-2) - canopyWetFraction, & ! intent(in): fraction of canopy that is wet [0-1] - dCanopyWetFraction_dWat, & ! intent(in): derivative in the canopy wetted fraction w.r.t. total water content (kg-1 m-2) - dCanopyWetFraction_dT, & ! intent(in): derivative in wetted fraction w.r.t. canopy temperature (K-1) - canopySunlitLAI, & ! intent(in): sunlit leaf area (-) - canopyShadedLAI, & ! intent(in): shaded leaf area (-) - soilRelHumidity, & ! intent(in): relative humidity in the soil pores [0-1] - soilResistance, & ! intent(in): resistance from the soil (s m-1) - leafResistance, & ! intent(in): mean leaf boundary layer resistance per unit leaf area (s m-1) - groundResistance, & ! intent(in): below canopy aerodynamic resistance (s m-1) - canopyResistance, & ! intent(in): above canopy aerodynamic resistance (s m-1) - stomResistSunlit, & ! intent(in): stomatal resistance for sunlit leaves (s m-1) - stomResistShaded, & ! intent(in): stomatal resistance for shaded leaves (s m-1) - ! input: derivatives in scalar resistances - dGroundResistance_dTGround, & ! intent(in): derivative in ground resistance w.r.t. ground temperature (s m-1 K-1) - dGroundResistance_dTCanopy, & ! intent(in): derivative in ground resistance w.r.t. canopy temperature (s m-1 K-1) - dGroundResistance_dTCanair, & ! intent(in): derivative in ground resistance w.r.t. canopy air temperature (s m-1 K-1) - dCanopyResistance_dTCanopy, & ! intent(in): derivative in canopy resistance w.r.t. canopy temperature (s m-1 K-1) - dCanopyResistance_dTCanair, & ! intent(in): derivative in canopy resistance w.r.t. canopy air temperature (s m-1 K-1) - ! output: conductances (used to check derivative calculations) - leafConductance, & ! intent(out): leaf conductance (m s-1) - canopyConductance, & ! intent(out): canopy conductance (m s-1) - groundConductanceSH, & ! intent(out): ground conductance for sensible heat (m s-1) - groundConductanceLH, & ! intent(out): ground conductance for latent heat -- includes soil resistance (m s-1) - evapConductance, & ! intent(out): conductance for evaporation (m s-1) - transConductance, & ! intent(out): conductance for transpiration (m s-1) - totalConductanceSH, & ! intent(out): total conductance for sensible heat (m s-1) - totalConductanceLH, & ! intent(out): total conductance for latent heat (m s-1) - ! output: canopy air space variables - VP_CanopyAir, & ! intent(out): vapor pressure of the canopy air space (Pa) - ! output: fluxes from the vegetation canopy - senHeatCanopy, & ! intent(out): sensible heat flux from the canopy to the canopy air space (W m-2) - latHeatCanopyEvap, & ! intent(out): latent heat flux associated with evaporation from the canopy to the canopy air space (W m-2) - latHeatCanopyTrans, & ! intent(out): latent heat flux associated with transpiration from the canopy to the canopy air space (W m-2) - ! output: fluxes from non-vegetated surfaces (ground surface below vegetation, bare ground, or snow covered vegetation) - senHeatGround, & ! intent(out): sensible heat flux from ground surface below vegetation, bare ground, or snow covered vegetation (W m-2) - latHeatGround, & ! intent(out): latent heat flux from ground surface below vegetation, bare ground, or snow covered vegetation (W m-2) - ! output: total heat fluxes to the atmosphere - senHeatTotal, & ! intent(out): total sensible heat flux to the atmosphere (W m-2) - latHeatTotal, & ! intent(out): total latent heat flux to the atmosphere (W m-2) - ! output: net fluxes - turbFluxCanair, & ! intent(out): net turbulent heat fluxes at the canopy air space (W m-2) - turbFluxCanopy, & ! intent(out): net turbulent heat fluxes at the canopy (W m-2) - turbFluxGround, & ! intent(out): net turbulent heat fluxes at the ground surface (W m-2) - ! output: flux derivatives - dTurbFluxCanair_dTCanair, & ! intent(out): derivative in net canopy air space fluxes w.r.t. canopy air temperature (W m-2 K-1) - dTurbFluxCanair_dTCanopy, & ! intent(out): derivative in net canopy air space fluxes w.r.t. canopy temperature (W m-2 K-1) - dTurbFluxCanair_dTGround, & ! intent(out): derivative in net canopy air space fluxes w.r.t. ground temperature (W m-2 K-1) - dTurbFluxCanopy_dTCanair, & ! intent(out): derivative in net canopy turbulent fluxes w.r.t. canopy air temperature (W m-2 K-1) - dTurbFluxCanopy_dTCanopy, & ! intent(out): derivative in net canopy turbulent fluxes w.r.t. canopy temperature (W m-2 K-1) - dTurbFluxCanopy_dTGround, & ! intent(out): derivative in net canopy turbulent fluxes w.r.t. ground temperature (W m-2 K-1) - dTurbFluxGround_dTCanair, & ! intent(out): derivative in net ground turbulent fluxes w.r.t. canopy air temperature (W m-2 K-1) - dTurbFluxGround_dTCanopy, & ! intent(out): derivative in net ground turbulent fluxes w.r.t. canopy temperature (W m-2 K-1) - dTurbFluxGround_dTGround, & ! intent(out): derivative in net ground turbulent fluxes w.r.t. ground temperature (W m-2 K-1) - ! output: liquid flux derivatives (canopy evap) - dLatHeatCanopyEvap_dCanWat, & ! intent(out): derivative in latent heat of canopy evaporation w.r.t. canopy total water content (J kg-1 s-1) - dLatHeatCanopyEvap_dTCanair, & ! intent(out): derivative in latent heat of canopy evaporation w.r.t. canopy air temperature (W m-2 K-1) - dLatHeatCanopyEvap_dTCanopy, & ! intent(out): derivative in latent heat of canopy evaporation w.r.t. canopy temperature (W m-2 K-1) - dLatHeatCanopyEvap_dTGround, & ! intent(out): derivative in latent heat of canopy evaporation w.r.t. ground temperature (W m-2 K-1) - ! output: liquid flux derivatives (ground evap) - dLatHeatGroundEvap_dCanWat, & ! intent(out): derivative in latent heat of ground evaporation w.r.t. canopy total water content (J kg-1 s-1) - dLatHeatGroundEvap_dTCanair, & ! intent(out): derivative in latent heat of ground evaporation w.r.t. canopy air temperature - dLatHeatGroundEvap_dTCanopy, & ! intent(out): derivative in latent heat of ground evaporation w.r.t. canopy temperature - dLatHeatGroundEvap_dTGround, & ! intent(out): derivative in latent heat of ground evaporation w.r.t. ground temperature - ! output: latent heat flux derivatives (canopy trans) - dLatHeatCanopyTrans_dCanWat, & ! intent(out): derivative in the latent heat of canopy transpiration w.r.t. canopy total water (J kg-1 s-1) - dLatHeatCanopyTrans_dTCanair, & ! intent(out): derivative in the latent heat of canopy transpiration w.r.t. canopy air temperature - dLatHeatCanopyTrans_dTCanopy, & ! intent(out): derivative in the latent heat of canopy transpiration w.r.t. canopy temperature - dLatHeatCanopyTrans_dTGround, & ! intent(out): derivative in the latent heat of canopy transpiration w.r.t. ground temperature - ! output: cross derivatives - dTurbFluxCanair_dCanWat, & ! intent(out): derivative in net canopy air space fluxes w.r.t. canopy total water content (J kg-1 s-1) - dTurbFluxCanopy_dCanWat, & ! intent(out): derivative in net canopy turbulent fluxes w.r.t. canopy total water content (J kg-1 s-1) - dTurbFluxGround_dCanWat, & ! intent(out): derivative in net ground turbulent fluxes w.r.t. canopy total water content (J kg-1 s-1) - ! output: error control - err,message ) ! intent(out): error control - ! ----------------------------------------------------------------------------------------------------------------------------------------- - implicit none - ! input: model control - logical(lgt),intent(in) :: computeVegFlux ! logical flag to compute vegetation fluxes (.false. if veg buried by snow) - integer(i4b),intent(in) :: ixDerivMethod ! choice of method used to compute derivative (analytical or numerical) - ! input: above-canopy forcing data - real(rkind),intent(in) :: airtemp ! air temperature at some height above the surface (K) - real(rkind),intent(in) :: airpres ! air pressure of the air above the vegetation canopy (Pa) - real(rkind),intent(in) :: VPair ! vapor pressure of the air above the vegetation canopy (Pa) - ! input: latent heat of sublimation/vaporization - real(rkind),intent(in) :: latHeatSubVapCanopy ! latent heat of sublimation/vaporization for the vegetation canopy (J kg-1) - real(rkind),intent(in) :: latHeatSubVapGround ! latent heat of sublimation/vaporization for the ground surface (J kg-1) - ! input: canopy and ground temperature - real(rkind),intent(in) :: canairTemp ! temperature of the canopy air space (K) - real(rkind),intent(in) :: canopyTemp ! canopy temperature (K) - real(rkind),intent(in) :: groundTemp ! ground temperature (K) - real(rkind),intent(in) :: satVP_CanopyTemp ! saturation vapor pressure at the temperature of the veg canopy (Pa) - real(rkind),intent(in) :: satVP_GroundTemp ! saturation vapor pressure at the temperature of the ground (Pa) - real(rkind),intent(in) :: dSVPCanopy_dCanopyTemp ! derivative in canopy saturation vapor pressure w.r.t. canopy temperature (Pa K-1) - real(rkind),intent(in) :: dSVPGround_dGroundTemp ! derivative in ground saturation vapor pressure w.r.t. ground temperature (Pa K-1) - ! input: diagnostic variables - real(rkind),intent(in) :: exposedVAI ! exposed vegetation area index -- leaf plus stem (m2 m-2) - real(rkind),intent(in) :: canopyWetFraction ! fraction of canopy that is wet [0-1] - real(rkind),intent(in) :: dCanopyWetFraction_dWat ! derivative in the canopy wetted fraction w.r.t. liquid water content (kg-1 m-2) - real(rkind),intent(in) :: dCanopyWetFraction_dT ! derivative in the canopy wetted fraction w.r.t. canopy temperature (K-1) - real(rkind),intent(in) :: canopySunlitLAI ! sunlit leaf area (-) - real(rkind),intent(in) :: canopyShadedLAI ! shaded leaf area (-) - real(rkind),intent(in) :: soilRelHumidity ! relative humidity in the soil pores [0-1] - real(rkind),intent(in) :: soilResistance ! resistance from the soil (s m-1) - real(rkind),intent(in) :: leafResistance ! mean leaf boundary layer resistance per unit leaf area (s m-1) - real(rkind),intent(in) :: groundResistance ! below canopy aerodynamic resistance (s m-1) - real(rkind),intent(in) :: canopyResistance ! above canopy aerodynamic resistance (s m-1) - real(rkind),intent(in) :: stomResistSunlit ! stomatal resistance for sunlit leaves (s m-1) - real(rkind),intent(in) :: stomResistShaded ! stomatal resistance for shaded leaves (s m-1) - ! input: derivatives in scalar resistances - real(rkind),intent(in) :: dGroundResistance_dTGround ! derivative in ground resistance w.r.t. ground temperature (s m-1 K-1) - real(rkind),intent(in) :: dGroundResistance_dTCanopy ! derivative in ground resistance w.r.t. canopy temperature (s m-1 K-1) - real(rkind),intent(in) :: dGroundResistance_dTCanair ! derivative in ground resistance w.r.t. canopy air temperature (s m-1 K-1) - real(rkind),intent(in) :: dCanopyResistance_dTCanopy ! derivative in canopy resistance w.r.t. canopy temperature (s m-1 K-1) - real(rkind),intent(in) :: dCanopyResistance_dTCanair ! derivative in canopy resistance w.r.t. canopy air temperature (s m-1 K-1) - ! --------------------------------------------------------------------------------------------------------------------------------------------------------------- - ! output: conductances -- used to test derivatives - real(rkind),intent(out) :: leafConductance ! leaf conductance (m s-1) - real(rkind),intent(out) :: canopyConductance ! canopy conductance (m s-1) - real(rkind),intent(out) :: groundConductanceSH ! ground conductance for sensible heat (m s-1) - real(rkind),intent(out) :: groundConductanceLH ! ground conductance for latent heat -- includes soil resistance (m s-1) - real(rkind),intent(out) :: evapConductance ! conductance for evaporation (m s-1) - real(rkind),intent(out) :: transConductance ! conductance for transpiration (m s-1) - real(rkind),intent(out) :: totalConductanceSH ! total conductance for sensible heat (m s-1) - real(rkind),intent(out) :: totalConductanceLH ! total conductance for latent heat (m s-1) - ! output: canopy air space variables - real(rkind),intent(out) :: VP_CanopyAir ! vapor pressure of the canopy air space (Pa) - ! output: fluxes from the vegetation canopy - real(rkind),intent(out) :: senHeatCanopy ! sensible heat flux from the canopy to the canopy air space (W m-2) - real(rkind),intent(out) :: latHeatCanopyEvap ! latent heat flux associated with evaporation from the canopy to the canopy air space (W m-2) - real(rkind),intent(out) :: latHeatCanopyTrans ! latent heat flux associated with transpiration from the canopy to the canopy air space (W m-2) - ! output: fluxes from non-vegetated surfaces (ground surface below vegetation, bare ground, or snow covered vegetation) - real(rkind),intent(out) :: senHeatGround ! sensible heat flux from ground surface below vegetation, bare ground, or snow covered vegetation (W m-2) - real(rkind),intent(out) :: latHeatGround ! latent heat flux from ground surface below vegetation, bare ground, or snow covered vegetation (W m-2) - ! output: total heat fluxes to the atmosphere - real(rkind),intent(out) :: senHeatTotal ! total sensible heat flux to the atmosphere (W m-2) - real(rkind),intent(out) :: latHeatTotal ! total latent heat flux to the atmosphere (W m-2) - ! output: net fluxes - real(rkind),intent(out) :: turbFluxCanair ! net turbulent heat fluxes at the canopy air space (W m-2) - real(rkind),intent(out) :: turbFluxCanopy ! net turbulent heat fluxes at the canopy (W m-2) - real(rkind),intent(out) :: turbFluxGround ! net turbulent heat fluxes at the ground surface (W m-2) - ! output: energy flux derivatives - real(rkind),intent(out) :: dTurbFluxCanair_dTCanair ! derivative in net canopy air space fluxes w.r.t. canopy air temperature (W m-2 K-1) - real(rkind),intent(out) :: dTurbFluxCanair_dTCanopy ! derivative in net canopy air space fluxes w.r.t. canopy temperature (W m-2 K-1) - real(rkind),intent(out) :: dTurbFluxCanair_dTGround ! derivative in net canopy air space fluxes w.r.t. ground temperature (W m-2 K-1) - real(rkind),intent(out) :: dTurbFluxCanopy_dTCanair ! derivative in net canopy turbulent fluxes w.r.t. canopy air temperature (W m-2 K-1) - real(rkind),intent(out) :: dTurbFluxCanopy_dTCanopy ! derivative in net canopy turbulent fluxes w.r.t. canopy temperature (W m-2 K-1) - real(rkind),intent(out) :: dTurbFluxCanopy_dTGround ! derivative in net canopy turbulent fluxes w.r.t. ground temperature (W m-2 K-1) - real(rkind),intent(out) :: dTurbFluxGround_dTCanair ! derivative in net ground turbulent fluxes w.r.t. canopy air temperature (W m-2 K-1) - real(rkind),intent(out) :: dTurbFluxGround_dTCanopy ! derivative in net ground turbulent fluxes w.r.t. canopy temperature (W m-2 K-1) - real(rkind),intent(out) :: dTurbFluxGround_dTGround ! derivative in net ground turbulent fluxes w.r.t. ground temperature (W m-2 K-1) - ! output: liquid flux derivatives (canopy evap) - real(rkind),intent(out) :: dLatHeatCanopyEvap_dCanWat ! derivative in latent heat of canopy evaporation w.r.t. canopy total water content (W kg-1) - real(rkind),intent(out) :: dLatHeatCanopyEvap_dTCanair ! derivative in latent heat of canopy evaporation w.r.t. canopy air temperature (W m-2 K-1) - real(rkind),intent(out) :: dLatHeatCanopyEvap_dTCanopy ! derivative in latent heat of canopy evaporation w.r.t. canopy temperature (W m-2 K-1) - real(rkind),intent(out) :: dLatHeatCanopyEvap_dTGround ! derivative in latent heat of canopy evaporation w.r.t. ground temperature (W m-2 K-1) - ! output: liquid flux derivatives (ground evap) - real(rkind),intent(out) :: dLatHeatGroundEvap_dCanWat ! derivative in latent heat of ground evaporation w.r.t. canopy total water content (J kg-1 s-1) - real(rkind),intent(out) :: dLatHeatGroundEvap_dTCanair ! derivative in latent heat of ground evaporation w.r.t. canopy air temperature (W m-2 K-1) - real(rkind),intent(out) :: dLatHeatGroundEvap_dTCanopy ! derivative in latent heat of ground evaporation w.r.t. canopy temperature (W m-2 K-1) - real(rkind),intent(out) :: dLatHeatGroundEvap_dTGround ! derivative in latent heat of ground evaporation w.r.t. ground temperature (W m-2 K-1) - ! output: latent heat flux derivatives (canopy trans) - real(rkind) :: dLatHeatCanopyTrans_dCanWat ! derivative in the latent heat of canopy transpiration w.r.t. canopy total water (J kg-1 s-1) - real(rkind) :: dLatHeatCanopyTrans_dTCanair ! derivative in the latent heat of canopy transpiration w.r.t. canopy air temperature - real(rkind) :: dLatHeatCanopyTrans_dTCanopy ! derivative in the latent heat of canopy transpiration w.r.t. canopy temperature - real(rkind) :: dLatHeatCanopyTrans_dTGround ! derivative in the latent heat of canopy transpiration flux w.r.t. ground temperature - ! output: cross derivatives - real(rkind),intent(out) :: dTurbFluxCanair_dCanWat ! derivative in net canopy air space fluxes w.r.t. canopy total water content (J kg-1 s-1) - real(rkind),intent(out) :: dTurbFluxCanopy_dCanWat ! derivative in net canopy turbulent fluxes w.r.t. canopy total water content (J kg-1 s-1) - real(rkind),intent(out) :: dTurbFluxGround_dCanWat ! derivative in net ground turbulent fluxes w.r.t. canopy total water content (J kg-1 s-1) - ! output: error control - integer(i4b),intent(out) :: err ! error code - character(*),intent(out) :: message ! error message - ! ----------------------------------------------------------------------------------------------------------------------------------------- - ! local variables -- general - real(rkind) :: fpart1,fpart2 ! different parts of a function - real(rkind) :: dPart0,dpart1,dpart2 ! derivatives for different parts of a function - ! local variables -- "constants" - real(rkind) :: volHeatCapacityAir ! volumetric heat capacity of air (J m-3) - real(rkind) :: latentHeatConstant ! latent heat constant (kg m-3 K-1) - ! local variables -- derivatives for energy conductances - real(rkind) :: dEvapCond_dCanopyTemp ! derivative in evap conductance w.r.t. canopy temperature - real(rkind) :: dTransCond_dCanopyTemp ! derivative in trans conductance w.r.t. canopy temperature - real(rkind) :: dCanopyCond_dCanairTemp ! derivative in canopy conductance w.r.t. canopy air temperature - real(rkind) :: dCanopyCond_dCanopyTemp ! derivative in canopy conductance w.r.t. canopy temperature - real(rkind) :: dGroundCondSH_dCanairTemp ! derivative in ground conductance of sensible heat w.r.t. canopy air temperature - real(rkind) :: dGroundCondSH_dCanopyTemp ! derivative in ground conductance of sensible heat w.r.t. canopy temperature - real(rkind) :: dGroundCondSH_dGroundTemp ! derivative in ground conductance of sensible heat w.r.t. ground temperature - ! local variables -- derivatives for mass conductances - real(rkind) :: dGroundCondLH_dCanairTemp ! derivative in ground conductance w.r.t. canopy air temperature - real(rkind) :: dGroundCondLH_dCanopyTemp ! derivative in ground conductance w.r.t. canopy temperature - real(rkind) :: dGroundCondLH_dGroundTemp ! derivative in ground conductance w.r.t. ground temperature - ! local variables -- derivatives for the canopy air space variables - real(rkind) :: fPart_VP ! part of the function for vapor pressure of the canopy air space - real(rkind) :: leafConductanceTr ! leaf conductance for transpiration (m s-1) - real(rkind) :: dVPCanopyAir_dTCanair ! derivative in the vapor pressure of the canopy air space w.r.t. temperature of the canopy air space - real(rkind) :: dVPCanopyAir_dTCanopy ! derivative in the vapor pressure of the canopy air space w.r.t. temperature of the canopy - real(rkind) :: dVPCanopyAir_dTGround ! derivative in the vapor pressure of the canopy air space w.r.t. temperature of the ground - real(rkind) :: dVPCanopyAir_dWetFrac ! derivative of vapor pressure in the canopy air space w.r.t. wetted fraction of the canopy - real(rkind) :: dVPCanopyAir_dCanWat ! derivative of vapor pressure in the canopy air space w.r.t. canopy total water content - ! local variables -- sensible heat flux derivatives - real(rkind) :: dSenHeatTotal_dTCanair ! derivative in the total sensible heat flux w.r.t. canopy air temperature - real(rkind) :: dSenHeatTotal_dTCanopy ! derivative in the total sensible heat flux w.r.t. canopy air temperature - real(rkind) :: dSenHeatTotal_dTGround ! derivative in the total sensible heat flux w.r.t. ground temperature - real(rkind) :: dSenHeatCanopy_dTCanair ! derivative in the canopy sensible heat flux w.r.t. canopy air temperature - real(rkind) :: dSenHeatCanopy_dTCanopy ! derivative in the canopy sensible heat flux w.r.t. canopy temperature - real(rkind) :: dSenHeatCanopy_dTGround ! derivative in the canopy sensible heat flux w.r.t. ground temperature - real(rkind) :: dSenHeatGround_dTCanair ! derivative in the ground sensible heat flux w.r.t. canopy air temperature - real(rkind) :: dSenHeatGround_dTCanopy ! derivative in the ground sensible heat flux w.r.t. canopy temperature - real(rkind) :: dSenHeatGround_dTGround ! derivative in the ground sensible heat flux w.r.t. ground temperature - ! local variables -- wetted fraction derivatives - real(rkind) :: dLatHeatCanopyEvap_dWetFrac ! derivative in the latent heat of canopy evaporation w.r.t. canopy wet fraction (W m-2) - real(rkind) :: dLatHeatCanopyTrans_dWetFrac ! derivative in the latent heat of canopy transpiration w.r.t. canopy wet fraction (W m-2) - ! ----------------------------------------------------------------------------------------------------------------------------------------- - ! initialize error control - err=0; message='turbFluxes/' - - ! compute constants - volHeatCapacityAir = iden_air*cp_air ! volumetric heat capacity of air (J m-3) - latentHeatConstant = iden_air*w_ratio/airpres ! latent heat constant for (kg m-3 Pa-1) - - ! ***** - ! * compute conductances, and derivatives... - ! ****************************************** - - ! compute conductances for sensible heat (m s-1) - if(computeVegFlux)then - leafConductance = exposedVAI/leafResistance - leafConductanceTr = canopySunlitLAI/(leafResistance+stomResistSunlit) + canopyShadedLAI/(leafResistance+stomResistShaded) - canopyConductance = 1._rkind/canopyResistance - else - leafConductance = 0._rkind - canopyConductance = 0._rkind - end if - groundConductanceSH = 1._rkind/groundResistance - - ! compute total conductance for sensible heat - totalConductanceSH = leafConductance + groundConductanceSH + canopyConductance - - ! compute conductances for latent heat (m s-1) - if(computeVegFlux)then - evapConductance = canopyWetFraction*leafConductance - transConductance = (1._rkind - canopyWetFraction) * leafConductanceTr - !write(*,'(a,10(f14.8,1x))') 'canopySunlitLAI, canopyShadedLAI, stomResistSunlit, stomResistShaded, leafResistance, canopyWetFraction = ', & - ! canopySunlitLAI, canopyShadedLAI, stomResistSunlit, stomResistShaded, leafResistance, canopyWetFraction - else - evapConductance = 0._rkind - transConductance = 0._rkind - end if - groundConductanceLH = 1._rkind/(groundResistance + soilResistance) ! NOTE: soilResistance accounts for fractional snow, and =0 when snow cover is 100% - totalConductanceLH = evapConductance + transConductance + groundConductanceLH + canopyConductance - - ! check sensible heat conductance - if(totalConductanceSH < -tinyVal .or. groundConductanceSH < -tinyVal .or. canopyConductance < -tinyVal)then - message=trim(message)//'negative conductance for sensible heat' - err=20; return - endif - - ! check latent heat conductance - if(totalConductanceLH < tinyVal .or. groundConductanceLH < -tinyVal)then - message=trim(message)//'negative conductance for latent heat' + end select + ! save the factor for the given layer (ensure between zero and one) + mLayerTranspireLimitFac(iLayer) = min( max(verySmall,gx), 1._rkind) + ! compute the weighted average (weighted by root density) + wAvgTranspireLimitFac = wAvgTranspireLimitFac + mLayerTranspireLimitFac(iLayer)*mLayerRootDensity(iLayer) + end do ! (looping through soil layers) + + ! ** compute the factor limiting evaporation in the aquifer + if(scalarAquiferRootFrac > verySmall)then + ! check that aquifer root fraction is allowed + if(ixGroundwater /= bigBucket)then + message=trim(message)//'aquifer evaporation only allowed for the big groundwater bucket -- increase the soil depth to account for roots' err=20; return - endif - - ! * compute derivatives - ! NOTE: it may be more efficient to compute these derivatives when computing resistances - if(ixDerivMethod == analytical)then - - ! compute derivatives in individual conductances for sensible heat w.r.t. canopy temperature (m s-1 K-1) - if(computeVegFlux)then - dEvapCond_dCanopyTemp = dCanopyWetFraction_dT*leafConductance ! derivative in evap conductance w.r.t. canopy temperature - dTransCond_dCanopyTemp = -dCanopyWetFraction_dT*leafConductanceTr ! derivative in trans conductance w.r.t. canopy temperature - dCanopyCond_dCanairTemp = -dCanopyResistance_dTCanair/canopyResistance**2._rkind ! derivative in canopy conductance w.r.t. canopy air emperature - dCanopyCond_dCanopyTemp = -dCanopyResistance_dTCanopy/canopyResistance**2._rkind ! derivative in canopy conductance w.r.t. canopy temperature - dGroundCondSH_dCanairTemp = -dGroundResistance_dTCanair/groundResistance**2._rkind ! derivative in ground conductance w.r.t. canopy air temperature - dGroundCondSH_dCanopyTemp = -dGroundResistance_dTCanopy/groundResistance**2._rkind ! derivative in ground conductance w.r.t. canopy temperature - dGroundCondSH_dGroundTemp = -dGroundResistance_dTGround/groundResistance**2._rkind ! derivative in ground conductance w.r.t. ground temperature - else - dEvapCond_dCanopyTemp = 0._rkind ! derivative in evap conductance w.r.t. canopy temperature - dTransCond_dCanopyTemp = 0._rkind ! derivative in trans conductance w.r.t. canopy temperature - dCanopyCond_dCanairTemp = 0._rkind ! derivative in canopy conductance w.r.t. canopy air emperature - dCanopyCond_dCanopyTemp = 0._rkind ! derivative in canopy conductance w.r.t. canopy temperature - dGroundCondSH_dCanairTemp = 0._rkind ! derivative in ground conductance w.r.t. canopy air temperature - dGroundCondSH_dCanopyTemp = 0._rkind ! derivative in ground conductance w.r.t. canopy temperature - dGroundCondSH_dGroundTemp = -dGroundResistance_dTGround/groundResistance**2._rkind ! derivative in ground conductance w.r.t. ground temperature - end if - - ! compute derivatives in individual conductances for latent heat w.r.t. canopy temperature (m s-1 K-1) - if(computeVegFlux)then - dGroundCondLH_dCanairTemp = -dGroundResistance_dTCanair/(groundResistance+soilResistance)**2._rkind ! derivative in ground conductance w.r.t. canopy air temperature - dGroundCondLH_dCanopyTemp = -dGroundResistance_dTCanopy/(groundResistance+soilResistance)**2._rkind ! derivative in ground conductance w.r.t. canopy temperature - dGroundCondLH_dGroundTemp = -dGroundResistance_dTGround/(groundResistance+soilResistance)**2._rkind ! derivative in ground conductance w.r.t. ground temperature - else - dGroundCondLH_dCanairTemp = 0._rkind ! derivative in ground conductance w.r.t. canopy air temperature - dGroundCondLH_dCanopyTemp = 0._rkind ! derivative in ground conductance w.r.t. canopy temperature - dGroundCondLH_dGroundTemp = -dGroundResistance_dTGround/(groundResistance+soilResistance)**2._rkind ! derivative in ground conductance w.r.t. ground temperature - end if - - end if ! (if computing analytical derivatives) - - ! ***** - ! * compute sensible and latent heat fluxes, and derivatives... - ! ************************************************************* - - ! * compute sensible and latent heat fluxes from the canopy to the canopy air space (W m-2) - if(computeVegFlux)then - - ! compute the vapor pressure in the canopy air space (Pa) - fPart_VP = canopyConductance*VPair + (evapConductance + transConductance)*satVP_CanopyTemp + groundConductanceLH*satVP_GroundTemp*soilRelHumidity - VP_CanopyAir = fPart_VP/totalConductanceLH - !write(*,'(a,10(f20.10,1x))') 'canopyConductance, evapConductance, transConductance, groundConductanceLH, soilRelHumidity = ', & - ! canopyConductance, evapConductance, transConductance, groundConductanceLH, soilRelHumidity - - ! compute sensible heat flux from the canopy air space to the atmosphere - ! NOTE: canairTemp is a state variable - senHeatTotal = -volHeatCapacityAir*canopyConductance*(canairTemp - airtemp) - !print*, 'canairTemp, airtemp, senHeatTotal = ', canairTemp, airtemp, senHeatTotal - - ! compute fluxes - senHeatCanopy = -volHeatCapacityAir*leafConductance*(canopyTemp - canairTemp) ! (positive downwards) - latHeatCanopyEvap = -latHeatSubVapCanopy*latentHeatConstant*evapConductance*(satVP_CanopyTemp - VP_CanopyAir) ! (positive downwards) - latHeatCanopyTrans = -LH_vap*latentHeatConstant*transConductance*(satVP_CanopyTemp - VP_CanopyAir) ! (positive downwards) - !write(*,'(a,10(f25.15,1x))') 'latHeatCanopyEvap, VP_CanopyAir = ', latHeatCanopyEvap, VP_CanopyAir - !write(*,'(a,10(f25.15,1x))') 'latHeatCanopyTrans, VP_CanopyAir = ', latHeatCanopyTrans, VP_CanopyAir - !write(*,'(a,10(f25.15,1x))') 'transConductance = ', transConductance - - ! check that energy for canopy evaporation does not exhaust the available water - ! NOTE: do this here, rather than enforcing solution constraints, because energy and mass solutions may be uncoupled - !if(latHeatSubVapCanopy > LH_vap+verySmall)then ! (sublimation) - ! maxFlux = -canopyIce*LH_sub/dt ! W m-2 - !else ! (evaporation) - ! maxFlux = -canopyLiquid*LH_vap/dt ! W m-2 - !end if - ! NOTE: fluxes are positive downwards - !if(latHeatCanopyEvap < maxFlux) latHeatCanopyEvap = maxFlux - !write(*,'(a,10(f20.10,1x))') 'maxFlux, latHeatCanopyEvap = ', maxFlux, latHeatCanopyEvap - - ! * no vegetation, so fluxes are zero - else - senHeatCanopy = 0._rkind - latHeatCanopyEvap = 0._rkind - latHeatCanopyTrans = 0._rkind - end if - - ! compute sensible and latent heat fluxes from the ground to the canopy air space (W m-2) - if(computeVegFlux)then - senHeatGround = -volHeatCapacityAir*groundConductanceSH*(groundTemp - canairTemp) ! (positive downwards) - latHeatGround = -latHeatSubVapGround*latentHeatConstant*groundConductanceLH*(satVP_GroundTemp*soilRelHumidity - VP_CanopyAir) ! (positive downwards) - else - senHeatGround = -volHeatCapacityAir*groundConductanceSH*(groundTemp - airtemp) ! (positive downwards) - latHeatGround = -latHeatSubVapGround*latentHeatConstant*groundConductanceLH*(satVP_GroundTemp*soilRelHumidity - VPair) ! (positive downwards) - senHeatTotal = senHeatGround - end if - !write(*,'(a,10(f25.15,1x))') 'latHeatGround = ', latHeatGround - - ! compute latent heat flux from the canopy air space to the atmosphere - ! NOTE: VP_CanopyAir is a diagnostic variable - latHeatTotal = latHeatCanopyEvap + latHeatCanopyTrans + latHeatGround - - ! * compute derivatives - if(ixDerivMethod == analytical)then - - ! differentiate CANOPY fluxes - if(computeVegFlux)then - - ! compute derivatives of vapor pressure in the canopy air space w.r.t. all state variables - ! (derivative of vapor pressure in the canopy air space w.r.t. temperature of the canopy air space) - dPart1 = dCanopyCond_dCanairTemp*VPair + dGroundCondLH_dCanairTemp*satVP_GroundTemp*soilRelHumidity - dPart2 = -(dCanopyCond_dCanairTemp + dGroundCondLH_dCanairTemp)/(totalConductanceLH**2._rkind) - dVPCanopyAir_dTCanair = dPart1/totalConductanceLH + fPart_VP*dPart2 - ! (derivative of vapor pressure in the canopy air space w.r.t. temperature of the canopy) - dPart0 = (evapConductance + transConductance)*dSVPCanopy_dCanopyTemp + (dEvapCond_dCanopyTemp + dTransCond_dCanopyTemp)*satVP_CanopyTemp - dPart1 = dCanopyCond_dCanopyTemp*VPair + dPart0 + dGroundCondLH_dCanopyTemp*satVP_GroundTemp*soilRelHumidity - dPart2 = -(dCanopyCond_dCanopyTemp + dEvapCond_dCanopyTemp + dTransCond_dCanopyTemp + dGroundCondLH_dCanopyTemp)/(totalConductanceLH**2._rkind) - dVPCanopyAir_dTCanopy = dPart1/totalConductanceLH + fPart_VP*dPart2 - ! (derivative of vapor pressure in the canopy air space w.r.t. temperature of the ground) - dPart1 = dGroundCondLH_dGroundTemp*satVP_GroundTemp*soilRelHumidity + groundConductanceLH*dSVPGround_dGroundTemp*soilRelHumidity - dPart2 = -dGroundCondLH_dGroundTemp/(totalConductanceLH**2._rkind) - dVPCanopyAir_dTGround = dPart1/totalConductanceLH + fPart_VP*dPart2 - ! (derivative of vapor pressure in the canopy air space w.r.t. wetted fraction of the canopy) - dPart1 = (leafConductance - leafConductanceTr)*satVP_CanopyTemp - dPart2 = -(leafConductance - leafConductanceTr)/(totalConductanceLH**2._rkind) - dVPCanopyAir_dWetFrac = dPart1/totalConductanceLH + fPart_VP*dPart2 - dVPCanopyAir_dCanWat = dVPCanopyAir_dWetFrac*dCanopyWetFraction_dWat - !write(*,'(a,5(f20.8,1x))') 'dVPCanopyAir_dTCanair, dVPCanopyAir_dTCanopy, dVPCanopyAir_dTGround, dVPCanopyAir_dWetFrac, dVPCanopyAir_dCanWat = ', & - ! dVPCanopyAir_dTCanair, dVPCanopyAir_dTCanopy, dVPCanopyAir_dTGround, dVPCanopyAir_dWetFrac, dVPCanopyAir_dCanWat - - ! sensible heat from the canopy to the atmosphere - dSenHeatTotal_dTCanair = -volHeatCapacityAir*canopyConductance - volHeatCapacityAir*dCanopyCond_dCanairTemp*(canairTemp - airtemp) - dSenHeatTotal_dTCanopy = -volHeatCapacityAir*dCanopyCond_dCanopyTemp*(canairTemp - airtemp) - dSenHeatTotal_dTGround = 0._rkind - !write(*,'(a,3(f20.8,1x))') 'dSenHeatTotal_dTCanair, dSenHeatTotal_dTCanopy, dSenHeatTotal_dTGround = ', & - ! dSenHeatTotal_dTCanair, dSenHeatTotal_dTCanopy, dSenHeatTotal_dTGround - - ! sensible heat from the canopy to the canopy air space - dSenHeatCanopy_dTCanair = volHeatCapacityAir*leafConductance - dSenHeatCanopy_dTCanopy = -volHeatCapacityAir*leafConductance - dSenHeatCanopy_dTGround = 0._rkind - !write(*,'(a,3(f20.8,1x))') 'dSenHeatCanopy_dTCanair, dSenHeatCanopy_dTCanopy, dSenHeatCanopy_dTGround = ', & - ! dSenHeatCanopy_dTCanair, dSenHeatCanopy_dTCanopy, dSenHeatCanopy_dTGround - - ! sensible heat from the ground to the canopy air space - dSenHeatGround_dTCanair = -volHeatCapacityAir*dGroundCondSH_dCanairTemp*(groundTemp - canairTemp) + volHeatCapacityAir*groundConductanceSH - dSenHeatGround_dTCanopy = -volHeatCapacityAir*dGroundCondSH_dCanopyTemp*(groundTemp - canairTemp) - dSenHeatGround_dTGround = -volHeatCapacityAir*dGroundCondSH_dGroundTemp*(groundTemp - canairTemp) - volHeatCapacityAir*groundConductanceSH - !write(*,'(a,3(f20.8,1x))') 'dSenHeatGround_dTCanair, dSenHeatGround_dTCanopy, dSenHeatGround_dTGround = ', & - ! dSenHeatGround_dTCanair, dSenHeatGround_dTCanopy, dSenHeatGround_dTGround - - ! latent heat associated with canopy evaporation - ! (initial calculations) - fPart1 = -latHeatSubVapCanopy*latentHeatConstant*evapConductance - dPart1 = -latHeatSubVapCanopy*latentHeatConstant*dEvapCond_dCanopyTemp - fPart2 = satVP_CanopyTemp - VP_CanopyAir - dPart2 = dSVPCanopy_dCanopyTemp - dVPCanopyAir_dTCanopy - ! (derivatives) - dLatHeatCanopyEvap_dTCanair = fPart1*(-dVPCanopyAir_dTCanair) - dLatHeatCanopyEvap_dTCanopy = fPart1*dpart2 + fPart2*dPart1 - dLatHeatCanopyEvap_dTGround = fPart1*(-dVPCanopyAir_dTGround) - !write(*,'(a,3(f20.8,1x))') 'dLatHeatCanopyEvap_dTCanair, dLatHeatCanopyEvap_dTCanopy, dLatHeatCanopyEvap_dTGround = ', & - ! dLatHeatCanopyEvap_dTCanair, dLatHeatCanopyEvap_dTCanopy, dLatHeatCanopyEvap_dTGround - - ! latent heat associated with canopy transpiration - ! (initial calculations) - fPart1 = -LH_vap*latentHeatConstant*transConductance - dPart1 = -LH_vap*latentHeatConstant*dTransCond_dCanopyTemp - ! (derivatives) - dLatHeatCanopyTrans_dTCanair = fPart1*(-dVPCanopyAir_dTCanair) - dLatHeatCanopyTrans_dTCanopy = fPart1*dPart2 + fPart2*dPart1 - dLatHeatCanopyTrans_dTGround = fPart1*(-dVPCanopyAir_dTGround) - !write(*,'(a,3(f20.8,1x))') 'dLatHeatCanopyTrans_dTCanair, dLatHeatCanopyTrans_dTCanopy, dLatHeatCanopyTrans_dTGround = ', & - ! dLatHeatCanopyTrans_dTCanair, dLatHeatCanopyTrans_dTCanopy, dLatHeatCanopyTrans_dTGround - - ! latent heat flux from the ground - fPart1 = -latHeatSubVapGround*latentHeatConstant*groundConductanceLH ! function of the first part - fPart2 = (satVP_GroundTemp*soilRelHumidity - VP_CanopyAir) ! function of the second part - dLatHeatGroundEvap_dTCanair = -latHeatSubVapGround*latentHeatConstant*dGroundCondLH_dCanairTemp*fPart2 - dVPCanopyAir_dTCanair*fPart1 - dLatHeatGroundEvap_dTCanopy = -latHeatSubVapGround*latentHeatConstant*dGroundCondLH_dCanopyTemp*fPart2 - dVPCanopyAir_dTCanopy*fPart1 - dLatHeatGroundEvap_dTGround = -latHeatSubVapGround*latentHeatConstant*dGroundCondLH_dGroundTemp*fPart2 + (dSVPGround_dGroundTemp*soilRelHumidity - dVPCanopyAir_dTGround)*fPart1 - !write(*,'(a,3(f20.8,1x))') 'dLatHeatGroundEvap_dTCanair, dLatHeatGroundEvap_dTCanopy, dLatHeatGroundEvap_dTGround = ', & - ! dLatHeatGroundEvap_dTCanair, dLatHeatGroundEvap_dTCanopy, dLatHeatGroundEvap_dTGround - - ! latent heat associated with canopy evaporation w.r.t. wetted fraction of the canopy - dPart1 = -latHeatSubVapCanopy*latentHeatConstant*leafConductance - fPart1 = dPart1*canopyWetFraction - dLatHeatCanopyEvap_dWetFrac = dPart1*(satVP_CanopyTemp - VP_CanopyAir) + fPart1*(-dVPCanopyAir_dWetFrac) - - ! latent heat associated with canopy transpiration w.r.t. wetted fraction of the canopy - dPart1 = LH_vap*latentHeatConstant*leafConductanceTr ! NOTE: positive, since (1 - wetFrac) - fPart1 = -dPart1*(1._rkind - canopyWetFraction) - dLatHeatCanopyTrans_dWetFrac = dPart1*(satVP_CanopyTemp - VP_CanopyAir) + fPart1*(-dVPCanopyAir_dWetFrac) - !print*, 'dLatHeatCanopyTrans_dWetFrac = ', dLatHeatCanopyTrans_dWetFrac - - ! latent heat associated with canopy transpiration w.r.t. canopy total water - dLatHeatCanopyTrans_dCanWat = dLatHeatCanopyTrans_dWetFrac*dCanopyWetFraction_dWat ! (J s-1 kg-1) - !print*, 'dLatHeatCanopyTrans_dCanWat = ', dLatHeatCanopyTrans_dCanWat - - else ! canopy is undefined - - ! set derivatives for canopy fluxes to zero (no canopy, so fluxes are undefined) - dSenHeatTotal_dTCanair = 0._rkind - dSenHeatTotal_dTCanopy = 0._rkind - dSenHeatTotal_dTGround = 0._rkind - dSenHeatCanopy_dTCanair = 0._rkind - dSenHeatCanopy_dTCanopy = 0._rkind - dSenHeatCanopy_dTGround = 0._rkind - dLatHeatCanopyEvap_dTCanair = 0._rkind - dLatHeatCanopyEvap_dTCanopy = 0._rkind - dLatHeatCanopyEvap_dTGround = 0._rkind - dLatHeatCanopyTrans_dTCanair = 0._rkind - dLatHeatCanopyTrans_dTCanopy = 0._rkind - dLatHeatCanopyTrans_dTGround = 0._rkind - - ! set derivatives for wetted area and canopy transpiration to zero (no canopy, so fluxes are undefined) - dLatHeatCanopyEvap_dWetFrac = 0._rkind - dLatHeatCanopyEvap_dCanWat = 0._rkind - dLatHeatCanopyTrans_dCanWat = 0._rkind - dVPCanopyAir_dCanWat = 0._rkind - - ! set derivatives for ground fluxes w.r.t canopy temperature to zero (no canopy, so fluxes are undefined) - dSenHeatGround_dTCanair = 0._rkind - dSenHeatGround_dTCanopy = 0._rkind - dLatHeatGroundEvap_dTCanair = 0._rkind - dLatHeatGroundEvap_dTCanopy = 0._rkind - - ! compute derivatives for the ground fluxes w.r.t. ground temperature - dSenHeatGround_dTGround = (-volHeatCapacityAir*dGroundCondSH_dGroundTemp)*(groundTemp - airtemp) + & ! d(ground sensible heat flux)/d(ground temp) - (-volHeatCapacityAir*groundConductanceSH) - dLatHeatGroundEvap_dTGround = (-latHeatSubVapGround*latentHeatConstant*dGroundCondLH_dGroundTemp)*(satVP_GroundTemp*soilRelHumidity - VPair) + & ! d(ground latent heat flux)/d(ground temp) - (-latHeatSubVapGround*latentHeatConstant*groundConductanceLH)*dSVPGround_dGroundTemp*soilRelHumidity - - !print*, 'dGroundCondLH_dGroundTemp = ', dGroundCondLH_dGroundTemp - - end if ! (if canopy is defined) - - end if ! (if computing analytical derivatives) - - - ! ***** - ! * compute net turbulent fluxes, and derivatives... - ! ************************************************** - - ! compute net fluxes - turbFluxCanair = senHeatTotal - senHeatCanopy - senHeatGround ! net turbulent flux at the canopy air space (W m-2) - turbFluxCanopy = senHeatCanopy + latHeatCanopyEvap + latHeatCanopyTrans ! net turbulent flux at the canopy (W m-2) - turbFluxGround = senHeatGround + latHeatGround ! net turbulent flux at the ground surface (W m-2) - !write(*,'(a,1x,3(f20.10,1x))') 'senHeatCanopy, latHeatCanopyEvap, latHeatCanopyTrans = ', senHeatCanopy, latHeatCanopyEvap, latHeatCanopyTrans - - ! * compute derivatives - if(ixDerivMethod == analytical)then - ! (energy derivatives) - dTurbFluxCanair_dTCanair = dSenHeatTotal_dTCanair - dSenHeatCanopy_dTCanair - dSenHeatGround_dTCanair ! derivative in net canopy air space fluxes w.r.t. canopy air temperature (W m-2 K-1) - dTurbFluxCanair_dTCanopy = dSenHeatTotal_dTCanopy - dSenHeatCanopy_dTCanopy - dSenHeatGround_dTCanopy ! derivative in net canopy air space fluxes w.r.t. canopy temperature (W m-2 K-1) - dTurbFluxCanair_dTGround = dSenHeatTotal_dTGround - dSenHeatCanopy_dTGround - dSenHeatGround_dTGround ! derivative in net canopy air space fluxes w.r.t. ground temperature (W m-2 K-1) - dTurbFluxCanopy_dTCanair = dSenHeatCanopy_dTCanair + dLatHeatCanopyEvap_dTCanair + dLatHeatCanopyTrans_dTCanair ! derivative in net canopy turbulent fluxes w.r.t. canopy air temperature (W m-2 K-1) - dTurbFluxCanopy_dTCanopy = dSenHeatCanopy_dTCanopy + dLatHeatCanopyEvap_dTCanopy + dLatHeatCanopyTrans_dTCanopy ! derivative in net canopy turbulent fluxes w.r.t. canopy temperature (W m-2 K-1) - dTurbFluxCanopy_dTGround = dSenHeatCanopy_dTGround + dLatHeatCanopyEvap_dTGround + dLatHeatCanopyTrans_dTGround ! derivative in net canopy turbulent fluxes w.r.t. ground temperature (W m-2 K-1) - dTurbFluxGround_dTCanair = dSenHeatGround_dTCanair + dLatHeatGroundEvap_dTCanair ! derivative in net ground turbulent fluxes w.r.t. canopy air temperature (W m-2 K-1) - dTurbFluxGround_dTCanopy = dSenHeatGround_dTCanopy + dLatHeatGroundEvap_dTCanopy ! derivative in net ground turbulent fluxes w.r.t. canopy temperature (W m-2 K-1) - dTurbFluxGround_dTGround = dSenHeatGround_dTGround + dLatHeatGroundEvap_dTGround ! derivative in net ground turbulent fluxes w.r.t. ground temperature (W m-2 K-1) - ! (liquid water derivatives) - dLatHeatCanopyEvap_dCanWat = dLatHeatCanopyEvap_dWetFrac*dCanopyWetFraction_dWat ! derivative in latent heat of canopy evaporation w.r.t. canopy total water (W kg-1) - dLatHeatGroundEvap_dCanWat = latHeatSubVapGround*latentHeatConstant*groundConductanceLH*dVPCanopyAir_dCanWat ! derivative in latent heat of ground evaporation w.r.t. canopy total water (J kg-1 s-1) - ! (cross deriavtives) - dTurbFluxCanair_dCanWat = 0._rkind ! derivative in net canopy air space fluxes w.r.t. canopy total water content (J kg-1 s-1) - dTurbFluxCanopy_dCanWat = dLatHeatCanopyEvap_dCanWat + dLatHeatCanopyTrans_dCanWat ! derivative in net canopy turbulent fluxes w.r.t. canopy total water content (J kg-1 s-1) - dTurbFluxGround_dCanWat = dLatHeatGroundEvap_dCanWat ! derivative in net ground turbulent fluxes w.r.t. canopy total water content (J kg-1 s-1) - else ! (just make sure we return something) - ! (energy derivatives) - dTurbFluxCanair_dTCanair = 0._rkind - dTurbFluxCanair_dTCanopy = 0._rkind - dTurbFluxCanair_dTGround = 0._rkind - dTurbFluxCanopy_dTCanair = 0._rkind - dTurbFluxCanopy_dTCanopy = 0._rkind - dTurbFluxCanopy_dTGround = 0._rkind - dTurbFluxGround_dTCanair = 0._rkind - dTurbFluxGround_dTCanopy = 0._rkind - dTurbFluxGround_dTGround = 0._rkind - ! (liquid water derivatives) + end if + ! compute the factor limiting evaporation for the aquifer + aquiferTranspireLimitFac = min(scalarAquiferStorage/critAquiferTranspire, 1._rkind) + else ! (if there are roots in the aquifer) + aquiferTranspireLimitFac = 0._rkind + end if + + ! compute the weighted average (weighted by root density) + wAvgTranspireLimitFac = wAvgTranspireLimitFac + aquiferTranspireLimitFac*scalarAquiferRootFrac + +end subroutine soilResist + + +! ******************************************************************************** +! private subroutine turbFluxes: compute turbulent heat fluxes +! ******************************************************************************** +subroutine turbFluxes(& + ! input: model control + computeVegFlux, & ! intent(in): logical flag to compute vegetation fluxes (.false. if veg buried by snow) + ixDerivMethod, & ! intent(in): choice of method used to compute derivative (analytical or numerical) + ! input: above-canopy forcing data + airtemp, & ! intent(in): air temperature at some height above the surface (K) + airpres, & ! intent(in): air pressure of the air above the vegetation canopy (Pa) + VPair, & ! intent(in): vapor pressure of the air above the vegetation canopy (Pa) + ! input: latent heat of sublimation/vaporization + latHeatSubVapCanopy, & ! intent(in): latent heat of sublimation/vaporization for the vegetation canopy (J kg-1) + latHeatSubVapGround, & ! intent(in): latent heat of sublimation/vaporization for the ground surface (J kg-1) + ! input: canopy and ground temperature + canairTemp, & ! intent(in): temperature of the canopy air space (K) + canopyTemp, & ! intent(in): canopy temperature (K) + groundTemp, & ! intent(in): ground temperature (K) + satVP_CanopyTemp, & ! intent(in): saturation vapor pressure at the temperature of the veg canopy (Pa) + satVP_GroundTemp, & ! intent(in): saturation vapor pressure at the temperature of the ground (Pa) + dSVPCanopy_dCanopyTemp, & ! intent(in): derivative in canopy saturation vapor pressure w.r.t. canopy temperature (Pa K-1) + dSVPGround_dGroundTemp, & ! intent(in): derivative in ground saturation vapor pressure w.r.t. ground temperature (Pa K-1) + ! input: diagnostic variables + exposedVAI, & ! intent(in): exposed vegetation area index -- leaf plus stem (m2 m-2) + canopyWetFraction, & ! intent(in): fraction of canopy that is wet [0-1] + dCanopyWetFraction_dWat, & ! intent(in): derivative in the canopy wetted fraction w.r.t. total water content (kg-1 m-2) + dCanopyWetFraction_dT, & ! intent(in): derivative in wetted fraction w.r.t. canopy temperature (K-1) + canopySunlitLAI, & ! intent(in): sunlit leaf area (-) + canopyShadedLAI, & ! intent(in): shaded leaf area (-) + soilRelHumidity, & ! intent(in): relative humidity in the soil pores [0-1] + soilResistance, & ! intent(in): resistance from the soil (s m-1) + leafResistance, & ! intent(in): mean leaf boundary layer resistance per unit leaf area (s m-1) + groundResistance, & ! intent(in): below canopy aerodynamic resistance (s m-1) + canopyResistance, & ! intent(in): above canopy aerodynamic resistance (s m-1) + stomResistSunlit, & ! intent(in): stomatal resistance for sunlit leaves (s m-1) + stomResistShaded, & ! intent(in): stomatal resistance for shaded leaves (s m-1) + ! input: derivatives in scalar resistances + dGroundResistance_dTGround, & ! intent(in): derivative in ground resistance w.r.t. ground temperature (s m-1 K-1) + dGroundResistance_dTCanopy, & ! intent(in): derivative in ground resistance w.r.t. canopy temperature (s m-1 K-1) + dGroundResistance_dTCanair, & ! intent(in): derivative in ground resistance w.r.t. canopy air temperature (s m-1 K-1) + dCanopyResistance_dTCanopy, & ! intent(in): derivative in canopy resistance w.r.t. canopy temperature (s m-1 K-1) + dCanopyResistance_dTCanair, & ! intent(in): derivative in canopy resistance w.r.t. canopy air temperature (s m-1 K-1) + ! output: conductances (used to check derivative calculations) + leafConductance, & ! intent(out): leaf conductance (m s-1) + canopyConductance, & ! intent(out): canopy conductance (m s-1) + groundConductanceSH, & ! intent(out): ground conductance for sensible heat (m s-1) + groundConductanceLH, & ! intent(out): ground conductance for latent heat -- includes soil resistance (m s-1) + evapConductance, & ! intent(out): conductance for evaporation (m s-1) + transConductance, & ! intent(out): conductance for transpiration (m s-1) + totalConductanceSH, & ! intent(out): total conductance for sensible heat (m s-1) + totalConductanceLH, & ! intent(out): total conductance for latent heat (m s-1) + ! output: canopy air space variables + VP_CanopyAir, & ! intent(out): vapor pressure of the canopy air space (Pa) + ! output: fluxes from the vegetation canopy + senHeatCanopy, & ! intent(out): sensible heat flux from the canopy to the canopy air space (W m-2) + latHeatCanopyEvap, & ! intent(out): latent heat flux associated with evaporation from the canopy to the canopy air space (W m-2) + latHeatCanopyTrans, & ! intent(out): latent heat flux associated with transpiration from the canopy to the canopy air space (W m-2) + ! output: fluxes from non-vegetated surfaces (ground surface below vegetation, bare ground, or snow covered vegetation) + senHeatGround, & ! intent(out): sensible heat flux from ground surface below vegetation, bare ground, or snow covered vegetation (W m-2) + latHeatGround, & ! intent(out): latent heat flux from ground surface below vegetation, bare ground, or snow covered vegetation (W m-2) + ! output: total heat fluxes to the atmosphere + senHeatTotal, & ! intent(out): total sensible heat flux to the atmosphere (W m-2) + latHeatTotal, & ! intent(out): total latent heat flux to the atmosphere (W m-2) + ! output: net fluxes + turbFluxCanair, & ! intent(out): net turbulent heat fluxes at the canopy air space (W m-2) + turbFluxCanopy, & ! intent(out): net turbulent heat fluxes at the canopy (W m-2) + turbFluxGround, & ! intent(out): net turbulent heat fluxes at the ground surface (W m-2) + ! output: flux derivatives + dTurbFluxCanair_dTCanair, & ! intent(out): derivative in net canopy air space fluxes w.r.t. canopy air temperature (W m-2 K-1) + dTurbFluxCanair_dTCanopy, & ! intent(out): derivative in net canopy air space fluxes w.r.t. canopy temperature (W m-2 K-1) + dTurbFluxCanair_dTGround, & ! intent(out): derivative in net canopy air space fluxes w.r.t. ground temperature (W m-2 K-1) + dTurbFluxCanopy_dTCanair, & ! intent(out): derivative in net canopy turbulent fluxes w.r.t. canopy air temperature (W m-2 K-1) + dTurbFluxCanopy_dTCanopy, & ! intent(out): derivative in net canopy turbulent fluxes w.r.t. canopy temperature (W m-2 K-1) + dTurbFluxCanopy_dTGround, & ! intent(out): derivative in net canopy turbulent fluxes w.r.t. ground temperature (W m-2 K-1) + dTurbFluxGround_dTCanair, & ! intent(out): derivative in net ground turbulent fluxes w.r.t. canopy air temperature (W m-2 K-1) + dTurbFluxGround_dTCanopy, & ! intent(out): derivative in net ground turbulent fluxes w.r.t. canopy temperature (W m-2 K-1) + dTurbFluxGround_dTGround, & ! intent(out): derivative in net ground turbulent fluxes w.r.t. ground temperature (W m-2 K-1) + ! output: liquid flux derivatives (canopy evap) + dLatHeatCanopyEvap_dCanWat, & ! intent(out): derivative in latent heat of canopy evaporation w.r.t. canopy total water content (J kg-1 s-1) + dLatHeatCanopyEvap_dTCanair, & ! intent(out): derivative in latent heat of canopy evaporation w.r.t. canopy air temperature (W m-2 K-1) + dLatHeatCanopyEvap_dTCanopy, & ! intent(out): derivative in latent heat of canopy evaporation w.r.t. canopy temperature (W m-2 K-1) + dLatHeatCanopyEvap_dTGround, & ! intent(out): derivative in latent heat of canopy evaporation w.r.t. ground temperature (W m-2 K-1) + ! output: liquid flux derivatives (ground evap) + dLatHeatGroundEvap_dCanWat, & ! intent(out): derivative in latent heat of ground evaporation w.r.t. canopy total water content (J kg-1 s-1) + dLatHeatGroundEvap_dTCanair, & ! intent(out): derivative in latent heat of ground evaporation w.r.t. canopy air temperature + dLatHeatGroundEvap_dTCanopy, & ! intent(out): derivative in latent heat of ground evaporation w.r.t. canopy temperature + dLatHeatGroundEvap_dTGround, & ! intent(out): derivative in latent heat of ground evaporation w.r.t. ground temperature + ! output: latent heat flux derivatives (canopy trans) + dLatHeatCanopyTrans_dCanWat, & ! intent(out): derivative in the latent heat of canopy transpiration w.r.t. canopy total water (J kg-1 s-1) + dLatHeatCanopyTrans_dTCanair, & ! intent(out): derivative in the latent heat of canopy transpiration w.r.t. canopy air temperature + dLatHeatCanopyTrans_dTCanopy, & ! intent(out): derivative in the latent heat of canopy transpiration w.r.t. canopy temperature + dLatHeatCanopyTrans_dTGround, & ! intent(out): derivative in the latent heat of canopy transpiration w.r.t. ground temperature + ! output: cross derivatives + dTurbFluxCanair_dCanWat, & ! intent(out): derivative in net canopy air space fluxes w.r.t. canopy total water content (J kg-1 s-1) + dTurbFluxCanopy_dCanWat, & ! intent(out): derivative in net canopy turbulent fluxes w.r.t. canopy total water content (J kg-1 s-1) + dTurbFluxGround_dCanWat, & ! intent(out): derivative in net ground turbulent fluxes w.r.t. canopy total water content (J kg-1 s-1) + ! output: error control + err,message ) ! intent(out): error control + ! ----------------------------------------------------------------------------------------------------------------------------------------- + implicit none + ! input: model control + logical(lgt),intent(in) :: computeVegFlux ! logical flag to compute vegetation fluxes (.false. if veg buried by snow) + integer(i4b),intent(in) :: ixDerivMethod ! choice of method used to compute derivative (analytical or numerical) + ! input: above-canopy forcing data + real(rkind),intent(in) :: airtemp ! air temperature at some height above the surface (K) + real(rkind),intent(in) :: airpres ! air pressure of the air above the vegetation canopy (Pa) + real(rkind),intent(in) :: VPair ! vapor pressure of the air above the vegetation canopy (Pa) + ! input: latent heat of sublimation/vaporization + real(rkind),intent(in) :: latHeatSubVapCanopy ! latent heat of sublimation/vaporization for the vegetation canopy (J kg-1) + real(rkind),intent(in) :: latHeatSubVapGround ! latent heat of sublimation/vaporization for the ground surface (J kg-1) + ! input: canopy and ground temperature + real(rkind),intent(in) :: canairTemp ! temperature of the canopy air space (K) + real(rkind),intent(in) :: canopyTemp ! canopy temperature (K) + real(rkind),intent(in) :: groundTemp ! ground temperature (K) + real(rkind),intent(in) :: satVP_CanopyTemp ! saturation vapor pressure at the temperature of the veg canopy (Pa) + real(rkind),intent(in) :: satVP_GroundTemp ! saturation vapor pressure at the temperature of the ground (Pa) + real(rkind),intent(in) :: dSVPCanopy_dCanopyTemp ! derivative in canopy saturation vapor pressure w.r.t. canopy temperature (Pa K-1) + real(rkind),intent(in) :: dSVPGround_dGroundTemp ! derivative in ground saturation vapor pressure w.r.t. ground temperature (Pa K-1) + ! input: diagnostic variables + real(rkind),intent(in) :: exposedVAI ! exposed vegetation area index -- leaf plus stem (m2 m-2) + real(rkind),intent(in) :: canopyWetFraction ! fraction of canopy that is wet [0-1] + real(rkind),intent(in) :: dCanopyWetFraction_dWat ! derivative in the canopy wetted fraction w.r.t. liquid water content (kg-1 m-2) + real(rkind),intent(in) :: dCanopyWetFraction_dT ! derivative in the canopy wetted fraction w.r.t. canopy temperature (K-1) + real(rkind),intent(in) :: canopySunlitLAI ! sunlit leaf area (-) + real(rkind),intent(in) :: canopyShadedLAI ! shaded leaf area (-) + real(rkind),intent(in) :: soilRelHumidity ! relative humidity in the soil pores [0-1] + real(rkind),intent(in) :: soilResistance ! resistance from the soil (s m-1) + real(rkind),intent(in) :: leafResistance ! mean leaf boundary layer resistance per unit leaf area (s m-1) + real(rkind),intent(in) :: groundResistance ! below canopy aerodynamic resistance (s m-1) + real(rkind),intent(in) :: canopyResistance ! above canopy aerodynamic resistance (s m-1) + real(rkind),intent(in) :: stomResistSunlit ! stomatal resistance for sunlit leaves (s m-1) + real(rkind),intent(in) :: stomResistShaded ! stomatal resistance for shaded leaves (s m-1) + ! input: derivatives in scalar resistances + real(rkind),intent(in) :: dGroundResistance_dTGround ! derivative in ground resistance w.r.t. ground temperature (s m-1 K-1) + real(rkind),intent(in) :: dGroundResistance_dTCanopy ! derivative in ground resistance w.r.t. canopy temperature (s m-1 K-1) + real(rkind),intent(in) :: dGroundResistance_dTCanair ! derivative in ground resistance w.r.t. canopy air temperature (s m-1 K-1) + real(rkind),intent(in) :: dCanopyResistance_dTCanopy ! derivative in canopy resistance w.r.t. canopy temperature (s m-1 K-1) + real(rkind),intent(in) :: dCanopyResistance_dTCanair ! derivative in canopy resistance w.r.t. canopy air temperature (s m-1 K-1) + ! --------------------------------------------------------------------------------------------------------------------------------------------------------------- + ! output: conductances -- used to test derivatives + real(rkind),intent(out) :: leafConductance ! leaf conductance (m s-1) + real(rkind),intent(out) :: canopyConductance ! canopy conductance (m s-1) + real(rkind),intent(out) :: groundConductanceSH ! ground conductance for sensible heat (m s-1) + real(rkind),intent(out) :: groundConductanceLH ! ground conductance for latent heat -- includes soil resistance (m s-1) + real(rkind),intent(out) :: evapConductance ! conductance for evaporation (m s-1) + real(rkind),intent(out) :: transConductance ! conductance for transpiration (m s-1) + real(rkind),intent(out) :: totalConductanceSH ! total conductance for sensible heat (m s-1) + real(rkind),intent(out) :: totalConductanceLH ! total conductance for latent heat (m s-1) + ! output: canopy air space variables + real(rkind),intent(out) :: VP_CanopyAir ! vapor pressure of the canopy air space (Pa) + ! output: fluxes from the vegetation canopy + real(rkind),intent(out) :: senHeatCanopy ! sensible heat flux from the canopy to the canopy air space (W m-2) + real(rkind),intent(out) :: latHeatCanopyEvap ! latent heat flux associated with evaporation from the canopy to the canopy air space (W m-2) + real(rkind),intent(out) :: latHeatCanopyTrans ! latent heat flux associated with transpiration from the canopy to the canopy air space (W m-2) + ! output: fluxes from non-vegetated surfaces (ground surface below vegetation, bare ground, or snow covered vegetation) + real(rkind),intent(out) :: senHeatGround ! sensible heat flux from ground surface below vegetation, bare ground, or snow covered vegetation (W m-2) + real(rkind),intent(out) :: latHeatGround ! latent heat flux from ground surface below vegetation, bare ground, or snow covered vegetation (W m-2) + ! output: total heat fluxes to the atmosphere + real(rkind),intent(out) :: senHeatTotal ! total sensible heat flux to the atmosphere (W m-2) + real(rkind),intent(out) :: latHeatTotal ! total latent heat flux to the atmosphere (W m-2) + ! output: net fluxes + real(rkind),intent(out) :: turbFluxCanair ! net turbulent heat fluxes at the canopy air space (W m-2) + real(rkind),intent(out) :: turbFluxCanopy ! net turbulent heat fluxes at the canopy (W m-2) + real(rkind),intent(out) :: turbFluxGround ! net turbulent heat fluxes at the ground surface (W m-2) + ! output: energy flux derivatives + real(rkind),intent(out) :: dTurbFluxCanair_dTCanair ! derivative in net canopy air space fluxes w.r.t. canopy air temperature (W m-2 K-1) + real(rkind),intent(out) :: dTurbFluxCanair_dTCanopy ! derivative in net canopy air space fluxes w.r.t. canopy temperature (W m-2 K-1) + real(rkind),intent(out) :: dTurbFluxCanair_dTGround ! derivative in net canopy air space fluxes w.r.t. ground temperature (W m-2 K-1) + real(rkind),intent(out) :: dTurbFluxCanopy_dTCanair ! derivative in net canopy turbulent fluxes w.r.t. canopy air temperature (W m-2 K-1) + real(rkind),intent(out) :: dTurbFluxCanopy_dTCanopy ! derivative in net canopy turbulent fluxes w.r.t. canopy temperature (W m-2 K-1) + real(rkind),intent(out) :: dTurbFluxCanopy_dTGround ! derivative in net canopy turbulent fluxes w.r.t. ground temperature (W m-2 K-1) + real(rkind),intent(out) :: dTurbFluxGround_dTCanair ! derivative in net ground turbulent fluxes w.r.t. canopy air temperature (W m-2 K-1) + real(rkind),intent(out) :: dTurbFluxGround_dTCanopy ! derivative in net ground turbulent fluxes w.r.t. canopy temperature (W m-2 K-1) + real(rkind),intent(out) :: dTurbFluxGround_dTGround ! derivative in net ground turbulent fluxes w.r.t. ground temperature (W m-2 K-1) + ! output: liquid flux derivatives (canopy evap) + real(rkind),intent(out) :: dLatHeatCanopyEvap_dCanWat ! derivative in latent heat of canopy evaporation w.r.t. canopy total water content (W kg-1) + real(rkind),intent(out) :: dLatHeatCanopyEvap_dTCanair ! derivative in latent heat of canopy evaporation w.r.t. canopy air temperature (W m-2 K-1) + real(rkind),intent(out) :: dLatHeatCanopyEvap_dTCanopy ! derivative in latent heat of canopy evaporation w.r.t. canopy temperature (W m-2 K-1) + real(rkind),intent(out) :: dLatHeatCanopyEvap_dTGround ! derivative in latent heat of canopy evaporation w.r.t. ground temperature (W m-2 K-1) + ! output: liquid flux derivatives (ground evap) + real(rkind),intent(out) :: dLatHeatGroundEvap_dCanWat ! derivative in latent heat of ground evaporation w.r.t. canopy total water content (J kg-1 s-1) + real(rkind),intent(out) :: dLatHeatGroundEvap_dTCanair ! derivative in latent heat of ground evaporation w.r.t. canopy air temperature (W m-2 K-1) + real(rkind),intent(out) :: dLatHeatGroundEvap_dTCanopy ! derivative in latent heat of ground evaporation w.r.t. canopy temperature (W m-2 K-1) + real(rkind),intent(out) :: dLatHeatGroundEvap_dTGround ! derivative in latent heat of ground evaporation w.r.t. ground temperature (W m-2 K-1) + ! output: latent heat flux derivatives (canopy trans) + real(rkind) :: dLatHeatCanopyTrans_dCanWat ! derivative in the latent heat of canopy transpiration w.r.t. canopy total water (J kg-1 s-1) + real(rkind) :: dLatHeatCanopyTrans_dTCanair ! derivative in the latent heat of canopy transpiration w.r.t. canopy air temperature + real(rkind) :: dLatHeatCanopyTrans_dTCanopy ! derivative in the latent heat of canopy transpiration w.r.t. canopy temperature + real(rkind) :: dLatHeatCanopyTrans_dTGround ! derivative in the latent heat of canopy transpiration flux w.r.t. ground temperature + ! output: cross derivatives + real(rkind),intent(out) :: dTurbFluxCanair_dCanWat ! derivative in net canopy air space fluxes w.r.t. canopy total water content (J kg-1 s-1) + real(rkind),intent(out) :: dTurbFluxCanopy_dCanWat ! derivative in net canopy turbulent fluxes w.r.t. canopy total water content (J kg-1 s-1) + real(rkind),intent(out) :: dTurbFluxGround_dCanWat ! derivative in net ground turbulent fluxes w.r.t. canopy total water content (J kg-1 s-1) + ! output: error control + integer(i4b),intent(out) :: err ! error code + character(*),intent(out) :: message ! error message + ! ----------------------------------------------------------------------------------------------------------------------------------------- + ! local variables -- general + real(rkind) :: fpart1,fpart2 ! different parts of a function + real(rkind) :: dPart0,dpart1,dpart2 ! derivatives for different parts of a function + ! local variables -- "constants" + real(rkind) :: volHeatCapacityAir ! volumetric heat capacity of air (J m-3) + real(rkind) :: latentHeatConstant ! latent heat constant (kg m-3 K-1) + ! local variables -- derivatives for energy conductances + real(rkind) :: dEvapCond_dCanopyTemp ! derivative in evap conductance w.r.t. canopy temperature + real(rkind) :: dTransCond_dCanopyTemp ! derivative in trans conductance w.r.t. canopy temperature + real(rkind) :: dCanopyCond_dCanairTemp ! derivative in canopy conductance w.r.t. canopy air temperature + real(rkind) :: dCanopyCond_dCanopyTemp ! derivative in canopy conductance w.r.t. canopy temperature + real(rkind) :: dGroundCondSH_dCanairTemp ! derivative in ground conductance of sensible heat w.r.t. canopy air temperature + real(rkind) :: dGroundCondSH_dCanopyTemp ! derivative in ground conductance of sensible heat w.r.t. canopy temperature + real(rkind) :: dGroundCondSH_dGroundTemp ! derivative in ground conductance of sensible heat w.r.t. ground temperature + ! local variables -- derivatives for mass conductances + real(rkind) :: dGroundCondLH_dCanairTemp ! derivative in ground conductance w.r.t. canopy air temperature + real(rkind) :: dGroundCondLH_dCanopyTemp ! derivative in ground conductance w.r.t. canopy temperature + real(rkind) :: dGroundCondLH_dGroundTemp ! derivative in ground conductance w.r.t. ground temperature + ! local variables -- derivatives for the canopy air space variables + real(rkind) :: fPart_VP ! part of the function for vapor pressure of the canopy air space + real(rkind) :: leafConductanceTr ! leaf conductance for transpiration (m s-1) + real(rkind) :: dVPCanopyAir_dTCanair ! derivative in the vapor pressure of the canopy air space w.r.t. temperature of the canopy air space + real(rkind) :: dVPCanopyAir_dTCanopy ! derivative in the vapor pressure of the canopy air space w.r.t. temperature of the canopy + real(rkind) :: dVPCanopyAir_dTGround ! derivative in the vapor pressure of the canopy air space w.r.t. temperature of the ground + real(rkind) :: dVPCanopyAir_dWetFrac ! derivative of vapor pressure in the canopy air space w.r.t. wetted fraction of the canopy + real(rkind) :: dVPCanopyAir_dCanWat ! derivative of vapor pressure in the canopy air space w.r.t. canopy total water content + ! local variables -- sensible heat flux derivatives + real(rkind) :: dSenHeatTotal_dTCanair ! derivative in the total sensible heat flux w.r.t. canopy air temperature + real(rkind) :: dSenHeatTotal_dTCanopy ! derivative in the total sensible heat flux w.r.t. canopy air temperature + real(rkind) :: dSenHeatTotal_dTGround ! derivative in the total sensible heat flux w.r.t. ground temperature + real(rkind) :: dSenHeatCanopy_dTCanair ! derivative in the canopy sensible heat flux w.r.t. canopy air temperature + real(rkind) :: dSenHeatCanopy_dTCanopy ! derivative in the canopy sensible heat flux w.r.t. canopy temperature + real(rkind) :: dSenHeatCanopy_dTGround ! derivative in the canopy sensible heat flux w.r.t. ground temperature + real(rkind) :: dSenHeatGround_dTCanair ! derivative in the ground sensible heat flux w.r.t. canopy air temperature + real(rkind) :: dSenHeatGround_dTCanopy ! derivative in the ground sensible heat flux w.r.t. canopy temperature + real(rkind) :: dSenHeatGround_dTGround ! derivative in the ground sensible heat flux w.r.t. ground temperature + ! local variables -- wetted fraction derivatives + real(rkind) :: dLatHeatCanopyEvap_dWetFrac ! derivative in the latent heat of canopy evaporation w.r.t. canopy wet fraction (W m-2) + real(rkind) :: dLatHeatCanopyTrans_dWetFrac ! derivative in the latent heat of canopy transpiration w.r.t. canopy wet fraction (W m-2) + ! ----------------------------------------------------------------------------------------------------------------------------------------- + ! initialize error control + err=0; message='turbFluxes/' + + ! compute constants + volHeatCapacityAir = iden_air*cp_air ! volumetric heat capacity of air (J m-3) + latentHeatConstant = iden_air*w_ratio/airpres ! latent heat constant for (kg m-3 Pa-1) + + ! ***** + ! * compute conductances, and derivatives... + ! ****************************************** + + ! compute conductances for sensible heat (m s-1) + if(computeVegFlux)then + leafConductance = exposedVAI/leafResistance + leafConductanceTr = canopySunlitLAI/(leafResistance+stomResistSunlit) + canopyShadedLAI/(leafResistance+stomResistShaded) + canopyConductance = 1._rkind/canopyResistance + else + leafConductance = 0._rkind + canopyConductance = 0._rkind + end if + groundConductanceSH = 1._rkind/groundResistance + + ! compute total conductance for sensible heat + totalConductanceSH = leafConductance + groundConductanceSH + canopyConductance + + ! compute conductances for latent heat (m s-1) + if(computeVegFlux)then + evapConductance = canopyWetFraction*leafConductance + transConductance = (1._rkind - canopyWetFraction) * leafConductanceTr + !write(*,'(a,10(f14.8,1x))') 'canopySunlitLAI, canopyShadedLAI, stomResistSunlit, stomResistShaded, leafResistance, canopyWetFraction = ', & + ! canopySunlitLAI, canopyShadedLAI, stomResistSunlit, stomResistShaded, leafResistance, canopyWetFraction + else + evapConductance = 0._rkind + transConductance = 0._rkind + end if + groundConductanceLH = 1._rkind/(groundResistance + soilResistance) ! NOTE: soilResistance accounts for fractional snow, and =0 when snow cover is 100% + totalConductanceLH = evapConductance + transConductance + groundConductanceLH + canopyConductance + + ! check sensible heat conductance + if(totalConductanceSH < -tinyVal .or. groundConductanceSH < -tinyVal .or. canopyConductance < -tinyVal)then + message=trim(message)//'negative conductance for sensible heat' + err=20; return + endif + + ! check latent heat conductance + if(totalConductanceLH < tinyVal .or. groundConductanceLH < -tinyVal)then + message=trim(message)//'negative conductance for latent heat' + err=20; return + endif + + ! * compute derivatives + ! NOTE: it may be more efficient to compute these derivatives when computing resistances + if(ixDerivMethod == analytical)then + + ! compute derivatives in individual conductances for sensible heat w.r.t. canopy temperature (m s-1 K-1) + if(computeVegFlux)then + dEvapCond_dCanopyTemp = dCanopyWetFraction_dT*leafConductance ! derivative in evap conductance w.r.t. canopy temperature + dTransCond_dCanopyTemp = -dCanopyWetFraction_dT*leafConductanceTr ! derivative in trans conductance w.r.t. canopy temperature + dCanopyCond_dCanairTemp = -dCanopyResistance_dTCanair/canopyResistance**2._rkind ! derivative in canopy conductance w.r.t. canopy air emperature + dCanopyCond_dCanopyTemp = -dCanopyResistance_dTCanopy/canopyResistance**2._rkind ! derivative in canopy conductance w.r.t. canopy temperature + dGroundCondSH_dCanairTemp = -dGroundResistance_dTCanair/groundResistance**2._rkind ! derivative in ground conductance w.r.t. canopy air temperature + dGroundCondSH_dCanopyTemp = -dGroundResistance_dTCanopy/groundResistance**2._rkind ! derivative in ground conductance w.r.t. canopy temperature + dGroundCondSH_dGroundTemp = -dGroundResistance_dTGround/groundResistance**2._rkind ! derivative in ground conductance w.r.t. ground temperature + else + dEvapCond_dCanopyTemp = 0._rkind ! derivative in evap conductance w.r.t. canopy temperature + dTransCond_dCanopyTemp = 0._rkind ! derivative in trans conductance w.r.t. canopy temperature + dCanopyCond_dCanairTemp = 0._rkind ! derivative in canopy conductance w.r.t. canopy air emperature + dCanopyCond_dCanopyTemp = 0._rkind ! derivative in canopy conductance w.r.t. canopy temperature + dGroundCondSH_dCanairTemp = 0._rkind ! derivative in ground conductance w.r.t. canopy air temperature + dGroundCondSH_dCanopyTemp = 0._rkind ! derivative in ground conductance w.r.t. canopy temperature + dGroundCondSH_dGroundTemp = -dGroundResistance_dTGround/groundResistance**2._rkind ! derivative in ground conductance w.r.t. ground temperature + end if + + ! compute derivatives in individual conductances for latent heat w.r.t. canopy temperature (m s-1 K-1) + if(computeVegFlux)then + dGroundCondLH_dCanairTemp = -dGroundResistance_dTCanair/(groundResistance+soilResistance)**2._rkind ! derivative in ground conductance w.r.t. canopy air temperature + dGroundCondLH_dCanopyTemp = -dGroundResistance_dTCanopy/(groundResistance+soilResistance)**2._rkind ! derivative in ground conductance w.r.t. canopy temperature + dGroundCondLH_dGroundTemp = -dGroundResistance_dTGround/(groundResistance+soilResistance)**2._rkind ! derivative in ground conductance w.r.t. ground temperature + else + dGroundCondLH_dCanairTemp = 0._rkind ! derivative in ground conductance w.r.t. canopy air temperature + dGroundCondLH_dCanopyTemp = 0._rkind ! derivative in ground conductance w.r.t. canopy temperature + dGroundCondLH_dGroundTemp = -dGroundResistance_dTGround/(groundResistance+soilResistance)**2._rkind ! derivative in ground conductance w.r.t. ground temperature + end if + + end if ! (if computing analytical derivatives) + + ! ***** + ! * compute sensible and latent heat fluxes, and derivatives... + ! ************************************************************* + + ! * compute sensible and latent heat fluxes from the canopy to the canopy air space (W m-2) + if(computeVegFlux)then + + ! compute the vapor pressure in the canopy air space (Pa) + fPart_VP = canopyConductance*VPair + (evapConductance + transConductance)*satVP_CanopyTemp + groundConductanceLH*satVP_GroundTemp*soilRelHumidity + VP_CanopyAir = fPart_VP/totalConductanceLH + + ! compute sensible heat flux from the canopy air space to the atmosphere + ! NOTE: canairTemp is a state variable + senHeatTotal = -volHeatCapacityAir*canopyConductance*(canairTemp - airtemp) + + ! compute fluxes + senHeatCanopy = -volHeatCapacityAir*leafConductance*(canopyTemp - canairTemp) ! (positive downwards) + latHeatCanopyEvap = -latHeatSubVapCanopy*latentHeatConstant*evapConductance*(satVP_CanopyTemp - VP_CanopyAir) ! (positive downwards) + latHeatCanopyTrans = -LH_vap*latentHeatConstant*transConductance*(satVP_CanopyTemp - VP_CanopyAir) ! (positive downwards) + + + ! * no vegetation, so fluxes are zero + else + senHeatCanopy = 0._rkind + latHeatCanopyEvap = 0._rkind + latHeatCanopyTrans = 0._rkind + end if + + ! compute sensible and latent heat fluxes from the ground to the canopy air space (W m-2) + if(computeVegFlux)then + senHeatGround = -volHeatCapacityAir*groundConductanceSH*(groundTemp - canairTemp) ! (positive downwards) + latHeatGround = -latHeatSubVapGround*latentHeatConstant*groundConductanceLH*(satVP_GroundTemp*soilRelHumidity - VP_CanopyAir) ! (positive downwards) + else + senHeatGround = -volHeatCapacityAir*groundConductanceSH*(groundTemp - airtemp) ! (positive downwards) + latHeatGround = -latHeatSubVapGround*latentHeatConstant*groundConductanceLH*(satVP_GroundTemp*soilRelHumidity - VPair) ! (positive downwards) + senHeatTotal = senHeatGround + end if + + + ! compute latent heat flux from the canopy air space to the atmosphere + ! NOTE: VP_CanopyAir is a diagnostic variable + latHeatTotal = latHeatCanopyEvap + latHeatCanopyTrans + latHeatGround + + ! * compute derivatives + if(ixDerivMethod == analytical)then + + ! differentiate CANOPY fluxes + if(computeVegFlux)then + + ! compute derivatives of vapor pressure in the canopy air space w.r.t. all state variables + ! (derivative of vapor pressure in the canopy air space w.r.t. temperature of the canopy air space) + dPart1 = dCanopyCond_dCanairTemp*VPair + dGroundCondLH_dCanairTemp*satVP_GroundTemp*soilRelHumidity + dPart2 = -(dCanopyCond_dCanairTemp + dGroundCondLH_dCanairTemp)/(totalConductanceLH**2._rkind) + dVPCanopyAir_dTCanair = dPart1/totalConductanceLH + fPart_VP*dPart2 + ! (derivative of vapor pressure in the canopy air space w.r.t. temperature of the canopy) + dPart0 = (evapConductance + transConductance)*dSVPCanopy_dCanopyTemp + (dEvapCond_dCanopyTemp + dTransCond_dCanopyTemp)*satVP_CanopyTemp + dPart1 = dCanopyCond_dCanopyTemp*VPair + dPart0 + dGroundCondLH_dCanopyTemp*satVP_GroundTemp*soilRelHumidity + dPart2 = -(dCanopyCond_dCanopyTemp + dEvapCond_dCanopyTemp + dTransCond_dCanopyTemp + dGroundCondLH_dCanopyTemp)/(totalConductanceLH**2._rkind) + dVPCanopyAir_dTCanopy = dPart1/totalConductanceLH + fPart_VP*dPart2 + ! (derivative of vapor pressure in the canopy air space w.r.t. temperature of the ground) + dPart1 = dGroundCondLH_dGroundTemp*satVP_GroundTemp*soilRelHumidity + groundConductanceLH*dSVPGround_dGroundTemp*soilRelHumidity + dPart2 = -dGroundCondLH_dGroundTemp/(totalConductanceLH**2._rkind) + dVPCanopyAir_dTGround = dPart1/totalConductanceLH + fPart_VP*dPart2 + ! (derivative of vapor pressure in the canopy air space w.r.t. wetted fraction of the canopy) + dPart1 = (leafConductance - leafConductanceTr)*satVP_CanopyTemp + dPart2 = -(leafConductance - leafConductanceTr)/(totalConductanceLH**2._rkind) + dVPCanopyAir_dWetFrac = dPart1/totalConductanceLH + fPart_VP*dPart2 + dVPCanopyAir_dCanWat = dVPCanopyAir_dWetFrac*dCanopyWetFraction_dWat + + ! sensible heat from the canopy to the atmosphere + dSenHeatTotal_dTCanair = -volHeatCapacityAir*canopyConductance - volHeatCapacityAir*dCanopyCond_dCanairTemp*(canairTemp - airtemp) + dSenHeatTotal_dTCanopy = -volHeatCapacityAir*dCanopyCond_dCanopyTemp*(canairTemp - airtemp) + dSenHeatTotal_dTGround = 0._rkind + + ! sensible heat from the canopy to the canopy air space + dSenHeatCanopy_dTCanair = volHeatCapacityAir*leafConductance + dSenHeatCanopy_dTCanopy = -volHeatCapacityAir*leafConductance + dSenHeatCanopy_dTGround = 0._rkind + + ! sensible heat from the ground to the canopy air space + dSenHeatGround_dTCanair = -volHeatCapacityAir*dGroundCondSH_dCanairTemp*(groundTemp - canairTemp) + volHeatCapacityAir*groundConductanceSH + dSenHeatGround_dTCanopy = -volHeatCapacityAir*dGroundCondSH_dCanopyTemp*(groundTemp - canairTemp) + dSenHeatGround_dTGround = -volHeatCapacityAir*dGroundCondSH_dGroundTemp*(groundTemp - canairTemp) - volHeatCapacityAir*groundConductanceSH + + ! latent heat associated with canopy evaporation + ! (initial calculations) + fPart1 = -latHeatSubVapCanopy*latentHeatConstant*evapConductance + dPart1 = -latHeatSubVapCanopy*latentHeatConstant*dEvapCond_dCanopyTemp + fPart2 = satVP_CanopyTemp - VP_CanopyAir + dPart2 = dSVPCanopy_dCanopyTemp - dVPCanopyAir_dTCanopy + ! (derivatives) + dLatHeatCanopyEvap_dTCanair = fPart1*(-dVPCanopyAir_dTCanair) + dLatHeatCanopyEvap_dTCanopy = fPart1*dpart2 + fPart2*dPart1 + dLatHeatCanopyEvap_dTGround = fPart1*(-dVPCanopyAir_dTGround) + + ! latent heat associated with canopy transpiration + ! (initial calculations) + fPart1 = -LH_vap*latentHeatConstant*transConductance + dPart1 = -LH_vap*latentHeatConstant*dTransCond_dCanopyTemp + ! (derivatives) + dLatHeatCanopyTrans_dTCanair = fPart1*(-dVPCanopyAir_dTCanair) + dLatHeatCanopyTrans_dTCanopy = fPart1*dPart2 + fPart2*dPart1 + dLatHeatCanopyTrans_dTGround = fPart1*(-dVPCanopyAir_dTGround) + + ! latent heat flux from the ground + fPart1 = -latHeatSubVapGround*latentHeatConstant*groundConductanceLH ! function of the first part + fPart2 = (satVP_GroundTemp*soilRelHumidity - VP_CanopyAir) ! function of the second part + dLatHeatGroundEvap_dTCanair = -latHeatSubVapGround*latentHeatConstant*dGroundCondLH_dCanairTemp*fPart2 - dVPCanopyAir_dTCanair*fPart1 + dLatHeatGroundEvap_dTCanopy = -latHeatSubVapGround*latentHeatConstant*dGroundCondLH_dCanopyTemp*fPart2 - dVPCanopyAir_dTCanopy*fPart1 + dLatHeatGroundEvap_dTGround = -latHeatSubVapGround*latentHeatConstant*dGroundCondLH_dGroundTemp*fPart2 + (dSVPGround_dGroundTemp*soilRelHumidity - dVPCanopyAir_dTGround)*fPart1 + + ! latent heat associated with canopy evaporation w.r.t. wetted fraction of the canopy + dPart1 = -latHeatSubVapCanopy*latentHeatConstant*leafConductance + fPart1 = dPart1*canopyWetFraction + dLatHeatCanopyEvap_dWetFrac = dPart1*(satVP_CanopyTemp - VP_CanopyAir) + fPart1*(-dVPCanopyAir_dWetFrac) + + ! latent heat associated with canopy transpiration w.r.t. wetted fraction of the canopy + dPart1 = LH_vap*latentHeatConstant*leafConductanceTr ! NOTE: positive, since (1 - wetFrac) + fPart1 = -dPart1*(1._rkind - canopyWetFraction) + dLatHeatCanopyTrans_dWetFrac = dPart1*(satVP_CanopyTemp - VP_CanopyAir) + fPart1*(-dVPCanopyAir_dWetFrac) + + ! latent heat associated with canopy transpiration w.r.t. canopy total water + dLatHeatCanopyTrans_dCanWat = dLatHeatCanopyTrans_dWetFrac*dCanopyWetFraction_dWat ! (J s-1 kg-1) + + + else ! canopy is undefined + + ! set derivatives for canopy fluxes to zero (no canopy, so fluxes are undefined) + dSenHeatTotal_dTCanair = 0._rkind + dSenHeatTotal_dTCanopy = 0._rkind + dSenHeatTotal_dTGround = 0._rkind + dSenHeatCanopy_dTCanair = 0._rkind + dSenHeatCanopy_dTCanopy = 0._rkind + dSenHeatCanopy_dTGround = 0._rkind + dLatHeatCanopyEvap_dTCanair = 0._rkind + dLatHeatCanopyEvap_dTCanopy = 0._rkind + dLatHeatCanopyEvap_dTGround = 0._rkind + dLatHeatCanopyTrans_dTCanair = 0._rkind + dLatHeatCanopyTrans_dTCanopy = 0._rkind + dLatHeatCanopyTrans_dTGround = 0._rkind + + ! set derivatives for wetted area and canopy transpiration to zero (no canopy, so fluxes are undefined) + dLatHeatCanopyEvap_dWetFrac = 0._rkind dLatHeatCanopyEvap_dCanWat = 0._rkind - dLatHeatGroundEvap_dCanWat = 0._rkind - ! (cross deriavtives) - dTurbFluxCanair_dCanWat = 0._rkind - dTurbFluxCanopy_dCanWat = 0._rkind - dTurbFluxGround_dCanWat = 0._rkind - end if - - end subroutine turbFluxes - - - ! ******************************************************************************************************* - ! private subroutine aStability: compute stability corrections for turbulent heat fluxes (-) - ! ******************************************************************************************************* - subroutine aStability(& - ! input: control - computeDerivative, & ! input: logical flag to compute analytical derivatives - ixStability, & ! input: choice of stability function - ! input: forcing data, diagnostic and state variables - mHeight, & ! input: measurement height (m) - airTemp, & ! input: air temperature (K) - sfcTemp, & ! input: surface temperature (K) - windspd, & ! input: wind speed (m s-1) - ! input: stability parameters - critRichNumber, & ! input: critical value for the bulk Richardson number where turbulence ceases (-) - Louis79_bparam, & ! input: parameter in Louis (1979) stability function - Mahrt87_eScale, & ! input: exponential scaling factor in the Mahrt (1987) stability function - ! output - RiBulk, & ! output: bulk Richardson number (-) - stabilityCorrection, & ! output: stability correction for turbulent heat fluxes (-) - dStabilityCorrection_dRich, & ! output: derivative in stability correction w.r.t. Richardson number (-) - dStabilityCorrection_dAirTemp, & ! output: derivative in stability correction w.r.t. temperature (K-1) - dStabilityCorrection_dSfcTemp, & ! output: derivative in stability correction w.r.t. temperature (K-1) - err, message ) ! output: error control - implicit none - ! input: control - logical(lgt),intent(in) :: computeDerivative ! flag to compute the derivative - integer(i4b),intent(in) :: ixStability ! choice of stability function - ! input: forcing data, diagnostic and state variables - real(rkind),intent(in) :: mHeight ! measurement height (m) - real(rkind),intent(in) :: airtemp ! air temperature (K) - real(rkind),intent(in) :: sfcTemp ! surface temperature (K) - real(rkind),intent(in) :: windspd ! wind speed (m s-1) - ! input: stability parameters - real(rkind),intent(in) :: critRichNumber ! critical value for the bulk Richardson number where turbulence ceases (-) - real(rkind),intent(in) :: Louis79_bparam ! parameter in Louis (1979) stability function - real(rkind),intent(in) :: Mahrt87_eScale ! exponential scaling factor in the Mahrt (1987) stability function - ! output - real(rkind),intent(out) :: RiBulk ! bulk Richardson number (-) - real(rkind),intent(out) :: stabilityCorrection ! stability correction for turbulent heat fluxes (-) - real(rkind),intent(out) :: dStabilityCorrection_dRich ! derivative in stability correction w.r.t. Richardson number (-) - real(rkind),intent(out) :: dStabilityCorrection_dAirTemp ! derivative in stability correction w.r.t. air temperature (K-1) - real(rkind),intent(out) :: dStabilityCorrection_dSfcTemp ! derivative in stability correction w.r.t. surface temperature (K-1) - integer(i4b),intent(out) :: err ! error code - character(*),intent(out) :: message ! error message - ! local - real(rkind), parameter :: verySmall=1.e-10_rkind ! a very small number (avoid stability of zero) - real(rkind) :: dRiBulk_dAirTemp ! derivative in the bulk Richardson number w.r.t. air temperature (K-1) - real(rkind) :: dRiBulk_dSfcTemp ! derivative in the bulk Richardson number w.r.t. surface temperature (K-1) - real(rkind) :: bPrime ! scaled "b" parameter for stability calculations in Louis (1979) - ! ----------------------------------------------------------------------------------------------------------------------------------------- - ! initialize error control - err=0; message='aStability/' - - ! compute the bulk Richardson number (-) - call bulkRichardson(& - ! input - airTemp, & ! input: air temperature (K) - sfcTemp, & ! input: surface temperature (K) - windspd, & ! input: wind speed (m s-1) - mHeight, & ! input: measurement height (m) - computeDerivative, & ! input: flag to compute the derivative - ! output - RiBulk, & ! output: bulk Richardson number (-) - dRiBulk_dAirTemp, & ! output: derivative in the bulk Richardson number w.r.t. air temperature (K-1) - dRiBulk_dSfcTemp, & ! output: derivative in the bulk Richardson number w.r.t. surface temperature (K-1) - err,message) ! output: error control - - ! set derivative to one if not computing it - if(.not.computeDerivative)then - dStabilityCorrection_dRich = 1._rkind - dStabilityCorrection_dAirTemp = 1._rkind - dStabilityCorrection_dSfcTemp = 1._rkind - end if - - ! ***** process unstable cases - if(RiBulk<0._rkind)then + dLatHeatCanopyTrans_dCanWat = 0._rkind + dVPCanopyAir_dCanWat = 0._rkind + + ! set derivatives for ground fluxes w.r.t canopy temperature to zero (no canopy, so fluxes are undefined) + dSenHeatGround_dTCanair = 0._rkind + dSenHeatGround_dTCanopy = 0._rkind + dLatHeatGroundEvap_dTCanair = 0._rkind + dLatHeatGroundEvap_dTCanopy = 0._rkind + + ! compute derivatives for the ground fluxes w.r.t. ground temperature + dSenHeatGround_dTGround = (-volHeatCapacityAir*dGroundCondSH_dGroundTemp)*(groundTemp - airtemp) + & ! d(ground sensible heat flux)/d(ground temp) + (-volHeatCapacityAir*groundConductanceSH) + dLatHeatGroundEvap_dTGround = (-latHeatSubVapGround*latentHeatConstant*dGroundCondLH_dGroundTemp)*(satVP_GroundTemp*soilRelHumidity - VPair) + & ! d(ground latent heat flux)/d(ground temp) + (-latHeatSubVapGround*latentHeatConstant*groundConductanceLH)*dSVPGround_dGroundTemp*soilRelHumidity + + end if ! (if canopy is defined) + + end if ! (if computing analytical derivatives) + + + ! ***** + ! * compute net turbulent fluxes, and derivatives... + ! ************************************************** + + ! compute net fluxes + turbFluxCanair = senHeatTotal - senHeatCanopy - senHeatGround ! net turbulent flux at the canopy air space (W m-2) + turbFluxCanopy = senHeatCanopy + latHeatCanopyEvap + latHeatCanopyTrans ! net turbulent flux at the canopy (W m-2) + turbFluxGround = senHeatGround + latHeatGround ! net turbulent flux at the ground surface (W m-2) + + ! * compute derivatives + if(ixDerivMethod == analytical)then + ! (energy derivatives) + dTurbFluxCanair_dTCanair = dSenHeatTotal_dTCanair - dSenHeatCanopy_dTCanair - dSenHeatGround_dTCanair ! derivative in net canopy air space fluxes w.r.t. canopy air temperature (W m-2 K-1) + dTurbFluxCanair_dTCanopy = dSenHeatTotal_dTCanopy - dSenHeatCanopy_dTCanopy - dSenHeatGround_dTCanopy ! derivative in net canopy air space fluxes w.r.t. canopy temperature (W m-2 K-1) + dTurbFluxCanair_dTGround = dSenHeatTotal_dTGround - dSenHeatCanopy_dTGround - dSenHeatGround_dTGround ! derivative in net canopy air space fluxes w.r.t. ground temperature (W m-2 K-1) + dTurbFluxCanopy_dTCanair = dSenHeatCanopy_dTCanair + dLatHeatCanopyEvap_dTCanair + dLatHeatCanopyTrans_dTCanair ! derivative in net canopy turbulent fluxes w.r.t. canopy air temperature (W m-2 K-1) + dTurbFluxCanopy_dTCanopy = dSenHeatCanopy_dTCanopy + dLatHeatCanopyEvap_dTCanopy + dLatHeatCanopyTrans_dTCanopy ! derivative in net canopy turbulent fluxes w.r.t. canopy temperature (W m-2 K-1) + dTurbFluxCanopy_dTGround = dSenHeatCanopy_dTGround + dLatHeatCanopyEvap_dTGround + dLatHeatCanopyTrans_dTGround ! derivative in net canopy turbulent fluxes w.r.t. ground temperature (W m-2 K-1) + dTurbFluxGround_dTCanair = dSenHeatGround_dTCanair + dLatHeatGroundEvap_dTCanair ! derivative in net ground turbulent fluxes w.r.t. canopy air temperature (W m-2 K-1) + dTurbFluxGround_dTCanopy = dSenHeatGround_dTCanopy + dLatHeatGroundEvap_dTCanopy ! derivative in net ground turbulent fluxes w.r.t. canopy temperature (W m-2 K-1) + dTurbFluxGround_dTGround = dSenHeatGround_dTGround + dLatHeatGroundEvap_dTGround ! derivative in net ground turbulent fluxes w.r.t. ground temperature (W m-2 K-1) + ! (liquid water derivatives) + dLatHeatCanopyEvap_dCanWat = dLatHeatCanopyEvap_dWetFrac*dCanopyWetFraction_dWat ! derivative in latent heat of canopy evaporation w.r.t. canopy total water (W kg-1) + dLatHeatGroundEvap_dCanWat = latHeatSubVapGround*latentHeatConstant*groundConductanceLH*dVPCanopyAir_dCanWat ! derivative in latent heat of ground evaporation w.r.t. canopy total water (J kg-1 s-1) + ! (cross deriavtives) + dTurbFluxCanair_dCanWat = 0._rkind ! derivative in net canopy air space fluxes w.r.t. canopy total water content (J kg-1 s-1) + dTurbFluxCanopy_dCanWat = dLatHeatCanopyEvap_dCanWat + dLatHeatCanopyTrans_dCanWat ! derivative in net canopy turbulent fluxes w.r.t. canopy total water content (J kg-1 s-1) + dTurbFluxGround_dCanWat = dLatHeatGroundEvap_dCanWat ! derivative in net ground turbulent fluxes w.r.t. canopy total water content (J kg-1 s-1) + else ! (just make sure we return something) + ! (energy derivatives) + dTurbFluxCanair_dTCanair = 0._rkind + dTurbFluxCanair_dTCanopy = 0._rkind + dTurbFluxCanair_dTGround = 0._rkind + dTurbFluxCanopy_dTCanair = 0._rkind + dTurbFluxCanopy_dTCanopy = 0._rkind + dTurbFluxCanopy_dTGround = 0._rkind + dTurbFluxGround_dTCanair = 0._rkind + dTurbFluxGround_dTCanopy = 0._rkind + dTurbFluxGround_dTGround = 0._rkind + ! (liquid water derivatives) + dLatHeatCanopyEvap_dCanWat = 0._rkind + dLatHeatGroundEvap_dCanWat = 0._rkind + ! (cross deriavtives) + dTurbFluxCanair_dCanWat = 0._rkind + dTurbFluxCanopy_dCanWat = 0._rkind + dTurbFluxGround_dCanWat = 0._rkind + end if + +end subroutine turbFluxes + + +! ******************************************************************************************************* +! private subroutine aStability: compute stability corrections for turbulent heat fluxes (-) +! ******************************************************************************************************* +subroutine aStability(& + ! input: control + computeDerivative, & ! input: logical flag to compute analytical derivatives + ixStability, & ! input: choice of stability function + ! input: forcing data, diagnostic and state variables + mHeight, & ! input: measurement height (m) + airTemp, & ! input: air temperature (K) + sfcTemp, & ! input: surface temperature (K) + windspd, & ! input: wind speed (m s-1) + ! input: stability parameters + critRichNumber, & ! input: critical value for the bulk Richardson number where turbulence ceases (-) + Louis79_bparam, & ! input: parameter in Louis (1979) stability function + Mahrt87_eScale, & ! input: exponential scaling factor in the Mahrt (1987) stability function + ! output + RiBulk, & ! output: bulk Richardson number (-) + stabilityCorrection, & ! output: stability correction for turbulent heat fluxes (-) + dStabilityCorrection_dRich, & ! output: derivative in stability correction w.r.t. Richardson number (-) + dStabilityCorrection_dAirTemp, & ! output: derivative in stability correction w.r.t. temperature (K-1) + dStabilityCorrection_dSfcTemp, & ! output: derivative in stability correction w.r.t. temperature (K-1) + err, message ) ! output: error control + implicit none + ! input: control + logical(lgt),intent(in) :: computeDerivative ! flag to compute the derivative + integer(i4b),intent(in) :: ixStability ! choice of stability function + ! input: forcing data, diagnostic and state variables + real(rkind),intent(in) :: mHeight ! measurement height (m) + real(rkind),intent(in) :: airtemp ! air temperature (K) + real(rkind),intent(in) :: sfcTemp ! surface temperature (K) + real(rkind),intent(in) :: windspd ! wind speed (m s-1) + ! input: stability parameters + real(rkind),intent(in) :: critRichNumber ! critical value for the bulk Richardson number where turbulence ceases (-) + real(rkind),intent(in) :: Louis79_bparam ! parameter in Louis (1979) stability function + real(rkind),intent(in) :: Mahrt87_eScale ! exponential scaling factor in the Mahrt (1987) stability function + ! output + real(rkind),intent(out) :: RiBulk ! bulk Richardson number (-) + real(rkind),intent(out) :: stabilityCorrection ! stability correction for turbulent heat fluxes (-) + real(rkind),intent(out) :: dStabilityCorrection_dRich ! derivative in stability correction w.r.t. Richardson number (-) + real(rkind),intent(out) :: dStabilityCorrection_dAirTemp ! derivative in stability correction w.r.t. air temperature (K-1) + real(rkind),intent(out) :: dStabilityCorrection_dSfcTemp ! derivative in stability correction w.r.t. surface temperature (K-1) + integer(i4b),intent(out) :: err ! error code + character(*),intent(out) :: message ! error message + ! local + real(rkind), parameter :: verySmall=1.e-10_rkind ! a very small number (avoid stability of zero) + real(rkind) :: dRiBulk_dAirTemp ! derivative in the bulk Richardson number w.r.t. air temperature (K-1) + real(rkind) :: dRiBulk_dSfcTemp ! derivative in the bulk Richardson number w.r.t. surface temperature (K-1) + real(rkind) :: bPrime ! scaled "b" parameter for stability calculations in Louis (1979) + ! ----------------------------------------------------------------------------------------------------------------------------------------- + ! initialize error control + err=0; message='aStability/' + + ! compute the bulk Richardson number (-) + call bulkRichardson(& + ! input + airTemp, & ! input: air temperature (K) + sfcTemp, & ! input: surface temperature (K) + windspd, & ! input: wind speed (m s-1) + mHeight, & ! input: measurement height (m) + computeDerivative, & ! input: flag to compute the derivative + ! output + RiBulk, & ! output: bulk Richardson number (-) + dRiBulk_dAirTemp, & ! output: derivative in the bulk Richardson number w.r.t. air temperature (K-1) + dRiBulk_dSfcTemp, & ! output: derivative in the bulk Richardson number w.r.t. surface temperature (K-1) + err,message) ! output: error control + + ! set derivative to one if not computing it + if(.not.computeDerivative)then + dStabilityCorrection_dRich = 1._rkind + dStabilityCorrection_dAirTemp = 1._rkind + dStabilityCorrection_dSfcTemp = 1._rkind + end if + + ! ***** process unstable cases + if(RiBulk<0._rkind)then + ! compute surface-atmosphere exchange coefficient (-) + stabilityCorrection = (1._rkind - 16._rkind*RiBulk)**0.5_rkind + ! compute derivative in surface-atmosphere exchange coefficient w.r.t. temperature (K-1) + if(computeDerivative)then + dStabilityCorrection_dRich = (-16._rkind) * 0.5_rkind*(1._rkind - 16._rkind*RiBulk)**(-0.5_rkind) + dStabilityCorrection_dAirTemp = dRiBulk_dAirTemp * dStabilityCorrection_dRich + dStabilityCorrection_dSfcTemp = dRiBulk_dSfcTemp * dStabilityCorrection_dRich + end if + return + end if + + ! ***** process stable cases + select case(ixStability) + + ! ("standard" stability correction, a la Anderson 1976) + case(standard) ! compute surface-atmosphere exchange coefficient (-) - stabilityCorrection = (1._rkind - 16._rkind*RiBulk)**0.5_rkind + if(RiBulk < critRichNumber) stabilityCorrection = (1._rkind - 5._rkind*RiBulk)**2._rkind + if(RiBulk >= critRichNumber) stabilityCorrection = verySmall ! compute derivative in surface-atmosphere exchange coefficient w.r.t. temperature (K-1) if(computeDerivative)then - dStabilityCorrection_dRich = (-16._rkind) * 0.5_rkind*(1._rkind - 16._rkind*RiBulk)**(-0.5_rkind) - dStabilityCorrection_dAirTemp = dRiBulk_dAirTemp * dStabilityCorrection_dRich - dStabilityCorrection_dSfcTemp = dRiBulk_dSfcTemp * dStabilityCorrection_dRich - end if - return - end if - - ! ***** process stable cases - select case(ixStability) - - ! ("standard" stability correction, a la Anderson 1976) - case(standard) - ! compute surface-atmosphere exchange coefficient (-) - if(RiBulk < critRichNumber) stabilityCorrection = (1._rkind - 5._rkind*RiBulk)**2._rkind - if(RiBulk >= critRichNumber) stabilityCorrection = verySmall - ! compute derivative in surface-atmosphere exchange coefficient w.r.t. temperature (K-1) - if(computeDerivative)then if(RiBulk < critRichNumber) dStabilityCorrection_dRich = (-5._rkind) * 2._rkind*(1._rkind - 5._rkind*RiBulk) if(RiBulk >= critRichNumber) dStabilityCorrection_dRich = verySmall - end if - + end if + ! (Louis 1979) case(louisInversePower) - ! scale the "b" parameter for stable conditions - bprime = Louis79_bparam/2._rkind - ! compute surface-atmosphere exchange coefficient (-) - stabilityCorrection = 1._rkind / ( (1._rkind + bprime*RiBulk)**2._rkind ) - if(stabilityCorrection < epsilon(stabilityCorrection)) stabilityCorrection = epsilon(stabilityCorrection) - ! compute derivative in surface-atmosphere exchange coefficient w.r.t. temperature (K-1) - if(computeDerivative)then + ! scale the "b" parameter for stable conditions + bprime = Louis79_bparam/2._rkind + ! compute surface-atmosphere exchange coefficient (-) + stabilityCorrection = 1._rkind / ( (1._rkind + bprime*RiBulk)**2._rkind ) + if(stabilityCorrection < epsilon(stabilityCorrection)) stabilityCorrection = epsilon(stabilityCorrection) + ! compute derivative in surface-atmosphere exchange coefficient w.r.t. temperature (K-1) + if(computeDerivative)then dStabilityCorrection_dRich = bprime * (-2._rkind)*(1._rkind + bprime*RiBulk)**(-3._rkind) - end if - - ! (Mahrt 1987) - case(mahrtExponential) - ! compute surface-atmosphere exchange coefficient (-) - stabilityCorrection = exp(-Mahrt87_eScale * RiBulk) - if(stabilityCorrection < epsilon(stabilityCorrection)) stabilityCorrection = epsilon(stabilityCorrection) - ! compute derivative in surface-atmosphere exchange coefficient w.r.t. temperature (K-1) - if(computeDerivative)then + end if + + ! (Mahrt 1987) + case(mahrtExponential) + ! compute surface-atmosphere exchange coefficient (-) + stabilityCorrection = exp(-Mahrt87_eScale * RiBulk) + if(stabilityCorrection < epsilon(stabilityCorrection)) stabilityCorrection = epsilon(stabilityCorrection) + ! compute derivative in surface-atmosphere exchange coefficient w.r.t. temperature (K-1) + if(computeDerivative)then dStabilityCorrection_dRich = (-Mahrt87_eScale) * exp(-Mahrt87_eScale * RiBulk) - end if - - ! (return error if the stability correction method is not found) - case default - err=10; message=trim(message)//"optionNotFound[stability correction]"; return - - end select - - ! get the stability correction with respect to air temperature and surface temperature - ! NOTE: air temperature is used for canopy air temperature, which is a model state variable - if(computeDerivative)then - dStabilityCorrection_dAirTemp = dRiBulk_dAirTemp * dStabilityCorrection_dRich - dStabilityCorrection_dSfcTemp = dRiBulk_dSfcTemp * dStabilityCorrection_dRich - end if - - end subroutine aStability - - - ! ******************************************************************************************************* - ! private subroutine bulkRichardson: compute bulk Richardson number - ! ******************************************************************************************************* - subroutine bulkRichardson(& - ! input - airTemp, & ! input: air temperature (K) - sfcTemp, & ! input: surface temperature (K) - windspd, & ! input: wind speed (m s-1) - mHeight, & ! input: measurement height (m) - computeDerivative, & ! input: flag to compute the derivative - ! output - RiBulk, & ! output: bulk Richardson number (-) - dRiBulk_dAirTemp, & ! output: derivative in the bulk Richardson number w.r.t. air temperature (K-1) - dRiBulk_dSfcTemp, & ! output: derivative in the bulk Richardson number w.r.t. surface temperature (K-1) - err,message) ! output: error control - implicit none - ! input - real(rkind),intent(in) :: airtemp ! air temperature (K) - real(rkind),intent(in) :: sfcTemp ! surface temperature (K) - real(rkind),intent(in) :: windspd ! wind speed (m s-1) - real(rkind),intent(in) :: mHeight ! measurement height (m) - logical(lgt),intent(in) :: computeDerivative ! flag to compute the derivative - ! output - real(rkind),intent(inout) :: RiBulk ! bulk Richardson number (-) - real(rkind),intent(out) :: dRiBulk_dAirTemp ! derivative in the bulk Richardson number w.r.t. air temperature (K-1) - real(rkind),intent(out) :: dRiBulk_dSfcTemp ! derivative in the bulk Richardson number w.r.t. surface temperature (K-1) - integer(i4b),intent(out) :: err ! error code - character(*),intent(out) :: message ! error message - ! local variables - real(rkind) :: T_grad ! gradient in temperature between the atmosphere and surface (K) - real(rkind) :: T_mean ! mean of the atmosphere and surface temperature (K) - real(rkind) :: RiMult ! dimensionless scaling factor (-) - ! initialize error control - err=0; message='bulkRichardson/' - ! compute local variables - T_grad = airtemp - sfcTemp - T_mean = 0.5_rkind*(airtemp + sfcTemp) - RiMult = (gravity*mHeight)/(windspd*windspd) - ! compute the Richardson number - RiBulk = (T_grad/T_mean) * RiMult - ! compute the derivative in the Richardson number - if(computeDerivative)then - dRiBulk_dAirTemp = RiMult/T_mean - RiMult*T_grad/(0.5_rkind*((airtemp + sfcTemp)**2._rkind)) - dRiBulk_dSfcTemp = -RiMult/T_mean - RiMult*T_grad/(0.5_rkind*((airtemp + sfcTemp)**2._rkind)) - else - dRiBulk_dAirTemp = 1._rkind - dRiBulk_dSfcTemp = 1._rkind - end if - end subroutine bulkRichardson - - - end module vegNrgFlux_module - \ No newline at end of file + end if + + ! (return error if the stability correction method is not found) + case default + err=10; message=trim(message)//"optionNotFound[stability correction]"; return + + end select + + ! get the stability correction with respect to air temperature and surface temperature + ! NOTE: air temperature is used for canopy air temperature, which is a model state variable + if(computeDerivative)then + dStabilityCorrection_dAirTemp = dRiBulk_dAirTemp * dStabilityCorrection_dRich + dStabilityCorrection_dSfcTemp = dRiBulk_dSfcTemp * dStabilityCorrection_dRich + end if + +end subroutine aStability + + +! ******************************************************************************************************* +! private subroutine bulkRichardson: compute bulk Richardson number +! ******************************************************************************************************* +subroutine bulkRichardson(& + ! input + airTemp, & ! input: air temperature (K) + sfcTemp, & ! input: surface temperature (K) + windspd, & ! input: wind speed (m s-1) + mHeight, & ! input: measurement height (m) + computeDerivative, & ! input: flag to compute the derivative + ! output + RiBulk, & ! output: bulk Richardson number (-) + dRiBulk_dAirTemp, & ! output: derivative in the bulk Richardson number w.r.t. air temperature (K-1) + dRiBulk_dSfcTemp, & ! output: derivative in the bulk Richardson number w.r.t. surface temperature (K-1) + err,message) ! output: error control +implicit none +! input +real(rkind),intent(in) :: airtemp ! air temperature (K) +real(rkind),intent(in) :: sfcTemp ! surface temperature (K) +real(rkind),intent(in) :: windspd ! wind speed (m s-1) +real(rkind),intent(in) :: mHeight ! measurement height (m) +logical(lgt),intent(in) :: computeDerivative ! flag to compute the derivative +! output +real(rkind),intent(inout) :: RiBulk ! bulk Richardson number (-) +real(rkind),intent(out) :: dRiBulk_dAirTemp ! derivative in the bulk Richardson number w.r.t. air temperature (K-1) +real(rkind),intent(out) :: dRiBulk_dSfcTemp ! derivative in the bulk Richardson number w.r.t. surface temperature (K-1) +integer(i4b),intent(out) :: err ! error code +character(*),intent(out) :: message ! error message +! local variables +real(rkind) :: T_grad ! gradient in temperature between the atmosphere and surface (K) +real(rkind) :: T_mean ! mean of the atmosphere and surface temperature (K) +real(rkind) :: RiMult ! dimensionless scaling factor (-) + ! initialize error control + err=0; message='bulkRichardson/' + ! compute local variables + T_grad = airtemp - sfcTemp + T_mean = 0.5_rkind*(airtemp + sfcTemp) + RiMult = (gravity*mHeight)/(windspd*windspd) + ! compute the Richardson number + RiBulk = (T_grad/T_mean) * RiMult + ! compute the derivative in the Richardson number + if(computeDerivative)then + dRiBulk_dAirTemp = RiMult/T_mean - RiMult*T_grad/(0.5_rkind*((airtemp + sfcTemp)**2._rkind)) + dRiBulk_dSfcTemp = -RiMult/T_mean - RiMult*T_grad/(0.5_rkind*((airtemp + sfcTemp)**2._rkind)) + else + dRiBulk_dAirTemp = 1._rkind + dRiBulk_dSfcTemp = 1._rkind + end if +end subroutine bulkRichardson + + +end module vegNrgFlux_module -- GitLab