[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: 20020504: basics of using UNLIMITED records in netcdf
- Subject: Re: 20020504: basics of using UNLIMITED records in netcdf
- Date: Tue, 07 May 2002 10:48:42 -0600
>To: address@hidden
>From: David Ovens <address@hidden>
>Subject: basics of using UNLIMITED records in netcdf
>Organization: UCAR/Unidata
>Keywords: 200205040754.g447s1a29265
Hi David,
Sorry it's taken so long to get to your question.
> I can't believe how much time I've just spent trying to figure out how
> to use and write data in FORTRAN netcdf. I can do things ok if I
> don't use a RECORD/UNLIMITED dimension, but once I do that, I'm all
> fouled up and ncdump never shows me any data in the file. Please
> help! I think there must be some step that increments the record
> dimension that I am totally missing and can't find in the
> documentation. I can fill RHVALS with data, but I can never write it
> into the file when I use an UNLIMITED dimension.
>
> Thanks for helping me regain my sanity.
>
> Here's what I do:
> f90 -I/usr/local/include test.F -lnetcdf ;\
> rm foo.nc ; a.out ; ncdump foo.nc
>
> Here's what I get from ncdump:
> netcdf foo {
> dimensions:
> lat = 5 ;
> lon = 10 ;
> time = UNLIMITED ; // (0 currently)
> variables:
> double rh(time, lat, lon) ;
> data:
> }
>
> Where's rh?
>
> Here's the simple code (pretty much verbatum from the documentation):
> INCLUDE 'netcdf.inc'
>
> INTEGER STATUS, NCID, TIMES
> PARAMETER (TIMES=3, LATS=5, LONS=10) ! dimension lengths
> INTEGER RHID ! variable ID
> DOUBLEprecision RHVALS(LONS, LATS, TIMES)
> INTEGER LATID, RECID, ivarid
> INTEGER LATDIM, LONDIM, TIMDIM ! dimension IDs
> INTEGER RHDIMS(3) ! variable shape
>
> STATUS = NF_CREATE('foo.nc', NF_NOCLOBBER, NCID)
> IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
>
> STATUS = NF_DEF_DIM(NCID, 'lat', 5, LATDIM)
> IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
> STATUS = NF_DEF_DIM(NCID, 'lon', 10, LONDIM)
> IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
> STATUS = NF_DEF_DIM(NCID, 'time', NF_UNLIMITED, TIMDIM)
> c STATUS = NF_DEF_DIM(NCID, 'time', 2, TIMDIM)
> IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
>
> RHDIMS(1) = LONDIM
> RHDIMS(2) = LATDIM
> RHDIMS(3) = TIMDIM
> STATUS = NF_DEF_VAR (NCID, 'rh', NF_DOUBLE, 3, RHDIMS, RHID)
> IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
>
> status = nf_enddef(ncid)
> status = nf_close(ncid)
>
> STATUS = NF_OPEN ('foo.nc', NF_WRITE, NCID)
> IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
>
> STATUS = NF_INQ_VARID (NCID, 'rh', RHID)
> IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
>
> DO 30 ILON = 1, LONS
> DO 20 ILAT = 1, LATS
> DO 10 ITIME = 1, TIMES
> RHVALS(ILON, ILAT, ITIME) = 0.5
> 10 CONTINUE
> 20 continue
> 30 continue
> STATUS = NF_PUT_var_DOUBLE (NCID, RHID, RHVALS)
> IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
>
> status = nf_close(ncid)
> stop
> end
>
> subroutine handle_err(iret)
> integer iret
> include 'netcdf.inc'
> if (iret .ne. NF_NOERR) then
> print *, nf_strerror(iret)
> stop
> endif
> end
The problem is in the documentation for the nf_put_var_ family of
functions, which should contain the following paragraph (and does in a
new version, which is unfortunately not yet available):
It is usually not appropriate to use this interface with record
variables, which are typically written a record at a time instead. If
you try to write all the values of a record variable into a netCDF
file that has no record data yet (hence has 0 records), nothing will
be written. Similarly, if you try to write all of a record variable
but there are more records in the file than you assume, more data may
be written to the file than you supply, which may result in a
segmentation violation.
Instead of nf_put_var_double() you need to use nf_put_vara_double() to
write one record at a time. So your rh variable in the program only
needs to be dimensioned for (lat, lon) rather than (time, lat,lon),
although the latter is OK too as long as you write one time slice at a
time. You could even write all the time slices at once using
nf_put_vara_double(), with something like
PARAMETER(RHRANK = 3)
INTEGER RHSTART(RHRANK)
INTEGER RHCOUNT(RHRANK)
...
RHSTART(1) = 1
RHSTART(2) = 1
RHSTART(3) = 1
RHCOUNT(1) = LONS
RHCOUNT(2) = LATS
RHCOUNT(3) = TIMES
STATUS = NF_PUT_vara_DOUBLE (NCID, RHID, RHSTART, RHCOUNT, RHVALS)
You can generate a working Fortran example from a CDL file using the
"ncgen" utility with the "-f" flag, so for example, from the CDL file
netcdf foo {
dimensions:
lat = 5 ;
lon = 10 ;
time = UNLIMITED ; // (0 currently)
variables:
double rh(time, lat, lon) ;
data:
rh = 1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,
2,2,2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,2,2;
}
stored in "foo.cdl", you could generate a Fortran program to create
the corresponding netCDF file foo.nc using
ncgen -f foo.cdl > foo.f
and see that it uses a call to nf_put_var_double().
Here's another support response that explains the issues with the
"whole variable" write for record variables in more detail:
http://www.unidata.ucar.edu/cgi-bin/mfs/70/4293
Please let us know if this answers your question.
--Russ
_____________________________________________________________________
Russ Rew UCAR Unidata Program
address@hidden http://www.unidata.ucar.edu