#include <misc.h> #include <preproc.h> module CNDVMod 1,4 #if (defined CNDV) !----------------------------------------------------------------------- !BOP ! ! !MODULE: CNDVMod ! ! !DESCRIPTION: ! Module containing routines to drive the annual dynamic vegetation ! that works with CN, reset related variables, ! and initialize/reset time invariant variables ! ! !USES: use shr_kind_mod , only : r8 => shr_kind_r8 use clm_varpar , only : maxpatch_pft, lsmlon, lsmlat, nlevsoi use abortutils , only : endrun use CNVegStructUpdateMod, only : CNVegStructUpdate ! ! !PUBLIC TYPES: implicit none private save ! ! !PUBLIC MEMBER FUNCTIONS: public dv ! Drives the annual dynamic vegetation that ! works with CN public histCNDV ! Output CNDV history file ! ! !REVISION HISTORY: ! Module modified by Sam Levis from similar module DGVMMod ! created by Mariana Vertenstein ! !EOP !----------------------------------------------------------------------- contains !----------------------------------------------------------------------- !BOP ! ! !IROUTINE: dv ! ! !INTERFACE: subroutine dv(lbg, ubg, lbp, ubp, num_natvegp, filter_natvegp, kyr) 1,6 ! ! !DESCRIPTION: ! Drives the annual dynamic vegetation that works with CN ! ! !USES: use clmtype use CNDVLightMod , only : Light use CNDVEstablishmentMod, only : Establishment ! ! !ARGUMENTS: implicit none integer, intent(in) :: lbg, ubg ! gridcell bounds integer, intent(in) :: lbp, ubp ! pft bounds integer, intent(inout) :: num_natvegp ! number of naturally-vegetated ! pfts in filter integer, intent(inout) :: filter_natvegp(ubp-lbp+1) ! filter for ! naturally-vegetated pfts integer, intent(in) :: kyr ! used in routine climate20 below ! ! !CALLED FROM: ! ! !REVISION HISTORY: ! Author: Sam Levis ! ! !LOCAL VARIABLES: ! ! local pointers to implicit in arguments ! integer , pointer :: mxy(:) ! pft m index (for laixy(i,j,m),etc.) integer , pointer :: pgridcell(:) ! gridcell of corresponding pft real(r8), pointer :: fpcgrid(:) ! foliar projective cover on gridcell (fraction) real(r8), pointer :: agdd(:) ! accumulated growing degree days above 5 real(r8), pointer :: t_mo_min(:) ! annual min of t_mo (Kelvin) ! ! local pointers to implicit inout arguments ! real(r8), pointer :: tmomin20(:) ! 20-yr running mean of tmomin real(r8), pointer :: agdd20(:) ! 20-yr running mean of agdd ! !EOP ! ! !LOCAL VARIABLES: integer :: g,p ! indices !----------------------------------------------------------------------- ! Assign local pointers to derived type members (gridcell-level) agdd20 => clm3%g%gdgvs%agdd20 tmomin20 => clm3%g%gdgvs%tmomin20 ! Assign local pointers to derived type members (pft-level) mxy => clm3%g%l%c%p%mxy pgridcell => clm3%g%l%c%p%gridcell fpcgrid => clm3%g%l%c%p%pdgvs%fpcgrid t_mo_min => clm3%g%l%c%p%pdgvs%t_mo_min agdd => clm3%g%l%c%p%pdgvs%agdd ! ************************************************************************* ! S. Levis version of LPJ's routine climate20: 'Returns' tmomin20 & agdd20 ! for use in routine bioclim, which I have placed in routine Establishment ! Instead of 20-yr running mean of coldest monthly temperature, ! use 20-yr running mean of minimum 10-day running mean ! ************************************************************************* do p = lbp,ubp g = pgridcell(p) if (kyr == 2) then ! slevis: add ".and. start_type==arb_ic" here? tmomin20(g) = t_mo_min(p) ! NO, b/c want to be able to start dgvm agdd20(g) = agdd(p) ! w/ clmi file from non-dgvm simulation end if tmomin20(g) = (19._r8 * tmomin20(g) + t_mo_min(p)) / 20._r8 agdd20(g) = (19._r8 * agdd20(g) + agdd(p) ) / 20._r8 end do ! Rebuild filter of present natually-vegetated pfts after Kill() call BuildNatVegFilter(lbp, ubp, num_natvegp, filter_natvegp) ! Returns fpcgrid and nind call Light(lbg, ubg, lbp, ubp, num_natvegp, filter_natvegp) ! Returns updated fpcgrid, nind, crownarea, and present. Due to updated ! present, we do not use the natveg filter in this subroutine. call Establishment(lbg, ubg, lbp, ubp) ! Reset dgvm variables needed in next yr (too few to keep subr. dvreset) do p = lbp,ubp clm3%g%l%c%p%pcs%leafcmax(p) = 0._r8 clm3%g%l%c%p%pdgvs%t_mo_min(p) = 1.0e+36_r8 end do end subroutine dv !----------------------------------------------------------------------- !BOP ! ! !IROUTINE: histCNDV ! ! !INTERFACE: subroutine histCNDV() 1,85 ! ! !DESCRIPTION: ! Create CNDV history file ! ! !USES: use clmtype use ncdio use decompMod , only : get_proc_bounds, get_proc_global, ldecomp use clm_varpar , only : lsmlon, lsmlat, maxpatch_pft use domainMod , only : ldomain,llatlon use clm_varctl , only : caseid, ctitle, finidat, fsurdat, fpftcon, & frivinp_rtm use clm_varcon , only : spval use clm_time_manager, only : get_ref_date, get_nstep, get_curr_date, & get_curr_time use fileutils , only : set_filename, putfil, get_filename use shr_sys_mod , only : shr_sys_getenv use spmdMod , only : masterproc use shr_const_mod , only : SHR_CONST_CDAY ! ! !ARGUMENTS: implicit none ! ! !CALLED FROM: ! ! !REVISION HISTORY: ! Author: Sam Levis ! ! !LOCAL VARIABLES: ! ! local pointers to implicit in arguments ! logical , pointer :: ifspecial(:) ! true=>landunit is not vegetated (landunit-level) integer , pointer :: pgridcell(:) ! gridcell index of corresponding pft (pft-level) integer , pointer :: plandunit(:) ! landunit index of corresponding pft (pft-level) integer , pointer :: mxy(:) ! pft m index (for laixy(i,j,m),etc.) real(r8), pointer :: fpcgrid(:) ! foliar projective cover on gridcell (fraction) real(r8), pointer :: nind(:) ! number of individuals (#/m**2) ! !EOP ! ! !LOCAL VARIABLES: character(len=256) :: dgvm_fn ! dgvm history filename integer :: ncid ! dgvm netcdf file id integer :: omode ! returned mode from netCDF call integer :: ncprec ! output precision integer :: g,p,l ! indices 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 integer :: numg,numl,numc,nump ! global glcp cells integer :: ier ! error status integer :: mdcur, mscur, mcdate ! outputs from get_curr_time integer :: yr,mon,day,mcsec ! outputs from get_curr_date integer :: hours,minutes,secs ! hours,minutes,seconds of hh:mm:ss integer :: nstep ! time step integer :: nbsec ! seconds components of a date integer :: dimid ! dimension, variable id real(r8):: time ! current time character(len=256) :: str ! temporary string character(len= 8) :: curdate ! current date character(len= 8) :: curtime ! current time character(len= 10) :: basedate ! base date (yyyymmdd) character(len= 8) :: basesec ! base seconds character(len=256) :: rem_dir ! remote (archive) directory character(len=256) :: rem_fn ! remote (archive) filename real(r8), pointer :: rbuf2dg(:,:) ! temporary integer , pointer :: ibuf2dg(:,:) ! temporary character(len=32) :: subname='histCNDV' !----------------------------------------------------------------------- ! Assign local pointers to derived type members (gridcell-level) ! NONE ! Assign local pointers to derived type members (landunit-level) ifspecial => clm3%g%l%ifspecial ! Assign local pointers to derived subtypes components (pft-level) mxy => clm3%g%l%c%p%mxy pgridcell => clm3%g%l%c%p%gridcell plandunit => clm3%g%l%c%p%landunit fpcgrid => clm3%g%l%c%p%pdgvs%fpcgrid nind => clm3%g%l%c%p%pdgvs%nind ! Determine subgrid bounds for this processor and allocate dynamic memory call get_proc_bounds(begg, endg, begl, endl, begc, endc, begp, endp) call get_proc_global(numg, numl, numc, nump) allocate(rbuf2dg(begg:endg,maxpatch_pft), ibuf2dg(begg:endg,maxpatch_pft), stat=ier) if (ier /= 0) call endrun('histCNDV: allocation error for rbuf2dg, ibuf2dg') ! Set output precision ncprec = nf_double if (masterproc) then ! ----------------------------------------------------------------------- ! Create new netCDF file. File will be in define mode ! Set fill mode to "no fill" to optimize performance ! ----------------------------------------------------------------------- dgvm_fn = set_dgvm_filename() call check_ret(nf_create(dgvm_fn, nf_clobber, ncid), subname) call check_ret(nf_set_fill(ncid, nf_nofill, omode), subname) ! ----------------------------------------------------------------------- ! Create global attributes. ! ----------------------------------------------------------------------- str = 'CF1.0' call check_ret(& nf_put_att_text (ncid, NF_GLOBAL, 'conventions', len_trim(str), trim(str)), subname) call getdatetime(curdate, curtime) str = 'created on ' // curdate // ' ' // curtime call check_ret(& nf_put_att_text(ncid, NF_GLOBAL,'history', len_trim(str), trim(str)), subname) call shr_sys_getenv('LOGNAME', str, ier) if (ier /= 0) call endrun('error: LOGNAME environment variable not defined') call check_ret(& nf_put_att_text (ncid, NF_GLOBAL, 'logname',len_trim(str), trim(str)), subname) call shr_sys_getenv('HOST', str, ier) call check_ret(& nf_put_att_text (ncid, NF_GLOBAL, 'host', len_trim(str), trim(str)), subname) str = 'Community Land Model: CLM3' call check_ret(& nf_put_att_text (ncid, NF_GLOBAL, 'source', len_trim(str), trim(str)), subname) str = '$Name$' call check_ret(& nf_put_att_text (ncid, NF_GLOBAL, 'version', len_trim(str), trim(str)), subname) str = '$Id$' call check_ret(& nf_put_att_text (ncid, NF_GLOBAL, 'revision_id', len_trim(str), trim(str)), subname) str = ctitle call check_ret(& nf_put_att_text (ncid, NF_GLOBAL, 'case_title', len_trim(str), trim(str)), subname) str = caseid call check_ret(& nf_put_att_text (ncid, NF_GLOBAL, 'case_id', len_trim(str), trim(str)), subname) str = get_filename(fsurdat) call check_ret(& nf_put_att_text(ncid, NF_GLOBAL, 'Surface_dataset', len_trim(str), trim(str)), subname) str = 'arbitrary initialization' if (finidat /= ' ') str = get_filename(finidat) call check_ret(& nf_put_att_text(ncid, NF_GLOBAL, 'Initial_conditions_dataset', len_trim(str), trim(str)), subname) str = get_filename(fpftcon) call check_ret(& nf_put_att_text(ncid, NF_GLOBAL, 'PFT_physiological_constants_dataset', len_trim(str), trim(str)), subname) if (frivinp_rtm /= ' ') then str = get_filename(frivinp_rtm) call check_ret(& nf_put_att_text(ncid, NF_GLOBAL, 'RTM_input_datset', len_trim(str), trim(str)), subname) end if ! ----------------------------------------------------------------------- ! Define dimensions. ! ----------------------------------------------------------------------- call check_ret(nf_def_dim (ncid, 'lon', lsmlon, dimid), subname) call check_ret(nf_def_dim (ncid, 'lat', lsmlat, dimid), subname) call check_ret(nf_def_dim (ncid, 'pft', maxpatch_pft, dimid), subname) call check_ret(nf_def_dim (ncid, 'time', nf_unlimited, dimid), subname) call check_ret(nf_def_dim (ncid, 'string_length', 80, dimid), subname) ! ----------------------------------------------------------------------- ! Define variables ! ----------------------------------------------------------------------- ! Define coordinate variables (including time) call ncd_defvar(ncid=ncid, varname='lon', xtype=ncprec, dim1name='lon', & long_name='coordinate longitude', units='degrees_east') call ncd_defvar(ncid=ncid, varname='lat', xtype=ncprec, dim1name='lat', & long_name='coordinate latitude', units='degrees_north') call get_curr_time(mdcur, mscur) call get_ref_date(yr, mon, day, nbsec) hours = nbsec / 3600 minutes = (nbsec - hours*3600) / 60 secs = (nbsec - hours*3600 - minutes*60) write(basedate,80) yr,mon,day 80 format(i4.4,'-',i2.2,'-',i2.2) write(basesec ,90) hours, minutes, secs 90 format(i2.2,':',i2.2,':',i2.2) str = 'days since ' // basedate // " " // basesec time = mdcur + mscur/SHR_CONST_CDAY call ncd_defvar(ncid=ncid, varname='time', xtype=nf_double, dim1name='time', & long_name='time', units=str) call ncd_defvar(ncid=ncid, varname='edgen', xtype=ncprec, & long_name='northern edge of surface grid', units='degrees_north') call ncd_defvar(ncid=ncid, varname='edgee', xtype=ncprec, & long_name='eastern edge of surface grid', units='degrees_east') call ncd_defvar(ncid=ncid, varname='edges', xtype=ncprec, & long_name='southern edge of surface grid', units='degrees_north') call ncd_defvar(ncid=ncid, varname='edgew', xtype=ncprec, & long_name='western edge of surface grid', units='degrees_east') ! Define surface grid (coordinate variables, latitude, longitude, surface type). call ncd_defvar(ncid=ncid, varname='longxy', xtype=ncprec, dim1name='lon', dim2name='lat', & long_name='longitude', units='degrees_east') call ncd_defvar(ncid=ncid, varname='latixy', xtype=ncprec, dim1name='lon', dim2name='lat', & long_name='latitude', units='degrees_north') call ncd_defvar(ncid=ncid, varname='landmask', xtype=nf_int, dim1name='lon', dim2name='lat', & long_name='land/ocean mask (0.=ocean and 1.=land)') ! Define time information call ncd_defvar(ncid=ncid, varname='mcdate', xtype=nf_int, dim1name='time',& long_name='current date (YYYYMMDD)') call ncd_defvar(ncid=ncid, varname='mcsec', xtype=nf_int, dim1name='time',& long_name='current seconds of current date', units='s') call ncd_defvar(ncid=ncid, varname='mdcur', xtype=nf_int, dim1name='time',& long_name='current day (from base day)') call ncd_defvar(ncid=ncid, varname='mscur', xtype=nf_int, dim1name='time',& long_name='current seconds of current day', units='s') call ncd_defvar(ncid=ncid, varname='nstep', xtype=nf_int, dim1name='time',& long_name='time step', units='s') ! Define time dependent variables call ncd_defvar(ncid=ncid, varname='FPCGRID', xtype=ncprec, & dim1name='lon', dim2name='lat', dim3name='pft', dim4name='time', & long_name='plant functional type cover', units='fraction of vegetated area', & missing_value=spval, fill_value=spval) call ncd_defvar(ncid=ncid, varname='NIND', xtype=ncprec, & dim1name='lon', dim2name='lat', dim3name='pft', dim4name='time', & long_name='number of individuals', units='individuals/m2 vegetated land', & missing_value=spval, fill_value=spval) call check_ret(nf_enddef(ncid), subname) end if ! End of if-masterproc block ! ----------------------------------------------------------------------- ! Write variables ! ----------------------------------------------------------------------- call ncd_ioglobal(varname='edgen', data=llatlon%edges(1), ncid=ncid, flag='write') call ncd_ioglobal(varname='edgee', data=llatlon%edges(2), ncid=ncid, flag='write') call ncd_ioglobal(varname='edges', data=llatlon%edges(3), ncid=ncid, flag='write') call ncd_ioglobal(varname='edgew', data=llatlon%edges(4), ncid=ncid, flag='write') ! Write surface grid (coordinate variables, latitude, longitude, surface type). if (masterproc) then call ncd_ioglobal(varname='lon', data=llatlon%lonc, ncid=ncid, flag='write') call ncd_ioglobal(varname='lat', data=llatlon%latc, ncid=ncid, flag='write') end if call ncd_iolocal(varname='longxy' , data=ldomain%lonc, ncid=ncid, & flag='write', dim1name=grlnd) call ncd_iolocal(varname='latixy' , data=ldomain%latc, ncid=ncid, & flag='write', dim1name=grlnd) call ncd_iolocal(varname='landmask', data=ldomain%mask, ncid=ncid, & flag='write', dim1name=grlnd) ! Write current date, current seconds, current day, current nstep call get_curr_date(yr, mon, day, mcsec) mcdate = yr*10000 + mon*100 + day nstep = get_nstep() call ncd_ioglobal(varname='mcdate', data=mcdate, nt=1, ncid=ncid, flag='write') call ncd_ioglobal(varname='mcsec' , data=mcsec , nt=1, ncid=ncid, flag='write') call ncd_ioglobal(varname='mdcur' , data=mdcur , nt=1, ncid=ncid, flag='write') call ncd_ioglobal(varname='mscur' , data=mcsec , nt=1, ncid=ncid, flag='write') call ncd_ioglobal(varname='nstep' , data=nstep , nt=1, ncid=ncid, flag='write') call ncd_ioglobal(varname='time' , data=time , nt=1, ncid=ncid, flag='write') ! Write time dependent variables to CNDV history file ! The if .not. ifspecial statment below guarantees that the m index will ! always lie between 1 and maxpatch_pft rbuf2dg(:,:) = 0._r8 do p = begp,endp g = pgridcell(p) l = plandunit(p) if (.not. ifspecial(l)) rbuf2dg(g,mxy(p)) = fpcgrid(p)*100._r8 end do call ncd_iolocal(varname='FPCGRID', dim1name=grlnd, dim2name='pft', data=rbuf2dg, & nt=1, ncid=ncid, flag='write') rbuf2dg(:,:) = 0._r8 do p = begp,endp g = pgridcell(p) l = plandunit(p) if (.not. ifspecial(l)) rbuf2dg(g,mxy(p)) = nind(p) end do call ncd_iolocal(varname='NIND',dim1name=grlnd, dim2name='pft', data=rbuf2dg, & nt=1, ncid=ncid, flag='write') ! Deallocate dynamic memory deallocate(rbuf2dg, ibuf2dg) !------------------------------------------------------------------ ! Close and archive netcdf CNDV history file !------------------------------------------------------------------ if (masterproc) then call check_ret(nf_close(ncid), subname) write(6,*)'(histCNDV): Finished writing CNDV history dataset ',& trim(dgvm_fn), 'at nstep = ',get_nstep() end if end subroutine histCNDV !----------------------------------------------------------------------- !BOP ! ! !IROUTINE: set_dgvm_filename ! ! !INTERFACE: character(len=256) function set_dgvm_filename () 1,3 ! ! !DESCRIPTION: ! Determine initial dataset filenames ! ! !USES: use clm_varctl , only : caseid use clm_time_manager, only : get_curr_date ! ! !ARGUMENTS: implicit none ! ! !CALLED FROM: ! ! !REVISION HISTORY: ! Author: Mariana Vertenstein ! !EOP ! ! !LOCAL VARIABLES: character(len=256) :: cdate !date char string integer :: day !day (1 -> 31) integer :: mon !month (1 -> 12) integer :: yr !year (0 -> ...) integer :: sec !seconds into current day !----------------------------------------------------------------------- call get_curr_date (yr, mon, day, sec) write(cdate,'(i4.4,"-",i2.2,"-",i2.2,"-",i5.5)') yr,mon,day,sec set_dgvm_filename = "./"//trim(caseid)//".clm2.hv."//trim(cdate)//".nc" end function set_dgvm_filename !----------------------------------------------------------------------- !BOP ! ! !IROUTINE: BuildNatVegFilter ! ! !INTERFACE: subroutine BuildNatVegFilter(lbp, ubp, num_natvegp, filter_natvegp) 1,1 ! ! !DESCRIPTION: ! Reconstruct a filter of naturally-vegetated PFTs for use in DGVM ! ! !USES: use clmtype ! ! !ARGUMENTS: implicit none integer, intent(in) :: lbp, ubp ! pft bounds integer, intent(out) :: num_natvegp ! number of pfts in naturally-vegetated filter integer, intent(out) :: filter_natvegp(ubp-lbp+1) ! pft filter for naturally-vegetated points ! ! !CALLED FROM: ! subroutine lpj in this module ! ! !REVISION HISTORY: ! Author: Forrest Hoffman ! ! !LOCAL VARIABLES: ! local pointers to implicit in arguments logical , pointer :: present(:) ! whether this pft present in patch !EOP ! ! !LOCAL VARIABLES: integer :: p !----------------------------------------------------------------------- ! Assign local pointers to derived type members (pft-level) present => clm3%g%l%c%p%pdgvs%present num_natvegp = 0 do p = lbp,ubp if (present(p)) then num_natvegp = num_natvegp + 1 filter_natvegp(num_natvegp) = p end if end do end subroutine BuildNatVegFilter #endif end module CNDVMod