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.
Ian, First, if you are willing to just use the default type-specific fill value for a variable, it's not necessary to explicitly define the _FillValue attribute, and not defining it makes sure it is of the right type for the variable. So you only need to define the time:_FillValue attribute if you want to use a particular non-default value for missing times. Second, if time is supposed to be a coordinate variable, it should not have missing values. This is not a requirement enforced by the library, just a "best practice", as listed here: http://www.unidata.ucar.edu/software/netcdf/docs/BestPractices.html#Coordinate%20Systems A coordinate variable is a one-dimensional variable with the same name as a dimension, which names the coordinate values of the dimension. It must not have any missing data (for example, no _FillValue or missing_value attributes) and must be strictly monotonic (values increasing or decreasing). Third, I tried using NF_FILL_DOUBLE as a fill value for a time coordinate associated with the unlimited dimension, and it worked fine. I've attached an example program, mostly generated by ncgen -f, that demonstrates this. Finally, in response to your last question, the fill value type has to match the type of the variable that the fill value is associated with. In your case that's the double precision time variable, not the single-precision data variable, right? I hope this helps. I still haven't figure out why the error isn't generated when the attribute is defined rather than when the data is written, but I hope you can just delete the attribute definition for the time _FillValue, since it shouldn't have such an attribute or the default value is adequate. --Russ Russ Rew UCAR Unidata Program address@hidden http://www.unidata.ucar.edu Ticket Details =================== Ticket ID: DXD-376053 Department: Support netCDF Priority: Normal Status: Closed
program fgennc include 'netcdf.inc' * error status return integer iret * netCDF id integer ncid * dimension ids integer lat_dim integer lon_dim integer time_dim * dimension lengths integer lat_len integer lon_len integer time_len parameter (lat_len = 2) parameter (lon_len = 3) parameter (time_len = NF_UNLIMITED) * variable ids integer lat_id integer lon_id integer time_id integer rh_id * rank (number of dimensions) for each variable integer lat_rank integer lon_rank integer time_rank integer rh_rank parameter (lat_rank = 1) parameter (lon_rank = 1) parameter (time_rank = 1) parameter (rh_rank = 3) * variable shapes integer lat_dims(lat_rank) integer lon_dims(lon_rank) integer time_dims(time_rank) integer rh_dims(rh_rank) * data variables real lat(lat_len) real lon(lon_len) * attribute vectors double precision doubleval(1) * enter define mode iret = nf_create('ih.nc', NF_CLOBBER, ncid) call check_err(iret) * define dimensions iret = nf_def_dim(ncid, 'lat', 2, lat_dim) call check_err(iret) iret = nf_def_dim(ncid, 'lon', 3, lon_dim) call check_err(iret) iret = nf_def_dim(ncid, 'time', NF_UNLIMITED, time_dim) call check_err(iret) * define variables lat_dims(1) = lat_dim iret = nf_def_var(ncid, 'lat', NF_REAL, lat_rank, lat_dims, lat_id 1) call check_err(iret) lon_dims(1) = lon_dim iret = nf_def_var(ncid, 'lon', NF_REAL, lon_rank, lon_dims, lon_id 1) call check_err(iret) time_dims(1) = time_dim iret = nf_def_var(ncid, 'time', NF_DOUBLE, time_rank, time_dims, t 1ime_id) call check_err(iret) rh_dims(3) = time_dim rh_dims(2) = lat_dim rh_dims(1) = lon_dim iret = nf_def_var(ncid, 'rh', NF_REAL, rh_rank, rh_dims, rh_id) call check_err(iret) * assign attributes doubleval(1) = 0 * iret = nf_put_att_double(ncid, time_id, '_FillValue', NF_DOUBLE, 1 * 1, doubleval) call check_err(iret) * print *, "about to define fill value attribute" * This causes error later when time value written * iret = nf_put_att_real(ncid, time_id, '_FillValue', NF_REAL, 1 * 1, 0.0) * This works OK * iret = nf_put_att_double(ncid, time_id, '_FillValue', NF_DOUBLE, 1 * 1, 0.0d0) iret = nf_put_att_double(ncid, time_id, '_FillValue', NF_DOUBLE, 1 1, NF_FILL_DOUBLE) call check_err(iret) * leave define mode iret = nf_enddef(ncid) call check_err(iret) * Write record variables call writerecs(ncid,time_id,rh_id) iret = nf_close(ncid) call check_err(iret) end subroutine writerecs(ncid,time_id,rh_id) * netCDF id integer ncid * variable ids integer time_id integer rh_id include 'netcdf.inc' * error status return integer iret * netCDF dimension sizes for dimensions used with record variables integer lat_len parameter (lat_len = 2) integer lon_len parameter (lon_len = 3) * rank (number of dimensions) for each variable integer time_rank integer rh_rank parameter (time_rank = 1) parameter (rh_rank = 3) * starts and counts for array sections of record variables integer time_start(time_rank), time_count(time_rank) integer rh_start(rh_rank), rh_count(rh_rank) * data variables integer time_nr parameter (time_nr = 2) double precision time(time_nr) integer rh_nr parameter (rh_nr = 2) real rh(lon_len, lat_len, rh_nr) data time /2., 3./ data rh /4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15/ * store time time_start(1) = 1 time_count(1) = time_nr iret = nf_put_vara_double(ncid, time_id, time_start, time_count, t 1ime) call check_err(iret) * iret = nf_put_var1_double(ncid, time_id, 1, 2.0d0) * print *, "about to put time value 1" * iret = nf_put_var1_double(ncid, time_id, 1, time(1)) * print *, "iret = ", iret * call check_err(iret) * print *, "about to put time value 2" * iret = nf_put_var1_double(ncid, time_id, 2, time(2)) * print *, "iret = ", iret * call check_err(iret) * store rh rh_start(1) = 1 rh_start(2) = 1 rh_start(3) = 1 rh_count(1) = lon_len rh_count(2) = lat_len rh_count(3) = rh_nr iret = nf_put_vara_real(ncid, rh_id, rh_start, rh_count, rh) call check_err(iret) end subroutine check_err(iret) integer iret include 'netcdf.inc' if (iret .ne. NF_NOERR) then print *, nf_strerror(iret) stop endif end