Skip to content

Commit

Permalink
Implement support for complex number datatypes (HDFGroup#4630)
Browse files Browse the repository at this point in the history
* Implement support for complex number datatypes

Adds the new datatype class H5T_COMPLEX

Adds the new API function H5Tcomplex_create which creates a complex
number datatype from an ID of a base floating-point datatype

Adds the new feature check macros H5_HAVE_COMPLEX_NUMBERS and
H5_HAVE_C99_COMPLEX_NUMBERS

Adds the new datatype size macros H5_SIZEOF_FLOAT_COMPLEX,
H5_SIZEOF_DOUBLE_COMPLEX and H5_SIZEOF_LONG_DOUBLE_COMPLEX

Adds the new datatype ID macros H5T_NATIVE_FLOAT_COMPLEX,
H5T_NATIVE_DOUBLE_COMPLEX, H5T_NATIVE_LDOUBLE_COMPLEX,
H5T_CPLX_IEEE_F16LE, H5T_CPLX_IEEE_F16BE,
H5T_CPLX_IEEE_F32LE, H5T_CPLX_IEEE_F32BE,
H5T_CPLX_IEEE_F64LE and H5T_CPLX_IEEE_F64BE

Adds hard and soft datatype conversion paths between complex number
datatypes and all the integer and floating-point datatypes, as well as
between other complex number datatypes

Adds a special conversion path between complex number datatypes and
array or compound datatypes where the in-memory layout of data is the
same between the datatypes and data can be converted directly

Adds support for complex number datatypes to the h5dump, h5ls and
h5diff/ph5diff tools. Allows h5dump '-m' option to change floating-point
printing format for float complex and double complex datatypes, as well
as long double complex if it has the same size as double complex

Adds minimal support to the h5watch and h5import tools

Adds support for the predefined complex number datatypes and
H5Tcomplex_create function to the Java wrappers. Also adds initial,
untested support to the JNI for future use with HDFView

Adds support for just the H5T_COMPLEX datatype class to the Fortran
wrappers

Adds support for the predefined complex number datatypes and
H5Tcomplex_create function to the high level library H5LT interface
for use with the H5LTtext_to_dtype and H5LTdtype_to_text functions

Changes some usages of "complex" in the library since it conflicts with
the "complex" keyword from the complex.h header. Also changes various
usages of the word "complex" throughout the library to distinguish
compound datatypes from complex datatypes.
  • Loading branch information
jhendersonHDF authored and brtnfld committed Nov 4, 2024
1 parent 0b7d658 commit a179e17
Show file tree
Hide file tree
Showing 14 changed files with 393 additions and 93 deletions.
12 changes: 6 additions & 6 deletions HDF5Examples/C/H5T/200/h5ex_t_complex.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@
#include <stdlib.h>
#include <complex.h>

#define FILENAME "h5ex_t_complex.h5"
#define DATASET "DS1"
#define DIM0 4
#define DIM1 7
#define FILE "h5ex_t_complex.h5"
#define DATASET "DS1"
#define DIM0 4
#define DIM1 7

int
main(void)
Expand All @@ -45,7 +45,7 @@ main(void)
/*
* Create a new file using the default properties.
*/
file = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
file = H5Fcreate(FILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);

/*
* Create dataspace. Setting maximum size to NULL sets the maximum
Expand Down Expand Up @@ -80,7 +80,7 @@ main(void)
/*
* Open file and dataset.
*/
file = H5Fopen(FILENAME, H5F_ACC_RDONLY, H5P_DEFAULT);
file = H5Fopen(FILE, H5F_ACC_RDONLY, H5P_DEFAULT);
dset = H5Dopen(file, DATASET, H5P_DEFAULT);

/*
Expand Down
12 changes: 6 additions & 6 deletions HDF5Examples/C/H5T/200/h5ex_t_complex_custom.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@
#include <stdlib.h>
#include <complex.h>

#define FILENAME "h5ex_t_complex_custom.h5"
#define DATASET "DS1"
#define DIM0 4
#define DIM1 7
#define FILE "h5ex_t_complex_custom.h5"
#define DATASET "DS1"
#define DIM0 4
#define DIM1 7

int
main(void)
Expand All @@ -45,7 +45,7 @@ main(void)
/*
* Create a new file using the default properties.
*/
file = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
file = H5Fcreate(FILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);

/*
* Create dataspace. Setting maximum size to NULL sets the maximum
Expand Down Expand Up @@ -87,7 +87,7 @@ main(void)
/*
* Open file and dataset.
*/
file = H5Fopen(FILENAME, H5F_ACC_RDONLY, H5P_DEFAULT);
file = H5Fopen(FILE, H5F_ACC_RDONLY, H5P_DEFAULT);
dset = H5Dopen(file, DATASET, H5P_DEFAULT);

/*
Expand Down
12 changes: 6 additions & 6 deletions HDF5Examples/C/H5T/200/h5ex_t_complex_msvc.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@
#include <stdlib.h>
#include <complex.h>

#define FILENAME "h5ex_t_complex_msvc.h5"
#define DATASET "DS1"
#define DIM0 4
#define DIM1 7
#define FILE "h5ex_t_complex_msvc.h5"
#define DATASET "DS1"
#define DIM0 4
#define DIM1 7

int
main(void)
Expand All @@ -46,7 +46,7 @@ main(void)
/*
* Create a new file using the default properties.
*/
file = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
file = H5Fcreate(FILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);

/*
* Create dataspace. Setting maximum size to NULL sets the maximum
Expand Down Expand Up @@ -81,7 +81,7 @@ main(void)
/*
* Open file and dataset.
*/
file = H5Fopen(FILENAME, H5F_ACC_RDONLY, H5P_DEFAULT);
file = H5Fopen(FILE, H5F_ACC_RDONLY, H5P_DEFAULT);
dset = H5Dopen(file, DATASET, H5P_DEFAULT);

/*
Expand Down
34 changes: 22 additions & 12 deletions hl/tools/h5watch/h5watch.c
Original file line number Diff line number Diff line change
Expand Up @@ -94,17 +94,21 @@ static struct h5_long_options l_opts[] = {{"help", no_arg, 'h'}, {"hel",
static herr_t
doprint(hid_t did, const hsize_t *start, const hsize_t *block, int rank)
{
h5tools_context_t ctx; /* print context */
h5tool_format_t info; /* Format info for the tools library */
static char fmt_ldouble[16]; /* Format info */
static char fmt_double[16], fmt_float[16]; /* Format info */
struct subset_t subset; /* Subsetting info */
hsize_t ss_start[H5S_MAX_RANK]; /* Info for hyperslab */
hsize_t ss_stride[H5S_MAX_RANK]; /* Info for hyperslab */
hsize_t ss_block[H5S_MAX_RANK]; /* Info for hyperslab */
hsize_t ss_count[H5S_MAX_RANK]; /* Info for hyperslab */
int i; /* Local index variable */
herr_t ret_value = SUCCEED; /* Return value */
h5tools_context_t ctx; /* print context */
h5tool_format_t info; /* Format info for the tools library */
static char fmt_ldouble[16]; /* Format info */
static char fmt_double[16]; /* Format info */
static char fmt_float[16]; /* Format info */
static char fmt_ldouble_complex[32]; /* Format info */
static char fmt_double_complex[32]; /* Format info */
static char fmt_float_complex[16]; /* Format info */
struct subset_t subset; /* Subsetting info */
hsize_t ss_start[H5S_MAX_RANK]; /* Info for hyperslab */
hsize_t ss_stride[H5S_MAX_RANK]; /* Info for hyperslab */
hsize_t ss_block[H5S_MAX_RANK]; /* Info for hyperslab */
hsize_t ss_count[H5S_MAX_RANK]; /* Info for hyperslab */
int i; /* Local index variable */
herr_t ret_value = SUCCEED; /* Return value */

/* Subsetting information for the tools library printing routines */
subset.start.data = ss_start;
Expand Down Expand Up @@ -176,8 +180,14 @@ doprint(hid_t did, const hsize_t *start, const hsize_t *block, int rank)
info.fmt_float = fmt_float;
snprintf(fmt_double, sizeof(fmt_double), "%%1.%dg", DBL_DIG);
info.fmt_double = fmt_double;
snprintf(fmt_ldouble, sizeof(fmt_ldouble), "%%1.%dLg", DBL_DIG);
snprintf(fmt_ldouble, sizeof(fmt_ldouble), "%%1.%dLg", LDBL_DIG);
info.fmt_ldouble = fmt_ldouble;
snprintf(fmt_float_complex, sizeof(fmt_float_complex), "%%1.%dg%%+1.%dgi", FLT_DIG, FLT_DIG);
info.fmt_float_complex = fmt_float_complex;
snprintf(fmt_double_complex, sizeof(fmt_double_complex), "%%1.%dg%%+1.%dgi", DBL_DIG, DBL_DIG);
info.fmt_double_complex = fmt_double_complex;
snprintf(fmt_ldouble_complex, sizeof(fmt_ldouble_complex), "%%1.%dLg%%+1.%dLgi", LDBL_DIG, LDBL_DIG);
info.fmt_ldouble_complex = fmt_ldouble_complex;

info.dset_format = "DSET-%s ";
info.dset_hidefileno = 0;
Expand Down
194 changes: 194 additions & 0 deletions release_docs/RELEASE.txt
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,200 @@ New Features

Library:
--------
- Added support for complex number datatypes

Support for the C99 "float _Complex", "double _Complex" and "long double _Complex"
(with MSVC, "_Fcomplex", "_Dcomplex" and "_Lcomplex") types has been added for
platforms/compilers that support them. These types have been implemented with a
new datatype class, H5T_COMPLEX. Note that any datatypes of class H5T_COMPLEX
will not be readable with previous versions of HDF5. If a file is accessed with
a library version bounds "high" setting less than H5F_LIBVER_V200, an error will
occur if the application tries to create an object with a complex number datatype.
If compatibility with previous versions of HDF5 is desired, applications should
instead consider adopting one of the existing conventions at
https://nc-complex.readthedocs.io/en/latest/#conventions-used-in-applications.

The following new macros have been added:

- H5_HAVE_COMPLEX_NUMBERS

This macro is defined in H5pubconf.h and will have the value 1 if native
support for complex numbers is available. It will not be defined otherwise.

- H5_HAVE_C99_COMPLEX_NUMBERS

This macro is defined in H5pubconf.h and will have the value 1 if native
support for C99 complex numbers is available. It will not be defined otherwise.
If this macro is not defined but H5_HAVE_COMPLEX_NUMBERS is defined, the
complex number types supported are the MSVC types.

- H5_SIZEOF_FLOAT_COMPLEX

This macro is defined in H5pubconf.h and will have a value corresponding
to the size of the native float complex datatype, as computed by sizeof().
If C99 complex number support is available, this will be the size of the
"float _Complex" type. Otherwise, it will be the size of the "_Fcomplex"
type. It will have the value 0 if support for a native float complex datatype
is not available.

- H5_SIZEOF_DOUBLE_COMPLEX

This macro is defined in H5pubconf.h and will have a value corresponding
to the size of the native double complex datatype, as computed by sizeof().
If C99 complex number support is available, this will be the size of the
"double _Complex" type. Otherwise, it will be the size of the "_Dcomplex"
type. It will have the value 0 if support for a native double complex datatype
is not available.

- H5_SIZEOF_LONG_DOUBLE_COMPLEX

This macro is defined in H5pubconf.h and will have a value corresponding
to the size of the native long double complex datatype, as computed by sizeof().
If C99 complex number support is available, this will be the size of the
"long double _Complex" type. Otherwise, it will be the size of the "_Lcomplex"
type. It will have the value 0 if support for a native long double complex
datatype is not available.

- H5T_NATIVE_FLOAT_COMPLEX

This macro maps to the ID of an HDF5 datatype representing the native C
float complex datatype (either "float _Complex" or "_Fcomplex") for the
platform. If support for a native float complex datatype is not available
(H5_HAVE_COMPLEX_NUMBERS is not defined), the macro will map to
H5I_INVALID_HID and should not be used.

- H5T_NATIVE_DOUBLE_COMPLEX

This macro maps to the ID of an HDF5 datatype representing the native C
double complex datatype (either "double _Complex" or "_Dcomplex") for the
platform. If support for a native double complex datatype is not available
(H5_HAVE_COMPLEX_NUMBERS is not defined), the macro will map to
H5I_INVALID_HID and should not be used.

- H5T_NATIVE_LDOUBLE_COMPLEX

This macro maps to the ID of an HDF5 datatype representing the native C
long double complex datatype (either "long double _Complex" or "_Lcomplex")
for the platform. If support for a native long double complex datatype is
not available (H5_HAVE_COMPLEX_NUMBERS is not defined), the macro will map
to H5I_INVALID_HID and should not be used.

- H5T_COMPLEX_IEEE_F16LE / H5T_COMPLEX_IEEE_F16BE

These macros map to IDs of HDF5 datatypes representing a complex number of
two parts, each of which is an IEEE 754 16-bit floating-point datatype in
little- or big-endian order. These datatypes are available regardless of
whether complex number support is available or not.

- H5T_COMPLEX_IEEE_F32LE / H5T_COMPLEX_IEEE_F32BE

These macros map to IDs of HDF5 datatypes representing a complex number of
two parts, each of which is an IEEE 754 32-bit floating-point datatype in
little- or big-endian order. These datatypes are available regardless of
whether complex number support is available or not.

- H5T_COMPLEX_IEEE_F64LE / H5T_COMPLEX_IEEE_F64BE

These macros map to IDs of HDF5 datatypes representing a complex number of
two parts, each of which is an IEEE 754 64-bit floating-point datatype in
little- or big-endian order. These datatypes are available regardless of
whether complex number support is available or not.

The following new API function has been added:

hid_t H5Tcomplex_create(hid_t base_type_id);

Creates a new complex number datatype from the base datatype specified
by the given HDF5 ID `base_type_id`. The base datatype must be a
floating-point datatype.

The following new hard datatype conversion paths have been added, but
will only be used when complex number support is available:

H5T_NATIVE_SCHAR <-> H5T_NATIVE_FLOAT_COMPLEX | H5T_NATIVE_UCHAR <-> H5T_NATIVE_FLOAT_COMPLEX
H5T_NATIVE_SHORT <-> H5T_NATIVE_FLOAT_COMPLEX | H5T_NATIVE_USHORT <-> H5T_NATIVE_FLOAT_COMPLEX
H5T_NATIVE_INT <-> H5T_NATIVE_FLOAT_COMPLEX | H5T_NATIVE_UINT <-> H5T_NATIVE_FLOAT_COMPLEX
H5T_NATIVE_LONG <-> H5T_NATIVE_FLOAT_COMPLEX | H5T_NATIVE_ULONG <-> H5T_NATIVE_FLOAT_COMPLEX
H5T_NATIVE_LLONG <-> H5T_NATIVE_FLOAT_COMPLEX | H5T_NATIVE_ULLONG <-> H5T_NATIVE_FLOAT_COMPLEX
H5T_NATIVE_FLOAT16 <-> H5T_NATIVE_FLOAT_COMPLEX | H5T_NATIVE_FLOAT <-> H5T_NATIVE_FLOAT_COMPLEX
H5T_NATIVE_DOUBLE <-> H5T_NATIVE_FLOAT_COMPLEX | H5T_NATIVE_LDOUBLE <-> H5T_NATIVE_FLOAT_COMPLEX

H5T_NATIVE_SCHAR <-> H5T_NATIVE_DOUBLE_COMPLEX | H5T_NATIVE_UCHAR <-> H5T_NATIVE_DOUBLE_COMPLEX
H5T_NATIVE_SHORT <-> H5T_NATIVE_DOUBLE_COMPLEX | H5T_NATIVE_USHORT <-> H5T_NATIVE_DOUBLE_COMPLEX
H5T_NATIVE_INT <-> H5T_NATIVE_DOUBLE_COMPLEX | H5T_NATIVE_UINT <-> H5T_NATIVE_DOUBLE_COMPLEX
H5T_NATIVE_LONG <-> H5T_NATIVE_DOUBLE_COMPLEX | H5T_NATIVE_ULONG <-> H5T_NATIVE_DOUBLE_COMPLEX
H5T_NATIVE_LLONG <-> H5T_NATIVE_DOUBLE_COMPLEX | H5T_NATIVE_ULLONG <-> H5T_NATIVE_DOUBLE_COMPLEX
H5T_NATIVE_FLOAT16 <-> H5T_NATIVE_DOUBLE_COMPLEX | H5T_NATIVE_FLOAT <-> H5T_NATIVE_DOUBLE_COMPLEX
H5T_NATIVE_DOUBLE <-> H5T_NATIVE_DOUBLE_COMPLEX | H5T_NATIVE_LDOUBLE <-> H5T_NATIVE_DOUBLE_COMPLEX

H5T_NATIVE_SCHAR <-> H5T_NATIVE_LDOUBLE_COMPLEX | H5T_NATIVE_UCHAR <-> H5T_NATIVE_LDOUBLE_COMPLEX
H5T_NATIVE_SHORT <-> H5T_NATIVE_LDOUBLE_COMPLEX | H5T_NATIVE_USHORT <-> H5T_NATIVE_LDOUBLE_COMPLEX
H5T_NATIVE_INT <-> H5T_NATIVE_LDOUBLE_COMPLEX | H5T_NATIVE_UINT <-> H5T_NATIVE_LDOUBLE_COMPLEX
H5T_NATIVE_LONG <-> H5T_NATIVE_LDOUBLE_COMPLEX | H5T_NATIVE_ULONG <-> H5T_NATIVE_LDOUBLE_COMPLEX
H5T_NATIVE_LLONG <-> H5T_NATIVE_LDOUBLE_COMPLEX | H5T_NATIVE_ULLONG <-> H5T_NATIVE_LDOUBLE_COMPLEX
H5T_NATIVE_FLOAT16 <-> H5T_NATIVE_LDOUBLE_COMPLEX | H5T_NATIVE_FLOAT <-> H5T_NATIVE_LDOUBLE_COMPLEX
H5T_NATIVE_DOUBLE <-> H5T_NATIVE_LDOUBLE_COMPLEX | H5T_NATIVE_LDOUBLE <-> H5T_NATIVE_LDOUBLE_COMPLEX

H5T_NATIVE_FLOAT_COMPLEX <-> H5T_NATIVE_DOUBLE_COMPLEX
H5T_NATIVE_FLOAT_COMPLEX <-> H5T_NATIVE_LDOUBLE_COMPLEX
H5T_NATIVE_DOUBLE_COMPLEX <-> H5T_NATIVE_LDOUBLE_COMPLEX

Alternative software implementation conversion paths have been added for all of
the above for use when native complex number support is not available. All of these
conversion paths follow the behavior outlined in the C standard for conversions of
complex number values.

Additionally, a special datatype conversion path has been added between complex number
datatypes and array or compound datatypes where the in-memory layout of data is the
same between the datatypes and data can be directly converted. This conversion path
is subject to the following rules:

- An array datatype must consist of exactly two elements where each element is of
the same floating-point datatype as the complex number datatype's base floating-point
datatype.

- A compound datatype must consist of exactly two fields where each field is of the
same floating-point datatype as the complex number datatype's base floating-point
datatype. The compound datatype must not have any leading or trailing structure
padding or any padding between its two fields. The fields must also have compatible
names, must have compatible offsets within the datatype and must be in the order
of "real" part -> "imaginary" part, such that the compound datatype matches the
following representation:

H5T_COMPOUND {
<float_type> "r(e)(a)(l)"; OFFSET 0
<float_type> "i(m)(a)(g)(i)(n)(a)(r)(y)"; OFFSET SIZEOF("r(e)(a)(l)")
}

where "r(e)(a)(l)" means the field may be named any substring of "real", such as
"r", or "re" and "i(m)(a)(g)(i)(n)(a)(r)(y)" means the field may be named any
substring of "imaginary", such as "im" or "imag".

Support for complex numbers has been added to the h5dump, h5ls and h5diff/ph5diff
tools. The h5dump command-line option '-m' can be used to change the floating-point
printing format for the float complex and double complex datatypes, as well as
the long double complex datatype if it has the same size as a double complex
datatype.

Support for the predefined complex number datatypes and the H5Tcomplex_create
function has been added to the Java wrappers. However, Java does not have
official types for complex numbers, so an application must be sure that
data is in an appropriate format in-memory when using these datatypes.

Support for the Fortran wrappers has not yet been added.

Support for the predefined complex number datatypes and the H5Tcomplex_create
function has been added to the high level library, allowing them to work
with the H5LTtext_to_dtype and H5LTdtype_to_text functions.

Simple example programs showing how to use complex number datatypes have
been added in the following files:

- HDF5Examples/C/H5T/200/h5ex_t_complex.c (Uses C99 complex number types)
- HDF5Examples/C/H5T/200/h5ex_t_complex_msvc.c (Uses MSVC complex number types)
- HDF5Examples/C/H5T/200/h5ex_t_complex_custom.c (Uses H5Tcomplex_create to create
a custom complex number type)

- The H5VLstart_lib_state / H5VLfinish_lib_state API routines for pass-
through connector authors now require a parameter that can be used to
store the library's context.
Expand Down
2 changes: 1 addition & 1 deletion src/H5T.c
Original file line number Diff line number Diff line change
Expand Up @@ -636,7 +636,7 @@ const unsigned H5O_dtype_ver_bounds[] = {
H5O_DTYPE_VERSION_3, /* H5F_LIBVER_V110 */
H5O_DTYPE_VERSION_4, /* H5F_LIBVER_V112 */
H5O_DTYPE_VERSION_4, /* H5F_LIBVER_V114 */
H5O_DTYPE_VERSION_4, /* H5F_LIBVER_V200 */
H5O_DTYPE_VERSION_5, /* H5F_LIBVER_V200 */
H5O_DTYPE_VERSION_LATEST /* H5F_LIBVER_LATEST */
};

Expand Down
9 changes: 2 additions & 7 deletions tools/lib/h5tools.h
Original file line number Diff line number Diff line change
Expand Up @@ -269,11 +269,8 @@ typedef struct h5tool_format_t {
* typed `unsigned long long'. The default depends on what
* printf() format is available to print this datatype.
*
* fmt_ldouble: The printf() format to use when rendering data which is
* typed `long double'. The default is `%Lg'.
*
* fmt_double: The printf() format to use when rendering data which is
* typed `double'. The default is `%g'.
* fmt_float: The printf() format to use when rendering data which is
* typed `float'. The default is `%g'.
*
* fmt_double: The printf() format to use when rendering data which is
* typed `double'. The default is `%g'.
Expand Down Expand Up @@ -323,8 +320,6 @@ typedef struct h5tool_format_t {
const char *fmt_ulong;
const char *fmt_llong;
const char *fmt_ullong;
const char *fmt_ldouble;
const char *fmt_double;
const char *fmt_float;
const char *fmt_double;
const char *fmt_ldouble;
Expand Down
Loading

0 comments on commit a179e17

Please sign in to comment.