module STATICEcosysdynMOD !----------------------------------------------------------------------- !BOP ! ! !MODULE: STATICEcosysDynMod ! ! !DESCRIPTION: ! Static Ecosystem dynamics: phenology, vegetation. This is for the CLM Satelitte Phenology ! model (CLMSP). Allow some subroutines to be used by the CLM Carbon Nitrogen model (CLMCN) ! so that DryDeposition code can get estimates of LAI differences between months. ! ! !USES: use shr_kind_mod, only : r8 => shr_kind_r8 use abortutils, only : endrun use clm_varctl, only : scmlat,scmlon,single_column use clm_varctl, only : iulog use perf_mod, only : t_startf, t_stopf use spmdMod, only : masterproc use ncdio_pio ! ! !PUBLIC TYPES: implicit none save ! ! !PUBLIC MEMBER FUNCTIONS: #if (!defined CN) && (!defined CNDV) public :: EcosystemDyn ! CLMSP Ecosystem dynamics: phenology, vegetation #endif public :: EcosystemDynini ! Dynamically allocate memory public :: interpMonthlyVeg ! interpolate monthly vegetation data public :: readAnnualVegetation ! Read in annual vegetation (needed for Dry-deposition) ! ! !REVISION HISTORY: ! Created by Mariana Vertenstein ! ! ! !PRIVATE MEMBER FUNCTIONS: private :: readMonthlyVegetation ! read monthly vegetation data for two months ! ! !PRIVATE TYPES: integer , private :: InterpMonths1 ! saved month index real(r8), private :: timwt(2) ! time weights for month 1 and month 2 real(r8), private, allocatable :: mlai2t(:,:) ! lai for interpolation (2 months) real(r8), private, allocatable :: msai2t(:,:) ! sai for interpolation (2 months) real(r8), private, allocatable :: mhvt2t(:,:) ! top vegetation height for interpolation (2 months) real(r8), private, allocatable :: mhvb2t(:,:) ! bottom vegetation height for interpolation(2 months) !EOP !----------------------------------------------------------------------- contains !----------------------------------------------------------------------- !BOP ! ! !IROUTINE: EcosystemDynini ! ! !INTERFACE: subroutine EcosystemDynini () ! ! !DESCRIPTION: ! Dynamically allocate memory and set to signaling NaN. ! ! !USES: use nanMod use decompMod, only : get_proc_bounds ! ! !ARGUMENTS: implicit none ! ! !REVISION HISTORY: ! ! ! !LOCAL VARIABLES: !EOP integer :: ier ! error code integer :: begp,endp ! local beg and end p index !----------------------------------------------------------------------- InterpMonths1 = -999 ! saved month index call get_proc_bounds(begp=begp,endp=endp) ier = 0 if(.not.allocated(mlai2t))allocate (mlai2t(begp:endp,2), & msai2t(begp:endp,2), & mhvt2t(begp:endp,2), & mhvb2t(begp:endp,2), stat=ier) if (ier /= 0) then write(iulog,*) 'EcosystemDynini allocation error' call endrun end if mlai2t(:,:) = nan msai2t(:,:) = nan mhvt2t(:,:) = nan mhvb2t(:,:) = nan end subroutine EcosystemDynini #if (!defined CN) && (!defined CNDV) !----------------------------------------------------------------------- !BOP ! ! !IROUTINE: EcosystemDyn ! ! !INTERFACE: subroutine EcosystemDyn(lbp, ubp, num_nolakep, filter_nolakep, doalb) ! ! !DESCRIPTION: ! Ecosystem dynamics: phenology, vegetation ! Calculates leaf areas (tlai, elai), stem areas (tsai, esai) and ! height (htop). ! ! !USES: use clmtype use pftvarcon, only : noveg, nc3crop, nbrdlf_dcd_brl_shrub ! ! !ARGUMENTS: implicit none integer, intent(in) :: lbp, ubp ! pft bounds integer, intent(in) :: num_nolakep ! number of column non-lake points in pft filter integer, intent(in) :: filter_nolakep(ubp-lbp+1) ! pft filter for non-lake points logical, intent(in) :: doalb ! true = surface albedo calculation time step ! ! !CALLED FROM: ! ! !REVISION HISTORY: ! Author: Gordon Bonan ! 2/1/02, Peter Thornton: Migrated to new data structure. ! 2/29/08, David Lawrence: revised snow burial fraction for short vegetation ! ! !LOCAL VARIABLES: ! ! local pointers to implicit in arguments ! integer , pointer :: pcolumn(:) ! column index associated with each pft real(r8), pointer :: snowdp(:) ! snow height (m) integer , pointer :: ivt(:) ! pft vegetation type ! ! local pointers to implicit out arguments ! real(r8), pointer :: tlai(:) ! one-sided leaf area index, no burying by snow real(r8), pointer :: tsai(:) ! one-sided stem area index, no burying by snow real(r8), pointer :: htop(:) ! canopy top (m) real(r8), pointer :: hbot(:) ! canopy bottom (m) real(r8), pointer :: elai(:) ! one-sided leaf area index with burying by snow real(r8), pointer :: esai(:) ! one-sided stem area index with burying by snow integer , pointer :: frac_veg_nosno_alb(:) ! frac of vegetation not covered by snow [-] ! ! ! !OTHER LOCAL VARIABLES: !EOP ! integer :: fp,p,c ! indices real(r8) :: ol ! thickness of canopy layer covered by snow (m) real(r8) :: fb ! fraction of canopy layer covered by snow !----------------------------------------------------------------------- if (doalb) then ! Assign local pointers to derived type scalar members (column-level) snowdp => clm3%g%l%c%cps%snowdp ! Assign local pointers to derived type scalar members (pftlevel) pcolumn => clm3%g%l%c%p%column tlai => clm3%g%l%c%p%pps%tlai tsai => clm3%g%l%c%p%pps%tsai elai => clm3%g%l%c%p%pps%elai esai => clm3%g%l%c%p%pps%esai htop => clm3%g%l%c%p%pps%htop hbot => clm3%g%l%c%p%pps%hbot frac_veg_nosno_alb => clm3%g%l%c%p%pps%frac_veg_nosno_alb ivt => clm3%g%l%c%p%itype do fp = 1, num_nolakep p = filter_nolakep(fp) c = pcolumn(p) ! need to update elai and esai only every albedo time step so do not ! have any inconsistency in lai and sai between SurfaceAlbedo calls (i.e., ! if albedos are not done every time step). ! leaf phenology ! Set leaf and stem areas based on day of year ! Interpolate leaf area index, stem area index, and vegetation heights ! between two monthly ! The weights below (timwt(1) and timwt(2)) were obtained by a call to ! routine InterpMonthlyVeg in subroutine NCARlsm. ! Field Monthly Values ! ------------------------- ! leaf area index LAI <- mlai1 and mlai2 ! leaf area index SAI <- msai1 and msai2 ! top height HTOP <- mhvt1 and mhvt2 ! bottom height HBOT <- mhvb1 and mhvb2 tlai(p) = timwt(1)*mlai2t(p,1) + timwt(2)*mlai2t(p,2) tsai(p) = timwt(1)*msai2t(p,1) + timwt(2)*msai2t(p,2) htop(p) = timwt(1)*mhvt2t(p,1) + timwt(2)*mhvt2t(p,2) hbot(p) = timwt(1)*mhvb2t(p,1) + timwt(2)*mhvb2t(p,2) ! adjust lai and sai for burying by snow. if exposed lai and sai ! are less than 0.05, set equal to zero to prevent numerical ! problems associated with very small lai and sai. ! snow burial fraction for short vegetation (e.g. grasses) as in ! Wang and Zeng, 2007. if (ivt(p) > noveg .and. ivt(p) <= nbrdlf_dcd_brl_shrub ) then ol = min( max(snowdp(c)-hbot(p), 0._r8), htop(p)-hbot(p)) fb = 1._r8 - ol / max(1.e-06_r8, htop(p)-hbot(p)) else fb = 1._r8 - max(min(snowdp(c),0.2_r8),0._r8)/0.2_r8 ! 0.2m is assumed !depth of snow required for complete burial of grasses endif elai(p) = max(tlai(p)*fb, 0.0_r8) esai(p) = max(tsai(p)*fb, 0.0_r8) if (elai(p) < 0.05_r8) elai(p) = 0._r8 if (esai(p) < 0.05_r8) esai(p) = 0._r8 ! Fraction of vegetation free of snow if ((elai(p) + esai(p)) >= 0.05_r8) then frac_veg_nosno_alb(p) = 1 else frac_veg_nosno_alb(p) = 0 end if end do ! end of pft loop end if !end of if-doalb block end subroutine EcosystemDyn #endif !----------------------------------------------------------------------- !BOP ! ! !IROUTINE: interpMonthlyVeg ! ! !INTERFACE: subroutine interpMonthlyVeg () ! ! !DESCRIPTION: ! Determine if 2 new months of data are to be read. ! ! !USES: use clm_varctl , only : fsurdat use clm_time_manager, only : get_curr_date, get_step_size, & get_perp_date, is_perpetual, get_nstep ! ! !ARGUMENTS: implicit none ! ! !REVISION HISTORY: ! Created by Mariana Vertenstein ! ! ! !LOCAL VARIABLES: !EOP integer :: kyr ! year (0, ...) for nstep+1 integer :: kmo ! month (1, ..., 12) integer :: kda ! day of month (1, ..., 31) integer :: ksec ! seconds into current date for nstep+1 real(r8):: dtime ! land model time step (sec) real(r8):: t ! a fraction: kda/ndaypm integer :: it(2) ! month 1 and month 2 (step 1) integer :: months(2) ! months to be interpolated (1 to 12) integer, dimension(12) :: ndaypm= & (/31,28,31,30,31,30,31,31,30,31,30,31/) !days per month !----------------------------------------------------------------------- dtime = get_step_size() if ( is_perpetual() ) then call get_perp_date(kyr, kmo, kda, ksec, offset=int(dtime)) else call get_curr_date(kyr, kmo, kda, ksec, offset=int(dtime)) end if t = (kda-0.5_r8) / ndaypm(kmo) it(1) = t + 0.5_r8 it(2) = it(1) + 1 months(1) = kmo + it(1) - 1 months(2) = kmo + it(2) - 1 if (months(1) < 1) months(1) = 12 if (months(2) > 12) months(2) = 1 timwt(1) = (it(1)+0.5_r8) - t timwt(2) = 1._r8-timwt(1) if (InterpMonths1 /= months(1)) then if (masterproc) then write(iulog,*) 'Attempting to read monthly vegetation data .....' write(iulog,*) 'nstep = ',get_nstep(),' month = ',kmo,' day = ',kda end if call t_startf('readMonthlyVeg') call readMonthlyVegetation (fsurdat, months) InterpMonths1 = months(1) call t_stopf('readMonthlyVeg') end if end subroutine interpMonthlyVeg !----------------------------------------------------------------------- ! read 12 months of veg data for dry deposition !----------------------------------------------------------------------- subroutine readAnnualVegetation ( ) use clmtype use clm_varpar , only : numpft use pftvarcon , only : noveg use decompMod , only : get_proc_bounds use domainMod , only : ldomain use fileutils , only : getfil use clm_varctl , only : fsurdat use shr_scam_mod, only : shr_scam_getCloseLatLon implicit none ! local vars type(file_desc_t) :: ncid ! netcdf id real(r8), pointer :: annlai(:,:) ! 12 months of monthly lai from input data set real(r8), pointer :: mlai(:,:) ! lai read from input files integer :: ier ! error code character(len=256) :: locfn ! local file name integer :: g,k,l,m,n,p,ivt ! indices integer :: ni,nj,ns ! indices integer :: dimid,varid ! input netCDF id's integer :: ntim ! number of input data time samples integer :: nlon_i ! number of input data longitudes integer :: nlat_i ! number of input data latitudes integer :: npft_i ! number of input data pft types integer :: begp,endp ! beg and end local p index integer :: begg,endg ! beg and end local g index integer :: closelatidx,closelonidx ! single column vars real(r8):: closelat,closelon ! single column vars logical :: isgrid2d ! true => file is 2d character(len=32) :: subname = 'readAnnualVegetation' annlai => clm3%g%l%c%p%pps%annlai ! Determine necessary indices call get_proc_bounds(begg=begg,endg=endg,begp=begp,endp=endp) allocate(mlai(begg:endg,0:numpft), stat=ier) if (ier /= 0) then write(iulog,*)subname, 'allocation error '; call endrun() end if if (masterproc) then write (iulog,*) 'Attempting to read annual vegetation data .....' end if call getfil(fsurdat, locfn, 0) call ncd_pio_openfile (ncid, trim(locfn), 0) call ncd_inqfdims (ncid, isgrid2d, ni, nj, ns) if (ldomain%ns /= ns .or. ldomain%ni /= ni .or. ldomain%nj /= nj) then write(iulog,*)trim(subname), 'ldomain and input file do not match dims ' write(iulog,*)trim(subname), 'ldomain%ni,ni,= ',ldomain%ni,ni write(iulog,*)trim(subname), 'ldomain%nj,nj,= ',ldomain%nj,nj write(iulog,*)trim(subname), 'ldomain%ns,ns,= ',ldomain%ns,ns call endrun() end if call check_dim(ncid, 'lsmpft', numpft+1) if (single_column) then call shr_scam_getCloseLatLon(locfn, scmlat, scmlon, & closelat, closelon, closelatidx, closelonidx) endif do k=1,12 !! loop over months and read vegetated data call ncd_io(ncid=ncid, varname='MONTHLY_LAI', flag='read', data=mlai, & dim1name=grlnd, nt=k) !! store data directly in clmtype structure !! only vegetated pfts have nonzero values !! Assign lai/sai/hgtt/hgtb to the top [maxpatch_pft] pfts !! as determined in subroutine surfrd do p = begp,endp g = clm3%g%l%c%p%gridcell(p) ivt = clm3%g%l%c%p%itype(p) if (ivt /= noveg) then !! vegetated pft do l = 0, numpft if (l == ivt) then annlai(k,p) = mlai(g,l) end if end do else !! non-vegetated pft annlai(k,p) = 0._r8 end if end do ! end of loop over pfts enddo ! months loop call ncd_pio_closefile(ncid) deallocate(mlai) endsubroutine readAnnualVegetation !----------------------------------------------------------------------- !BOP ! ! !IROUTINE: readMonthlyVegetation ! ! !INTERFACE: subroutine readMonthlyVegetation (fveg, months) ! ! !DESCRIPTION: ! Read monthly vegetation data for two consec. months. ! ! !USES: use clmtype use decompMod , only : get_proc_bounds use clm_varpar , only : numpft use pftvarcon , only : noveg use fileutils , only : getfil use spmdMod , only : masterproc, mpicom, MPI_REAL8, MPI_INTEGER use shr_scam_mod, only : shr_scam_getCloseLatLon use clm_time_manager, only : get_nstep use netcdf ! ! !ARGUMENTS: implicit none character(len=*), intent(in) :: fveg ! file with monthly vegetation data integer, intent(in) :: months(2) ! months to be interpolated (1 to 12) ! ! !REVISION HISTORY: ! Created by Sam Levis ! ! ! !LOCAL VARIABLES: !EOP character(len=256) :: locfn ! local file name type(file_desc_t) :: ncid ! netcdf id integer :: g,n,k,l,m,p,ivt,ni,nj,ns ! indices integer :: dimid,varid ! input netCDF id's integer :: ntim ! number of input data time samples integer :: nlon_i ! number of input data longitudes integer :: nlat_i ! number of input data latitudes integer :: npft_i ! number of input data pft types integer :: begp,endp ! beg and end local p index integer :: begg,endg ! beg and end local g index integer :: ier ! error code integer :: closelatidx,closelonidx real(r8):: closelat,closelon logical :: readvar real(r8), pointer :: mlai(:,:) ! lai read from input files real(r8), pointer :: msai(:,:) ! sai read from input files real(r8), pointer :: mhgtt(:,:) ! top vegetation height real(r8), pointer :: mhgtb(:,:) ! bottom vegetation height real(r8), pointer :: mlaidiff(:) ! difference between lai month one and month two character(len=32) :: subname = 'readMonthlyVegetation' !----------------------------------------------------------------------- ! Determine necessary indices call get_proc_bounds(begg=begg,endg=endg,begp=begp,endp=endp) allocate(mlai(begg:endg,0:numpft), & msai(begg:endg,0:numpft), & mhgtt(begg:endg,0:numpft), & mhgtb(begg:endg,0:numpft), & stat=ier) if (ier /= 0) then write(iulog,*)subname, 'allocation big error '; call endrun() end if ! ---------------------------------------------------------------------- ! Open monthly vegetation file ! Read data and convert from gridcell to pft data ! ---------------------------------------------------------------------- call getfil(fveg, locfn, 0) call ncd_pio_openfile (ncid, trim(locfn), 0) if (single_column) then call shr_scam_getCloseLatLon (ncid, scmlat, scmlon, closelat, closelon,& closelatidx, closelonidx) endif do k=1,2 !loop over months and read vegetated data call ncd_io(ncid=ncid, varname='MONTHLY_LAI', flag='read', data=mlai, dim1name=grlnd, & nt=months(k), readvar=readvar) if (.not. readvar) call endrun( trim(subname)//' ERROR: MONTHLY_LAI NOT on fveg file' ) call ncd_io(ncid=ncid, varname='MONTHLY_SAI', flag='read', data=msai, dim1name=grlnd, & nt=months(k), readvar=readvar) if (.not. readvar) call endrun( trim(subname)//' ERROR: MONTHLY_SAI NOT on fveg file' ) call ncd_io(ncid=ncid, varname='MONTHLY_HEIGHT_TOP', flag='read', data=mhgtt, dim1name=grlnd, & nt=months(k), readvar=readvar) if (.not. readvar) call endrun( trim(subname)//' ERROR: MONTHLY_HEIGHT_TOP NOT on fveg file' ) call ncd_io(ncid=ncid, varname='MONTHLY_HEIGHT_BOT', flag='read', data=mhgtb, dim1name=grlnd, & nt=months(k), readvar=readvar) if (.not. readvar) call endrun( trim(subname)//' ERROR: MONTHLY_HEIGHT_TOP NOT on fveg file' ) ! Store data directly in clmtype structure ! only vegetated pfts have nonzero values ! Assign lai/sai/hgtt/hgtb to the top [maxpatch_pft] pfts ! as determined in subroutine surfrd do p = begp,endp g = clm3%g%l%c%p%gridcell(p) ivt = clm3%g%l%c%p%itype(p) if (ivt /= noveg) then ! vegetated pft do l = 0, numpft if (l == ivt) then mlai2t(p,k) = mlai(g,l) msai2t(p,k) = msai(g,l) mhvt2t(p,k) = mhgtt(g,l) mhvb2t(p,k) = mhgtb(g,l) end if end do else ! non-vegetated pft mlai2t(p,k) = 0._r8 msai2t(p,k) = 0._r8 mhvt2t(p,k) = 0._r8 mhvb2t(p,k) = 0._r8 end if end do ! end of loop over pfts end do ! end of loop over months call ncd_pio_closefile(ncid) if (masterproc) then k = 2 write(iulog,*) 'Successfully read monthly vegetation data for' write(iulog,*) 'month ', months(k) write(iulog,*) end if deallocate(mlai, msai, mhgtt, mhgtb) mlaidiff => clm3%g%l%c%p%pps%mlaidiff do p = begp,endp mlaidiff(p)=mlai2t(p,1)-mlai2t(p,2) enddo end subroutine readMonthlyVegetation end module STATICEcosysDynMod