Pre-scan: parallel beam-stop mask, leaner background beam-centre fit
Exact: p.mtz and the pre-scan products (shadow mask, mean projection, defective-pixel mask, ring and capture centres, compared as hashes and hex floats) are bit-identical to rc174 on three in-house rotation sets, GPU and CPU builds. - ShadowFinder::GetMask: the serial parts run in parallel - connected components by row band joined with union-find (both the shadow and the transmitting-arm searches, and the hole fill), ring binning and the harmonic sector gather by blocks, gap bridging by line; ring pixel counts read off the ring offsets. Mean projection filled in parallel. - ShadowFinder host accumulation: one band-locked projection instead of a 20 B/px shard per pre-scan worker (2.7 GB zeroed and folded on a 16M detector); SetShardCount and the shard argument are gone. - FindBeamCenterFromBackground: the usable-pixel test is made once, the in-band pixels are kept in pixel order so the clipping rounds no longer sweep the whole detector, the 67 MB cell map is gone and the per-iteration block fold runs in parallel - same sums, same order. - HotPixelFinder::GetMask: the chance-rate counts in parallel (integers). Measured on a loaded box (load ~25 from other jobs), pre-scan window: GPU 5.9-6.5 s -> 3.2-3.4 s, CPU 8.4-9.0 s -> 6.1-7.4 s. The GPU-build pre-scan now ends with its background spot measurement (CPU spot finder on ~120 frames, ~13 core-s on 8 workers). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01K5K8jvPPbmCrbqnWkddTuB
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
#include <cmath>
|
||||
#include <thread>
|
||||
|
||||
#include "../../common/CompressedImage.h"
|
||||
#include "../../common/JFJochMath.h"
|
||||
#include "../../common/ParallelFor.h"
|
||||
|
||||
@@ -111,7 +112,6 @@ FindBeamCenterFromBackground(const DiffractionExperiment &experiment, const Pixe
|
||||
float beam_y = start ? start->second : geom.GetBeamY_pxl();
|
||||
|
||||
constexpr int n_cells = RADIAL_BINS * SECTORS;
|
||||
std::vector<int32_t> cell_of(n_pixels);
|
||||
std::vector<double> sum(n_cells), sum_sq(n_cells), sum_jx(n_cells), sum_jy(n_cells);
|
||||
std::vector<int32_t> count(n_cells), count_all(n_cells);
|
||||
std::vector<float> profile(RADIAL_BINS), d_profile(RADIAL_BINS), clip_limit(n_cells);
|
||||
@@ -127,6 +127,38 @@ FindBeamCenterFromBackground(const DiffractionExperiment &experiment, const Pixe
|
||||
std::vector<double> block_jy(static_cast<size_t>(BLOCKS) * n_cells);
|
||||
std::vector<int32_t> block_count(static_cast<size_t>(BLOCKS) * n_cells);
|
||||
|
||||
// Whether a pixel can take part at all, which does not depend on the centre.
|
||||
std::vector<char, NoInitAllocator<char>> usable(n_pixels);
|
||||
ParallelFor(BLOCKS, nthreads, [&](int b) {
|
||||
for (size_t i = static_cast<size_t>(block_row[b]) * W; i < static_cast<size_t>(block_row[b + 1]) * W; i++)
|
||||
usable[i] = pixel_mask[i] == 0 && std::isfinite(mean[i]);
|
||||
});
|
||||
// The pixels of each block that fall in the band at the current centre, with their cell and value,
|
||||
// in pixel order from the block's first pixel on. The clipping rounds read these instead of the
|
||||
// whole detector, in the same order.
|
||||
std::vector<int32_t, NoInitAllocator<int32_t>> band_cell(n_pixels);
|
||||
std::vector<float, NoInitAllocator<float>> band_value(n_pixels);
|
||||
std::vector<size_t> band_pixels(BLOCKS);
|
||||
|
||||
// The blocks' cells folded in block order. Each cell is folded on its own, so the cells are split
|
||||
// over the threads and every cell is still summed in the same order.
|
||||
const auto fold = [&](bool with_jacobian) {
|
||||
ParallelChunks(n_cells, nthreads, [&](int c0, int c1) {
|
||||
for (int c = c0; c < c1; c++) {
|
||||
double s = 0, ss = 0, jx = 0, jy = 0;
|
||||
int32_t n = 0;
|
||||
for (int b = 0; b < BLOCKS; b++) {
|
||||
const size_t k = static_cast<size_t>(b) * n_cells + c;
|
||||
s += block_sum[k]; ss += block_sum_sq[k];
|
||||
if (with_jacobian) { jx += block_jx[k]; jy += block_jy[k]; }
|
||||
n += block_count[k];
|
||||
}
|
||||
sum[c] = s; sum_sq[c] = ss; count[c] = n;
|
||||
if (with_jacobian) { sum_jx[c] = jx; sum_jy[c] = jy; }
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Most pixels lie outside the band. Those clearly outside it in tan(2theta) = rho / lz - by a
|
||||
// margin far above float rounding - skip the square root and both atan2 below; every pixel the exact
|
||||
// test would keep still reaches it.
|
||||
@@ -148,11 +180,13 @@ FindBeamCenterFromBackground(const DiffractionExperiment &experiment, const Pixe
|
||||
std::fill(b_jx, b_jx + n_cells, 0.0);
|
||||
std::fill(b_jy, b_jy + n_cells, 0.0);
|
||||
std::fill(b_count, b_count + n_cells, 0);
|
||||
int32_t *cells = band_cell.data() + static_cast<size_t>(block_row[b]) * W;
|
||||
float *values = band_value.data() + static_cast<size_t>(block_row[b]) * W;
|
||||
size_t n_band = 0;
|
||||
for (int y = block_row[b]; y < block_row[b + 1]; y++) {
|
||||
for (int x = 0; x < W; x++) {
|
||||
const size_t i = static_cast<size_t>(y) * W + x;
|
||||
cell_of[i] = -1;
|
||||
if (pixel_mask[i] != 0 || !std::isfinite(mean[i]))
|
||||
if (!usable[i])
|
||||
continue;
|
||||
const float u = (x - beam_x) * pixel_size;
|
||||
const float v = (y - beam_y) * pixel_size;
|
||||
@@ -183,7 +217,9 @@ FindBeamCenterFromBackground(const DiffractionExperiment &experiment, const Pixe
|
||||
const float g_x = lz * lx / (rho * denominator);
|
||||
const float g_y = lz * ly / (rho * denominator);
|
||||
const float g_z = -rho / denominator;
|
||||
cell_of[i] = cell;
|
||||
cells[n_band] = cell;
|
||||
values[n_band] = mean[i];
|
||||
n_band++;
|
||||
b_count[cell]++;
|
||||
b_sum[cell] += mean[i];
|
||||
b_sum_sq[cell] += static_cast<double>(mean[i]) * mean[i];
|
||||
@@ -191,18 +227,9 @@ FindBeamCenterFromBackground(const DiffractionExperiment &experiment, const Pixe
|
||||
b_jy[cell] += -pixel_size * (g_x * rot[1] + g_y * rot[4] + g_z * rot[7]);
|
||||
}
|
||||
}
|
||||
band_pixels[b] = n_band;
|
||||
});
|
||||
for (int c = 0; c < n_cells; c++) {
|
||||
double s = 0, ss = 0, jx = 0, jy = 0;
|
||||
int32_t n = 0;
|
||||
for (int b = 0; b < BLOCKS; b++) {
|
||||
const size_t k = static_cast<size_t>(b) * n_cells + c;
|
||||
s += block_sum[k]; ss += block_sum_sq[k];
|
||||
jx += block_jx[k]; jy += block_jy[k];
|
||||
n += block_count[k];
|
||||
}
|
||||
sum[c] = s; sum_sq[c] = ss; sum_jx[c] = jx; sum_jy[c] = jy; count[c] = n;
|
||||
}
|
||||
fold(true);
|
||||
|
||||
count_all = count; // the Jacobian sums belong to the unclipped pixel set
|
||||
|
||||
@@ -220,26 +247,19 @@ FindBeamCenterFromBackground(const DiffractionExperiment &experiment, const Pixe
|
||||
std::fill(b_sum, b_sum + n_cells, 0.0);
|
||||
std::fill(b_sum_sq, b_sum_sq + n_cells, 0.0);
|
||||
std::fill(b_count, b_count + n_cells, 0);
|
||||
const size_t lo = static_cast<size_t>(block_row[b]) * W;
|
||||
const size_t hi = static_cast<size_t>(block_row[b + 1]) * W;
|
||||
for (size_t i = lo; i < hi; i++) {
|
||||
const int32_t c = cell_of[i];
|
||||
if (c < 0 || clip_limit[c] < 0.0f || mean[i] > clip_limit[c])
|
||||
const int32_t *cells = band_cell.data() + static_cast<size_t>(block_row[b]) * W;
|
||||
const float *values = band_value.data() + static_cast<size_t>(block_row[b]) * W;
|
||||
for (size_t j = 0; j < band_pixels[b]; j++) {
|
||||
const int32_t c = cells[j];
|
||||
const float value = values[j];
|
||||
if (clip_limit[c] < 0.0f || value > clip_limit[c])
|
||||
continue;
|
||||
b_count[c]++;
|
||||
b_sum[c] += mean[i];
|
||||
b_sum_sq[c] += static_cast<double>(mean[i]) * mean[i];
|
||||
b_sum[c] += value;
|
||||
b_sum_sq[c] += static_cast<double>(value) * value;
|
||||
}
|
||||
});
|
||||
for (int c = 0; c < n_cells; c++) {
|
||||
double s = 0, ss = 0;
|
||||
int32_t n = 0;
|
||||
for (int b = 0; b < BLOCKS; b++) {
|
||||
const size_t k = static_cast<size_t>(b) * n_cells + c;
|
||||
s += block_sum[k]; ss += block_sum_sq[k]; n += block_count[k];
|
||||
}
|
||||
sum[c] = s; sum_sq[c] = ss; count[c] = n;
|
||||
}
|
||||
fold(false);
|
||||
}
|
||||
|
||||
// Radial profile: the median over the sectors that have a mean, on rings that are
|
||||
|
||||
Reference in New Issue
Block a user