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:
1 parent
c8fb472f4d
commit
dc784c073d
15 files changed
+274
-4
No files matched your search
@@ -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);
|
||||
}
|
||||
Reference in new issue
Block a user