reader/viewer: snapshot image->original map; subset runs register and overlay
Foundation for a dataset (snapshot or, later, the main file) being a subset of the truly collected images: - JFJochReaderDataset gains source_image_number (image index -> original image number; empty = identity). - HDF5MetadataSource reads /entry/detector/number into that map and an inverse (original -> local) map; FillPerImage / ReadSpots translate the requested global image to this source's local index via ToLocalIndex (return nothing if the image is not covered), so partial snapshots are correct and never read out of bounds. - RegisterSnapshot now accepts a snapshot with fewer images than the dataset (only rejects more), so sub-range / strided reprocessing runs register. - The dataset-info plot draws each run at its original image numbers (x map from source_image_number), so a subset run lands at the right place on the shared axis. The live run's map is filled from msg.original_number. This makes the foundation ready for strided / filtered selections (e.g. reprocess only images with >N spots) without restricting to a min-max sub-range. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -693,6 +693,23 @@ HDF5MetadataSource::OpenResult HDF5MetadataSource::Open(const std::string &filen
|
||||
|
||||
dataset->experiment.ImagesPerTrigger(number_of_images);
|
||||
cached_geom = dataset->experiment.GetDiffractionGeometry();
|
||||
|
||||
// Image-index -> original-image-number map (written as /entry/detector/number). When it is a
|
||||
// genuine subset/strided selection, keep it so plots and per-image lookups use the original
|
||||
// numbering; a plain 0..N-1 sequence is identity and left empty.
|
||||
image_to_local_.clear();
|
||||
auto numbers = master_file->ReadOptVector<uint64_t>("/entry/detector/number");
|
||||
if (numbers.size() == number_of_images) {
|
||||
bool identity = true;
|
||||
for (size_t i = 0; i < numbers.size(); i++)
|
||||
if (numbers[i] != i) { identity = false; break; }
|
||||
if (!identity) {
|
||||
dataset->source_image_number.assign(numbers.begin(), numbers.end());
|
||||
for (size_t i = 0; i < numbers.size(); i++)
|
||||
image_to_local_[static_cast<int64_t>(numbers[i])] = static_cast<int64_t>(i);
|
||||
}
|
||||
}
|
||||
|
||||
dataset_ = dataset;
|
||||
|
||||
return OpenResult{
|
||||
@@ -726,6 +743,15 @@ HDF5ImageLocator::Location HDF5MetadataSource::ResolveMeta(int64_t global) const
|
||||
return {master_file, static_cast<uint32_t>(global)};
|
||||
}
|
||||
|
||||
std::optional<int64_t> HDF5MetadataSource::ToLocalIndex(int64_t image_number) const {
|
||||
if (image_to_local_.empty())
|
||||
return image_number; // 1:1 source (identity)
|
||||
const auto it = image_to_local_.find(image_number);
|
||||
if (it == image_to_local_.end())
|
||||
return std::nullopt; // this source does not cover that image
|
||||
return it->second;
|
||||
}
|
||||
|
||||
// Reads spot data for a single image from the appropriate HDF5 source.
|
||||
// master_image / source_image are the logical indices within master_file and
|
||||
// source_file respectively (identical for NXmxVDS contiguous / integrated;
|
||||
@@ -852,8 +878,13 @@ static void ReadSpotsFromFiles(HDF5Object &master_file,
|
||||
GenerateSpotPlot(message, 1.5);
|
||||
}
|
||||
|
||||
void HDF5MetadataSource::FillPerImage(DataMessage &message, int64_t image_number,
|
||||
void HDF5MetadataSource::FillPerImage(DataMessage &message, int64_t requested_image,
|
||||
const std::shared_ptr<const JFJochReaderDataset> &dataset) const {
|
||||
const auto local_opt = ToLocalIndex(requested_image);
|
||||
if (!local_opt)
|
||||
return; // this metadata source does not cover the requested image
|
||||
const int64_t image_number = *local_opt; // local index into this source (identity for 1:1)
|
||||
|
||||
auto loc = ResolveMeta(image_number);
|
||||
auto &source_file = loc.file;
|
||||
const uint32_t image_id = loc.local_index;
|
||||
@@ -862,7 +893,7 @@ void HDF5MetadataSource::FillPerImage(DataMessage &message, int64_t image_number
|
||||
const auto source_image = static_cast<hsize_t>(image_id);
|
||||
|
||||
ReadSpotsFromFiles(*master_file, *source_file, master_image, source_image,
|
||||
image_number, dataset->experiment.GetDiffractionGeometry(), message);
|
||||
requested_image, dataset->experiment.GetDiffractionGeometry(), message);
|
||||
|
||||
if (!dataset->az_int_bin_to_q.empty()) {
|
||||
if (dataset->azimuthal_bins == 0) {
|
||||
@@ -1094,10 +1125,16 @@ std::vector<IntegrationOutcome> HDF5MetadataSource::ReadReflections(size_t start
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<SpotToSave> HDF5MetadataSource::ReadSpots(int64_t image) const {
|
||||
if (image < 0)
|
||||
std::vector<SpotToSave> HDF5MetadataSource::ReadSpots(int64_t requested_image) const {
|
||||
if (requested_image < 0)
|
||||
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
|
||||
"image number must be non-negative");
|
||||
|
||||
const auto local_opt = ToLocalIndex(requested_image);
|
||||
if (!local_opt)
|
||||
return {}; // this (subset) source does not cover the requested image
|
||||
const int64_t image = *local_opt;
|
||||
|
||||
if (image >= number_of_images)
|
||||
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
|
||||
"image must be less than number_of_images");
|
||||
@@ -1107,17 +1144,17 @@ std::vector<SpotToSave> HDF5MetadataSource::ReadSpots(int64_t image) const {
|
||||
"Cannot read spots if file not loaded");
|
||||
|
||||
// Per-image spot/MX data, resolved the same way as the pixels (or in our own master at the
|
||||
// global index for an integrated _process.h5 snapshot).
|
||||
// local index for an integrated _process.h5 snapshot).
|
||||
const auto loc = ResolveMeta(image);
|
||||
HDF5Object *meta_file = loc.file.get();
|
||||
const size_t meta_image_id = loc.local_index;
|
||||
|
||||
DataMessage tmp_message;
|
||||
tmp_message.number = static_cast<int64_t>(image);
|
||||
tmp_message.number = requested_image;
|
||||
|
||||
ReadSpotsFromFiles(*master_file, *meta_file,
|
||||
image, meta_image_id,
|
||||
static_cast<int64_t>(image),
|
||||
requested_image,
|
||||
cached_geom,
|
||||
tmp_message);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user