From e64d510b1637dd7ce64ba5c121dcbc85e254ad79 Mon Sep 17 00:00:00 2001 From: aaronkanzer Date: Sat, 24 Oct 2026 07:58:00 -0400 Subject: [PATCH] Fix SZ and SZ3 from_filter_options for chunks with 3 or more dimensions The SZ filters prepend (ndim, dtype, dims...) to the cd_values: 4 values for 1D and 2D chunks, ndim + 2 values otherwise. _from_filter_options always read the error bound mode at index 4, so it raised "Unsupported sz_mode" or returned the wrong config for 3D+ chunks. --- src/hdf5plugin/_filters.py | 15 +++++++++++++++ src/hdf5plugin/test.py | 20 ++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/src/hdf5plugin/_filters.py b/src/hdf5plugin/_filters.py index ea8ace21..9b12ec75 100644 --- a/src/hdf5plugin/_filters.py +++ b/src/hdf5plugin/_filters.py @@ -1089,6 +1089,19 @@ def _sz_unpack_float64(high: int, low: int) -> float: return float(struct.unpack(">d", packed)[0]) +def _sz_strip_dims(filter_options: tuple[int, ...]) -> tuple[int, ...]: + """Returns SZ/SZ3 "cd_values" without the leading chunk shape information + + The filter stores (ndim, dtype, dims...) first: + 4 values for 1 and 2 dimensions, ndim + 2 values otherwise. + See SZ_cdArrayToMetaDataErr in H5Z_SZ.c and H5Z_SZ3.cpp. + """ + ndim = filter_options[0] if filter_options else 0 + offset = 4 if ndim <= 2 else ndim + 2 + # Keep 4 leading values so indices match the 1D/2D layout + return (*filter_options[:4], *filter_options[offset:]) + + class SZ(FilterBase): """``h5py.Group.create_dataset``'s compression arguments for using SZ2 filter. @@ -1185,6 +1198,7 @@ def _from_filter_options(cls, filter_options: tuple[int, ...]) -> SZ: (_, _, _, _, mode, absolute1, absolute2, relative1, relative2, pointwise1, pointwise2) :raises ValueError: Unsupported filter_options """ + filter_options = _sz_strip_dims(filter_options) if len(filter_options) < 13: raise ValueError(f"Expected 13 values, got {len(filter_options)}") @@ -1286,6 +1300,7 @@ def _from_filter_options(cls, filter_options: tuple[int, ...]) -> SZ3: (_, _, _, _, mode, absolute1, absolute2, relative1, relative2, norm2_1, norm2_2, pointwise1, pointwise2) :raises ValueError: Unsupported filter_options """ + filter_options = _sz_strip_dims(filter_options) if len(filter_options) < 13: raise ValueError(f"Expected 13 values, got {len(filter_options)}") diff --git a/src/hdf5plugin/test.py b/src/hdf5plugin/test.py index 69620f91..00a87f14 100644 --- a/src/hdf5plugin/test.py +++ b/src/hdf5plugin/test.py @@ -658,6 +658,18 @@ def testSZ(self): (1, 0, 0, 256, 10, 0, 0, 0, 0, 1062232653, 3539053052, 0, 0), hdf5plugin.SZ(pointwise_relative=1e-3), ), + ( # 2D chunk + (2, 0, 32, 32, 0, 1062232653, 3539053052, 0, 0, 0, 0, 0, 0), + hdf5plugin.SZ(absolute=1e-3), + ), + ( # 3D chunk + (3, 0, 32, 32, 4, 0, 1062232653, 3539053052, 0, 0, 0, 0, 0, 0), + hdf5plugin.SZ(absolute=1e-3), + ), + ( # 4D chunk + (4, 0, 16, 16, 2, 2, 1, 0, 0, 1062232653, 3539053052, 0, 0, 0, 0), + hdf5plugin.SZ(relative=1e-3), + ), ): with self.subTest(filter_options=filter_options): compression_filter = hdf5plugin.SZ._from_filter_options(filter_options) @@ -687,6 +699,14 @@ def testSZ3(self): (1, 0, 0, 256, 3, 0, 0, 0, 0, 0, 0, 1062232653, 3539053052), hdf5plugin.SZ3(peak_signal_to_noise_ratio=1e-3), ), + ( # 3D chunk + (3, 0, 32, 32, 4, 0, 1062232653, 3539053052, 0, 0, 0, 0, 0, 0), + hdf5plugin.SZ3(absolute=1e-3), + ), + ( # 4D chunk + (4, 0, 16, 16, 2, 2, 2, 0, 0, 0, 0, 1062232653, 3539053052, 0, 0), + hdf5plugin.SZ3(norm2=1e-3), + ), ): with self.subTest(filter_options=filter_options): compression_filter = hdf5plugin.SZ3._from_filter_options(filter_options)