mirror of
https://github.com/Unidata/netcdf-c.git
synced 2024-11-27 07:30:33 +08:00
moved put and get vars functions from nc4hdf5.c to hdf5var.c
This commit is contained in:
parent
5e9ffcaab3
commit
2e7a7ea94e
@ -1248,3 +1248,830 @@ NC4_get_vars(int ncid, int varid, const size_t *startp,
|
||||
return nc4_get_vars(nc, ncid, varid, startp, countp, stridep, memtype,
|
||||
(void *)ip);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal Do some common check for nc4_put_vara and
|
||||
* nc4_get_vara. These checks have to be done when both reading and
|
||||
* writing data.
|
||||
*
|
||||
* @param mem_nc_type Pointer to type of data in memory.
|
||||
* @param var Pointer to var info struct.
|
||||
* @param h5 Pointer to HDF5 file info struct.
|
||||
*
|
||||
* @return ::NC_NOERR No error.
|
||||
* @author Ed Hartnett
|
||||
*/
|
||||
static int
|
||||
check_for_vara(nc_type *mem_nc_type, NC_VAR_INFO_T *var, NC_FILE_INFO_T *h5)
|
||||
{
|
||||
int retval;
|
||||
|
||||
/* If mem_nc_type is NC_NAT, it means we want to use the file type
|
||||
* as the mem type as well. */
|
||||
assert(mem_nc_type);
|
||||
if (*mem_nc_type == NC_NAT)
|
||||
*mem_nc_type = var->type_info->hdr.id;
|
||||
assert(*mem_nc_type);
|
||||
|
||||
/* No NC_CHAR conversions, you pervert! */
|
||||
if (var->type_info->hdr.id != *mem_nc_type &&
|
||||
(var->type_info->hdr.id == NC_CHAR || *mem_nc_type == NC_CHAR))
|
||||
return NC_ECHAR;
|
||||
|
||||
/* If we're in define mode, we can't read or write data. */
|
||||
if (h5->flags & NC_INDEF)
|
||||
{
|
||||
if (h5->cmode & NC_CLASSIC_MODEL)
|
||||
return NC_EINDEFINE;
|
||||
if ((retval = nc4_enddef_netcdf4_file(h5)))
|
||||
return retval;
|
||||
}
|
||||
|
||||
return NC_NOERR;
|
||||
}
|
||||
|
||||
#ifdef LOGGING
|
||||
/**
|
||||
* @intarnal Print some debug info about dimensions to the log.
|
||||
*/
|
||||
static void
|
||||
log_dim_info(NC_VAR_INFO_T *var, hsize_t *fdims, hsize_t *fmaxdims,
|
||||
hsize_t *start, hsize_t *count)
|
||||
{
|
||||
int d2;
|
||||
|
||||
/* Print some debugging info... */
|
||||
LOG((4, "%s: var name %s ndims %d", __func__, var->hdr.name, var->ndims));
|
||||
LOG((4, "File space, and requested:"));
|
||||
for (d2 = 0; d2 < var->ndims; d2++)
|
||||
{
|
||||
LOG((4, "fdims[%d]=%Ld fmaxdims[%d]=%Ld", d2, fdims[d2], d2,
|
||||
fmaxdims[d2]));
|
||||
LOG((4, "start[%d]=%Ld count[%d]=%Ld", d2, start[d2], d2, count[d2]));
|
||||
}
|
||||
}
|
||||
#endif /* LOGGING */
|
||||
|
||||
#ifdef USE_PARALLEL4
|
||||
/**
|
||||
* @internal Set the parallel access for a var (collective
|
||||
* vs. independent).
|
||||
*
|
||||
* @param h5 Pointer to HDF5 file info struct.
|
||||
* @param var Pointer to var info struct.
|
||||
* @param xfer_plistid H5FD_MPIO_COLLECTIVE or H5FD_MPIO_INDEPENDENT.
|
||||
*
|
||||
* @returns NC_NOERR No error.
|
||||
* @author Ed Hartnett
|
||||
*/
|
||||
static int
|
||||
set_par_access(NC_FILE_INFO_T *h5, NC_VAR_INFO_T *var, hid_t xfer_plistid)
|
||||
{
|
||||
/* If netcdf is built with parallel I/O, then parallel access can
|
||||
* be used, and, if this file was opened or created for parallel
|
||||
* access, we need to set the transfer mode. */
|
||||
if (h5->parallel)
|
||||
{
|
||||
H5FD_mpio_xfer_t hdf5_xfer_mode;
|
||||
|
||||
/* Decide on collective or independent. */
|
||||
hdf5_xfer_mode = (var->parallel_access != NC_INDEPENDENT) ?
|
||||
H5FD_MPIO_COLLECTIVE : H5FD_MPIO_INDEPENDENT;
|
||||
|
||||
/* Set the mode in the transfer property list. */
|
||||
if (H5Pset_dxpl_mpio(xfer_plistid, hdf5_xfer_mode) < 0)
|
||||
return NC_EPARINIT;
|
||||
|
||||
LOG((4, "%s: %d H5FD_MPIO_COLLECTIVE: %d H5FD_MPIO_INDEPENDENT: %d",
|
||||
__func__, (int)hdf5_xfer_mode, H5FD_MPIO_COLLECTIVE, H5FD_MPIO_INDEPENDENT));
|
||||
}
|
||||
return NC_NOERR;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @internal Write a strided array of data to a variable.
|
||||
*
|
||||
* @param nc Pointer to the file NC struct.
|
||||
* @param ncid File ID.
|
||||
* @param varid Variable ID.
|
||||
* @param startp Array of start indices. Will default to starts of 0
|
||||
* if NULL.
|
||||
* @param countp Array of counts. Will default to counts of 1 if NULL.
|
||||
* @param stridep Array of strides. Will default to strides of 1 if
|
||||
* NULL.
|
||||
* @param mem_nc_type The type of the data in memory.
|
||||
* @param data The data to be written.
|
||||
*
|
||||
* @returns ::NC_NOERR No error.
|
||||
* @returns ::NC_EBADID Bad ncid.
|
||||
* @returns ::NC_ENOTVAR Var not found.
|
||||
* @returns ::NC_EHDFERR HDF5 function returned error.
|
||||
* @returns ::NC_EINVALCOORDS Incorrect start.
|
||||
* @returns ::NC_EEDGE Incorrect start/count.
|
||||
* @returns ::NC_ENOMEM Out of memory.
|
||||
* @returns ::NC_EMPI MPI library error (parallel only)
|
||||
* @returns ::NC_ECANTEXTEND Can't extend dimension for write.
|
||||
* @returns ::NC_ERANGE Data conversion error.
|
||||
* @author Ed Hartnett, Dennis Heimbigner
|
||||
*/
|
||||
int
|
||||
nc4_put_vars(NC *nc, int ncid, int varid, const size_t *startp,
|
||||
const size_t *countp, const ptrdiff_t* stridep,
|
||||
nc_type mem_nc_type, void *data)
|
||||
{
|
||||
NC_GRP_INFO_T *grp;
|
||||
NC_FILE_INFO_T *h5;
|
||||
NC_VAR_INFO_T *var;
|
||||
NC_DIM_INFO_T *dim;
|
||||
hid_t file_spaceid = 0, mem_spaceid = 0, xfer_plistid = 0;
|
||||
long long unsigned xtend_size[NC_MAX_VAR_DIMS];
|
||||
hsize_t fdims[NC_MAX_VAR_DIMS], fmaxdims[NC_MAX_VAR_DIMS];
|
||||
hsize_t start[NC_MAX_VAR_DIMS], count[NC_MAX_VAR_DIMS];
|
||||
hsize_t stride[NC_MAX_VAR_DIMS];
|
||||
char *name_to_use;
|
||||
int need_to_extend = 0;
|
||||
#ifdef USE_PARALLEL4
|
||||
int extend_possible = 0;
|
||||
#endif
|
||||
int retval = NC_NOERR, range_error = 0, i, d2;
|
||||
void *bufr = NULL;
|
||||
int need_to_convert = 0;
|
||||
int zero_count = 0; /* true if a count is zero */
|
||||
size_t len = 1;
|
||||
|
||||
/* Find our metadata for this file, group, and var. */
|
||||
assert(nc);
|
||||
if ((retval = nc4_find_g_var_nc(nc, ncid, varid, &grp, &var)))
|
||||
return retval;
|
||||
h5 = NC4_DATA(nc);
|
||||
assert(grp && h5 && var && var->hdr.name);
|
||||
|
||||
LOG((3, "%s: var->hdr.name %s mem_nc_type %d", __func__,
|
||||
var->hdr.name, mem_nc_type));
|
||||
|
||||
/* Check some stuff about the type and the file. If the file must
|
||||
* be switched from define mode, it happens here. */
|
||||
if ((retval = check_for_vara(&mem_nc_type, var, h5)))
|
||||
return retval;
|
||||
|
||||
/* Convert from size_t and ptrdiff_t to hssize_t, and hsize_t. */
|
||||
/* Also do sanity checks */
|
||||
for (i = 0; i < var->ndims; i++)
|
||||
{
|
||||
/* Check for non-positive stride. */
|
||||
if (stridep && stridep[i] <= 0)
|
||||
return NC_ESTRIDE;
|
||||
|
||||
start[i] = (startp == NULL ? 0 : startp[i]);
|
||||
count[i] = (countp == NULL ? 1 : countp[i]);
|
||||
stride[i] = (stridep == NULL ? 1 : stridep[i]);
|
||||
|
||||
/* Check to see if any counts are zero. */
|
||||
if (!count[i])
|
||||
zero_count++;
|
||||
}
|
||||
|
||||
/* Open this dataset if necessary, also checking for a weird case:
|
||||
* a non-coordinate (and non-scalar) variable that has the same
|
||||
* name as a dimension. */
|
||||
if (var->hdf5_name && strlen(var->hdf5_name) >= strlen(NON_COORD_PREPEND) &&
|
||||
strncmp(var->hdf5_name, NON_COORD_PREPEND, strlen(NON_COORD_PREPEND)) == 0 &&
|
||||
var->ndims)
|
||||
name_to_use = var->hdf5_name;
|
||||
else
|
||||
name_to_use = var->hdr.name;
|
||||
if (!var->hdf_datasetid)
|
||||
if ((var->hdf_datasetid = H5Dopen2(grp->hdf_grpid, name_to_use, H5P_DEFAULT)) < 0)
|
||||
return NC_ENOTVAR;
|
||||
|
||||
/* Get file space of data. */
|
||||
if ((file_spaceid = H5Dget_space(var->hdf_datasetid)) < 0)
|
||||
BAIL(NC_EHDFERR);
|
||||
|
||||
/* Get the sizes of all the dims and put them in fdims. */
|
||||
if (H5Sget_simple_extent_dims(file_spaceid, fdims, fmaxdims) < 0)
|
||||
BAIL(NC_EHDFERR);
|
||||
|
||||
#ifdef LOGGING
|
||||
log_dim_info(var, fdims, fmaxdims, start, count);
|
||||
#endif
|
||||
|
||||
/* Check dimension bounds. Remember that unlimited dimensions can
|
||||
* put data beyond their current length. */
|
||||
for (d2 = 0; d2 < var->ndims; d2++)
|
||||
{
|
||||
hsize_t endindex = start[d2] + stride[d2] * (count[d2] - 1); /* last index written */
|
||||
dim = var->dim[d2];
|
||||
assert(dim && dim->hdr.id == var->dimids[d2]);
|
||||
if (count[d2] == 0)
|
||||
endindex = start[d2]; /* fixup for zero read count */
|
||||
if (!dim->unlimited)
|
||||
{
|
||||
#ifdef RELAX_COORD_BOUND
|
||||
/* Allow start to equal dim size if count is zero. */
|
||||
if (start[d2] > (hssize_t)fdims[d2] ||
|
||||
(start[d2] == (hssize_t)fdims[d2] && count[d2] > 0))
|
||||
BAIL_QUIET(NC_EINVALCOORDS);
|
||||
if (!zero_count && endindex >= fdims[d2])
|
||||
BAIL_QUIET(NC_EEDGE);
|
||||
#else
|
||||
if (start[d2] >= (hssize_t)fdims[d2])
|
||||
BAIL_QUIET(NC_EINVALCOORDS);
|
||||
if (endindex >= fdims[d2])
|
||||
BAIL_QUIET(NC_EEDGE);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* Now you would think that no one would be crazy enough to write
|
||||
a scalar dataspace with one of the array function calls, but you
|
||||
would be wrong. So let's check to see if the dataset is
|
||||
scalar. If it is, we won't try to set up a hyperslab. */
|
||||
if (H5Sget_simple_extent_type(file_spaceid) == H5S_SCALAR)
|
||||
{
|
||||
if ((mem_spaceid = H5Screate(H5S_SCALAR)) < 0)
|
||||
BAIL(NC_EHDFERR);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (H5Sselect_hyperslab(file_spaceid, H5S_SELECT_SET, start, stride,
|
||||
count, NULL) < 0)
|
||||
BAIL(NC_EHDFERR);
|
||||
|
||||
/* Create a space for the memory, just big enough to hold the slab
|
||||
we want. */
|
||||
if ((mem_spaceid = H5Screate_simple(var->ndims, count, NULL)) < 0)
|
||||
BAIL(NC_EHDFERR);
|
||||
}
|
||||
|
||||
/* Are we going to convert any data? (No converting of compound or
|
||||
* opaque types.) */
|
||||
if (mem_nc_type != var->type_info->hdr.id &&
|
||||
mem_nc_type != NC_COMPOUND && mem_nc_type != NC_OPAQUE)
|
||||
{
|
||||
size_t file_type_size;
|
||||
|
||||
/* We must convert - allocate a buffer. */
|
||||
need_to_convert++;
|
||||
if (var->ndims)
|
||||
for (d2=0; d2<var->ndims; d2++)
|
||||
len *= countp[d2];
|
||||
LOG((4, "converting data for var %s type=%d len=%d", var->hdr.name,
|
||||
var->type_info->hdr.id, len));
|
||||
|
||||
/* Later on, we will need to know the size of this type in the
|
||||
* file. */
|
||||
assert(var->type_info->size);
|
||||
file_type_size = var->type_info->size;
|
||||
|
||||
/* If we're reading, we need bufr to have enough memory to store
|
||||
* the data in the file. If we're writing, we need bufr to be
|
||||
* big enough to hold all the data in the file's type. */
|
||||
if (len > 0)
|
||||
if (!(bufr = malloc(len * file_type_size)))
|
||||
BAIL(NC_ENOMEM);
|
||||
}
|
||||
else
|
||||
bufr = data;
|
||||
|
||||
/* Create the data transfer property list. */
|
||||
if ((xfer_plistid = H5Pcreate(H5P_DATASET_XFER)) < 0)
|
||||
BAIL(NC_EHDFERR);
|
||||
|
||||
#ifdef USE_PARALLEL4
|
||||
/* Set up parallel I/O, if needed. */
|
||||
if ((retval = set_par_access(h5, var, xfer_plistid)))
|
||||
BAIL(retval);
|
||||
#endif
|
||||
|
||||
/* Read this hyperslab from memory. */
|
||||
/* Does the dataset have to be extended? If it's already
|
||||
extended to the required size, it will do no harm to reextend
|
||||
it to that size. */
|
||||
if (var->ndims)
|
||||
{
|
||||
for (d2 = 0; d2 < var->ndims; d2++)
|
||||
{
|
||||
hsize_t endindex = start[d2] + stride[d2] * (count[d2] - 1); /* last index written */
|
||||
if (count[d2] == 0)
|
||||
endindex = start[d2];
|
||||
dim = var->dim[d2];
|
||||
assert(dim && dim->hdr.id == var->dimids[d2]);
|
||||
if (dim->unlimited)
|
||||
{
|
||||
#ifdef USE_PARALLEL4
|
||||
extend_possible = 1;
|
||||
#endif
|
||||
if (!zero_count && endindex >= fdims[d2])
|
||||
{
|
||||
xtend_size[d2] = (long long unsigned)(endindex+1);
|
||||
need_to_extend++;
|
||||
}
|
||||
else
|
||||
xtend_size[d2] = (long long unsigned)fdims[d2];
|
||||
|
||||
if (!zero_count && endindex >= dim->len)
|
||||
{
|
||||
dim->len = endindex+1;
|
||||
dim->extended = NC_TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
xtend_size[d2] = (long long unsigned)dim->len;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_PARALLEL4
|
||||
/* Check if anyone wants to extend */
|
||||
if (extend_possible && h5->parallel &&
|
||||
NC_COLLECTIVE == var->parallel_access)
|
||||
{
|
||||
/* Form consensus opinion among all processes about whether to perform
|
||||
* collective I/O
|
||||
*/
|
||||
if (MPI_SUCCESS != MPI_Allreduce(MPI_IN_PLACE, &need_to_extend, 1,
|
||||
MPI_INT, MPI_BOR, h5->comm))
|
||||
BAIL(NC_EMPI);
|
||||
}
|
||||
#endif /* USE_PARALLEL4 */
|
||||
|
||||
/* If we need to extend it, we also need a new file_spaceid
|
||||
to reflect the new size of the space. */
|
||||
if (need_to_extend)
|
||||
{
|
||||
LOG((4, "extending dataset"));
|
||||
#ifdef USE_PARALLEL4
|
||||
if (h5->parallel)
|
||||
{
|
||||
if (NC_COLLECTIVE != var->parallel_access)
|
||||
BAIL(NC_ECANTEXTEND);
|
||||
|
||||
/* Reach consensus about dimension sizes to extend to */
|
||||
if (MPI_SUCCESS != MPI_Allreduce(MPI_IN_PLACE, xtend_size, var->ndims,
|
||||
MPI_UNSIGNED_LONG_LONG, MPI_MAX,
|
||||
h5->comm))
|
||||
BAIL(NC_EMPI);
|
||||
}
|
||||
#endif /* USE_PARALLEL4 */
|
||||
/* Convert xtend_size back to hsize_t for use with H5Dset_extent */
|
||||
for (d2 = 0; d2 < var->ndims; d2++)
|
||||
fdims[d2] = (hsize_t)xtend_size[d2];
|
||||
|
||||
if (H5Dset_extent(var->hdf_datasetid, fdims) < 0)
|
||||
BAIL(NC_EHDFERR);
|
||||
if (file_spaceid > 0 && H5Sclose(file_spaceid) < 0)
|
||||
BAIL2(NC_EHDFERR);
|
||||
if ((file_spaceid = H5Dget_space(var->hdf_datasetid)) < 0)
|
||||
BAIL(NC_EHDFERR);
|
||||
if (H5Sselect_hyperslab(file_spaceid, H5S_SELECT_SET,
|
||||
start, stride, count, NULL) < 0)
|
||||
BAIL(NC_EHDFERR);
|
||||
}
|
||||
}
|
||||
|
||||
/* Do we need to convert the data? */
|
||||
if (need_to_convert)
|
||||
{
|
||||
if ((retval = nc4_convert_type(data, bufr, mem_nc_type, var->type_info->hdr.id,
|
||||
len, &range_error, var->fill_value,
|
||||
(h5->cmode & NC_CLASSIC_MODEL))))
|
||||
BAIL(retval);
|
||||
}
|
||||
|
||||
/* Write the data. At last! */
|
||||
LOG((4, "about to H5Dwrite datasetid 0x%x mem_spaceid 0x%x "
|
||||
"file_spaceid 0x%x", var->hdf_datasetid, mem_spaceid, file_spaceid));
|
||||
if (H5Dwrite(var->hdf_datasetid, var->type_info->hdf_typeid,
|
||||
mem_spaceid, file_spaceid, xfer_plistid, bufr) < 0)
|
||||
BAIL(NC_EHDFERR);
|
||||
|
||||
/* Remember that we have written to this var so that Fill Value
|
||||
* can't be set for it. */
|
||||
if (!var->written_to)
|
||||
var->written_to = NC_TRUE;
|
||||
|
||||
/* For strict netcdf-3 rules, ignore erange errors between UBYTE
|
||||
* and BYTE types. */
|
||||
if ((h5->cmode & NC_CLASSIC_MODEL) &&
|
||||
(var->type_info->hdr.id == NC_UBYTE || var->type_info->hdr.id == NC_BYTE) &&
|
||||
(mem_nc_type == NC_UBYTE || mem_nc_type == NC_BYTE) &&
|
||||
range_error)
|
||||
range_error = 0;
|
||||
|
||||
exit:
|
||||
if (file_spaceid > 0 && H5Sclose(file_spaceid) < 0)
|
||||
BAIL2(NC_EHDFERR);
|
||||
if (mem_spaceid > 0 && H5Sclose(mem_spaceid) < 0)
|
||||
BAIL2(NC_EHDFERR);
|
||||
if (xfer_plistid && (H5Pclose(xfer_plistid) < 0))
|
||||
BAIL2(NC_EPARINIT);
|
||||
if (need_to_convert && bufr) free(bufr);
|
||||
|
||||
/* If there was an error return it, otherwise return any potential
|
||||
range error value. If none, return NC_NOERR as usual.*/
|
||||
if (retval)
|
||||
return retval;
|
||||
if (range_error)
|
||||
return NC_ERANGE;
|
||||
return NC_NOERR;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal Read a strided array of data from a variable.
|
||||
*
|
||||
* @param nc Pointer to the file NC struct.
|
||||
* @param ncid File ID.
|
||||
* @param varid Variable ID.
|
||||
* @param startp Array of start indices. Will default to starts of 0
|
||||
* if NULL.
|
||||
* @param countp Array of counts. Will default to counts of 1 if NULL.
|
||||
* @param stridep Array of strides. Will default to strides of 1 if
|
||||
* NULL.
|
||||
* @param mem_nc_type The type of the data in memory. (Convert to this
|
||||
* type from file type.)
|
||||
* @param data The data to be written.
|
||||
*
|
||||
* @returns ::NC_NOERR No error.
|
||||
* @returns ::NC_EBADID Bad ncid.
|
||||
* @returns ::NC_ENOTVAR Var not found.
|
||||
* @returns ::NC_EHDFERR HDF5 function returned error.
|
||||
* @returns ::NC_EINVALCOORDS Incorrect start.
|
||||
* @returns ::NC_EEDGE Incorrect start/count.
|
||||
* @returns ::NC_ENOMEM Out of memory.
|
||||
* @returns ::NC_EMPI MPI library error (parallel only)
|
||||
* @returns ::NC_ECANTEXTEND Can't extend dimension for write.
|
||||
* @returns ::NC_ERANGE Data conversion error.
|
||||
* @author Ed Hartnett, Dennis Heimbigner
|
||||
*/
|
||||
int
|
||||
nc4_get_vars(NC *nc, int ncid, int varid, const size_t *startp,
|
||||
const size_t *countp, const ptrdiff_t* stridep,
|
||||
nc_type mem_nc_type, void *data)
|
||||
{
|
||||
NC_GRP_INFO_T *grp;
|
||||
NC_FILE_INFO_T *h5;
|
||||
NC_VAR_INFO_T *var;
|
||||
NC_DIM_INFO_T *dim;
|
||||
hid_t file_spaceid = 0, mem_spaceid = 0;
|
||||
hid_t xfer_plistid = 0;
|
||||
size_t file_type_size;
|
||||
hsize_t *xtend_size = NULL, count[NC_MAX_VAR_DIMS];
|
||||
hsize_t fdims[NC_MAX_VAR_DIMS], fmaxdims[NC_MAX_VAR_DIMS];
|
||||
hsize_t start[NC_MAX_VAR_DIMS];
|
||||
hsize_t stride[NC_MAX_VAR_DIMS];
|
||||
char *name_to_use;
|
||||
void *fillvalue = NULL;
|
||||
int no_read = 0, provide_fill = 0;
|
||||
int fill_value_size[NC_MAX_VAR_DIMS];
|
||||
int scalar = 0, retval = NC_NOERR, range_error = 0, i, d2;
|
||||
void *bufr = NULL;
|
||||
int need_to_convert = 0;
|
||||
size_t len = 1;
|
||||
|
||||
/* Find our metadata for this file, group, and var. */
|
||||
assert(nc);
|
||||
if ((retval = nc4_find_g_var_nc(nc, ncid, varid, &grp, &var)))
|
||||
return retval;
|
||||
h5 = NC4_DATA(nc);
|
||||
assert(grp && h5 && var && var->hdr.name);
|
||||
|
||||
LOG((3, "%s: var->hdr.name %s mem_nc_type %d", __func__,
|
||||
var->hdr.name, mem_nc_type));
|
||||
|
||||
/* Check some stuff about the type and the file. */
|
||||
if ((retval = check_for_vara(&mem_nc_type, var, h5)))
|
||||
return retval;
|
||||
|
||||
/* Convert from size_t and ptrdiff_t to hsize_t. Also do sanity
|
||||
* checks. */
|
||||
for (i = 0; i < var->ndims; i++)
|
||||
{
|
||||
/* If any of the stride values are non-positive, fail. */
|
||||
if (stridep && stridep[i] <= 0)
|
||||
return NC_ESTRIDE;
|
||||
|
||||
start[i] = (startp == NULL ? 0 : startp[i]);
|
||||
count[i] = (countp == NULL ? 1 : countp[i]);
|
||||
stride[i] = (stridep == NULL ? 1 : stridep[i]);
|
||||
|
||||
/* if any of the count values are zero don't actually read. */
|
||||
if (count[i] == 0)
|
||||
no_read++;
|
||||
}
|
||||
|
||||
/* Open this dataset if necessary, also checking for a weird case:
|
||||
* a non-coordinate (and non-scalar) variable that has the same
|
||||
* name as a dimension. */
|
||||
if (var->hdf5_name && strlen(var->hdf5_name) >= strlen(NON_COORD_PREPEND) &&
|
||||
strncmp(var->hdf5_name, NON_COORD_PREPEND, strlen(NON_COORD_PREPEND)) == 0 &&
|
||||
var->ndims)
|
||||
name_to_use = var->hdf5_name;
|
||||
else
|
||||
name_to_use = var->hdr.name;
|
||||
if (!var->hdf_datasetid)
|
||||
if ((var->hdf_datasetid = H5Dopen2(grp->hdf_grpid, name_to_use, H5P_DEFAULT)) < 0)
|
||||
return NC_ENOTVAR;
|
||||
|
||||
/* Get file space of data. */
|
||||
if ((file_spaceid = H5Dget_space(var->hdf_datasetid)) < 0)
|
||||
BAIL(NC_EHDFERR);
|
||||
|
||||
/* Check to ensure the user selection is
|
||||
* valid. H5Sget_simple_extent_dims gets the sizes of all the dims
|
||||
* and put them in fdims. */
|
||||
if (H5Sget_simple_extent_dims(file_spaceid, fdims, fmaxdims) < 0)
|
||||
BAIL(NC_EHDFERR);
|
||||
|
||||
#ifdef LOGGING
|
||||
log_dim_info(var, fdims, fmaxdims, start, count);
|
||||
#endif
|
||||
|
||||
/* Check dimension bounds. Remember that unlimited dimensions can
|
||||
* put data beyond their current length. */
|
||||
for (d2 = 0; d2 < var->ndims; d2++)
|
||||
{
|
||||
hsize_t endindex = start[d2] + stride[d2] *(count[d2] - 1); /* last index read */
|
||||
dim = var->dim[d2];
|
||||
assert(dim && dim->hdr.id == var->dimids[d2]);
|
||||
if (count[d2] == 0)
|
||||
endindex = start[d2]; /* fixup for zero read count */
|
||||
if (dim->unlimited)
|
||||
{
|
||||
size_t ulen;
|
||||
|
||||
/* We can't go beyond the largest current extent of
|
||||
the unlimited dim. */
|
||||
if ((retval = NC4_inq_dim(ncid, dim->hdr.id, NULL, &ulen)))
|
||||
BAIL(retval);
|
||||
|
||||
/* Check for out of bound requests. */
|
||||
#ifdef RELAX_COORD_BOUND
|
||||
/* Allow start to equal dim size if count is zero. */
|
||||
if (start[d2] > (hssize_t)ulen ||
|
||||
(start[d2] == (hssize_t)ulen && count[d2] > 0))
|
||||
BAIL_QUIET(NC_EINVALCOORDS);
|
||||
#else
|
||||
if (start[d2] >= (hssize_t)ulen && ulen > 0)
|
||||
BAIL_QUIET(NC_EINVALCOORDS);
|
||||
#endif
|
||||
if (count[d2] && endindex >= ulen)
|
||||
BAIL_QUIET(NC_EEDGE);
|
||||
|
||||
/* Things get a little tricky here. If we're getting
|
||||
a GET request beyond the end of this var's
|
||||
current length in an unlimited dimension, we'll
|
||||
later need to return the fill value for the
|
||||
variable. */
|
||||
if (start[d2] >= (hssize_t)fdims[d2])
|
||||
fill_value_size[d2] = count[d2];
|
||||
else if (endindex >= fdims[d2])
|
||||
fill_value_size[d2] = count[d2] - ((fdims[d2] - start[d2])/stride[d2]);
|
||||
else
|
||||
fill_value_size[d2] = 0;
|
||||
count[d2] -= fill_value_size[d2];
|
||||
if (fill_value_size[d2])
|
||||
provide_fill++;
|
||||
}
|
||||
else /* Dim is not unlimited. */
|
||||
{
|
||||
/* Check for out of bound requests. */
|
||||
#ifdef RELAX_COORD_BOUND
|
||||
/* Allow start to equal dim size if count is zero. */
|
||||
if (start[d2] > (hssize_t)fdims[d2] ||
|
||||
(start[d2] == (hssize_t)fdims[d2] && count[d2] > 0))
|
||||
BAIL_QUIET(NC_EINVALCOORDS);
|
||||
#else
|
||||
if (start[d2] >= (hssize_t)fdims[d2])
|
||||
BAIL_QUIET(NC_EINVALCOORDS);
|
||||
#endif
|
||||
if (count[d2] && endindex >= fdims[d2])
|
||||
BAIL_QUIET(NC_EEDGE);
|
||||
|
||||
/* Set the fill value boundary */
|
||||
fill_value_size[d2] = count[d2];
|
||||
}
|
||||
}
|
||||
|
||||
/* Later on, we will need to know the size of this type in the
|
||||
* file. */
|
||||
assert(var->type_info->size);
|
||||
file_type_size = var->type_info->size;
|
||||
|
||||
if (!no_read)
|
||||
{
|
||||
/* Now you would think that no one would be crazy enough to write
|
||||
a scalar dataspace with one of the array function calls, but you
|
||||
would be wrong. So let's check to see if the dataset is
|
||||
scalar. If it is, we won't try to set up a hyperslab. */
|
||||
if (H5Sget_simple_extent_type(file_spaceid) == H5S_SCALAR)
|
||||
{
|
||||
if ((mem_spaceid = H5Screate(H5S_SCALAR)) < 0)
|
||||
BAIL(NC_EHDFERR);
|
||||
scalar++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (H5Sselect_hyperslab(file_spaceid, H5S_SELECT_SET,
|
||||
start, stride, count, NULL) < 0)
|
||||
BAIL(NC_EHDFERR);
|
||||
/* Create a space for the memory, just big enough to hold the slab
|
||||
we want. */
|
||||
if ((mem_spaceid = H5Screate_simple(var->ndims, count, NULL)) < 0)
|
||||
BAIL(NC_EHDFERR);
|
||||
}
|
||||
|
||||
/* Fix bug when reading HDF5 files with variable of type
|
||||
* fixed-length string. We need to make it look like a
|
||||
* variable-length string, because that's all netCDF-4 data
|
||||
* model supports, lacking anonymous dimensions. So
|
||||
* variable-length strings are in allocated memory that user has
|
||||
* to free, which we allocate here. */
|
||||
if (var->type_info->nc_type_class == NC_STRING &&
|
||||
H5Tget_size(var->type_info->hdf_typeid) > 1 &&
|
||||
!H5Tis_variable_str(var->type_info->hdf_typeid))
|
||||
{
|
||||
hsize_t fstring_len;
|
||||
|
||||
if ((fstring_len = H5Tget_size(var->type_info->hdf_typeid)) == 0)
|
||||
BAIL(NC_EHDFERR);
|
||||
if (!(*(char **)data = malloc(1 + fstring_len)))
|
||||
BAIL(NC_ENOMEM);
|
||||
bufr = *(char **)data;
|
||||
}
|
||||
|
||||
/* Are we going to convert any data? (No converting of compound or
|
||||
* opaque types.) */
|
||||
if (mem_nc_type != var->type_info->hdr.id &&
|
||||
mem_nc_type != NC_COMPOUND && mem_nc_type != NC_OPAQUE)
|
||||
{
|
||||
/* We must convert - allocate a buffer. */
|
||||
need_to_convert++;
|
||||
if (var->ndims)
|
||||
for (d2 = 0; d2 < var->ndims; d2++)
|
||||
len *= countp[d2];
|
||||
LOG((4, "converting data for var %s type=%d len=%d", var->hdr.name,
|
||||
var->type_info->hdr.id, len));
|
||||
|
||||
/* If we're reading, we need bufr to have enough memory to store
|
||||
* the data in the file. If we're writing, we need bufr to be
|
||||
* big enough to hold all the data in the file's type. */
|
||||
if (len > 0)
|
||||
if (!(bufr = malloc(len * file_type_size)))
|
||||
BAIL(NC_ENOMEM);
|
||||
}
|
||||
else
|
||||
if (!bufr)
|
||||
bufr = data;
|
||||
|
||||
/* Create the data transfer property list. */
|
||||
if ((xfer_plistid = H5Pcreate(H5P_DATASET_XFER)) < 0)
|
||||
BAIL(NC_EHDFERR);
|
||||
|
||||
#ifdef USE_PARALLEL4
|
||||
/* Set up parallel I/O, if needed. */
|
||||
if ((retval = set_par_access(h5, var, xfer_plistid)))
|
||||
BAIL(retval);
|
||||
#endif
|
||||
|
||||
/* Read this hyperslab into memory. */
|
||||
LOG((5, "About to H5Dread some data..."));
|
||||
if (H5Dread(var->hdf_datasetid, var->type_info->native_hdf_typeid,
|
||||
mem_spaceid, file_spaceid, xfer_plistid, bufr) < 0)
|
||||
BAIL(NC_EHDFERR);
|
||||
|
||||
/* Convert data type if needed. */
|
||||
if (need_to_convert)
|
||||
{
|
||||
if ((retval = nc4_convert_type(bufr, data, var->type_info->hdr.id, mem_nc_type,
|
||||
len, &range_error, var->fill_value,
|
||||
(h5->cmode & NC_CLASSIC_MODEL))))
|
||||
BAIL(retval);
|
||||
|
||||
/* For strict netcdf-3 rules, ignore erange errors between UBYTE
|
||||
* and BYTE types. */
|
||||
if ((h5->cmode & NC_CLASSIC_MODEL) &&
|
||||
(var->type_info->hdr.id == NC_UBYTE || var->type_info->hdr.id == NC_BYTE) &&
|
||||
(mem_nc_type == NC_UBYTE || mem_nc_type == NC_BYTE) &&
|
||||
range_error)
|
||||
range_error = 0;
|
||||
}
|
||||
} /* endif ! no_read */
|
||||
else
|
||||
{
|
||||
#ifdef USE_PARALLEL4 /* Start block contributed by HDF group. */
|
||||
/* For collective IO read, some processes may not have any element for reading.
|
||||
Collective requires all processes to participate, so we use H5Sselect_none
|
||||
for these processes. */
|
||||
if (var->parallel_access == NC_COLLECTIVE)
|
||||
{
|
||||
/* Create the data transfer property list. */
|
||||
if ((xfer_plistid = H5Pcreate(H5P_DATASET_XFER)) < 0)
|
||||
BAIL(NC_EHDFERR);
|
||||
|
||||
if ((retval = set_par_access(h5, var, xfer_plistid)))
|
||||
BAIL(retval);
|
||||
|
||||
if (H5Sselect_none(file_spaceid) < 0)
|
||||
BAIL(NC_EHDFERR);
|
||||
|
||||
/* Since no element will be selected, we just get the memory
|
||||
* space the same as the file space. */
|
||||
if ((mem_spaceid = H5Dget_space(var->hdf_datasetid)) < 0)
|
||||
BAIL(NC_EHDFERR);
|
||||
if (H5Sselect_none(mem_spaceid) < 0)
|
||||
BAIL(NC_EHDFERR);
|
||||
|
||||
/* Read this hyperslab into memory. */
|
||||
LOG((5, "About to H5Dread some data..."));
|
||||
if (H5Dread(var->hdf_datasetid, var->type_info->native_hdf_typeid,
|
||||
mem_spaceid, file_spaceid, xfer_plistid, bufr) < 0)
|
||||
BAIL(NC_EHDFERR);
|
||||
}
|
||||
#endif /* End ifdef USE_PARALLEL4 */
|
||||
}
|
||||
/* Now we need to fake up any further data that was asked for,
|
||||
using the fill values instead. First skip past the data we
|
||||
just read, if any. */
|
||||
if (!scalar && provide_fill)
|
||||
{
|
||||
void *filldata;
|
||||
size_t real_data_size = 0;
|
||||
size_t fill_len;
|
||||
|
||||
/* Skip past the real data we've already read. */
|
||||
if (!no_read)
|
||||
for (real_data_size = file_type_size, d2 = 0; d2 < var->ndims; d2++)
|
||||
real_data_size *= (count[d2] - start[d2]);
|
||||
|
||||
/* Get the fill value from the HDF5 variable. Memory will be
|
||||
* allocated. */
|
||||
if (nc4_get_fill_value(h5, var, &fillvalue) < 0)
|
||||
BAIL(NC_EHDFERR);
|
||||
|
||||
/* How many fill values do we need? */
|
||||
for (fill_len = 1, d2 = 0; d2 < var->ndims; d2++)
|
||||
fill_len *= (fill_value_size[d2] ? fill_value_size[d2] : 1);
|
||||
|
||||
/* Copy the fill value into the rest of the data buffer. */
|
||||
filldata = (char *)data + real_data_size;
|
||||
for (i = 0; i < fill_len; i++)
|
||||
{
|
||||
|
||||
if (var->type_info->nc_type_class == NC_STRING)
|
||||
{
|
||||
if (*(char **)fillvalue)
|
||||
{
|
||||
if (!(*(char **)filldata = strdup(*(char **)fillvalue)))
|
||||
BAIL(NC_ENOMEM);
|
||||
}
|
||||
else
|
||||
*(char **)filldata = NULL;
|
||||
}
|
||||
else if (var->type_info->nc_type_class == NC_VLEN)
|
||||
{
|
||||
if (fillvalue)
|
||||
{
|
||||
memcpy(filldata,fillvalue,file_type_size);
|
||||
} else {
|
||||
*(char **)filldata = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
memcpy(filldata, fillvalue, file_type_size);
|
||||
filldata = (char *)filldata + file_type_size;
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
if (file_spaceid > 0)
|
||||
if (H5Sclose(file_spaceid) < 0)
|
||||
BAIL2(NC_EHDFERR);
|
||||
if (mem_spaceid > 0)
|
||||
if (H5Sclose(mem_spaceid) < 0)
|
||||
BAIL2(NC_EHDFERR);
|
||||
if (xfer_plistid > 0)
|
||||
if (H5Pclose(xfer_plistid) < 0)
|
||||
BAIL2(NC_EHDFERR);
|
||||
if (need_to_convert && bufr != NULL)
|
||||
free(bufr);
|
||||
if (xtend_size)
|
||||
free(xtend_size);
|
||||
if (fillvalue)
|
||||
{
|
||||
if (var->type_info->nc_type_class == NC_VLEN)
|
||||
nc_free_vlen((nc_vlen_t *)fillvalue);
|
||||
else if (var->type_info->nc_type_class == NC_STRING && *(char **)fillvalue)
|
||||
free(*(char **)fillvalue);
|
||||
free(fillvalue);
|
||||
}
|
||||
|
||||
/* If there was an error return it, otherwise return any potential
|
||||
range error value. If none, return NC_NOERR as usual.*/
|
||||
if (retval)
|
||||
return retval;
|
||||
if (range_error)
|
||||
return NC_ERANGE;
|
||||
return NC_NOERR;
|
||||
}
|
||||
|
826
libhdf5/nc4hdf.c
826
libhdf5/nc4hdf.c
@ -531,106 +531,6 @@ exit:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal Do some common check for nc4_put_vara and
|
||||
* nc4_get_vara. These checks have to be done when both reading and
|
||||
* writing data.
|
||||
*
|
||||
* @param mem_nc_type Pointer to type of data in memory.
|
||||
* @param var Pointer to var info struct.
|
||||
* @param h5 Pointer to HDF5 file info struct.
|
||||
*
|
||||
* @return ::NC_NOERR No error.
|
||||
* @author Ed Hartnett
|
||||
*/
|
||||
static int
|
||||
check_for_vara(nc_type *mem_nc_type, NC_VAR_INFO_T *var, NC_FILE_INFO_T *h5)
|
||||
{
|
||||
int retval;
|
||||
|
||||
/* If mem_nc_type is NC_NAT, it means we want to use the file type
|
||||
* as the mem type as well. */
|
||||
assert(mem_nc_type);
|
||||
if (*mem_nc_type == NC_NAT)
|
||||
*mem_nc_type = var->type_info->hdr.id;
|
||||
assert(*mem_nc_type);
|
||||
|
||||
/* No NC_CHAR conversions, you pervert! */
|
||||
if (var->type_info->hdr.id != *mem_nc_type &&
|
||||
(var->type_info->hdr.id == NC_CHAR || *mem_nc_type == NC_CHAR))
|
||||
return NC_ECHAR;
|
||||
|
||||
/* If we're in define mode, we can't read or write data. */
|
||||
if (h5->flags & NC_INDEF)
|
||||
{
|
||||
if (h5->cmode & NC_CLASSIC_MODEL)
|
||||
return NC_EINDEFINE;
|
||||
if ((retval = nc4_enddef_netcdf4_file(h5)))
|
||||
return retval;
|
||||
}
|
||||
|
||||
return NC_NOERR;
|
||||
}
|
||||
|
||||
#ifdef LOGGING
|
||||
/**
|
||||
* @intarnal Print some debug info about dimensions to the log.
|
||||
*/
|
||||
static void
|
||||
log_dim_info(NC_VAR_INFO_T *var, hsize_t *fdims, hsize_t *fmaxdims,
|
||||
hsize_t *start, hsize_t *count)
|
||||
{
|
||||
int d2;
|
||||
|
||||
/* Print some debugging info... */
|
||||
LOG((4, "%s: var name %s ndims %d", __func__, var->hdr.name, var->ndims));
|
||||
LOG((4, "File space, and requested:"));
|
||||
for (d2 = 0; d2 < var->ndims; d2++)
|
||||
{
|
||||
LOG((4, "fdims[%d]=%Ld fmaxdims[%d]=%Ld", d2, fdims[d2], d2,
|
||||
fmaxdims[d2]));
|
||||
LOG((4, "start[%d]=%Ld count[%d]=%Ld", d2, start[d2], d2, count[d2]));
|
||||
}
|
||||
}
|
||||
#endif /* LOGGING */
|
||||
|
||||
#ifdef USE_PARALLEL4
|
||||
/**
|
||||
* @internal Set the parallel access for a var (collective
|
||||
* vs. independent).
|
||||
*
|
||||
* @param h5 Pointer to HDF5 file info struct.
|
||||
* @param var Pointer to var info struct.
|
||||
* @param xfer_plistid H5FD_MPIO_COLLECTIVE or H5FD_MPIO_INDEPENDENT.
|
||||
*
|
||||
* @returns NC_NOERR No error.
|
||||
* @author Ed Hartnett
|
||||
*/
|
||||
static int
|
||||
set_par_access(NC_FILE_INFO_T *h5, NC_VAR_INFO_T *var, hid_t xfer_plistid)
|
||||
{
|
||||
/* If netcdf is built with parallel I/O, then parallel access can
|
||||
* be used, and, if this file was opened or created for parallel
|
||||
* access, we need to set the transfer mode. */
|
||||
if (h5->parallel)
|
||||
{
|
||||
H5FD_mpio_xfer_t hdf5_xfer_mode;
|
||||
|
||||
/* Decide on collective or independent. */
|
||||
hdf5_xfer_mode = (var->parallel_access != NC_INDEPENDENT) ?
|
||||
H5FD_MPIO_COLLECTIVE : H5FD_MPIO_INDEPENDENT;
|
||||
|
||||
/* Set the mode in the transfer property list. */
|
||||
if (H5Pset_dxpl_mpio(xfer_plistid, hdf5_xfer_mode) < 0)
|
||||
return NC_EPARINIT;
|
||||
|
||||
LOG((4, "%s: %d H5FD_MPIO_COLLECTIVE: %d H5FD_MPIO_INDEPENDENT: %d",
|
||||
__func__, (int)hdf5_xfer_mode, H5FD_MPIO_COLLECTIVE, H5FD_MPIO_INDEPENDENT));
|
||||
}
|
||||
return NC_NOERR;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @internal Write an attribute.
|
||||
*
|
||||
@ -3598,729 +3498,3 @@ NC4_walk(hid_t gid, int* countp)
|
||||
return ncstat;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal Write a strided array of data to a variable.
|
||||
*
|
||||
* @param nc Pointer to the file NC struct.
|
||||
* @param ncid File ID.
|
||||
* @param varid Variable ID.
|
||||
* @param startp Array of start indices. Will default to starts of 0
|
||||
* if NULL.
|
||||
* @param countp Array of counts. Will default to counts of 1 if NULL.
|
||||
* @param stridep Array of strides. Will default to strides of 1 if
|
||||
* NULL.
|
||||
* @param mem_nc_type The type of the data in memory.
|
||||
* @param data The data to be written.
|
||||
*
|
||||
* @returns ::NC_NOERR No error.
|
||||
* @returns ::NC_EBADID Bad ncid.
|
||||
* @returns ::NC_ENOTVAR Var not found.
|
||||
* @returns ::NC_EHDFERR HDF5 function returned error.
|
||||
* @returns ::NC_EINVALCOORDS Incorrect start.
|
||||
* @returns ::NC_EEDGE Incorrect start/count.
|
||||
* @returns ::NC_ENOMEM Out of memory.
|
||||
* @returns ::NC_EMPI MPI library error (parallel only)
|
||||
* @returns ::NC_ECANTEXTEND Can't extend dimension for write.
|
||||
* @returns ::NC_ERANGE Data conversion error.
|
||||
* @author Ed Hartnett, Dennis Heimbigner
|
||||
*/
|
||||
int
|
||||
nc4_put_vars(NC *nc, int ncid, int varid, const size_t *startp,
|
||||
const size_t *countp, const ptrdiff_t* stridep,
|
||||
nc_type mem_nc_type, void *data)
|
||||
{
|
||||
NC_GRP_INFO_T *grp;
|
||||
NC_FILE_INFO_T *h5;
|
||||
NC_VAR_INFO_T *var;
|
||||
NC_DIM_INFO_T *dim;
|
||||
hid_t file_spaceid = 0, mem_spaceid = 0, xfer_plistid = 0;
|
||||
long long unsigned xtend_size[NC_MAX_VAR_DIMS];
|
||||
hsize_t fdims[NC_MAX_VAR_DIMS], fmaxdims[NC_MAX_VAR_DIMS];
|
||||
hsize_t start[NC_MAX_VAR_DIMS], count[NC_MAX_VAR_DIMS];
|
||||
hsize_t stride[NC_MAX_VAR_DIMS];
|
||||
char *name_to_use;
|
||||
int need_to_extend = 0;
|
||||
#ifdef USE_PARALLEL4
|
||||
int extend_possible = 0;
|
||||
#endif
|
||||
int retval = NC_NOERR, range_error = 0, i, d2;
|
||||
void *bufr = NULL;
|
||||
int need_to_convert = 0;
|
||||
int zero_count = 0; /* true if a count is zero */
|
||||
size_t len = 1;
|
||||
|
||||
/* Find our metadata for this file, group, and var. */
|
||||
assert(nc);
|
||||
if ((retval = nc4_find_g_var_nc(nc, ncid, varid, &grp, &var)))
|
||||
return retval;
|
||||
h5 = NC4_DATA(nc);
|
||||
assert(grp && h5 && var && var->hdr.name);
|
||||
|
||||
LOG((3, "%s: var->hdr.name %s mem_nc_type %d", __func__,
|
||||
var->hdr.name, mem_nc_type));
|
||||
|
||||
/* Check some stuff about the type and the file. If the file must
|
||||
* be switched from define mode, it happens here. */
|
||||
if ((retval = check_for_vara(&mem_nc_type, var, h5)))
|
||||
return retval;
|
||||
|
||||
/* Convert from size_t and ptrdiff_t to hssize_t, and hsize_t. */
|
||||
/* Also do sanity checks */
|
||||
for (i = 0; i < var->ndims; i++)
|
||||
{
|
||||
/* Check for non-positive stride. */
|
||||
if (stridep && stridep[i] <= 0)
|
||||
return NC_ESTRIDE;
|
||||
|
||||
start[i] = (startp == NULL ? 0 : startp[i]);
|
||||
count[i] = (countp == NULL ? 1 : countp[i]);
|
||||
stride[i] = (stridep == NULL ? 1 : stridep[i]);
|
||||
|
||||
/* Check to see if any counts are zero. */
|
||||
if (!count[i])
|
||||
zero_count++;
|
||||
}
|
||||
|
||||
/* Open this dataset if necessary, also checking for a weird case:
|
||||
* a non-coordinate (and non-scalar) variable that has the same
|
||||
* name as a dimension. */
|
||||
if (var->hdf5_name && strlen(var->hdf5_name) >= strlen(NON_COORD_PREPEND) &&
|
||||
strncmp(var->hdf5_name, NON_COORD_PREPEND, strlen(NON_COORD_PREPEND)) == 0 &&
|
||||
var->ndims)
|
||||
name_to_use = var->hdf5_name;
|
||||
else
|
||||
name_to_use = var->hdr.name;
|
||||
if (!var->hdf_datasetid)
|
||||
if ((var->hdf_datasetid = H5Dopen2(grp->hdf_grpid, name_to_use, H5P_DEFAULT)) < 0)
|
||||
return NC_ENOTVAR;
|
||||
|
||||
/* Get file space of data. */
|
||||
if ((file_spaceid = H5Dget_space(var->hdf_datasetid)) < 0)
|
||||
BAIL(NC_EHDFERR);
|
||||
|
||||
/* Get the sizes of all the dims and put them in fdims. */
|
||||
if (H5Sget_simple_extent_dims(file_spaceid, fdims, fmaxdims) < 0)
|
||||
BAIL(NC_EHDFERR);
|
||||
|
||||
#ifdef LOGGING
|
||||
log_dim_info(var, fdims, fmaxdims, start, count);
|
||||
#endif
|
||||
|
||||
/* Check dimension bounds. Remember that unlimited dimensions can
|
||||
* put data beyond their current length. */
|
||||
for (d2 = 0; d2 < var->ndims; d2++)
|
||||
{
|
||||
hsize_t endindex = start[d2] + stride[d2] * (count[d2] - 1); /* last index written */
|
||||
dim = var->dim[d2];
|
||||
assert(dim && dim->hdr.id == var->dimids[d2]);
|
||||
if (count[d2] == 0)
|
||||
endindex = start[d2]; /* fixup for zero read count */
|
||||
if (!dim->unlimited)
|
||||
{
|
||||
#ifdef RELAX_COORD_BOUND
|
||||
/* Allow start to equal dim size if count is zero. */
|
||||
if (start[d2] > (hssize_t)fdims[d2] ||
|
||||
(start[d2] == (hssize_t)fdims[d2] && count[d2] > 0))
|
||||
BAIL_QUIET(NC_EINVALCOORDS);
|
||||
if (!zero_count && endindex >= fdims[d2])
|
||||
BAIL_QUIET(NC_EEDGE);
|
||||
#else
|
||||
if (start[d2] >= (hssize_t)fdims[d2])
|
||||
BAIL_QUIET(NC_EINVALCOORDS);
|
||||
if (endindex >= fdims[d2])
|
||||
BAIL_QUIET(NC_EEDGE);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* Now you would think that no one would be crazy enough to write
|
||||
a scalar dataspace with one of the array function calls, but you
|
||||
would be wrong. So let's check to see if the dataset is
|
||||
scalar. If it is, we won't try to set up a hyperslab. */
|
||||
if (H5Sget_simple_extent_type(file_spaceid) == H5S_SCALAR)
|
||||
{
|
||||
if ((mem_spaceid = H5Screate(H5S_SCALAR)) < 0)
|
||||
BAIL(NC_EHDFERR);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (H5Sselect_hyperslab(file_spaceid, H5S_SELECT_SET, start, stride,
|
||||
count, NULL) < 0)
|
||||
BAIL(NC_EHDFERR);
|
||||
|
||||
/* Create a space for the memory, just big enough to hold the slab
|
||||
we want. */
|
||||
if ((mem_spaceid = H5Screate_simple(var->ndims, count, NULL)) < 0)
|
||||
BAIL(NC_EHDFERR);
|
||||
}
|
||||
|
||||
/* Are we going to convert any data? (No converting of compound or
|
||||
* opaque types.) */
|
||||
if (mem_nc_type != var->type_info->hdr.id &&
|
||||
mem_nc_type != NC_COMPOUND && mem_nc_type != NC_OPAQUE)
|
||||
{
|
||||
size_t file_type_size;
|
||||
|
||||
/* We must convert - allocate a buffer. */
|
||||
need_to_convert++;
|
||||
if (var->ndims)
|
||||
for (d2=0; d2<var->ndims; d2++)
|
||||
len *= countp[d2];
|
||||
LOG((4, "converting data for var %s type=%d len=%d", var->hdr.name,
|
||||
var->type_info->hdr.id, len));
|
||||
|
||||
/* Later on, we will need to know the size of this type in the
|
||||
* file. */
|
||||
assert(var->type_info->size);
|
||||
file_type_size = var->type_info->size;
|
||||
|
||||
/* If we're reading, we need bufr to have enough memory to store
|
||||
* the data in the file. If we're writing, we need bufr to be
|
||||
* big enough to hold all the data in the file's type. */
|
||||
if (len > 0)
|
||||
if (!(bufr = malloc(len * file_type_size)))
|
||||
BAIL(NC_ENOMEM);
|
||||
}
|
||||
else
|
||||
bufr = data;
|
||||
|
||||
/* Create the data transfer property list. */
|
||||
if ((xfer_plistid = H5Pcreate(H5P_DATASET_XFER)) < 0)
|
||||
BAIL(NC_EHDFERR);
|
||||
|
||||
#ifdef USE_PARALLEL4
|
||||
/* Set up parallel I/O, if needed. */
|
||||
if ((retval = set_par_access(h5, var, xfer_plistid)))
|
||||
BAIL(retval);
|
||||
#endif
|
||||
|
||||
/* Read this hyperslab from memory. */
|
||||
/* Does the dataset have to be extended? If it's already
|
||||
extended to the required size, it will do no harm to reextend
|
||||
it to that size. */
|
||||
if (var->ndims)
|
||||
{
|
||||
for (d2 = 0; d2 < var->ndims; d2++)
|
||||
{
|
||||
hsize_t endindex = start[d2] + stride[d2] * (count[d2] - 1); /* last index written */
|
||||
if (count[d2] == 0)
|
||||
endindex = start[d2];
|
||||
dim = var->dim[d2];
|
||||
assert(dim && dim->hdr.id == var->dimids[d2]);
|
||||
if (dim->unlimited)
|
||||
{
|
||||
#ifdef USE_PARALLEL4
|
||||
extend_possible = 1;
|
||||
#endif
|
||||
if (!zero_count && endindex >= fdims[d2])
|
||||
{
|
||||
xtend_size[d2] = (long long unsigned)(endindex+1);
|
||||
need_to_extend++;
|
||||
}
|
||||
else
|
||||
xtend_size[d2] = (long long unsigned)fdims[d2];
|
||||
|
||||
if (!zero_count && endindex >= dim->len)
|
||||
{
|
||||
dim->len = endindex+1;
|
||||
dim->extended = NC_TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
xtend_size[d2] = (long long unsigned)dim->len;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_PARALLEL4
|
||||
/* Check if anyone wants to extend */
|
||||
if (extend_possible && h5->parallel &&
|
||||
NC_COLLECTIVE == var->parallel_access)
|
||||
{
|
||||
/* Form consensus opinion among all processes about whether to perform
|
||||
* collective I/O
|
||||
*/
|
||||
if (MPI_SUCCESS != MPI_Allreduce(MPI_IN_PLACE, &need_to_extend, 1,
|
||||
MPI_INT, MPI_BOR, h5->comm))
|
||||
BAIL(NC_EMPI);
|
||||
}
|
||||
#endif /* USE_PARALLEL4 */
|
||||
|
||||
/* If we need to extend it, we also need a new file_spaceid
|
||||
to reflect the new size of the space. */
|
||||
if (need_to_extend)
|
||||
{
|
||||
LOG((4, "extending dataset"));
|
||||
#ifdef USE_PARALLEL4
|
||||
if (h5->parallel)
|
||||
{
|
||||
if (NC_COLLECTIVE != var->parallel_access)
|
||||
BAIL(NC_ECANTEXTEND);
|
||||
|
||||
/* Reach consensus about dimension sizes to extend to */
|
||||
if (MPI_SUCCESS != MPI_Allreduce(MPI_IN_PLACE, xtend_size, var->ndims,
|
||||
MPI_UNSIGNED_LONG_LONG, MPI_MAX,
|
||||
h5->comm))
|
||||
BAIL(NC_EMPI);
|
||||
}
|
||||
#endif /* USE_PARALLEL4 */
|
||||
/* Convert xtend_size back to hsize_t for use with H5Dset_extent */
|
||||
for (d2 = 0; d2 < var->ndims; d2++)
|
||||
fdims[d2] = (hsize_t)xtend_size[d2];
|
||||
|
||||
if (H5Dset_extent(var->hdf_datasetid, fdims) < 0)
|
||||
BAIL(NC_EHDFERR);
|
||||
if (file_spaceid > 0 && H5Sclose(file_spaceid) < 0)
|
||||
BAIL2(NC_EHDFERR);
|
||||
if ((file_spaceid = H5Dget_space(var->hdf_datasetid)) < 0)
|
||||
BAIL(NC_EHDFERR);
|
||||
if (H5Sselect_hyperslab(file_spaceid, H5S_SELECT_SET,
|
||||
start, stride, count, NULL) < 0)
|
||||
BAIL(NC_EHDFERR);
|
||||
}
|
||||
}
|
||||
|
||||
/* Do we need to convert the data? */
|
||||
if (need_to_convert)
|
||||
{
|
||||
if ((retval = nc4_convert_type(data, bufr, mem_nc_type, var->type_info->hdr.id,
|
||||
len, &range_error, var->fill_value,
|
||||
(h5->cmode & NC_CLASSIC_MODEL))))
|
||||
BAIL(retval);
|
||||
}
|
||||
|
||||
/* Write the data. At last! */
|
||||
LOG((4, "about to H5Dwrite datasetid 0x%x mem_spaceid 0x%x "
|
||||
"file_spaceid 0x%x", var->hdf_datasetid, mem_spaceid, file_spaceid));
|
||||
if (H5Dwrite(var->hdf_datasetid, var->type_info->hdf_typeid,
|
||||
mem_spaceid, file_spaceid, xfer_plistid, bufr) < 0)
|
||||
BAIL(NC_EHDFERR);
|
||||
|
||||
/* Remember that we have written to this var so that Fill Value
|
||||
* can't be set for it. */
|
||||
if (!var->written_to)
|
||||
var->written_to = NC_TRUE;
|
||||
|
||||
/* For strict netcdf-3 rules, ignore erange errors between UBYTE
|
||||
* and BYTE types. */
|
||||
if ((h5->cmode & NC_CLASSIC_MODEL) &&
|
||||
(var->type_info->hdr.id == NC_UBYTE || var->type_info->hdr.id == NC_BYTE) &&
|
||||
(mem_nc_type == NC_UBYTE || mem_nc_type == NC_BYTE) &&
|
||||
range_error)
|
||||
range_error = 0;
|
||||
|
||||
exit:
|
||||
if (file_spaceid > 0 && H5Sclose(file_spaceid) < 0)
|
||||
BAIL2(NC_EHDFERR);
|
||||
if (mem_spaceid > 0 && H5Sclose(mem_spaceid) < 0)
|
||||
BAIL2(NC_EHDFERR);
|
||||
if (xfer_plistid && (H5Pclose(xfer_plistid) < 0))
|
||||
BAIL2(NC_EPARINIT);
|
||||
if (need_to_convert && bufr) free(bufr);
|
||||
|
||||
/* If there was an error return it, otherwise return any potential
|
||||
range error value. If none, return NC_NOERR as usual.*/
|
||||
if (retval)
|
||||
return retval;
|
||||
if (range_error)
|
||||
return NC_ERANGE;
|
||||
return NC_NOERR;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal Read a strided array of data from a variable.
|
||||
*
|
||||
* @param nc Pointer to the file NC struct.
|
||||
* @param ncid File ID.
|
||||
* @param varid Variable ID.
|
||||
* @param startp Array of start indices. Will default to starts of 0
|
||||
* if NULL.
|
||||
* @param countp Array of counts. Will default to counts of 1 if NULL.
|
||||
* @param stridep Array of strides. Will default to strides of 1 if
|
||||
* NULL.
|
||||
* @param mem_nc_type The type of the data in memory. (Convert to this
|
||||
* type from file type.)
|
||||
* @param data The data to be written.
|
||||
*
|
||||
* @returns ::NC_NOERR No error.
|
||||
* @returns ::NC_EBADID Bad ncid.
|
||||
* @returns ::NC_ENOTVAR Var not found.
|
||||
* @returns ::NC_EHDFERR HDF5 function returned error.
|
||||
* @returns ::NC_EINVALCOORDS Incorrect start.
|
||||
* @returns ::NC_EEDGE Incorrect start/count.
|
||||
* @returns ::NC_ENOMEM Out of memory.
|
||||
* @returns ::NC_EMPI MPI library error (parallel only)
|
||||
* @returns ::NC_ECANTEXTEND Can't extend dimension for write.
|
||||
* @returns ::NC_ERANGE Data conversion error.
|
||||
* @author Ed Hartnett, Dennis Heimbigner
|
||||
*/
|
||||
int
|
||||
nc4_get_vars(NC *nc, int ncid, int varid, const size_t *startp,
|
||||
const size_t *countp, const ptrdiff_t* stridep,
|
||||
nc_type mem_nc_type, void *data)
|
||||
{
|
||||
NC_GRP_INFO_T *grp;
|
||||
NC_FILE_INFO_T *h5;
|
||||
NC_VAR_INFO_T *var;
|
||||
NC_DIM_INFO_T *dim;
|
||||
hid_t file_spaceid = 0, mem_spaceid = 0;
|
||||
hid_t xfer_plistid = 0;
|
||||
size_t file_type_size;
|
||||
hsize_t *xtend_size = NULL, count[NC_MAX_VAR_DIMS];
|
||||
hsize_t fdims[NC_MAX_VAR_DIMS], fmaxdims[NC_MAX_VAR_DIMS];
|
||||
hsize_t start[NC_MAX_VAR_DIMS];
|
||||
hsize_t stride[NC_MAX_VAR_DIMS];
|
||||
char *name_to_use;
|
||||
void *fillvalue = NULL;
|
||||
int no_read = 0, provide_fill = 0;
|
||||
int fill_value_size[NC_MAX_VAR_DIMS];
|
||||
int scalar = 0, retval = NC_NOERR, range_error = 0, i, d2;
|
||||
void *bufr = NULL;
|
||||
int need_to_convert = 0;
|
||||
size_t len = 1;
|
||||
|
||||
/* Find our metadata for this file, group, and var. */
|
||||
assert(nc);
|
||||
if ((retval = nc4_find_g_var_nc(nc, ncid, varid, &grp, &var)))
|
||||
return retval;
|
||||
h5 = NC4_DATA(nc);
|
||||
assert(grp && h5 && var && var->hdr.name);
|
||||
|
||||
LOG((3, "%s: var->hdr.name %s mem_nc_type %d", __func__,
|
||||
var->hdr.name, mem_nc_type));
|
||||
|
||||
/* Check some stuff about the type and the file. */
|
||||
if ((retval = check_for_vara(&mem_nc_type, var, h5)))
|
||||
return retval;
|
||||
|
||||
/* Convert from size_t and ptrdiff_t to hsize_t. Also do sanity
|
||||
* checks. */
|
||||
for (i = 0; i < var->ndims; i++)
|
||||
{
|
||||
/* If any of the stride values are non-positive, fail. */
|
||||
if (stridep && stridep[i] <= 0)
|
||||
return NC_ESTRIDE;
|
||||
|
||||
start[i] = (startp == NULL ? 0 : startp[i]);
|
||||
count[i] = (countp == NULL ? 1 : countp[i]);
|
||||
stride[i] = (stridep == NULL ? 1 : stridep[i]);
|
||||
|
||||
/* if any of the count values are zero don't actually read. */
|
||||
if (count[i] == 0)
|
||||
no_read++;
|
||||
}
|
||||
|
||||
/* Open this dataset if necessary, also checking for a weird case:
|
||||
* a non-coordinate (and non-scalar) variable that has the same
|
||||
* name as a dimension. */
|
||||
if (var->hdf5_name && strlen(var->hdf5_name) >= strlen(NON_COORD_PREPEND) &&
|
||||
strncmp(var->hdf5_name, NON_COORD_PREPEND, strlen(NON_COORD_PREPEND)) == 0 &&
|
||||
var->ndims)
|
||||
name_to_use = var->hdf5_name;
|
||||
else
|
||||
name_to_use = var->hdr.name;
|
||||
if (!var->hdf_datasetid)
|
||||
if ((var->hdf_datasetid = H5Dopen2(grp->hdf_grpid, name_to_use, H5P_DEFAULT)) < 0)
|
||||
return NC_ENOTVAR;
|
||||
|
||||
/* Get file space of data. */
|
||||
if ((file_spaceid = H5Dget_space(var->hdf_datasetid)) < 0)
|
||||
BAIL(NC_EHDFERR);
|
||||
|
||||
/* Check to ensure the user selection is
|
||||
* valid. H5Sget_simple_extent_dims gets the sizes of all the dims
|
||||
* and put them in fdims. */
|
||||
if (H5Sget_simple_extent_dims(file_spaceid, fdims, fmaxdims) < 0)
|
||||
BAIL(NC_EHDFERR);
|
||||
|
||||
#ifdef LOGGING
|
||||
log_dim_info(var, fdims, fmaxdims, start, count);
|
||||
#endif
|
||||
|
||||
/* Check dimension bounds. Remember that unlimited dimensions can
|
||||
* put data beyond their current length. */
|
||||
for (d2 = 0; d2 < var->ndims; d2++)
|
||||
{
|
||||
hsize_t endindex = start[d2] + stride[d2] *(count[d2] - 1); /* last index read */
|
||||
dim = var->dim[d2];
|
||||
assert(dim && dim->hdr.id == var->dimids[d2]);
|
||||
if (count[d2] == 0)
|
||||
endindex = start[d2]; /* fixup for zero read count */
|
||||
if (dim->unlimited)
|
||||
{
|
||||
size_t ulen;
|
||||
|
||||
/* We can't go beyond the largest current extent of
|
||||
the unlimited dim. */
|
||||
if ((retval = NC4_inq_dim(ncid, dim->hdr.id, NULL, &ulen)))
|
||||
BAIL(retval);
|
||||
|
||||
/* Check for out of bound requests. */
|
||||
#ifdef RELAX_COORD_BOUND
|
||||
/* Allow start to equal dim size if count is zero. */
|
||||
if (start[d2] > (hssize_t)ulen ||
|
||||
(start[d2] == (hssize_t)ulen && count[d2] > 0))
|
||||
BAIL_QUIET(NC_EINVALCOORDS);
|
||||
#else
|
||||
if (start[d2] >= (hssize_t)ulen && ulen > 0)
|
||||
BAIL_QUIET(NC_EINVALCOORDS);
|
||||
#endif
|
||||
if (count[d2] && endindex >= ulen)
|
||||
BAIL_QUIET(NC_EEDGE);
|
||||
|
||||
/* Things get a little tricky here. If we're getting
|
||||
a GET request beyond the end of this var's
|
||||
current length in an unlimited dimension, we'll
|
||||
later need to return the fill value for the
|
||||
variable. */
|
||||
if (start[d2] >= (hssize_t)fdims[d2])
|
||||
fill_value_size[d2] = count[d2];
|
||||
else if (endindex >= fdims[d2])
|
||||
fill_value_size[d2] = count[d2] - ((fdims[d2] - start[d2])/stride[d2]);
|
||||
else
|
||||
fill_value_size[d2] = 0;
|
||||
count[d2] -= fill_value_size[d2];
|
||||
if (fill_value_size[d2])
|
||||
provide_fill++;
|
||||
}
|
||||
else /* Dim is not unlimited. */
|
||||
{
|
||||
/* Check for out of bound requests. */
|
||||
#ifdef RELAX_COORD_BOUND
|
||||
/* Allow start to equal dim size if count is zero. */
|
||||
if (start[d2] > (hssize_t)fdims[d2] ||
|
||||
(start[d2] == (hssize_t)fdims[d2] && count[d2] > 0))
|
||||
BAIL_QUIET(NC_EINVALCOORDS);
|
||||
#else
|
||||
if (start[d2] >= (hssize_t)fdims[d2])
|
||||
BAIL_QUIET(NC_EINVALCOORDS);
|
||||
#endif
|
||||
if (count[d2] && endindex >= fdims[d2])
|
||||
BAIL_QUIET(NC_EEDGE);
|
||||
|
||||
/* Set the fill value boundary */
|
||||
fill_value_size[d2] = count[d2];
|
||||
}
|
||||
}
|
||||
|
||||
/* Later on, we will need to know the size of this type in the
|
||||
* file. */
|
||||
assert(var->type_info->size);
|
||||
file_type_size = var->type_info->size;
|
||||
|
||||
if (!no_read)
|
||||
{
|
||||
/* Now you would think that no one would be crazy enough to write
|
||||
a scalar dataspace with one of the array function calls, but you
|
||||
would be wrong. So let's check to see if the dataset is
|
||||
scalar. If it is, we won't try to set up a hyperslab. */
|
||||
if (H5Sget_simple_extent_type(file_spaceid) == H5S_SCALAR)
|
||||
{
|
||||
if ((mem_spaceid = H5Screate(H5S_SCALAR)) < 0)
|
||||
BAIL(NC_EHDFERR);
|
||||
scalar++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (H5Sselect_hyperslab(file_spaceid, H5S_SELECT_SET,
|
||||
start, stride, count, NULL) < 0)
|
||||
BAIL(NC_EHDFERR);
|
||||
/* Create a space for the memory, just big enough to hold the slab
|
||||
we want. */
|
||||
if ((mem_spaceid = H5Screate_simple(var->ndims, count, NULL)) < 0)
|
||||
BAIL(NC_EHDFERR);
|
||||
}
|
||||
|
||||
/* Fix bug when reading HDF5 files with variable of type
|
||||
* fixed-length string. We need to make it look like a
|
||||
* variable-length string, because that's all netCDF-4 data
|
||||
* model supports, lacking anonymous dimensions. So
|
||||
* variable-length strings are in allocated memory that user has
|
||||
* to free, which we allocate here. */
|
||||
if (var->type_info->nc_type_class == NC_STRING &&
|
||||
H5Tget_size(var->type_info->hdf_typeid) > 1 &&
|
||||
!H5Tis_variable_str(var->type_info->hdf_typeid))
|
||||
{
|
||||
hsize_t fstring_len;
|
||||
|
||||
if ((fstring_len = H5Tget_size(var->type_info->hdf_typeid)) == 0)
|
||||
BAIL(NC_EHDFERR);
|
||||
if (!(*(char **)data = malloc(1 + fstring_len)))
|
||||
BAIL(NC_ENOMEM);
|
||||
bufr = *(char **)data;
|
||||
}
|
||||
|
||||
/* Are we going to convert any data? (No converting of compound or
|
||||
* opaque types.) */
|
||||
if (mem_nc_type != var->type_info->hdr.id &&
|
||||
mem_nc_type != NC_COMPOUND && mem_nc_type != NC_OPAQUE)
|
||||
{
|
||||
/* We must convert - allocate a buffer. */
|
||||
need_to_convert++;
|
||||
if (var->ndims)
|
||||
for (d2 = 0; d2 < var->ndims; d2++)
|
||||
len *= countp[d2];
|
||||
LOG((4, "converting data for var %s type=%d len=%d", var->hdr.name,
|
||||
var->type_info->hdr.id, len));
|
||||
|
||||
/* If we're reading, we need bufr to have enough memory to store
|
||||
* the data in the file. If we're writing, we need bufr to be
|
||||
* big enough to hold all the data in the file's type. */
|
||||
if (len > 0)
|
||||
if (!(bufr = malloc(len * file_type_size)))
|
||||
BAIL(NC_ENOMEM);
|
||||
}
|
||||
else
|
||||
if (!bufr)
|
||||
bufr = data;
|
||||
|
||||
/* Create the data transfer property list. */
|
||||
if ((xfer_plistid = H5Pcreate(H5P_DATASET_XFER)) < 0)
|
||||
BAIL(NC_EHDFERR);
|
||||
|
||||
#ifdef USE_PARALLEL4
|
||||
/* Set up parallel I/O, if needed. */
|
||||
if ((retval = set_par_access(h5, var, xfer_plistid)))
|
||||
BAIL(retval);
|
||||
#endif
|
||||
|
||||
/* Read this hyperslab into memory. */
|
||||
LOG((5, "About to H5Dread some data..."));
|
||||
if (H5Dread(var->hdf_datasetid, var->type_info->native_hdf_typeid,
|
||||
mem_spaceid, file_spaceid, xfer_plistid, bufr) < 0)
|
||||
BAIL(NC_EHDFERR);
|
||||
|
||||
/* Convert data type if needed. */
|
||||
if (need_to_convert)
|
||||
{
|
||||
if ((retval = nc4_convert_type(bufr, data, var->type_info->hdr.id, mem_nc_type,
|
||||
len, &range_error, var->fill_value,
|
||||
(h5->cmode & NC_CLASSIC_MODEL))))
|
||||
BAIL(retval);
|
||||
|
||||
/* For strict netcdf-3 rules, ignore erange errors between UBYTE
|
||||
* and BYTE types. */
|
||||
if ((h5->cmode & NC_CLASSIC_MODEL) &&
|
||||
(var->type_info->hdr.id == NC_UBYTE || var->type_info->hdr.id == NC_BYTE) &&
|
||||
(mem_nc_type == NC_UBYTE || mem_nc_type == NC_BYTE) &&
|
||||
range_error)
|
||||
range_error = 0;
|
||||
}
|
||||
} /* endif ! no_read */
|
||||
else
|
||||
{
|
||||
#ifdef USE_PARALLEL4 /* Start block contributed by HDF group. */
|
||||
/* For collective IO read, some processes may not have any element for reading.
|
||||
Collective requires all processes to participate, so we use H5Sselect_none
|
||||
for these processes. */
|
||||
if (var->parallel_access == NC_COLLECTIVE)
|
||||
{
|
||||
/* Create the data transfer property list. */
|
||||
if ((xfer_plistid = H5Pcreate(H5P_DATASET_XFER)) < 0)
|
||||
BAIL(NC_EHDFERR);
|
||||
|
||||
if ((retval = set_par_access(h5, var, xfer_plistid)))
|
||||
BAIL(retval);
|
||||
|
||||
if (H5Sselect_none(file_spaceid) < 0)
|
||||
BAIL(NC_EHDFERR);
|
||||
|
||||
/* Since no element will be selected, we just get the memory
|
||||
* space the same as the file space. */
|
||||
if ((mem_spaceid = H5Dget_space(var->hdf_datasetid)) < 0)
|
||||
BAIL(NC_EHDFERR);
|
||||
if (H5Sselect_none(mem_spaceid) < 0)
|
||||
BAIL(NC_EHDFERR);
|
||||
|
||||
/* Read this hyperslab into memory. */
|
||||
LOG((5, "About to H5Dread some data..."));
|
||||
if (H5Dread(var->hdf_datasetid, var->type_info->native_hdf_typeid,
|
||||
mem_spaceid, file_spaceid, xfer_plistid, bufr) < 0)
|
||||
BAIL(NC_EHDFERR);
|
||||
}
|
||||
#endif /* End ifdef USE_PARALLEL4 */
|
||||
}
|
||||
/* Now we need to fake up any further data that was asked for,
|
||||
using the fill values instead. First skip past the data we
|
||||
just read, if any. */
|
||||
if (!scalar && provide_fill)
|
||||
{
|
||||
void *filldata;
|
||||
size_t real_data_size = 0;
|
||||
size_t fill_len;
|
||||
|
||||
/* Skip past the real data we've already read. */
|
||||
if (!no_read)
|
||||
for (real_data_size = file_type_size, d2 = 0; d2 < var->ndims; d2++)
|
||||
real_data_size *= (count[d2] - start[d2]);
|
||||
|
||||
/* Get the fill value from the HDF5 variable. Memory will be
|
||||
* allocated. */
|
||||
if (nc4_get_fill_value(h5, var, &fillvalue) < 0)
|
||||
BAIL(NC_EHDFERR);
|
||||
|
||||
/* How many fill values do we need? */
|
||||
for (fill_len = 1, d2 = 0; d2 < var->ndims; d2++)
|
||||
fill_len *= (fill_value_size[d2] ? fill_value_size[d2] : 1);
|
||||
|
||||
/* Copy the fill value into the rest of the data buffer. */
|
||||
filldata = (char *)data + real_data_size;
|
||||
for (i = 0; i < fill_len; i++)
|
||||
{
|
||||
|
||||
if (var->type_info->nc_type_class == NC_STRING)
|
||||
{
|
||||
if (*(char **)fillvalue)
|
||||
{
|
||||
if (!(*(char **)filldata = strdup(*(char **)fillvalue)))
|
||||
BAIL(NC_ENOMEM);
|
||||
}
|
||||
else
|
||||
*(char **)filldata = NULL;
|
||||
}
|
||||
else if (var->type_info->nc_type_class == NC_VLEN)
|
||||
{
|
||||
if (fillvalue)
|
||||
{
|
||||
memcpy(filldata,fillvalue,file_type_size);
|
||||
} else {
|
||||
*(char **)filldata = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
memcpy(filldata, fillvalue, file_type_size);
|
||||
filldata = (char *)filldata + file_type_size;
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
if (file_spaceid > 0)
|
||||
if (H5Sclose(file_spaceid) < 0)
|
||||
BAIL2(NC_EHDFERR);
|
||||
if (mem_spaceid > 0)
|
||||
if (H5Sclose(mem_spaceid) < 0)
|
||||
BAIL2(NC_EHDFERR);
|
||||
if (xfer_plistid > 0)
|
||||
if (H5Pclose(xfer_plistid) < 0)
|
||||
BAIL2(NC_EHDFERR);
|
||||
if (need_to_convert && bufr != NULL)
|
||||
free(bufr);
|
||||
if (xtend_size)
|
||||
free(xtend_size);
|
||||
if (fillvalue)
|
||||
{
|
||||
if (var->type_info->nc_type_class == NC_VLEN)
|
||||
nc_free_vlen((nc_vlen_t *)fillvalue);
|
||||
else if (var->type_info->nc_type_class == NC_STRING && *(char **)fillvalue)
|
||||
free(*(char **)fillvalue);
|
||||
free(fillvalue);
|
||||
}
|
||||
|
||||
/* If there was an error return it, otherwise return any potential
|
||||
range error value. If none, return NC_NOERR as usual.*/
|
||||
if (retval)
|
||||
return retval;
|
||||
if (range_error)
|
||||
return NC_ERANGE;
|
||||
return NC_NOERR;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user