Build Packages / Create release (push) Successful in 21s
Build Packages / build:portable:macos-arm64:nocuda (push) Successful in 5m11s
Build Packages / build:rugnux:linux-aarch64:cuda (push) Successful in 7m47s
Build Packages / build:portable:linux-x86_64:nocuda (push) Successful in 13m9s
Build Packages / HDF5 consumer tests (DIALS, XDS) (push) Successful in 24m3s
Build Packages / build:portable:linux-x86_64:cuda (push) Successful in 15m53s
Build Packages / build:jfjoch:rocky8:nocuda (push) Successful in 16m4s
Build Packages / build:portable:windows-x86_64:nocuda (push) Successful in 22m33s
Build Packages / build:jfjoch:rocky9:nocuda (push) Successful in 17m46s
Build Packages / build:portable:windows-x86_64:cuda (push) Successful in 26m48s
Build Packages / build:jfjoch:ubuntu2204:nocuda (push) Successful in 14m35s
Build Packages / build:jfjoch:ubuntu2404:nocuda (push) Successful in 20m11s
Build Packages / build:jfjoch:rocky8:cuda-sls9 (push) Successful in 23m11s
Build Packages / build:jfjoch:rocky9:cuda-sls9 (push) Successful in 25m28s
Build Packages / Generate python client (push) Successful in 20s
Build Packages / Build documentation (push) Successful in 1m4s
Build Packages / build:jfjoch:rocky8:cuda (push) Successful in 23m8s
Build Packages / build:jfjoch:ubuntu2204:cuda (push) Successful in 15m47s
Build Packages / build:jfjoch:rocky9:cuda (push) Successful in 25m30s
Build Packages / build:jfjoch:ubuntu2404:cuda (push) Successful in 18m34s
Build Packages / Unit tests (push) Successful in 1h34m12s
Build Packages / Validation Battery (push) Successful in 35m33s
The two pixel-level differences left between the Metal kernels and the CPU engine are closed:
- clip_sums follows the radial curve handed over by RadialBackgroundFromRings (RadialClipOffset, written
out line for line as radial_clip_offset; the curve in buffer 11, BraggPassAFrame::n_curve), so the
CPU fallback for such frames (3467c2191) is removed;
- box_sums counts the saturated signal-disk pixels (BraggBoxSums::n_saturated), so a still's overload
kept as a lower bound counts them at the saturation limit, as on the CPU and CUDA.
Everything else - the gain (clip floor, sigma floor, fit floor, Finalize), the radial correction and D14 -
is the CPU engine's own host code on the Metal path already.
The structs the host hands the kernels carry static_asserts on their size in the shared headers, so the
host and the Metal compiler check the same numbers.
The [Metal] bit-identity test now covers the handed-over curve under every integrator, stills keeping
overloads (overloads_kept compared and required non-zero), gains 4 and 1.7, and a footprint still with a
curve; `clipped` is compared too. A [portable] CPU-only case checks everywhere that these cases reach
their modes. Not compiled here (no macOS): the Mac CI job is the check.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015CeEGgpKdfkCTJb3YNMJcu
(cherry picked from commit 285d40c99b6356a52d224e610bc7b28d69973a06)
54 lines
3.0 KiB
C++
54 lines
3.0 KiB
C++
// SPDX-FileCopyrightText: 2026 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
|
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
|
|
#pragma once
|
|
|
|
// Pass A of BraggIntegrationEngineCPU, as the data it hands on: what the walk over one reflection's box
|
|
// counts, and the clip sums of its background ring. Integers only, so the counts do not depend on the
|
|
// order the pixels are visited in: the Metal engine walks the boxes on the GPU and gets the CPU's
|
|
// counts exactly. Compiled by the host and by the Metal compiler, so the two agree on the layout -
|
|
// which is also why there are no default member initialisers (Metal does not take a struct with them
|
|
// as a buffer type); zero one with {}.
|
|
|
|
#ifndef __METAL_VERSION__
|
|
#include <cstdint>
|
|
#endif
|
|
|
|
struct BraggBoxSums {
|
|
int64_t I_sum, I_sum_x, I_sum_y; // readable signal-disk pixels, and their first moments
|
|
int64_t x_sum, y_sum; // the positions behind I_sum, to take the background out of the centroid
|
|
int64_t bkg_sum; // ring pixels kept for the background
|
|
int64_t n_inner, n_inner_valid; // signal-disk pixels kept, and how many of them were readable
|
|
int32_t n_disk, n_own; // signal-disk pixels, and how many of them are this reflection's
|
|
int32_t n_bkg; // ring pixels behind bkg_sum
|
|
int32_t n_ring, n_clean; // readable ring pixels, and those no predicted neighbour covers
|
|
int32_t overloaded; // a signal-disk pixel was saturated, or unreadable on this frame only
|
|
int32_t n_saturated; // signal-disk pixels at the saturation limit
|
|
int32_t unused;
|
|
};
|
|
|
|
// The ring pixels at or below a reflection's clip threshold (BraggIntegrationEngineCPU::ClipThreshold).
|
|
struct BraggClipSums {
|
|
int64_t sum;
|
|
int32_t n;
|
|
int32_t unused;
|
|
};
|
|
|
|
// What the Metal kernels are told about the frame, beside the stencil (BraggStencilParams).
|
|
struct BraggPassAFrame {
|
|
int32_t width, height;
|
|
float r1_sq, r2_sq, r3_sq;
|
|
float claim, inv_claim; // how far a reflection claims pixels in the owner map
|
|
int32_t use_owner; // an overlap treatment is on, so the owner map is built and read
|
|
int32_t exclude; // ... and a pixel a neighbour owns leaves the signal disk
|
|
int32_t n_rad; // radial background bins; 0 when the curve is not accumulated
|
|
int32_t n_curve; // bins of the handed-over curve the clip follows (RadialClipOffset); 0: none
|
|
uint32_t static_mask_words; // length of the run's packed pixel mask
|
|
uint32_t n; // reflections
|
|
};
|
|
|
|
// Compiled on both sides, so a layout the host and the Metal compiler disagree on fails to compile.
|
|
static_assert(sizeof(BraggBoxSums) == 96, "BraggBoxSums layout shared with the Metal kernels");
|
|
static_assert(sizeof(BraggClipSums) == 16, "BraggClipSums layout shared with the Metal kernels");
|
|
static_assert(sizeof(BraggPassAFrame) == 52, "BraggPassAFrame layout shared with the Metal kernels");
|