Panel id on spots and the panel table in the start message

SpotToSave gains int16_t panel (-1 = no panel table). It sits in the padding
after the two bools, so sizeof(SpotToSave) stays 80. It is serialised only
where it is set: CBOR spot key "panel", HDF5 /entry/MX/peakPanel (data file,
plus a virtual dataset in a VDS master when the start message has panels),
read back by HDF5MetadataSource. For a flat detector none of these is written,
so files and streams for existing data are byte-for-byte unchanged.

The start message carries the panel table (detector_modules, CBOR key absent
when empty), filled from the experiment; JFJochHttpReader takes it, so a
stream viewer knows the panels too.

AssignModules takes the spot's panel id where it has one - the stored pixel box
it was found in - and falls back to the plane position otherwise (every spot
until per-panel spot finding sets the id).

Reflection deliberately gets no panel id (owner decision): it is needed only
between prediction and integration, and the struct feeds GPU layout and
memory budgets.

Tests: CBORSerialize_SpotPanelId, CBORSerialize_StartDetectorModules,
JFJochReader_PanelId (VDS/legacy/integrated, with and without panels).

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-21 10:28:23 +02:00
1 parent c8fb472f4d
commit dc784c073d
15 files changed
+274 -4

No files matched your search

+1
View File
@@ -652,6 +652,7 @@ SpotFindingSettings DiffractionExperiment::DefaultDataProcessingSettings() {
void DiffractionExperiment::FillMessage(StartMessage &message) const {
message.images_per_file = GetImagesPerFile();
message.detector_modules = GetModules().Get();
message.beam_center_x = GetBeamX_pxl();
message.beam_center_y = GetBeamY_pxl();
const auto direct_beam = GetDiffractionGeometry().GetDirectBeam_pxl();
+5
View File
@@ -24,6 +24,7 @@
#include "CrystalLattice.h"
#include "IndexingSettings.h"
#include "XrayFluorescenceSpectrum.h"
#include "DetectorModules.h"
#include "../gemmi_gph/gemmi/symmetry.hpp"
constexpr const uint64_t user_data_release = 6;
@@ -324,6 +325,10 @@ struct StartMessage {
// Per-pixel ROI bitmask (converted geometry), bit i set for ROI i in rois.
std::vector<uint16_t> roi_map;
// The detector's panels (DetectorModules.h), where the image's pixels are on the detector plane. Empty
// for one flat detector, the image being the plane; then the CBOR key is absent.
std::vector<DetectorModule> detector_modules;
std::map<std::string, float> threshold_energy;
std::optional<float> total_flux;
+1
View File
@@ -18,6 +18,7 @@ struct SpotToSave {
float dist_ewald_sphere = 0.0;
bool ice_ring = false;
bool indexed = false;
int16_t panel = -1; // index into the experiment's DetectorModules; -1 = no panel table
Coord ReciprocalCoord(const DiffractionGeometry &experiment) const;
};
+2
View File
@@ -32,6 +32,7 @@ There are minor differences at the moment:
| mirror_y | bool | Whether the assembled image is mirrored in Y relative to the detector's raw readout order. True is the MX convention - row 0 at the top of the detector seen from the sample - and is what absence of the key means | |
| detector_orientation_mirror_y | bool | Whether the assembled image is mirrored in Y relative to the frame the PONI angles are stated in. A different setting from `mirror_y` above, which is about the module layout; this one changes no pixel. Absence means false | |
| detector_orientation_quarter_turns | int | How many multiples of 90 degrees about the beam the assembled image is turned by, relative to the frame the PONI angles are stated in (0-3). Absence means 0 | |
| detector_modules | Array(object) (optional) | Panels: where the image's pixels lie on the detector plane the geometry describes. Each has `x0`, `y0`, `width`, `height` (int, the panel's box in the image) and `ox`, `oy`, `fx`, `fy`, `sx`, `sy` (double, plane pixels): image pixel (x, y) of the panel is at `(ox, oy) + (x - x0) (fx, fy) + (y - y0) (sx, sy)`. Absent for a flat detector, the image being the plane; spot and reflection positions are always plane coordinates | |
| incident_energy | float | X-ray energy \[eV\] | X |
| incident_wavelength | float | X-ray wavelength \[Angstrom\] | X |
| incident_wavelength_spread | float (optional) | FWHM of the X-ray wavelength distribution \[Angstrom\] (NXmx incident_wavelength_spread); omitted when the beam is monochromatic | |
@@ -150,6 +151,7 @@ See [DECTRIS documentation](https://github.com/dectris/documentation/tree/main/s
| - indexed | bool | indexed solution | | |
| - latt | int64 | Lattice to which the peak belongs (negative number = not indexed) | | |
| - image | int64 | image number the spot belongs to | | |
| - panel | int64 (optional) | panel (index into `detector_modules`) the spot was found on; absent for a detector without a panel table | | |
| - h | int64 | Miller index (indexed spots only) | | |
| - k | int64 | Miller index (indexed spots only) | | |
| - l | int64 | Miller index (indexed spots only) | | |
+1
View File
@@ -342,6 +342,7 @@ In legacy/VDS mode these live in the data files and are linked/virtual-stacked i
| `peakDistEwaldSphere` | Å⁻¹ | distance of the spot from the Ewald sphere | ✓ |
| `peakIndexed` | | spot fits the indexing solution | ✓ |
| `peakLattice` | | lattice the spot belongs to (`-1` = unindexed) | ✓ |
| `peakPanel` | | panel the spot was found on (`-1` = none); written only for a detector with a panel table | |
**Per-image vectors `[n_images]`:**
@@ -59,6 +59,16 @@ namespace {
throw JFJochException(JFJochExceptionCategory::CBORError, "Float expected");
}
double GetCBORDouble(CborValue &value) {
if (cbor_value_is_double(&value)) {
double tmp;
cborErr(cbor_value_get_double(&value, &tmp));
cborErr(cbor_value_advance(&value));
return tmp;
}
return GetCBORFloat(value);
}
bool GetCBORBool(CborValue &value) {
if (!cbor_value_is_boolean(&value)) {
throw JFJochException(JFJochExceptionCategory::CBORError,
@@ -514,6 +524,8 @@ namespace {
s.dist_ewald_sphere = GetCBORFloat(map_value);
else if (key == "image")
s.image = GetCBORInt(map_value);
else if (key == "panel")
s.panel = static_cast<int16_t>(GetCBORInt(map_value));
else
cbor_value_advance(&map_value);
}
@@ -1299,6 +1311,45 @@ namespace {
}
}
void GetDetectorModules(CborValue &value, std::vector<DetectorModule> &modules) {
const size_t array_len = GetCBORArrayLen(value);
CborValue array_value;
cborErr(cbor_value_enter_container(&value, &array_value));
for (size_t i = 0; i < array_len; i++) {
DetectorModule m;
CborValue map_value;
cborErr(cbor_value_enter_container(&array_value, &map_value));
while (!cbor_value_at_end(&map_value)) {
const auto key = GetCBORString(map_value);
if (key == "x0")
m.x0 = GetCBORInt(map_value);
else if (key == "y0")
m.y0 = GetCBORInt(map_value);
else if (key == "width")
m.width = GetCBORInt(map_value);
else if (key == "height")
m.height = GetCBORInt(map_value);
else if (key == "ox")
m.ox = GetCBORDouble(map_value);
else if (key == "oy")
m.oy = GetCBORDouble(map_value);
else if (key == "fx")
m.fx = GetCBORDouble(map_value);
else if (key == "fy")
m.fy = GetCBORDouble(map_value);
else if (key == "sx")
m.sx = GetCBORDouble(map_value);
else if (key == "sy")
m.sy = GetCBORDouble(map_value);
else
cbor_value_advance(&map_value);
}
cborErr(cbor_value_leave_container(&array_value, &map_value));
modules.push_back(m);
}
cborErr(cbor_value_leave_container(&value, &array_value));
}
bool ProcessStartMessageElement(StartMessage &message, CborValue &value) {
if (cbor_value_at_end(&value))
return false;
@@ -1370,6 +1421,8 @@ namespace {
ProcessAzintMapElement(message, value);
else if (key == "roi_map")
ProcessROIMapElement(message, value);
else if (key == "detector_modules")
GetDetectorModules(value, message.detector_modules);
else if (key == "channels")
GetCBORStringArray(value, message.channels);
else if (key == "detector_translation")
+30
View File
@@ -238,6 +238,8 @@ inline void CBOR_ENC(CborEncoder &encoder, const SpotToSave& spot) {
CBOR_ENC(mapEncoder, "indexed", spot.indexed);
CBOR_ENC(mapEncoder, "latt", spot.lattice);
CBOR_ENC(mapEncoder, "image", spot.image);
if (spot.panel >= 0)
CBOR_ENC(mapEncoder, "panel", static_cast<int64_t>(spot.panel));
if (spot.indexed) {
CBOR_ENC(mapEncoder, "h", spot.h);
CBOR_ENC(mapEncoder, "k", spot.k);
@@ -484,6 +486,33 @@ inline void CBOR_ENC_AZINT_MAP(CborEncoder &encoder, const StartMessage &msg) {
CBOR_ENC_2D_TYPED_ARRAY(encoder, image);
}
// Not a DECTRIS field. Absent for a flat detector (no panel table), which is what every stream written
// before the key existed means.
inline void CBOR_ENC_DETECTOR_MODULES(CborEncoder &encoder, const std::vector<DetectorModule> &modules) {
if (modules.empty())
return;
CborEncoder arrayEncoder;
cborErr(cbor_encode_text_stringz(&encoder, "detector_modules"));
cborErr(cbor_encoder_create_array(&encoder, &arrayEncoder, modules.size()));
for (const auto &m: modules) {
CborEncoder mapEncoder;
cborErr(cbor_encoder_create_map(&arrayEncoder, &mapEncoder, 10));
CBOR_ENC(mapEncoder, "x0", m.x0);
CBOR_ENC(mapEncoder, "y0", m.y0);
CBOR_ENC(mapEncoder, "width", m.width);
CBOR_ENC(mapEncoder, "height", m.height);
const std::pair<const char *, double> placement[] = {
{"ox", m.ox}, {"oy", m.oy}, {"fx", m.fx}, {"fy", m.fy}, {"sx", m.sx}, {"sy", m.sy}
};
for (const auto &[key, val]: placement) {
cborErr(cbor_encode_text_stringz(&mapEncoder, key));
cborErr(cbor_encode_double(&mapEncoder, val));
}
cborErr(cbor_encoder_close_container(&arrayEncoder, &mapEncoder));
}
cborErr(cbor_encoder_close_container(&encoder, &arrayEncoder));
}
inline void CBOR_ENC_ROI_MAP(CborEncoder &encoder, const StartMessage &msg) {
if (msg.roi_map.empty())
return;
@@ -835,6 +864,7 @@ void CBORStream2Serializer::SerializeSequenceStart(const StartMessage& message)
CBOR_ENC_PIXEL_MASK(mapEncoder, message);
CBOR_ENC_AZINT_MAP(mapEncoder, message);
CBOR_ENC_ROI_MAP(mapEncoder, message);
CBOR_ENC_DETECTOR_MODULES(mapEncoder, message.detector_modules);
CBOR_ENC(mapEncoder, "channels", message.channels);
CBOR_ENC(mapEncoder, "max_spot_count", message.max_spot_count);
+9
View File
@@ -1291,6 +1291,13 @@ static void ReadSpotsFromFiles(HDF5Object &master_file,
{master_image, 0}, {source_image, 0}, {1, spot_count}
);
// Written only for a detector with a panel table.
auto spot_panel = ReadVectorMasterFirst<int16_t>(
master_file, source_file,
"/entry/MX/peakPanel",
{master_image, 0}, {source_image, 0}, {1, spot_count}
);
message.spots.reserve(message.spots.size() + spot_count);
for (size_t i = 0; i < spot_count; i++) {
const auto x = spot_x.at(i);
@@ -1317,6 +1324,8 @@ static void ReadSpotsFromFiles(HDF5Object &master_file,
s.ice_ring = (spot_ice.at(i) != 0);
if (spot_lattice.size() > i)
s.lattice = spot_lattice.at(i);
if (spot_panel.size() > i)
s.panel = spot_panel.at(i);
message.spots.emplace_back(s);
}
+6 -4
View File
@@ -89,12 +89,14 @@ using namespace rugnux_internal;
namespace {
// The module of each spot, by where it lies on the detector plane (spots are on the plane already).
// The module of each spot: the panel the spot finder found it on, or - where the spot carries no panel id -
// the module where it lies on the detector plane (spots are on the plane already).
void AssignModules(std::vector<GeomRefineFrame> &frames, const DetectorModules &modules) {
for (auto &f: frames)
for (auto *list: {&f.spots, &f.unindexed})
for (auto &s: *list)
s.module = static_cast<int16_t>(modules.ModuleOfPlanePoint(s.x, s.y));
if (s.module < 0)
s.module = static_cast<int16_t>(modules.ModuleOfPlanePoint(s.x, s.y));
}
} // namespace
@@ -217,9 +219,9 @@ void Rugnux::RefineStillsGeometry(int start_image, int end_image, int images_to_
for (const auto &s : msg.spots) {
if (s.indexed && s.lattice == 0)
f.spots.push_back(GeomRefineSpot{s.x, s.y,
static_cast<int32_t>(s.h), static_cast<int32_t>(s.k), static_cast<int32_t>(s.l)});
static_cast<int32_t>(s.h), static_cast<int32_t>(s.k), static_cast<int32_t>(s.l), s.panel});
else
f.unindexed.push_back(GeomRefineSpot{s.x, s.y});
f.unindexed.push_back(GeomRefineSpot{s.x, s.y, 0, 0, 0, s.panel});
}
if (f.spots.size() >= 6) {
if (static_cast<int>(f.spots.size()) >= MIN_STRONG_SPOTS)
+81
View File
@@ -1,6 +1,7 @@
// SPDX-FileCopyrightText: 2024 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
// SPDX-License-Identifier: GPL-3.0-only
#include <algorithm>
#include <catch2/catch_all.hpp>
#include "../frame_serialize/CBORStream2Serializer.h"
@@ -1507,3 +1508,83 @@ TEST_CASE("CBORDeserialize_Start_CompressedLookupTable", "[CBOR]") {
REQUIRE(deserialized->start_message);
CHECK(deserialized->start_message->countrate_correction_lookup_table == lut);
}
// The panel id of a spot is a CBOR key only for a detector with a panel table: a spot with panel -1
// serialises to the same bytes as before the key existed.
TEST_CASE("CBORSerialize_SpotPanelId", "[CBOR][PanelId]") {
std::vector<uint8_t> buffer(1 << 20);
const std::string key = "panel";
std::vector<uint16_t> test(512);
CompressedImage image(test, 256, 2);
auto serialize = [&](int16_t p0, int16_t p1) {
CBORStream2Serializer serializer(buffer.data(), buffer.size());
DataMessage message{
.number = 1,
.image = image,
.spots = {SpotToSave{.x = 7, .y = 8, .intensity = 34, .panel = p0},
SpotToSave{.x = 37, .y = 48, .intensity = 123, .panel = p1}}
};
serializer.SerializeImage(message);
return std::vector<uint8_t>(buffer.begin(), buffer.begin() + serializer.GetBufferSize());
};
const auto absent = serialize(-1, -1);
CHECK(std::search(absent.begin(), absent.end(), key.begin(), key.end()) == absent.end());
auto deserialized = CBORStream2Deserialize(absent.data(), absent.size());
REQUIRE(deserialized->data_message);
REQUIRE(deserialized->data_message->spots.size() == 2);
CHECK(deserialized->data_message->spots[0].panel == -1);
CHECK(deserialized->data_message->spots[1].panel == -1);
const auto present = serialize(3, 0);
CHECK(std::search(present.begin(), present.end(), key.begin(), key.end()) != present.end());
deserialized = CBORStream2Deserialize(present.data(), present.size());
REQUIRE(deserialized->data_message);
REQUIRE(deserialized->data_message->spots.size() == 2);
CHECK(deserialized->data_message->spots[0].panel == 3);
CHECK(deserialized->data_message->spots[1].panel == 0);
CHECK(deserialized->data_message->spots[1].x == 37);
}
// The start message carries the panel table only when there is one.
TEST_CASE("CBORSerialize_StartDetectorModules", "[CBOR][PanelId]") {
std::vector<uint8_t> buffer(8 * 1024 * 1024);
const std::string key = "detector_modules";
StartMessage message{};
message.image_size_x = 256;
message.image_size_y = 128;
{
CBORStream2Serializer serializer(buffer.data(), buffer.size());
serializer.SerializeSequenceStart(message);
CHECK(std::search(buffer.begin(), buffer.begin() + serializer.GetBufferSize(), key.begin(), key.end())
== buffer.begin() + serializer.GetBufferSize());
auto deserialized = CBORStream2Deserialize(buffer.data(), serializer.GetBufferSize());
REQUIRE(deserialized->start_message);
CHECK(deserialized->start_message->detector_modules.empty());
}
DetectorModule turned{.x0 = 0, .y0 = 64, .width = 256, .height = 64,
.ox = 300.25, .oy = -12.5, .fx = 0, .fy = 1, .sx = -1, .sy = 0};
message.detector_modules = {DetectorModule::AsImaged(0, 0, 256, 64), turned};
{
CBORStream2Serializer serializer(buffer.data(), buffer.size());
serializer.SerializeSequenceStart(message);
auto deserialized = CBORStream2Deserialize(buffer.data(), serializer.GetBufferSize());
REQUIRE(deserialized->start_message);
const auto &m = deserialized->start_message->detector_modules;
REQUIRE(m.size() == 2);
CHECK(m[0].x0 == 0);
CHECK(m[0].height == 64);
CHECK(m[0].fx == 1);
CHECK(m[1].y0 == 64);
CHECK(m[1].width == 256);
CHECK(m[1].ox == 300.25);
CHECK(m[1].oy == -12.5);
CHECK(m[1].fx == 0);
CHECK(m[1].fy == 1);
CHECK(m[1].sx == -1);
CHECK(m[1].sy == 0);
}
}
+72
View File
@@ -4931,3 +4931,75 @@ TEST_CASE("JFJochXTCReader", "[portable]") {
std::filesystem::remove_all("xtc_test");
}
// The panel id of spots goes to /entry/MX/peakPanel only for a detector with a panel table; for a flat
// detector the dataset is not written, so such files are unchanged.
TEST_CASE("JFJochReader_PanelId", "[HDF5][PanelId]") {
const auto format = GENERATE(FileWriterFormat::NXmxVDS, FileWriterFormat::NXmxLegacy,
FileWriterFormat::NXmxIntegrated);
const bool panels = GENERATE(true, false);
INFO("format " << static_cast<int>(format) << " panels " << panels);
DiffractionExperiment x(DetJF(1));
x.FilePrefix("test_panel_id").ImagesPerTrigger(2).ImagesPerFile(10).OverwriteExistingFiles(true)
.BitDepthImage(16).PixelSigned(true).SetFileWriterFormat(format)
.IndexingAlgorithm(IndexingAlgorithmEnum::FFT).Compression(CompressionAlgorithm::NO_COMPRESSION);
if (panels)
x.Modules(DetectorModules({DetectorModule::AsImaged(0, 0, x.GetXPixelsNum(), x.GetYPixelsNum() / 2),
DetectorModule::AsImaged(0, x.GetYPixelsNum() / 2, x.GetXPixelsNum(),
x.GetYPixelsNum() / 2)}));
const int16_t p0 = panels ? 0 : -1;
const int16_t p1 = panels ? 1 : -1;
std::vector<int16_t> image(x.GetPixelsNum());
RegisterHDF5Filter();
{
StartMessage start_message;
x.FillMessage(start_message);
CHECK(start_message.detector_modules.size() == (panels ? 2 : 0));
FileWriter file_set(start_message);
for (int i = 0; i < 2; i++) {
DataMessage message{};
message.number = i;
message.image = CompressedImage(image, x.GetXPixelsNum(), x.GetYPixelsNum());
message.indexing_result = true;
message.indexing_lattice = CrystalLattice(40, 50, 60, 90, 90, 90);
message.spots = {SpotToSave{.x = 10, .y = 50, .intensity = 80, .panel = p0},
SpotToSave{.x = 20, .y = 400, .intensity = 90, .panel = p1}};
REQUIRE_NOTHROW(file_set.WriteHDF5(message));
}
EndMessage end_message;
end_message.max_image_number = 2;
file_set.WriteHDF5(end_message);
file_set.Finalize();
}
{
HDF5ReadOnlyFile master("test_panel_id_master.h5");
const bool separate_data = format != FileWriterFormat::NXmxIntegrated;
// The master of a VDS set exposes it as a virtual dataset, the integrated file holds it itself
CHECK(master.Exists("/entry/MX/peakPanel") == (panels && format != FileWriterFormat::NXmxLegacy));
if (separate_data) {
HDF5ReadOnlyFile data("test_panel_id_data_000001.h5");
CHECK(data.Exists("/entry/MX/peakPanel") == panels);
}
}
{
JFJochHDF5Reader reader;
REQUIRE_NOTHROW(reader.ReadFile("test_panel_id_master.h5"));
for (int i = 0; i < 2; i++) {
std::shared_ptr<JFJochReaderImage> reader_image;
REQUIRE_NOTHROW(reader_image = reader.LoadImage(i));
REQUIRE(reader_image);
const auto &spots = reader_image->ImageData().spots;
REQUIRE(spots.size() == 2);
CHECK(spots[0].panel == p0);
CHECK(spots[1].panel == p1);
}
}
remove("test_panel_id_master.h5");
remove("test_panel_id_data_000001.h5");
REQUIRE(H5Fget_obj_count(H5F_OBJ_ALL, H5F_OBJ_ALL) == 0);
}
+2
View File
@@ -224,6 +224,8 @@ std::shared_ptr<JFJochReaderDataset> JFJochHttpReader::UpdateDataset_i() {
detector.MinCountTime(std::chrono::microseconds(0));
detector.ReadOutTime(std::chrono::microseconds (0));
dataset->experiment.Detector(detector);
// Absent (empty) for a flat detector, the image being the detector plane
dataset->experiment.Modules(DetectorModules(msg->start_message->detector_modules));
dataset->experiment.FrameTime(
std::chrono::microseconds(std::lround(msg->start_message->frame_time * 1e6)),
+7
View File
@@ -67,6 +67,7 @@ void HDF5DataFilePluginMX::OpenFile(HDF5File &data_file, const DataMessage &msg,
spot_k.reserve(max_spots * images_per_file);
spot_l.reserve(max_spots * images_per_file);
spot_dist_ewald.reserve(max_spots * images_per_file);
spot_panel.reserve(max_spots * images_per_file);
if (indexing) {
spot_indexed.reserve(max_spots * images_per_file);
@@ -120,6 +121,7 @@ void HDF5DataFilePluginMX::Write(const DataMessage &msg, uint64_t image_number)
spot_l.resize(max_spots * (max_image_number + 1));
spot_lattice.resize(max_spots * (max_image_number + 1), -1);
spot_dist_ewald.resize(max_spots * (max_image_number + 1), NAN);
spot_panel.resize(max_spots * (max_image_number + 1), -1);
if (indexing) {
spot_indexed.resize(max_spots * (max_image_number + 1));
@@ -134,6 +136,9 @@ void HDF5DataFilePluginMX::Write(const DataMessage &msg, uint64_t image_number)
spot_x[max_spots * image_number + i] = msg.spots[i].x;
spot_y[max_spots * image_number + i] = msg.spots[i].y;
spot_int[max_spots * image_number + i] = msg.spots[i].intensity;
spot_panel[max_spots * image_number + i] = msg.spots[i].panel;
if (msg.spots[i].panel >= 0)
spot_panel_present = true;
if (indexing) {
spot_indexed[max_spots * image_number + i] = msg.spots[i].indexed;
spot_lattice[max_spots * image_number + i] = msg.spots[i].lattice;
@@ -213,6 +218,8 @@ void HDF5DataFilePluginMX::WriteFinal(HDF5File &data_file) {
data_file.SaveVector("/entry/MX/peakTotalIntensity", spot_int, {(hsize_t) (max_image_number + 1), max_spots});
data_file.SaveVector("/entry/MX/peakIceRingRes", spot_ice_ring, {(hsize_t) (max_image_number + 1), max_spots});
data_file.SaveVector("/entry/MX/nPeaks", npeaks.vec());
if (spot_panel_present)
data_file.SaveVector("/entry/MX/peakPanel", spot_panel, {(hsize_t) (max_image_number + 1), max_spots});
if (indexing) {
data_file.SaveVector("/entry/MX/peakH", spot_h, {(hsize_t) (max_image_number + 1), max_spots});
+2
View File
@@ -21,6 +21,8 @@ class HDF5DataFilePluginMX : public HDF5DataFilePlugin {
std::vector<int32_t> spot_k;
std::vector<int32_t> spot_l;
std::vector<float> spot_dist_ewald;
std::vector<int16_t> spot_panel;
bool spot_panel_present = false; // written only for a detector with a panel table
AutoIncrVector<float> beam_corr_x{NAN};
AutoIncrVector<float> beam_corr_y{NAN};
+2
View File
@@ -132,6 +132,8 @@ void NXmx::LinkToData_VDS(const StartMessage &start, const EndMessage &end) {
VDS(start, "/entry/MX/peakTotalIntensity",{total_images, start.max_spot_count}, HDF5DataType(0.0f));
VDS(start, "/entry/MX/peakIceRingRes", {total_images, start.max_spot_count}, HDF5DataType(static_cast<int8_t>(0)));
VDS(start, "/entry/MX/nPeaks", {total_images}, HDF5DataType((uint32_t) 0));
if (!start.detector_modules.empty())
VDS(start, "/entry/MX/peakPanel", {total_images, start.max_spot_count}, HDF5DataType(static_cast<int16_t>(-1)), -1);
}
if (start.indexing_algorithm != IndexingAlgorithmEnum::None) {