From 6b95600260d5e82db51ca252eb043d6ed07b0338 Mon Sep 17 00:00:00 2001 From: leonarski_f Date: Fri, 19 Jun 2026 10:38:24 +0200 Subject: [PATCH] writer: link ROI results into the VDS master file In VDS mode the per-image ROI results (max/sum/sum_sq/npixel/x/y) are written into the data files but were not exposed in the master, so a VDS master surfaced no ROI statistics. Add virtual datasets under /entry/roi/ in LinkToData_VDS, one group per ROI, mirroring how the spot-finding and azimuthal-integration arrays are linked. Integrated and legacy formats are unaffected (the results are already reachable there). Extended the reader round-trip test to write real ROI results and check they read back from the master for both VDS and integrated formats. Co-Authored-By: Claude Opus 4.8 --- docs/HDF5.md | 4 +++- tests/JFJochReaderTest.cpp | 10 ++++++++++ writer/HDF5NXmx.cpp | 16 ++++++++++++++++ 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/docs/HDF5.md b/docs/HDF5.md index b0e285c5..ddfc52b2 100644 --- a/docs/HDF5.md +++ b/docs/HDF5.md @@ -322,7 +322,9 @@ In the master file these per-image groups are exposed through `/entry/reflection ### 4.4 `/entry/roi` — regions of interest (per-image results) `/entry/roi/` has one sub-group per configured ROI, holding the **per-image result -vectors** `[n_images]` (in the data files): +vectors** `[n_images]`. These are written into the data files; in VDS mode they are exposed from +the master file through virtual datasets, and in integrated mode they are in the single file. +(In legacy mode they remain only in the data files.) | Dataset | Meaning | |---------|---------| diff --git a/tests/JFJochReaderTest.cpp b/tests/JFJochReaderTest.cpp index 92d750d3..91dc0bf3 100644 --- a/tests/JFJochReaderTest.cpp +++ b/tests/JFJochReaderTest.cpp @@ -288,6 +288,9 @@ TEST_CASE("JFJochReader_ROIDefinitions", "[HDF5][Full]") { DataMessage message{}; message.image = CompressedImage(image, x.GetXPixelsNum(), x.GetYPixelsNum()); message.number = 0; + for (const auto &name : {"mybox", "mycircle", "mywedge"}) + message.roi[name] = ROIMessage{.sum = 100, .sum_square = 1000, .max_count = 50, + .pixels = 10, .x_weighted = 500, .y_weighted = 600}; REQUIRE_NOTHROW(file_set.WriteHDF5(message)); generator.Add(message); @@ -319,6 +322,13 @@ TEST_CASE("JFJochReader_ROIDefinitions", "[HDF5][Full]") { CHECK(dataset->roi_map.size() == x.GetXPixelsNumConv() * x.GetYPixelsNumConv()); CHECK(dataset->roi_bit_index.size() == 3); CHECK(dataset->roi_bit_index.at("mybox") == 0); + + // per-image ROI results surface from the master (VDS-linked for VDS format) + REQUIRE(dataset->roi.size() == 3); + auto it = std::find(dataset->roi.begin(), dataset->roi.end(), "mybox"); + REQUIRE(it != dataset->roi.end()); + const size_t idx = std::distance(dataset->roi.begin(), it); + CHECK(dataset->roi_sum.at(idx).at(0) == 100); } remove("test_roi_master.h5"); remove("test_roi_data_000001.h5"); diff --git a/writer/HDF5NXmx.cpp b/writer/HDF5NXmx.cpp index fc776102..1da5057f 100644 --- a/writer/HDF5NXmx.cpp +++ b/writer/HDF5NXmx.cpp @@ -160,6 +160,22 @@ void NXmx::LinkToData_VDS(const StartMessage &start, const EndMessage &end) { } } + if (!start.rois.empty()) { + // Per-image ROI results live in the data files; expose them in the master + // through virtual datasets, one /entry/roi/ group per ROI. + HDF5Group(*hdf5_file, "/entry/roi").NXClass("NXcollection"); + for (const auto &r: start.rois) { + const std::string base = "/entry/roi/" + r.name; + HDF5Group(*hdf5_file, base); + VDS(start, base + "/max", {total_images}, HDF5DataType((int64_t) 0)); + VDS(start, base + "/sum", {total_images}, HDF5DataType((int64_t) 0)); + VDS(start, base + "/sum_sq", {total_images}, HDF5DataType((int64_t) 0)); + VDS(start, base + "/npixel", {total_images}, HDF5DataType((int64_t) 0)); + VDS(start, base + "/x", {total_images}, HDF5DataType((float) 0)); + VDS(start, base + "/y", {total_images}, HDF5DataType((float) 0)); + } + } + if (start.xfel_pulse_id.value_or(false)) { HDF5Group(*hdf5_file, "/entry/xfel").NXClass("NXcollection"); VDS(start, "/entry/xfel/pulseID", {total_images}, HDF5DataType((uint64_t) 0));