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 COPYING file, which can be found  *
009 * at the root of the source code distribution tree,                         *
010 * or in https://www.hdfgroup.org/licenses.                                  *
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
021import org.slf4j.Logger;
022import org.slf4j.LoggerFactory;
023
024/** HDF5 utility class */
025public final class H5Utils {
026
027    private static final Logger log = LoggerFactory.getLogger(H5Utils.class);
028
029    /**
030     * Set up a hyperslab selection within a dataset.
031     *
032     * @param did
033     *            IN dataset ID
034     * @param dsetDims
035     *            IN dimensions
036     * @param startDims
037     *            IN start dimensions
038     * @param selectedStride
039     *            IN selected stride values
040     * @param selectedDims
041     *            IN selected dimensions
042     * @param spaceIDs
043     *            IN/OUT memory and file space IDs -- spaceIDs[0]=mspace, spaceIDs[1]=fspace
044     *
045     * @return total number of data points selected
046     *
047     * @throws HDF5Exception
048     *             If there is an error at the HDF5 library level.
049     */
050    public static final long selectHyperslab(long did, long[] dsetDims, long[] startDims,
051                                             long[] selectedStride, long[] selectedDims, long[] spaceIDs)
052        throws HDF5Exception
053    {
054        if (dsetDims == null) {
055            log.debug("selectHyperslab(): dsetDims is null");
056            return -1;
057        }
058
059        int rank = dsetDims.length;
060        if ((startDims != null) && (startDims.length != rank)) {
061            log.debug("selectHyperslab(): startDims rank didn't match dsetDims rank");
062            return -1;
063        }
064        if ((selectedStride != null) && (selectedStride.length != rank)) {
065            log.debug("selectHyperslab(): selectedStride rank didn't match startDims rank");
066            return -1;
067        }
068        if ((selectedDims != null) && (selectedDims.length != rank)) {
069            log.debug("selectHyperslab(): selectedDims rank didn't match startDims rank");
070            return -1;
071        }
072
073        long lsize = 1;
074
075        boolean isAllSelected = true;
076        for (int i = 0; i < rank; i++) {
077            if (selectedDims != null) {
078                lsize *= selectedDims[i];
079                if (selectedDims[i] < dsetDims[i])
080                    isAllSelected = false;
081            }
082        }
083
084        log.trace("selectHyperslab(): isAllSelected={}", isAllSelected);
085
086        if (isAllSelected) {
087            spaceIDs[0] = HDF5Constants.H5S_ALL;
088            spaceIDs[1] = HDF5Constants.H5S_ALL;
089        }
090        else {
091            spaceIDs[1] = H5.H5Dget_space(did);
092
093            // When a 1D dataspace is used for a chunked dataset, reading is very slow.
094            //
095            // It is a known problem within the HDF5 library.
096            // mspace = H5.H5Screate_simple(1, lsize, null);
097            spaceIDs[0] = H5.H5Screate_simple(rank, selectedDims, null);
098            H5.H5Sselect_hyperslab(spaceIDs[1], HDF5Constants.H5S_SELECT_SET, startDims, selectedStride,
099                                   selectedDims, null);
100        }
101
102        return lsize;
103    }
104
105    /**
106     * Get the total number of datapoints for the hyperslab selection within a dataset.
107     *
108     * @param did
109     *            IN dataset ID
110     * @param dsetDims
111     *            IN dimensions
112     * @param startDims
113     *            IN start dimensions
114     * @param selectedStride
115     *            IN selected stride values
116     * @param selectedDims
117     *            IN selected dimensions
118     * @param spaceIDs
119     *            IN/OUT memory and file space IDs -- spaceIDs[0]=mspace, spaceIDs[1]=fspace
120     *
121     * @return total number of data points selected
122     *
123     * @throws HDF5Exception
124     *             If there is an error at the HDF5 library level.
125     */
126    public static final long getTotalSelectedSpacePoints(long did, long[] dsetDims, long[] startDims,
127                                                         long[] selectedStride, long[] selectedDims,
128                                                         long[] spaceIDs) throws HDF5Exception
129    {
130        long totalSelectedSpacePoints =
131            selectHyperslab(did, dsetDims, startDims, selectedStride, selectedDims, spaceIDs);
132
133        log.trace("getTotalSelectedSpacePoints(): selected {} points in dataset's dataspace",
134                  totalSelectedSpacePoints);
135
136        if (totalSelectedSpacePoints == 0) {
137            log.debug("getTotalSelectedSpacePoints(): No data to read. Dataset or selected subset is empty.");
138            throw new HDF5Exception("No data to read.\nEither the dataset or the selected subset is empty.");
139        }
140
141        if (totalSelectedSpacePoints < Integer.MIN_VALUE || totalSelectedSpacePoints > Integer.MAX_VALUE) {
142            log.debug(
143                "getTotalSelectedSpacePoints(): totalSelectedSpacePoints outside valid Java int range; unsafe cast");
144            throw new HDF5Exception("Invalid int size");
145        }
146
147        if (log.isDebugEnabled()) {
148            // check is storage space is allocated
149            try {
150                long ssize = H5.H5Dget_storage_size(did);
151                log.trace("getTotalSelectedSpacePoints(): Storage space allocated = {} bytes", ssize);
152            }
153            catch (Exception ex) {
154                log.debug("getTotalSelectedSpacePoints(): check if storage space is allocated:", ex);
155            }
156        }
157
158        return totalSelectedSpacePoints;
159    }
160}