HDF5 2.0 native complex as a first-class type on read; Python libver=
- Datatype::parse returns Datatype::Complex for class 11 (also inside
compounds, arrays and VL types) instead of the {r, i} compound view.
- Facade: DType::Complex(Box<DType>); read_complex_f32/f64 accept it.
- h5rs dump/ls/diff print native complex as h5dump/h5ls/h5diff 2.2.0 do
(checked against a fixture written by h5py 3.16 / libhdf5 2.0.0);
dump --json keeps the {r, i} compound (hdf5-json has no complex class).
- clawhdf5-wasm reads native complex datasets as [re, im] pairs.
- Python: clawhdf5.File(path, 'w', libver=...) with h5py's values,
mapped to FileBuilder::libver_bounds; 'v108' output opens in HDF5 1.8.23.
- Docs: known-issues entry moved to Fixed (history), CHANGELOG, READMEs.
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
@@ -56,6 +56,69 @@
|
||||
and `docs/known-issues.md` (tank, 2026-09-29, netCDF4-python 1.7.4).
|
||||
Affected v2.1.0 to v2.7.0.
|
||||
|
||||
### HDF5 2.0 native complex is its own type on read; Python `libver=` (2026-09-29)
|
||||
- **`Datatype::parse` returns `Datatype::Complex { size, base_type }`** for
|
||||
a class-11 message, also as a compound member, array base or
|
||||
variable-length base. It used to return the equivalent `{r, i}`
|
||||
compound (`docs/known-issues.md`, "HDF5 2.0 native complex numbers read
|
||||
as a `{r, i}` compound"). **Breaking** for code that matched the
|
||||
compound view of a native complex type: `Dataset::raw_datatype()` and
|
||||
attribute datatypes are now `Datatype::Complex`;
|
||||
`Datatype::complex_as_compound(size, base)` still gives the `{r, i}` view,
|
||||
and `data_read::read_compound_fields` accepts a `Complex` directly.
|
||||
Re-serializing a parsed type (e.g. copying it to another file) now writes
|
||||
class 11 again instead of a compound.
|
||||
- **Facade:** `DType::Complex(Box<DType>)` (new variant, **breaking** for
|
||||
exhaustive `match`es over `DType`): `Complex(F32)` is numpy `complex64`,
|
||||
`Complex(F64)` `complex128`, a binary16 part `Complex(Other("float16"))`
|
||||
(the same `Other` name small floats already use); `Display` prints
|
||||
`complex<f64>`. h5py's own complex encoding, the compound `{r, i}`, is
|
||||
still `DType::Compound`. `read_complex_f64`/`read_complex_f32` read both.
|
||||
- **`h5rs`:** `dump` prints native complex as h5dump 2.2.0 does:
|
||||
`H5T_COMPLEX_IEEE_F{16,32,64}{LE,BE}` (else `H5T_COMPLEX { <base> }`), in
|
||||
arrays and compounds too, and values as `1.5-2i` (`%g%+gi`; for binary16
|
||||
parts, which h5dump has no C type for, `1+-2i` as it prints them). `ls`
|
||||
shows `complex64`, `complex128-be`, `complex32` (and `complex<part>` for
|
||||
non-IEEE parts); `ls -v` shows h5ls 2.2.0's `complex number of` /
|
||||
`IEEE 64-bit big-endian float`. `diff` compares complex values part by
|
||||
part and prints the difference as h5diff 2.2.0 does (`1+0i`); a native
|
||||
complex and an `{r, i}` compound are no longer comparable (different
|
||||
classes, as in h5diff). `dump --json` keeps the `{r, i}` compound and
|
||||
`[re, im]` values: hdf5-json (h5json 2.0.0) has no complex class.
|
||||
- **Browser (`clawhdf5-wasm`):** native complex datasets are readable, as
|
||||
`[re, im]` pairs: `info().elementShape` ends in `2`, `read()` returns the
|
||||
parts interleaved in a `Float32Array`/`Float64Array` (binary16 parts
|
||||
widened to f32), and `dtype` is `complex<f64>` (`complex<f32
|
||||
(big-endian)>`, `array[2]<complex<f32>>`). The viewer shows each element
|
||||
as `[re, im]` with no change to the page. h5py's `{r, i}` compound is
|
||||
still refused, as every compound is.
|
||||
- **Python:** `clawhdf5.File(path, 'w', libver=...)` takes h5py's values:
|
||||
`'v108'`, `'v110'`, `'v112'`, `'v114'`, `'v200'`, `'latest'` (the low
|
||||
bound; high `'latest'`, as h5py) or a `(low, high)` tuple, mapped to
|
||||
`FileBuilder::libver_bounds`. `'earliest'` as the low bound writes the
|
||||
1.8 format with a `UserWarning` (clawhdf5 cannot write the pre-1.8
|
||||
format); as the high bound it is a `ValueError`, as are unknown names and
|
||||
a low bound above the high one. It is ignored for `'r'` and refused
|
||||
(`NotImplementedError`) for `'r+'`/`'a'`. Native complex already read as
|
||||
numpy `complex64`/`complex128` and still does
|
||||
(`test_read_native_complex_from_h5py`).
|
||||
- Tests (tank, 2026-09-29): `crates/clawhdf5-tools/tests/native_complex_dump.rs`
|
||||
compares `h5rs dump` with h5dump 2.2.0's output stored next to a fixture
|
||||
written by h5py 3.16 / libhdf5 2.0.0
|
||||
(`crates/clawhdf5/tests/fixtures/gen_native_complex.py`:
|
||||
`F32LE`/`F64LE`/`F64BE`/`F16LE`, scalar, compound member, array, root
|
||||
attribute), line for line outside the values and value for value within
|
||||
them, and `ls`/`diff` with h5ls/h5diff 2.2.0;
|
||||
`integration_tests::complex_datasets_and_attributes_round_trip`
|
||||
(`DType::Complex`, `raw_datatype()`); `clawhdf5-wasm` unit tests on the
|
||||
fixture, `h5py_interop` and `examples/wasm-viewer/test` (Node:
|
||||
`test.mjs`, 274 + 1324 checks; the page in headless Chromium for
|
||||
`/native_c128`, `/native_c64_be`, `/pairs`) with two native complex
|
||||
datasets added to `make_fixture.py` (when h5py's libhdf5 is 2.0+);
|
||||
`crates/clawhdf5-py/tests/test_libver.py` (every bound; `'v108'` output
|
||||
opens in HDF5 1.8.23's h5dump and in h5py). `test.mjs` no longer
|
||||
hard-codes the fixture's length.
|
||||
|
||||
### NetCDF-4: variables' dimensions come from the file (2026-09-28)
|
||||
- `clawhdf5-netcdf4` gave each variable the first unused dimension of
|
||||
equal size (else an anonymous `dim_<n>`), so a variable on an unlimited
|
||||
|
||||
Reference in New Issue
Block a user