Files
Jungfraujoch/reader/JFJochCrystFELReader.h
T
leonarski_fandClaude Opus 5.5 ce528f3a14 rugnux: read stills through a CrystFEL geometry file (--crystfel-geometry)
A CrystFEL .geom (current and old syntax) is parsed for panels (pixel ranges, fs/ss, corners),
clen/coffset (a number, or an HDF5 path read as mm), res, adu_per_eV/adu_per_photon, max_adu,
no_index, bad regions (panel, whole-frame or lab-plane) and the HDF5 mask (mask/mask_file,
mask_good/mask_bad). JFJochCrystFELReader reads the frames the geometry's data path names - a 3D
stack (Cheetah CXI), one 2D frame per file, or one group per shot (/%/data) - from a file or a
directory, puts the panels on one flat image at their rounded positions with gaps and bad regions
masked, and converts to photons where a gain is stated (otherwise the pre-scan measures it). One
wavelength and one camera length per run: values taken from the files are averaged over the first
file. Panel positions are used as given. Frames stored as one deflate(+shuffle) chunk are read raw
under the HDF5 lock and decoded outside it.

Replaces the MPCCD-specific reader of the previous commit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 15:09:56 +02:00

82 lines
3.4 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 <string>
#include <vector>
#include "JFJochReader.h"
#include "CrystFELGeometry.h"
class HDF5ReadOnlyFile;
// Reads serial (stills) frames from HDF5 files laid out the way CrystFEL reads them, placed on the
// detector by a CrystFEL geometry file: Cheetah CXI files with the frames stacked along the first
// dimension, files holding one frame each, or files with one group per shot (data = /%/data). The
// panels are put on one flat image at their geometry-file positions, rounded to whole pixels, with
// everything between them and every bad region masked. Pixel values are converted to photons with the
// geometry's gain where it states one, and are otherwise left in detector units.
//
// One wavelength and one camera length hold for the whole run: where the geometry takes either from
// the image files, it is the mean over the first file's frames.
//
// A path is one file, or a directory, every .h5/.cxi file of which is read in name order.
class JFJochCrystFELReader : public JFJochReader {
struct Frame {
size_t file;
std::string dataset;
int64_t index; // along the first dimension of a 3D dataset; -1 for a 2D one
std::string group; // the shot group the geometry's % stands for, if any
};
crystfel::Geometry geom_;
std::vector<std::string> files_;
std::vector<std::unique_ptr<HDF5ReadOnlyFile>> open_files_;
std::vector<Frame> frames_;
std::shared_ptr<JFJochReaderDataset> dataset_;
size_t frame_width_ = 0, frame_height_ = 0; // the stored frame
size_t width_ = 0, height_ = 0; // the flat image
// For every stored pixel, where it lands on the flat image (-1: nowhere) and what one photon reads.
std::vector<int64_t> destination_;
std::vector<float> adu_per_photon_;
bool counts_in_photons_ = false;
// Where every frame is stored as one deflated (and optionally byte-shuffled) chunk of a plain
// number type - the Cheetah outputs - the chunk is read raw under the HDF5 lock and decoded
// outside it, so decoding runs on every reading thread instead of one at a time.
bool direct_chunks_ = false;
bool shuffled_ = false;
bool stored_float_ = false, stored_signed_ = false;
size_t stored_size_ = 0;
void CheckDirectChunks();
double MeanOverFirstFile(const std::string &path);
bool LoadImage_i(std::shared_ptr<JFJochReaderDataset> &dataset,
DataMessage &message,
std::vector<uint8_t> &buffer,
int64_t image_number,
bool update_dataset) override;
template <class Buffer>
void DecodeInto(int64_t image_number, Buffer &buffer) const;
public:
JFJochCrystFELReader();
~JFJochCrystFELReader() override;
void ReadFiles(const std::string &path, const std::string &geometry_file);
// False where the geometry states no gain, so the images are in detector units, not photons.
[[nodiscard]] bool CountsInPhotons() const;
[[nodiscard]] uint64_t GetNumberOfImages() const override;
void Close() override;
bool ReadRawImage(int64_t image_number, JFJochReaderRawImage &image) override;
[[nodiscard]] std::vector<SpotToSave> ReadSpots(int64_t image) const override;
};