clawhdf5-netcdf4: phony dimensions, skipped types and order as netCDF-C
Read a file's metadata the way netCDF-C 4.9.3 does (libhdf5/hdf5open.c), for the whole file on first use (src/model.rs, replacing src/scope.rs): - links in creation order when the group tracks it, else name order; a group's datasets before its subgroups; dimension ids file-wide; - variables' dimensions from _Netcdf4Coordinates (file-wide ids), else the scales DIMENSION_LIST attaches when the first axis has one, else netCDF-C's phony dimensions phony_dim_<id> (create_phony_dims: shared by length and unlimitedness within a group, not between two axes of one variable, numbered subgroups first, a zero length unlimited); - datasets of types netCDF-C cannot represent are not variables (references, bit fields, time, arrays, compounds/enums/VLENs over them), replaying netCDF-C's file-wide type list, failed types included; - unlimited lengths as nc4_find_dim_len (its group and below). NcType gains Enum, Compound, VLen, Opaque and is #[non_exhaustive]; Variable::nc_type is netCDF-C's type (1-byte strings NC_CHAR). New clawhdf5_format::group_v2::links_in_creation_order_in. Tests compare with netCDF-C itself (tests/netcdf_c_view.py calls the libnetcdf netCDF4-python bundles through ctypes): new interop cases for h5py files without dimension scales, every type class, link order; and the gated corpus_vs_netcdf_c (CLAWHDF5_NETCDF_CORPUS): 420 of the 429 conformance-corpus files netCDF-C opens match (main: 68); the other 9 are explained in tests/corpus_known_differences.txt and known-issues. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
@@ -2,6 +2,60 @@
|
||||
|
||||
## Unreleased
|
||||
|
||||
### NetCDF-4: phony dimensions, skipped types and order as in netCDF-C (2026-09-29)
|
||||
- `clawhdf5-netcdf4` now reads a file's metadata as netCDF-C 4.9.3 does
|
||||
(`libhdf5/hdf5open.c`), for the whole file on first use
|
||||
(`src/model.rs`): links in creation order when the group tracks it,
|
||||
else in name order; a group's datasets before its subgroups; dimension
|
||||
ids file-wide (`_Netcdf4Dimid`, else the next free id); then variables'
|
||||
dimensions, subgroups first: `_Netcdf4Coordinates` ids (looked up
|
||||
file-wide), else the scales `DIMENSION_LIST` attaches (when the first
|
||||
axis has one), else phony dimensions.
|
||||
- **Files without dimension scales** get netCDF-C's phony dimensions,
|
||||
`phony_dim_<id>` (`create_phony_dims`): per axis, the first dimension of
|
||||
the variable's group of the same length and unlimitedness not used by an
|
||||
earlier axis of the variable (real dimensions included), else a new one;
|
||||
a length of 0 is always unlimited. They used to be one dimension per 1-D
|
||||
dataset, named after it, and `dim_<size>` for other axes.
|
||||
- **Datasets netCDF-C skips are not variables:** references, bit fields,
|
||||
time and array types, and compounds, enums and VLENs whose members or
|
||||
base type are not netCDF atomic types (4- and 8-byte floats only) or a
|
||||
type read before — replaying netCDF-C's file-wide type list, which also
|
||||
keeps a type it failed to read, so the second dataset of a compound with
|
||||
a reference member is a variable, as in netCDF-C.
|
||||
- `NcType` gains `Enum`, `Compound`, `VLen` and `Opaque` and is now
|
||||
`#[non_exhaustive]` (breaking for exhaustive matches);
|
||||
`Variable::nc_type` is the type netCDF-C gives the variable: a 1-byte
|
||||
fixed-length string is `Char`, a longer one `String` (both were
|
||||
`String`); user-defined types have their class (they were `Char`).
|
||||
`dtype_to_nctype` maps compounds and enums to their classes.
|
||||
- Groups (`group_names`), variables (`variables`, `variable_names`) and
|
||||
dimensions (`dimensions`, by id) come in netCDF-C's order; a zero-length
|
||||
dimension scale is unlimited; an unlimited dimension's length is the
|
||||
longest extent along it of the variables in its group and below
|
||||
(`nc4_find_dim_len`; was: of the variables its `REFERENCE_LIST` names).
|
||||
`NetCDF4File::group` and `NetCDF4Group::group` take a path (`"a/b"`).
|
||||
- Deliberate differences: floats of other than 4 or 8 bytes are
|
||||
`Float`/`Double` (netCDF-C 4.9.3 on libhdf5 1.14.6 labels them
|
||||
`NC_STRING`); an axis netCDF-C leaves without a dimension (where it
|
||||
reads uninitialised memory) gets one by the phony rule.
|
||||
- New `clawhdf5_format::group_v2::links_in_creation_order_in`: a group's
|
||||
link names in creation order, or `None` when it does not track it.
|
||||
- Tests compare with netCDF-C itself (`tests/netcdf_c_view.py` calls the
|
||||
libnetcdf netCDF4-python bundles through ctypes, since netCDF4-python
|
||||
hides variables of types it does not support): `interop_tests` cases of
|
||||
h5py files without dimension scales (sharing, unlimited and zero-length
|
||||
axes, subgroups, a real dimension taken by length), of every HDF5 type
|
||||
class, of creation and name order in compact and dense groups, and a
|
||||
netCDF4-python file; and the gated `tests/corpus_vs_netcdf_c.rs`
|
||||
(`CLAWHDF5_NETCDF_CORPUS=<dir>`): over the conformance corpus 420 of the
|
||||
429 files netCDF-C 4.9.3 opens match in groups, dimensions, variables,
|
||||
types, shapes and numeric values (up to 5000 elements); `main` at
|
||||
`4260af4` matched 68. The other 9 (external links, values the HDF5
|
||||
reader refuses) are explained in `tests/corpus_known_differences.txt`
|
||||
and `docs/known-issues.md` (tank, 2026-09-29, netCDF4-python 1.7.4).
|
||||
Affected v2.1.0 to v2.7.0.
|
||||
|
||||
### 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