diff options
author | Allen Byrne <50328838+byrnHDF@users.noreply.github.com> | 2022-08-09 23:11:14 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-08-09 23:11:14 (GMT) |
commit | 4c66bf627ec4b963f026bbfa7101127271644f79 (patch) | |
tree | 4a4352a58dde0a80f7f72eab56484ddd94ec2294 /src/H5Dmodule.h | |
parent | fc9f31ad8c8ff4122e8bb2997e0a2bfa89cb054b (diff) | |
download | hdf5-4c66bf627ec4b963f026bbfa7101127271644f79.zip hdf5-4c66bf627ec4b963f026bbfa7101127271644f79.tar.gz hdf5-4c66bf627ec4b963f026bbfa7101127271644f79.tar.bz2 |
Merge UG from 1.10 and add prelim vol section (#1980)
* Merge UG from 1.10 and add prelim vol section
* Spelling fixes
* Merge format and autotools javadoc from 1.10
Diffstat (limited to 'src/H5Dmodule.h')
-rw-r--r-- | src/H5Dmodule.h | 2956 |
1 files changed, 2955 insertions, 1 deletions
diff --git a/src/H5Dmodule.h b/src/H5Dmodule.h index 596fd48..4ad3709 100644 --- a/src/H5Dmodule.h +++ b/src/H5Dmodule.h @@ -29,7 +29,2961 @@ #define H5_MY_PKG_ERR H5E_DATASET #define H5_MY_PKG_INIT YES -/**\defgroup H5D H5D +/** \page H5D_UG HDF5 Datasets + * + * \section sec_dataset HDF5 Datasets + * + * \subsection subsec_dataset_intro Introduction + * + * An HDF5 dataset is an object composed of a collection of data elements, or raw data, and + * metadata that stores a description of the data elements, data layout, and all other information + * necessary to write, read, and interpret the stored data. From the viewpoint of the application the + * raw data is stored as a one-dimensional or multi-dimensional array of elements (the raw data), + * those elements can be any of several numerical or character types, small arrays, or even + * compound types similar to C structs. The dataset object may have attribute objects. See the + * figure below. + * + * <table> + * <tr> + * <td> + * \image html Dsets_fig1.gif "Application view of a dataset" + * </td> + * </tr> + * </table> + * + * A dataset object is stored in a file in two parts: a header and a data array. The header contains + * information that is needed to interpret the array portion of the dataset, as well as metadata (or + * pointers to metadata) that describes or annotates the dataset. Header information includes the + * name of the object, its dimensionality, its number-type, information about how the data itself is + * stored on disk (the storage layout), and other information used by the library to speed up access + * to the dataset or maintain the file’s integrity. + * + * The HDF5 dataset interface, comprising the @ref H5D functions, provides a mechanism for managing + * HDF5 datasets including the transfer of data between memory and disk and the description of + * dataset properties. + * + * A dataset is used by other HDF5 APIs, either by name or by an identifier. For more information, + * \see \ref api-compat-macros. + * + * \subsubsection subsubsec_dataset_intro_link Link/Unlink + * A dataset can be added to a group with one of the H5Lcreate calls, and deleted from a group with + * #H5Ldelete. The link and unlink operations use the name of an object, which may be a dataset. + * The dataset does not have to open to be linked or unlinked. + * + * \subsubsection subsubsec_dataset_intro_obj Object Reference + * A dataset may be the target of an object reference. The object reference is created by + * #H5Rcreate with the name of an object which may be a dataset and the reference type + * #H5R_OBJECT. The dataset does not have to be open to create a reference to it. + * + * An object reference may also refer to a region (selection) of a dataset. The reference is created + * with #H5Rcreate and a reference type of #H5R_DATASET_REGION. + * + * An object reference can be accessed by a call to #H5Rdereference. When the reference is to a + * dataset or dataset region, the #H5Rdereference call returns an identifier to the dataset just as if + * #H5Dopen has been called. + * + * \subsubsection subsubsec_dataset_intro_attr Adding Attributes + * A dataset may have user-defined attributes which are created with #H5Acreate and accessed + * through the @ref H5A API. To create an attribute for a dataset, the dataset must be open, and the + * identifier is passed to #H5Acreate. The attributes of a dataset are discovered and opened using + * #H5Aopen_name, #H5Aopen_idx, or #H5Aiterate; these functions use the identifier of the dataset. + * An attribute can be deleted with #H5Adelete which also uses the identifier of the dataset. + * + * \subsection subsec_dataset_function Dataset Function Summaries + * Functions that can be used with datasets (@ref H5D functions) and property list functions that can + * used with datasets (@ref H5P functions) are listed below. + * + * <table> + * <caption>Dataset functions</caption> + * <tr> + * <th>Function</th> + * <th>Purpose</th> + * </tr> + * <tr> + * <td>#H5Dcreate</td> + * <td>Creates a dataset at the specified location. The + * C function is a macro: \see \ref api-compat-macros.</td> + * </tr> + * <tr> + * <td>#H5Dcreate_anon</td> + * <td>Creates a dataset in a file without linking it into the file structure.</td> + * </tr> + * <tr> + * <td>#H5Dopen</td> + * <td>Opens an existing dataset. The C function is a macro: \see \ref api-compat-macros.</td> + * </tr> + * <tr> + * <td>#H5Dclose</td> + * <td>Closes the specified dataset.</td> + * </tr> + * <tr> + * <td>#H5Dget_space</td> + * <td>Returns an identifier for a copy of the dataspace for a dataset.</td> + * </tr> + * <tr> + * <td>#H5Dget_space_status</td> + * <td>Determines whether space has been allocated for a dataset.</td> + * </tr> + * <tr> + * <td>#H5Dget_type</td> + * <td>Returns an identifier for a copy of the datatype for a dataset.</td> + * </tr> + * <tr> + * <td>#H5Dget_create_plist</td> + * <td>Returns an identifier for a copy of the dataset creation property list for a dataset.</td> + * </tr> + * <tr> + * <td>#H5Dget_access_plist</td> + * <td>Returns the dataset access property list associated with a dataset.</td> + * </tr> + * <tr> + * <td>#H5Dget_offset</td> + * <td>Returns the dataset address in a file.</td> + * </tr> + * <tr> + * <td>#H5Dget_storage_size</td> + * <td>Returns the amount of storage required for a dataset.</td> + * </tr> + * <tr> + * <td>#H5Dvlen_get_buf_size</td> + * <td>Determines the number of bytes required to store variable-length (VL) data.</td> + * </tr> + * <tr> + * <td>#H5Dvlen_reclaim</td> + * <td>Reclaims VL datatype memory buffers.</td> + * </tr> + * <tr> + * <td>#H5Dread</td> + * <td>Reads raw data from a dataset into a buffer.</td> + * </tr> + * <tr> + * <td>#H5Dwrite</td> + * <td>Writes raw data from a buffer to a dataset.</td> + * </tr> + * <tr> + * <td>#H5Diterate</td> + * <td>Iterates over all selected elements in a dataspace.</td> + * </tr> + * <tr> + * <td>#H5Dgather</td> + * <td>Gathers data from a selection within a memory buffer.</td> + * </tr> + * <tr> + * <td>#H5Dscatter</td> + * <td>Scatters data into a selection within a memory buffer.</td> + * </tr> + * <tr> + * <td>#H5Dfill</td> + * <td>Fills dataspace elements with a fill value in a memory buffer.</td> + * </tr> + * <tr> + * <td>#H5Dset_extent</td> + * <td>Changes the sizes of a dataset’s dimensions.</td> + * </tr> + * </table> + * + * <table> + * <caption>Dataset creation property list functions (H5P)</caption> + * <tr> + * <th>Function</th> + * <th>Purpose</th> + * </tr> + * <tr> + * <td>#H5Pset_layout</td> + * <td>Sets the type of storage used to store the raw data for a dataset.</td> + * </tr> + * <tr> + * <td>#H5Pget_layout</td> + * <td>Returns the layout of the raw data for a dataset.</td> + * </tr> + * <tr> + * <td>#H5Pset_chunk</td> + * <td>Sets the size of the chunks used to store a chunked layout dataset.</td> + * </tr> + * <tr> + * <td>#H5Pget_chunk</td> + * <td>Retrieves the size of chunks for the raw data of a chunked layout dataset.</td> + * </tr> + * <tr> + * <td>#H5Pset_deflate</td> + * <td>Sets compression method and compression level.</td> + * </tr> + * <tr> + * <td>#H5Pset_fill_value</td> + * <td>Sets the fill value for a dataset.</td> + * </tr> + * <tr> + * <td>#H5Pget_fill_value</td> + * <td>Retrieves a dataset fill value.</td> + * </tr> + * <tr> + * <td>#H5Pfill_value_defined</td> + * <td>Determines whether the fill value is defined.</td> + * </tr> + * <tr> + * <td>#H5Pset_fill_time</td> + * <td>Sets the time when fill values are written to a dataset.</td> + * </tr> + * <tr> + * <td>#H5Pget_fill_time</td> + * <td>Retrieves the time when fill value are written to a dataset.</td> + * </tr> + * <tr> + * <td>#H5Pset_alloc_time</td> + * <td>Sets the timing for storage space allocation.</td> + * </tr> + * <tr> + * <td>#H5Pget_alloc_time</td> + * <td>Retrieves the timing for storage space allocation.</td> + * </tr> + * <tr> + * <td>#H5Pset_filter</td> + * <td>Adds a filter to the filter pipeline.</td> + * </tr> + * <tr> + * <td>#H5Pall_filters_avail</td> + * <td>Verifies that all required filters are available.</td> + * </tr> + * <tr> + * <td>#H5Pget_nfilters</td> + * <td>Returns the number of filters in the pipeline.</td> + * </tr> + * <tr> + * <td>#H5Pget_filter</td> + * <td>Returns information about a filter in a pipeline. + * The C function is a macro: \see \ref api-compat-macros.</td> + * </tr> + * <tr> + * <td>#H5Pget_filter_by_id</td> + * <td>Returns information about the specified filter. + * The C function is a macro: \see \ref api-compat-macros.</td> + * </tr> + * <tr> + * <td>#H5Pmodify_filter</td> + * <td>Modifies a filter in the filter pipeline.</td> + * </tr> + * <tr> + * <td>#H5Premove_filter</td> + * <td>Deletes one or more filters in the filter pipeline.</td> + * </tr> + * <tr> + * <td>#H5Pset_fletcher32</td> + * <td>Sets up use of the Fletcher32 checksum filter.</td> + * </tr> + * <tr> + * <td>#H5Pset_nbit</td> + * <td>Sets up use of the n-bit filter.</td> + * </tr> + * <tr> + * <td>#H5Pset_scaleoffset</td> + * <td>Sets up use of the scale-offset filter.</td> + * </tr> + * <tr> + * <td>#H5Pset_shuffle</td> + * <td>Sets up use of the shuffle filter.</td> + * </tr> + * <tr> + * <td>#H5Pset_szip</td> + * <td>Sets up use of the Szip compression filter.</td> + * </tr> + * <tr> + * <td>#H5Pset_external</td> + * <td>Adds an external file to the list of external files.</td> + * </tr> + * <tr> + * <td>#H5Pget_external_count</td> + * <td>Returns the number of external files for a dataset.</td> + * </tr> + * <tr> + * <td>#H5Pget_external</td> + * <td>Returns information about an external file.</td> + * </tr> + * <tr> + * <td>#H5Pset_char_encoding</td> + * <td>Sets the character encoding used to encode a string. Use to set ASCII or UTF-8 character + * encoding for object names.</td> + * </tr> + * <tr> + * <td>#H5Pget_char_encoding</td> + * <td>Retrieves the character encoding used to create a string.</td> + * </tr> + * </table> + * + * <table> + * <caption>Dataset access property list functions (H5P)</caption> + * <tr> + * <th>Function</th> + * <th>Purpose</th> + * </tr> + * <tr> + * <td>#H5Pset_buffer</td> + * <td>Sets type conversion and background buffers.</td> + * </tr> + * <tr> + * <td>#H5Pget_buffer</td> + * <td>Reads buffer settings.</td> + * </tr> + * <tr> + * <td>#H5Pset_chunk_cache</td> + * <td>Sets the raw data chunk cache parameters.</td> + * </tr> + * <tr> + * <td>#H5Pget_chunk_cache</td> + * <td>Retrieves the raw data chunk cache parameters.</td> + * </tr> + * <tr> + * <td>#H5Pset_edc_check</td> + * <td>Sets whether to enable error-detection when reading a dataset.</td> + * </tr> + * <tr> + * <td>#H5Pget_edc_check</td> + * <td>Determines whether error-detection is enabled for dataset reads.</td> + * </tr> + * <tr> + * <td>#H5Pset_filter_callback</td> + * <td>Sets user-defined filter callback function.</td> + * </tr> + * <tr> + * <td>#H5Pset_data_transform</td> + * <td>Sets a data transform expression.</td> + * </tr> + * <tr> + * <td>#H5Pget_data_transform</td> + * <td>Retrieves a data transform expression.</td> + * </tr> + * <tr> + * <td>#H5Pset_type_conv_cb</td> + * <td>Sets user-defined datatype conversion callback function.</td> + * </tr> + * <tr> + * <td>#H5Pget_type_conv_cb</td> + * <td>Gets user-defined datatype conversion callback function.</td> + * </tr> + * <tr> + * <td>#H5Pset_hyper_vector_size</td> + * <td>Sets number of I/O vectors to be read/written in hyperslab I/O.</td> + * </tr> + * <tr> + * <td>#H5Pget_hyper_vector_size</td> + * <td>Retrieves number of I/O vectors to be read/written in hyperslab I/O.</td> + * </tr> + * <tr> + * <td>#H5Pset_btree_ratios</td> + * <td>Sets B-tree split ratios for a dataset transfer property list.</td> + * </tr> + * <tr> + * <td>#H5Pget_btree_ratios</td> + * <td>Gets B-tree split ratios for a dataset transfer property list.</td> + * </tr> + * <tr> + * <td>#H5Pset_vlen_mem_manager</td> + * <td>Sets the memory manager for variable-length datatype allocation in #H5Dread and + * #H5Dvlen_reclaim.</td> + * </tr> + * <tr> + * <td>#H5Pget_vlen_mem_manager</td> + * <td>Gets the memory manager for variable-length datatype allocation in #H5Dread and + * #H5Dvlen_reclaim.</td> + * </tr> + * <tr> + * <td>#H5Pset_dxpl_mpio</td> + * <td>Sets data transfer mode.</td> + * </tr> + * <tr> + * <td>#H5Pget_dxpl_mpio</td> + * <td>Returns the data transfer mode.</td> + * </tr> + * <tr> + * <td>#H5Pset_dxpl_mpio_chunk_opt</td> + * <td>Sets a flag specifying linked-chunk I/O or multi-chunk I/O.</td> + * </tr> + * <tr> + * <td>#H5Pset_dxpl_mpio_chunk_opt_num</td> + * <td>Sets a numeric threshold for linked-chunk I/O.</td> + * </tr> + * <tr> + * <td>#H5Pset_dxpl_mpio_chunk_opt_ratio</td> + * <td>Sets a ratio threshold for collective I/O.</td> + * </tr> + * <tr> + * <td>#H5Pset_dxpl_mpio_collective_opt</td> + * <td>Sets a flag governing the use of independent versus collective I/O.</td> + * </tr> + * <tr> + * <td>#H5Pset_multi_type</td> + * <td>Sets the type of data property for the MULTI driver.</td> + * </tr> + * <tr> + * <td>#H5Pget_multi_type</td> + * <td>Retrieves the type of data property for the MULTI driver.</td> + * </tr> + * <tr> + * <td>#H5Pset_small_data_block_size</td> + * <td>Sets the size of a contiguous block reserved for small data.</td> + * </tr> + * <tr> + * <td>#H5Pget_small_data_block_size</td> + * <td>Retrieves the current small data block size setting.</td> + * </tr> + * </table> + * + * \subsection subsec_dataset_program Programming Model for Datasets + * This section explains the programming model for datasets. + * + * \subsubsection subsubsec_dataset_program_general General Model + * + * The programming model for using a dataset has three main phases: + * \li Obtain access to the dataset + * \li Operate on the dataset using the dataset identifier returned at access + * \li Release the dataset + * + * These three phases or steps are described in more detail below the figure. + * + * A dataset may be opened several times and operations performed with several different + * identifiers to the same dataset. All the operations affect the dataset although the calling program + * must synchronize if necessary to serialize accesses. + * + * Note that the dataset remains open until every identifier is closed. The figure below shows the + * basic sequence of operations. + * + * <table> + * <tr> + * <td> + * \image html Dsets_fig2.gif "Dataset programming sequence" + * </td> + * </tr> + * </table> + * + * Creation and data access operations may have optional parameters which are set with property + * lists. The general programming model is: + * \li Create property list of appropriate class (dataset create, dataset transfer) + * \li Set properties as needed; each type of property has its own format and datatype + * \li Pass the property list as a parameter of the API call + * + * The steps below describe the programming phases or steps for using a dataset. + * <h4>Step 1. Obtain Access</h4> + * A new dataset is created by a call to #H5Dcreate. If successful, the call returns an identifier for the + * newly created dataset. + * + * Access to an existing dataset is obtained by a call to #H5Dopen. This call returns an identifier for + * the existing dataset. + * + * An object reference may be dereferenced to obtain an identifier to the dataset it points to. + * + * In each of these cases, the successful call returns an identifier to the dataset. The identifier is + * used in subsequent operations until the dataset is closed. + * + * <h4>Step 2. Operate on the Dataset</h4> + * The dataset identifier can be used to write and read data to the dataset, to query and set + * properties, and to perform other operations such as adding attributes, linking in groups, and + * creating references. + * + * The dataset identifier can be used for any number of operations until the dataset is closed. + * + * <h4>Step 3. Close the Dataset</h4> + * When all operations are completed, the dataset identifier should be closed with a call to + * #H5Dclose. This releases the dataset. + * + * After the identifier is closed, it cannot be used for further operations. + * + * \subsubsection subsubsec_dataset_program_create Create Dataset + * + * A dataset is created and initialized with a call to #H5Dcreate. The dataset create operation sets + * permanent properties of the dataset: + * \li Name + * \li Dataspace + * \li Datatype + * \li Storage properties + * + * These properties cannot be changed for the life of the dataset, although the dataspace may be + * expanded up to its maximum dimensions. + * + * <h4>Name</h4> + * A dataset name is a sequence of alphanumeric ASCII characters. The full name would include a + * tracing of the group hierarchy from the root group of the file. An example is + * /rootGroup/groupA/subgroup23/dataset1. The local name or relative name within the lowest- + * level group containing the dataset would include none of the group hierarchy. An example is + * Dataset1. + * + * <h4>Dataspace</h4> + * The dataspace of a dataset defines the number of dimensions and the size of each dimension. The + * dataspace defines the number of dimensions, and the maximum dimension sizes and current size + * of each dimension. The maximum dimension size can be a fixed value or the constant + * #H5S_UNLIMITED, in which case the actual dimension size can be changed with calls to + * #H5Dset_extent, up to the maximum set with the maxdims parameter in the #H5Screate_simple + * call that established the dataset’s original dimensions. The maximum dimension size is set when + * the dataset is created and cannot be changed. + * + * <h4>Datatype</h4> + * Raw data has a datatype which describes the layout of the raw data stored in the file. The + * datatype is set when the dataset is created and can never be changed. When data is transferred to + * and from the dataset, the HDF5 library will assure that the data is transformed to and from the + * stored format. + * + * <h4>Storage Properties</h4> + * Storage properties of the dataset are set when it is created. The required inputs table below shows + * the categories of storage properties. The storage properties cannot be changed after the dataset is + * created. + * + * <h4>Filters</h4> + * When a dataset is created, optional filters are specified. The filters are added to the data transfer + * pipeline when data is read or written. The standard library includes filters to implement + * compression, data shuffling, and error detection code. Additional user-defined filters may also be + * used. + * + * The required filters are stored as part of the dataset, and the list may not be changed after the + * dataset is created. The HDF5 library automatically applies the filters whenever data is + * transferred. + * + * <h4>Summary</h4> + * + * A newly created dataset has no attributes and no data values. The dimensions, datatype, storage + * properties, and selected filters are set. The table below lists the required inputs, and the second + * table below lists the optional inputs. + * + * <table> + * <caption>Required inputs</caption> + * <tr> + * <th>Required Inputs</th> + * <th>Description</th> + * </tr> + * <tr> + * <td>Dataspace</td> + * <td>The shape of the array.</td> + * </tr> + * <tr> + * <td>Datatype</td> + * <td>The layout of the stored elements.</td> + * </tr> + * <tr> + * <td>Name</td> + * <td>The name of the dataset in the group.</td> + * </tr> + * </table> + * + * <table> + * <caption>Optional inputs</caption> + * <tr> + * <th>Optional Inputs</th> + * <th>Description</th> + * </tr> + * <tr> + * <td>Storage Layout</td> + * <td>How the data is organized in the file including chunking.</td> + * </tr> + * <tr> + * <td>Fill Value</td> + * <td>The behavior and value for uninitialized data.</td> + * </tr> + * <tr> + * <td>External Storage</td> + * <td>Option to store the raw data in an external file.</td> + * </tr> + * <tr> + * <td>Filters</td> + * <td>Select optional filters to be applied. One of the filters that might be applied is compression.</td> + * </tr> + * </table> + * + * <h4>Example</h4> + * To create a new dataset, go through the following general steps: + * \li Set dataset characteristics (optional where default settings are acceptable) + * \li Datatype + * \li Dataspace + * \li Dataset creation property list + * \li Create the dataset + * \li Close the datatype, dataspace, and property list (as necessary) + * \li Close the dataset + * + * Example 1 below shows example code to create an empty dataset. The dataspace is 7 x 8, and the + * datatype is a big-endian integer. The dataset is created with the name “dset1” and is a member of + * the root group, “/”. + * + * <em> Example 1. Create an empty dataset</em> + * \code + * hid_t dataset, datatype, dataspace; + * + * // Create dataspace: Describe the size of the array and create the dataspace for fixed-size dataset. + * dimsf[0] = 7; + * dimsf[1] = 8; + * dataspace = H5Screate_simple(2, dimsf, NULL); + * + * // Define datatype for the data in the file. + * // For this example, store little-endian integer numbers. + * datatype = H5Tcopy(H5T_NATIVE_INT); + * status = H5Tset_order(datatype, H5T_ORDER_LE); + * + * // Create a new dataset within the file using defined + * // dataspace and datatype. No properties are set. + * dataset = H5Dcreate(file, "/dset", datatype, dataspace, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + * H5Dclose(dataset); + * H5Sclose(dataspace); + * H5Tclose(datatype); + * \endcode + * + * Example 2, below, shows example code to create a similar dataset with a fill value of ‘-1’. This + * code has the same steps as in the example above, but uses a non-default property list. A file + * creation property list is created, and then the fill value is set to the desired value. Then the + * property list is passed to the #H5Dcreate call. + * + * <em> Example 2. Create a dataset with fill value set</em> + * \code + * hid_t plist; // property list + * hid_t dataset, datatype, dataspace; + * int fillval = -1; + * + * dimsf[0] = 7; + * dimsf[1] = 8; + * dataspace = H5Screate_simple(2, dimsf, NULL); + * datatype = H5Tcopy(H5T_NATIVE_INT); + * status = H5Tset_order(datatype, H5T_ORDER_LE); + * + * // Example of Dataset Creation property list: set fill value to '-1' + * plist = H5Pcreate(H5P_DATASET_CREATE); + * status = H5Pset_fill_value(plist, datatype, &fillval); + * + * // Same as above, but use the property list + * dataset = H5Dcreate(file, "/dset", datatype, dataspace, H5P_DEFAULT, plist, H5P_DEFAULT); + * H5Dclose(dataset); + * H5Sclose(dataspace); + * H5Tclose(datatype); + * H5Pclose(plist); + * \endcode + * + * After this code is executed, the dataset has been created and written to the file. The data array is + * uninitialized. Depending on the storage strategy and fill value options that have been selected, + * some or all of the space may be allocated in the file, and fill values may be written in the file. + * + * \subsubsection subsubsec_dataset_program_transfer Data Transfer Operations on a Dataset + * Data is transferred between memory and the raw data array of the dataset through #H5Dwrite and + * #H5Dread operations. A data transfer has the following basic steps: + * \li 1. Allocate and initialize memory space as needed + * \li 2. Define the datatype of the memory elements + * \li 3. Define the elements to be transferred (a selection, or all the elements) + * \li 4. Set data transfer properties (including parameters for filters or file drivers) as needed + * \li 5. Call the @ref H5D API + * + * Note that the location of the data in the file, the datatype of the data in the file, the storage + * properties, and the filters do not need to be specified because these are stored as a permanent part + * of the dataset. A selection of elements from the dataspace is specified; the selected elements may + * be the whole dataspace. + * + * The following figure shows a diagram of a write operation which + * transfers a data array from memory to a dataset in the file (usually on disk). A read operation has + * similar parameters with the data flowing the other direction. + * + * <table> + * <tr> + * <td> + * \image html Dsets_fig3.gif "A write operation" + * </td> + * </tr> + * </table> + * + * <h4>Memory Space</h4> + * The calling program must allocate sufficient memory to store the data elements to be transferred. + * For a write (from memory to the file), the memory must be initialized with the data to be written + * to the file. For a read, the memory must be large enough to store the elements that will be read. + * The amount of storage needed can be computed from the memory datatype (which defines the + * size of each data element) and the number of elements in the selection. + * + * <h4>Memory Datatype</h4> + * The memory layout of a single data element is specified by the memory datatype. This specifies + * the size, alignment, and byte order of the element as well as the datatype class. Note that the + * memory datatype must be the same datatype class as the file, but may have different byte order + * and other properties. The HDF5 Library automatically transforms data elements between the + * source and destination layouts. For more information, \ref sec_datatype. + * + * For a write, the memory datatype defines the layout of the data to be written; an example is IEEE + * floating-point numbers in native byte order. If the file datatype (defined when the dataset is + * created) is different but compatible, the HDF5 Library will transform each data element when it + * is written. For example, if the file byte order is different than the native byte order, the HDF5 + * library will swap the bytes. + * + * For a read, the memory datatype defines the desired layout of the data to be read. This must be + * compatible with the file datatype, but should generally use native formats such as byte orders. + * The HDF5 library will transform each data element as it is read. + * + * <h4>Selection</h4> + * The data transfer will transfer some or all of the elements of the dataset depending on the + * dataspace selection. The selection has two dataspace objects: one for the source, and one for the + * destination. These objects describe which elements of the dataspace to be transferred. Some + * (partial I/O) or all of the data may be transferred. Partial I/O is defined by defining hyperslabs or + * lists of elements in a dataspace object. + * + * The dataspace selection for the source defines the indices of the elements to be read or written. + * The two selections must define the same number of points, but the order and layout may be + * different. The HDF5 Library automatically selects and distributes the elements according to the + * selections. It might, for example, perform a scatter-gather or sub-set of the data. + * + * <h4>Data Transfer Properties</h4> + * For some data transfers, additional parameters should be set using the transfer property list. The + * table below lists the categories of transfer properties. These properties set parameters for the + * HDF5 Library and may be used to pass parameters for optional filters and file drivers. For + * example, transfer properties are used to select independent or collective operation when using + * MPI-I/O. + * + * <table> + * <caption>Categories of transfer properties</caption> + * <tr> + * <th>Properties</th> + * <th>Description</th> + * </tr> + * <tr> + * <td>Library parameters</td> + * <td>Internal caches, buffers, B-Trees, etc.</td> + * </tr> + * <tr> + * <td>Memory management</td> + * <td>Variable-length memory management, data overwrite</td> + * </tr> + * <tr> + * <td>File driver management</td> + * <td>Parameters for file drivers</td> + * </tr> + * <tr> + * <td>Filter management</td> + * <td>Parameters for filters</td> + * </tr> + * </table> + * + * <h4>Data Transfer Operation (Read or Write)</h4> + * The data transfer is done by calling #H5Dread or #H5Dwrite with the parameters described above. + * The HDF5 Library constructs the required pipeline, which will scatter-gather, transform + * datatypes, apply the requested filters, and use the correct file driver. + * + * During the data transfer, the transformations and filters are applied to each element of the data in + * the required order until all the data is transferred. + * + * <h4>Summary</h4> + * To perform a data transfer, it is necessary to allocate and initialize memory, describe the source + * and destination, set required and optional transfer properties, and call the \ref H5D API. + * + * <h4>Examples</h4> + * The basic procedure to write to a dataset is the following: + * \li Open the dataset. + * \li Set the dataset dataspace for the write (optional if dataspace is #H5S_ALL). + * \li Write data. + * \li Close the datatype, dataspace, and property list (as necessary). + * \li Close the dataset. + * + * Example 3 below shows example code to write a 4 x 6 array of integers. In the example, the data + * is initialized in the memory array dset_data. The dataset has already been created in the file, so it + * is opened with H5Dopen. + * + * The data is written with #H5Dwrite. The arguments are the dataset identifier, the memory + * datatype (#H5T_NATIVE_INT), the memory and file selections (#H5S_ALL in this case: the + * whole array), and the default (empty) property list. The last argument is the data to be + * transferred. + * + * <em> Example 3. Write an array of integers</em> + * \code + * hid_t file_id, dataset_id; // identifiers + * herr_t status; + * int i, j, dset_data[4][6]; + * + * // Initialize the dataset. + * for (i = 0; i < 4; i++) + * for (j = 0; j < 6; j++) + * dset_data[i][j] = i * 6 + j + 1; + * + * // Open an existing file. + * file_id = H5Fopen("dset.h5", H5F_ACC_RDWR, H5P_DEFAULT); + * + * // Open an existing dataset. + * dataset_id = H5Dopen(file_id, "/dset", H5P_DEFAULT); + * + * // Write the entire dataset, using 'dset_data': memory type is 'native int' + * // write the entire dataspace to the entire dataspace, no transfer properties + * status = H5Dwrite(dataset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, dset_data); + * + * status = H5Dclose(dataset_id); + * \endcode + * + * Example 4 below shows a similar write except for setting a non-default value for the transfer + * buffer. The code is the same as Example 3, but a transfer property list is created, and the desired + * buffer size is set. The #H5Dwrite function has the same arguments, but uses the property list to set + * the buffer. + * + * <em> Example 4. Write an array using a property list</em> + * \code + * hid_t file_id, dataset_id; + * hid_t xferplist; + * herr_t status; + * int i, j, dset_data[4][6]; + * + * file_id = H5Fopen("dset.h5", H5F_ACC_RDWR, H5P_DEFAULT); + * dataset_id = H5Dopen(file_id, "/dset", H5P_DEFAULT); + * + * // Example: set type conversion buffer to 64MB + * xferplist = H5Pcreate(H5P_DATASET_XFER); + * status = H5Pset_buffer( xferplist, 64 * 1024 *1024, NULL, NULL); + * + * // Write the entire dataset, using 'dset_data': memory type is 'native int' + * write the entire dataspace to the entire dataspace, set the buffer size with the property list + * status = H5Dwrite(dataset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, xferplist, dset_data); + * + * status = H5Dclose(dataset_id); + * \endcode + * + * The basic procedure to read from a dataset is the following: + * \li Define the memory dataspace of the read (optional if dataspace is #H5S_ALL). + * \li Open the dataset. + * \li Get the dataset dataspace (if using #H5S_ALL above). + * + * Else define dataset dataspace of read. + * \li Define the memory datatype (optional). + * \li Define the memory buffer. + * \li Open the dataset. + * \li Read data. + * \li Close the datatype, dataspace, and property list (as necessary). + * \li Close the dataset. + * + * The example below shows code that reads a 4 x 6 array of integers from a dataset called “dset1”. + * First, the dataset is opened. The #H5Dread call has parameters: + * \li The dataset identifier (from #H5Dopen) + * \li The memory datatype (#H5T_NATIVE_INT) + * \li The memory and file dataspace (#H5S_ALL, the whole array) + * \li A default (empty) property list + * \li The memory to be filled + * + * <em> Example 5. Read an array from a dataset</em> + * \code + * hid_t file_id, dataset_id; + * herr_t status; + * int i, j, dset_data[4][6]; + * + * // Open an existing file. + * file_id = H5Fopen("dset.h5", H5F_ACC_RDWR, H5P_DEFAULT); + * + * // Open an existing dataset. + * dataset_id = H5Dopen(file_id, "/dset", H5P_DEFAULT); + * + * // read the entire dataset, into 'dset_data': memory type is 'native int' + * // read the entire dataspace to the entire dataspace, no transfer properties, + * status = H5Dread(dataset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, dset_data); + * + * status = H5Dclose(dataset_id); + * \endcode + * + * \subsubsection subsubsec_dataset_program_read Retrieve the Properties of a Dataset + * The functions listed below allow the user to retrieve information regarding a dataset including + * the datatype, the dataspace, the dataset creation property list, and the total stored size of the data. + * + * <table> + * <caption>Retrieve dataset information</caption> + * <tr> + * <th>Query Function</th> + * <th>Description</th> + * </tr> + * <tr> + * <td>H5Dget_space</td> + * <td>Retrieve the dataspace of the dataset as stored in the file.</td> + * </tr> + * <tr> + * <td>H5Dget_type</td> + * <td>Retrieve the datatype of the dataset as stored in the file.</td> + * </tr> + * <tr> + * <td>H5Dget_create_plist</td> + * <td>Retrieve the dataset creation properties.</td> + * </tr> + * <tr> + * <td>H5Dget_storage_size</td> + * <td>Retrieve the total bytes for all the data of the dataset.</td> + * </tr> + * <tr> + * <td>H5Dvlen_get_buf_size</td> + * <td>Retrieve the total bytes for all the variable-length data of the dataset.</td> + * </tr> + * </table> + * + * The example below illustrates how to retrieve dataset information. + * + * <em> Example 6. Retrieve dataset</em> + * \code + * hid_t file_id, dataset_id; + * hid_t dspace_id, dtype_id, plist_id; + * herr_t status; + * + * // Open an existing file. + * file_id = H5Fopen("dset.h5", H5F_ACC_RDWR, H5P_DEFAULT); + * + * // Open an existing dataset. + * dataset_id = H5Dopen(file_id, "/dset", H5P_DEFAULT); + * dspace_id = H5Dget_space(dataset_id); + * dtype_id = H5Dget_type(dataset_id); + * plist_id = H5Dget_create_plist(dataset_id); + * + * // use the objects to discover the properties of the dataset + * status = H5Dclose(dataset_id); + * \endcode + * + * \subsection subsec_dataset_transfer Data Transfer + * The HDF5 library implements data transfers through a pipeline which implements data + * transformations (according to the datatype and selections), chunking (as requested), and I/O + * operations using different mechanisms (file drivers). The pipeline is automatically configured by + * the HDF5 library. Metadata is stored in the file so that the correct pipeline can be constructed to + * retrieve the data. In addition, optional filters such as compression may be added to the standard + * pipeline. + * + * The figure below illustrates data layouts for different layers of an application using HDF5. The + * application data is organized as a multidimensional array of elements. The HDF5 format + * specification defines the stored layout of the data and metadata. The storage layout properties + * define the organization of the abstract data. This data is written to and read from some storage + * medium. + * + * <table> + * <tr> + * <td> + * \image html Dsets_fig4.gif "Data layouts in an application" + * </td> + * </tr> + * </table> + * + * The last stage of a write (and first stage of a read) is managed by an HDF5 file driver module. + * The virtual file layer of the HDF5 Library implements a standard interface to alternative I/O + * methods, including memory (AKA “core”) files, single serial file I/O, multiple file I/O, and + * parallel I/O. The file driver maps a simple abstract HDF5 file to the specific access methods. + * + * The raw data of an HDF5 dataset is conceived to be a multidimensional array of data elements. + * This array may be stored in the file according to several storage strategies: + * \li Contiguous + * \li Chunked + * \li Compact + * + * The storage strategy does not affect data access methods except that certain operations may be + * more or less efficient depending on the storage strategy and the access patterns. + * + * Overall, the data transfer operations (#H5Dread and #H5Dwrite) work identically for any storage + * method, for any file driver, and for any filters and transformations. The HDF5 library + * automatically manages the data transfer process. In some cases, transfer properties should or + * must be used to pass additional parameters such as MPI/IO directives when using the parallel file + * driver. + * + * \subsubsection subsubsec_dataset_transfer_pipe The Data Pipeline + * When data is written or read to or from an HDF5 file, the HDF5 library passes the data through a + * sequence of processing steps which are known as the HDF5 data pipeline. This data pipeline + * performs operations on the data in memory such as byte swapping, alignment, scatter-gather, and + * hyperslab selections. The HDF5 library automatically determines which operations are needed + * and manages the organization of memory operations such as extracting selected elements from a + * data block. The data pipeline modules operate on data buffers: each module processes a buffer + * and passes the transformed buffer to the next stage. + * + * The table below lists the stages of the data pipeline. The figure below the table shows the order + * of processing during a read or write. + * + * <table> + * <caption>Stages of the data pipeline</caption> + * <tr> + * <th>Layers</th> + * <th>Description</th> + * </tr> + * <tr> + * <td>I/O initiation</td> + * <td>Initiation of HDF5 I/O activities (#H5Dwrite and #H5Dread) in a user’s application program.</td> + * </tr> + * <tr> + * <td>Memory hyperslab operation</td> + * <td>Data is scattered to (for read), or gathered from (for write) the application’s memory buffer + * (bypassed if no datatype conversion is needed).</td> + * </tr> + * <tr> + * <td>Datatype conversion</td> + * <td>Datatype is converted if it is different between memory and storage (bypassed if no datatype + * conversion is needed).</td> + * </tr> + * <tr> + * <td>File hyperslab operation</td> + * <td>Data is gathered from (for read), or scattered to (for write) to file space in memory (bypassed + * if no datatype conversion is needed).</td> + * </tr> + * <tr> + * <td>Filter pipeline</td> + * <td>Data is processed by filters when it passes. Data can be modified and restored here (bypassed + * if no datatype conversion is needed, no filter is enabled, or dataset is not chunked).</td> + * </tr> + * <tr> + * <td>Virtual File Layer</td> + * <td>Facilitate easy plug-in file drivers such as MPIO or POSIX I/O.</td> + * </tr> + * <tr> + * <td>Actual I/O</td> + * <td>Actual file driver used by the library such as MPIO or STDIO.</td> + * </tr> + * </table> + * + * <table> + * <tr> + * <td> + * \image html Dsets_fig5.gif "The processing order in the data pipeline" + * </td> + * </tr> + * </table> + * + * The HDF5 library automatically applies the stages as needed. + * + * When the memory dataspace selection is other than the whole dataspace, the memory hyperslab + * stage scatters/gathers the data elements between the application memory (described by the + * selection) and a contiguous memory buffer for the pipeline. On a write, this is a gather operation; + * on a read, this is a scatter operation. + * + * When the memory datatype is different from the file datatype, the datatype conversion stage + * transforms each data element. For example, if data is written from 32-bit big-endian memory, + * and the file datatype is 32-bit little-endian, the datatype conversion stage will swap the bytes of + * every element. Similarly, when data is read from the file to native memory, byte swapping will + * be applied automatically when needed. + * + * The file hyperslab stage is similar to the memory hyperslab stage, but is managing the + * arrangement of the elements according to the dataspace selection. When data is read, data + * elements are gathered from the data blocks from the file to fill the contiguous buffers which are + * then processed by the pipeline. When data is read, the elements from a buffer are scattered to the + * data blocks of the file. + * + * \subsubsection subsubsec_dataset_transfer_filter Data Pipeline Filters + * In addition to the standard pipeline, optional stages, called filters, can be inserted in the pipeline. + * The standard distribution includes optional filters to implement compression and error checking. + * User applications may add custom filters as well. + * + * The HDF5 library distribution includes or employs several optional filters. These are listed in the + * table below. The filters are applied in the pipeline between the virtual file layer and the file + * hyperslab operation. See the figure above. The application can use any number of filters in any + * order. + * + * <table> + * <caption>Data pipeline filters</caption> + * <tr> + * <th>Filter</th> + * <th>Description</th> + * </tr> + * <tr> + * <td>gzip compression</td> + * <td>Data compression using zlib.</td> + * </tr> + * <tr> + * <td>Szip compression</td> + * <td>Data compression using the Szip library. See The HDF Group website for more information + * regarding the Szip filter.</td> + * </tr> + * <tr> + * <td>N-bit compression</td> + * <td>Data compression using an algorithm specialized for n-bit datatypes.</td> + * </tr> + * <tr> + * <td>Scale-offset compression</td> + * <td>Data compression using a “scale and offset” algorithm.</td> + * </tr> + * <tr> + * <td>Shuffling</td> + * <td>To improve compression performance, data is regrouped by its byte position in the data + * unit. In other words, the 1st, 2nd, 3rd, and 4th bytes of integers are stored together + * respectively.</td> + * </tr> + * <tr> + * <td>Fletcher32</td> + * <td>Fletcher32 checksum for error-detection.</td> + * </tr> + * </table> + * + * Filters may be used only for chunked data and are applied to chunks of data between the file + * hyperslab stage and the virtual file layer. At this stage in the pipeline, the data is organized as + * fixed-size blocks of elements, and the filter stage processes each chunk separately. + * + * Filters are selected by dataset creation properties, and some behavior may be controlled by data + * transfer properties. The library determines what filters must be applied and applies them in the + * order in which they were set by the application. That is, if an application calls + * #H5Pset_shuffle and then #H5Pset_deflate when creating a dataset’s creation property list, the + * library will apply the shuffle filter first and then the deflate filter. + * + * For more information, + * \li @see @ref subsubsec_dataset_filters_nbit + * \li @see @ref subsubsec_dataset_filters_scale + * + * \subsubsection subsubsec_dataset_transfer_drive File Drivers + * I/O is performed by the HDF5 virtual file layer. The file driver interface writes and reads blocks + * of data; each driver module implements the interface using different I/O mechanisms. The table + * below lists the file drivers currently supported. Note that the I/O mechanisms are separated from + * the pipeline processing: the pipeline and filter operations are identical no matter what data access + * mechanism is used. + * + * <table> + * <caption>I/O file drivers</caption> + * <tr> + * <th>File Driver</th> + * <th>Description</th> + * </tr> + * <tr> + * <td>#H5FD_CORE</td> + * <td>Store in memory (optional backing store to disk file).</td> + * </tr> + * <tr> + * <td>#H5FD_FAMILY</td> + * <td>Store in a set of files.</td> + * </tr> + * <tr> + * <td>#H5FD_LOG</td> + * <td>Store in logging file.</td> + * </tr> + * <tr> + * <td>#H5FD_MPIO</td> + * <td>Store using MPI/IO.</td> + * </tr> + * <tr> + * <td>#H5FD_MULTI</td> + * <td>Store in multiple files. There are several options to control layout.</td> + * </tr> + * <tr> + * <td>#H5FD_SEC2</td> + * <td>Serial I/O to file using Unix “section 2” functions.</td> + * </tr> + * <tr> + * <td>#H5FD_STDIO</td> + * <td>Serial I/O to file using Unix “stdio” functions.</td> + * </tr> + * </table> + * + * Each file driver writes/reads contiguous blocks of bytes from a logically contiguous address + * space. The file driver is responsible for managing the details of the different physical storage + * methods. + * + * In serial environments, everything above the virtual file layer tends to work identically no matter + * what storage method is used. + * + * Some options may have substantially different performance depending on the file driver that is + * used. In particular, multi-file and parallel I/O may perform considerably differently from serial + * drivers depending on chunking and other settings. + * + * \subsubsection subsubsec_dataset_transfer_props Data Transfer Properties to Manage the Pipeline + * Data transfer properties set optional parameters that control parts of the data pipeline. The + * function listing below shows transfer properties that control the behavior of the library. + * + * <table> + * <caption>Data transfer property list functions</caption> + * <tr> + * <th>C Function</th> + * <th>Purpose</th> + * </tr> + * <tr> + * <td>#H5Pset_buffer</td> + * <td>Maximum size for the type conversion buffer and the background buffer. May also supply + * pointers to application-allocated buffers.</td> + * </tr> + * <tr> + * <td>#H5Pset_hyper_vector_size</td> + * <td>set the number of "I/O vectors" (offset and length pairs) which are to be + * accumulated in memory before being issued to the lower levels + * of the library for reading or writing the actual data.</td> + * </tr> + * <tr> + * <td>#H5Pset_btree_ratios</td> + * <td>Set the B-tree split ratios for a dataset transfer property list. The split ratios determine + * what percent of children go in the first node when a node splits.</td> + * </tr> + * </table> + * + * Some filters and file drivers require or use additional parameters from the application program. + * These can be passed in the data transfer property list. The table below shows file driver property + * list functions. + * + * <table> + * <caption>File driver property list functions</caption> + * <tr> + * <th>C Function</th> + * <th>Purpose</th> + * </tr> + * <tr> + * <td>#H5Pset_dxpl_mpio</td> + * <td>Control the MPI I/O transfer mode (independent or collective) during data I/O operations.</td> + * </tr> + * <tr> + * <td>#H5Pset_small_data_block_size</td> + * <td>Reserves blocks of size bytes for the contiguous storage of the raw data portion of small + * datasets. The HDF5 Library then writes the raw data from small datasets to this reserved space + * which reduces unnecessary discontinuities within blocks of metadata and improves + * I/O performance.</td> + * </tr> + * <tr> + * <td>#H5Pset_edc_check</td> + * <td>Disable/enable EDC checking for read. When selected, EDC is always written.</td> + * </tr> + * </table> + * + * The transfer properties are set in a property list which is passed as a parameter of the #H5Dread or + * #H5Dwrite call. The transfer properties are passed to each pipeline stage. Each stage may use or + * ignore any property in the list. In short, there is one property list that contains all the properties. + * + * \subsubsection subsubsec_dataset_transfer_store Storage Strategies + * The raw data is conceptually a multi-dimensional array of elements that is stored as a contiguous + * array of bytes. The data may be physically stored in the file in several ways. The table below lists + * the storage strategies for a dataset. + * + * <table> + * <caption> Dataset storage strategies</caption> + * <tr> + * <th>Storage Strategy</th> + * <th>Description</th> + * </tr> + * <tr> + * <td>Contiguous</td> + * <td>The dataset is stored as one continuous array of bytes.</td> + * </tr> + * <tr> + * <td>Chunked </td> + * <td>The dataset is stored as fixed-size chunks.</td> + * </tr> + * <tr> + * <td>Compact</td> + * <td>A small dataset is stored in the metadata header.</td> + * </tr> + * </table> + * + * The different storage strategies do not affect the data transfer operations of the dataset: reads and + * writes work the same for any storage strategy. + * + * These strategies are described in the following sections. + * + * <h4>Contiguous</h4> + * A contiguous dataset is stored in the file as a header and a single continuous array of bytes. See + * the figure below. In the case of a multi-dimensional array, the data is serialized in row major order. By + * default, data is stored contiguously. + * + * <table> + * <tr> + * <td> + * \image html Dsets_fig6.gif "Contiguous data storage" + * </td> + * </tr> + * </table> + * + * Contiguous storage is the simplest model. It has several limitations. First, the dataset must be a + * fixed-size: it is not possible to extend the limit of the dataset or to have unlimited dimensions. In + * other words, if the number of dimensions of the array might change over time, then chunking + * storage must be used instead of contiguous. Second, because data is passed through the pipeline + * as fixed-size blocks, compression and other filters cannot be used with contiguous data. + * + * <h4>Chunked</h4> + * The data of a dataset may be stored as fixed-size chunks. A chunk is a hyper- + * rectangle of any shape. When a dataset is chunked, each chunk is read or written as a single I/O + * operation, and individually passed from stage to stage of the data pipeline. + * + * <table> + * <tr> + * <td> + * \image html Dsets_fig7.gif "Chunked data storage" + * </td> + * </tr> + * </table> + * + * Chunks may be any size and shape that fits in the dataspace of the dataset. For example, a three + * dimensional dataspace can be chunked as 3-D cubes, 2-D planes, or 1-D lines. The chunks may + * extend beyond the size of the dataspace. For example, a 3 x 3 dataset might by chunked in 2 x 2 + * chunks. Sufficient chunks will be allocated to store the array, and any extra space will not be + * accessible. So, to store the 3 x 3 array, four 2 x 2 chunks would be allocated with 5 unused + * elements stored. + * + * Chunked datasets can be unlimited in any direction and can be compressed or filtered. + * + * Since the data is read or written by chunks, chunking can have a dramatic effect on performance + * by optimizing what is read and written. Note, too, that for specific access patterns such as + * parallel I/O, decomposition into chunks can have a large impact on performance. + * + * Two restrictions have been placed on chunk shape and size: + * <ul><li> The rank of a chunk must be less than or equal to the rank of the dataset</li> + * <li> Chunk size cannot exceed the size of a fixed-size dataset; for example, a dataset consisting of + * a 5 x 4 fixed-size array cannot be defined with 10 x 10 chunks</li></ul> + * + * <h4>Compact</h4> + * For contiguous and chunked storage, the dataset header information and data are stored in two + * (or more) blocks. Therefore, at least two I/O operations are required to access the data: one to + * access the header, and one (or more) to access data. For a small dataset, this is considerable + * overhead. + * + * A small dataset may be stored in a continuous array of bytes in the header block using the + * compact storage option. This dataset can be read entirely in one operation which retrieves the + * header and data. The dataset must fit in the header. This may vary depending on the metadata + * that is stored. In general, a compact dataset should be approximately 30 KB or less total size. + * + * <table> + * <tr> + * <td> + * \image html Dsets_fig8.gif "Compact data storage" + * </td> + * </tr> + * </table> + * + * \subsubsection subsubsec_dataset_transfer_partial Partial I/O Sub‐setting and Hyperslabs + * Data transfers can write or read some of the data elements of the dataset. This is controlled by + * specifying two selections: one for the source and one for the destination. Selections are specified + * by creating a dataspace with selections. + * + * Selections may be a union of hyperslabs or a list of points. A hyperslab is a contiguous hyper- + * rectangle from the dataspace. Selected fields of a compound datatype may be read or written. In + * this case, the selection is controlled by the memory and file datatypes. + * + * Summary of procedure: + * \li 1. Open the dataset + * \li 2. Define the memory datatype + * \li 3. Define the memory dataspace selection and file dataspace selection + * \li 4. Transfer data (#H5Dread or #H5Dwrite) + * + * For more information, + * @see @ref sec_dataspace + * + * \subsection subsec_dataset_allocation Allocation of Space in the File + * When a dataset is created, space is allocated in the file for its header and initial data. The amount +of space allocated when the dataset is created depends on the storage properties. When the +dataset is modified (data is written, attributes added, or other changes), additional storage may be +allocated if necessary. + * + * <table> + * <caption>Initial dataset size</caption> + * <tr> + * <th>Object</th> + * <th>Size</th> + * </tr> + * <tr> + * <td>Header</td> + * <td>Variable, but typically around 256 bytes at the creation of a simple dataset with a simple + * datatype.</td> + * </tr> + * <tr> + * <td>Data</td> + * <td>Size of the data array (number of elements x size of element). Space allocated in + * the file depends on the storage strategy and the allocation strategy.</td> + * </tr> + * </table> + * + * <h4>Header</h4> + * A dataset header consists of one or more header messages containing persistent metadata + * describing various aspects of the dataset. These records are defined in the HDF5 File Format + * Specification. The amount of storage required for the metadata depends on the metadata to be + * stored. The table below summarizes the metadata. + * + * <table> + * <caption>Metadata storage sizes</caption> + * <tr> + * <th>Header Information</th> + * <th>Approximate Storage Size</th> + * </tr> + * <tr> + * <td>Datatype (required)</td> + * <td>Bytes or more. Depends on type.</td> + * </tr> + * <tr> + * <td>Dataspace (required)</td> + * <td>Bytes or more. Depends on number of dimensions and hsize_t.</td> + * </tr> + * <tr> + * <td>Layout (required)</td> + * <td>Points to the stored data. Bytes or more. Depends on hsize_t and number of dimensions.</td> + * </tr> + * <tr> + * <td>Filters</td> + * <td>Depends on the number of filters. The size of the filter message depends on the name and + * data that will be passed.</td> + * </tr> + * </table> + * + * The header blocks also store the name and values of attributes, so the total storage depends on + * the number and size of the attributes. + * + * In addition, the dataset must have at least one link, including a name, which is stored in the file + * and in the group it is linked from. + * + * The different storage strategies determine when and how much space is allocated for the data + * array. See the discussion of fill values below for a detailed explanation of the storage allocation. + * + * <h4>Contiguous Storage</h4> + * For a continuous storage option, the data is stored in a single, contiguous block in the file. The + * data is nominally a fixed-size, (number of elements x size of element). The figure below shows + * an example of a two dimensional array stored as a contiguous dataset. + * + * Depending on the fill value properties, the space may be allocated when the dataset is created or + * when first written (default), and filled with fill values if specified. For parallel I/O, by default the + * space is allocated when the dataset is created. + * + * <table> + * <tr> + * <td> + * \image html Dsets_fig9.gif "A two dimensional array stored as a contiguous dataset" + * </td> + * </tr> + * </table> + * + * <h4>Chunked Storage</h4> + * For chunked storage, the data is stored in one or more chunks. Each chunk is a continuous block + * in the file, but chunks are not necessarily stored contiguously. Each chunk has the same size. The + * data array has the same nominal size as a contiguous array (number of elements x size of + * element), but the storage is allocated in chunks, so the total size in the file can be larger than the + * nominal size of the array. See the figure below. + * + * If a fill value is defined, each chunk will be filled with the fill value. Chunks must be allocated + * when data is written, but they may be allocated when the file is created, as the file expands, or + * when data is written. + * + * For serial I/O, by default chunks are allocated incrementally, as data is written to the chunk. For + * a sparse dataset, chunks are allocated only for the parts of the dataset that are written. In this + * case, if the dataset is extended, no storage is allocated. + * + * For parallel I/O, by default chunks are allocated when the dataset is created or extended with fill + * values written to the chunk. + * + * In either case, the default can be changed using fill value properties. For example, using serial + * I/O, the properties can select to allocate chunks when the dataset is created. + * + * <table> + * <tr> + * <td> + * \image html Dsets_fig10.gif "A two dimensional array stored in chunks" + * </td> + * </tr> + * </table> + * + * <h4>Changing Dataset Dimensions</h4> + * #H5Dset_extent is used to change the current dimensions of the dataset within the limits of the + * dataspace. Each dimension can be extended up to its maximum or unlimited. Extending the + * dataspace may or may not allocate space in the file and may or may not write fill values, if they + * are defined. See the example code below. + * + * The dimensions of the dataset can also be reduced. If the sizes specified are smaller than the + * dataset’s current dimension sizes, #H5Dset_extent will reduce the dataset’s dimension sizes to the + * specified values. It is the user’s responsibility to ensure that valuable data is not lost; + * #H5Dset_extent does not check. + * + * <em>Using #H5Dset_extent to increase the size of a dataset</em> + * \code + * hid_t file_id, dataset_id; + * herr_t status; + * size_t newdims[2]; + * + * // Open an existing file. + * file_id = H5Fopen("dset.h5", H5F_ACC_RDWR, H5P_DEFAULT); + * + * // Open an existing dataset. + * dataset_id = H5Dopen(file_id, "/dset", H5P_DEFAULT); + * + * // Example: dataset is 2 x 3, each dimension is UNLIMITED + * // extend to 2 x 7 + * newdims[0] = 2; + * newdims[1] = 7; + * status = H5Dset_extent(dataset_id, newdims); + * + * // dataset is now 2 x 7 + * + * status = H5Dclose(dataset_id); + * \endcode + * + * \subsubsection subsubsec_dataset_allocation_store Storage Allocation in the File: Early, Incremental, Late + * The HDF5 Library implements several strategies for when storage is allocated if and when it is + * filled with fill values for elements not yet written by the user. Different strategies are + * recommended for different storage layouts and file drivers. In particular, a parallel program + * needs storage allocated during a collective call (for example, create or extend), while serial + * programs may benefit from delaying the allocation until the data is written. + * + * Two file creation properties control when to allocate space, when to write the fill value, and the + * actual fill value to write. + * + * <h4>When to Allocate Space</h4> + * The table below shows the options for when data is allocated in the file. Early allocation is done + * during the dataset create call. Certain file drivers (especially MPI-I/O and MPI-POSIX) require + * space to be allocated when a dataset is created, so all processors will have the correct view of the + * data. + * + * <table> + * <caption>File storage allocation options</caption> + * <tr> + * <th>Strategy</th> + * <th>Description</th> + * </tr> + * <tr> + * <td>Early</td> + * <td>Allocate storage for the dataset immediately when the dataset is created.</td> + * </tr> + * <tr> + * <td>Late</td> + * <td>Defer allocating space for storing the dataset until the dataset is written.</td> + * </tr> + * <tr> + * <td>Incremental</td> + * <td>Defer allocating space for storing each chunk until the chunk is written.</td> + * </tr> + * <tr> + * <td>Default</td> + * <td>Use the strategy (Early, Late, or Incremental) for the storage method and + * access method. This is the recommended strategy.</td> + * </tr> + * </table> + * + * Late allocation is done at the time of the first write to dataset. Space for the whole dataset is + * allocated at the first write. + * + * Incremental allocation (chunks only) is done at the time of the first write to the chunk. Chunks + * that have never been written are not allocated in the file. In a sparsely populated dataset, this + * option allocates chunks only where data is actually written. + * + * The “Default” property selects the option recommended as appropriate for the storage method + * and access method. The defaults are shown in the table below. Note that Early allocation is + * recommended for all Parallel I/O, while other options are recommended as the default for serial + * I/O cases. + * + * <table> + * <caption>Default storage options</caption> + * <tr> + * <th>Storage Type</th> + * <th>Serial I/O</th> + * <th>Parallel I/O</th> + * </tr> + * <tr> + * <td>Contiguous</td> + * <td>Late</td> + * <td>Early</td> + * </tr> + * <tr> + * <td>Chunked</td> + * <td>Incremental</td> + * <td>Early</td> + * </tr> + * <tr> + * <td>Compact</td> + * <td>Early</td> + * <td>Early</td> + * </tr> + * </table> + * + * <h4>When to Write the Fill Value</h4> + * The second property is when to write the fill value. The possible values are “Never” and + * “Allocation”. The table below shows these options. + * + * <table> + * <caption>When to write fill values</caption> + * <tr> + * <th>When</th> + * <th>Description</th> + * </tr> + * <tr> + * <td>Never</td> + * <td>Fill value will never be written.</td> + * </tr> + * <tr> + * <td>Allocation</td> + * <td>Fill value is written when space is allocated. (Default for chunked and contiguous + * data storage.)</td> + * </tr> + * </table> + * + * <h4>What Fill Value to Write</h4> + * The third property is the fill value to write. The table below shows the values. By default, the + * data is filled with zeros. The application may choose no fill value (Undefined). In this case, + * uninitialized data may have random values. The application may define a fill value of an + * appropriate type. For more information, @see @ref subsec_datatype_fill. + * + * <table> + * <caption>Fill values to write</caption> + * <tr> + * <th>What to Write</th> + * <th>Description</th> + * </tr> + * <tr> + * <td>Default</td> + * <td>By default, the library fills allocated space with zeros.</td> + * </tr> + * <tr> + * <td>Undefined</td> + * <td>Allocated space is filled with random values.</td> + * </tr> + * <tr> + * <td>User-defined</td> + * <td>The application specifies the fill value.</td> + * </tr> + * </table> + * + * Together these three properties control the library’s behavior. The table below summarizes the + * possibilities during the dataset create-write-close cycle. + * + * <table> + * <caption>Storage allocation and fill summary</caption> + * <tr> + * <th>When to allocate space</th> + * <th>When to write fill value</th> + * <th>What fill value to write</th> + * <th>Library create-write-close behavior</th> + * </tr> + * <tr> + * <td>Early</td> + * <td>Never</td> + * <td>-</td> + * <td>Library allocates space when dataset is created, but never writes a fill value to dataset. A read + * of unwritten data returns undefined values.</td> + * </tr> + * <tr> + * <td>Late</td> + * <td>Never</td> + * <td>-</td> + * <td>Library allocates space when dataset is written to, but never writes a fill value to the dataset. A + * read of unwritten data returns undefined values.</td> + * </tr> + * <tr> + * <td>Incremental</td> + * <td>Never</td> + * <td>-</td> + * <td>Library allocates space when a dataset or chunk (whichever is the smallest unit of space) + * is written to, but it never writes a fill value to a dataset or a chunk. A read of unwritten data + * returns undefined values.</td> + * </tr> + * <tr> + * <td>-</td> + * <td>Allocation</td> + * <td>Undefined</td> + * <td>Error on creating the dataset. The dataset is not created.</td> + * </tr> + * <tr> + * <td>Early</td> + * <td>Allocation</td> + * <td>Default or User-defined</td> + * <td>Allocate space for the dataset when the dataset is created. Write the fill value (default or + * user-defined) to the entire dataset when the dataset is created.</td> + * </tr> + * <tr> + * <td>Late</td> + * <td>Allocation</td> + * <td>Default or User-define</td> + * <td>Allocate space for the dataset when the application first writes data values to the dataset. + * Write the fill value to the entire dataset before writing application data values.</td> + * </tr> + * <tr> + * <td>Incremental</td> + * <td>Allocation</td> + * <td>Default or User-define</td> + * <td>Allocate space for the dataset when the application first writes data values to the dataset or + * chunk (whichever is the smallest unit of space). Write the fill value to the entire dataset + * or chunk before writing application data values.</td> + * </tr> + * </table> + * + * During the #H5Dread function call, the library behavior depends on whether space has been + * allocated, whether the fill value has been written to storage, how the fill value is defined, and + * when to write the fill value. The table below summarizes the different behaviors. + * + * <table> + * <caption>H5Dread summary</caption> + * <tr> + * <th>Is space allocated in the file?</th> + * <th>What is the fill value?</th> + * <th>When to write the fill value?</th> + * <th>Library read behavior</th> + * </tr> + * <tr> + * <td>No</td> + * <td>Undefined</td> + * <td>anytime</td> + * <td>Error. Cannot create this dataset.</td> + * </tr> + * <tr> + * <td>No</td> + * <td>Default or User-define</td> + * <td>anytime</td> + * <td>Fill the memory buffer with the fill value.</td> + * </tr> + * <tr> + * <td>Yes</td> + * <td>Undefined</td> + * <td>anytime</td> + * <td>Return data from storage (dataset). Trash is possible if the application has not written data + * to the portion of the dataset being read.</td> + * </tr> + * <tr> + * <td>Yes</td> + * <td>Default or User-define</td> + * <td>Never</td> + * <td>Return data from storage (dataset). Trash is possible if the application has not written data + * to the portion of the dataset being read.</td> + * </tr> + * <tr> + * <td>Yes</td> + * <td>Default or User-define</td> + * <td>Allocation</td> + * <td>Return data from storage (dataset).</td> + * </tr> + * </table> + * + * There are two cases to consider depending on whether the space in the file has been allocated + * before the read or not. When space has not yet been allocated and if a fill value is defined, the + * memory buffer will be filled with the fill values and returned. In other words, no data has been + * read from the disk. If space has been allocated, the values are returned from the stored data. The + * unwritten elements will be filled according to the fill value. + * + * \subsubsection subsubsec_dataset_allocation_delete Deleting a Dataset from a File and Reclaiming Space + * HDF5 does not at this time provide an easy mechanism to remove a dataset from a file or to + * reclaim the storage space occupied by a deleted object. + * + * Removing a dataset and reclaiming the space it used can be done with the #H5Ldelete function + * and the h5repack utility program. With the H5Ldelete function, links to a dataset can be removed + * from the file structure. After all the links have been removed, the dataset becomes inaccessible to + * any application and is effectively removed from the file. The way to recover the space occupied + * by an unlinked dataset is to write all of the objects of the file into a new file. Any unlinked object + * is inaccessible to the application and will not be included in the new file. Writing objects to a + * new file can be done with a custom program or with the h5repack utility program. + * + * For more information, @see @ref sec_group + * + * \subsubsection subsubsec_dataset_allocation_release Releasing Memory Resources + * The system resources required for HDF5 objects such as datasets, datatypes, and dataspaces + * should be released once access to the object is no longer needed. This is accomplished via the + * appropriate close function. This is not unique to datasets but a general requirement when + * working with the HDF5 Library; failure to close objects will result in resource leaks. + * + * In the case where a dataset is created or data has been transferred, there are several objects that + * must be closed. These objects include datasets, datatypes, dataspaces, and property lists. + * + * The application program must free any memory variables and buffers it allocates. When + * accessing data from the file, the amount of memory required can be determined by calculating + * the size of the memory datatype and the number of elements in the memory selection. + * + * Variable-length data are organized in two or more areas of memory. For more information, + * \see \ref h4_vlen_datatype "Variable-length Datatypes". + * + * When writing data, the application creates an array of + * vl_info_t which contains pointers to the elements. The elements might be, for example, strings. + * In the file, the variable-length data is stored in two parts: a heap with the variable-length values + * of the data elements and an array of vl_info_t elements. When the data is read, the amount of + * memory required for the heap can be determined with the #H5Dvlen_get_buf_size call. + * + * The data transfer property may be used to set a custom memory manager for allocating variable- + * length data for a #H5Dread. This is set with the #H5Pset_vlen_mem_manager call. + * To free the memory for variable-length data, it is necessary to visit each element, free the + * variable-length data, and reset the element. The application must free the memory it has + * allocated. For memory allocated by the HDF5 Library during a read, the #H5Dvlen_reclaim + * function can be used to perform this operation. + * + * \subsubsection subsubsec_dataset_allocation_ext External Storage Properties + * The external storage format allows data to be stored across a set of non-HDF5 files. A set of + * segments (offsets and sizes) in one or more files is defined as an external file list, or EFL, and + * the contiguous logical addresses of the data storage are mapped onto these segments. Currently, + * only the #H5D_CONTIGUOUS storage format allows external storage. External storage is + * enabled by a dataset creation property. The table below shows the API. + * + * <table> + * <caption>External storage API</caption> + * <tr> + * <th>Function</th> + * <th>Description</th> + * </tr> + * <tr> + * <td>#H5Pset_external</td> + * <td>This function adds a new segment to the end of the external file list of the specified dataset + * creation property list. The segment begins a byte offset of file name and continues for size + * bytes. The space represented by this segment is adjacent to the space already represented by + * the external file list. The last segment in a file list may have the size #H5F_UNLIMITED, in + * which case the external file may be of unlimited size and no more files can be added to the + * external files list.</td> + * </tr> + * <tr> + * <td>#H5Pget_external_count</td> + * <td>Calling this function returns the number of segments in an external file list. If the dataset + * creation property list has no external data, then zero is returned.</td> + * </tr> + * <tr> + * <td>#H5Pget_external</td> + * <td>This is the counterpart for the #H5Pset_external function. Given a dataset creation + * property list and a zero-based index into that list, the file name, byte offset, and segment + * size are returned through non-null arguments. At most name_size characters are copied into + * the name argument which is not null terminated if the file name is longer than the + * supplied name buffer (this is similar to strncpy()).</td> + * </tr> + * </table> + * + * The figure below shows an example of how a contiguous, one-dimensional dataset is partitioned + * into three parts and each of those parts is stored in a segment of an external file. The top + * rectangle represents the logical address space of the dataset while the bottom rectangle represents + * an external file. + * + * <table> + * <tr> + * <td> + * \image html Dsets_fig11.gif "External file storage" + * </td> + * </tr> + * </table> + * + * The example below shows code that defines the external storage for the example. Note that the + * segments are defined in order of the logical addresses they represent, not their order within the + * external file. It would also have been possible to put the segments in separate files. Care should + * be taken when setting up segments in a single file since the library does not automatically check + * for segments that overlap. + * + * <em>External storage</em> + * \code + * plist = H5Pcreate (H5P_DATASET_CREATE); + * H5Pset_external (plist, "velocity.data", 3000, 1000); + * H5Pset_external (plist, "velocity.data", 0, 2500); + * H5Pset_external (plist, "velocity.data", 4500, 1500); + * \endcode + * + * The figure below shows an example of how a contiguous, two-dimensional dataset is partitioned + * into three parts and each of those parts is stored in a separate external file. The top rectangle + * represents the logical address space of the dataset while the bottom rectangles represent external + * files. + * + * <table> + * <tr> + * <td> + * \image html Dsets_fig12.gif "Partitioning a 2-D dataset for external storage" + * </td> + * </tr> + * </table> + * + * The example below shows code for the partitioning described above. In this example, the library + * maps the multi-dimensional array onto a linear address space as defined by the HDF5 format + * specification, and then maps that address space into the segments defined in the external file list. + * + * <em>Partitioning a 2-D dataset for external storage</em> + * \code + * plist = H5Pcreate (H5P_DATASET_CREATE); + * H5Pset_external (plist, "scan1.data", 0, 24); + * H5Pset_external (plist, "scan2.data", 0, 24); + * H5Pset_external (plist, "scan3.data", 0, 16); + * \endcode + * + * The segments of an external file can exist beyond the end of the (external) file. The library reads + * that part of a segment as zeros. When writing to a segment that exists beyond the end of a file, + * the external file is automatically extended. Using this feature, one can create a segment (or set of + * segments) which is larger than the current size of the dataset. This allows the dataset to be + * extended at a future time (provided the dataspace also allows the extension). + * + * All referenced external data files must exist before performing raw data I/O on the dataset. This + * is normally not a problem since those files are being managed directly by the application or + * indirectly through some other library. However, if the file is transferred from its original context, + * care must be taken to assure that all the external files are accessible in the new location. + * + * \subsection subsec_dataset_filters Using HDF5 Filters + * This section describes in detail how to use the n-bit, scale-offset filters and szip filters. + * + * \subsubsection subsubsec_dataset_filters_nbit Using the N‐bit Filter + * N-bit data has n significant bits, where n may not correspond to a precise number of bytes. On + * the other hand, computing systems and applications universally, or nearly so, run most efficiently + * when manipulating data as whole bytes or multiple bytes. + * + * Consider the case of 12-bit integer data. In memory, that data will be handled in at least 2 bytes, + * or 16 bits, and on some platforms in 4 or even 8 bytes. The size of such a dataset can be + * significantly reduced when written to disk if the unused bits are stripped out. + * + * The n-bit filter is provided for this purpose, packing n-bit data on output by stripping off all + * unused bits and unpacking on input, restoring the extra bits required by the computational + * processor. + * + * <h4>N-bit Datatype</h4> + * An n-bit datatype is a datatype of n significant bits. Unless it is packed, an n-bit datatype is + * presented as an n-bit bitfield within a larger-sized value. For example, a 12-bit datatype might be + * presented as a 12-bit field in a 16-bit, or 2-byte, value. + * + * Currently, the datatype classes of n-bit datatype or n-bit field of a compound datatype or an array + * datatype are limited to integer or floating-point. + * + * The HDF5 user can create an n-bit datatype through a series of function calls. For example, the + * following calls create a 16-bit datatype that is stored in a 32-bit value with a 4-bit offset: + * \code + * hid_t nbit_datatype = H5Tcopy(H5T_STD_I32LE); + * H5Tset_precision(nbit_datatype, 16); + * H5Tset_offset(nbit_datatype, 4); + * \endcode + * + * In memory, one value of the above example n-bit datatype would be stored on a little-endian + * machine as follows: + * <table> + * <tr> + * <th>byte 3</th> + * <th>byte 2</th> + * <th>byte 1</th> + * <th>byte 0</th> + * </tr> + * <tr> + * <td>????????</td> + * <td>????SPPP</td> + * <td>PPPPPPPP</td> + * <td>PPPP????</td> + * </tr> + * <tr> + * <td colspan="4"> + * <em>Note: Key: S - sign bit, E - exponent bit, M - mantissa bit, ? - padding bit. Sign bit is + * included in signed integer datatype precision.</em> + * </td> + * </tr> + * </table> + * + * <h4>N-bit Filter</h4> + * When data of an n-bit datatype is stored on disk using the n-bit filter, the filter packs the data by + * stripping off the padding bits; only the significant bits are retained and stored. The values on disk + * will appear as follows: + * <table> + * <tr> + * <th>1st value</th> + * <th>2nd value</th> + * <th>nth value</th> + * </tr> + * <tr> + * <td>SPPPPPPP PPPPPPPP</td> + * <td>SPPPPPPP PPPPPPPP</td> + * <td>...</td> + * </tr> + * <tr> + * <td colspan="3"> + * <em>Note: Key: S - sign bit, E - exponent bit, M - mantissa bit, ? - padding bit. Sign bit is + * included in signed integer datatype precision.</em> + * </td> + * </tr> + * </table> + * + * <h4>How Does the N-bit Filter Work?</h4> + * The n-bit filter always compresses and decompresses according to dataset properties supplied by + * the HDF5 library in the datatype, dataspace, or dataset creation property list. + * + * The dataset datatype refers to how data is stored in an HDF5 file while the memory datatype + * refers to how data is stored in memory. The HDF5 library will do datatype conversion when + * writing data in memory to the dataset or reading data from the dataset to memory if the memory + * datatype differs from the dataset datatype. Datatype conversion is performed by HDF5 library + * before n-bit compression and after n-bit decompression. + * + * The following sub-sections examine the common cases: + * \li N-bit integer conversions + * \li N-bit floating-point conversions + * + * <h4>N-bit Integer Conversions</h4> + * Integer data with a dataset of integer datatype of less than full precision and a memory datatype + * of #H5T_NATIVE_INT, provides the simplest application of the n-bit filter. + * + * The precision of #H5T_NATIVE_INT is 8 multiplied by sizeof(int). This value, the size of an + * int in bytes, differs from platform to platform; we assume a value of 4 for the following + * illustration. We further assume the memory byte order to be little-endian. + * + * In memory, therefore, the precision of #H5T_NATIVE_INT is 32 and the offset is 0. One value of + * #H5T_NATIVE_INT is laid out in memory as follows: + * <table> + * <tr> + * <td> + * \image html Dsets_NbitInteger1.gif "H5T_NATIVE_INT in memory"<br /> + * <em>Note: Key: S - sign bit, E - exponent bit, M - mantissa bit, ? - padding bit. Sign bit is + * included in signed integer datatype precision.</em> + * </td> + * </tr> + * </table> + * + * Suppose the dataset datatype has a precision of 16 and an offset of 4. After HDF5 converts + * values from the memory datatype to the dataset datatype, it passes something like the following + * to the n-bit filter for compression: + * <table> + * <tr> + * <td> + * \image html Dsets_NbitInteger2.gif "Passed to the n-bit filter"<br /> + * <em>Note: Key: S - sign bit, E - exponent bit, M - mantissa bit, ? - padding bit. Sign bit is + * included in signed integer datatype precision.</em> + * </td> + * </tr> + * </table> + * + * Notice that only the specified 16 bits (15 significant bits and the sign bit) are retained in the + * conversion. All other significant bits of the memory datatype are discarded because the dataset + * datatype calls for only 16 bits of precision. After n-bit compression, none of these discarded bits, + * known as padding bits will be stored on disk. + * + * <h4>N-bit Floating-point Conversions</h4> + * Things get more complicated in the case of a floating-point dataset datatype class. This sub- + * section provides an example that illustrates the conversion from a memory datatype of + * #H5T_NATIVE_FLOAT to a dataset datatype of class floating-point. + * + * As before, let the #H5T_NATIVE_FLOAT be 4 bytes long, and let the memory byte order be + * little-endian. Per the IEEE standard, one value of #H5T_NATIVE_FLOAT is laid out in memory + * as follows: + * <table> + * <tr> + * <td> + * \image html Dsets_NbitFloating1.gif "H5T_NATIVE_FLOAT in memory"<br /> + * <em>Note: Key: S - sign bit, E - exponent bit, M - mantissa bit, ? - padding bit. Sign bit is + * included in floating-point datatype precision.</em> + * </td> + * </tr> + * </table> + * + * Suppose the dataset datatype has a precision of 20, offset of 7, mantissa size of 13, mantissa + * position of 7, exponent size of 6, exponent position of 20, and sign position of 26. For more + * information, @see @ref subsubsec_datatype_program_define. + * + * After HDF5 converts values from the memory datatype to the dataset datatype, it passes + * something like the following to the n-bit filter for compression: + * <table> + * <tr> + * <td> + * \image html Dsets_NbitFloating2.gif "Passed to the n-bit filter"<br /> + * <em>Note: Key: S - sign bit, E - exponent bit, M - mantissa bit, ? - padding bit. Sign bit is + * included in floating-point datatype precision.</em> + * </td> + * </tr> + * </table> + * + * The sign bit and truncated mantissa bits are not changed during datatype conversion by the + * HDF5 library. On the other hand, the conversion of the 8-bit exponent to a 6-bit exponent is a + * little tricky: + * + * The bias for the new exponent in the n-bit datatype is: + * <code> + * 2<sup>(n-1)</sup>-1 + * </code> + * + * The following formula is used for this exponent conversion:<br /> + * <code> + * exp8 - (2<sup>(8-1)</sup> -1) = exp6 - (2<sup>(6-1)</sup>-1) = actual exponent value + * </code><br /> + * where exp8 is the stored decimal value as represented by the 8-bit exponent, and exp6 is the + * stored decimal value as represented by the 6-bit exponent. + * + * In this example, caution must be taken to ensure that, after conversion, the actual exponent value + * is within the range that can be represented by a 6-bit exponent. For example, an 8-bit exponent + * can represent values from -127 to 128 while a 6-bit exponent can represent values only from -31 + * to 32. + * + * <h4>N-bit Filter Behavior</h4> + * The n-bit filter was designed to treat the incoming data byte by byte at the lowest level. The + * purpose was to make the n-bit filter as generic as possible so that no pointer cast related to the + * datatype is needed. + * + * Bitwise operations are employed for packing and unpacking at the byte level. + * + * Recursive function calls are used to treat compound and array datatypes. + * + * <h4>N-bit Compression</h4> + * The main idea of n-bit compression is to use a loop to compress each data element in a chunk. + * Depending on the datatype of each element, the n-bit filter will call one of four functions. Each + * of these functions performs one of the following tasks: + * \li Compress a data element of a no-op datatype + * \li Compress a data element of an atomic datatype + * \li Compress a data element of a compound datatype + * \li Compress a data element of an array datatype + * + * No-op datatypes: The n-bit filter does not actually compress no-op datatypes. Rather, it copies + * the data buffer of the no-op datatype from the non-compressed buffer to the proper location in + * the compressed buffer; the compressed buffer has no holes. The term “compress” is used here + * simply to distinguish this function from the function that performs the reverse operation during + * decompression. + * + * Atomic datatypes: The n-bit filter will find the bytes where significant bits are located and try to + * compress these bytes, one byte at a time, using a loop. At this level, the filter needs the following + * information: + * <ul><li>The byte offset of the beginning of the current data element with respect to the + * beginning of the input data buffer</li> + * <li>Datatype size, precision, offset, and byte order</li></ul> + * + * The n-bit filter compresses from the most significant byte containing significant bits to the least + * significant byte. For big-endian data, therefore, the loop index progresses from smaller to larger + * while for little-endian, the loop index progresses from larger to smaller. + * + * In the extreme case of when the n-bit datatype has full precision, this function copies the content + * of the entire non-compressed datatype to the compressed output buffer. + * + * Compound datatypes: The n-bit filter will compress each data member of the compound + * datatype. If the member datatype is of an integer or floating-point datatype, the n-bit filter will + * call the function described above. If the member datatype is of a no-op datatype, the filter will + * call the function described above. If the member datatype is of a compound datatype, the filter + * will make a recursive call to itself. If the member datatype is of an array datatype, the filter will + * call the function described below. + * + * Array datatypes: The n-bit filter will use a loop to compress each array element in the array. If + * the base datatype of array element is of an integer or floating-point datatype, the n-bit filter will + * call the function described above. If the base datatype is of a no-op datatype, the filter will call + * the function described above. If the base datatype is of a compound datatype, the filter will call + * the function described above. If the member datatype is of an array datatype, the filter will make + * a recursive call of itself. + * + * <h4>N-bit Decompression</h4> + * The n-bit decompression algorithm is very similar to n-bit compression. The only difference is + * that at the byte level, compression packs out all padding bits and stores only significant bits into + * a continuous buffer (unsigned char) while decompression unpacks significant bits and inserts + * padding bits (zeros) at the proper positions to recover the data bytes as they existed before + * compression. + * + * <h4>Storing N-bit Parameters to Array cd_value[]</h4> + * All of the information, or parameters, required by the n-bit filter are gathered and stored in the + * array cd_values[] by the private function H5Z__set_local_nbit and are passed to another private + * function, H5Z__filter_nbit, by the HDF5 Library. + * These parameters are as follows: + * \li Parameters related to the datatype + * \li The number of elements within the chunk + * \li A flag indicating whether compression is needed + * + * The first and second parameters can be obtained using the HDF5 dataspace and datatype + * interface calls. + * + * A compound datatype can have members of array or compound datatype. An array datatype’s + * base datatype can be a complex compound datatype. Recursive calls are required to set + * parameters for these complex situations. + * + * Before setting the parameters, the number of parameters should be calculated to dynamically + * allocate the array cd_values[], which will be passed to the HDF5 Library. This also requires + * recursive calls. + * + * For an atomic datatype (integer or floating-point), parameters that will be stored include the + * datatype’s size, endianness, precision, and offset. + * + * For a no-op datatype, only the size is required. + * + * For a compound datatype, parameters that will be stored include the datatype’s total size and + * number of members. For each member, its member offset needs to be stored. Other parameters + * for members will depend on the respective datatype class. + * + * For an array datatype, the total size parameter should be stored. Other parameters for the array’s + * base type depend on the base type’s datatype class. + * + * Further, to correctly retrieve the parameter for use of n-bit compression or decompression later, + * parameters for distinguishing between datatype classes should be stored. + * + * <h4>Implementation</h4> + * Three filter callback functions were written for the n-bit filter: + * \li H5Z__can_apply_nbit + * \li H5Z__set_local_nbit + * \li H5Z__filter_nbit + * + * These functions are called internally by the HDF5 library. A number of utility functions were + * written for the function H5Z__set_local_nbit. Compression and decompression functions were + * written and are called by function H5Z__filter_nbit. All these functions are included in the file + * H5Znbit.c. + * + * The public function #H5Pset_nbit is called by the application to set up the use of the n-bit filter. + * This function is included in the file H5Pdcpl.c. The application does not need to supply any + * parameters. + * + * <h4>How N-bit Parameters are Stored</h4> + * A scheme of storing parameters required by the n-bit filter in the array cd_values[] was + * developed utilizing recursive function calls. + * + * Four private utility functions were written for storing the parameters associated with atomic + * (integer or floating-point), no-op, array, and compound datatypes: + * \li H5Z__set_parms_atomic + * \li H5Z__set_parms_array + * \li H5Z__set_parms_nooptype + * \li H5Z__set_parms_compound + * + * The scheme is briefly described below. + * + * First, assign a numeric code for datatype class atomic (integer or float), no-op, array, and + * compound datatype. The code is stored before other datatype related parameters are stored. + * + * The first three parameters of cd_values[] are reserved for: + * \li 1. The number of valid entries in the array cd_values[] + * \li 2. A flag indicating whether compression is needed + * \li 3. The number of elements in the chunk + * + * Throughout the balance of this explanation, i represents the index of cd_values[]. + * In the function H5Z__set_local_nbit: + * <ul><li>1. i = 2</li> + * <li>2. Get the number of elements in the chunk and store in cd_value[i]; increment i</li> + * <li>3. Get the class of the datatype: + * <ul><li>For an integer or floating-point datatype, call H5Z__set_parms_atomic</li> + * <li>For an array datatype, call H5Z__set_parms_array</li> + * <li>For a compound datatype, call H5Z__set_parms_compound</li> + * <li>For none of the above, call H5Z__set_parms_noopdatatype</li></ul></li> + * <li>4. Store i in cd_value[0] and flag in cd_values[1]</li></ul> + * + * In the function H5Z__set_parms_atomic: + * \li 1. Store the assigned numeric code for the atomic datatype in cd_value[i]; increment i + * \li 2. Get the size of the atomic datatype and store in cd_value[i]; increment i + * \li 3. Get the order of the atomic datatype and store in cd_value[i]; increment i + * \li 4. Get the precision of the atomic datatype and store in cd_value[i]; increment i + * \li 5. Get the offset of the atomic datatype and store in cd_value[i]; increment i + * \li 6. Determine the need to do compression at this point + * + * In the function H5Z__set_parms_nooptype: + * \li 1. Store the assigned numeric code for the no-op datatype in cd_value[i]; increment i + * \li 2. Get the size of the no-op datatype and store in cd_value[i]; increment i + * + * In the function H5Z__set_parms_array: + * <ul><li>1. Store the assigned numeric code for the array datatype in cd_value[i]; increment i</li> + * <li>2. Get the size of the array datatype and store in cd_value[i]; increment i</li> + * <li>3. Get the class of the array’s base datatype. + * <ul><li>For an integer or floating-point datatype, call H5Z__set_parms_atomic</li> + * <li>For an array datatype, call H5Z__set_parms_array</li> + * <li>For a compound datatype, call H5Z__set_parms_compound</li> + * <li>If none of the above, call H5Z__set_parms_noopdatatype</li></ul></li></ul> + * + * In the function H5Z__set_parms_compound: + * <ul><li>1. Store the assigned numeric code for the compound datatype in cd_value[i]; increment i</li> + * <li>2. Get the size of the compound datatype and store in cd_value[i]; increment i</li> + * <li>3. Get the number of members and store in cd_values[i]; increment i</li> + * <li>4. For each member + * <ul><li>Get the member offset and store in cd_values[i]; increment i</li> + * <li>Get the class of the member datatype</li> + * <li>For an integer or floating-point datatype, call H5Z__set_parms_atomic</li> + * <li>For an array datatype, call H5Z__set_parms_array</li> + * <li>For a compound datatype, call H5Z__set_parms_compound</li> + * <li>If none of the above, call H5Z__set_parms_noopdatatype</li></ul></li></ul> + * + * <h4>N-bit Compression and Decompression Functions</h4> + * The n-bit compression and decompression functions above are called by the private HDF5 + * function H5Z__filter_nbit. The compress and decompress functions retrieve the n-bit parameters + * from cd_values[] as it was passed by H5Z__filter_nbit. Parameters are retrieved in exactly the + * same order in which they are stored and lower-level compression and decompression functions + * for different datatype classes are called. + * + * N-bit compression is not implemented in place. Due to the difficulty of calculating actual output + * buffer size after compression, the same space as that of the input buffer is allocated for the output + * buffer as passed to the compression function. However, the size of the output buffer passed by + * reference to the compression function will be changed (smaller) after the compression is + * complete. + * + * <h4>Usage Examples</h4> + * + * The following code example illustrates the use of the n-bit filter for writing and reading n-bit + * integer data. + * + * <em>N-bit compression for integer data</em> + * \code + * #include "hdf5.h" + * #include "stdlib.h" + * #include "math.h" + * + * #define H5FILE_NAME "nbit_test_int.h5" + * #define DATASET_NAME "nbit_int" + * #define NX 200 + * #define NY 300 + * #define CH_NX 10 + * #define CH_NY 15 + * + * int main(void) + * { + * hid_t file, dataspace, dataset, datatype, mem_datatype, dset_create_props; + * hsize_t dims[2], chunk_size[2]; + * int orig_data[NX][NY]; + * int new_data[NX][NY]; + * int i, j; + * size_t precision, offset; + * + * // Define dataset datatype (integer), and set precision, offset + * datatype = H5Tcopy(H5T_NATIVE_INT); + * precision = 17; // precision includes sign bit + * if(H5Tset_precision(datatype,precision) < 0) { + * printf("Error: fail to set precision\n"); + * return -1; + * } + * offset = 4; + * if(H5Tset_offset(datatype,offset) < 0) { + * printf("Error: fail to set offset\n"); + * return -1; + * } + * + * // Copy to memory datatype + * mem_datatype = H5Tcopy(datatype); + * + * // Set order of dataset datatype + * if(H5Tset_order(datatype, H5T_ORDER_BE) < 0) { + * printf("Error: fail to set endianness\n"); + * return -1; + * } + * + * // Initialize data buffer with random data within correct + * // range corresponding to the memory datatype's precision + * // and offset. + * for (i = 0; i < NX; i++) + * for (j = 0; j < NY; j++) + * orig_data[i][j] = rand() % (int)pow(2, precision-1) << offset; + * + * // Describe the size of the array. + * dims[0] = NX; + * dims[1] = NY; + * if((dataspace = H5Screate_simple (2, dims, NULL)) < 0) { + * printf("Error: fail to create dataspace\n"); + * return -1; + * } + * + * // Create a new file using read/write access, default file + * // creation properties, and default file access properties. + * if((file = H5Fcreate (H5FILE_NAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + * printf("Error: fail to create file\n"); + * return -1; + * } + * + * // Set the dataset creation property list to specify that + * // the raw data is to be partitioned into 10 x 15 element + * // chunks and that each chunk is to be compressed. + * chunk_size[0] = CH_NX; + * chunk_size[1] = CH_NY; + * if((dset_create_props = H5Pcreate (H5P_DATASET_CREATE)) < 0) { + * printf("Error: fail to create dataset property\n"); + * return -1; + * } + * if(H5Pset_chunk (dset_create_props, 2, chunk_size) < 0) { + * printf("Error: fail to set chunk\n"); + * return -1; + * } + * + * // Set parameters for n-bit compression; check the description + * // of the H5Pset_nbit function in the HDF5 Reference Manual + * // for more information. + * if(H5Pset_nbit (dset_create_props) < 0) { + * printf("Error: fail to set nbit filter\n"); + * return -1; + * } + * + * // Create a new dataset within the file. The datatype + * // and dataspace describe the data on disk, which may + * // be different from the format used in the application's + * // memory. + * if((dataset = H5Dcreate(file, DATASET_NAME, datatype, dataspace, + * H5P_DEFAULT, dset_create_props, H5P_DEFAULT)) < 0) { + * printf("Error: fail to create dataset\n"); + * return -1; + * } + * + * // Write the array to the file. The datatype and dataspace + * // describe the format of the data in the 'orig_data' buffer. + * // The raw data is translated to the format required on disk, + * // as defined above. We use default raw data transfer + * // properties. + * if(H5Dwrite (dataset, mem_datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, orig_data) < 0) { + * printf("Error: fail to write to dataset\n"); + * return -1; + * } + * H5Dclose (dataset); + * + * if((dataset = H5Dopen(file, DATASET_NAME, H5P_DEFAULT)) < 0) { + * printf("Error: fail to open dataset\n"); + * return -1; + * } + * + * // Read the array. This is similar to writing data, + * // except the data flows in the opposite direction. + * // Note: Decompression is automatic. + * if(H5Dread (dataset, mem_datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, new_data) < 0) { + * printf("Error: fail to read from dataset\n"); + * return -1; + * } + * + * H5Tclose (datatype); + * H5Tclose (mem_datatype); + * H5Dclose (dataset); + * H5Sclose (dataspace); + * H5Pclose (dset_create_props); + * H5Fclose (file); + * + * return 0; + * } + * \endcode + * + * The following code example illustrates the use of the n-bit filter for writing and reading n-bit + * floating-point data. + * + * <em>N-bit compression for floating-point data</em> + * \code + * #include "hdf5.h" + * + * #define H5FILE_NAME "nbit_test_float.h5" + * #define DATASET_NAME "nbit_float" + * #define NX 2 + * #define NY 5 + * #define CH_NX 2 + * #define CH_NY 5 + * + * int main(void) + * { + * hid_t file, dataspace, dataset, datatype, dset_create_props; + * hsize_t dims[2], chunk_size[2]; + * + * // orig_data[] are initialized to be within the range that + * // can be represented by dataset datatype (no precision + * // loss during datatype conversion) + * // + * float orig_data[NX][NY] = {{188384.00, 19.103516,-1.0831790e9, -84.242188, 5.2045898}, + * {-49140.000, 2350.2500, -3.2110596e-1, 6.4998865e-5, -0.0000000}}; + * float new_data[NX][NY]; + * size_t precision, offset; + * + * // Define single-precision floating-point type for dataset + * //--------------------------------------------------------------- + * // size=4 byte, precision=20 bits, offset=7 bits, + * // mantissa size=13 bits, mantissa position=7, + * // exponent size=6 bits, exponent position=20, + * // exponent bias=31. + * // It can be illustrated in little-endian order as: + * // (S - sign bit, E - exponent bit, M - mantissa bit, ? - padding bit) + * // + * // 3 2 1 0 + * // ?????SEE EEEEMMMM MMMMMMMM M??????? + * // + * // To create a new floating-point type, the following + * // properties must be set in the order of + * // set fields -> set offset -> set precision -> set size. + * // All these properties must be set before the type can + * // function. Other properties can be set anytime. Derived + * // type size cannot be expanded bigger than original size + * // but can be decreased. There should be no holes + * // among the significant bits. Exponent bias usually + * // is set 2^(n-1)-1, where n is the exponent size. + * //--------------------------------------------------------------- + * datatype = H5Tcopy(H5T_IEEE_F32BE); + * if(H5Tset_fields(datatype, 26, 20, 6, 7, 13) < 0) { + * printf("Error: fail to set fields\n"); + * return -1; + * } + * offset = 7; + * if(H5Tset_offset(datatype,offset) < 0) { + * printf("Error: fail to set offset\n"); + * return -1; + * } + * precision = 20; + * if(H5Tset_precision(datatype,precision) < 0) { + * printf("Error: fail to set precision\n"); + * return -1; + * } + * if(H5Tset_size(datatype, 4) < 0) { + * printf("Error: fail to set size\n"); + * return -1; + * } + * if(H5Tset_ebias(datatype, 31) < 0) { + * printf("Error: fail to set exponent bias\n"); + * return -1; + * } + * + * // Describe the size of the array. + * dims[0] = NX; + * dims[1] = NY; + * if((dataspace = H5Screate_simple (2, dims, NULL)) < 0) { + * printf("Error: fail to create dataspace\n"); + * return -1; + * } + * + * // Create a new file using read/write access, default file + * // creation properties, and default file access properties. + * if((file = H5Fcreate (H5FILE_NAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + * printf("Error: fail to create file\n"); + * return -1; + * } + * + * // Set the dataset creation property list to specify that + * // the raw data is to be partitioned into 2 x 5 element + * // chunks and that each chunk is to be compressed. + * chunk_size[0] = CH_NX; + * chunk_size[1] = CH_NY; + * if((dset_create_props = H5Pcreate (H5P_DATASET_CREATE)) < 0) { + * printf("Error: fail to create dataset property\n"); + * return -1; + * } + * if(H5Pset_chunk (dset_create_props, 2, chunk_size) < 0) { + * printf("Error: fail to set chunk\n"); + * return -1; + * } + * + * // Set parameters for n-bit compression; check the description + * // of the H5Pset_nbit function in the HDF5 Reference Manual + * // for more information. + * if(H5Pset_nbit (dset_create_props) < 0) { + * printf("Error: fail to set nbit filter\n"); + * return -1; + * } + * + * // Create a new dataset within the file. The datatype + * // and dataspace describe the data on disk, which may + * // be different from the format used in the application's memory. + * if((dataset = H5Dcreate(file, DATASET_NAME, datatype, dataspace, H5P_DEFAULT, + * dset_create_plists, H5P_DEFAULT)) < 0) { + * printf("Error: fail to create dataset\n"); + * return -1; + * } + * + * // Write the array to the file. The datatype and dataspace + * // describe the format of the data in the 'orig_data' buffer. + * // The raw data is translated to the format required on disk, + * // as defined above. We use default raw data transfer properties. + * if(H5Dwrite (dataset, H5T_NATIVE_FLOAT, H5S_ALL, H5S_ALL, H5P_DEFAULT, orig_data) < 0) { + * printf("Error: fail to write to dataset\n"); + * return -1; + * } + * H5Dclose (dataset); + * if((dataset = H5Dopen(file, DATASET_NAME, H5P_DEFAULT))<0) { + * printf("Error: fail to open dataset\n"); + * return -1; + * } + * + * // Read the array. This is similar to writing data, + * // except the data flows in the opposite direction. + * // Note: Decompression is automatic. + * if(H5Dread (dataset, H5T_NATIVE_FLOAT, H5S_ALL, H5S_ALL, H5P_DEFAULT, new_data) < 0) { + * printf("Error: fail to read from dataset\n"); + * return -1; + * } + * H5Tclose (datatype); + * H5Dclose (dataset); + * H5Sclose (dataspace); + * H5Pclose (dset_create_props); + * H5Fclose (file); + * + * return 0 + * } + * \endcode + * + * <h4>Limitations</h4> + * Because the array cd_values[] has to fit into an object header message of 64K, the n-bit filter has + * an upper limit on the number of n-bit parameters that can be stored in it. To be conservative, a + * maximum of 4K is allowed for the number of parameters. + * + * The n-bit filter currently only compresses n-bit datatypes or fields derived from integer or + * floating-point datatypes. The n-bit filter assumes padding bits of zero. This may not be true since + * the HDF5 user can set padding bit to be zero, one, or leave the background alone. However, it is + * expected the n-bit filter will be modified to adjust to such situations. + * + * The n-bit filter does not have a way to handle the situation where the fill value of a dataset is + * defined and the fill value is not of an n-bit datatype although the dataset datatype is. + * + * \subsubsection subsubsec_dataset_filters_scale Using the Scale‐offset Filter + * Generally speaking, scale-offset compression performs a scale and/or offset operation on each + * data value and truncates the resulting value to a minimum number of bits (minimum-bits) before + * storing it. + * + * The current scale-offset filter supports integer and floating-point datatypes only. For the floating- + * point datatype, float and double are supported, but long double is not supported. + * + * Integer data compression uses a straight-forward algorithm. Floating-point data compression + * adopts the GRiB data packing mechanism which offers two alternate methods: a fixed minimum- + * bits method, and a variable minimum-bits method. Currently, only the variable minimum-bits + * method is implemented. + * + * Like other I/O filters supported by the HDF5 library, applications using the scale-offset filter + * must store data with chunked storage. + * + * Integer type: The minimum-bits of integer data can be determined by the filter. For example, if + * the maximum value of data to be compressed is 7065 and the minimum value is 2970. Then the + * “span” of dataset values is equal to (max-min+1), which is 4676. If no fill value is defined for the + * dataset, the minimum-bits is: ceiling(log2(span)) = 12. With fill value set, the minimum-bits is: + * ceiling(log2(span+1)) = 13. + * + * HDF5 users can also set the minimum-bits. However, if the user gives a minimum-bits that is + * less than that calculated by the filter, the compression will be lossy. + * + * Floating-point type: The basic idea of the scale-offset filter for the floating-point type is to + * transform the data by some kind of scaling to integer data, and then to follow the procedure of + * the scale-offset filter for the integer type to do the data compression. Due to the data + * transformation from floating-point to integer, the scale-offset filter is lossy in nature. + * + * Two methods of scaling the floating-point data are used: the so-called D-scaling and E-scaling. + * D-scaling is more straightforward and easy to understand. For HDF5 1.8 release, only the + * D-scaling method had been implemented. + * + * <h4>Design</h4> + * Before the filter does any real work, it needs to gather some information from the HDF5 Library + * through API calls. The parameters the filter needs are: + * \li The minimum-bits of the data value + * \li The number of data elements in the chunk + * \li The datatype class, size, sign (only for integer type), byte order, and fill value if defined + * + * Size and sign are needed to determine what kind of pointer cast to use when retrieving values + * from the data buffer. + * + * The pipeline of the filter can be divided into four parts: (1)pre-compression; (2)compression; + * (3)decompression; (4)post-decompression. + * + * Depending on whether a fill value is defined or not, the filter will handle pre-compression and + * post-decompression differently. + * + * The scale-offset filter only needs the memory byte order, size of datatype, and minimum-bits for + * compression and decompression. + * + * Since decompression has no access to the original data, the minimum-bits and the minimum + * value need to be stored with the compressed data for decompression and post-decompression. + * + * <h4>Integer Type</h4> + * Pre-compression: During pre-compression minimum-bits is calculated if it is not set by the user. + * For more information on how minimum-bits are calculated, @see @ref subsubsec_dataset_filters_nbit. + * + * If the fill value is defined, finding the maximum and minimum values should ignore the data + * element whose value is equal to the fill value. + * + * If no fill value is defined, the value of each data element is subtracted by the minimum value + * during this stage. + * + * If the fill value is defined, the fill value is assigned to the maximum value. In this way minimum- + * bits can represent a data element whose value is equal to the fill value and subtracts the + * minimum value from a data element whose value is not equal to the fill value. + * + * The fill value (if defined), the number of elements in a chunk, the class of the datatype, the size + * of the datatype, the memory order of the datatype, and other similar elements will be stored in + * the HDF5 object header for the post-decompression usage. + * + * After pre-compression, all values are non-negative and are within the range that can be stored by + * minimum-bits. + * + * Compression: All modified data values after pre-compression are packed together into the + * compressed data buffer. The number of bits for each data value decreases from the number of + * bits of integer (32 for most platforms) to minimum-bits. The value of minimum-bits and the + * minimum value are added to the data buffer and the whole buffer is sent back to the library. In + * this way, the number of bits for each modified value is no more than the size of minimum-bits. + * + * Decompression: In this stage, the number of bits for each data value is resumed from minimum- + * bits to the number of bits of integer. + * + * Post-decompression: For the post-decompression stage, the filter does the opposite of what it + * does during pre-compression except that it does not calculate the minimum-bits or the minimum + * value. These values were saved during compression and can be retrieved through the resumed + * data buffer. If no fill value is defined, the filter adds the minimum value back to each data + * element. + * + * If the fill value is defined, the filter assigns the fill value to the data element whose value is equal + * to the maximum value that minimum-bits can represent and adds the minimum value back to + * each data element whose value is not equal to the maximum value that minimum-bits can + * represent. + * + * @anchor h4_float_datatype <h4>Floating-point Type</h4> + * The filter will do data transformation from floating-point type to integer type and then handle the + * data by using the procedure for handling the integer data inside the filter. Insignificant bits of + * floating-point data will be cut off during data transformation, so this filter is a lossy compression + * method. + * + * There are two scaling methods: D-scaling and E-scaling. The HDF5 1.8 release only supports D- + * scaling. D-scaling is short for decimal scaling. E-scaling should be similar conceptually. In order + * to transform data from floating-point to integer, a scale factor is introduced. The minimum value + * will be calculated. Each data element value will subtract the minimum value. The modified data + * will be multiplied by 10 (Decimal) to the power of scale_factor, and only the integer part will be + * kept and manipulated through the routines for the integer type of the filter during pre- + * compression and compression. Integer data will be divided by 10 to the power of scale_factor to + * transform back to floating-point data during decompression and post-decompression. Each data + * element value will then add the minimum value, and the floating-point data are resumed. + * However, the resumed data will lose some insignificant bits compared with the original value. + * + * For example, the following floating-point data are manipulated by the filter, and the D-scaling + * factor is 2. + * <em>{104.561, 99.459, 100.545, 105.644}</em> + * + * The minimum value is 99.459, each data element subtracts 99.459, the modified data is + * <em>{5.102, 0, 1.086, 6.185}</em> + * + * Since the D-scaling factor is 2, all floating-point data will be multiplied by 10^2 with this result: + * <em>{510.2, 0, 108.6, 618.5}</em> + * + * The digit after decimal point will be rounded off, and then the set looks like: + * <em>{510, 0, 109, 619}</em> + * + * After decompression, each value will be divided by 10^2 and will be added to the offset 99.459. + * The floating-point data becomes + * <em>{104.559, 99.459, 100.549, 105.649}</em> + * + * The relative error for each value should be no more than 5* (10^(D-scaling factor +1)). + * D-scaling sometimes is also referred as a variable minimum-bits method since for different datasets + * the minimum-bits to represent the same decimal precision will vary. The data value is modified + * to 2 to power of scale_factor for E-scaling. E-scaling is also called fixed-bits method since for + * different datasets the minimum-bits will always be fixed to the scale factor of E-scaling. + * Currently, HDF5 ONLY supports the D-scaling (variable minimum-bits) method. + * + * <h4>Implementation</h4> + * The scale-offset filter implementation was written and included in the file H5Zscaleoffset.c. + * Function #H5Pset_scaleoffset was written and included in the file “H5Pdcpl.c”. The HDF5 user + * can supply minimum-bits by calling function #H5Pset_scaleoffset. + * + * The scale-offset filter was implemented based on the design outlined in this section. However, + * the following factors need to be considered: + * <ol><li> + * The filter needs the appropriate cast pointer whenever it needs to retrieve data values. + * </li> + * <li> + * The HDF5 Library passes to the filter the to-be-compressed data in the format of the dataset + * datatype, and the filter passes back the decompressed data in the same format. If a fill value is + * defined, it is also in dataset datatype format. For example, if the byte order of the dataset data- + * type is different from that of the memory datatype of the platform, compression or decompression performs + * an endianness conversion of data buffer. Moreover, it should be aware that + * memory byte order can be different during compression and decompression. + * </li> + * <li> + * The difference of endianness and datatype between file and memory should be considered + * when saving and retrieval of minimum-bits, minimum value, and fill value. + * <li> + * If the user sets the minimum-bits to full precision of the datatype, no operation is needed at + * the filter side. If the full precision is a result of calculation by the filter, then the minimum-bits + * needs to be saved for decompression but no compression or decompression is needed (only a + * copy of the input buffer is needed).</li> + * <li> + * If by calculation of the filter, the minimum-bits is equal to zero, special handling is needed. + * Since it means all values are the same, no compression or decompression is needed. But the + * minimum-bits and minimum value still need to be saved during compression.</li> + * <li> + * For floating-point data, the minimum value of the dataset should be calculated at first. Each + * data element value will then subtract the minimum value to obtain the “offset” data. The offset + * data will then follow the steps outlined above in the discussion of floating-point types to do data + * transformation to integer and rounding. For more information, @see @ref h4_float_datatype. + * </li></ol> + * + * <h4>Usage Examples</h4> + * The following code example illustrates the use of the scale-offset filter for writing and reading + * integer data. + * + * <em>Scale-offset compression integer data</em> + * \code + * #include "hdf5.h" + * #include "stdlib.h" + * + * #define H5FILE_NAME "scaleoffset_test_int.h5" + * #define DATASET_NAME "scaleoffset_int" + * #define NX 200 + * #define NY 300 + * #define CH_NX 10 + * #define CH_NY 15 + * int main(void) + * { + * hid_t file, dataspace, dataset, datatype, dset_create_props; + * hsize_t dims[2], chunk_size[2]; + * int orig_data[NX][NY]; + * int new_data[NX][NY]; + * int i, j, fill_val; + * + * // Define dataset datatype + * datatype = H5Tcopy(H5T_NATIVE_INT); + * + * // Initialize data buffer + * for (i=0; i < NX; i++) + * for (j=0; j < NY; j++) + * orig_data[i][j] = rand() % 10000; + * + * // Describe the size of the array. + * dims[0] = NX; + * dims[1] = NY; + * if((dataspace = H5Screate_simple (2, dims, NULL)) < 0) { + * printf("Error: fail to create dataspace\n"); + * return -1; + * } + * + * // Create a new file using read/write access, default file + * // creation properties, and default file access properties. + * if((file = H5Fcreate (H5FILE_NAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + * printf("Error: fail to create file\n"); + * return -1; + * } + * + * // Set the dataset creation property list to specify that + * // the raw data is to be partitioned into 10 x 15 element + * // chunks and that each chunk is to be compressed. + * chunk_size[0] = CH_NX; + * chunk_size[1] = CH_NY; + * if((dset_create_props = H5Pcreate (H5P_DATASET_CREATE)) < 0) { + * printf("Error: fail to create dataset property\n"); + * return -1; + * } + * if(H5Pset_chunk (dset_create_props, 2, chunk_size) < 0) { + * printf("Error: fail to set chunk\n"); + * return -1; + * } + * + * // Set the fill value of dataset + * fill_val = 10000; + * if (H5Pset_fill_value(dset_create_props, H5T_NATIVE_INT, &fill_val)<0) { + * printf("Error: can not set fill value for dataset\n"); + * return -1; + * } + * + * // Set parameters for scale-offset compression. Check the + * // description of the H5Pset_scaleoffset function in the + * // HDF5 Reference Manual for more information. + * if(H5Pset_scaleoffset (dset_create_props, H5Z_SO_INT, H5Z_SO_INT_MINIMUMBITS_DEFAULT) < 0) { + * printf("Error: fail to set scaleoffset filter\n"); + * return -1; + * } + * + * // Create a new dataset within the file. The datatype + * // and dataspace describe the data on disk, which may + * // or may not be different from the format used in the + * // application's memory. The link creation and + * // dataset access property list parameters are passed + * // with default values. + * if((dataset = H5Dcreate (file, DATASET_NAME, datatype, dataspace, H5P_DEFAULT, + * dset_create_props, H5P_DEFAULT)) < 0) { + * printf("Error: fail to create dataset\n"); + * return -1; + * } + * + * // Write the array to the file. The datatype and dataspace + * // describe the format of the data in the 'orig_data' buffer. + * // We use default raw data transfer properties. + * if(H5Dwrite (dataset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, orig_data) < 0) { + * printf("Error: fail to write to dataset\n"); + * return -1; + * } + * + * H5Dclose (dataset); + * + * if((dataset = H5Dopen(file, DATASET_NAME, H5P_DEFAULT)) < 0) { + * printf("Error: fail to open dataset\n"); + * return -1; + * } + * + * // Read the array. This is similar to writing data, + * // except the data flows in the opposite direction. + * // Note: Decompression is automatic. + * if(H5Dread (dataset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, new_data) < 0) { + * printf("Error: fail to read from dataset\n"); + * return -1; + * } + * + * H5Tclose (datatype); + * H5Dclose (dataset); + * H5Sclose (dataspace); + * H5Pclose (dset_create_props); + * H5Fclose (file); + * + * return 0; + * } + * \endcode + * + * The following code example illustrates the use of the scale-offset filter (set for variable + * minimum-bits method) for writing and reading floating-point data. + * + * <em>Scale-offset compression floating-point data</em> + * \code + * #include "hdf5.h" + * #include "stdlib.h" + * + * #define H5FILE_NAME "scaleoffset_test_float_Dscale.h5" + * #define DATASET_NAME "scaleoffset_float_Dscale" + * #define NX 200 + * #define NY 300 + * #define CH_NX 10 + * #define CH_NY 15 + * + * int main(void) + * { + * hid_t file, dataspace, dataset, datatype, dset_create_props; + * hsize_t dims[2], chunk_size[2]; + * float orig_data[NX][NY]; + * float new_data[NX][NY]; + * float fill_val; + * int i, j; + * + * // Define dataset datatype + * datatype = H5Tcopy(H5T_NATIVE_FLOAT); + * + * // Initialize data buffer + * for (i=0; i < NX; i++) + * for (j=0; j < NY; j++) + * orig_data[i][j] = (rand() % 10000) / 1000.0; + * + * // Describe the size of the array. + * dims[0] = NX; + * dims[1] = NY; + * if((dataspace = H5Screate_simple (2, dims, NULL)) < 0) { + * printf("Error: fail to create dataspace\n"); + * return -1; + * } + * + * // Create a new file using read/write access, default file + * // creation properties, and default file access properties. + * if((file = H5Fcreate (H5FILE_NAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + * printf("Error: fail to create file\n"); + * return -1; + * } + * + * // Set the dataset creation property list to specify that + * // the raw data is to be partitioned into 10 x 15 element + * // chunks and that each chunk is to be compressed. + * chunk_size[0] = CH_NX; + * chunk_size[1] = CH_NY; + * if((dset_create_props = H5Pcreate (H5P_DATASET_CREATE)) < 0) { + * printf("Error: fail to create dataset property\n"); + * return -1; + * } + * if(H5Pset_chunk (dset_create_props, 2, chunk_size) < 0) { + * printf("Error: fail to set chunk\n"); + * return -1; + * } + * + * // Set the fill value of dataset + * fill_val = 10000.0; + * if (H5Pset_fill_value(dset_create_props, H5T_NATIVE_FLOAT, &fill_val) < 0) { + * printf("Error: can not set fill value for dataset\n"); + * return -1; + * } + * + * // Set parameters for scale-offset compression; use variable + * // minimum-bits method, set decimal scale factor to 3. Check + * // the description of the H5Pset_scaleoffset function in the + * // HDF5 Reference Manual for more information. + * if(H5Pset_scaleoffset (dset_create_props, H5Z_SO_FLOAT_DSCALE, 3) < 0) { + * printf("Error: fail to set scaleoffset filter\n"); + * return -1; + * } + * + * // Create a new dataset within the file. The datatype + * // and dataspace describe the data on disk, which may + * // or may not be different from the format used in the + * // application's memory. + * if((dataset = H5Dcreate (file, DATASET_NAME, datatype, dataspace, H5P_DEFAULT, + * dset_create_props, H5P_DEFAULT)) < 0) { + * printf("Error: fail to create dataset\n"); + * return -1; + * } + * + * // Write the array to the file. The datatype and dataspace + * // describe the format of the data in the 'orig_data' buffer. + * // We use default raw data transfer properties. + * if(H5Dwrite (dataset, H5T_NATIVE_FLOAT, H5S_ALL, H5S_ALL, H5P_DEFAULT, orig_data) < 0) { + * printf("Error: fail to write to dataset\n"); + * return -1; + * } + * + * H5Dclose (dataset); + * + * if((dataset = H5Dopen(file, DATASET_NAME, H5P_DEFAULT)) < 0) { + * printf("Error: fail to open dataset\n"); + * return -1; + * } + * + * // Read the array. This is similar to writing data, + * // except the data flows in the opposite direction. + * // Note: Decompression is automatic. + * if(H5Dread (dataset, H5T_NATIVE_FLOAT, H5S_ALL, H5S_ALL, H5P_DEFAULT, new_data) < 0) { + * printf("Error: fail to read from dataset\n"); + * return -1; + * } + * + * H5Tclose (datatype); + * H5Dclose (dataset); + * H5Sclose (dataspace); + * H5Pclose (dset_create_props); + * H5Fclose (file); + * + * return 0; + * } + * \endcode + * + * <h4>Limitations</h4> + * For floating-point data handling, there are some algorithmic limitations to the GRiB data packing + * mechanism: + * <ol><li> + * Both the E-scaling and D-scaling methods are lossy compression + * </li> + * <li> + * For the D-scaling method, since data values have been rounded to integer values (positive) + * before truncating to the minimum-bits, their range is limited by the maximum value that can be + * represented by the corresponding unsigned integer type (the same size as that of the floating- + * point type) + * </li></ol> + * + * <h4>Suggestions</h4> + * The following are some suggestions for using the filter for floating-point data: + * <ol><li> + * It is better to convert the units of data so that the units are within certain common range (for + * example, 1200m to 1.2km) + * </li> + * <li> + * If data values to be compressed are very near to zero, it is strongly recommended that the + * user sets the fill value away from zero (for example, a large positive number); if the user does + * nothing, the HDF5 library will set the fill value to zero, and this may cause undesirable + * compression results + * </li> + * <li> + * Users are not encouraged to use a very large decimal scale factor (for example, 100) for the + * D-scaling method; this can cause the filter not to ignore the fill value when finding maximum + * and minimum values, and they will get a much larger minimum-bits (poor compression) + * </li></ol> + * + * \subsubsection subsubsec_dataset_filters_szip Using the Szip Filter + * See The HDF Group website for further information regarding the Szip filter. + * + * Previous Chapter \ref sec_group - Next Chapter \ref sec_datatype + * + */ + +/** + * \defgroup H5D Datasets (H5D) * * Use the functions in this module to manage HDF5 datasets, including the * transfer of data between memory and disk and the description of dataset |