Record the corrections a DECTRIS detector applied; read multichannel NXmx

The broker rebuilds the outgoing StartMessage from DiffractionExperiment,
and FillMessage hard-coded countrate_correction_enabled and
flatfield_enabled to false. JFJochReceiverLite parsed the true values from
the detector's stream2 start message and dropped them, so every DECTRIS
file written through the broker said neither correction was applied -
DECTRIS enables both by default. pixel_mask_applied had the same defect:
it reported the local apply_mask setting (an FPGA feature), not what the
detector did to the pixels, which ReceiverLite forwards byte for byte.

These now come from the stream: DetectorSetup carries them, ReceiverLite
copies them in Configure, FillMessage reads them. Two more fields the
DECTRIS stream sends and NXmx defines are passed through to the master
file: countrate_correction_lookup_table (uint32, possibly bslz4/bszstd
compressed in the stream) and virtual_pixel_interpolation_applied. The
flatfield is deliberately not written - it makes the master file too
large. PSI EIGER is unchanged: jfjoch never enables rate correction and
the detector server starts with it off.

The reader also opens the DECTRIS "hdf5 nexus v2024.2 nxmx" layout, where
/entry/data/data is 4D [image, channel, y, x] and the pixel mask is kept
per channel. Only the first channel is read; this is compatibility, not
full multichannel support. A _process.h5 made from such a file links its
pictures to that channel.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013nW6FNRP1bBJJ8pfHiByAT
This commit is contained in:
leonarski_fandClaude Opus 5.5 committed 2026-09-23 21:04:16 +02:00
1 parent 0252880e06
commit aea13044b5
18 files changed
+397 -31

No files matched your search

@@ -165,6 +165,12 @@ inline void CBOR_ENC(CborEncoder &encoder, const char* key, const std::vector<ui
cborErr(cbor_encode_byte_string(&encoder, v.data(), v.size() * sizeof(uint8_t)));
}
inline void CBOR_ENC(CborEncoder &encoder, const char* key, const std::vector<uint32_t>& v) {
cborErr(cbor_encode_text_stringz(&encoder, key));
cborErr(cbor_encode_tag(&encoder, TagUnsignedInt32BitLE));
cborErr(cbor_encode_byte_string(&encoder, reinterpret_cast<const uint8_t *>(v.data()), v.size() * sizeof(uint32_t)));
}
inline void CBOR_ENC(CborEncoder &encoder, const char* key, const std::vector<int32_t>& v) {
cborErr(cbor_encode_text_stringz(&encoder, key));
cborErr(cbor_encode_tag(&encoder, TagSignedInt32BitLE));
@@ -696,7 +702,10 @@ void CBORStream2Serializer::SerializeSequenceStart(const StartMessage& message)
CBOR_ENC(mapEncoder, "direct_beam_x", message.direct_beam_x);
CBOR_ENC(mapEncoder, "direct_beam_y", message.direct_beam_y);
CBOR_ENC(mapEncoder, "countrate_correction_enabled", message.countrate_correction_enabled);
if (!message.countrate_correction_lookup_table.empty())
CBOR_ENC(mapEncoder, "countrate_correction_lookup_table", message.countrate_correction_lookup_table);
CBOR_ENC(mapEncoder, "flatfield_enabled", message.flatfield_enabled);
CBOR_ENC(mapEncoder, "virtual_pixel_interpolation_enabled", message.virtual_pixel_interpolation_enabled);
CBOR_ENC(mapEncoder, "number_of_images", message.number_of_images);
CBOR_ENC(mapEncoder, "image_size_x", message.image_size_x);
CBOR_ENC(mapEncoder, "image_size_y", message.image_size_y);