netcdf-c/nc_test4/tst_interops5.c
Dennis Heimbigner 3ffe7be446 Enhance/Fix filter support
re: Discussion https://github.com/Unidata/netcdf-c/discussions/2214

The primary change is to support so-called "standard filters".
A standard filter is one that is defined by the following
netcdf-c API:
````
int nc_def_var_XXX(int ncid, int varid, size_t nparams, unsigned* params);
int nc_inq_var_XXXX(int ncid, int varid, int* usefilterp, unsigned* params);
````
So for example, zstandard would be a standard filter by defining
the functions *nc_def_var_zstandard* and *nc_inq_var_zstandard*.

In order to define these functions, we need a new dispatch function:
````
int nc_inq_filter_avail(int ncid, unsigned filterid);
````
This function, combined with the existing filter API can be used
to implement arbitrary standard filters using a simple code pattern.
Note that I would have preferred that this function return a list
of all available filters, but HDF5 does not support that functionality.

So this PR implements the dispatch function and implements
the following standard functions:
    + bzip2
    + zstandard
    + blosc
Specific test cases are also provided for HDF5 and NCZarr.
Over time, other specific standard filters will be defined.

## Primary Changes
* Add nc_inq_filter_avail() to netcdf-c API.
* Add standard filter implementations to test use of *nc_inq_filter_avail*.
* Bump the dispatch table version number and add to all the relevant
   dispatch tables (libsrc, libsrcp, etc).
* Create a program to invoke nc_inq_filter_avail so that it is accessible
  to shell scripts.
* Cleanup szip support to properly support szip
  when HDF5 is disabled. This involves detecting
  libsz separately from testing if HDF5 supports szip.
* Integrate shuffle and fletcher32 into the existing
  filter API. This means that, for example, nc_def_var_fletcher32
  is now a wrapper around nc_def_var_filter.
* Extend the Codec defaulting to allow multiple default shared libraries.

## Misc. Changes
* Modify configure.ac/CMakeLists.txt to look for the relevant
  libraries implementing standard filters.
* Modify libnetcdf.settings to list available standard filters
  (including deflate and szip).
* Add CMake test modules to locate libbz2 and libzstd.
* Cleanup the HDF5 memory manager function use in the plugins.
* remove unused file include//ncfilter.h
* remove tests for the HDF5 memory operations e.g. H5allocate_memory.
* Add flag to ncdump to force use of _Filter instead of _Deflate
  or _Shuffle or _Fletcher32. Used for testing.
2022-03-14 12:39:37 -06:00

279 lines
9.3 KiB
C

/* This is part of the netCDF package. Copyright 2005-2019, University
Corporation for Atmospheric Research/Unidata. See COPYRIGHT file
for conditions of use.
Test that HDF5 and NetCDF-4 can read and write the same file.
Ed Hartnett
*/
#include <config.h>
#include <nc_tests.h>
#include "err_macros.h"
#include <hdf5.h>
#include <H5DSpublic.h>
#define FILE_NAME "tst_interops5.h5"
int
main(int argc, char **argv)
{
printf("\n*** Testing HDF5/NetCDF-4 interoperability...\n");
printf("*** testing HDF5 compatibility...");
{
#define GRPA_NAME "grpa"
#define VAR_NAME "vara"
#define NDIMS 2
int nrowCur = 7; /* current size */
int ncolCur = 3;
int nrowMax = nrowCur + 0; /* maximum size */
int ncolMax = ncolCur + 0;
hid_t xdimId;
hid_t ydimId;
hsize_t xscaleDims[1];
hsize_t yscaleDims[1];
hid_t xdimSpaceId, spaceId;
hid_t fileId;
hid_t fapl;
hsize_t curDims[2];
hsize_t maxDims[2];
hid_t dataTypeId, dsPropertyId, grpaId, grpaPropId, dsId;
hid_t ydimSpaceId;
const char * dimNameBase
= "This is a netCDF dimension but not a netCDF variable.";
char dimNameBuf[1000];
char *varaName = "/grpa/vara";
short amat[nrowCur][ncolCur];
int ii, jj;
xscaleDims[0] = nrowCur;
yscaleDims[0] = ncolCur;
if ((xdimSpaceId = H5Screate_simple(1, xscaleDims, NULL)) < 0) ERR;
/* With the WEAK close degree, the HDF5 file close will not fail if
* anything is left open. */
if ((fapl = H5Pcreate(H5P_FILE_ACCESS)) < 0) ERR;
if (H5Pset_fclose_degree(fapl, H5F_CLOSE_WEAK)) ERR;
/* Create file */
if((fileId = H5Fcreate(FILE_NAME, H5F_ACC_TRUNC,
H5Pcreate(H5P_FILE_CREATE), fapl)) < 0) ERR;
if (H5Pclose(fapl) < 0) ERR;
/* Create data space */
curDims[0] = nrowCur;
curDims[1] = ncolCur;
maxDims[0] = nrowMax;
maxDims[1] = ncolMax;
if ((spaceId = H5Screate_simple(2, curDims, maxDims)) < 0) ERR;
if ((dataTypeId = H5Tcopy(H5T_NATIVE_SHORT)) < 0) ERR;
if ((dsPropertyId = H5Pcreate(H5P_DATASET_CREATE)) < 0) ERR;
if ((grpaPropId = H5Pcreate(H5P_GROUP_CREATE)) < 0) ERR;
if ((grpaId = H5Gcreate2(fileId, GRPA_NAME, H5P_DEFAULT,
grpaPropId, H5P_DEFAULT)) < 0) ERR;
if (H5Pclose(grpaPropId) < 0) ERR;
/* Create vara dataset */
if ((dsId = H5Dcreate2(fileId, varaName, dataTypeId, spaceId,
H5P_DEFAULT, dsPropertyId,
H5P_DEFAULT)) < 0) ERR;
if (H5Pclose(dsPropertyId) < 0) ERR;
if (H5Tclose(dataTypeId) < 0) ERR;
if ((ydimSpaceId = H5Screate_simple(1, yscaleDims, NULL)) < 0) ERR;
/* Create xdim dimension dataset */
if ((xdimId = H5Dcreate2(fileId, "/xdim", H5T_IEEE_F32BE,
xdimSpaceId, H5P_DEFAULT, H5P_DEFAULT,
H5P_DEFAULT)) < 0) ERR;
if (H5Sclose(xdimSpaceId) < 0) ERR;
/* Create ydim dimension dataset */
if ((ydimId = H5Dcreate2(fileId, "/ydim", H5T_IEEE_F32BE,
ydimSpaceId, H5P_DEFAULT, H5P_DEFAULT,
H5P_DEFAULT)) < 0) ERR;
if (H5Sclose(ydimSpaceId) < 0) ERR;
/* Create xdim scale */
sprintf(dimNameBuf, "%s%10d", dimNameBase, nrowCur);
if (H5DSset_scale(xdimId, dimNameBuf) < 0) ERR;
/* Create ydim scale */
sprintf(dimNameBuf, "%s%10d", dimNameBase, ncolCur);
if (H5DSset_scale(ydimId, dimNameBuf) < 0) ERR;
/* Attach dimension scales to the dataset */
if (H5DSattach_scale(dsId, xdimId, 0) < 0) ERR;
if (H5DSattach_scale(dsId, ydimId, 1) < 0) ERR;
/* Close stuff. */
if (H5Dclose(xdimId) < 0) ERR;
if (H5Dclose(ydimId) < 0) ERR;
if (H5Dclose(dsId) < 0) ERR;
if (H5Gclose(grpaId) < 0) ERR;
if (H5Sclose(spaceId) < 0) ERR;
if (H5Fclose(fileId) < 0) ERR;
/* Create some data */
for (ii = 0; ii < nrowCur; ii++)
for (jj = 0; jj < ncolCur; jj++)
amat[ii][jj] = 100 * ii + jj;
/* Re-open file */
if ((fileId = H5Fopen(FILE_NAME, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) ERR;
if ((grpaId = H5Gopen2(fileId, GRPA_NAME, H5P_DEFAULT)) < 0) ERR;
if ((dsId = H5Dopen2(grpaId, varaName, H5P_DEFAULT)) < 0) ERR;
/* Write dataset */
if (H5Dwrite(dsId, H5T_NATIVE_SHORT, H5S_ALL, H5S_ALL, H5P_DEFAULT,
amat) < 0) ERR;
/* Write dimension values for both xdim, ydim */
{
short xydimMat[ nrowCur >= ncolCur ? nrowCur : ncolCur];
for (ii = 0; ii < nrowCur; ii++)
xydimMat[ii] = 0; /*#### 100 * ii; */
/* Write xdim */
if ((xdimId = H5Dopen2(fileId, "/xdim", H5P_DEFAULT)) < 0) ERR;
if (H5Dwrite(xdimId, H5T_NATIVE_SHORT, H5S_ALL, H5S_ALL,
H5P_DEFAULT, xydimMat) < 0) ERR;
if (H5Dclose(xdimId) < 0) ERR;
/* Write ydim */
if ((ydimId = H5Dopen2(fileId, "/ydim", H5P_DEFAULT)) < 0) ERR;
if (H5Dwrite(ydimId, H5T_NATIVE_SHORT, H5S_ALL, H5S_ALL,
H5P_DEFAULT, xydimMat) < 0) ERR;
if (H5Dclose(ydimId) < 0) ERR;
}
if (H5Dclose(dsId) < 0) ERR;
if (H5Gclose(grpaId) < 0) ERR;
if (H5Fclose(fileId) < 0) ERR;
{
int ncid, grpid, nvars, ngatts, ndims, unlimdimid, ngrps;
char name_in[NC_MAX_NAME + 1];
nc_type xtype_in;
int ndims_in, natts_in, dimid_in[NDIMS];
/* nc_set_log_level(5);*/
if (nc_open(FILE_NAME, NC_NOWRITE, &ncid)) ERR;
if (nc_inq(ncid, &ndims, &nvars, &ngatts, &unlimdimid)) ERR;
if (ndims != 2 || nvars != 0 || ngatts != 0 || unlimdimid != -1) ERR;
if (nc_inq_grps(ncid, &ngrps, &grpid)) ERR;
if (ngrps != 1) ERR;
if (nc_inq(grpid, &ndims, &nvars, &ngatts, &unlimdimid)) ERR;
if (ndims != 0 || nvars != 1 || ngatts != 0 || unlimdimid != -1) ERR;
if (nc_inq_var(grpid, 0, name_in, &xtype_in, &ndims_in, dimid_in,
&natts_in)) ERR;
if (strcmp(name_in, VAR_NAME) || xtype_in != NC_SHORT || ndims_in != NDIMS ||
dimid_in[0] != 0 || dimid_in[1] != 1 || natts_in != 0) ERR;
if (nc_close(ncid)) ERR;
}
}
SUMMARIZE_ERR;
#ifdef HAVE_H5Z_SZIP
printf("*** testing HDF5 compatibility with szip...");
{
#define DEFLATE_LEVEL 9
#define MAX_NAME 100
#define NUM_CD_ELEM 10
/* HDF5 defines this... */
#define DEFLATE_NAME "deflate"
#define DIM1_LEN 3000
#define GRP_NAME "George_Washington"
#define BATTLE_RECORD "Battle_Record"
hid_t fileid, grpid, spaceid, datasetid;
int data_out[DIM1_LEN], data_in[DIM1_LEN];
hsize_t dims[1] = {DIM1_LEN};
hid_t propid;
char name_in[MAX_NAME + 1];
int ncid, ndims_in, nvars_in, ngatts_in, unlimdimid_in, ngrps_in;
int nc_grpid;
int dimid_in[1], natts_in;
nc_type xtype_in;
int i;
for (i = 0; i < DIM1_LEN; i++)
data_out[i] = i;
/* Open file and create group. */
if ((fileid = H5Fcreate(FILE_NAME, H5F_ACC_TRUNC, H5P_DEFAULT,
H5P_DEFAULT)) < 0) ERR;
if ((grpid = H5Gcreate1(fileid, GRP_NAME, 0)) < 0) ERR;
/* Write an array of bools, with szip compression. */
if ((propid = H5Pcreate(H5P_DATASET_CREATE)) < 0) ERR;
if (H5Pset_layout(propid, H5D_CHUNKED)) ERR;
if (H5Pset_chunk(propid, 1, dims)) ERR;
if (H5Pset_szip(propid, H5_SZIP_EC_OPTION_MASK, 32)) ERR;
if ((spaceid = H5Screate_simple(1, dims, dims)) < 0) ERR;
if ((datasetid = H5Dcreate1(grpid, BATTLE_RECORD, H5T_NATIVE_INT,
spaceid, propid)) < 0) ERR;
if (H5Dwrite(datasetid, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT,
data_out) < 0) ERR;
if (H5Dclose(datasetid) < 0 ||
H5Pclose(propid) < 0 ||
H5Sclose(spaceid) < 0 ||
H5Gclose(grpid) < 0 ||
H5Fclose(fileid) < 0)
ERR;
/* Open the file with netCDF and check it. */
if (nc_open(FILE_NAME, NC_NOWRITE, &ncid)) ERR;
if (nc_inq(ncid, &ndims_in, &nvars_in, &ngatts_in, &unlimdimid_in)) ERR;
if (ndims_in != 0 || nvars_in != 0 || ngatts_in != 0 || unlimdimid_in != -1) ERR;
if (nc_inq_grps(ncid, &ngrps_in, &nc_grpid)) ERR;
if (ngrps_in != 1) ERR;
if (nc_inq(nc_grpid, &ndims_in, &nvars_in, &ngatts_in, &unlimdimid_in)) ERR;
if (ndims_in != 1 || nvars_in != 1 || ngatts_in != 0 || unlimdimid_in != -1) ERR;
/* Check the variable. */
if (nc_inq_var(nc_grpid, 0, name_in, &xtype_in, &ndims_in, dimid_in,
&natts_in)) ERR;
if (strcmp(name_in, BATTLE_RECORD) || xtype_in != NC_INT || ndims_in != 1 ||
dimid_in[0] != 0 || natts_in != 0) ERR;
/* Check the data. */
if (nc_get_var(nc_grpid, 0, data_in)) ERR;
for (i = 0; i < DIM1_LEN; i++)
if (data_in[i] != data_out[i]) ERR;
if (nc_close(ncid)) ERR;
}
SUMMARIZE_ERR;
#endif /* HAVE_H5Z_SZIP */
/* This test suggested by user brentd42 to find a memory problem in
* function rec_read_metadata(). This test demonstrates the bug on
* address sanitizer runs. See
* https://github.com/Unidata/netcdf-c/issues/1558. */
printf("*** testing error when opening HDF5 file without creating ordering...");
{
hid_t file_hid;
int ncid;
char *filename = "tst_interops5.h5";
/* Create a HDF5 file, but don't set creation ordering on. */
file_hid = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
H5Fclose(file_hid);
/* Open the file with netCDF. */
nc_set_log_level(3);
if (nc_open(filename, NC_WRITE, &ncid) != NC_ECANTWRITE) ERR;
}
SUMMARIZE_ERR;
FINAL_RESULTS;
}