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>
82 lines
3.4 KiB
C++
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;
|
|
};
|