feat: write complex numbers, incl. HDF5 2.0 native complex (class 11)
- Datatype::Complex serializes class 11 version 5 byte-identically to
libhdf5 2.2.0; containers holding it are written as version 5.
- DatasetBuilder::with_complex_f32/f64_data (h5py's {r, i} compound,
default) and with_native_complex_f32/f64_data (class 11, opt-in);
make_(native_)complex_f32/f64_type for attributes.
- Dataset::read_complex_f64/f32 read either form.
- Python create_dataset accepts complex64/complex128 (compound form).
- Parsing unchanged: class 11 still surfaces as {r, i}.
- Tests vs h5py 3.16 / libhdf5 2.0.0 and h5dump 2.2.0; docs.
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
@@ -247,6 +247,51 @@ def test_roundtrip_uint8(tmp_h5):
|
||||
assert result.dtype == np.uint8
|
||||
|
||||
|
||||
@pytest.mark.parametrize("dtype", [np.complex64, np.complex128])
|
||||
def test_roundtrip_complex(tmp_h5, dtype):
|
||||
"""Complex arrays are written as h5py writes them (a compound {r, i});
|
||||
h5py and clawhdf5 both read them back as the same numpy complex dtype."""
|
||||
import h5py
|
||||
|
||||
original = (np.arange(12).reshape(3, 4) * (1.5 - 0.25j)).astype(dtype)
|
||||
with clawhdf5.File(tmp_h5, "w") as f:
|
||||
f.create_dataset("z", data=original)
|
||||
f.create_dataset("zc", data=original, chunks=(2, 2), compression="gzip")
|
||||
with clawhdf5.File(tmp_h5, "r") as f:
|
||||
for name in ["z", "zc"]:
|
||||
result = f[name][:]
|
||||
assert result.dtype == dtype
|
||||
np.testing.assert_array_equal(result, original)
|
||||
with h5py.File(tmp_h5, "r") as f:
|
||||
for name in ["z", "zc"]:
|
||||
assert f[name].dtype == dtype
|
||||
assert f[name].id.get_type().get_class() == h5py.h5t.COMPOUND
|
||||
np.testing.assert_array_equal(f[name][:], original)
|
||||
|
||||
|
||||
def test_read_native_complex_from_h5py(tmp_h5):
|
||||
"""HDF5 2.0's native complex type (class 11), written through h5py's
|
||||
low-level API, reads as numpy complex."""
|
||||
import h5py
|
||||
from h5py import h5s, h5t
|
||||
|
||||
if not getattr(h5py.get_config(), "has_native_complex", False):
|
||||
pytest.skip("h5py's libhdf5 predates 2.0")
|
||||
original = np.array([1 + 2j, -3.5 + 0j, 0 - 1e-3j])
|
||||
with h5py.File(tmp_h5, "w") as f:
|
||||
for name, t, dt in [
|
||||
(b"n64", h5t.COMPLEX_IEEE_F32LE, np.complex64),
|
||||
(b"n128", h5t.COMPLEX_IEEE_F64LE, np.complex128),
|
||||
]:
|
||||
d = h5py.h5d.create(f.id, name, t, h5s.create_simple((3,)))
|
||||
d.write(h5s.ALL, h5s.ALL, original.astype(dt), mtype=t)
|
||||
with clawhdf5.File(tmp_h5, "r") as f:
|
||||
for name, dt in [("n64", np.complex64), ("n128", np.complex128)]:
|
||||
result = f[name][:]
|
||||
assert result.dtype == dt
|
||||
np.testing.assert_array_equal(result, original.astype(dt))
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Test: chunked + compressed datasets
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user