module ndepFileMod 2,7 #ifdef CN !----------------------------------------------------------------------- !BOP ! ! !MODULE: ndepFileMod ! ! !DESCRIPTION: ! Contains methods for reading in nitrogen deposition data file ! Also includes functions for dynamic ndep file handling and ! interpolation. ! ! !USES use abortutils, only : endrun use ncdio use clmtype use spmdMod use clm_varpar, only: lsmlat, lsmlon use clm_varctl, only: iulog use shr_kind_mod, only: r8 => shr_kind_r8 ! ! !PUBLIC TYPES: implicit none save ! ! !PUBLIC MEMBER FUNCTIONS: public :: ndeprd ! Read nitrogen deposition dataset public :: ndepdyn_init ! position datasets for dynamic ndep public :: ndepdyn_interp ! interpolates between two years of ndep file data ! ! !REVISION HISTORY: ! Created by Peter Thornton, 1 June 2004 ! 2/5/05, PET: Added ndepdyn_init and ndepdyn_interp ! !EOP ! ! ! PRIVATE TYPES real(r8), parameter :: days_per_year = 365._r8 integer , pointer :: yearsndep(:) real(r8), pointer :: ndepdyn1(:) real(r8), pointer :: ndepdyn2(:) real(r8), pointer :: ndepdyn(:) integer :: nt1 integer :: nt2 integer :: ncid !----------------------------------------------------------------------- contains !----------------------------------------------------------------------- !BOP ! ! !IROUTINE: ndeprd ! ! !INTERFACE: subroutine ndeprd(fndepdat) 2,15 ! ! !DESCRIPTION: ! Read the nitrogen deposition dataset. ! ! !USES: use shr_kind_mod, only: r8 => shr_kind_r8 use clm_varctl , only : single_column use fileutils , only : getfil use decompMod , only : get_proc_bounds use clm_atmlnd , only : clm_a2l ! ! !ARGUMENTS: implicit none include 'netcdf.inc' character(len=*), intent(in), optional :: fndepdat ! ! !CALLED FROM: ! subroutine initialize in module initializeMod ! ! !REVISION HISTORY: ! Created by Peter Thornton, 1 June 2004 ! ! ! !LOCAL VARIABLES: !EOP character(len=256) :: locfn ! local file name character(len=256) :: units = ' ' ! units of ndep_year variable integer :: ncid,dimid,varid ! netCDF id's integer :: g,begg,endg ! start/stop gridcells integer :: ier, ret ! error status real(r8), pointer :: ndep(:) ! annual nitrogen deposition rate (gN/m2/yr) character(len=32) :: subname = 'ndeprd' ! subroutine name !----------------------------------------------------------------------- ! Initialize data to zero - no nitrogen deposition call get_proc_bounds(begg,endg) allocate(ndep(begg:endg)) ndep(:) = 0._r8 ! Obtain netcdf file and read surface data if appropriate if (present(fndepdat)) then if (masterproc) then write(iulog,*) 'Attempting to read nitrogen deposition data .....' call getfil (fndepdat, locfn, 0) call check_ret(nf_open(locfn, 0, ncid), subname) if ( .not. single_column )then call check_dim(ncid, 'lon' , lsmlon) call check_dim(ncid, 'lat' , lsmlat) else lsmlon = 1 lsmlat = 1 end if ! Check that units are correct on NDEP_year variable call check_ret(nf_inq_varid(ncid, 'NDEP_year', varid), subname) call check_ret(nf_get_att_text(ncid, varid, 'units', units), subname) if ( trim(units) .ne. "g(N)/m2/yr" .and. trim(units) .ne. "gN/m2/yr" )then call endrun( 'ERROR: units are NOT what is expected on ndepdat file = '//trim(units) ) end if endif call ncd_iolocal(ncid,'NDEP_year','read', ndep, grlnd, status=ret) if (ret /= 0) call endrun( trim(subname)//' ERROR: NDEP_year NOT on ndepdat file' ) write(iulog,*) 'Successfully read nitrogen deposition data' write(iulog,*) end if do g = begg,endg clm_a2l%forc_ndep(g) = ndep(g)/(86400._r8 * 365._r8) end do end subroutine ndeprd !----------------------------------------------------------------------- !BOP ! ! !ROUTINE: ndepdyn_init ! ! !INTERFACE: subroutine ndepdyn_init() 1,21 ! ! !DESCRIPTION: ! Initialize dynamic nitrogen deposition dataset ! ! !USES: use shr_kind_mod, only : r8 => shr_kind_r8 use decompMod , only : get_proc_bounds use clm_time_manager, only : get_curr_date use clm_varctl , only : fndepdyn use fileutils , only : getfil ! ! !ARGUMENTS: implicit none include 'netcdf.inc' ! ! ! !LOCAL VARIABLES: !EOP integer :: i,j,m,n,g ! indices integer :: ntimes ! number of input time samples real(r8) :: sumpct ! sum for error check integer :: varid ! netcdf ids integer :: year ! year (0, ...) for nstep+1 integer :: mon ! month (1, ..., 12) for nstep+1 integer :: day ! day of month (1, ..., 31) for nstep+1 integer :: sec ! seconds into current date for nstep+1 integer :: ier ! error status logical :: found ! true => input dataset bounding dates found integer :: begg,endg ! local beg/end indices type(gridcell_type), pointer :: gptr ! pointer to gridcell derived subtype character(len=256) :: locfn ! local file name character(len=256) :: units = ' ' ! units of ndep_year variable character(len= 32) :: subname='ndepdyn_init' ! subroutine name !----------------------------------------------------------------------- ! Set pointers into derived type gptr => clm3%g ! Get relevant sizes call get_proc_bounds(begg,endg) allocate(ndepdyn1(begg:endg), ndepdyn2(begg:endg), ndepdyn(begg:endg), stat=ier) if (ier /= 0) then write(iulog,*)'ndepdyn_init allocation error for ndepdyn1, ndepdyn2, ndepdyn' call endrun() end if if (masterproc) then ! Obtain file write(iulog,*) 'Attempting to read dynamic ndep data .....' call getfil (fndepdyn, locfn, 0) call check_ret(nf_open(locfn, 0, ncid), subname) ! Obtain ndep years from dynamic ndep file call check_ret(nf_inq_dimid(ncid, 'time', varid), subname) call check_ret(nf_inq_dimlen(ncid, varid, ntimes), subname) allocate (yearsndep(ntimes), stat=ier) if (ier /= 0) then write(iulog,*)'ndepdyn_init allocation error for yearsndep'; call endrun() end if call check_ret(nf_inq_varid(ncid, 'YEAR', varid), subname) call check_ret(nf_get_var_int(ncid, varid, yearsndep), subname) ! Determine if current date spans the years ! If current year is less than first dynamic PFT timeseries year, ! then use the first year from dynamic pft file for both nt1 and nt2, ! forcing constant weights until the model year enters the dynamic ! pft dataset timeseries range. ! If current year is equal to or greater than the last dynamic pft ! timeseries year, then use the last year for both nt1 and nt2, ! forcing constant weights for the remainder of the simulation. ! This mechanism permits the introduction of a dynamic pft period in the middle ! of a simulation, with constant weights before and after the dynamic period. call get_curr_date(year, mon, day, sec) if (year < yearsndep(1)) then nt1 = 1 nt2 = 1 else if (year >= yearsndep(ntimes)) then nt1 = ntimes nt2 = ntimes else found = .false. do n = 1,ntimes-1 if (year == yearsndep(n)) then nt1 = n nt2 = nt1 + 1 found = .true. end if end do if (.not. found) then write(iulog,*)'ndepdyn_init error: model year not found in ndepdyn timeseries' write(iulog,*)'model year = ',year call endrun() end if end if ! ! Check that units are correct on NDEP_year variable ! call check_ret(nf_inq_varid(ncid, 'NDEP_year', varid), subname) call check_ret(nf_get_att_text(ncid, varid, 'units', units), subname) if ( trim(units) .ne. "g(N)/m2/yr" )then call endrun( 'ERROR: units are NOT what is expected on fndepdyn file' ) end if end if ! end of if-masterproc block call mpi_bcast (nt1 , 1, MPI_INTEGER, 0, mpicom, ier) call mpi_bcast (nt2 , 1, MPI_INTEGER, 0, mpicom, ier) call mpi_bcast (ntimes, 1, MPI_INTEGER, 0, mpicom, ier) if (.not. masterproc) then allocate(yearsndep(ntimes)) end if call mpi_bcast (yearsndep, size(yearsndep), MPI_INTEGER, 0, mpicom, ier) ! Get ndep time samples bracketing the current time call ndepdyn_getdata(nt1, ndepdyn1) call ndepdyn_getdata(nt2, ndepdyn2) end subroutine ndepdyn_init !----------------------------------------------------------------------- !BOP ! ! !ROUTINE: ndepdyn_interp ! ! !INTERFACE: subroutine ndepdyn_interp() 2,8 ! ! !DESCRIPTION: ! Time interpolate dynamic ndep data to get ndep for model time ! ! !USES: use shr_kind_mod, only : r8 => shr_kind_r8 use clm_time_manager, only : get_curr_date, get_curr_calday use decompMod , only : get_proc_bounds use clm_atmlnd , only : clm_a2l ! ! !ARGUMENTS: implicit none ! ! ! !LOCAL VARIABLES: !EOP integer :: i,j,m,p,l,g ! indices integer :: year ! year (0, ...) for nstep+1 integer :: mon ! month (1, ..., 12) for nstep+1 integer :: day ! day of month (1, ..., 31) for nstep+1 integer :: sec ! seconds into current date for nstep+1 real(r8) :: cday ! current calendar day (1.0 = 0Z on Jan 1) integer :: begg, endg ! per-proc gridcell ending gridcell indices integer :: ier ! error status real(r8) :: wt1 ! time interpolation weights real(r8), allocatable :: ndep(:,:) ! input ndep type(gridcell_type), pointer :: gptr ! pointer to gridcell derived subtype character(len=32) :: subname='ndepdyn_interp' ! subroutine name !----------------------------------------------------------------------- ! Set pointers into derived type gptr => clm3%g ! Get relevant sizes call get_proc_bounds(begg, endg) ! Interpolat ndep to current time step - output in ndep ! If necessary, obtain new time sample ! Get current date call get_curr_date(year, mon, day, sec) ! Obtain new time sample if necessary. ! The first condition is the regular crossing of a year boundary ! when within the dynndep timeseries range. The second condition is ! the case of the first entry into the dynndep timeseries range from ! an earlier period of constant weights. if (year > yearsndep(nt1) .or. (nt1 == 1 .and. nt2 == 1 .and. year == yearsndep(1))) then if (year >= yearsndep(size(yearsndep))) then nt1 = size(yearsndep) nt2 = size(yearsndep) else nt1 = nt2 nt2 = nt1 + 1 end if if (nt2 > size(yearsndep)) then write(iulog,*)subname,' error - current year is past input data boundary' end if do g = begg,endg ndepdyn1(g) = ndepdyn2(g) end do call ndepdyn_getdata(nt2, ndepdyn2) end if ! end of need new data if-block ! Interpolate ndep to current time cday = get_curr_calday() wt1 = ((days_per_year + 1._r8) - cday)/days_per_year ! assign interpolated flux field to forc_ndep ! convert units from gN/yr -> gN/s do g = begg,endg ! --- recoded for roundoff error, tcraig 3/07 from k.lindsay ! clm_a2l%forc_ndep(g) = (ndepdyn1(g)*wt1 + ndepdyn2(g)* wt2)/(86400._r8 * 365._r8) clm_a2l%forc_ndep(g) = (ndepdyn2(g) + wt1*(ndepdyn1(g)-ndepdyn2(g)))/(86400._r8 * 365._r8) end do end subroutine ndepdyn_interp !----------------------------------------------------------------------- !BOP ! ! !ROUTINE: ndepdyn_getdata ! ! !INTERFACE: subroutine ndepdyn_getdata(ntime, ndep) 3,4 ! ! !DESCRIPTION: ! Obtain dynamic ndep ! ! !USES: use clmtype , only : grlnd use shr_kind_mod, only : r8 => shr_kind_r8 ! ! !ARGUMENTS: implicit none include 'netcdf.inc' integer , intent(in) :: ntime real(r8), pointer :: ndep(:) ! ! ! !LOCAL VARIABLES: !EOP integer :: beg3d(3), len3d(3) ! input sizes integer :: ret ! error status character(len=32) :: subname='ndepdyn_getdata' ! subroutine name !----------------------------------------------------------------------- beg3d(1) = 1 ; len3d(1) = lsmlon beg3d(2) = 1 ; len3d(2) = lsmlat beg3d(3) = ntime ; len3d(3) = 1 call ncd_iolocal(ncid,'NDEP_year','read',ndep,grlnd,beg3d,len3d,status=ret) if (ret /= 0) call endrun( trim(subname)//' ERROR: NDEP_year NOT on ndepdyn file' ) end subroutine ndepdyn_getdata #endif end module ndepFileMod