Skip to content

Commit

Permalink
Implement support for complex number datatypes
Browse files Browse the repository at this point in the history
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 committed Jul 3, 2024
1 parent 773831f commit 1b1e812
Show file tree
Hide file tree
Showing 137 changed files with 23,996 additions and 4,898 deletions.
3 changes: 2 additions & 1 deletion HDF5Examples/JAVA/H5T/H5Ex_T_Commit.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ enum H5T_class {
H5T_ENUM(HDF5Constants.H5T_ENUM), // enumeration types
H5T_VLEN(HDF5Constants.H5T_VLEN), // Variable-Length types
H5T_ARRAY(HDF5Constants.H5T_ARRAY), // Array types
H5T_NCLASSES(11); // this must be last
H5T_COMPLEX(HDF5Constants.H5T_COMPLEX), // Complex number types
H5T_NCLASSES(12); // this must be last

private static final Map<Long, H5T_class> lookup = new HashMap<Long, H5T_class>();

Expand Down
8 changes: 4 additions & 4 deletions c++/test/tattr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -632,7 +632,7 @@ test_attr_compound_write(FileAccPropList &fapl)
hsize_t dims2[] = {ATTR4_DIM1, ATTR4_DIM2};
DataSpace sid2(ATTR4_RANK, dims2);

// Create complex attribute for the dataset
// Create compound attribute for the dataset
Attribute attr = dataset.createAttribute(ATTR4_NAME, comp_type, sid2);

// Try to create the same attribute again (should fail)
Expand All @@ -643,7 +643,7 @@ test_attr_compound_write(FileAccPropList &fapl)
{
} // do nothing, exception expected

// Write complex attribute data
// Write compound attribute data
attr.write(comp_type, attr_data4);

PASSED();
Expand Down Expand Up @@ -2001,8 +2001,8 @@ test_attr()
test_attr_rename(curr_fapl); // Test renaming attribute
test_attr_basic_read(curr_fapl); // Test basic H5A reading code

test_attr_compound_write(curr_fapl); // Test complex datatype H5A writing code
test_attr_compound_read(curr_fapl); // Test complex datatype H5A reading code
test_attr_compound_write(curr_fapl); // Test compound datatype H5A writing code
test_attr_compound_read(curr_fapl); // Test compound datatype H5A reading code

test_attr_scalar_write(curr_fapl); // Test scalar dataspace H5A writing code
test_attr_scalar_read(curr_fapl); // Test scalar dataspace H5A reading code
Expand Down
66 changes: 66 additions & 0 deletions config/cmake/ConfigureChecks.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ include (CheckTypeSize)
include (CheckVariableExists)
include (TestBigEndian)
include (CheckStructHasMember)
include (CMakePushCheckState)

set (HDF_PREFIX "H5")

Expand Down Expand Up @@ -816,6 +817,71 @@ macro (H5ConversionTests TEST def msg)
endif ()
endmacro ()

#-----------------------------------------------------------------------------
# Check for complex number support
#-----------------------------------------------------------------------------
message (STATUS "Checking if complex number support is available")
CHECK_INCLUDE_FILE (complex.h ${HDF_PREFIX}_HAVE_COMPLEX_H)
if (${HDF_PREFIX}_HAVE_COMPLEX_H)
set (H5_HAVE_C99_COMPLEX_NUMBERS 1)

HDF_CHECK_TYPE_SIZE ("float _Complex" ${HDF_PREFIX}_SIZEOF_FLOAT_COMPLEX)
HDF_CHECK_TYPE_SIZE ("double _Complex" ${HDF_PREFIX}_SIZEOF_DOUBLE_COMPLEX)
HDF_CHECK_TYPE_SIZE ("long double _Complex" ${HDF_PREFIX}_SIZEOF_LONG_DOUBLE_COMPLEX)

if (MSVC AND NOT ${HDF_PREFIX}_SIZEOF_FLOAT_COMPLEX AND NOT ${HDF_PREFIX}_SIZEOF_DOUBLE_COMPLEX
AND NOT ${HDF_PREFIX}_SIZEOF_LONG_DOUBLE_COMPLEX)
# If using MSVC, the _Complex types (if available) are _Fcomplex, _Dcomplex and _Lcomplex.
# The standard types are checked for first in case MSVC uses them in the future or in case
# the compiler used is simulating MSVC and uses the standard types.
cmake_push_check_state()
list (APPEND CMAKE_EXTRA_INCLUDE_FILES complex.h)
HDF_CHECK_TYPE_SIZE ("_Fcomplex" ${HDF_PREFIX}_SIZEOF__FCOMPLEX)
HDF_CHECK_TYPE_SIZE ("_Dcomplex" ${HDF_PREFIX}_SIZEOF__DCOMPLEX)
HDF_CHECK_TYPE_SIZE ("_Lcomplex" ${HDF_PREFIX}_SIZEOF__LCOMPLEX)
cmake_pop_check_state()
if (${HDF_PREFIX}_SIZEOF__FCOMPLEX AND ${HDF_PREFIX}_SIZEOF__DCOMPLEX AND
${HDF_PREFIX}_SIZEOF__FCOMPLEX)
set (${HDF_PREFIX}_SIZEOF_FLOAT_COMPLEX ${${HDF_PREFIX}_SIZEOF__FCOMPLEX}
CACHE INTERNAL "SizeOf for float _Complex" FORCE)
set (${HDF_PREFIX}_SIZEOF_DOUBLE_COMPLEX ${${HDF_PREFIX}_SIZEOF__DCOMPLEX}
CACHE INTERNAL "SizeOf for double _Complex" FORCE)
set (${HDF_PREFIX}_SIZEOF_LONG_DOUBLE_COMPLEX ${${HDF_PREFIX}_SIZEOF__LCOMPLEX}
CACHE INTERNAL "SizeOf for long double _Complex" FORCE)

unset (H5_HAVE_C99_COMPLEX_NUMBERS)
endif ()
endif ()

if (${HDF_PREFIX}_SIZEOF_FLOAT_COMPLEX AND ${HDF_PREFIX}_SIZEOF_DOUBLE_COMPLEX AND
${HDF_PREFIX}_SIZEOF_LONG_DOUBLE_COMPLEX)
# Check if __STDC_NO_COMPLEX__ macro is defined, in which case complex number
# support is not available
HDF_FUNCTION_TEST (HAVE_STDC_NO_COMPLEX)

if (NOT H5_HAVE_STDC_NO_COMPLEX)
# Compile simple test program with complex numbers
HDF_FUNCTION_TEST (HAVE_COMPLEX_NUMBERS)

if (H5_HAVE_COMPLEX_NUMBERS)
if (H5_HAVE_C99_COMPLEX_NUMBERS)
message (STATUS "Using C99 complex number types")
else ()
message (STATUS "Using MSVC complex number types")
endif ()
else ()
message (STATUS "Complex number support has been disabled since a simple test program couldn't be compiled and linked")
endif ()
else ()
message (STATUS "Complex number support has been disabled since __STDC_NO_COMPLEX__ is defined")
endif ()
else ()
message (STATUS "Complex number support has been disabled since the C types were not found")
endif ()
else ()
message (STATUS "Complex number support has been disabled since the complex.h header was not found")
endif ()

#-----------------------------------------------------------------------------
# Check various conversion capabilities
#-----------------------------------------------------------------------------
Expand Down
18 changes: 18 additions & 0 deletions config/cmake/H5pubconf.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -104,12 +104,18 @@
/* Define if the __attribute__(()) extension is present */
#cmakedefine H5_HAVE_ATTRIBUTE @H5_HAVE_ATTRIBUTE@

/* Define if C99 complex number types are present */
#cmakedefine H5_HAVE_C99_COMPLEX_NUMBERS @H5_HAVE_C99_COMPLEX_NUMBERS@

/* Define to 1 if you have the `clock_gettime' function. */
#cmakedefine H5_HAVE_CLOCK_GETTIME @H5_HAVE_CLOCK_GETTIME@

/* Define to 1 if CLOCK_MONOTONIC_COARSE is available */
#cmakedefine H5_HAVE_CLOCK_MONOTONIC_COARSE @H5_HAVE_CLOCK_MONOTONIC_COARSE@

/* Define if complex number support is available */
#cmakedefine H5_HAVE_COMPLEX_NUMBERS @H5_HAVE_COMPLEX_NUMBERS@

/* Define to 1 if you have the <curl/curl.h> header file. */
#cmakedefine H5_HAVE_CURL_CURL_H @H5_HAVE_CURL_H@

Expand Down Expand Up @@ -445,9 +451,15 @@
/* The size of `double', as computed by sizeof. */
#cmakedefine H5_SIZEOF_DOUBLE @H5_SIZEOF_DOUBLE@

/* The size of `double _Complex', as computed by sizeof. */
#cmakedefine H5_SIZEOF_DOUBLE_COMPLEX @H5_SIZEOF_DOUBLE_COMPLEX@

/* The size of `float', as computed by sizeof. */
#cmakedefine H5_SIZEOF_FLOAT @H5_SIZEOF_FLOAT@

/* The size of `float _Complex', as computed by sizeof. */
#cmakedefine H5_SIZEOF_FLOAT_COMPLEX @H5_SIZEOF_FLOAT_COMPLEX@

/* The size of `int', as computed by sizeof. */
#cmakedefine H5_SIZEOF_INT @H5_SIZEOF_INT@

Expand Down Expand Up @@ -501,6 +513,9 @@
/* The size of `long double', as computed by sizeof. */
#cmakedefine H5_SIZEOF_LONG_DOUBLE @H5_SIZEOF_LONG_DOUBLE@

/* The size of `long double _Complex', as computed by sizeof. */
#cmakedefine H5_SIZEOF_LONG_DOUBLE_COMPLEX @H5_SIZEOF_LONG_DOUBLE_COMPLEX@

#else

/* On Apple, to support Universal Binaries (where multiple CPU
Expand All @@ -520,10 +535,13 @@

# if defined(__i386__) || defined(__x86_64__)
#define H5_SIZEOF_LONG_DOUBLE 16
#define H5_SIZEOF_LONG_DOUBLE_COMPLEX 32
# elif defined(__aarch64__)
#define H5_SIZEOF_LONG_DOUBLE 8
#define H5_SIZEOF_LONG_DOUBLE_COMPLEX 16
# else
#cmakedefine H5_SIZEOF_LONG_DOUBLE @H5_SIZEOF_LONG_DOUBLE@
#cmakedefine H5_SIZEOF_LONG_DOUBLE_COMPLEX @H5_SIZEOF_LONG_DOUBLE_COMPLEX@
# endif

#endif
Expand Down
62 changes: 62 additions & 0 deletions config/cmake/HDFTests.c
Original file line number Diff line number Diff line change
Expand Up @@ -118,3 +118,65 @@ main(void)
#endif
}
#endif

#ifdef HAVE_STDC_NO_COMPLEX
#ifndef __STDC_NO_COMPLEX__
#error "__STDC_NO_COMPLEX__ not defined"
#else
int
main(void)
{
return 0;
}
#endif
#endif

#ifdef HAVE_COMPLEX_NUMBERS
#include <complex.h>

#ifdef _MSC_VER

typedef _Fcomplex H5_float_complex;
typedef _Dcomplex H5_double_complex;
typedef _Lcomplex H5_ldouble_complex;
#define H5_make_fcomplex _FCbuild
#define H5_make_dcomplex _Cbuild
#define H5_make_lcomplex _LCbuild

#else

typedef float _Complex H5_float_complex;
typedef double _Complex H5_double_complex;
typedef long double _Complex H5_ldouble_complex;
static float _Complex
H5_make_fcomplex(float real, float imaginary)
{
return real + imaginary * (float _Complex)_Complex_I;
}
static double _Complex
H5_make_dcomplex(double real, double imaginary)
{
return real + imaginary * (double _Complex)_Complex_I;
}
static long double _Complex
H5_make_lcomplex(long double real, long double imaginary)
{
return real + imaginary * (long double _Complex)_Complex_I;
}
#endif

int
main(void)
{
H5_float_complex z1 = H5_make_fcomplex(1.0f, 1.0f);
H5_double_complex z2 = H5_make_dcomplex(2.0, 4.0);
H5_ldouble_complex z3 = H5_make_lcomplex(3.0L, 5.0L);
float r1 = crealf(z1);
float i1 = cimagf(z1);
double r2 = creal(z2);
double i2 = cimag(z2);
long double r3 = creall(z3);
long double i3 = cimagl(z3);
return 0;
}
#endif
52 changes: 52 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -574,6 +574,58 @@ AC_CHECK_SIZEOF([float])
AC_CHECK_SIZEOF([double])
AC_CHECK_SIZEOF([long double])

## ----------------------------------------------------------------------
## Check if complex number support is available
##
HAVE_COMPLEX_NUMBERS="no"
AC_CHECK_SIZEOF([float complex], [], [#include <complex.h>])
AC_CHECK_SIZEOF([double complex], [], [#include <complex.h>])
AC_CHECK_SIZEOF([long double complex], [], [#include <complex.h>])

if test "$ac_cv_sizeof_float_complex" != 0 &&
test "$ac_cv_sizeof_double_complex" != 0 &&
test "$ac_cv_sizeof_long_double_complex" != 0; then
# Check if __STDC_NO_COMPLEX__ macro is defined, in which case complex number
# support is not available
AC_MSG_CHECKING([if __STDC_NO_COMPLEX__ is defined])
TEST_SRC="`(echo \"#define HAVE_STDC_NO_COMPLEX 1\"; cat $srcdir/config/cmake/HDFTests.c)`"
AC_CACHE_VAL([hdf5_cv_have_stdc_no_complex],
[AC_RUN_IFELSE(
[AC_LANG_SOURCE([$TEST_SRC])],
[hdf5_cv_have_stdc_no_complex=yes],
[hdf5_cv_have_stdc_no_complex=no],
[hdf5_cv_have_stdc_no_complex=maybe])])
AC_MSG_RESULT(${hdf5_cv_have_stdc_no_complex})

if test "X$hdf5_cv_have_stdc_no_complex" == "Xno"; then
# Compile simple test program with complex numbers
AC_MSG_CHECKING([if complex number test program can be compiled and linked])
TEST_SRC="`(echo \"#define HAVE_COMPLEX_NUMBERS 1\"; cat $srcdir/config/cmake/HDFTests.c)`"
AC_CACHE_VAL([hdf5_cv_have_complex_numbers],
[AC_RUN_IFELSE(
[AC_LANG_SOURCE([$TEST_SRC])],
[hdf5_cv_have_complex_numbers=yes],
[hdf5_cv_have_complex_numbers=no],
[hdf5_cv_have_complex_numbers=maybe])])
AC_MSG_RESULT(${hdf5_cv_have_complex_numbers})

if test "X$hdf5_cv_have_complex_numbers" == "Xyes"; then
HAVE_COMPLEX_NUMBERS="yes"

# Define HAVE_COMPLEX_NUMBERS macro for H5pubconf.h.
AC_DEFINE([HAVE_COMPLEX_NUMBERS], [1], [Determine if complex number support is available])
AC_DEFINE([HAVE_C99_COMPLEX_NUMBERS], [1], [Determine if C99 complex number types are present])
fi
fi
fi

# Define HAVE_COMPLEX_NUMBERS value to substitute into other files for conditional testing
AC_SUBST([HAVE_COMPLEX_NUMBERS])
AC_SUBST([HAVE_C99_COMPLEX_NUMBERS])

AC_MSG_CHECKING([if complex number support is available])
AC_MSG_RESULT([$HAVE_COMPLEX_NUMBERS])

#-----------------------------------------------------------------------------
# Option for enabling/disabling support for non-standard features, datatypes,
# etc. These features should still be checked for at configure time, but these
Expand Down
2 changes: 1 addition & 1 deletion doxygen/aliases
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,7 @@ ALIASES += ref_rfc20040811="<a href=\"https://\RFCURL/text-dtype.htm.pdf\">Conve

ALIASES += click4more="(Click on a enumerator, field, or type for more information.)"
ALIASES += csets="<table><tr><td>#H5T_CSET_ASCII</td><td>US ASCII</td></tr><tr><td>#H5T_CSET_UTF8</td><td>UTF-8 Unicode encoding</td></tr></table>"
ALIASES += datatype_class=" \li #H5T_INTEGER \li #H5T_FLOAT \li #H5T_STRING \li #H5T_BITFIELD \li #H5T_OPAQUE \li #H5T_COMPOUND \li #H5T_REFERENCE \li #H5T_ENUM \li #H5T_VLEN \li #H5T_ARRAY"
ALIASES += datatype_class=" \li #H5T_INTEGER \li #H5T_FLOAT \li #H5T_STRING \li #H5T_BITFIELD \li #H5T_OPAQUE \li #H5T_COMPOUND \li #H5T_REFERENCE \li #H5T_ENUM \li #H5T_VLEN \li #H5T_ARRAY \li #H5T_COMPLEX"
ALIASES += file_access="<table><tr><td>#H5F_ACC_RDWR</td><td>File was opened with read/write access.</td></tr><tr><td>#H5F_ACC_RDONLY</td><td>File was opened with read-only access.</td></tr><tr><td>#H5F_ACC_SWMR_WRITE</td><td>File was opened with read/write access for a single-writer/multiple-reader (SWMR) scenario. Note that the writer process must also open the file with the #H5F_ACC_RDWR flag.</td></tr><tr><td>#H5F_ACC_SWMR_READ</td><td>File was opened with read-only access for a single-writer/multiple-reader (SWMR) scenario. Note that the reader process must also open the file with the #H5F_ACC_RDONLY flag.</td></tr></table>"
ALIASES += id_types="<table><tr><td>#H5I_FILE</td><td>File</td></tr><tr><td>#H5I_GROUP</td><td>Group</td></tr><tr><td>#H5I_DATATYPE</td><td>Datatype</td></tr><tr><td>#H5I_DATASPACE</td><td>Dataspace</td></tr><tr><td>#H5I_DATASET</td><td>Dataset</td></tr><tr><td>#H5I_ATTR</td><td>Attribute</td></tr></table>"
ALIASES += indexes="<table><tr><td>#H5_INDEX_NAME</td><td>Lexicographic order on name</td></tr><tr><td>#H5_INDEX_CRT_ORDER</td><td>Index on creation order</td></tr></table>"
Expand Down
Loading

0 comments on commit 1b1e812

Please sign in to comment.