Files
clawhdf5/crates/clawhdf5-netcdf4/README.md
T
osobhandClaude Opus 5.5 00b6f76ee0
CI / test-arm64 (pull_request) Successful in 1m33s
CI / test (pull_request) Successful in 18m24s
clawhdf5-netcdf4: variables' dimensions come from the file
Variables got the first unused dimension of equal size, so a variable on
an unlimited dimension with fewer records got an anonymous dim_<n>, and
dimensions of one size could be swapped. Resolve them as netCDF-C does
(libhdf5/hdf5open.c): _Netcdf4Coordinates ids, else the scales
DIMENSION_LIST references (the last one attached to an axis), searched in
the variable's group and its parents; a coordinate variable is on its own
scale. Size matching remains only for axes the file names nothing for.

variables()/variable_names() leave out dimension scales that are only
dimensions, and _nc4_non_coord_<name> is the variable <name>.
Variable::shape is the netCDF shape (an unlimited dimension's length) and
the reads pad unwritten records with the fill value (_FillValue, else
NC_FILL_*; NaN from read_f64); Variable::stored_shape is the HDF5 extent.
New NetCDF4File::variable_names.

Tests compare with netCDF4-python variable by variable: the known-issues
reproducer, equal sizes, (p, p), scalars, inherited dimensions, unwritten
records, h5py dimension scales, h5netcdf and xarray files. CI installs
h5netcdf. known-issues entry moved to Fixed (history); stale open-table
row for the unlimited-size fix removed.

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

3.4 KiB

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 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:

[dependencies]
clawhdf5-netcdf4 = { git = "https://git.redclaw.dev/quantumclaw/clawhdf5" }

Usage

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_names, 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, variable_names, attrs, nested group)
Variable name, shape, stored_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

Variables and dimensions follow netCDF-C:

  • A variable's dimensions are the ones the file names: the ids in its _Netcdf4Coordinates attribute, else the dimension scales its DIMENSION_LIST references, found in its group or a parent group. Only an axis the file names no dimension for (an HDF5 file not written by a netCDF library) gets the first dimension of the group of the same size, else an anonymous dim_<size>.
  • Dimension scales that are only dimensions are not variables; a dataset _nc4_non_coord_<name> is the variable <name>.
  • A variable along an unlimited dimension has the dimension's length: shape is that length, and the reads return that many values, the records the variable has not written as its fill value (_FillValue, else netCDF's default for the type; NaN from read_f64). stored_shape is the HDF5 dataset's extent.

No cargo features. Tests compare against files written by netCDF4-python, h5py dimension scales, h5netcdf and xarray, variable by variable with what netCDF4-python reads (tests/interop_tests.rs; the CI job requires them with CLAWHDF5_REQUIRE_INTEROP=1; the h5netcdf cases skip when h5netcdf is not installed). What the HDF5 reader underneath cannot read is listed in docs/known-issues.md.

License

MIT