module co2_data_flux 1,9
!------------------------------------------------------------------------------------------------
! for data reading and interpolation
!------------------------------------------------------------------------------------------------
use shr_kind_mod
, only : r8 => shr_kind_r8
use spmd_utils
, only : masterproc
use ppgrid
, only : begchunk, endchunk, pcols
use phys_grid
, only : scatter_field_to_chunk, get_ncols_p
use error_messages
, only : alloc_err, handle_ncerr, handle_err
use abortutils
, only : endrun
use netcdf
use error_messages
, only : handle_ncerr
use cam_logfile
, only : iulog
#if ( defined SPMD )
use mpishorthand
, only: mpicom, mpiint, mpir8
#endif
implicit none
! public data
! public type
public read_interp
! public interface
public read_data_flux
public interp_time_flux
! private data
private
! integer, parameter :: totsz=2000 ! number greater than data time sample
real(r8), parameter :: daysperyear = 365.0_r8 ! Number of days in a year
integer :: lonsiz ! size of longitude dimension, dataset is 2d(lat,lon), in CAM grid
integer :: latsiz ! size of latitude dimension
!--------------------------------------------------------------------------------------------------
TYPE :: read_interp
real(r8), pointer, dimension(:,:) :: co2flx
! Interpolated output (pcols,begchunk:endchunk)
real(r8), pointer, dimension(:,:,:) :: co2bdy
! bracketing data (pcols,begchunk:endchunk,2)
real(r8) :: cdayfm ! Calendar day for prv. month read in
real(r8) :: cdayfp ! Calendar day for nxt. month read in
integer :: nm_f ! Array indices for prv. month data
integer :: np_f ! Array indices for nxt. month data
integer :: np1_f ! current forward time index of dataset
integer :: timesz ! size of time dimension on dataset
integer, pointer :: date_f(:) ! Date on dataset (YYYYMMDD)
integer, pointer :: sec_f(:) ! seconds of date on dataset (0-86399)
character(len=256) :: locfn ! dataset name
integer :: ncid_f ! netcdf id for dataset
integer :: fluxid ! netcdf id for dataset flux
real(r8), pointer :: xvar(:,:,:) ! work space for dataset
END TYPE read_interp
!-------------------------------------------------------------------------------------------------
contains
!===============================================================================
subroutine read_data_flux (input_file, xin) 2,45
!-------------------------------------------------------------------------------
! Do initial read of time-varying 2d(lat,lon NetCDF dataset,
! reading two data bracketing current timestep
!-------------------------------------------------------------------------------
use time_manager
, only : get_curr_date, get_curr_calday, &
is_perpetual, get_perp_date, get_step_size, is_first_step
use ioFileMod
, only : getfil
implicit none
!---------------------------Common blocks-------------------------------
! Dummy arguments
character(len=*), intent(in) :: input_file
TYPE(read_interp), intent(inout) :: xin
integer lonid ! netcdf id for longitude variable
integer latid ! netcdf id for latitude variable
integer timeid ! netcdf id for time variable
integer dateid ! netcdf id for date variable
integer secid ! netcdf id for seconds variable
integer londimid ! netcdf id for longitude variable
integer latdimid ! netcdf id for latitude variable
integer dtime ! timestep size [seconds]
integer cnt3(3) ! array of counts for each dimension
integer strt3(3) ! array of starting indices
integer n ! indices
integer j ! latitude index
integer istat ! error return
integer :: yr, mon, day ! components of a date
integer :: ncdate ! current date in integer format [yyyymmdd]
integer :: ncsec ! current time of day [seconds]
real(r8) calday ! calendar day (includes yr if no cycling)
real(r8) caldayloc ! calendar day (includes yr if no cycling)
xin%nm_f = 1
xin%np_f = 2
! Allocate space for data.
allocate( xin%co2flx(pcols,begchunk:endchunk), stat=istat )
call alloc_err
( istat, 'CO2FLUX_READ', 'co2flx', &
pcols*(endchunk-begchunk+1) )
allocate( xin%co2bdy(pcols,begchunk:endchunk,2), stat=istat )
call alloc_err
( istat, 'CO2FLUX_READ', 'co2bdy', &
pcols*(endchunk-begchunk+1)*2 )
! SPMD: Master does all the work.
if (masterproc) then
!
! Use year information only if not cycling sst dataset
!
if (is_first_step
()) then
dtime = get_step_size
()
dtime = -dtime
calday = get_curr_calday
(offset=dtime)
else
calday = get_curr_calday
()
endif
if ( is_perpetual
() ) then
call get_perp_date
(yr, mon, day, ncsec)
else
if (is_first_step
()) then
call get_curr_date
(yr, mon, day, ncsec,offset=dtime)
else
call get_curr_date
(yr, mon, day, ncsec)
endif
end if
ncdate = yr*10000 + mon*100 + day
caldayloc = calday + yr*daysperyear
! Open NetCDF File
call getfil
(input_file, xin%locfn)
call handle_ncerr
( nf90_open(xin%locfn, 0, xin%ncid_f),&
'co2_data_flux.F90:154')
write(iulog,*)'CO2FLUX_READ: NCOPN returns id ',xin%ncid_f,' for file ',trim(xin%locfn)
! Get and check dimension info
call handle_ncerr
( nf90_inq_dimid( xin%ncid_f, 'lon', londimid ),&
'co2_data_flux.F90:160')
call handle_ncerr
( nf90_inq_dimid( xin%ncid_f, 'lat', latdimid ),&
'co2_data_flux.F90:162')
call handle_ncerr
( nf90_inq_dimid( xin%ncid_f, 'time', timeid ),&
'co2_data_flux.F90:164')
call handle_ncerr
( nf90_inquire_dimension( xin%ncid_f, londimid, len=lonsiz ),&
'co2_data_flux.F90:167')
call handle_ncerr
( nf90_inquire_dimension( xin%ncid_f, latdimid, len=latsiz ),&
'co2_data_flux.F90:169')
call handle_ncerr
( nf90_inquire_dimension( xin%ncid_f, timeid, len=xin%timesz ),&
'co2_data_flux.F90:171')
allocate(xin%date_f(xin%timesz), xin%sec_f(xin%timesz))
! Get data id
call handle_ncerr
( nf90_inq_varid( xin%ncid_f, 'date', dateid ),&
'co2_data_flux.F90:192')
call handle_ncerr
( nf90_inq_varid( xin%ncid_f, 'datesec', secid ),&
'co2_data_flux.F90:194')
call handle_ncerr
( nf90_inq_varid( xin%ncid_f, 'CO2_flux', xin%fluxid ),&
'co2_data_flux.F90:196')
! Retrieve entire date and sec variables.
call handle_ncerr
( nf90_get_var ( xin%ncid_f, dateid, xin%date_f ),&
'co2_data_flux.F90:201')
call handle_ncerr
( nf90_get_var ( xin%ncid_f, secid, xin%sec_f ),&
'co2_data_flux.F90:203')
! initialize
strt3(1) = 1
strt3(2) = 1
strt3(3) = 1
cnt3(1) = lonsiz
cnt3(2) = latsiz
cnt3(3) = 1
endif
#ifdef SPMD
call mpibcast
( cnt3, 2, mpiint, 0, mpicom )
#endif
allocate(xin%xvar(cnt3(1),cnt3(2),2))
if (masterproc) then
! Normal interpolation between consecutive time slices.
do n=1,xin%timesz-1
xin%np1_f = n + 1
call bnddyi
(xin%date_f(n ), xin%sec_f(n ), xin%cdayfm)
call bnddyi
(xin%date_f(xin%np1_f), xin%sec_f(xin%np1_f), xin%cdayfp)
yr = xin%date_f(n)/10000
xin%cdayfm = xin%cdayfm + yr*daysperyear
yr = xin%date_f(xin%np1_f)/10000
xin%cdayfp = xin%cdayfp + yr*daysperyear
! read 2 time sample bracketing ncdate
if ( caldayloc > xin%cdayfm .and. caldayloc <= xin%cdayfp ) then
strt3(3) = n
call handle_ncerr
( nf90_get_var ( xin%ncid_f, xin%fluxid, xin%xvar(:,:,xin%nm_f), strt3, cnt3), &
'co2_data_flux.F90:235')
strt3(3) = xin%np1_f
call handle_ncerr
( nf90_get_var ( xin%ncid_f, xin%fluxid, xin%xvar(:,:,xin%np_f), strt3, cnt3),&
'co2_data_flux.F90:238')
goto 10
end if
end do
write(iulog,*)'CO2FLUX_READ: Failed to find dates bracketing ncdate, ncsec=', ncdate, ncsec
call endrun
10 continue
write(iulog,*)'CO2FLUX_READ: Read ', trim(xin%locfn), ' for dates ', xin%date_f(n), xin%sec_f(n), &
' and ', xin%date_f(xin%np1_f), xin%sec_f(xin%np1_f)
#if (defined SPMD )
call mpibcast
( xin%timesz, 1, mpiint, 0, mpicom )
call mpibcast
( xin%date_f, xin%timesz, mpiint, 0, mpicom )
call mpibcast
( xin%sec_f, xin%timesz, mpiint, 0, mpicom )
call mpibcast
( xin%cdayfm, 1, mpir8 , 0, mpicom )
call mpibcast
( xin%cdayfp, 1, mpir8, 0, mpicom )
call mpibcast
( xin%np1_f, 1, mpiint, 0, mpicom )
else
call mpibcast
( xin%timesz, 1, mpiint, 0, mpicom )
allocate(xin%date_f(xin%timesz), xin%sec_f(xin%timesz))
call mpibcast
( xin%date_f, xin%timesz, mpiint, 0, mpicom )
call mpibcast
( xin%sec_f, xin%timesz, mpiint, 0, mpicom )
call mpibcast
( xin%cdayfm, 1, mpir8 , 0, mpicom )
call mpibcast
( xin%cdayfp, 1, mpir8, 0, mpicom )
call mpibcast
( xin%np1_f, 1, mpiint, 0, mpicom )
#endif
end if
call scatter_field_to_chunk
( 1,1,2,cnt3(1), xin%xvar, xin%co2bdy )
return
end subroutine read_data_flux
!===============================================================================
subroutine interp_time_flux (xin, prev_timestep) 4,17
!-----------------------------------------------------------------------
! Time interpolate data to current time.
! Reading in new monthly data if necessary.
!
!-----------------------------------------------------------------------
use time_manager
, only : get_curr_date, get_curr_calday, &
is_perpetual, get_perp_date, get_step_size, is_first_step
use interpolate_data
, only : get_timeinterp_factors
logical, intent(in), optional :: prev_timestep ! If using previous timestep, set to true
TYPE(read_interp), intent(inout) :: xin
!---------------------------Local variables-----------------------------
integer dtime ! timestep size [seconds]
integer cnt3(3) ! array of counts for each dimension
integer strt3(3) ! array of starting indices
integer i,j,lchnk ! indices
integer ncol ! number of columns in current chunk
integer ntmp ! temporary
real(r8) fact1, fact2 ! time interpolation factors
integer :: yr, mon, day! components of a date
integer :: ncdate ! current date in integer format [yyyymmdd]
integer :: ncsec ! current time of day [seconds]
real(r8) :: calday ! current calendar day
real(r8) caldayloc ! calendar day (includes yr if no cycling)
real(r8) deltat ! time (days) between interpolating data
logical :: previous
logical :: co2cyc=.false.
!-----------------------------------------------------------------------
! SPMD: Master does all the work. Sends needed info to slaves
! Use year information only if a multiyear dataset
if ( .not. present(prev_timestep) ) then
previous = .false.
else
previous = prev_timestep
end if
if (previous .and. is_first_step()) then
dtime = get_step_size
()
dtime = -dtime
calday = get_curr_calday
(offset=dtime)
else
calday = get_curr_calday
()
endif
if ( is_perpetual
() ) then
call get_perp_date
(yr, mon, day, ncsec)
else
if (previous .and. is_first_step()) then
call get_curr_date
(yr, mon, day, ncsec,offset=dtime)
else
call get_curr_date
(yr, mon, day, ncsec)
endif
end if
ncdate = yr*10000 + mon*100 + day
caldayloc = calday + yr*daysperyear
if (masterproc) then
strt3(1) = 1
strt3(2) = 1
strt3(3) = 1
cnt3(1) = lonsiz
cnt3(2) = latsiz
cnt3(3) = 1
endif
#ifdef SPMD
call mpibcast
(cnt3, 2, mpiint, 0, mpicom)
#endif
! If model time is past current forward data timeslice, read in the next
! timeslice for time interpolation.
if ( caldayloc > xin%cdayfp .and. .not. (xin%np1_f==1 .and. caldayloc > xin%cdayfm) ) then
xin%np1_f = xin%np1_f + 1
if ( xin%np1_f > xin%timesz ) then
call endrun
('CO2FLUX_INTERP: Attempt to read past end of dataset')
end if
xin%cdayfm = xin%cdayfp
call bnddyi
( xin%date_f(xin%np1_f), xin%sec_f(xin%np1_f), xin%cdayfp )
yr = xin%date_f(xin%np1_f)/10000
xin%cdayfp = xin%cdayfp + yr*daysperyear
if ( .not. (xin%np1_f == 1 .or. caldayloc <= xin%cdayfp) ) then
if (masterproc) then
write(iulog,*)'CO2FLUX_INTERP: Input data for date', xin%date_f(xin%np1_f), ' sec ', xin%sec_f(xin%np1_f), &
' does not exceed model date', ncdate, ' sec ', ncsec, ' Stopping.'
end if
call endrun
()
end if
ntmp = xin%nm_f
xin%nm_f = xin%np_f
xin%np_f = ntmp
if (masterproc) then
strt3(3) = xin%np1_f
call handle_ncerr
( nf90_get_var ( xin%ncid_f, xin%fluxid, xin%xvar(:,:,xin%np_f), strt3, cnt3 ),&
'co2_data_flux.F90:391')
write(iulog,*)'CO2FLUX_INTERP: Read ', trim(xin%locfn),' for date (yyyymmdd) ', xin%date_f(xin%np1_f), &
' sec ', xin%sec_f(xin%np1_f)
endif
call scatter_field_to_chunk
( 1,1,2,cnt3(1), xin%xvar, xin%co2bdy )
end if
! Determine time interpolation factors.
call get_timeinterp_factors
( co2cyc, xin%np1_f, xin%cdayfm, xin%cdayfp, caldayloc, fact1, fact2, 'CO2FLUX_INTERP:' )
do lchnk=begchunk,endchunk
ncol = get_ncols_p
(lchnk)
do i=1,ncol
xin%co2flx(i,lchnk) = xin%co2bdy(i,lchnk,xin%nm_f)*fact1 + xin%co2bdy(i,lchnk,xin%np_f)*fact2
end do
end do
return
end subroutine interp_time_flux
!============================================================================================================
end module co2_data_flux