From 1aeb7cfbe39fa8c4ce50aa6fcfc4df839d309000 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Fri, 31 Jul 2026 14:44:42 +0200 Subject: [PATCH] writer: clamp the processing VDS to the images actually written The processing VDS mapping is built from the number of images a run set out to process, while total_images comes from the end message and is the number it actually finished. Those differ whenever a run is cancelled or skips an unreadable frame, and the mismatch was a hard throw - which NXmx::Finalize catches by deleting the temporary master, so rugnux lost the entire _process.h5 and every completed image with it. Ctrl-C after 5000 of 100000 images produced no output file at all. Map what was written and drop the remainder instead. Co-Authored-By: Claude Opus 5 (1M context) --- writer/HDF5NXmx.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/writer/HDF5NXmx.cpp b/writer/HDF5NXmx.cpp index d0ff03e5..8cdffec1 100644 --- a/writer/HDF5NXmx.cpp +++ b/writer/HDF5NXmx.cpp @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: 2024 Filip Leonarski, Paul Scherrer Institute // SPDX-License-Identifier: GPL-3.0-only +#include #include #include "HDF5NXmx.h" @@ -210,9 +211,15 @@ void NXmx::LinkToData_ProcessingVDS(const StartMessage &start, const EndMessage if (mapping.image_count == 0) continue; - if (mapping.virtual_first_image + mapping.image_count > total_images) - throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, - "Processing VDS mapping exceeds output image count"); + // The mapping is built from the number of images the run intended to process, while + // total_images is the number it actually finished. A cancelled run, or one that skipped an + // unreadable frame, legitimately ends up with fewer - so map what was written and drop the + // rest. Rejecting the mismatch here would take the whole output file with it. + if (mapping.virtual_first_image >= total_images) + continue; + + const hsize_t image_count = std::min(static_cast(mapping.image_count), + total_images - mapping.virtual_first_image); const std::string source_dataset = mapping.dataset.empty() ? "/entry/data/data" @@ -221,14 +228,14 @@ void NXmx::LinkToData_ProcessingVDS(const StartMessage &start, const EndMessage HDF5DataSpace virtual_data_space({total_images, height, width}); virtual_data_space.SelectHyperslab( {static_cast(mapping.virtual_first_image), 0, 0}, - {static_cast(mapping.image_count), height, width} + {image_count, height, width} ); - const hsize_t source_extent_images = mapping.source_first_image + mapping.image_count; + const hsize_t source_extent_images = mapping.source_first_image + image_count; HDF5DataSpace source_data_space({source_extent_images, height, width}); source_data_space.SelectHyperslab( {static_cast(mapping.source_first_image), 0, 0}, - {static_cast(mapping.image_count), height, width} + {image_count, height, width} ); dcpl.SetVirtual(mapping.filename,