// SPDX-FileCopyrightText: 2026 Filip Leonarski, Paul Scherrer Institute // SPDX-License-Identifier: GPL-3.0-only #pragma once #include #include #include #include // Where the panels of a stills detector lie and what their pixels are worth, as the XFEL readers // gather it from a file's own metadata (or, while it is still read, a CrystFEL geometry file): the // panels with their pixel ranges in the stored frame, fast/slow-scan directions and corners, the camera // length, the pixel size, the gain and the regions to leave out. The conventions are CrystFEL's - a // corner is the very corner of the panel's first pixel, x and y in pixels in the detector plane. // // Lengths are in pixels, except the camera length, which is held in metres. A value taken from the // image files (a camera length or photon energy stated per shot) is kept as its path, with the factor // that turns the stored number into the unit held here. namespace xfel { // A number stated in the layout, or a path to it in the image file, times scale. struct Value { std::string path; // empty: value holds the number double value = 0; double scale = 1; // what one stored unit at path is worth }; struct Panel { std::string name; int64_t min_fs = 0, max_fs = 0, min_ss = 0, max_ss = 0; // inclusive, in the stored frame double fs_x = 1, fs_y = 0, ss_x = 0, ss_y = 1; double corner_x = 0, corner_y = 0; double res = 0; // pixels per metre std::optional clen; // metres double coffset = 0; // metres std::optional adu_per_eV; std::optional adu_per_photon; std::optional max_adu; int64_t mask_edge_pixels = 0; bool no_index = false; }; // A region to leave out: either a pixel range on one panel (or, in the old syntax, on the whole // frame), or a box in the laboratory plane, in pixels. struct BadRegion { std::string panel; // empty: fs/ss are whole-frame coordinates bool in_lab = false; double min_x = 0, max_x = 0, min_y = 0, max_y = 0; int64_t min_fs = 0, max_fs = 0, min_ss = 0, max_ss = 0; }; // A mask array: a pixel is bad where it has any of bad's bits set, or lacks any of good's - or, with // nonzero_good, where the array is zero. struct Mask { std::string data; // HDF5 path; a % in it stands for the shot group, as in the data path std::string file; // file holding it, or empty for the image file itself uint32_t good = 0, bad = 0; bool nonzero_good = false; std::string panel; // empty: every panel; otherwise only this panel's pixels bool operator==(const Mask &) const = default; // Whether a pixel the mask reads as v is bad, given the mask's good, bad and nonzero_good (passed rather than // read from the mask, so that a loop over the pixels keeps them in registers). Each term is false where its // field is unset; bitwise, so that the loop has no branch. [[nodiscard]] static bool Bad(uint32_t v, uint32_t good, uint32_t bad, bool nonzero_good) { return ((v & bad) != 0) | ((v & good) != good) | (nonzero_good & (v == 0)); } }; struct Layout { std::vector panels; std::vector bad; std::vector masks; std::string data = "/data/data"; std::optional photon_energy; // eV std::optional wavelength; // Angstrom; used where no photon_energy is stated }; } // namespace xfel