Files
Jungfraujoch/reader/HDF5MetadataSource.h
T
leonarski_f b9f8c2b675 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>
2026-06-22 14:59:23 +02:00

78 lines
3.8 KiB
C++

// SPDX-FileCopyrightText: 2026 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
// SPDX-License-Identifier: GPL-3.0-only
#pragma once
#include <memory>
#include <optional>
#include <string>
#include <unordered_map>
#include <vector>
#include "JFJochReaderDataset.h"
#include "HDF5ImageSource.h"
#include "../common/JFJochMessages.h"
#include "../common/SpotToSave.h"
#include "../common/GoniometerAxis.h"
#include "../common/DiffractionExperiment.h"
#include "../common/DiffractionGeometry.h"
#include "../image_analysis/IntegrationOutcome.h"
// Metadata side of the reader: everything read from one master file that is NOT raw pixels -
// dataset-level metadata (geometry, mask, ROI definitions, azimuthal mapping, the per-image plot
// arrays) and per-image metadata (spots, reflections, MX scalars, azimuthal profile, lattice).
//
// This is the swappable part: a dataset can have several metadata sources over the same images
// (the original _master.h5 plus reprocessing _process.h5 snapshots). Per-image metadata is
// located either through the shared image source (original file: metadata sits in the same files
// as the pixels) or in this master at the global index (integrated _process.h5 snapshot).
//
// HDF5 is not thread-safe; all calls must be made with the global hdf5_mutex held by the caller.
class HDF5MetadataSource {
public:
struct OpenResult {
HDF5ImageLocator::Layout image_layout; // layout implied by this master (for the image source)
uint64_t number_of_images = 0;
};
// Parse a master file's dataset-level metadata into a JFJochReaderDataset. default_experiment
// seeds the dataset's experiment. Returns the image layout it implies; the caller decides
// whether to use it to configure the shared image source.
OpenResult Open(const std::string &filename, const DiffractionExperiment &default_experiment);
// How per-image metadata is located: with image_source set, metadata is co-located with the
// pixels (original file); when null it lives in this master at the global index.
void UseImageSourceForMetadata(const HDF5ImageSource *image_source) { image_source_ = image_source; }
std::shared_ptr<JFJochReaderDataset> Dataset() const { return dataset_; }
uint64_t NumberOfImages() const { return number_of_images; }
// Per-image metadata (spots, azimuthal profile, MX scalars, lattice, reflections) into msg.
void FillPerImage(DataMessage &message, int64_t image_number,
const std::shared_ptr<const JFJochReaderDataset> &dataset) const;
std::vector<SpotToSave> ReadSpots(int64_t image) const;
std::vector<IntegrationOutcome> ReadReflections(size_t start_image, std::optional<size_t> end_image) const;
CompressedImage ReadCalibration(std::vector<uint8_t> &tmp, const std::string &name) const;
private:
std::shared_ptr<HDF5ReadOnlyFile> master_file;
std::string master_filename;
std::shared_ptr<JFJochReaderDataset> dataset_;
DiffractionGeometry cached_geom;
uint64_t number_of_images = 0;
const HDF5ImageSource *image_source_ = nullptr;
// Inverse of dataset_->source_image_number (original image number -> local index in this
// master). Empty for a 1:1 source; populated when this metadata covers a subset of images.
std::unordered_map<int64_t, int64_t> image_to_local_;
// Translate a global/original image number to the local index in this metadata source, or
// nullopt if this source does not cover that image. Identity for a 1:1 source.
std::optional<int64_t> ToLocalIndex(int64_t image_number) const;
HDF5ImageLocator::Location ResolveMeta(int64_t global) const;
std::optional<GoniometerAxis> ReadAxis(HDF5Object *file, const std::string &name);
void ReadROIMetadata(HDF5ReadOnlyFile &file, JFJochReaderDataset &dataset) const;
};