A detector of two or more panels is no longer assembled. The image is the stored frame, and each panel of the geometry (CrystFEL .geom or the file's own panel table) is a DetectorModule over its box of the frame, at its true placement on the detector plane: fractional origin, the panel's own axes, no snapping to an image axis or a whole pixel. Pixels on no panel, edge, bad-region and file-masked pixels are masked in the stored layout. The block scatter (a transpose for the 90-degree-turned JUNGFRAU and MPCCD panels) is gone for these inputs. A single panel keeps the old block path, so single-panel CXI files are unchanged. Signed-integer frames in their own units (gain 1, no per-frame mask) go up with no copy: a bitshuffle/LZ4 chunk still compressed, for the GPU preprocessor's BSLZ4 decoder (int16's smallest value is its error value there, so the type-min rule holds), a deflated one inflated outside the HDF5 lock straight into the caller's buffer. Everything else (float, unsigned, a gain, a per-frame mask) is converted once in stored order. A float NaN/inf now reads as no measurement (INT32_MIN) instead of 0, and values past int32 are clamped before the cast. Also: SpotToSave.panel is filled from DiffractionSpot::Panel(), so AssignModules takes the panel the spot was found on. PreviewImage_PanelLayout expects stage 3's PlaneRasterOf raster (merge fallout). Main pass, 2000 frames, vs the CCD-reader build: JF4M int16 bslz4 465 -> 1860 frames/s, JF16M 105 -> 1111, MPCCD 212 -> 252; flat Jungfraujoch data unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015CeEGgpKdfkCTJb3YNMJcu
115 lines
4.4 KiB
C++
115 lines
4.4 KiB
C++
// SPDX-FileCopyrightText: 2024 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
|
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
|
|
#include "DiffractionSpot.h"
|
|
#include "DiffractionGeometry.h"
|
|
#include "RawToConvertedGeometry.h"
|
|
|
|
DiffractionSpot::DiffractionSpot(uint32_t col, uint32_t line, int64_t in_photons) {
|
|
if (in_photons < 0) in_photons = 0;
|
|
x = static_cast<int64_t>(col) * in_photons;
|
|
y = static_cast<int64_t>(line) * in_photons;
|
|
pixel_count = 1;
|
|
photons = in_photons;
|
|
max_photons = in_photons;
|
|
}
|
|
|
|
DiffractionSpot& DiffractionSpot::operator+=(const DiffractionSpot &other) {
|
|
this->x += other.x;
|
|
this->y += other.y;
|
|
this->photons += other.photons;
|
|
this->max_photons = std::max(this->max_photons, other.max_photons);
|
|
this->pixel_count += other.pixel_count;
|
|
return *this;
|
|
}
|
|
|
|
DiffractionSpot::DiffractionSpot(int64_t x_sum, int64_t y_sum, int64_t in_pixel_count,
|
|
int64_t in_photons, int64_t in_max_photons, int64_t in_panel)
|
|
: x(x_sum), y(y_sum), pixel_count(in_pixel_count), photons(in_photons), max_photons(in_max_photons),
|
|
panel(in_panel) {}
|
|
|
|
int64_t DiffractionSpot::Count() const {
|
|
return photons;
|
|
}
|
|
|
|
int64_t DiffractionSpot::MaxCount() const {
|
|
return max_photons;
|
|
}
|
|
|
|
Coord DiffractionSpot::RawCoord() const {
|
|
if (photons == 0)
|
|
return {0, 0, 0};
|
|
// In double: the sums run past what a float mantissa holds on a bright spot, and the centroid is
|
|
// wanted to better than the last pixel bit.
|
|
return {static_cast<float>(static_cast<double>(x) / static_cast<double>(photons)),
|
|
static_cast<float>(static_cast<double>(y) / static_cast<double>(photons)), 0};
|
|
}
|
|
|
|
int64_t DiffractionSpot::Panel() const {
|
|
return panel;
|
|
}
|
|
|
|
void DiffractionSpot::Panel(int64_t in_panel) {
|
|
panel = in_panel;
|
|
}
|
|
|
|
int64_t DiffractionSpot::PixelCount() const {
|
|
return pixel_count;
|
|
}
|
|
|
|
void DiffractionSpot::AddPixel(uint32_t col, uint32_t line, int64_t photons) {
|
|
this->x += static_cast<int64_t>(col) * photons;
|
|
this->y += static_cast<int64_t>(line) * photons;
|
|
this->photons += photons;
|
|
this->max_photons = std::max(this->max_photons, photons);
|
|
this->pixel_count += 1;
|
|
}
|
|
|
|
void DiffractionSpot::ConvertToImageCoordinates(const DiffractionExperiment &experiment, uint16_t module_number) {
|
|
// The raw -> image map is a signed axis swap (module axes are +/-1 along X or Y, never rotated -
|
|
// see DetectorGeometryModular::GetDirection) plus an integer translation: the module's origin in
|
|
// the assembled image, and the two-pixel multipixel gaps, which depend on where the centroid
|
|
// falls. Applied to the SUMS rather than to the centroid, it therefore leaves them exact
|
|
// integers; converting the centroid and multiplying it back by the photon count would put the
|
|
// rounding this class avoids straight back in.
|
|
const Coord centroid = RawCoord();
|
|
const Coord fast = experiment.GetModuleFastDirection(module_number);
|
|
const Coord slow = experiment.GetModuleSlowDirection(module_number);
|
|
// Everything the map adds on top of the axis swap - origin plus gap corrections, an integer.
|
|
const Coord shift = RawToConvertedCoordinate(experiment, module_number, centroid)
|
|
- fast * centroid.x - slow * centroid.y;
|
|
|
|
const int64_t x_raw = x, y_raw = y;
|
|
x = std::lround(shift.x) * photons + std::lround(fast.x) * x_raw + std::lround(slow.x) * y_raw;
|
|
y = std::lround(shift.y) * photons + std::lround(fast.y) * x_raw + std::lround(slow.y) * y_raw;
|
|
}
|
|
|
|
std::optional<SpotToSave> DiffractionSpot::Export(const DiffractionGeometry &geometry, int64_t image_num) const {
|
|
if (photons == 0)
|
|
return std::nullopt;
|
|
|
|
const Coord centroid = RawCoord();
|
|
auto d = geometry.PxlToRes(centroid.x, centroid.y);
|
|
|
|
float phi = 0.0f;
|
|
if (geometry.GetRotation()) {
|
|
// Rotation angle is considered as increment + half wedge.
|
|
// It ignores the starting angle.
|
|
phi = geometry.GetRotation()->GetAngle_deg(image_num) + geometry.GetRotation()->GetWedge_deg() / 2.0f;
|
|
}
|
|
|
|
return SpotToSave{
|
|
.x = centroid.x,
|
|
.y = centroid.y,
|
|
.phi = phi,
|
|
.intensity = static_cast<float>(photons),
|
|
.maxc = max_photons,
|
|
.lattice = -1,
|
|
.image = image_num,
|
|
.d_A = d,
|
|
.ice_ring = false,
|
|
.indexed = false,
|
|
.panel = static_cast<int16_t>(panel)
|
|
};
|
|
}
|