Hello,
I'm a student at the Philipps-University Marburg (Germany) and want to work
with the NCEP/NCAR Reanalysis Data but I've got problems compiling
'readgeneral.f' from CDC, which is for reading netcdf format files from CDC.
I have installed netcdf-3.5.1 and udunits-1.11.7 from source on this system:
Linux linux 2.4.21-99-athlon #1 Wed Sep 24 13:34:32 UTC 2003 i686 athlon i386
GNU/Linux
I set following environments:
setenv CPPFLAGS "-DNDEBUG -Df2cFortran"
setenv FC g77
setenv LD_MATH "-lm"
I tried to compile readgeneral.f with the following command:
g77 readgeneral.F -lnetcdf -ludunits
and get this output:
/usr/local/udunits/include/udunits.inc: In subroutine `gridread':
In file included from readgeneral.F:174:
/usr/local/udunits/include/udunits.inc:27: error: undefined or invalid #
directive
/usr/local/udunits/include/udunits.inc:36:
PTR utmake
1 2
Unrecognized statement name at (1) and invalid form for assignment or
statement-function definition at (2)
readgeneral.F:217: warning:
call ncagt(inet,ivar,'scale_factor',xscale,icode1)
1
readgeneral.F:219: (continued):
....
/usr/local/udunits/include/udunits.inc:36:
PTR utmake
1 2
Unrecognized statement name at (1) and invalid form for assignment or
statement-function definition at (2)
Attached is 'udunits.inc' and 'readgeneral.F'
Thank you very much for your help!
Regards
Katja Trachte
__________________________________________________________
Mit WEB.DE FreePhone mit hoechster Qualitaet ab 0 Ct./Min.
weltweit telefonieren! http://freephone.web.de/?mc=021201
integer UT_EOF, UT_ENOFILE, UT_ESYNTAX, UT_EUNKNOWN
integer UT_EIO, UT_EINVALID, UT_ENOINIT, UT_ECONVERT
integer UT_EALLOC, UT_ENOROOM, UT_ENOTTIME
parameter (UT_EOF = 1)
parameter (UT_ENOFILE = -1)
parameter (UT_ESYNTAX = -2)
parameter (UT_EUNKNOWN = -3)
parameter (UT_EIO = -4)
parameter (UT_EINVALID = -5)
parameter (UT_ENOINIT = -6)
parameter (UT_ECONVERT = -7)
parameter (UT_EALLOC = -8)
parameter (UT_ENOROOM = -9)
parameter (UT_ENOTTIME = -10)
integer UT_MAXNUM_BASE_QUANTITIES
parameter (UT_MAXNUM_BASE_QUANTITIES = 10)
C The FORTRAN API:
C
C NB: `PTR in the following stands for whatever FORTRAN type is
C appropriate for storing a pointer to a structure. Because this is
C necessarily platform-dependent, IT IS UP TO THE USER TO DECLARE AND USE
C THE CORRECT TYPE.
#ifndef PTR
# define PTR integer
#endif
C
C Initialize the units package:
integer utopen
C (character*(*) fpath)
C Create a new unit:
PTR utmake
C ()
C Is a unit a temporal one?
integer uttime
C (PTR unit)
C Indicate whether or not a unit has a non-zero origin (0=>no, 1=>yes).
integer utorigin
C (PTR unit)
C Clear a unit:
C utclr
C (PTR unit)
C Copy a unit:
C utcpy
C (PTR source,
C PTR dest)
C Shift the origin of a unit:
C utorig
C (PTR source,
C doubleprecision amount,
C PTR result)
C Scale a unit:
C utscal
C (PTR source,
C doubleprecision factor,
C PTR result)
C Multiply two units:
C utmult
C (PTR term1,
C PTR term2,
C PTR result)
C Invert a unit:
C utinv
C (PTR source,
C PTR result)
C Divide one unit by another:
C utdiv
C (PTR numer,
C PTR denom,
C PTR result)
C Raise a unit to a power:
C utexp
C (PTR source,
C PTR power,
C PTR result)
C Decode a formatted specification into a unit:
integer utdec
C (character*(*) fspec,
C PTR unit)
C Convert a temporal value into a UTC Gregorian date and time:
integer utcaltime
C (real value,
C PTR unit,
C integer year
C integer month,
C integer day,
C integer hour,
C integer minute,
C real second)
C Convert a Gregorian/Julian date and time into a temporal value:
integer uticaltime
C (integer year,
C integer month,
C integer day,
C integer hour,
C integer minute,
C real second,
C PTR unit,
C doubleprecision value)
C Encode a unit into a formatted specification:
integer utenc
C (PTR unit,
C char fspec)
C Convert from one unit to another:
integer utcvt
C (PTR from,
C PTR to,
C doubleprecision slope,
C doubleprecision intercept)
C Free a unit thingy created by utmake():
C utfree
C (PTR unit)
C Close the units package:
C utcls
C ()
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
C
C This is a sample program that will read netCDF data files
C from the NOAA-CIRES Climate Diagnostics Center.
C
C In order to run the code you must have the netCDF and UDUNITS
C libraries installed from UniData.
C
C netCDF can be found at
C http://www.unidata.ucar.edu/packages/netcdf/index.html
C
C UDUNITS can be found at
C http://www.unidata.ucar.edu/packages/udunits/index.html
C
C Don't forget to add them -lnetcdf and -ludunits options to the compile
C or load command line.
C
C There are four things that you must change to use this code
C at your site. Each place where you must make a change is
C indicated with a comment of the form like the line below.
C
C STEP 1.
C Change the location of the netcdf.inc and udunits.inc include files
C to match your installation. (Occurs in 4 places.)
C
C STEP 2.
C Change the location of the udunits.dat file to match your system
C installation.
C
C STEP 3.
C Change PARAMETER values for ilon and jlat to match your file.
C You can find out the sizes of the lon and lat dimensions by looking
C at the output of ncdump -h <your_file>.
C
C STEP 4.
C Change the name of the input file to match the data file you want to read.
C
C STEP 5.
C Choose among the three different ways to read data and remove the comments
C to get the code you need to do your job.
C
C NOTES:
C Data is read in one 2D grid at a time in the same lat/lon order
C it was stored.
C The gridread subroutine returns the date of the grid read.
C
C Code written 10/9/96 by Cathy Smith
C
C NOAA-CIRES Climate Diagnostics Center, Boulder, CO.
C based on code writen by Tom Baltzer, Roland Schweitzer and
C Cathy Smtih
C For help, contact Roland Schweitzer or Cathy Smith
C Roland.Schweitzer@xxxxxxxx or
cathy.smith@xxxxxxxx
C :)
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
C MAIN CODE
c
c This is the latitude, longitude dimension of the grid to be read.
c This corresponds to the lat and lon dimension variables in the netCDF file.
c
C STEP 3.
parameter (ilon =360)
parameter (jlat=180)
c
c The data are packed into short integers (INTEGER*2). The array work
c will be used to hold the packed integers. The array 'x' will contain
c the unpacked data.
c
C DATA ARRAY AND WORK ARRAY
real x(ilon,jlat)
integer*2 work(ilon,jlat)
c
c Initialize the UDUNITS package. You may need to change the location
c of the udunits.dat file to match your system.
c
C STEP 2.
retcode=utopen('/usr/local/udunits/etc/udunits.dat')
C STEP 4.
c
c Below in the ncopen call is the file name of the netCDF file.
c You may want to add code to read in the file name and the variable name.
c
c The variable name is the netCDF variable name. At CDC we name our files
c after the variable name. If you follow that convention the variable name
c is the same as the first few letters of the file name (the letters up to
c but not including the first '.'.
C
C OPEN FILE AND GET FILES ID AND VARIABLE ID(S)
inet=ncopn('sst.mnmean.nc',0,icode)
ivar=ncvid(inet,'sst',icode)
C STEP 5.
C Pick one of the following scenarios to match your needs.
C
C Comment out this section and remove the comment from one of
C the sections below.
print*, 'Pick one of the three scenarios for your data.'
print*, 'See STEP 5 in the comments.'
stop 'Pick a scenario'
c
C SCENARIO 1.
c USE THIS LOOP TO READ THE FIRST 'NTIME' TIME STEPS FROM A FILE
c WITH ONLY ONE LEVEL. IF THE FILE ONLY HAS ONE LEVEL SET ILEV TO 0.
c
ntime = 5
ilev = 0
do it=1,ntime
call gridread(inet,ivar,it,x,jlat,ilon,ilev,ny,nm,nd,nh,work)
print*,x(2,2),x(72,36),ny,nm,nd,nh
enddo
c
C SCENARIO 2.
c USE THIS LOOP TO READ THE FIRST 'NTIME' TIME STEPS FROM A FILE
c WITH 'NLEV' LEVELS IN IT. EACH PASS THROUGH THE LOOP WILL RESULT
c IN A GRID AT LEVEL ILEV, AND TIME STEP NTIME.
c
c ntime = 5
c nlev = 17
c
c do it=1,ntime
c do ilev = 1, nlev
c call gridread(inet,ivar,it,x,jlat,ilon,ilev,ny,nm,nd,nh,work)
c print*,x(1,1),ny,nm,nd,nh
c enddo
c enddo
c
C SCENARIO 3.
c THIS CODE BLOCK WILL READ A SPECIFIC TIME AND DATE FROM THE FILE.
c
c
c Set the time of the grid to be read.
c
ny = 1995
nm = 3
nd = 6
nh = 12
c
c Set this to 0 for a file with one level, loop over it to get all levels,
c or set it to the index of a specific level.
c
c ilev = 5
c call timeindex(inet,ny,nm,nd,nh,it)
c call gridread(inet,ivar,it,x,jlat,ilon,ilev,ny,nm,nd,nh,work)
c
c The value of ny, nm, nd, and nh have been overwritten with the
c values for the grid just read.
c
c print*,x(1,1),ny,nm,nd,nh
stop
end
********************************************************************
********************************************************************
C MAIN SUBROUTINE TO READ GRID
subroutine gridread(inet,ivar,nt,x,jlat,ilon,ilev,iyear,imonth,
& iday,ihour,idata)
C STEP 1.
include '/usr/local/udunits/include/udunits.inc'
include '/usr/local/netcdf/include/netcdf.inc'
********************************************************************
C UDUNITS STUFF TO UNPACK TIME:
********************************************************************
C declare udunits function calls
integer*4 UTMAKE
c integer UTDEC,uttime
C declare everything else
integer*4 iyear,imonth,iday,ihour,retcode,itimeid
integer*4 unitptr
character*1024 unitstrin
character*1024 unitstr
integer*2 idata(ilon,jlat)
real*4 x(ilon,jlat)
integer count(3),start(3)
integer countl(4),startl(4)
integer icount2(1),istart2(1)
integer*2 miss
c unitptr=utmake()
retcode=utdec(unitstr,unitptr)
retcode=uttime(unitptr)
isave=1
itimeid=NCVID(inet,'time',icode)
call ncainq(inet,itimeid,'units',iNCCHAR,mlen,i)
call ncagtc(inet,itimeid,'units',unitstrin,mlen,icode)
unitstr=unitstrin(1:nblen(unitstrin))
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
C TEST AND SEE OF FILE HAS LEVELS
C ALSO SEE IF PACKED
C GET SCALE FACTOR AND MISSING VALUE IF NECESSARY
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
call NCPOPT(0) !Turn off netCDF error reaction
call ncagt(inet,ivar,'scale_factor',xscale,icode1)
call ncagt(inet,ivar,'add_offset',xoff,icode2)
call ncagt(inet,ivar,'missing_value',miss,icode3)
C you need to get level or else use integer level
C SLAB INFO FOR DATA ARRAY
C see if packed or not
ipack=0
if((icode1.eq.0).and.(icode2.eq.0))then
if((xscale.eq.1).and.(xoff.eq.0))then
ipack=0
else
ipack=1
endif
endif
start(3)=nt
if(ilev.eq.0)then
start(1)=1
start(2)=1
start(3)=nt
count(1)=ilon
count(2)=jlat
count(3)=1
C LOOP THROUGH 1 YEAR OF DATA, UNPACK ARRAY, UNPACK TIME
C AND READ HEADER
if(ipack.eq.1)then
call ncvgt(inet,ivar,start,count,idata,icode)
call unpack(idata,x,xscale,xoff,miss,ilon,jlat)
else
call ncvgt(inet,ivar,start,count,x,icode)
endif
call ncvgt(inet,itimeid,nt,1,xtime,icode)
istart2(1)=nt
icount2(1)=1
call ncvgt(inet,itimeid,istart2,icount2,xtime,iercode)
call udparse(unitstrin,xtime,iyear,imonth,iday,ihour)
else
startl(1)=1
startl(2)=1
startl(3)=ilev
startl(4)=nt
countl(1)=ilon
countl(2)=jlat
countl(3)=1
countl(4)=1
C LOOP THROUGH 1 YEAR OF DATA, UNPACK ARRAY, UNPACK TIME
C AND READ HEADER
if(ipack.eq.1)then
call ncvgt(inet,ivar,startl,countl,idata,icode)
call unpack(idata,x,xscale,xoff,miss,ilon,jlat)
else
call ncvgt(inet,ivar,startl,countl,x,icode)
endif
call ncvgt(inet,itimeid,nt,1,xtime,icode)
istart2(1)=nt
icount2(1)=1
call ncvgt(inet,itimeid,istart2,icount2,xtime,iercode)
call udparse(unitstrin,xtime,iyear,imonth,iday,ihour)
endif
return
end
********************************************************************
subroutine unpack(x,y,xscale,xadd,miss,ilon,jlat)
parameter (zmiss=1e30)
integer*2 x(ilon,jlat),miss
real y(ilon,jlat)
do i=1,ilon
do j=1,jlat
if(x(i,j).eq.miss)then
y(i,j)=zmiss
else
y(i,j)=(x(i,j)*xscale)+xadd
endif
enddo
enddo
return
end
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
C
C This routine (part of the netopen package for CDC netCDF file
C handling) takes a netCDF file id, a year, month, day and hour
C and converts it to the time index for that time in the file
C and returns that index
C
C NOTE: WILL NOT HANDLE LESS THAN HOURLY DATA! Prints error message
C and terminates.
C
C Written by Cathy Smith of CDC on ???
C Modified by Tom Baltzer of CDC on 2/14/95
C - Broke out into own file and added comments
C Modified by Tom Baltzer of CDC on 2/27/95
C added declarations comments and made to work with
C reanalysis.
C
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
subroutine timeindex(netid,nyr,nmn,ndy,nhr,itime)
C STEP 1.
include '/usr/local/netcdf/include/netcdf.inc'
include '/usr/local/udunits/include/udunits.inc'
integer netid ! NetCDF file id
integer nyr,nmn,ndy,nhr ! Input year,month,day & hour
integer itime ! Return time index
integer inyr2d ! 2 digit in year (used throughout)
integer inyr4d ! 4 digit input year
real*8 xtime(10) ! Holds 10 time values from file
real*8 inxtime ! Input time in netCDF file form
character*25 cdeltat ! delta_t attribute from file
integer timevid ! Time variable id
integer timedid ! Time dimension id
character*100 timeunit ! unit attribute for time variable
integer*4 unitptr ! pointer to udunits unit
integer*4 UTMAKE ! Declare the function. It's in the
! udunits.inc at our site, but
! may not be at others.
integer yr1,mn1,dy1,hr1 ! First time value in file
integer yr2,mn2,dy2,hr2 ! Second time value in file
integer*4 xhour1,xhour2,xhourin ! results of xhour calls
integer*4 hourinc ! delta time in hours
integer monthly ! 1 if data is monthly
integer daily ! 1 if data is daily
integer found ! 0 if not found 1 if found
integer ltm ! Used to identify a LTM file
integer equalinc ! Identify non-equal time increments
integer ercode ! To get netCDF error codes
c integer UTDEC ! Declare the functions.
c integer UTICALTIME
integer istart(1),icount(1) ! Used in netCDF calls
character*15 cname ! Place holder
C Initialize
c
c I added the condition to find values less that 100. We assume that such
c a year is a 2 digit year in the 20th century.
c
c The other else if block gets set up for other years, like 1851 the beginning
c of the DOE data set.
c
if (nyr.gt.1900.and.nyr.lt.3000) then
inyr2d = nyr - 1900
inyr4d = nyr
else if ( nyr.lt.100 ) then ! Between 0-99, it's a 2 digit year.
inyr2d = nyr
inyr4d = nyr + 1900
else if ( nyr .ge. 100 .and. nyr .lt. 2000) then ! Some other year
inyr2d = nyr !Not really, but it's non-zero which is inportant.
inyr4d = nyr !What ever they gave us was the year we want.
endif
ltm = 0
equalinc = 0
monthly = 0
daily = 0
C Get all the time variable information including the first 10 or
C (if < 10) total available values and convert 1st 3 to yr,mn,dy, & hr
timedid=NCDID(netid,'time',ercode)
call NCDINQ(netid,timedid,cname,idimt,ercode)
istart(1)=1
if (idimt.ge.10) then
icount(1)=10
else
icount(1)=idimt
endif
timevid=NCVID(netid,'time',ercode)
call NCVGT(netid,timevid,istart,icount,xtime,ercode)
call NCAGTC (netid,timevid, 'units', timeunit, 100, ercode)
if (idimt.ge.3) then
call udparse(timeunit, xtime(1), yr1,mn1,dy1,hr1)
call udparse(timeunit, xtime(2), yr2,mn2,dy2,hr2)
elseif (idimt.eq.1) then
write(0,*) "Only one time increment in the file - returning it"
itime = 1
found = 1
return
else
equalinc = 1
call udparse(timeunit, xtime(1), yr1,mn1,dy1,hr1)
call udparse(timeunit, xtime(2), yr2,mn2,dy2,hr2)
endif
C Turn off error checking and see if this is a CDC data file, and
C if so, check time increment < hourly and check for ltm file.
C Also do first check for equal increment.
call NCPOPT(0)
call NCAGTC(netid,timevid,'delta_t',cdeltat,25,ercode)
if (ercode.eq.0) then
equalinc = 1
c
c Previously, this was called with variable id hard coded to 1.
c This won't work for multiple variables in the same run.
c
c call NCAGTC(netid,1,'statistic',cstat,25,ercode)
c
c We will detect long term means from the ltm_range attribute.
c That way we don't need the variable id at all.
c
call NCAGT(netid,timevid,'ltm_range',ltm_range,ercode)
c
c Ugly kludge to handle different spellings of LTM. Probably
c should do this as a caseless comparison. rhs 1/8/96
c Using ltm range gets rid of this ugly kludge.
c
c if(cstat(1:14).eq.'Long Term Mean' .or.
c & cstat(1:14).eq.'Long term mean' .or.
c & cstat(1:14).eq.'long term mean') then
c
c If the return code from the above is zero then we have
c and LTM file.
if (ercode .eq. 0) then
c
c Looking for daily long term means as well as monthly.
c
c if(inyr2d.ne.0.or.ndy.ne.0.or.nhr.ne.0) then
c write(0,*) 'timeindex: Warning - non-monthly value ',
c & 'requested for monthly LTM file'
c write(0,*) 'Using month value ',nmn,' to get index'
c endif
c
c Detect both monthly and daily long term mean.
c
if(inyr2d.ne.0.or.nhr.ne.0) then
write(0,*) 'timeindex: Warning - non-zero hourly value ',
& 'requested for a LTM file.',
& 'Do not know how do deal with hourly LTM. ',
& 'Quiting...'
stop 'LTM'
endif
ltm = 1
endif
if (cdeltat(15:16).ne.'00'.or.cdeltat(18:19).ne.'00') then
write(0,*) 'timeindex: Error: Time increment is < hourly -'
write(0,*) ' cannot be handled. -Terminating.'
stop
endif
if (cdeltat(7:7).eq.'1') monthly = 1
if (cdeltat(10:10).eq.'1') daily = 1
endif
call NCPOPT(NCVERBOS+NCFATAL)
C Get the time index.
if (ltm.eq.1 .and. monthly.eq.1) then
itime=(nmn-mn1)+1
found = 1
elseif ( ltm.eq.1 .and. daily.eq.1) then
call xhour(yr1,mn1,dy1,hr1,xhour1)
call xhour(yr2,mn2,dy2,hr2,xhour2)
hourinc = xhour2 - xhour1
c
c Well, this looks ugly.
c Previously, these xhour values were computed from the year 0.
c xhour turns the year 0 into 1900 and all the calculations are
c done relative to 1900. 1900 is a leap year, which pushes the
c ltm values off by a day. Instead, since we know it's a ltm
c already from the statistic attribute, we use year 1 for
c the xhour calculations. rhs 1/8/95
c
if (daily.eq.1.or.hourinc.eq.24) then
c call xhour(yr1,mn1,dy1,0,xhour1)
c call xhour(yr2,mn2,dy2,0,xhour2)
c call xhour(inyr4d,nmn,ndy,0,xhourin)
call xhour(1,mn1,dy1,0,xhour1)
call xhour(1,mn2,dy2,0,xhour2)
call xhour(1,nmn,ndy,0,xhourin)
else
call xhour(inyr4d,nmn,ndy,nhr,xhourin)
endif
itime = INT(((xhourin - xhour1)/hourinc) + 0.5)
itime = itime + 1
found = 1
elseif (monthly.eq.1) then
itime=(((inyr4d*12)+nmn)-((yr1*12)+mn1))
itime=itime+1
found = 1
elseif (equalinc.eq.1) then
call xhour(yr1,mn1,dy1,hr1,xhour1)
call xhour(yr2,mn2,dy2,hr2,xhour2)
hourinc = xhour2 - xhour1
if (daily.eq.1.or.hourinc.eq.24) then
call xhour(yr1,mn1,dy1,0,xhour1)
call xhour(yr2,mn2,dy2,0,xhour2)
call xhour(inyr4d,nmn,ndy,0,xhourin)
else
call xhour(inyr4d,nmn,ndy,nhr,xhourin)
endif
itime = INT(((xhourin - xhour1)/hourinc) + 0.5)
itime = itime + 1
found = 1
else
write(0,*) 'Cannot assume consistant delta time for ',
& 'finding index (no delta_t attribute)'
write(0,*) 'This may take a while ...'
found = 0
C Inverse parse the date for comparisons - and move through the
C time values searching for the one we want.
if (timeunit(1:1).eq.'y'.or.timeunit(1:1).eq.'Y') then
inxtime = inyr4d*10000000000.d0 + nmn*100000000.d0 +
& ndy*1000000. + nhr*10000.
else
unitptr = UTMAKE()
ercode = UTDEC(timeunit(1:nblen(timeunit)),unitptr)
if (ercode.ne.0) then
call uduerr(ercode,'UTDEC','')
write(0,*) ''
write(0,*) 'NOTE: You must call netop_init to use
& gridread,'
write(0,*) ' gridreadx, dayread, and dayreadx'
stop
endif
ercode = UTICALTIME(inyr4d,nmn,ndy,nhr,0,0.,unitptr,inxtime)
if (ercode.ne.0) then
call uduerr(ercode,'UTICALTIME','')
write(0,*) ' '
write(0,*) 'Something wrong with finding time increment'
write(0,*) 'Terminating'
stop
endif
call UTFREE(unitptr)
endif
C See if time is in first group of time values gotten from file
do i = 1,icount(1)
if (xtime(i).eq.inxtime) then
itime = i
found = 1
endif
enddo
if (icount(1).eq.idimt) then
write(0,*) 'Could not find desired time increment'
write(0,*) ' - Terminating'
stop
endif
C Step through file getting groups of values and seeing if it's in there
istart(1) = istart(1) + icount(1)
do while (found.eq.0.and.istart(1)+icount(1).le.idimt)
call NCVGT(netid,timevid,istart,icount,xtime,ercode)
do i = 1,icount(1)
if (xtime(i).eq.inxtime) then
itime = (istart(1) + i) - 1
found = 1
endif
enddo
enddo
C Check the last group of time values in the file
if (found.eq.0) then
icount(1) = (idimt - istart(1)) + 1
call NCVGT(netid,timevid,istart,icount,xtime,ercode)
do i = 1,icount(1)
if (xtime(i).eq.inxtime) then
itime = (istart(1) + i) - 1
found = 1
endif
enddo
endif
if (found.eq.0) then
write(0,*) 'Could not find desired time increment'
write(0,*) ' - Terminating'
stop
endif
endif
if(itime.gt.idimt)then
write(0,*)'You are requesting a time past the end of the file'
istart(1)=idimt
icount(1)=1
call NCVGT(netid,timevid,istart,icount,xtime,ercode)
call udparse(timeunit,xtime(1),iyear,imonth,iday,ihour)
write(0,*)' last day of file is: ',iyear,imonth,iday,ihour
endif
if(itime.le.0)then
print*,'you asked for a time before first day of the dataset'
print*,iyear,imonth,iday,ihour,' is first day of data'
itime=0
endif
return
end
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
C
C This subroutine is part of the netopen/read set of Fortran callable
C routines for reading CDC netCDF files and returning grids.
C
C This routine takes in a year, month, day and hour and calculates
C the number of hours since a date before all our data (year 1 month 1
C day 1) - this gives a referece value from which differences between
C dates can be derived.
C
C Note that this routine will take a 4 or a 2 digit date, if it
C receives a 2 digit date it assumes that it is in the range 1900 -
C 1999.
C
C Written by Cathy Smith of CDC on ???
C Modified by Tom Baltzer of CDC on Feb 28, 1995
C - converted from days to hours so that hourly data can be
C accounted for, and made starting date 1-1-1 from 1-1-1920.
C
C File: xhour.f (to be included in netopen.subr.f)
C
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
subroutine xhour(iy,im,id,ih,xhours)
integer iy,im,id,ih ! The input year, month, day and hour
integer*4 xhours ! OUT # of hours between in and 1-1-1
integer*4 xdays ! Used in calculating hours
integer inyear ! Used to work with input year
integer imonth(12) ! Used in calculating # days in this year
integer imonthl(12) ! " "
data imonth/31,28,31,30,31,30,31,31,30,31,30,31/
data imonthl/31,29,31,30,31,30,31,31,30,31,30,31/
C See if date is in 1900s but given as 2 digit.
if (iy.lt.100) then
inyear = iy + 1900
else
inyear = iy
endif
C CALCULATE DAYS FROM JAN 1 Year 1
xdays=0
xhours=0
xdays = INT((inyear-1)*365.25)
if(im.gt.1)then
do imm=1,im-1
if((mod(inyear,4).eq.0).and.(inyear.ne.0))then
xdays=xdays+imonthl(imm)
else
xdays=xdays+imonth(imm)
endif
enddo
endif
xdays=xdays+id
xhours = xdays*24
xhours = xhours + ih
return
end
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
C
C This subroutine is part of the netopen Fortran callable CDC
C group of routines for reading generic netCDF files in the new
C cooperative standard as presented in:
C http://ferret.wrc.noaa.gov/noaa_coop/coop_cdf_profile.html
C
C This routine takes a time value pulled from the netCDF file,
C determines if it is in the new or old time format (by using the
C udunits function) and then returns the representative year,
C month, day and hour represented by the time value.
C
C Written by Cathy Smith of CDC on ???
C Modified by Tom Baltzer of CDC on Feb. 8, 1995
C - To determine if time is old or new format and parse
C accordingly
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
subroutine udparse(timeunit,intime,oyear,omonth,oday,ohour)
C STEP 1.
include '/usr/local/udunits/include/udunits.inc'
C Note: POINTER type is integer*4 on the CDC SparcCenter 2000
c system running SunOS 5.3
c integer UTMAKE,UTDEC,utcaltime
integer*4 unitptr ! Pointer to udunits "unit" type
character*100 timeunit
! The unit attribute for time in the netCDF file
real*8 intime,xx ! The input time value and var to work with it
integer oyear,omonth,oday,ohour
! The output year,month,day and hour
integer tmin ! Temporary storage for minutes value
real tsec ! Temporary storage for seconds value
integer ercode ! For determining udunits result
unitptr = UTMAKE()
ercode = UTDEC(timeunit(1:nblen(timeunit)),unitptr)
if (ercode.ne.0) then
C Assume old CDC standard if time unit is unknown
if (ercode.eq.UT_EUNKNOWN.and.(timeunit(1:1).eq.'y'.or.
& timeunit(1:1).eq.'Y')) then
xx=0.
oyear=int(intime/10000000000.d0)
xx=oyear*10000000000.d0
omonth=int((intime-xx)/100000000.d0)
xx=xx+omonth*100000000.
oday=int((intime-xx)/1000000.)
xx=xx+oday*1000000.
ohour=int((intime-xx)/10000.)
else
call uduerr(ercode,'UTDEC','')
write(0,*) ''
write(0,*) 'NOTE: You must call netop_init to use gridread,'
write(0,*) ' gridreadx, dayread, and dayreadx'
stop
endif
else
ercode = UTCALTIME(intime,unitptr,oyear,omonth,oday,ohour,
& tmin,tsec)
if (ercode.ne.0) then
call uduerr(ercode,'UTCALTIME','')
stop
endif
endif
C Free up the pointer
call UTFREE(unitptr)
return
end
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
C
C This function is intended to handle all possible error conditions
C for the Udunits package (Version 1.7.1) from Unidata, it takes the
C error code returned from a udunits function, the function name and
C the filename the function was accessing (applicable only for utopen
C function). It prints an indication to the user of the error and
C function in which it occurred.
C
C Written by: Tom Baltzer of CDC February 10, 1995
C
C File: uduerr.f (To be added to netopen.subr.f)
C
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
subroutine uduerr(ercode, funcname, filename)
C STEP 1.
include '/usr/local/udunits/include/udunits.inc'
integer ercode ! The Udunits Error number
character* (*) funcname ! Function name which returned error
character* (*) filename ! Name of file on which funct operates
character*1024 path ! Path to file on which funct really works
if (filename.eq.'') then
call getenv('UDUNITS_PATH',path)
if (path.eq.'') then
path = '/usr/local/udunits'
endif
else
path = filename
endif
write(0,*) 'Error in udunits function: ',funcname
if (ercode.eq.UT_ENOFILE) then
write(0,*) 'File: ',path(1:nblen(path))
write(0,*) 'Does not exist!'
elseif (ercode.eq.UT_ESYNTAX) then
write(0,*) 'A Udunits syntax error was detected'
if (path.ne.'') then
write(0,*) 'Possibly in the file: ',
& path(1:nblen(path))
endif
elseif (ercode.eq.UT_EUNKNOWN) then
write(0,*) 'Udunits unknown specification found'
if (path.ne.'') then
write(0,*) 'Possibly in the file: ',
& path(1:nblen(path))
endif
elseif (ercode.eq.UT_EIO) then
write(0,*) 'I/O Error detected'
if (path.ne.'') then
write(0,*) 'Possibly in the file: ',
& path(1:nblen(path))
endif
elseif (ercode.eq.UT_EINVALID) then
write(0,*) 'An invalid udunits structure was found'
write(0,*) ' Note: probably a temporal struct'
elseif (ercode.eq.UT_ENOINIT) then
write(0,*) 'Udunits package has not been initialized'
elseif (ercode.eq.UT_ECONVERT) then
write(0,*) 'No conversion between the two units is possible'
elseif (ercode.eq.UT_ENOROOM) then
write(0,*) 'Not enough room in character string for conversion'
elseif (ercode.eq.UT_EALLOC) then
write(0,*) 'Memory allocation falure'
else
write(0,*) 'UTOPEN: Unknown error: ',ercode
endif
return
end
integer function nblen (string)
c
c given a character string, nblen returns the length of the string
c to the last non-blank character, presuming the string is left-
c justified, i.e. if string = ' xs j ', nblen = 8.
c
c called non-library routines: none
c language: standard fortran 77
c
integer ls,i
character*(*) string, blank*1, null*1
data blank /' '/
c
null = char(0)
nblen = 0
ls = len(string)
if (ls .eq. 0) return
do 1 i = ls, 1, -1
if (string(i:i) .ne. blank .and. string(i:i) .ne. null) go to 2
1 continue
return
2 nblen = i
return
end