The photon-weighted position sums were floats, so the centroid's last bit depended on the build rather than on the data: gcc contracts the multiply-add in AddPixel into an FMA under -march=x86-64-v3 and cannot at the baseline, and MSVC does not contract at all under /fp:precise. The GPU extractor had to match with __fmaf_rn, and the parity test still needed a two-ulp slack for hosts that do not fuse. Column, line and the per-pixel count are all integral, so the sums are exact in int64 and both implementations reach the same bits with nothing to match. The parity test now demands exact equality unconditionally and gets it, including on a baseline build. ConvertToImageCoordinates keeps the sums integral too: the raw -> image map is a signed axis swap plus an integer translation, so it is applied to the sums instead of to the centroid. Drops the SpotToSave constructor, which had no callers and could not have been converted without quantising the stored centroid. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
39 lines
1.9 KiB
C++
39 lines
1.9 KiB
C++
// SPDX-FileCopyrightText: 2024 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
|
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
|
|
#pragma once
|
|
|
|
#include "Coord.h"
|
|
#include "DiffractionExperiment.h"
|
|
#include "DiffractionGeometry.h"
|
|
#include "SpotToSave.h"
|
|
|
|
// Definition of Bragg spot
|
|
class DiffractionSpot {
|
|
// Photon-weighted position sums, sum(col * photons) and sum(line * photons). Integers, not a
|
|
// centroid: column, line and the per-pixel count are all integral, so the sums are exact and
|
|
// every implementation that builds them - host, GPU, whatever the build lets the compiler
|
|
// contract - arrives at the same bits. In float they did not: gcc fuses the multiply-add under
|
|
// -march=x86-64-v3 and not at the baseline, which left the last bit of the centroid a property
|
|
// of the build flags rather than of the data.
|
|
int64_t x = 0;
|
|
int64_t y = 0;
|
|
int64_t pixel_count = 0;
|
|
int64_t photons = 0; // total photon count
|
|
int64_t max_photons = INT64_MIN; // maximum number of counts per pixel in the spot
|
|
public:
|
|
DiffractionSpot() = default;
|
|
DiffractionSpot(uint32_t col, uint32_t line, int64_t photons);
|
|
// From already-summed quantities, i.e. the members as AddPixel leaves them, NOT a centroid.
|
|
// Used by the GPU spot extractor, which computes those sums on the device.
|
|
DiffractionSpot(int64_t x_sum, int64_t y_sum, int64_t pixel_count, int64_t photons, int64_t max_photons);
|
|
DiffractionSpot& operator+=(const DiffractionSpot& spot);
|
|
int64_t PixelCount() const;
|
|
int64_t Count() const;
|
|
int64_t MaxCount() const;
|
|
Coord RawCoord() const;
|
|
void ConvertToImageCoordinates(const DiffractionExperiment& experiment, uint16_t module_number);
|
|
std::optional<SpotToSave> Export(const DiffractionGeometry &geometry, int64_t image_num = 0) const;
|
|
void AddPixel(uint32_t col, uint32_t line, int64_t photons);
|
|
};
|