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