Decompress Dectris Eiger bitshuffle-LZ4 data directly to sparse index/value arrays.
Documentation, with runnable examples and speed on real data: https://jonwright.github.io/bslz4_to_sparse/
This repository brings together upstream code from bitshuffle [1], the DECTRIS bitshuffle SIMD kernels [2], LZ4 [3] and Zstandard [4] to process detector data as a stream (in cache), rather than writing whole images to RAM and reading them back again. Versions before 0.0.16 were mostly written by @jonwright; later versions include a large amount of LLM-generated code (DeepSeek and Claude).
It is used in ImageD11 [5] to convert images directly to sparse
format, and it can also do radial integrations as sparse matrix products
(for example with the integration matrices of pyFAI [6]). The C/C++ core
is a Python extension through c2py23 [7]. Each decoder object has a
pipeline: one value per processing step (decode, mask, untranspose,
collect, and for matrix objects route and dot), chosen automatically for the
CPU, data and matrix unless given; bslz4_to_sparse.describe() lists the
values and which ones this machine can run.
After git clone:
git submodule update --init
python3 -m pip install .
To run it at the ESRF:
cd test
python3 test_vs_hdf5plugin.py
python3 bench1.py
To test a local build without installing:
python3 setup.py build --build-lib=lib
cd test
BSLZ4_TO_SPARSE_PATH=$(pwd)/../lib python3 -m pytest -v
BSLZ4_TO_SPARSE_PATH=$(pwd)/../lib python3 bench1.py
Every script in test/ prepends BSLZ4_TO_SPARSE_PATH to sys.path, so
it wins over any installed bslz4_to_sparse and works where PYTHONPATH
is ignored (ESRF jupyter-slurm).
The extension is tagged by platform only
(_bslz4_to_sparse.c2py23-linux_ppc64le.so); c2py23 resolves the CPython
API at runtime, so one binary serves any Python version. Run the build
once per machine: a single lib/ on a shared filesystem holds all of
them. C2PY_TRACE=1 reports which file the loader picks.
Threads and free-threaded Python (3.14t, 3.15t): the decode entry points
release the GIL, and the extension declares itself free-threading safe, so
importing it does not re-enable the GIL. Nothing is locked; the rule is one
chunk2sparse / chunk2sparseCSC object per thread (for the second, give
the objects of a thread pool one plan(mask, csc): they share its matrix instead of
each building and holding a copy). Each object reuses its
own workspace and output arrays, so the arrays a call returns are
overwritten by that object's next call, and a call's inputs (chunks, mmap
base, mask) must not be changed or closed by another thread while it runs.
Breaking these rules gives wrong results or a crash, not an error.
_testing.counters() (test instrumentation) is only exact while one
decode runs at a time.
Collect values the machine cannot run (vsx on x86_64, neon on x86_64/POWER,
avx512cs/avx2cs/sse2 on POWER/ARM) are skipped by
test_simd_collect_matches_scalar.
The licences of the bundled upstream code are in licenses/.
This package is mostly a regrouping of other people's work, put together so that detector frames can be decoded and reduced in one pass. The bitshuffle format and its reference implementation come from K. Masui and co-authors [1]; the fast SIMD bit-transpose kernels from K. Conley at DECTRIS [2]; the LZ4 and Zstandard decompressors from Y. Collet and the Zstandard contributors [3], [4]. The integration matrices are pyFAI's [6], and the sparse output serves ImageD11 [5]. The optional GPU decoder uses an edited extract of the LZ4 device kernels of NVIDIA's nvcomp [8]. The portable Python wrappers come from c2py23 [7]: they let one compiled module load on every CPython from 2.7 to 3.15, free-threaded builds included, without compiling against any Python headers. Our thanks to all of these projects; please cite them as well as this one.
[1] bitshuffle, K. Masui et al., https://github.com/kiyo-masui/bitshuffle; K. Masui et al., "A compression scheme for radio data in high performance computing", Astronomy and Computing 12, 181-190 (2015), https://doi.org/10.1016/j.ascom.2015.07.002
[2] bitshuffle SIMD bit-transpose kernels ("kcb"), K. Conley (DECTRIS), https://github.com/kalcutter/bitshuffle
[3] LZ4, Y. Collet, https://github.com/lz4/lz4
[4] Zstandard, Y. Collet and Meta Platforms, https://github.com/facebook/zstd; Y. Collet and M. Kucherawy (ed.), "Zstandard Compression and the 'application/zstd' Media Type", RFC 8878 (2021), https://doi.org/10.17487/RFC8878
[5] ImageD11, https://github.com/FABLE-3DXRD/ImageD11
[6] pyFAI, https://github.com/silx-kit/pyFAI; G. Ashiotis, A. Deschildre, Z. Nawaz, J. P. Wright, D. Karkoulis, F. E. Picca and J. Kieffer, "The fast azimuthal integration Python library: pyFAI", J. Appl. Cryst. 48, 510-519 (2015), https://doi.org/10.1107/S1600576715004306
[7] c2py23, https://github.com/jonwright/c2py23
[8] nvcomp, NVIDIA, https://github.com/NVIDIA/nvcomp (BSD 3-Clause; src/cuda/nvcomp_lz4.cuh)