Files
clawhdf5/crates/clawhdf5-netcdf4/README.md
T
osobhandClaude Opus 5.5 31efac1ae1
CI / test-arm64 (pull_request) Successful in 1m34s
CI / test (pull_request) Successful in 30m38s
clawhdf5-netcdf4: an unlimited dimension reports its current length
Dimension::size of an unlimited dimension was its dimension scale's
extent, which netCDF-C leaves at 0, so it read 0 for a dimension holding
records. It is now what netCDF-C reports (nc4_find_dim_len): the largest
current extent of the variables using it in any group, found through the
scale's REFERENCE_LIST, a coordinate variable's own extent included; 0
when nothing has been written.

interop_tests::unlimited_dimension_lengths_match_netcdf4_python compares
with netCDF4-python (variables of different lengths, one in a subgroup,
an unwritten dimension, a coordinate variable shorter than another
variable on its dimension, a subgroup's own dimension); before the fix it
got time 0/6, rec 3/5, srec 0/1.

The known-issues entry moves to Fixed; the crate README's warning goes.
A new open entry records a related bug found meanwhile: variables'
dimensions are matched by size, not DIMENSION_LIST.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-28 21:24:59 -05:00

54 lines
2.3 KiB
Markdown

# clawhdf5-netcdf4
Read NetCDF-4 files in pure Rust. NetCDF-4 files are HDF5 files with
conventions for dimensions, coordinate variables and attributes; this crate
reads them through the [`clawhdf5`](../clawhdf5/README.md) facade, with no
libnetcdf or libhdf5. Read-only: NetCDF-3 (classic) files are not HDF5 and
are not supported.
Not on crates.io yet; depend on it from git:
```toml
[dependencies]
clawhdf5-netcdf4 = { git = "https://git.redclaw.dev/quantumclaw/clawhdf5" }
```
## Usage
```rust,no_run
use clawhdf5_netcdf4::NetCDF4File;
let nc = NetCDF4File::open("climate.nc")?;
for dim in nc.dimensions()? {
println!("{}: {} (unlimited = {})", dim.name, dim.size, dim.is_unlimited);
}
let mut temp = nc.variable("temperature")?;
let dims: Vec<&str> = temp.dimensions().iter().map(|d| d.name.as_str()).collect();
println!("{:?} over {:?}", temp.shape()?, dims);
let cf = temp.cf_attributes()?;
println!("units: {:?}", cf.units);
// scale_factor/add_offset applied; _FillValue and missing_value become NaN
let values: Vec<f64> = temp.read_f64()?;
# Ok::<(), clawhdf5_netcdf4::Error>(())
```
## API
| Item | What |
|---|---|
| `NetCDF4File` | `open`, `from_bytes`, `dimensions`, `variables`, `variable`, `global_attrs`, `group`, `group_names`, `nc_properties`, and `hdf5_file` for the underlying `clawhdf5::File` |
| `NetCDF4Group` | the same for a sub-group (`dimensions`, `variables`, `attrs`, nested `group`) |
| `Variable` | `name`, `shape`, `dimensions`, `nc_type`, `is_coordinate`, `attrs`, `cf_attributes`; `read_f64` (CF scale/offset and fill applied), `read_raw_f32`/`_f64`/`_i32`/`_i64`/`_u64`, `read_string`, `read_raw` |
| `Dimension` | `name`, `size`, `is_unlimited` (an unlimited dimension's `size` is its current length as netCDF-C reports it: the largest extent of the variables using it) |
| `CfAttributes` | CF convention attributes: `units`, `long_name`, `standard_name`, `fill_value` (`_FillValue`), `missing_value`, `scale_factor`, `add_offset`, `valid_range`, `calendar`, `axis` |
| `NcType` | the NetCDF type of a variable |
No cargo features. Tests compare against files written by netCDF4-python
(`tests/interop_tests.rs`; the CI job requires them with
`CLAWHDF5_REQUIRE_INTEROP=1`). What the HDF5 reader underneath cannot
read is listed in [`docs/known-issues.md`](../../docs/known-issues.md).
## License
MIT