XFEL reader: a per-frame mask is read the way the frames are, its chunk inflated outside the HDF5 lock

The Cheetah CXI per-frame mask (N x H x W uint16, one gzip chunk per frame) was read with
ReadVector<uint32_t> under hdf5_mutex: the inflate and HDF5's element-wise type conversion serialised
every reading thread and held an AGIPD run to ~40 frames/s. It now goes through ReadStored, as the
data does: only the chunk lookup is under the lock; the read, inflate and unshuffle are not, and the
stored uint16/uint32 values are widened to uint32 exactly as HDF5 converted them.

The direct path is taken where the mask is plain unsigned integers of the frame's size, stored alike
in every file (checked once, in Place); a chunk stored with a filter skipped is read by HDF5 as for
the data, and any other mask keeps the locked HDF5 read. Images and pixel mask are bit-identical to
before (hash of every pixel of 2000 images on two AGIPD runs and one MPCCD run).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015CeEGgpKdfkCTJb3YNMJcu
This commit is contained in:
leonarski_fandClaude Opus 5.5 committed 2026-10-22 17:45:58 +02:00
1 parent 4858816e2a
commit 9507b064b4
3 files changed
+71 -23

No files matched your search

+5
View File
@@ -280,6 +280,11 @@ TEST_CASE("JFJochXFELReader_GeometryMasks", "[portable]") {
std::vector<uint16_t> mask(2 * 24, 0);
mask[1 * 6 + 1] = 0x20; // frame 0 only, (fs 1, ss 1): a bit Cheetah's own set does not include
WriteFrames(f, "entry_1/data_1/mask", H5T_NATIVE_UINT16, mask.data(), {2, 4, 6});
// Frame 1's mask chunk is stored with both its filters skipped: HDF5 reads that one.
const hid_t ds = H5Dopen2(f, "entry_1/data_1/mask", H5P_DEFAULT);
const hsize_t offset[3] = {1, 0, 0};
REQUIRE(H5Dwrite_chunk(ds, H5P_DEFAULT, 0x3, offset, 24 * sizeof(uint16_t), mask.data() + 24) >= 0);
H5Dclose(ds);
const std::string det = "entry_1/instrument_1/detector_1/";
std::vector<uint16_t> shared(24, 0);
shared[3 * 6 + 5] = 8; // (fs 5, ss 3) dead to Cheetah