From 404f9e9cc9595e5349a9d0941ed6b0d4d339f934 Mon Sep 17 00:00:00 2001 From: Tim Reichelt Date: Wed, 27 May 2026 09:25:42 +0100 Subject: [PATCH 1/2] Add SZ3 and EBCC versions that only use absolute error bound --- .../compressor/compressors/__init__.py | 6 ++-- .../compressor/compressors/ebcc.py | 29 ++++++++++++++++++- .../compressor/compressors/sz3.py | 14 ++++++++- 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/src/climatebenchpress/compressor/compressors/__init__.py b/src/climatebenchpress/compressor/compressors/__init__.py index 1b87b38..4c58e9f 100644 --- a/src/climatebenchpress/compressor/compressors/__init__.py +++ b/src/climatebenchpress/compressor/compressors/__init__.py @@ -2,6 +2,7 @@ "BitRound", "BitRoundPco", "Ebcc", + "EbccAbsOnly", "Jpeg2000", "SafeguardedBitRoundPco", "SafeguardedSperr", @@ -13,6 +14,7 @@ "StochRound", "StochRoundPco", "Sz3", + "Sz3AbsOnly", "Tthresh", "Zfp", "ZfpRound", @@ -21,7 +23,7 @@ from . import abc as abc from .bitround import BitRound from .bitround_pco import BitRoundPco -from .ebcc import Ebcc +from .ebcc import Ebcc, EbccAbsOnly from .jpeg2000 import Jpeg2000 from .safeguarded import ( SafeguardedBitRoundPco, @@ -34,7 +36,7 @@ from .sperr import Sperr from .stochround import StochRound from .stochround_pco import StochRoundPco -from .sz3 import Sz3 +from .sz3 import Sz3, Sz3AbsOnly from .tthresh import Tthresh from .zfp import Zfp from .zfp_round import ZfpRound diff --git a/src/climatebenchpress/compressor/compressors/ebcc.py b/src/climatebenchpress/compressor/compressors/ebcc.py index 9c77e5c..8c82808 100644 --- a/src/climatebenchpress/compressor/compressors/ebcc.py +++ b/src/climatebenchpress/compressor/compressors/ebcc.py @@ -1,4 +1,4 @@ -__all__ = ["Ebcc"] +__all__ = ["Ebcc", "EbccAbsOnly"] import numcodecs.astype import numcodecs_wasm_ebcc @@ -50,3 +50,30 @@ def rel_bound_codec(error_bound, dtype=None, **kwargs): chunk_shape="auto", ), ) + + +class EbccAbsOnly(Compressor): + """EBCC compressor but instead of using the internal EBCC relative error bound, + it converts the relative error bound to an absolute error bound..""" + + name = "ebcc-abs" + description = "EBCC-Abs" + + @staticmethod + def abs_bound_codec(error_bound, dtype=None, **kwargs): + assert dtype is not None, "dtype must be provided" + + return CodecStack( + # EBCC only supports float32 data + numcodecs.astype.AsType( + encode_dtype="float32", + decode_dtype=dtype.name, + ), + numcodecs_wasm_ebcc.Ebcc( + # reasonable default recommended by Langwen Huang + base_cr=100, + residual="absolute", + error=error_bound, + chunk_shape="auto", + ), + ) diff --git a/src/climatebenchpress/compressor/compressors/sz3.py b/src/climatebenchpress/compressor/compressors/sz3.py index 6d00300..4dcb9f2 100644 --- a/src/climatebenchpress/compressor/compressors/sz3.py +++ b/src/climatebenchpress/compressor/compressors/sz3.py @@ -1,4 +1,4 @@ -__all__ = ["Sz3"] +__all__ = ["Sz3", "Sz3AbsOnly"] import numcodecs_wasm_sz3 @@ -22,3 +22,15 @@ def rel_bound_codec(error_bound, **kwargs): # based on the range of the input data: # https://github.com/szcompressor/SZ3/blob/e8a6b1569067abdd6b7d4276e91eced115be4f14/include/SZ3/utils/Statistic.hpp#L36 return numcodecs_wasm_sz3.Sz3(eb_mode="rel", eb_rel=error_bound) + + +class Sz3AbsOnly(Compressor): + """SZ3 compressor but instead of using the internal SZ3 relative error bound, + it converts the relative error bound to an absolute error bound.""" + + name = "sz3-abs" + description = "SZ3-Abs" + + @staticmethod + def abs_bound_codec(error_bound, **kwargs): + return numcodecs_wasm_sz3.Sz3(eb_mode="abs", eb_abs=error_bound) From 9f5426eaa10877d5ab1e3b3330f20f5683edce5b Mon Sep 17 00:00:00 2001 From: Tim Reichelt Date: Thu, 28 May 2026 12:19:59 +0100 Subject: [PATCH 2/2] Ensure that EBCC error bound is positive --- src/climatebenchpress/compressor/compressors/ebcc.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/climatebenchpress/compressor/compressors/ebcc.py b/src/climatebenchpress/compressor/compressors/ebcc.py index 8c82808..72f5e2c 100644 --- a/src/climatebenchpress/compressor/compressors/ebcc.py +++ b/src/climatebenchpress/compressor/compressors/ebcc.py @@ -2,6 +2,7 @@ import numcodecs.astype import numcodecs_wasm_ebcc +import numpy as np from numcodecs_combinators.stack import CodecStack from .abc import Compressor @@ -63,6 +64,13 @@ class EbccAbsOnly(Compressor): def abs_bound_codec(error_bound, dtype=None, **kwargs): assert dtype is not None, "dtype must be provided" + # Ensure that the error bound is representable as a float32. + # For numbers smaller than the smallest positive normal float32, + # we use the smallest subnormal float32. + error_bound = max( + np.float32(error_bound), np.finfo(np.float32).smallest_subnormal + ) + return CodecStack( # EBCC only supports float32 data numcodecs.astype.AsType( @@ -73,7 +81,7 @@ def abs_bound_codec(error_bound, dtype=None, **kwargs): # reasonable default recommended by Langwen Huang base_cr=100, residual="absolute", - error=error_bound, + error=float(error_bound), chunk_shape="auto", ), )