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:
@@ -4,6 +4,8 @@
|
||||
#include "HDF5ImageSource.h"
|
||||
#include "../common/JFJochException.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
@@ -97,22 +99,26 @@ HDF5ImageSource::GetDataset(const HDF5ImageLocator::Location &loc) const {
|
||||
HDF5DataType datatype(*entry.dataset);
|
||||
HDF5Dcpl dcpl(*entry.dataset);
|
||||
|
||||
if (dataspace.GetNumOfDimensions() != 3)
|
||||
const auto rank = dataspace.GetNumOfDimensions();
|
||||
if (rank != 3 && rank != 4)
|
||||
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
|
||||
loc.dataset + " dataset must be 3D");
|
||||
loc.dataset + " dataset must be 3D or 4D");
|
||||
entry.multichannel = (rank == 4);
|
||||
|
||||
if (datatype.IsFloat())
|
||||
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
|
||||
"Float datasets not supported at this time");
|
||||
|
||||
auto dim = dataspace.GetDimensions();
|
||||
entry.height = dim[1];
|
||||
entry.width = dim[2];
|
||||
entry.height = dim[rank - 2];
|
||||
entry.width = dim[rank - 1];
|
||||
entry.mode = CalcImageMode(datatype.GetElemSize(), datatype.IsFloat(), datatype.IsSigned());
|
||||
|
||||
// One chunk per image: [1, h, w], or [1, 1, h, w] for a multichannel dataset
|
||||
auto chunk_size = dcpl.GetChunking();
|
||||
entry.direct_chunk = (chunk_size.size() == 3) && (chunk_size[0] == 1)
|
||||
&& (chunk_size[1] == dim[1]) && (chunk_size[2] == dim[2]);
|
||||
entry.direct_chunk = (chunk_size.size() == rank)
|
||||
&& std::all_of(chunk_size.begin(), chunk_size.end() - 2, [](hsize_t c) { return c == 1; })
|
||||
&& (chunk_size[rank - 2] == entry.height) && (chunk_size[rank - 1] == entry.width);
|
||||
if (entry.direct_chunk)
|
||||
entry.algorithm = dcpl.GetCompression();
|
||||
|
||||
@@ -155,7 +161,9 @@ HDF5ImageSource::PrepareDirectRead(const HDF5ImageLocator::Location &loc) const
|
||||
if (!ds.raw)
|
||||
return {};
|
||||
|
||||
const hsize_t coord[3] = {static_cast<hsize_t>(loc.local_index), 0, 0};
|
||||
const hsize_t coord_3d[3] = {loc.local_index, 0, 0};
|
||||
const hsize_t coord_4d[4] = {loc.local_index, loc.channel, 0, 0};
|
||||
const hsize_t *coord = ds.multichannel ? coord_4d : coord_3d;
|
||||
unsigned filter_mask = 0;
|
||||
haddr_t address = HADDR_UNDEF;
|
||||
hsize_t size = 0;
|
||||
|
||||
Reference in New Issue
Block a user