more testing for late fill setting

This commit is contained in:
Ed Hartnett 2018-10-17 09:44:18 -06:00
parent d959512a2e
commit 91ec0109f3
2 changed files with 87 additions and 39 deletions

View File

@ -546,42 +546,57 @@ NC_getshape(int ncid, int varid, int ndims, size_t* shape)
return status;
}
/*! Set the fill value for a variable.
\ingroup variables
\param ncid NetCDF ID, from a previous call to nc_open or
nc_create.
\param varid Variable ID.
\param no_fill Set to NC_NOFILL to turn off fill mode for this
variable. Set to NC_FILL (the default) to turn on fill mode for the
variable.
\param fill_value the fill value to be used for this variable. Must be
the same type as the variable. This must point to enough free memory
to hold one element of the data type of the variable. (For example, an
NC_INT will require 4 bytes for it's fill value, which is also an
NC_INT.)
/**
* @ingroup variables
*
* Set the fill value for a variable.
*
* @note For netCDF classic, 64-bit offset, and CDF5 formats, it is
* allowed (but not good practice) to set the fill value after data
* have been written to the variable. In this case, unless the
* variable has been completely specified (without gaps in the data),
* any existing filled values will not be recognized as fill values by
* applications reading the data. Best practice is to set the fill
* value after the variable has been defined, but before any data have
* been written to that varibale. In NetCDF-4 files, this is enforced
* by the HDF5 library. For netCDF-4 files, an error is returned if
* the user attempts to set the fill value after writing data to the
* variable.
* @param ncid NetCDF ID, from a previous call to nc_open or
* nc_create.
* @param varid Variable ID.
* @param no_fill Set to NC_NOFILL to turn off fill mode for this
* variable. Set to NC_FILL (the default) to turn on fill mode for the
* variable.
* @param fill_value the fill value to be used for this variable. Must
* be the same type as the variable. This must point to enough free
* memory to hold one element of the data type of the variable. (For
* example, an NC_INT will require 4 bytes for it's fill value, which
* is also an NC_INT.)
*
* @returns ::NC_NOERR No error.
* @returns ::NC_EBADID Bad ID.
* @returns ::NC_ENOTINDEFINE Not in define mode. This is returned for
netCDF classic, 64-bit offset, or 64-bit data files, or for netCDF-4 files,
when they were created with NC_STRICT_NC3 flag. See \ref nc_create.
* @returns ::NC_ENOTINDEFINE Not in define mode. This is returned
* for netCDF classic, 64-bit offset, or 64-bit data files, or for
* netCDF-4 files, when they were created with NC_STRICT_NC3 flag. See
* @ref nc_create.
* @returns ::NC_EPERM Attempt to create object in read-only file.
\section nc_def_var_fill_example Example
In this example from libsrc4/tst_vars.c, a variable is defined, and
the fill mode turned off. Then nc_inq_fill() is used to check that the
setting is correct. Then some data are written to the variable. Since
the data that are written do not cover the full extent of the
variable, the missing values will just be random. If fill value mode
was turned on, the missing values would get the fill value.
\code
* @returns ::NC_ELATEDEF (NetCDF-4 only). Returned when user attempts
* to set fill value after data are written.
* @returns ::NC_EGLOBAL Attempt to set fill value on NC_GLOBAL.
*
* @section nc_def_var_fill_example Example
*
* In this example from libsrc4/tst_vars.c, a variable is defined, and
* the fill mode turned off. Then nc_inq_fill() is used to check that
* the setting is correct. Then some data are written to the
* variable. Since the data that are written do not cover the full
* extent of the variable, the missing values will just be random. If
* fill value mode was turned on, the missing values would get the
* fill value.
*
@code
#define DIM7_LEN 2
#define DIM7_NAME "dim_7_from_Indiana"
#define VAR7_NAME "var_7_from_Idaho"
@ -608,7 +623,8 @@ was turned on, the missing values would get the fill value.
if (nc_get_var1_ushort(ncid, varid, index, &ushort_data_in)) ERR;
if (nc_close(ncid)) ERR;
\endcode
@endcode
* @author Glenn Davis, Ed Hartnett, Dennis Heimbigner
*/
int
nc_def_var_fill(int ncid, int varid, int no_fill, const void *fill_value)
@ -617,7 +633,7 @@ nc_def_var_fill(int ncid, int varid, int no_fill, const void *fill_value)
int stat = NC_check_id(ncid,&ncp);
if(stat != NC_NOERR) return stat;
/* Dennis Heimbigner: (Using NC_GLOBAL is ilegal, as this API) has no
/* Dennis Heimbigner: Using NC_GLOBAL is illegal, as this API has no
* provision for specifying the type of the fillvalue, it must of necessity
* be using the type of the variable to interpret the bytes of the
* fill_value argument.

View File

@ -17,6 +17,7 @@
#define DIM_LEN 10
#define VAR_NAME "Copernicus_var"
#define DIM_NAME "Copernicus_dim"
#define NUM_FILL_WRITE_TESTS 2
/* Determine how many formats are available, and what they are. */
void
@ -103,7 +104,7 @@ main(int argc, char **argv)
printf("\n*** Testing netcdf format functions.\n");
{
int ncid;
int f;
int f, d;
int format[MAX_NUM_FORMATS];
int num_formats;
@ -160,20 +161,51 @@ main(int argc, char **argv)
if (nc_close(ncid)) ERR;
}
SUMMARIZE_ERR;
printf("*** testing NC_ELATEFILL errors with format %d...", format[f]);
for (d = 0; d < NUM_FILL_WRITE_TESTS; d++)
{
printf("*** testing late fill handling with format %d writing %d...", format[f], d);
char file_name[NC_MAX_NAME + 1];
int dimid, varid;
size_t index = {DIM_LEN - 1};
int data = TEST_VAL_42;
int data_in;
int fill_value = TEST_VAL_42 * 2;
sprintf(file_name, "%s_%d_elatefill.nc", FILE_NAME_BASE, format[f]);
/* Try to set fill mode after data have been written. */
sprintf(file_name, "%s_%d_%d_elatefill.nc", FILE_NAME_BASE, format[f], d);
if (nc_set_default_format(format[f], NULL)) ERR;
if (nc_create(file_name, 0, &ncid)) ERR;
if (nc_def_dim(ncid, DIM_NAME, DIM_LEN, &dimid)) ERR;
if (nc_def_var(ncid, VAR_NAME, NC_INT, NDIM1, &dimid, &varid)) ERR;
if (nc_enddef(ncid)) ERR;
/* For netCDF-4, we don't actually have to write data to
* prevent future setting of the fill value. Once the user
* leaves calls enddef after defining a var, fill values
* can no longer be set. */
if (d)
if (nc_put_var1_int(ncid, varid, &index, &data)) ERR;
if (nc_redef(ncid)) ERR;
/* Setting the fill value after data are written is
* allowed in classic formats, but not netcdf-4. */
if (format[f] == NC_FORMAT_CLASSIC || format[f] == NC_FORMAT_64BIT_OFFSET ||
format[f] == NC_FORMAT_CDF5)
{
if (nc_def_var_fill(ncid, varid, NC_FILL, &fill_value)) ERR;
}
else
{
if (nc_def_var_fill(ncid, varid, NC_FILL, &fill_value) != NC_ELATEDEF) ERR;
}
if (nc_enddef(ncid)) ERR;
if (nc_close(ncid)) ERR;
}
SUMMARIZE_ERR;
/* Open the file and check data. */
if (nc_open(file_name, NC_NOWRITE, &ncid)) ERR;
if (nc_get_var1_int(ncid, varid, &index, &data_in)) ERR;
if (data_in != (d ? data : NC_FILL_INT)) ERR;
if (nc_close(ncid)) ERR;
SUMMARIZE_ERR;
} /* next fill val write test */
} /* next format */
}
FINAL_RESULTS;