2022-09-15 04:44:24 +08:00
/** @page LBGrpCreate Creating an Group
Navigate back: \ref index "Main" / \ref GettingStarted / \ref LearnBasics
<hr>
\section secLBGrpCreate Creating an group
An HDF5 group is a structure containing zero or more HDF5 objects. The two primary HDF5 objects are groups and datasets. To create a group, the calling program must:
<ol>
<li>Obtain the location identifier where the group is to be created.</li>
<li>Create the group.</li>
<li>Close the group.</li>
</ol>
To create a group, the calling program must call #H5Gcreate.
To close the group, #H5Gclose must be called. The close call is mandatory.
For example:
<em>C</em>
\code
group_id = H5Gcreate(file_id, "/MyGroup", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
status = H5Gclose (group_id);
\endcode
<em>Fortran</em>
\code
CALL h5gcreate_f (loc_id, name, group_id, error)
CALL h5gclose_f (group_id, error)
\endcode
\section secLBGrpCreateRWEx Programming Example
\subsection secLBGrpCreateRWExDesc Description
See \ref LBExamples for the examples used in the \ref LearnBasics tutorial.
The example shows how to create and close a group. It creates a file called <code style="background-color:whitesmoke;">group.h5</code> in C
(<code style="background-color:whitesmoke;">groupf.h5</code> for FORTRAN), creates a group called MyGroup in the root group, and then closes the group and file.
For details on compiling an HDF5 application:
[ \ref LBCompiling ]
\subsection secLBGrpCreateRWExCont File Contents
Shown below is the contents and the definition of the group of <code style="background-color:whitesmoke;">group.h5</code> (created by the C program).
(The FORTRAN program creates the HDF5 file <code style="background-color:whitesmoke;">groupf.h5</code> and the resulting DDL shows the filename
<code style="background-color:whitesmoke;">groupf.h5</code> in the first line.)
<table>
<caption>The Contents of group.h5.</caption>
<tr>
<td>
\image html imggrpcreate.gif
</td>
</tr>
</table>
<em>group.h5 in DDL</em>
\code
HDF5 "group.h5" {
GROUP "/" {
GROUP "MyGroup" {
}
}
}
\endcode
<hr>
Navigate back: \ref index "Main" / \ref GettingStarted / \ref LearnBasics
@page LBGrpCreateNames Creating Groups using Absolute and Relative Names
Navigate back: \ref index "Main" / \ref GettingStarted / \ref LearnBasics
<hr>
Recall that to create an HDF5 object, we have to specify the location where the object is to be created.
This location is determined by the identifier of an HDF5 object and the name of the object to be created.
The name of the created object can be either an absolute name or a name relative to the specified identifier.
In the previous example, we used the file identifier and the absolute name <code style="background-color:whitesmoke;">/MyGroup</code> to create a group.
In this section, we discuss HDF5 names and show how to use absolute and relative names.
\section secLBGrpCreateNames Names
HDF5 object names are a slash-separated list of components. There are few restrictions on names: component
names may be any length except zero and may contain any character except slash (<code style="background-color:whitesmoke;">/</code>) and the null terminator.
A full name may be composed of any number of component names separated by slashes, with any of the component
names being the special name <code style="background-color:whitesmoke;">.</code> (a dot or period). A name which begins with a slash is an <em>absolute name</em> which
is accessed beginning with the root group of the file; all other names are <em>relative names</em> and and the named
object is accessed beginning with the specified group. A special case is the name <code style="background-color:whitesmoke;">/</code> (or equivalent) which
refers to the root group.
Functions which operate on names generally take a location identifier, which can be either a file identifier
or a group identifier, and perform the lookup with respect to that location. Several possibilities are
described in the following table:
<table>
<tr>
<th><strong>Location Type</strong></th>
<th><strong>Object Name</strong></th>
<th><strong>Description</strong></th>
</tr>
<tr>
<th><strong>File identifier</strong></th>
<td>/foo/bar</td>
<td>The object bar in group foo in the root group.</td>
</tr>
<tr>
<th><strong>Group identifier</strong></th>
<td>/foo/bar</td>
<td>The object bar in group foo in the root group of the file containing the specified group.
In other words, the group identifier's only purpose is to specify a file.</td>
</tr>
<tr>
<th><strong>File identifier</strong></th>
<td>/</td>
<td>The root group of the specified file.</td>
</tr>
<tr>
<th><strong>Group identifier</strong></th>
<td>/</td>
<td>The root group of the file containing the specified group.</td>
</tr>
<tr>
<th><strong>Group identifier</strong></th>
<td>foo/bar</td>
<td>The object bar in group foo in the specified group.</td>
</tr>
<tr>
<th><strong>File identifier</strong></th>
<td>.</td>
<td>The root group of the file.</td>
</tr>
<tr>
<th><strong>Group identifier</strong></th>
<td>.</td>
<td>The specified group.</td>
</tr>
<tr>
<th><strong>Other identifier</strong></th>
<td>.</td>
<td>The specified object.</td>
</tr>
</table>
\section secLBGrpCreateNamesEx Programming Example
\subsection secLBGrpCreateNamesExDesc Description
See \ref LBExamples for the examples used in the \ref LearnBasics tutorial.
The example code shows how to create groups using absolute and relative names. It creates three groups: the first two groups are created using
the file identifier and the group absolute names while the third group is created using a group identifier and a name relative to the specified group.
For details on compiling an HDF5 application:
[ \ref LBCompiling ]
\subsection secLBGrpCreateNamesExRem Remarks
#H5Gcreate creates a group at the location specified by a location identifier and a name. The location identifier
can be a file identifier or a group identifier and the name can be relative or absolute.
The first #H5Gcreate/h5gcreate_f creates the group <code style="background-color:whitesmoke;">MyGroup</code> in the root group of the specified file.
The second #H5Gcreate/h5gcreate_f creates the group <code style="background-color:whitesmoke;">Group_A</code> in the group <code style="background-color:whitesmoke;">MyGroup</code> in the root group of the specified
file. Note that the parent group (<code style="background-color:whitesmoke;">MyGroup</code>) already exists.
The third #H5Gcreate/h5gcreate_f creates the group <code style="background-color:whitesmoke;">Group_B</code> in the specified group.
\subsection secLBGrpCreateNamesExCont File Contents
Shown below is the contents and the definition of the group of <code style="background-color:whitesmoke;">groups.h5</code> (created by the C program).
(The FORTRAN program creates the HDF5 file <code style="background-color:whitesmoke;">groupsf.h5</code> and the resulting DDL shows the filename
<code style="background-color:whitesmoke;">groupsf.h5</code> in the first line.)
<table>
<caption>The Contents of groups.h5.</caption>
<tr>
<td>
\image html imggrps.gif
</td>
</tr>
</table>
<em>groups.h5 in DDL</em>
\code
HDF5 "groups.h5" {
GROUP "/" {
GROUP "MyGroup" {
GROUP "Group_A" {
}
GROUP "Group_B" {
}
}
}
}
\endcode
<hr>
Navigate back: \ref index "Main" / \ref GettingStarted / \ref LearnBasics
@page LBGrpDset Creating Datasets in Groups
Navigate back: \ref index "Main" / \ref GettingStarted / \ref LearnBasics
<hr>
\section secLBGrpDset Datasets in Groups
We have shown how to create groups, datasets, and attributes. In this section, we show how to create
datasets in groups. Recall that #H5Dcreate creates a dataset at the location specified by a location
identifier and a name. Similar to #H5Gcreate, the location identifier can be a file identifier or a
group identifier and the name can be relative or absolute. The location identifier and the name
together determine the location where the dataset is to be created. If the location identifier and
name refer to a group, then the dataset is created in that group.
\section secLBGrpDsetEx Programming Example
\subsection secLBGrpDsetExDesc Description
See \ref LBExamples for the examples used in the \ref LearnBasics tutorial.
The example shows how to create a dataset in a particular group. It opens the file created in the previous example and creates two datasets:
For details on compiling an HDF5 application:
[ \ref LBCompiling ]
\subsection secLBGrpDsetExCont File Contents
Shown below is the contents and the definition of the group of <code style="background-color:whitesmoke;">groups.h5</code> (created by the C program).
(The FORTRAN program creates the HDF5 file <code style="background-color:whitesmoke;">groupsf.h5</code> and the resulting DDL shows the filename
<code style="background-color:whitesmoke;">groupsf.h5</code> in the first line.)
<table>
<caption>The contents of the file groups.h5 (groupsf.h5 for FORTRAN)</caption>
<tr>
<td>
\image html imggrpdsets.gif
</td>
</tr>
</table>
<em>groups.h5 in DDL</em>
\code
HDF5 "groups.h5" {
GROUP "/" {
GROUP "MyGroup" {
GROUP "Group_A" {
DATASET "dset2" {
DATATYPE { H5T_STD_I32BE }
DATASPACE { SIMPLE ( 2, 10 ) / ( 2, 10 ) }
DATA {
1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10
}
}
}
GROUP "Group_B" {
}
DATASET "dset1" {
DATATYPE { H5T_STD_I32BE }
DATASPACE { SIMPLE ( 3, 3 ) / ( 3, 3 ) }
DATA {
1, 2, 3,
1, 2, 3,
1, 2, 3
}
}
}
}
}
\endcode
<em>groupsf.h5 in DDL</em>
\code
HDF5 "groupsf.h5" {
GROUP "/" {
GROUP "MyGroup" {
GROUP "Group_A" {
DATASET "dset2" {
DATATYPE { H5T_STD_I32BE }
DATASPACE { SIMPLE ( 10, 2 ) / ( 10, 2 ) }
DATA {
1, 1,
2, 2,
3, 3,
4, 4,
5, 5,
6, 6,
7, 7,
8, 8,
9, 9,
10, 10
}
}
}
GROUP "Group_B" {
}
DATASET "dset1" {
DATATYPE { H5T_STD_I32BE }
DATASPACE { SIMPLE ( 3, 3 ) / ( 3, 3 ) }
DATA {
1, 1, 1,
2, 2, 2,
3, 3, 3
}
}
}
}
}
\endcode
<hr>
Navigate back: \ref index "Main" / \ref GettingStarted / \ref LearnBasics
@page LBDsetSubRW Reading From or Writing To a Subset of a Dataset
Navigate back: \ref index "Main" / \ref GettingStarted / \ref LearnBasics
<hr>
\section secLBDsetSubRW Dataset Subsets
There are two ways that you can select a subset in an HDF5 dataset and read or write to it:
<ul><li>
<strong>Hyperslab Selection</strong>: The #H5Sselect_hyperslab call selects a logically contiguous
collection of points in a dataspace, or a regular pattern of points or blocks in a dataspace.
</li><li>
<strong>Element Selection</strong>: The #H5Sselect_elements call selects elements in an array.
</li></ul>
HDF5 allows you to read from or write to a portion or subset of a dataset by:
\li Selecting a Subset of the Dataset's Dataspace,
\li Selecting a Memory Dataspace,
\li Reading From or Writing to a Dataset Subset.
\section secLBDsetSubRWSel Selecting a Subset of the Dataset's Dataspace
First you must obtain the dataspace of a dataset in a file by calling #H5Dget_space.
Then select a subset of that dataspace by calling #H5Sselect_hyperslab. The <em>offset</em>, <em>count</em>, <em>stride</em>
and <em>block</em> parameters of this API define the shape and size of the selection. They must be arrays
with the same number of dimensions as the rank of the dataset's dataspace. These arrays <strong>ALL</strong> work
together to define a selection. A change to one of these arrays can affect the others.
\li \em offset: An array that specifies the offset of the starting element of the specified hyperslab.
\li \em count: An array that determines how many blocks to select from the dataspace in each dimension. If the block
size for a dimension is one then the count is the number of elements along that dimension.
\li \em stride: An array that allows you to sample elements along a dimension. For example, a stride of one (or NULL)
will select every element along a dimension, a stride of two will select every other element, and a stride of three
will select an element after every two elements.
\li \em block: An array that determines the size of the element block selected from a dataspace. If the block size
is one or NULL then the block size is a single element in that dimension.
\section secLBDsetSubRWMem Selecting a Memory Dataspace
You must select a memory dataspace in addition to a file dataspace before you can read a subset from or write a subset
to a dataset. A memory dataspace can be specified by calling #H5Screate_simple.
The memory dataspace passed to the read or write call must contain the same number of elements as the file dataspace.
The number of elements in a dataspace selection can be determined with the #H5Sget_select_npoints API.
\section secLBDsetSubRWSub Reading From or Writing To a Dataset Subset
To read from or write to a dataset subset, the #H5Dread and #H5Dwrite routines are used. The memory and file dataspace
identifiers from the selections that were made are passed into the read or write call. For example (C):
\code
status = H5Dwrite (.., .., memspace_id, dataspace_id, .., ..);
\endcode
\section secLBDsetSubRWProg Programming Example
\subsection subsecLBDsetSubRWProgDesc Description
See \ref LBExamples for the examples used in the \ref LearnBasics tutorial.
The example creates an 8 x 10 integer dataset in an HDF5 file. It then selects and writes to a 3 x 4 subset
of the dataset created with the dimensions offset by 1 x 2. (If using Fortran, the dimensions will be swapped.
The dataset will be 10 x 8, the subset will be 4 x 3, and the offset will be 2 x 1.)
PLEASE NOTE that the examples and images below were created using C.
The following image shows the dataset that gets written originally, and the subset of data that gets modified
afterwards. Dimension 0 is vertical and Dimension 1 is horizontal as shown below:
<table>
<tr>
<td>
\image html LBDsetSubRWProg.png
</td>
</tr>
</table>
The subset on the right above is created using these values for offset, count stride, and block:
\code
offset = {1, 2}
count = {3, 4}
stride = {1, 1}
block = {1, 1}
\endcode
\subsection subsecLBDsetSubRWProgExper Experiments with Different Selections
Following are examples of changes that can be made to the example code provided to better understand
how to make selections.
\subsubsection subsubsecLBDsetSubRWProgExperOne Example 1
By default the example code will select and write to a 3 x 4 subset. You can modify the count
parameter in the example code to select a different subset, by changing the value of
DIM0_SUB (C, C++) / dim0_sub (Fortran) near the top. Change its value to 7 to create a 7 x 4 subset:
<table>
<tr>
<td>
\image html imgLBDsetSubRW11.png
</td>
</tr>
</table>
If you were to change the subset to 8 x 4, the selection would be beyond the extent of the dimension:
<table>
<tr>
<td>
\image html imgLBDsetSubRW12.png
</td>
</tr>
</table>
The write will fail with the error: "<strong>file selection+offset not within extent</strong>"
\subsubsection subsubsecLBDsetSubRWProgExperTwo Example 2
In the example code provided, the memory and file dataspaces passed to the H5Dwrite call have the
same size, 3 x 4 (DIM0_SUB x DIM1_SUB). Change the size of the memory dataspace to be 4 x 4 so that
they do not match, and then compile:
\code
dimsm[0] = DIM0_SUB + 1;
dimsm[1] = DIM1_SUB;
memspace_id = H5Screate_simple (RANK, dimsm, NULL);
\endcode
The code will fail with the error: "<strong>src and dest data spaces have different sizes</strong>"
How many elements are in the memory and file dataspaces that were specified above? Add these lines:
\code
hssize_t size;
/* Just before H5Dwrite call the following */
size = H5Sget_select_npoints (memspace_id);
printf ("\nmemspace_id size: %i\n", size);
size = H5Sget_select_npoints (dataspace_id);
printf ("dataspace_id size: %i\n", size);
\endcode
You should see these lines followed by the error:
\code
memspace_id size: 16
dataspace_id size: 12
\endcode
\subsubsection subsubsecLBDsetSubRWProgExperThree Example 3
This example shows the selection that occurs if changing the values of the <em>offset</em>, <em>count</em>,
<em>stride</em> and <em>block</em> parameters in the example code.
This will select two blocks. The <em>count</em> array specifies the number of blocks. The <em>block</em> array
specifies the size of a block. The <em>stride</em> must be modified to accommodate the block <em>size</em>.
<table>
<tr>
<td>
\image html imgLBDsetSubRW31.png
</td>
</tr>
</table>
Now try modifying the count as shown below. The write will fail because the selection goes beyond the extent of the dimension:
<table>
<tr>
<td>
\image html imgLBDsetSubRW32.png
</td>
</tr>
</table>
If the offset were 1x1 (instead of 1x2), then the selection can be made:
<table>
<tr>
<td>
\image html imgLBDsetSubRW33.png
</td>
</tr>
</table>
The selections above were tested with the
<a href="https://support.hdfgroup.org/ftp/HDF5/examples/howto/subset/h5_subsetbk.c">h5_subsetbk.c</a>
example code. The memory dataspace was defined as one-dimensional.
\subsection subsecLBDsetSubRWProgRem Remarks
\li In addition to #H5Sselect_hyperslab, this example introduces the #H5Dget_space call to obtain the dataspace of a dataset.
\li If using the default values for the stride and block parameters of #H5Sselect_hyperslab, then, for C you can specify NULL
for these parameters, rather than passing in an array for each, and for Fortran 90 you can omit these parameters.
<hr>
Navigate back: \ref index "Main" / \ref GettingStarted / \ref LearnBasics
@page LBDatatypes Datatype Basics
Navigate back: \ref index "Main" / \ref GettingStarted / \ref LearnBasics
<hr>
\section secLBDtype What is a Datatype?
A datatype is a collection of datatype properties which provide complete information for data conversion to or from that datatype.
Datatypes in HDF5 can be grouped as follows:
\li <strong>Pre-Defined Datatypes</strong>: These are datatypes that are created by HDF5. They are actually opened
(and closed) by HDF5, and can have a different value from one HDF5 session to the next.
\li <strong>Derived Datatypes</strong>: These are datatypes that are created or derived from the pre-defined datatypes.
Although created from pre-defined types, they represent a category unto themselves. An example of a commonly used derived
datatype is a string of more than one character.
\section secLBDtypePre Pre-defined Datatypes
The properties of pre-defined datatypes are:
\li Pre-defined datatypes are opened and closed by HDF5.
\li A pre-defined datatype is a handle and is NOT PERSISTENT. Its value can be different from one HDF5 session to the next.
\li Pre-defined datatypes are Read-Only.
\li As mentioned, other datatypes can be derived from pre-defined datatypes.
There are two types of pre-defined datatypes, standard (file) and native.
<h4>Standard</h4>
A standard (or file) datatype can be:
<ul>
<li><strong>Atomic</strong>: A datatype which cannot be decomposed into smaller datatype units at the API level.
The atomic datatypes are:
<ul>
<li>integer</li>
<li>float</li>
<li>string (1-character)</li>
<li>date and time</li>
<li>bitfield</li>
<li>reference</li>
<li>opaque</li>
</ul>
</li>
<li><strong>Composite</strong>: An aggregation of one or more datatypes.
Composite datatypes include:
<ul>
<li>array</li>
<li>variable length</li>
<li>enumeration</li>
<li>compound datatypes</li>
</ul>
Array, variable length, and enumeration datatypes are defined in terms of a single atomic datatype,
whereas a compound datatype is a datatype composed of a sequence of datatypes.
</li>
</ul>
<table>
<tr>
<th><strong>Notes</strong></th>
</tr>
<tr>
<td>
\li Standard pre-defined datatypes are the SAME on all platforms.
\li They are the datatypes that you see in an HDF5 file.
\li They are typically used when creating a dataset.
</td>
</tr>
</table>
<h4>Native</h4>
Native pre-defined datatypes are used for memory operations, such as reading and writing. They are
NOT THE SAME on different platforms. They are similar to C type names, and are aliased to the
appropriate HDF5 standard pre-defined datatype for a given platform.
For example, when on an Intel based PC, #H5T_NATIVE_INT is aliased to the standard pre-defined type,
#H5T_STD_I32LE. On a MIPS machine, it is aliased to #H5T_STD_I32BE.
<table>
<tr>
<th><strong>Notes</strong></th>
</tr>
<tr>
<td>
\li Native datatypes are NOT THE SAME on all platforms.
\li Native datatypes simplify memory operations (read/write). The HDF5 library automatically converts as needed.
\li Native datatypes are NOT in an HDF5 File. The standard pre-defined datatype that a native datatype corresponds
to is what you will see in the file.
</td>
</tr>
</table>
<h4>Pre-Defined</h4>
The following table shows the native types and the standard pre-defined datatypes they correspond
to. (Keep in mind that HDF5 can convert between datatypes, so you can specify a buffer of a larger
type for a dataset of a given type. For example, you can read a dataset that has a short datatype
into a long integer buffer.)
<table>
<caption>Some HDF5 pre-defined native datatypes and corresponding standard (file) type</caption>
<tr>
<th><strong>C Type</strong></th>
<th><strong>HDF5 Memory Type</strong></th>
<th><strong>HDF5 File Type*</strong></th>
</tr>
<tr>
<th span="3"><strong>Integer</strong></th>
</tr>
<tr>
<td>int</td>
<td>#H5T_NATIVE_INT</td>
<td>#H5T_STD_I32BE or #H5T_STD_I32LE</td>
</tr>
<tr>
<td>short</td>
<td>#H5T_NATIVE_SHORT</td>
<td>#H5T_STD_I16BE or #H5T_STD_I16LE</td>
</tr>
<tr>
<td>long</td>
<td>#H5T_NATIVE_LONG</td>
<td>#H5T_STD_I32BE, #H5T_STD_I32LE,
#H5T_STD_I64BE or #H5T_STD_I64LE</td>
</tr>
<tr>
<td>long long</td>
<td>#H5T_NATIVE_LLONG</td>
<td>#H5T_STD_I64BE or #H5T_STD_I64LE</td>
</tr>
<tr>
<td>unsigned int</td>
<td>#H5T_NATIVE_UINT</td>
<td>#H5T_STD_U32BE or #H5T_STD_U32LE</td>
</tr>
<tr>
<td>unsigned short</td>
<td>#H5T_NATIVE_USHORT</td>
<td>#H5T_STD_U16BE or #H5T_STD_U16LE</td>
</tr>
<tr>
<td>unsigned long</td>
<td>#H5T_NATIVE_ULONG</td>
<td>#H5T_STD_U32BE, #H5T_STD_U32LE,
#H5T_STD_U64BE or #H5T_STD_U64LE</td>
</tr>
<tr>
<td>unsigned long long</td>
<td>#H5T_NATIVE_ULLONG</td>
<td>#H5T_STD_U64BE or #H5T_STD_U64LE</td>
</tr>
<tr>
<th span="3"><strong>Float</strong></th>
</tr>
<tr>
2024-03-19 12:36:46 +08:00
<td>_Float16</td>
<td>#H5T_NATIVE_FLOAT16</td>
<td>#H5T_IEEE_F16BE or #H5T_IEEE_F16LE</td>
</tr>
<tr>
2022-09-15 04:44:24 +08:00
<td>float</td>
<td>#H5T_NATIVE_FLOAT</td>
<td>#H5T_IEEE_F32BE or #H5T_IEEE_F32LE</td>
</tr>
<tr>
<td>double</td>
<td>#H5T_NATIVE_DOUBLE</td>
<td>#H5T_IEEE_F64BE or #H5T_IEEE_F64LE</td>
</tr>
</table>
<table>
<caption>Some HDF5 pre-defined native datatypes and corresponding standard (file) type</caption>
<tr>
<th><strong>F90 Type</strong></th>
<th><strong>HDF5 Memory Type</strong></th>
<th><strong>HDF5 File Type*</strong></th>
</tr>
<tr>
<td>integer</td>
<td>H5T_NATIVE_INTEGER</td>
<td>#H5T_STD_I32BE(8,16) or #H5T_STD_I32LE(8,16)</td>
</tr>
<tr>
<td>real</td>
<td>H5T_NATIVE_REAL</td>
<td>#H5T_IEEE_F32BE or #H5T_IEEE_F32LE</td>
</tr>
<tr>
<td>double-precision</td>
<td>#H5T_NATIVE_DOUBLE</td>
<td>#H5T_IEEE_F64BE or #H5T_IEEE_F64LE</td>
</tr>
</table>
<table>
<tr>
<td>* Note that the HDF5 File Types listed are those that are most commonly created.
The file type created depends on the compiler switches and platforms being
used. For example, on the Cray an integer is 64-bit, and using #H5T_NATIVE_INT (C)
or H5T_NATIVE_INTEGER (F90) would result in an #H5T_STD_I64BE file type.</td>
</tr>
</table>
The following code is an example of when you would use standard pre-defined datatypes vs. native types:
\code
#include "hdf5.h"
main() {
hid_t file_id, dataset_id, dataspace_id;
herr_t status;
hsize_t dims[2]={4,6};
int i, j, dset_data[4][6];
for (i = 0; i < 4; i++)
for (j = 0; j < 6; j++)
dset_data[i][j] = i * 6 + j + 1;
file_id = H5Fcreate ("dtypes.h5", H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
dataspace_id = H5Screate_simple (2, dims, NULL);
dataset_id = H5Dcreate (file_id, "/dset", H5T_STD_I32BE, dataspace_id,
H5P_DEFAULT);
status = H5Dwrite (dataset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL,
H5P_DEFAULT, dset_data);
status = H5Dclose (dataset_id);
status = H5Fclose (file_id);
}
\endcode
By using the native types when reading and writing, the code that reads from or writes to a dataset
can be the same for different platforms.
Can native types also be used when creating a dataset? Yes. However, just be aware that the resulting
datatype in the file will be one of the standard pre-defined types and may be different than expected.
What happens if you do not use the correct native datatype for a standard (file) datatype? Your data
may be incorrect or not what you expect.
\section secLBDtypeDer Derived Datatypes
ANY pre-defined datatype can be used to derive user-defined datatypes.
To create a datatype derived from a pre-defined type:
<ol>
<li>Make a copy of the pre-defined datatype:
\code
tid = H5Tcopy (H5T_STD_I32BE);
\endcode
</li>
<li>Change the datatype.</li>
</ol>
There are numerous datatype functions that allow a user to alter a pre-defined datatype. See
\ref subsecLBDtypeSpecStr below for a simple example.
Refer to the \ref H5T in the \ref RM. Example functions are #H5Tset_size and #H5Tset_precision.
\section secLBDtypeSpec Specific Datatypes
2023-11-02 20:55:50 +08:00
On the \ref ExAPI
page under \ref sec_exapi_dtypes
2022-09-15 04:44:24 +08:00
you will find many example programs for creating and reading datasets with different datatypes.
Below is additional information on some of the datatypes. See
2023-11-02 20:55:50 +08:00
the \ref ExAPI
2022-09-15 04:44:24 +08:00
page for examples of these datatypes.
\subsection subsecLBDtypeSpec Array Datatype vs Array Dataspace
#H5T_ARRAY is a datatype, and it should not be confused with the dataspace of a dataset. The dataspace
of a dataset can consist of a regular array of elements. For example, the datatype for a dataset
could be an atomic datatype like integer, and the dataset could be an N-dimensional appendable array,
as specified by the dataspace. See #H5Screate and #H5Screate_simple for details.
Unlimited dimensions and subsetting are not supported when using the #H5T_ARRAY datatype.
The #H5T_ARRAY datatype was primarily created to address the simple case of a compound datatype
when all members of the compound datatype are of the same type and there is no need to subset by
compound datatype members. Creation of such a datatype is more efficient and I/O also requires
less work, because there is no alignment involved.
\subsection subsecLBDtypeSpecArr Array Datatype
The array class of datatypes, #H5T_ARRAY, allows the construction of true, homogeneous,
multi-dimensional arrays. Since these are homogeneous arrays, each element of the array
will be of the same datatype, designated at the time the array is created.
Users may be confused by this datatype, as opposed to a dataset with a simple atomic
datatype (eg. integer) that is an array. See subsecLBDtypeSpec for more information.
Arrays can be nested. Not only is an array datatype used as an element of an HDF5 dataset,
but the elements of an array datatype may be of any datatype, including another array datatype.
Array datatypes <strong>cannot be subdivided for I/O</strong>; the entire array must be transferred from one
dataset to another.
Within certain limitations, outlined in the next paragraph, array datatypes may be N-dimensional
and of any dimension size. <strong>Unlimited dimensions, however, are not supported</strong>. Functionality similar
to unlimited dimension arrays is available through the use of variable-length datatypes.
The maximum number of dimensions, i.e., the maximum rank, of an array datatype is specified by
the HDF5 library constant #H5S_MAX_RANK. The minimum rank is 1 (one). All dimension sizes must
be greater than 0 (zero).
One array datatype may only be converted to another array datatype if the number of dimensions
and the sizes of the dimensions are equal and the datatype of the first array's elements can be
converted to the datatype of the second array's elements.
\subsubsection subsubsecLBDtypeSpecArrAPI Array Datatype APIs
There are three functions that are specific to array datatypes: one, #H5Tarray_create, for creating
an array datatype, and two, #H5Tget_array_ndims and #H5Tget_array_dims
for working with existing array datatypes.
<h4>Creating</h4>
The function #H5Tarray_create creates a new array datatype object. Parameters specify
\li the base datatype of each element of the array,
\li the rank of the array, i.e., the number of dimensions,
\li the size of each dimension, and
\li the dimension permutation of the array, i.e., whether the elements of the array are listed in C or FORTRAN order.
<h4>Working with existing array datatypes</h4>
2023-05-02 00:06:39 +08:00
When working with existing arrays, one must first determine the rank, or number of dimensions, of the array.
2022-09-15 04:44:24 +08:00
The function #H5Tget_array_dims returns the rank of a specified array datatype.
In many instances, one needs further information. The function #H5Tget_array_dims retrieves the
permutation of the array and the size of each dimension.
\subsection subsecLBDtypeSpecCmpd Compound
\subsubsection subsubsecLBDtypeSpecCmpdProp Properties of compound datatypes
A compound datatype is similar to a struct in C or a common block in Fortran. It is a collection of
one or more atomic types or small arrays of such types. To create and use of a compound datatype
you need to refer to various properties of the data compound datatype:
\li It is of class compound.
\li It has a fixed total size, in bytes.
\li It consists of zero or more members (defined in any order) with unique names and which occupy non-overlapping regions within the datum.
\li Each member has its own datatype.
\li Each member is referenced by an index number between zero and N-1, where N is the number of members in the compound datatype.
\li Each member has a name which is unique among its siblings in a compound datatype.
\li Each member has a fixed byte offset, which is the first byte (smallest byte address) of that member in a compound datatype.
\li Each member can be a small array of up to four dimensions.
Properties of members of a compound datatype are defined when the member is added to the compound type and cannot be subsequently modified.
\subsubsection subsubsecLBDtypeSpecCmpdDef Defining compound datatypes
Compound datatypes must be built out of other datatypes. First, one creates an empty compound
datatype and specifies its total size. Then members are added to the compound datatype in any order.
Member names. Each member must have a descriptive name, which is the key used to uniquely identify
the member within the compound datatype. A member name in an HDF5 datatype does not necessarily
have to be the same as the name of the corresponding member in the C struct in memory, although
this is often the case. Nor does one need to define all members of the C struct in the HDF5
compound datatype (or vice versa).
Offsets. Usually a C struct will be defined to hold a data point in memory, and the offsets of the
members in memory will be the offsets of the struct members from the beginning of an instance of the
struct. The library defines the macro to compute the offset of a member within a struct:
\code
HOFFSET(s,m)
\endcode
This macro computes the offset of member m within a struct variable s.
Here is an example in which a compound datatype is created to describe complex numbers whose type
is defined by the complex_t struct.
\code
typedef struct {
double re; /*real part */
double im; /*imaginary part */
} complex_t;
complex_t tmp; /*used only to compute offsets */
hid_t complex_id = H5Tcreate (H5T_COMPOUND, sizeof tmp);
H5Tinsert (complex_id, "real", HOFFSET(tmp,re), H5T_NATIVE_DOUBLE);
H5Tinsert (complex_id, "imaginary", HOFFSET(tmp,im), H5T_NATIVE_DOUBLE);
\endcode
\subsection subsecLBDtypeSpecRef Reference
There are two types of Reference datatypes in HDF5:
\li \ref subsubsecLBDtypeSpecRefObj
\li \ref subsubsecLBDtypeSpecRefDset
\subsubsection subsubsecLBDtypeSpecRefObj Reference to objects
In HDF5, objects (i.e. groups, datasets, and named datatypes) are usually accessed by name.
There is another way to access stored objects -- by reference.
An object reference is based on the relative file address of the object header in the file
and is constant for the life of the object. Once a reference to an object is created and
stored in a dataset in the file, it can be used to dereference the object it points to.
References are handy for creating a file index or for grouping related objects by storing
references to them in one dataset.
<h4>Creating and storing references to objects</h4>
The following steps are involved in creating and storing file references to objects:
<ol>
<li>Create the objects or open them if they already exist in the file.</li>
<li>Create a dataset to store the objects' references, by specifying #H5T_STD_REF_OBJ as the datatype</li>
<li>Create and store references to the objects in a buffer, using #H5Rcreate.</li>
<li>Write a buffer with the references to the dataset, using #H5Dwrite with the #H5T_STD_REF_OBJ datatype.</li>
</ol>
<h4>Reading references and accessing objects using references</h4>
The following steps are involved:
<ol>
<li>Open the dataset with the references and read them. The #H5T_STD_REF_OBJ datatype must be used to describe the memory datatype.</li>
<li>Use the read reference to obtain the identifier of the object the reference points to using #H5Rdereference.</li>
<li>Open the dereferenced object and perform the desired operations.</li>
<li>Close all objects when the task is complete.</li>
</ol>
\subsubsection subsubsecLBDtypeSpecRefDset Reference to a dataset region
A dataset region reference points to a dataset selection in another dataset.
A reference to the dataset selection (region) is constant for the life of the dataset.
<h4>Creating and storing references to dataset regions</h4>
The following steps are involved in creating and storing references to a dataset region:
\li Create a dataset to store the dataset region (selection), by passing in #H5T_STD_REF_DSETREG for the datatype when calling #H5Dcreate.
\li Create selection(s) in existing dataset(s) using #H5Sselect_hyperslab and/or #H5Sselect_elements.
\li Create reference(s) to the selection(s) using #H5Rcreate and store them in a buffer.
\li Write the references to the dataset regions in the file.
\li Close all objects.
<h4>Reading references to dataset regions</h4>
The following steps are involved in reading references to dataset regions and referenced dataset regions (selections).
<ol>
<li>Open and read the dataset containing references to the dataset regions.
The datatype #H5T_STD_REF_DSETREG must be used during read operation.</li>
<li>Use #H5Rdereference to obtain the dataset identifier from the read dataset region reference.
OR
Use #H5Rget_region to obtain the dataspace identifier for the dataset containing the selection from the read dataset region reference.
</li>
<li>With the dataspace identifier, the \ref H5S interface functions, H5Sget_select_*,
can be used to obtain information about the selection.</li>
<li>Close all objects when they are no longer needed.</li>
</ol>
The dataset with the region references was read by #H5Dread with the #H5T_STD_REF_DSETREG datatype specified.
The read reference can be used to obtain the dataset identifier by calling #H5Rdereference or by obtaining
2023-03-09 04:42:47 +08:00
obtain spatial information (dataspace and selection) with the call to #H5Rget_region.
2022-09-15 04:44:24 +08:00
The reference to the dataset region has information for both the dataset itself and its selection. In both functions:
\li The first parameter is an identifier of the dataset with the region references.
\li The second parameter specifies the type of reference stored. In this example, a reference to the dataset region is stored.
\li The third parameter is a buffer containing the reference of the specified type.
This example introduces several H5Sget_select_* functions used to obtain information about selections:
<table>
<caption>Examples of HDF5 predefined datatypes</caption>
<tr>
<th><strong>Function</strong></th>
<th><strong>Description</strong></th>
</tr>
<tr>
<td>#H5Sget_select_npoints</td>
<td>Returns the number of elements in the hyperslab</td>
</tr>
<tr>
<td>#H5Sget_select_hyper_nblocks</td>
<td>Returns the number of blocks in the hyperslab</td>
</tr>
<tr>
<td>#H5Sget_select_hyper_blocklist</td>
<td>Returns the "lower left" and "upper right" coordinates of the blocks in the hyperslab selection</td>
</tr>
<tr>
<td>#H5Sget_select_bounds</td>
<td>Returns the coordinates of the "minimal" block containing a hyperslab selection</td>
</tr>
<tr>
<td>#H5Sget_select_elem_npoints</td>
<td>Returns the number of points in the element selection</td>
</tr>
<tr>
<td>#H5Sget_select_elem_pointlist</td>
<td>Returns the coordinates of points in the element selection</td>
</tr>
</table>
\subsection subsecLBDtypeSpecStr String
A simple example of creating a derived datatype is using the string datatype,
#H5T_C_S1 (#H5T_FORTRAN_S1) to create strings of more than one character. Strings
can be stored as either fixed or variable length, and may have different rules
for padding of unused storage.
\subsubsection subsecLBDtypeSpecStrFix Fixed Length 5-character String Datatype
\code
hid_t strtype; /* Datatype ID */
herr_t status;
strtype = H5Tcopy (H5T_C_S1);
status = H5Tset_size (strtype, 5); /* create string of length 5 */
\endcode
\subsubsection subsecLBDtypeSpecStrVar Variable Length String Datatype
\code
strtype = H5Tcopy (H5T_C_S1);
status = H5Tset_size (strtype, H5T_VARIABLE);
\endcode
The ability to derive datatypes from pre-defined types allows users to create any number of datatypes,
from simple to very complex.
As the term implies, variable length strings are strings of varying lengths. They are stored internally
in a heap, potentially impacting efficiency in the following ways:
\li Heap storage requires more space than regular raw data storage.
\li Heap access generally reduces I/O efficiency because it requires individual read or write operations
for each data element rather than one read or write per dataset or per data selection.
\li A variable length dataset consists of pointers to the heaps of data, not the actual data. Chunking
and filters, including compression, are not available for heaps.
See \ref subsubsec_datatype_other_strings in the \ref UG, for more information on how fixed and variable
length strings are stored.
\subsection subsecLBDtypeSpecVL Variable Length
Variable-length (VL) datatypes are sequences of an existing datatype (atomic, VL, or compound)
which are not fixed in length from one dataset location to another. In essence, they are similar
to C character strings -- a sequence of a type which is pointed to by a particular type of
pointer -- although they are implemented more closely to FORTRAN strings by including an explicit
length in the pointer instead of using a particular value to terminate the sequence.
VL datatypes are useful to the scientific community in many different ways, some of which are listed below:
<ul>
<li>Ragged arrays: Multi-dimensional ragged arrays can be implemented with the last (fastest changing)
dimension being ragged by using a VL datatype as the type of the element stored. (Or as a field in a compound datatype.)
</li>
<li>Fractal arrays: If a compound datatype has a VL field of another compound type with VL fields
(a nested VL datatype), this can be used to implement ragged arrays of ragged arrays, to whatever
nesting depth is required for the user.
</li>
<li>Polygon lists: A common storage requirement is to efficiently store arrays of polygons with
different numbers of vertices. VL datatypes can be used to efficiently and succinctly describe an
array of polygons with different numbers of vertices.
</li>
<li>Character strings: Perhaps the most common use of VL datatypes will be to store C-like VL character
strings in dataset elements or as attributes of objects.
</li>
<li>Indices: An array of VL object references could be used as an index to all the objects in a file
which contain a particular sequence of dataset values. Perhaps an array something like the following:
\code
Value1: Object1, Object3, Object9
Value2: Object0, Object12, Object14, Object21, Object22
Value3: Object2
Value4: <none>
Value5: Object1, Object10, Object12
.
.
\endcode
</li>
<li>Object Tracking: An array of VL dataset region references can be used as a method of tracking
objects or features appearing in a sequence of datasets. Perhaps an array of them would look like:
\code
Feature1: Dataset1:Region, Dataset3:Region, Dataset9:Region
Feature2: Dataset0:Region, Dataset12:Region, Dataset14:Region,
Dataset21:Region, Dataset22:Region
Feature3: Dataset2:Region
Feature4: <none>
Feature5: Dataset1:Region, Dataset10:Region, Dataset12:Region
.
.
\endcode
</li>
</ul>
\subsubsection subsubsecLBDtypeSpecVLMem Variable-length datatype memory management
With each element possibly being of different sequence lengths for a dataset with a VL datatype,
the memory for the VL datatype must be dynamically allocated. Currently there are two methods
of managing the memory for VL datatypes: the standard C malloc/free memory allocation routines
or a method of calling user-defined memory management routines to allocate or free memory. Since
the memory allocated when reading (or writing) may be complicated to release, an HDF5 routine is
provided to traverse a memory buffer and free the VL datatype information without leaking memory.
\subsubsection subsubsecLBDtypeSpecVLDiv Variable-length datatypes cannot be divided
VL datatypes are designed so that they cannot be subdivided by the library with selections, etc.
This design was chosen due to the complexities in specifying selections on each VL element of a
dataset through a selection API that is easy to understand. Also, the selection APIs work on
dataspaces, not on datatypes. At some point in time, we may want to create a way for dataspaces
to have VL components to them and we would need to allow selections of those VL regions, but
that is beyond the scope of this document.
\subsubsection subsubsecLBDtypeSpecVLErr What happens if the library runs out of memory while reading?
It is possible for a call to #H5Dread to fail while reading in VL datatype information if the memory
required exceeds that which is available. In this case, the #H5Dread call will fail gracefully and any
VL data which has been allocated prior to the memory shortage will be returned to the system via the
memory management routines detailed below. It may be possible to design a partial read API function
at a later date, if demand for such a function warrants.
\subsubsection subsubsecLBDtypeSpecVLStr Strings as variable-length datatypes
Since character strings are a special case of VL data that is implemented in many different ways on
different machines and in different programming languages, they are handled somewhat differently from
other VL datatypes in HDF5.
HDF5 has native VL strings for each language API, which are stored the same way on disk, but are
exported through each language API in a natural way for that language. When retrieving VL strings
from a dataset, users may choose to have them stored in memory as a native VL string or in HDF5's
#hvl_t struct for VL datatypes.
VL strings may be created in one of two ways: by creating a VL datatype with a base type of
#H5T_C_S1 and setting its length to #H5T_VARIABLE. The second method is used to access native VL strings in memory. The
library will convert between the two types, but they are stored on disk using different datatypes
and have different memory representations.
Multi-byte character representations, such as \em UNICODE or \em wide characters in C/C++, will need the
appropriate character and string datatypes created so that they can be described properly through
the datatype API. Additional conversions between these types and the current ASCII characters
will also be required.
Variable-width character strings (which might be compressed data or some other encoding) are not
currently handled by this design. We will evaluate how to implement them based on user feedback.
\subsubsection subsubsecLBDtypeSpecVLAPIs Variable-length datatype APIs
<h4>Creation</h4>
VL datatypes are created with the #H5Tvlen_create function as follows:
\code
type_id = H5Tvlen_create(hid_t base_type_id);
\endcode
The base datatype will be the datatype that the sequence is composed of, characters for character
strings, vertex coordinates for polygon lists, etc. The base datatype specified for the VL datatype
can be of any HDF5 datatype, including another VL datatype, a compound datatype, or an atomic datatype.
<h4>Querying base datatype of VL datatype</h4>
It may be necessary to know the base datatype of a VL datatype before memory is allocated, etc.
The base datatype is queried with the #H5Tget_super function, described in the \ref H5T documentation.
<h4>Querying minimum memory required for VL information</h4>
It order to predict the memory usage that #H5Dread may need to allocate to store VL data while
reading the data, the #H5Dvlen_get_buf_size function is provided:
\code
herr_t H5Dvlen_get_buf_size(hid_t dataset_id, hid_t type_id, hid_t space_id, hsize_t *size)
\endcode
This routine checks the number of bytes required to store the VL data from the dataset, using
the \em space_id for the selection in the dataset on disk and the \em type_id for the memory representation
of the VL data in memory. The *\em size value is modified according to how many bytes are required
to store the VL data in memory.
<h4>Specifying how to manage memory for the VL datatype</h4>
The memory management method is determined by dataset transfer properties passed into the
#H5Dread and #H5Dwrite functions with the dataset transfer property list.
Default memory management is set by using #H5P_DEFAULT for the dataset transfer
property list identifier. If #H5P_DEFAULT is used with #H5Dread, the system \em malloc and \em free
calls will be used for allocating and freeing memory. In such a case, #H5P_DEFAULT should
also be passed as the property list identifier to #H5Dvlen_reclaim.
The rest of this subsection is relevant only to those who choose not to use default memory management.
The user can choose whether to use the system \em malloc and \em free calls or user-defined, or custom,
memory management functions. If user-defined memory management functions are to be used, the
memory allocation and free routines must be defined via #H5Pset_vlen_mem_manager(), as follows:
\code
herr_t H5Pset_vlen_mem_manager(hid_t plist_id, H5MM_allocate_t alloc, void *alloc_info, H5MM_free_t free, void *free_info)
\endcode
The \em alloc and \em free parameters identify the memory management routines to be used. If the user
has defined custom memory management routines, \em alloc and/or \em free should be set to make those
routine calls (i.e., the name of the routine is used as the value of the parameter); if the user
prefers to use the system's \em malloc and/or \em free, the \em alloc and \em free parameters, respectively, should be set to \em NULL
The prototypes for the user-defined functions would appear as follows:
\code
typedef void *(*H5MM_allocate_t)(size_t size, void *info) ; typedef void (*H5MM_free_t)(void *mem, void *free_info) ;
\endcode
The \em alloc_info and \em free_info parameters can be used to pass along any required information to
the user's memory management routines.
In summary, if the user has defined custom memory management routines, the name(s) of the routines
are passed in the \em alloc and \em free parameters and the custom routines' parameters are passed in the
\em alloc_info and \em free_info parameters. If the user wishes to use the system \em malloc and \em free functions,
the \em alloc and/or \em free parameters are set to \em NULL and the \em alloc_info and \em free_info parameters are ignored.
<h4>Recovering memory from VL buffers read in</h4>
The complex memory buffers created for a VL datatype may be reclaimed with the #H5Dvlen_reclaim
function call, as follows:
\code
herr_t H5Dvlen_reclaim(hid_t type_id, hid_t space_id, hid_t plist_id, void *buf);
\endcode
The \em type_id must be the datatype stored in the buffer, \em space_id describes the selection for the
memory buffer to free the VL datatypes within, \em plist_id is the dataset transfer property list
which was used for the I/O transfer to create the buffer, and \em buf is the pointer to the buffer
to free the VL memory within. The VL structures (#hvl_t) in the user's buffer are modified to zero
out the VL information after it has been freed.
If nested VL datatypes were used to create the buffer, this routine frees them from the bottom up,
releasing all the memory without creating memory leaks.
<hr>
Navigate back: \ref index "Main" / \ref GettingStarted / \ref LearnBasics
*/