#include <misc.h> #include <preproc.h> module CASAPhenologyMod 2,2 #if (defined CASA) !----------------------------------------------------------------------- !BOP ! ! !MODULE: CASAPhenologyMod ! ! !DESCRIPTION: ! Initialize and run the CASA vegetation phenology. ! ! replaces pheno_params.h, pheno_paramsi.F, phenotci.F, phenoinit.F, ! phenology.F, phenotcdyn.h, phenotvdyn.h from LSM-CASA code ! ! !USES: use shr_kind_mod, only : r8 => shr_kind_r8 use clm_varpar , only : numpft ! ! !PUBLIC TYPES: implicit none save ! define parameters and constants used in Phenology integer , parameter :: nsecbeg = 0 ! seconds at start of a day real(r8), parameter :: ngrowmin = 30.0_r8 ! minimum growing season of 30 days integer :: evergreen(0:numpft) ! evergreen flag (0 or 1), 1 = evergreen real(r8) :: tbase(0:numpft) ! base temperature (deg C) real(r8) :: ddcrit(0:numpft) ! degree days for start of growing season (deg C) real(r8) :: tdaycrit(0:numpft) ! daily temp threshold for dropping leaves (deg C) ! tbase min temperature for starting growth (degrees C) ! = 5C if not crops, use 10C if crops ! = 40F for wheat, barley, rye, oats... (not used) ! = 45F for sunflower, potato... (not used) ! = 50F for corn, sorghym, rice, soybeans, tomato ...(not used) ! ddcrit cumulative degree days threshold for start of ! growing season (deg C) ! = tbase until better info ! tdaycrit daily temperature threshold for dropping leaves (deg C) ! = tbase until better info data tbase/ 999.00_r8, & 5.00_r8, 5.00_r8, 5.00_r8, 5.00_r8, 5.00_r8, 5.00_r8, 5.00_r8, 5.00_r8, & 5.00_r8, 5.00_r8, 5.00_r8, 5.00_r8, 5.00_r8, 5.00_r8, 10.00_r8, 10.00_r8/ data ddcrit/ 999.00_r8, & 5.00_r8, 5.00_r8, 5.00_r8, 5.00_r8, 5.00_r8, 5.00_r8, 5.00_r8, 5.00_r8, & 5.00_r8, 5.00_r8, 5.00_r8, 5.00_r8, 5.00_r8, 5.00_r8, 10.00_r8, 10.00_r8/ data tdaycrit/ 999.00_r8, & 5.00_r8, 5.00_r8, 5.00_r8, 5.00_r8, 5.00_r8, 5.00_r8, 5.00_r8, 5.00_r8, & 5.00_r8, 5.00_r8, 5.00_r8, 5.00_r8, 5.00_r8, 5.00_r8, 10.00_r8, 10.00_r8/ ! ! !PUBLIC MEMBER FUNCTIONS: public :: initCASAPhenology ! Initialize CASA phenology public :: CASAPhenology ! Compute CASA phenology ! ! !REVISION HISTORY: ! 2004.06.08 Vectorized and reformatted by Forrest Hoffman ! !EOP !----------------------------------------------------------------------- contains !----------------------------------------------------------------------- !BOP ! ! !IROUTINE: initCASAPhenology ! ! !INTERFACE: subroutine initCASAPhenology() 1,4 ! ! !DESCRIPTION: ! Initialize CASA vegetation phenology. ! ! !USES: use clmtype use decompMod , only : get_proc_bounds use clm_varctl, only : nsrest ! ! !ARGUMENTS: implicit none ! ! !LOCAL VARIABLES: integer , pointer :: ivt(:) ! pft vegetation type real(r8), pointer :: tday(:) ! daily accumulated temperature (deg C) real(r8), pointer :: tdayavg(:) ! daily averaged temperature (deg C) real(r8), pointer :: tcount(:) ! counter for daily avg temp real(r8), pointer :: degday(:) ! accumulated degree days (deg C) real(r8), pointer :: ndegday(:) ! counter for number of degree days real(r8), pointer :: stressT(:) ! temperature stress function for leaf ! loss apply to Litterfall of decid veg real(r8), pointer :: stressW(:) ! water stress function for leaf loss real(r8), pointer :: stressCD(:) ! cold and drought stress function (sec-1) real(r8), pointer :: iseabeg(:) ! index for start of growing season real(r8), pointer :: nstepbeg(:) ! nstep at start of growing season real(r8), pointer :: lgrow(:) ! growing season index (0 or 1) to be ! passed daily to CASA to get NPP integer p ! pft index integer begp, endp ! per-proc beginning and ending pft indices integer begc, endc ! per-proc beginning and ending column indices integer begl, endl ! per-proc beginning and ending landunit indices integer begg, endg ! per-proc gridcell ending gridcell indices ! ! !CALLED FROM: ! initialize in initializeMod ! ! !REVISION HISTORY: ! 2004.06.08 Vectorized and reformatted by Forrest Hoffman ! !EOP !----------------------------------------------------------------------- ! implicit intent in !============================================================ ivt => clm3%g%l%c%p%itype ! implicit intent out !============================================================ tday => clm3%g%l%c%p%pps%tday tdayavg => clm3%g%l%c%p%pps%tdayavg tcount => clm3%g%l%c%p%pps%tcount degday => clm3%g%l%c%p%pps%degday ndegday => clm3%g%l%c%p%pps%ndegday stressT => clm3%g%l%c%p%pps%stressT stressW => clm3%g%l%c%p%pps%stressW stressCD => clm3%g%l%c%p%pps%stressCD iseabeg => clm3%g%l%c%p%pps%iseabeg nstepbeg => clm3%g%l%c%p%pps%nstepbeg lgrow => clm3%g%l%c%p%pps%lgrow call get_proc_bounds(begg, endg, begl, endl, begc, endc, begp, endp) ! set up array of crop types used in phenology ! set up array of evergreen types used in phenology do p = 0,numpft if (p == 1 .or. p == 2 .or. p == 4 .or. p == 5 .or. p == 9) then evergreen(p) = 1 else evergreen(p) = 0 end if end do do p = begp, endp ! stressT(p) = 0.0 ! stressW(p) = 0.0 if (nsrest == 0) then if (evergreen(ivt(p)) == 1 ) then lgrow(p) = 1._r8 else lgrow(p) = 0._r8 end if iseabeg(p) = 0.0_r8 nstepbeg(p) = 0.0_r8 ndegday(p) = 0.0_r8 tday(p) = 0.0_r8 tcount(p) = 0.0_r8 tdayavg(p) = 0.0_r8 degday(p) = 0.0_r8 stressCD(p) = 0.0_r8 stressT(p) = 0.0_r8 !! added to restart stressW(p) = 0.0_r8 !! added to restart end if end do end subroutine initCASAPhenology !----------------------------------------------------------------------- !BOP ! ! !IROUTINE: CASAPhenology ! ! !INTERFACE: subroutine CASAPhenology(lbp, ubp, num_soilp, filter_soilp) 1,7 ! ! !DESCRIPTION: ! Compute CASA vegetation phenology. ! ! !USES: use clmtype use clm_varcon , only : tfrz use clm_time_manager, only : get_step_size, get_nstep, get_curr_date ! ! !ARGUMENTS: implicit none integer, intent(in) :: lbp, ubp ! pft-index bounds integer, intent(in) :: num_soilp ! number of soil points in pft filter integer, intent(in) :: filter_soilp(ubp-lbp+1) ! pft filter for soil points ! ! !LOCAL VARIABLES: integer , pointer :: ivt(:) ! pft vegetation type integer , pointer :: pgridcell(:) ! pft's gridcell index real(r8), pointer :: latdeg(:) ! latitude (degrees) real(r8), pointer :: tday(:) ! daily accumulated temperature (deg C) real(r8), pointer :: tdayavg(:) ! daily averaged temperature (deg C) real(r8), pointer :: tcount(:) ! counter for daily avg temp real(r8), pointer :: degday(:) ! accumulated degree days (deg C) real(r8), pointer :: ndegday(:) ! counter for number of degree days real(r8), pointer :: stressT(:) ! temperature stress function for leaf ! loss apply to Litterfall of decid veg real(r8), pointer :: stressW(:) ! water stress function for leaf loss real(r8), pointer :: stressCD(:) ! cold and drought stress function (sec-1) real(r8), pointer :: iseabeg(:) ! index for start of growing season real(r8), pointer :: nstepbeg(:) ! nstep at start of growing season real(r8), pointer :: lgrow(:) ! growing season index (0 or 1) to be ! passed daily to CASA to get NPP real(r8), pointer :: t_ref2m(:) ! 2m height surface air temperature (K) real(r8), pointer :: btran(:) ! transpiration factor (0 to 1) !============================================================== integer :: g ! gridcell index integer :: p ! pft index integer :: f ! filter index integer :: nstepmin integer :: mcsec_n !current seconds of next timestep (0, ..., 86400) integer :: mcsec !current seconds of current date (0, ..., 86400) integer :: kyr !year integer :: kmo !month (1, ..., 12) integer :: kda !day of month (1, ..., 31) integer :: nstep !time step number real(r8) :: dtime !land model time step (sec) real(r8) :: tnorm ! ! !CALLED FROM: ! casa_ecosystemDyn ! ! !REVISION HISTORY: ! 2004.06.08 Vectorized and reformatted by Forrest Hoffman ! !EOP !----------------------------------------------------------------------- ! implicit intent in !============================================================ ivt => clm3%g%l%c%p%itype pgridcell => clm3%g%l%c%p%gridcell latdeg => clm3%g%latdeg ! implicit intent inout !============================================================ tday => clm3%g%l%c%p%pps%tday ! daily accumulated temperature (deg C) tdayavg => clm3%g%l%c%p%pps%tdayavg ! daily averaged temperature (deg C) tcount => clm3%g%l%c%p%pps%tcount ! counter for daily avg temp degday => clm3%g%l%c%p%pps%degday ! accumulated degree days (deg C) ndegday => clm3%g%l%c%p%pps%ndegday ! counter for number of degree days ! implicit intent out !============================================================ stressT => clm3%g%l%c%p%pps%stressT ! temperature stress function for leaf loss apply to Litterfall of deciduous veg stressW => clm3%g%l%c%p%pps%stressW ! water stress function for leaf loss stressCD => clm3%g%l%c%p%pps%stressCD ! cold and drought stress function (sec-1) iseabeg => clm3%g%l%c%p%pps%iseabeg ! index for start of growing season nstepbeg => clm3%g%l%c%p%pps%nstepbeg ! nstep at start of growing season lgrow => clm3%g%l%c%p%pps%lgrow ! growing season index (0 or 1) to be passed daily to CASA to get NPP t_ref2m => clm3%g%l%c%p%pes%t_ref2m ! 2m surface air temperature (K) btran => clm3%g%l%c%p%pps%btran ! transpiration factor (0 to 1) ! ----------------------------------------------------------------------- ! Get step size and current timestep dtime = get_step_size() nstep = get_nstep() ! convert ngrowmin (days) to timesteps nstepmin = ngrowmin*86400/dtime ! ---------------------------------------------------------------------- ! initialize arrays at start of the winter season ! NOTE: kda is not a julian day or this will not work. ! removed kmobeg (start of winter season) and hardwired to 1 or 7 ! easy to reintroduce if expect it to vary (slevis) ! assign 0 deg latitude to the Northern hemisphere ! as the thermal equator is south of the equator. call get_curr_date(kyr, kmo, kda, mcsec) if (mcsec == nsecbeg .and. kda == 1) then do f = 1, num_soilp p = filter_soilp(f) g = pgridcell(p) if ((latdeg(g) >= 0._r8 .and. kmo == 1) .or. & ! Jan start in NH (latdeg(g) < 0._r8 .and. kmo == 7)) then ! Jul start in SH degday(p) = 0.0_r8 ndegday(p) = 0.0_r8 iseabeg(p) = 0.0_r8 end if end do end if ! ---------------------------------------------------------------------- ! DAILY AVERAGING ! initialize arrays on first timestep of each new day if (mcsec == nsecbeg) then do f = 1, num_soilp p = filter_soilp(f) ! tdayavg is needed for degday calculation and possibly for ! monthly history accumulations - don't reset to zero. ! tdayavg(k) = 0.0 tday(p) = 0.0_r8 tcount(p) = 0.0_r8 end do end if do f = 1, num_soilp p = filter_soilp(f) ! get min/max daily temp for dtr ! accumulate temperature during the day tday(p) = tday(p) + (t_ref2m(p)-tfrz) !deg C tcount(p) = tcount(p) + 1.0_r8 end do ! get daily averaged temperature (at end of day) ! mcsec_n = 0 is start of next day call get_curr_date(kyr, kmo, kda, mcsec_n, offset=int(dtime)) if (mcsec_n /= nsecbeg) return ! exit if not end of day ! reset counters for start of next day ! tdayavg is needed for degday calculation and possibly for ! monthly history accumulations - don't reset to zero. do f = 1, num_soilp p = filter_soilp(f) if (tcount(p) /= 0.0_r8) then tdayavg(p) = tday(p)/tcount(p) tday(p) = 0.0_r8 tcount(p) = 0.0_r8 end if end do ! END OF DAILY AVERAGING ! IF NOT END OF DAY, EXIT FROM SUBROUTINE ! THIS EXITING WILL MISS THE FIRST DAY OF THE GROWING SEASON ! ---------------------------------------------------------------------- ! accumulate degree days since daily Temp > base temperature for vegtype ! for corn, tbase = 50F ! Foley (1996) essentially has Tbase = 5C for winter deciduous trees do f = 1, num_soilp p = filter_soilp(f) if (tdayavg(p) > tbase(ivt(p))) then if (iseabeg(p) == 0.0_r8) nstepbeg(p) = real(nstep) iseabeg(p) = 1.0_r8 degday(p) = degday(p) + tdayavg(p) ndegday(p) = ndegday(p)+1.0_r8 end if end do ! ---------------------------------------------------------------------- ! start growing season if degday > threshold ! here we assume that ddcrit(k) = tbase(k) ! ! lgrow is either 0 or 1. ! It is to be passed daily to the GPP subroutine. ! April02: we are passing this to the first call to CASA ! where we go from GPP to NPP. ! If lgrow=0 even if GPP > 0, we set NPP to zero, and ! pretend that all GPP went into autotrophic respiration. do f = 1, num_soilp p = filter_soilp(f) if (evergreen(ivt(p)) == 0) then if (degday(p) > ddcrit(ivt(p))) lgrow(p) = 1.0_r8 end if end do ! ---------------------------------------------------------------------- ! end of growing season ! if daily air temperature < critical value for veg ! Foley et al. (1996) used a critical temp of 5C for all veg ! drop leaves gradually by stress index ! ala Equation 7 and 8 of Dickinson et al J Climate 1998. ! Note Dickinson used canopy temperature rather than air temperature ! 6/23/02 ! Dickinson et al. (JClim 1998) Eqn(7) has T as argument in exponential ! and the exp goes to infinity very fast ! stressT(k)=exp(-(tdayavg(k)-tdaycrit(i))) ! modify the equation to use normalized T as argument ! ! - Dickinson et al. Equation 6: ! stressCD is cold and drought stress, unit is sec-1 ! cross-check: 1/stressCD ~1-2 months ! stressCD(k) to be added to "annK(m,LEAF)" and "annK(m,FROOT)" ! in casa_bgfluxes.F !---------------------------------------------------------------------- ! Notes from iyf 02/07/11 ! ! Dickinson 1998 Interactive canopies for a climate model, J Climate ! ! Cold and drought stress for phenology - Eqn 7-8 ! ! Here we modify the arguments of Dickinson's equation ! StressT = exp(-(Tavg-Tcrit)/Tcrit)) ! StressW = exp((1-btran) ! No change to ! StressCD = (StressT+StressD)x2e-7 (sec-1) ! ! Typical values: ! --------------- ! let stressT = 0. btran = 0.1 --> tau=1/stressCD = 26 days. ! btran = 0.9 --> 56 days ! ! Default values: ! --------------- ! evergreens: stressT = 0, stressW = 0 ! ! Notes: ! ------ ! In Dickinson's formulation of StressT, arg=-(T-Tcrit). The normalization ! to Tcrit is necessary. ! ! In Dickinson's formulation of StressW, arg=100(W-1), where W is a water ! stress ! term, est from the reduction by soil drying of the max evapotranspiration ! allowed by roots. W>1 is permanent wilting. ! ! In the LSM (documentation page 107), ! BTRAN = \sum (w_i*r_i) ! where w_i = (theta_i - theta_dry)/(theta_opt - theta-dry) ! theta_i is the volumetric soil moisture for layer i, ! and r_i is the relative root abundance. ! BTRAN varies between 0 (dry) and 1 (wet). ! !---------------------------------------------------------------------- ! To distinguish the autumn from the spring, ! put in a minimum growing season of 30 days do f = 1, num_soilp p = filter_soilp(f) ! Initialize every time step stressT(p) = 0._r8 stressW(p) = 0._r8 stressCD(p) = 0._r8 if (evergreen(ivt(p)) == 0 .and. nstep-nstepbeg(p) > nstepmin & .and. tdayavg(p) < tdaycrit(ivt(p))) then lgrow(p) = 0.0_r8 tnorm = tdaycrit(ivt(p)) if (abs(tnorm) <= 1.e-5_r8) tnorm = 1.0_r8 stressT(p) = exp(-(tdayavg(p)-tdaycrit(ivt(p)))/tnorm) stressW(p) = exp(1.0_r8-btran(p)) stressCD(p) = (stressT(p)+stressW(p))*2.e-7_r8 end if end do ! We apply StressT to litterfall of deciduous vegetation. ! Need to adjust seasonally invariant turnover times from before. ! April 02: Dickinson has a water stress as well. Not yet implemnted. ! July 02 - implemented water stress and cold/drought stress. end subroutine CASAPhenology #endif end module CASAPhenologyMod