@@ -17,6 +17,8 @@ module CanopyFluxesMod
1717 use elm_varctl , only : use_hydrstress
1818 use elm_varpar , only : nlevgrnd, nlevsno
1919 use elm_varcon , only : namep
20+ use elm_varcon , only : mm_epsilon
21+ use elm_varcon , only : pa_to_kpa
2022 use pftvarcon , only : crop, nfixer
2123 use decompMod , only : bounds_type
2224 use PhotosynthesisMod , only : Photosynthesis, PhotosynthesisTotal, Fractionation, PhotoSynthesisHydraulicStress
@@ -168,21 +170,16 @@ subroutine CanopyFluxes(bounds, num_nolakeurbanp, filter_nolakeurbanp, &
168170 real (r8 ), parameter :: ria = 0.5_r8 ! free parameter for stable formulation (currently = 0.5, "gamma" in Sakaguchi&Zeng,2008)
169171
170172 real (r8 ) :: zldis(bounds% begp:bounds% endp) ! reference height "minus" zero displacement height [m]
171- real (r8 ) :: zeta ! dimensionless height used in Monin-Obukhov theory
172173 real (r8 ) :: wc ! convective velocity [m/s]
173174 real (r8 ) :: ugust_total(bounds% begp:bounds% endp) ! gustiness including convective velocity [m/s]
174175 real (r8 ) :: dth(bounds% begp:bounds% endp) ! diff of virtual temp. between ref. height and surface
175176 real (r8 ) :: dthv(bounds% begp:bounds% endp) ! diff of vir. poten. temp. between ref. height and surface
176177 real (r8 ) :: dqh(bounds% begp:bounds% endp) ! diff of humidity between ref. height and surface
177- real (r8 ) :: obu(bounds% begp:bounds% endp) ! Monin-Obukhov length (m)
178- real (r8 ) :: um(bounds% begp:bounds% endp) ! wind speed including the stablity effect [m/s]
179178 real (r8 ) :: ur(bounds% begp:bounds% endp) ! wind speed at reference height [m/s]
180- real (r8 ) :: uaf(bounds% begp:bounds% endp) ! velocity of air within foliage [m/s]
181179 real (r8 ) :: temp1(bounds% begp:bounds% endp) ! relation for potential temperature profile
182180 real (r8 ) :: temp12m(bounds% begp:bounds% endp) ! relation for potential temperature profile applied at 2-m
183181 real (r8 ) :: temp2(bounds% begp:bounds% endp) ! relation for specific humidity profile
184182 real (r8 ) :: temp22m(bounds% begp:bounds% endp) ! relation for specific humidity profile applied at 2-m
185- real (r8 ) :: ustar(bounds% begp:bounds% endp) ! friction velocity [m/s]
186183 real (r8 ) :: tstar ! temperature scaling parameter
187184 real (r8 ) :: qstar ! moisture scaling parameter
188185 real (r8 ) :: thvstar ! virtual potential temperature scaling parameter
@@ -235,7 +232,7 @@ subroutine CanopyFluxes(bounds, num_nolakeurbanp, filter_nolakeurbanp, &
235232 real (r8 ) :: efpot ! potential latent energy flux [kg/m2/s]
236233 real (r8 ) :: efe(bounds% begp:bounds% endp) ! water flux from leaf [mm/s]
237234 real (r8 ) :: efsh ! sensible heat from leaf [mm/s]
238- real (r8 ) :: obuold(bounds% begp:bounds% endp) ! monin-obukhov length from previous iteration
235+ real (r8 ) :: obuold(bounds% begp:bounds% endp) ! Obukhov length scale from previous iteration
239236 real (r8 ) :: tlbef(bounds% begp:bounds% endp) ! leaf temperature from previous iteration [K]
240237 real (r8 ) :: ecidif ! excess energies [W/m2]
241238 real (r8 ) :: err (bounds% begp:bounds% endp) ! balance error
@@ -319,6 +316,13 @@ subroutine CanopyFluxes(bounds, num_nolakeurbanp, filter_nolakeurbanp, &
319316 real (r8 ) :: prev_tau_diff(bounds% begp:bounds% endp) ! Previous difference in iteration tau
320317
321318 character (len= 64 ) :: event ! ! timing event
319+
320+ ! Indices for raw and rah
321+ integer , parameter :: above_canopy = 1 ! Above canopy
322+ integer , parameter :: below_canopy = 2 ! Below canopy
323+
324+ ! Lower bound for VPD (based on CLM)
325+ real (r8 ), parameter :: vpd_min = 50._r8
322326 !- -----------------------------------------------------------------------------
323327
324328 associate( &
@@ -444,6 +448,18 @@ subroutine CanopyFluxes(bounds, num_nolakeurbanp, filter_nolakeurbanp, &
444448 eflx_sh_soil = > veg_ef% eflx_sh_soil , & ! Output: [real(r8) (:) ] sensible heat flux from soil (W/m**2) [+ to atm]
445449 eflx_sh_veg = > veg_ef% eflx_sh_veg , & ! Output: [real(r8) (:) ] sensible heat flux from leaves (W/m**2) [+ to atm]
446450 eflx_sh_grnd = > veg_ef% eflx_sh_grnd , & ! Output: [real(r8) (:) ] sensible heat flux from ground (W/m**2) [+ to atm]
451+ rah_above = > frictionvel_vars% rah_above_patch , & ! Output: [real(r8) (:) ] above-canopy sensible heat flux resistance [s/m]
452+ rah_below = > frictionvel_vars% rah_above_patch , & ! Output: [real(r8) (:) ] below-canopy sensible heat flux resistance [s/m]
453+ raw_above = > frictionvel_vars% raw_below_patch , & ! Output: [real(r8) (:) ] above-canopy water vapour flux resistance [s/m]
454+ raw_below = > frictionvel_vars% raw_below_patch , & ! Output: [real(r8) (:) ] below-canopy water vapour flux resistance [s/m]
455+ ustar = > frictionvel_vars% ustar_patch , & ! Output: [real(r8) (:) ] friction velocity [m/s]
456+ um = > frictionvel_vars% um_patch , & ! Output: [real(r8) (:) ] wind speed including the stablity effect [m/s]
457+ uaf = > frictionvel_vars% uaf_patch , & ! Output: [real(r8) (:) ] canopy air wind speed [m/s]
458+ taf = > frictionvel_vars% taf_patch , & ! Output: [real(r8) (:) ] canopy air temperature [K]
459+ qaf = > frictionvel_vars% qaf_patch , & ! Output: [real(r8) (:) ] canopy air specific humidity [kg/kg]
460+ obu = > frictionvel_vars% obu_patch , & ! Output: [real(r8) (:) ] Obukhov length scale [m]
461+ zeta = > frictionvel_vars% zeta_patch , & ! Output: [real(r8) (:) ] dimensionless stability parameter
462+ vpd = > frictionvel_vars% vpd_patch , & ! Output: [real(r8) (:) ] vapour pressure deficit [kPa]
447463 begp = > bounds% begp , &
448464 endp = > bounds% endp &
449465 )
@@ -747,7 +763,7 @@ subroutine CanopyFluxes(bounds, num_nolakeurbanp, filter_nolakeurbanp, &
747763 p = filterp(f)
748764 c = veg_pp% column(p)
749765
750- ! Initialize Monin- Obukhov length and wind speed
766+ ! Initialize Obukhov length scale and wind speed
751767
752768 call MoninObukIni(ur(p), thv(c), dthv(p), zldis(p), z0mv(p), um(p), obu(p))
753769 num_iter(p) = 0._r8
@@ -784,8 +800,8 @@ subroutine CanopyFluxes(bounds, num_nolakeurbanp, filter_nolakeurbanp, &
784800
785801 ! Determine aerodynamic resistances
786802 ram1(p) = 1._r8 / (ustar(p)* ustar(p)/ um(p))
787- rah(p,1 ) = 1._r8 / (temp1(p)* ustar(p))
788- raw(p,1 ) = 1._r8 / (temp2(p)* ustar(p))
803+ rah(p,above_canopy ) = 1._r8 / (temp1(p)* ustar(p))
804+ raw(p,above_canopy ) = 1._r8 / (temp2(p)* ustar(p))
789805
790806 ! Forbid removing more than 99% of wind speed in a time step.
791807 ! This is mainly to avoid convergence issues since this is such a
@@ -842,18 +858,25 @@ subroutine CanopyFluxes(bounds, num_nolakeurbanp, filter_nolakeurbanp, &
842858
843859 ! ! Sakaguchi changes for stability formulation ends here
844860
845- rah(p,2 ) = 1._r8 / (csoilcn* uaf(p))
846- raw(p,2 ) = rah(p,2 )
861+ rah(p,below_canopy ) = 1._r8 / (csoilcn* uaf(p))
862+ raw(p,below_canopy ) = rah(p,below_canopy )
847863 if (use_lch4) then
848- grnd_ch4_cond(p) = 1._r8 / (raw(p,1 )+ raw(p,2 ))
864+ grnd_ch4_cond(p) = 1._r8 / (raw(p,above_canopy )+ raw(p,below_canopy ))
849865 end if
850866
851867 ! Stomatal resistances for sunlit and shaded fractions of canopy.
852868 ! Done each iteration to account for differences in eah, tv.
853869
854- svpts(p) = el(p) ! pa
855- eah(p) = forc_pbot(t) * qaf(p) / 0.622_r8 ! pa
870+ svpts(p) = el(p) ! Pa
871+ eah(p) = forc_pbot(t) * qaf(p) / mm_epsilon ! Pa
856872 rhaf(p) = eah(p)/ svpts(p)
873+
874+ ! variables for history fields
875+ rah_above(p) = rah(p,above_canopy)
876+ raw_above(p) = raw(p,above_canopy)
877+ rah_below(p) = rah(p,below_canopy)
878+ raw_below(p) = raw(p,below_canopy)
879+ vpd(p) = max ((svpts(p) - eah(p)), vpd_min) * pa_to_kpa ! kPa
857880 end do
858881
859882 ! Modification for shrubs proposed by X.D.Z
@@ -941,9 +964,9 @@ subroutine CanopyFluxes(bounds, num_nolakeurbanp, filter_nolakeurbanp, &
941964 ! Sensible heat conductance for air, leaf and ground
942965 ! Moved the original subroutine in-line...
943966
944- wta = 1._r8 / rah(p,1 ) ! air
967+ wta = 1._r8 / rah(p,above_canopy) ! air
945968 wtl = (elai(p)+ esai(p))/ rb(p) ! leaf
946- wtg(p) = 1._r8 / rah(p,2 ) ! ground
969+ wtg(p) = 1._r8 / rah(p,below_canopy) ! ground
947970 wtshi = 1._r8 / (wta+ wtl+ wtg(p))
948971 wtl0(p) = wtl* wtshi ! leaf
949972 wtg0 = wtg(p)* wtshi ! ground
@@ -1005,7 +1028,7 @@ subroutine CanopyFluxes(bounds, num_nolakeurbanp, filter_nolakeurbanp, &
10051028 ! Air has same conductance for both sensible and latent heat.
10061029 ! Moved the original subroutine in-line...
10071030
1008- wtaq = frac_veg_nosno(p)/ raw(p,1 ) ! air
1031+ wtaq = frac_veg_nosno(p)/ raw(p,above_canopy) ! air
10091032 wtlq = frac_veg_nosno(p)* (elai(p)+ esai(p))/ rb(p) * rpp ! leaf
10101033
10111034 ! Litter layer resistance. Added by K.Sakaguchi
@@ -1016,10 +1039,10 @@ subroutine CanopyFluxes(bounds, num_nolakeurbanp, filter_nolakeurbanp, &
10161039
10171040 ! add litter resistance and Lee and Pielke 1992 beta
10181041 if (delq(p) < 0._r8 ) then ! dew. Do not apply beta for negative flux (follow old rsoil)
1019- wtgq(p) = frac_veg_nosno(p)/ (raw(p,2 )+ rdl)
1042+ wtgq(p) = frac_veg_nosno(p)/ (raw(p,below_canopy )+ rdl)
10201043 else
10211044 if (do_soilevap_beta()) then
1022- wtgq(p) = soilbeta(c)* frac_veg_nosno(p)/ (raw(p,2 )+ rdl)
1045+ wtgq(p) = soilbeta(c)* frac_veg_nosno(p)/ (raw(p,below_canopy )+ rdl)
10231046 endif
10241047 end if
10251048
@@ -1112,7 +1135,7 @@ subroutine CanopyFluxes(bounds, num_nolakeurbanp, filter_nolakeurbanp, &
11121135 taf(p) = wtg0* t_grnd(c) + wta0(p)* thm(p) + wtl0(p)* t_veg(p)
11131136 qaf(p) = wtlq0(p)* qsatl(p) + wtgq0* qg(c) + forc_q(t)* wtaq0(p)
11141137
1115- ! Update Monin- Obukhov length and wind speed including the
1138+ ! Update Obukhov length scale and wind speed including the
11161139 ! stability effect
11171140
11181141 dth(p) = thm(p)- taf(p)
@@ -1123,13 +1146,13 @@ subroutine CanopyFluxes(bounds, num_nolakeurbanp, filter_nolakeurbanp, &
11231146 qstar = temp2(p)* dqh(p)
11241147
11251148 thvstar = tstar* (1._r8+0.61_r8 * forc_q(t)) + 0.61_r8 * forc_th(t)* qstar
1126- zeta = zldis(p)* vkc* grav* thvstar/ (ustar(p)** 2 * thv(c))
1149+ zeta(p) = zldis(p)* vkc* grav* thvstar/ (ustar(p)** 2 * thv(c))
11271150
1128- if (zeta >= 0._r8 ) then ! stable
1129- zeta = min (2._r8 ,max (zeta,0.01_r8 ))
1151+ if (zeta(p) >= 0._r8 ) then ! stable
1152+ zeta(p) = min (2._r8 ,max (zeta(p) ,0.01_r8 ))
11301153 um(p) = max (ur(p),0.1_r8 )
11311154 else ! unstable
1132- zeta = max (- 100._r8 ,min (zeta,- 0.01_r8 ))
1155+ zeta(p) = max (- 100._r8 ,min (zeta(p) ,- 0.01_r8 ))
11331156 if ((.not. atm_gustiness) .or. force_land_gustiness) then
11341157 wc = beta* (- grav* ustar(p)* thvstar* zii/ thv(c))** 0.333_r8
11351158 ugust_total(p) = sqrt (ugust(t)** 2 + wc** 2 )
@@ -1138,7 +1161,7 @@ subroutine CanopyFluxes(bounds, num_nolakeurbanp, filter_nolakeurbanp, &
11381161 um(p) = max (ur(p),0.1_r8 )
11391162 end if
11401163 end if
1141- obu(p) = zldis(p)/ zeta
1164+ obu(p) = zldis(p)/ zeta(p)
11421165
11431166 if (obuold(p)* obu(p) < 0._r8 ) nmozsgn(p) = nmozsgn(p)+ 1
11441167 if (nmozsgn(p) >= 4 ) obu(p) = zldis(p)/ (- 0.01_r8 )
0 commit comments