This archive contains answers to questions sent to Unidata support through mid-2025. Note that the archive is no longer being updated. We provide the archive for reference; many of the answers presented here remain technically correct, even if somewhat outdated. For the most up-to-date information on the use of NSF Unidata software and data services, please consult the Software Documentation first.
>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