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