001/*****************************************************************************
002 * Copyright by The HDF Group.                                               *
003 * Copyright by the Board of Trustees of the University of Illinois.         *
004 * All rights reserved.                                                      *
005 *                                                                           *
006 * This file is part of the HDF Java Products distribution.                  *
007 * The full copyright notice, including terms governing use, modification,   *
008 * and redistribution, is contained in the files COPYING and Copyright.html. *
009 * COPYING can be found at the root of the source code distribution tree.    *
010 * Or, see https://support.hdfgroup.org/products/licenses.html               *
011 * If you do not have access to either file, you may request a copy from     *
012 * help@hdfgroup.org.                                                        *
013 ****************************************************************************/
014
015package hdf.object.h5;
016
017import hdf.hdf5lib.H5;
018import hdf.hdf5lib.HDF5Constants;
019import hdf.hdf5lib.exceptions.HDF5Exception;
020
021/** HDF5 utility class */
022public final class H5Utils {
023
024    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(H5Utils.class);
025
026    /**
027     * Set up a hyperslab selection within a dataset.
028     *
029     * @param did
030     *            IN dataset ID
031     * @param dsetDims
032     *            IN dimensions
033     * @param startDims
034     *            IN start dimensions
035     * @param selectedStride
036     *            IN selected stride values
037     * @param selectedDims
038     *            IN selected dimensions
039     * @param spaceIDs
040     *            IN/OUT memory and file space IDs -- spaceIDs[0]=mspace, spaceIDs[1]=fspace
041     *
042     * @return total number of data points selected
043     *
044     * @throws HDF5Exception
045     *             If there is an error at the HDF5 library level.
046     */
047    public static final long selectHyperslab(long did, long[] dsetDims, long[] startDims, long[] selectedStride,
048            long[] selectedDims, long[] spaceIDs) throws HDF5Exception {
049        if (dsetDims == null) {
050            log.debug("selectHyperslab(): dsetDims is null");
051            return -1;
052        }
053
054        int rank = dsetDims.length;
055        if ((startDims != null) && (startDims.length != rank)) {
056            log.debug("selectHyperslab(): startDims rank didn't match dsetDims rank");
057            return -1;
058        }
059        if ((selectedStride != null) && (selectedStride.length != rank)) {
060            log.debug("selectHyperslab(): selectedStride rank didn't match startDims rank");
061            return -1;
062        }
063        if ((selectedDims != null) && (selectedDims.length != rank)) {
064            log.debug("selectHyperslab(): selectedDims rank didn't match startDims rank");
065            return -1;
066        }
067
068        long lsize = 1;
069
070        boolean isAllSelected = true;
071        for (int i = 0; i < rank; i++) {
072            if (selectedDims != null) {
073                lsize *= selectedDims[i];
074                if (selectedDims[i] < dsetDims[i])
075                    isAllSelected = false;
076            }
077        }
078
079        log.trace("selectHyperslab(): isAllSelected={}", isAllSelected);
080
081        if (isAllSelected) {
082            spaceIDs[0] = HDF5Constants.H5S_ALL;
083            spaceIDs[1] = HDF5Constants.H5S_ALL;
084        }
085        else {
086            spaceIDs[1] = H5.H5Dget_space(did);
087
088            // When a 1D dataspace is used for a chunked dataset, reading is very slow.
089            //
090            // It is a known problem within the HDF5 library.
091            // mspace = H5.H5Screate_simple(1, lsize, null);
092            spaceIDs[0] = H5.H5Screate_simple(rank, selectedDims, null);
093            H5.H5Sselect_hyperslab(spaceIDs[1], HDF5Constants.H5S_SELECT_SET, startDims, selectedStride, selectedDims, null);
094        }
095
096        return lsize;
097    }
098
099    /**
100     * Get the total number of datapoints for the hyperslab selection within a dataset.
101     *
102     * @param did
103     *            IN dataset ID
104     * @param dsetDims
105     *            IN dimensions
106     * @param startDims
107     *            IN start dimensions
108     * @param selectedStride
109     *            IN selected stride values
110     * @param selectedDims
111     *            IN selected dimensions
112     * @param spaceIDs
113     *            IN/OUT memory and file space IDs -- spaceIDs[0]=mspace, spaceIDs[1]=fspace
114     *
115     * @return total number of data points selected
116     *
117     * @throws HDF5Exception
118     *             If there is an error at the HDF5 library level.
119     */
120    public static final long getTotalSelectedSpacePoints(long did, long[] dsetDims, long[] startDims,
121            long[] selectedStride, long[] selectedDims, long[] spaceIDs) throws HDF5Exception {
122        long totalSelectedSpacePoints = selectHyperslab(did, dsetDims, startDims, selectedStride, selectedDims, spaceIDs);
123
124        log.trace("getTotalSelectedSpacePoints(): selected {} points in dataset's dataspace", totalSelectedSpacePoints);
125
126        if (totalSelectedSpacePoints == 0) {
127            log.debug("getTotalSelectedSpacePoints(): No data to read. Dataset or selected subset is empty.");
128            throw new HDF5Exception("No data to read.\nEither the dataset or the selected subset is empty.");
129        }
130
131        if (totalSelectedSpacePoints < Integer.MIN_VALUE || totalSelectedSpacePoints > Integer.MAX_VALUE) {
132            log.debug("getTotalSelectedSpacePoints(): totalSelectedSpacePoints outside valid Java int range; unsafe cast");
133            throw new HDF5Exception("Invalid int size");
134        }
135
136        if (log.isDebugEnabled()) {
137            // check is storage space is allocated
138            try {
139                long ssize = H5.H5Dget_storage_size(did);
140                log.trace("getTotalSelectedSpacePoints(): Storage space allocated = {} bytes", ssize);
141            }
142            catch (Exception ex) {
143                log.debug("getTotalSelectedSpacePoints(): check if storage space is allocated:", ex);
144            }
145        }
146
147        return totalSelectedSpacePoints;
148    }
149
150}