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