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/<name> 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 <noreply@anthropic.com>
This commit is contained in:
+3
-1
@@ -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/<roi_name>` 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 |
|
||||
|---------|---------|
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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/<name> 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));
|
||||
|
||||
Reference in New Issue
Block a user