Panel layout stage 2: prediction and Bragg integration through the panel table
Everything sparse that took a radial quantity from an image coordinate now takes it from the reflection's (or spot's) position on the detector plane, through its panel (DetectorModules). With an empty module table every changed expression reduces to the old one in the same floating-point order, so flat detectors - every rotation set, EIGER, CCDs, assembled JUNGFRAU - integrate bit for bit as before. - Prediction (CPU, GPU, rotation CPU and GPU): bounds test against PlaneBounds instead of the image rectangle. - IntegrateOnImage: a prediction in a gap or off every panel is dropped (PlaneToPanel), no longer passed through onto an unrelated stored pixel. The panel id stays local: the engine and the way back find it from the image position (the panel boxes tile the image), and a prediction that rounding to float put on another panel's edge is dropped so the two agree. Nothing is added to Reflection. - Bragg engines (CPU, CUDA, Metal) take a BraggPanel per reflection (BraggStencil.h): its plane position, the panel's pixel axes on the plane and its box. The stencil's radial direction is taken on the plane and expressed in the panel's pixel axes; r0, the radial background curve, the Gaussian's elongation, the learned moments, tan(2theta) and Finalize's polarisation use the plane position; r_max / n_rad come from PlaneBounds. The neighbour mask and the owner map are clamped to the reflection's own panel; inside the walked box a pixel off the reflection's panel is read as a gap (unreadable, statically masked - not an overload), which is what the assembled image has there, so a disk cut by a panel edge is partial rather than silently "full". - Risk R4: the ProfileEmpirical grid is learned and applied in the plane's axes (the panel axes taken to the nearest quarter turn, BraggProfileCell), so turned panels pool one shape. Without it the stacked layout read up to 0.3 % off the assembled one in the harness. - SpotWidth / SpotFootprint: aperture bounds against the spot's panel box, beam distance, resolution and the shape's 2theta Jacobian on the plane, moments read in the panel's axes. - GetDetectorMaxQ_recipA, the far-corner radii (first-pass tilt report, metric-symmetry arm, footprint table range) from PlaneBounds; pre-scan spot resolution on the plane; LogHeaderBeamCenter: geometric centre of the panels' plane box, and the masked-pixel check on the panel the beam lands on (none when it is in a gap). Harness: PanelLayout_BraggIntegration is now a real [PanelLayout] check, over six settings (default, bandwidth-elongated ring, radial background, overlap exclude, box sum, empirical profile, all with polarisation), stacked vs assembled to 1e-5; PanelLayout_BraggIntegrationGPU runs the same on the CUDA engine. Its spots avoid exact half pixels: the grid centres on the rounded position, and a half rounds to the other neighbour on a turned panel. The Metal engine (.metal/.mm) mirrors the CPU change exactly but is UNCOMPILED here (no macOS): it needs a build and BraggIntegrationEngineMetal_BitIdenticalToCPU on a Mac. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015CeEGgpKdfkCTJb3YNMJcu
This commit is contained in:
1 parent
c8fb472f4d
commit
d6166f6fa5
32 files changed
+531
-216
No files matched your search
@@ -7,6 +7,8 @@
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_IX86))
|
||||
@@ -23,6 +25,11 @@ namespace {
|
||||
// The engine reads pixels in the INT32_MIN(masked)/INT32_MAX(saturated) convention.
|
||||
inline bool valid(int32_t v) { return v != INT32_MIN && v != INT32_MAX; }
|
||||
|
||||
// A direction on the plane in a panel's pixel axes (MakeBraggStencil). Unchanged without panels.
|
||||
inline std::pair<double, double> to_panel_axes(const BraggPanel &pn, double ux, double uy) {
|
||||
return {ux * pn.fx + uy * pn.fy, ux * pn.sx + uy * pn.sy};
|
||||
}
|
||||
|
||||
// Ask for the cache lines from first to last ahead of their use. Only a hint: it changes no result.
|
||||
inline void prefetch(const void *p) {
|
||||
#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_IX86))
|
||||
@@ -85,24 +92,26 @@ BraggIntegrationEngineCPU::BraggIntegrationEngineCPU(const DiffractionExperiment
|
||||
}
|
||||
|
||||
void BraggIntegrationEngineCPU::MarkNeighbours(const std::vector<Reflection> &predicted,
|
||||
const std::vector<BraggPanel> &panels,
|
||||
const std::vector<uint32_t> &order) {
|
||||
const int W = static_cast<int>(xpixel), H = static_cast<int>(ypixel);
|
||||
// --- Reflection mask: mark the r2 signal region of every predicted reflection, so a neighbour's
|
||||
// signal is excluded from this reflection's r2..r3 background ring. MASK_FLUX where the
|
||||
// neighbour puts flux on this frame (NEIGHBOUR_MASK_MIN_PARTIALITY) - only those are excluded
|
||||
// - and MASK_TAIL where only the tail of a rocking curve does, which is counted for the density
|
||||
// guard but read as background. The region is the INNER stencil ellipse, taken in each
|
||||
// neighbour's OWN frame - an elongated neighbour whose streak is still marked as a disk would
|
||||
// leak its tails into this reflection's ring. ---
|
||||
// leak its tails into this reflection's ring. Only on the neighbour's own panel: beyond it the
|
||||
// image holds pixels that are elsewhere on the detector. ---
|
||||
refl_mask.Clear();
|
||||
for (const uint32_t i : order) {
|
||||
const auto &r = predicted[i];
|
||||
const BraggPanel &pn = panels[i];
|
||||
const uint8_t level = r.partiality >= NEIGHBOUR_MASK_MIN_PARTIALITY ? MASK_FLUX : MASK_TAIL;
|
||||
const BraggStencil st = MakeBraggStencil(r.predicted_x, r.predicted_y, stencil);
|
||||
const int x0 = std::max(0, static_cast<int>(std::floor(r.predicted_x - st.ex_in - 1.0f)));
|
||||
const int x1 = std::min(W - 1, static_cast<int>(std::ceil(r.predicted_x + st.ex_in + 1.0f)));
|
||||
const int y0 = std::max(0, static_cast<int>(std::floor(r.predicted_y - st.ey_in - 1.0f)));
|
||||
const int y1 = std::min(H - 1, static_cast<int>(std::ceil(r.predicted_y + st.ey_in + 1.0f)));
|
||||
const BraggStencil st = MakeBraggStencil(pn, stencil);
|
||||
const int x0 = std::max(pn.x0, static_cast<int>(std::floor(r.predicted_x - st.ex_in - 1.0f)));
|
||||
const int x1 = std::min(pn.x1, static_cast<int>(std::ceil(r.predicted_x + st.ex_in + 1.0f)));
|
||||
const int y0 = std::max(pn.y0, static_cast<int>(std::floor(r.predicted_y - st.ey_in - 1.0f)));
|
||||
const int y1 = std::min(pn.y1, static_cast<int>(std::ceil(r.predicted_y + st.ey_in + 1.0f)));
|
||||
for (int y = y0; y <= y1; ++y)
|
||||
for (int x = x0; x <= x1; ++x) {
|
||||
const auto d = BraggStencilDistances(st, x - r.predicted_x, y - r.predicted_y);
|
||||
@@ -119,10 +128,12 @@ void BraggIntegrationEngineCPU::CountNeighbourCrowding(const std::vector<Reflect
|
||||
const int W = static_cast<int>(xpixel), H = static_cast<int>(ypixel);
|
||||
counts.predicted += npredicted;
|
||||
const std::vector<uint32_t> order = FrameOrder(predicted, npredicted);
|
||||
MarkNeighbours(predicted, order);
|
||||
const std::vector<BraggPanel> panels = Panels(predicted, npredicted);
|
||||
MarkNeighbours(predicted, panels, order);
|
||||
for (const uint32_t i : order) {
|
||||
const auto &r = predicted[i];
|
||||
const BraggStencil st = MakeBraggStencil(r.predicted_x, r.predicted_y, stencil);
|
||||
const BraggPanel &pn = panels[i];
|
||||
const BraggStencil st = MakeBraggStencil(pn, stencil);
|
||||
const int x0 = std::max(0, static_cast<int>(std::floor(r.predicted_x - st.ex_out - 1.0f)));
|
||||
const int x1 = std::min(W - 1, static_cast<int>(std::ceil(r.predicted_x + st.ex_out + 1.0f)));
|
||||
const int y0 = std::max(0, static_cast<int>(std::floor(r.predicted_y - st.ey_out - 1.0f)));
|
||||
@@ -135,7 +146,8 @@ void BraggIntegrationEngineCPU::CountNeighbourCrowding(const std::vector<Reflect
|
||||
|| d.inner < r2_sq || d.outer >= r3_sq)
|
||||
continue;
|
||||
const size_t idx = static_cast<size_t>(y) * W + x;
|
||||
if (idx / 32 < static_mask.size() && ((static_mask[idx / 32] >> (idx % 32)) & 1U))
|
||||
if (!BraggPanelHolds(pn, x, y)
|
||||
|| (idx / 32 < static_mask.size() && ((static_mask[idx / 32] >> (idx % 32)) & 1U)))
|
||||
continue;
|
||||
++n_ring;
|
||||
if (refl_mask.Get(x, y) == 0)
|
||||
@@ -151,7 +163,7 @@ std::vector<Reflection> BraggIntegrationEngineCPU::RunImpl(const Sampler &img,
|
||||
const std::vector<Reflection> &predicted,
|
||||
size_t npredicted, int64_t image_number) {
|
||||
if (npredicted == 0)
|
||||
return Finalize(predicted, npredicted, std::vector<BraggFitResult>(npredicted), image_number);
|
||||
return Finalize(predicted, npredicted, {}, std::vector<BraggFitResult>(npredicted), image_number);
|
||||
counts.predicted += npredicted;
|
||||
|
||||
const int W = static_cast<int>(xpixel), H = static_cast<int>(ypixel);
|
||||
@@ -159,7 +171,8 @@ std::vector<Reflection> BraggIntegrationEngineCPU::RunImpl(const Sampler &img,
|
||||
|
||||
// Every loop below whose results do not depend on the order walks the reflections in this one.
|
||||
const std::vector<uint32_t> order = FrameOrder(predicted, npredicted);
|
||||
MarkNeighbours(predicted, order);
|
||||
const std::vector<BraggPanel> panels = Panels(predicted, npredicted);
|
||||
MarkNeighbours(predicted, panels, order);
|
||||
owner.Clear();
|
||||
|
||||
// --- Signal-region ownership: a pixel inside two reflections' signal regions belongs to the
|
||||
@@ -173,10 +186,11 @@ std::vector<Reflection> BraggIntegrationEngineCPU::RunImpl(const Sampler &img,
|
||||
const float claim_sq = claim * claim;
|
||||
for (const uint32_t i : order) {
|
||||
const auto &r = predicted[i];
|
||||
const int x0 = std::max(0, static_cast<int>(std::floor(r.predicted_x - claim)));
|
||||
const int x1 = std::min(W - 1, static_cast<int>(std::ceil(r.predicted_x + claim)));
|
||||
const int y0 = std::max(0, static_cast<int>(std::floor(r.predicted_y - claim)));
|
||||
const int y1 = std::min(H - 1, static_cast<int>(std::ceil(r.predicted_y + claim)));
|
||||
const BraggPanel &pn = panels[i];
|
||||
const int x0 = std::max(pn.x0, static_cast<int>(std::floor(r.predicted_x - claim)));
|
||||
const int x1 = std::min(pn.x1, static_cast<int>(std::ceil(r.predicted_x + claim)));
|
||||
const int y0 = std::max(pn.y0, static_cast<int>(std::floor(r.predicted_y - claim)));
|
||||
const int y1 = std::min(pn.y1, static_cast<int>(std::ceil(r.predicted_y + claim)));
|
||||
for (int y = y0; y <= y1; ++y)
|
||||
for (int x = x0; x <= x1; ++x) {
|
||||
const float dx = x - r.predicted_x, dy = y - r.predicted_y;
|
||||
@@ -224,15 +238,16 @@ std::vector<Reflection> BraggIntegrationEngineCPU::RunImpl(const Sampler &img,
|
||||
// prefetch.)
|
||||
if (k + 1 < npredicted) {
|
||||
const Reflection &n = predicted[order[k + 1]];
|
||||
const Box b = box_of(n, MakeBraggStencil(n.predicted_x, n.predicted_y, stencil));
|
||||
const Box b = box_of(n, MakeBraggStencil(panels[order[k + 1]], stencil));
|
||||
for (int y = b.y0; y <= b.y1 && b.x0 <= b.x1; ++y)
|
||||
prefetch_row(img.address(static_cast<size_t>(y) * W + b.x0),
|
||||
img.address(static_cast<size_t>(y) * W + b.x1));
|
||||
}
|
||||
const auto &r = predicted[i];
|
||||
const BraggPanel &pn = panels[i];
|
||||
// This reflection's stencil: the r1 signal disk, and the r2..r3 ring elongated radially by
|
||||
// the analytic smear.
|
||||
const BraggStencil st = MakeBraggStencil(r.predicted_x, r.predicted_y, stencil);
|
||||
const BraggStencil st = MakeBraggStencil(pn, stencil);
|
||||
const Box box = box_of(r, st);
|
||||
const int x0 = box.x0, x1 = box.x1, y0 = box.y0, y1 = box.y1;
|
||||
|
||||
@@ -247,7 +262,9 @@ std::vector<Reflection> BraggIntegrationEngineCPU::RunImpl(const Sampler &img,
|
||||
for (int y = y0; y <= y1; ++y)
|
||||
for (int x = x0; x <= x1; ++x) {
|
||||
const auto d = BraggStencilDistances(st, x - r.predicted_x, y - r.predicted_y);
|
||||
const int32_t px = img[y * W + x];
|
||||
// Off the reflection's panel is a gap: unreadable, and not lost to the flux.
|
||||
const bool on = BraggPanelHolds(pn, x, y);
|
||||
const int32_t px = on ? img[y * W + x] : INT32_MIN;
|
||||
if (do_clip && d.inner >= r2_sq && d.outer < r3_sq && valid(px) && refl_mask.Get(x, y) != MASK_FLUX)
|
||||
clip_ring.push_back({px, d.rad});
|
||||
if (BraggStencilInSignal(st, x - r.predicted_x, y - r.predicted_y, d.signal, r1_sq)) {
|
||||
@@ -262,7 +279,7 @@ std::vector<Reflection> BraggIntegrationEngineCPU::RunImpl(const Sampler &img,
|
||||
}
|
||||
++s.n_inner;
|
||||
if (px == INT32_MAX
|
||||
|| (px == INT32_MIN && !static_masked(static_cast<size_t>(y) * W + x)))
|
||||
|| (px == INT32_MIN && on && !static_masked(static_cast<size_t>(y) * W + x)))
|
||||
s.overloaded = 1;
|
||||
if (!valid(px)) continue;
|
||||
s.I_sum += px;
|
||||
@@ -306,17 +323,18 @@ std::vector<Reflection> BraggIntegrationEngineCPU::RunImpl(const Sampler &img,
|
||||
FinishPassA(a, i, r, st, s, clip, bkg_vals);
|
||||
}
|
||||
|
||||
return ProfilePasses(img, owner, predicted, npredicted, a, image_number);
|
||||
return ProfilePasses(img, owner, predicted, npredicted, panels, a, image_number);
|
||||
}
|
||||
|
||||
BraggIntegrationEngineCPU::PassA BraggIntegrationEngineCPU::StartPassA(size_t npredicted) const {
|
||||
const int W = static_cast<int>(xpixel), H = static_cast<int>(ypixel);
|
||||
PassA a;
|
||||
a.rough.resize(npredicted);
|
||||
// A pixel's radius is the reflection's radius plus the pixel's projection on the beam->reflection
|
||||
// direction, so no per-pixel sqrt is needed.
|
||||
a.n_rad = static_cast<int>(std::ceil(std::hypot(std::max<double>(beam_x, W - beam_x),
|
||||
std::max<double>(beam_y, H - beam_y)))) + 2;
|
||||
// direction, so no per-pixel sqrt is needed. Out to the far corner of the plane the panels span.
|
||||
const float bx0 = static_cast<float>(plane_bounds.x0), bx1 = static_cast<float>(plane_bounds.x1);
|
||||
const float by0 = static_cast<float>(plane_bounds.y0), by1 = static_cast<float>(plane_bounds.y1);
|
||||
a.n_rad = static_cast<int>(std::ceil(std::hypot(std::max<double>(beam_x - bx0, bx1 - beam_x),
|
||||
std::max<double>(beam_y - by0, by1 - beam_y)))) + 2;
|
||||
if (bkg_radial) {
|
||||
a.rad_sum.assign(a.n_rad, 0);
|
||||
a.rad_cnt.assign(a.n_rad, 0);
|
||||
@@ -469,7 +487,7 @@ bool BraggIntegrationEngineCPU::FitKept(const BraggFitOut &o) const {
|
||||
|
||||
template <class Sampler, class OwnerMap>
|
||||
BraggFitOut BraggIntegrationEngineCPU::FitProfile(const Sampler &img, const OwnerMap &owner_map,
|
||||
const BraggFitSetup &s, size_t i,
|
||||
const BraggFitSetup &s, const BraggPanel &pn, size_t i,
|
||||
const std::vector<float> &shell_profiles,
|
||||
std::vector<float> &cells,
|
||||
std::vector<FitPixel> &fit_pixels) const {
|
||||
@@ -480,9 +498,15 @@ BraggFitOut BraggIntegrationEngineCPU::FitProfile(const Sampler &img, const Owne
|
||||
BraggFitOut o{};
|
||||
|
||||
const float *P;
|
||||
if (s.shell >= 0)
|
||||
P = shell_profiles.data() + static_cast<size_t>(s.shell) * GG;
|
||||
else {
|
||||
if (s.shell >= 0) {
|
||||
// The shell's learned profile is in the plane's axes; laid out here in the panel's.
|
||||
const float *learned = shell_profiles.data() + static_cast<size_t>(s.shell) * GG;
|
||||
cells.resize(GG);
|
||||
for (int dy = -R; dy <= R; ++dy)
|
||||
for (int dx = -R; dx <= R; ++dx)
|
||||
cells[(dy + R) * G + (dx + R)] = learned[BraggProfileCell(pn, dx, dy, R)];
|
||||
P = cells.data();
|
||||
} else {
|
||||
// The grid's image rows, asked for now (as in pass A): building the profile below takes long
|
||||
// enough for them to arrive before the fit reads them.
|
||||
const int gx0 = std::max(0, s.cx - Rf), gx1 = std::min(W - 1, s.cx + Rf);
|
||||
@@ -510,7 +534,7 @@ BraggFitOut BraggIntegrationEngineCPU::FitProfile(const Sampler &img, const Owne
|
||||
// pixels, what Reject cuts on. m_read / m_all is the fraction of the r1 disk the
|
||||
// summation seed the runaway guard compares against actually summed; with nothing missing
|
||||
// and nothing excluded it is 1 and the guard is untouched. ---
|
||||
const BraggStencil st = MakeBraggStencil(s.px, s.py, stencil);
|
||||
const BraggStencil st = MakeBraggStencil(pn, stencil);
|
||||
fit_pixels.clear();
|
||||
for (int dy = -Rf; dy <= Rf; ++dy)
|
||||
for (int dx = -Rf; dx <= Rf; ++dx) {
|
||||
@@ -527,7 +551,7 @@ BraggFitOut BraggIntegrationEngineCPU::FitProfile(const Sampler &img, const Owne
|
||||
o.p_grid += Pp;
|
||||
o.p_peak = std::max(o.p_peak, Pp);
|
||||
if (in_disk) o.m_all += Pp;
|
||||
const int32_t v = img[y * W + x];
|
||||
const int32_t v = BraggPanelHolds(pn, x, y) ? img[y * W + x] : INT32_MIN;
|
||||
if (!valid(v)) {
|
||||
o.p_lost_peak = std::max(o.p_lost_peak, Pp);
|
||||
continue;
|
||||
@@ -561,7 +585,8 @@ BraggFitOut BraggIntegrationEngineCPU::FitProfile(const Sampler &img, const Owne
|
||||
template <class Sampler, class OwnerMap>
|
||||
std::vector<Reflection> BraggIntegrationEngineCPU::ProfilePasses(const Sampler &img, const OwnerMap &owner_map,
|
||||
const std::vector<Reflection> &predicted,
|
||||
size_t npredicted, PassA &a,
|
||||
size_t npredicted,
|
||||
const std::vector<BraggPanel> &panels, PassA &a,
|
||||
int64_t image_number) {
|
||||
const int W = static_cast<int>(xpixel), H = static_cast<int>(ypixel);
|
||||
std::vector<BraggFitResult> results(npredicted);
|
||||
@@ -572,7 +597,6 @@ std::vector<Reflection> BraggIntegrationEngineCPU::ProfilePasses(const Sampler &
|
||||
return !use_owner
|
||||
|| BraggOwnedBy(owner_map.Get(x, y), static_cast<int>(i));
|
||||
};
|
||||
auto grid_idx = [this](int dx, int dy) { return (dy + R) * G + (dx + R); };
|
||||
|
||||
// --- Radial background curvature correction. The annulus mean is blind to the curvature of the
|
||||
// radial background (a linear background cancels between the concentric disk and annulus), so
|
||||
@@ -613,7 +637,7 @@ std::vector<Reflection> BraggIntegrationEngineCPU::ProfilePasses(const Sampler &
|
||||
static_cast<float>(rh.obs_x), static_cast<float>(rh.obs_y),
|
||||
static_cast<float>(rh.var_bkg), true, rh.has_obs, rh.overloaded};
|
||||
}
|
||||
return Finalize(predicted, npredicted, results, image_number);
|
||||
return Finalize(predicted, npredicted, panels, results, image_number);
|
||||
}
|
||||
|
||||
auto shell_of = [&](float d) {
|
||||
@@ -626,7 +650,7 @@ std::vector<Reflection> BraggIntegrationEngineCPU::ProfilePasses(const Sampler &
|
||||
|
||||
// --- Learn the profile per shell (+ global) from the strong spots. ---
|
||||
// Two things are learned. The empirical profile is the average grid in the DETECTOR frame, which is
|
||||
// where it is applied. The width is a pair of second moments taken in each spot's OWN radial /
|
||||
// where it is applied - in the plane's axes, which a turned panel's pixels are mapped onto. The width is a pair of second moments taken in each spot's OWN radial /
|
||||
// tangential frame: a grid stacked in the detector frame is azimuthally averaged, so its <r^2> is
|
||||
// sigma_r^2 + sigma_t^2 with no way back, and a radially smeared spot reads as a wide TANGENTIAL
|
||||
// one. Rotating each contribution into the spot's frame keeps the two apart.
|
||||
@@ -641,19 +665,22 @@ std::vector<Reflection> BraggIntegrationEngineCPU::ProfilePasses(const Sampler &
|
||||
for (size_t i = 0; i < npredicted; ++i) {
|
||||
const auto &rh = rough[i];
|
||||
if (!rh.ok || !rh.strong || rh.I <= 0.0) continue;
|
||||
const double rx = predicted[i].predicted_x - beam_x, ry = predicted[i].predicted_y - beam_y;
|
||||
const BraggPanel &pn = panels[i];
|
||||
const double rx = pn.plane_x - beam_x, ry = pn.plane_y - beam_y;
|
||||
const double Rpx = std::hypot(rx, ry);
|
||||
const double ux = Rpx > 1e-6 ? rx / Rpx : 1.0, uy = Rpx > 1e-6 ? ry / Rpx : 0.0;
|
||||
for (int dy = -R; dy <= R; ++dy)
|
||||
const auto [ux, uy] = to_panel_axes(pn, Rpx > 1e-6 ? rx / Rpx : 1.0, Rpx > 1e-6 ? ry / Rpx : 0.0);
|
||||
for (int dy = -R; dy <= R; ++dy)
|
||||
for (int dx = -R; dx <= R; ++dx) {
|
||||
const int x = rh.cx + dx, y = rh.cy + dy;
|
||||
if (x < 0 || y < 0 || x >= W || y >= H) continue;
|
||||
if (x < 0 || y < 0 || x >= W || y >= H || !BraggPanelHolds(pn, x, y)) continue;
|
||||
const int32_t px = img[y * W + x];
|
||||
if (!valid(px)) continue;
|
||||
if (exclude && !clean(x, y, i)) continue;
|
||||
const double v = (static_cast<double>(px) - rh.bkg) / rh.I;
|
||||
shell_grid[rh.shell][grid_idx(dx, dy)] += v;
|
||||
global_grid[grid_idx(dx, dy)] += v;
|
||||
// The grid in the plane's axes (BraggProfileCell); the moments below are axis-free.
|
||||
const int cell = BraggProfileCell(pn, dx, dy, R);
|
||||
shell_grid[rh.shell][cell] += v;
|
||||
global_grid[cell] += v;
|
||||
if (dx * dx + dy * dy >= r1_sq) continue;
|
||||
const double rad = dx * ux + dy * uy, tn = -dx * uy + dy * ux;
|
||||
shell_mom[rh.shell].rad += v * rad * rad;
|
||||
@@ -734,7 +761,8 @@ std::vector<Reflection> BraggIntegrationEngineCPU::ProfilePasses(const Sampler &
|
||||
continue;
|
||||
}
|
||||
const int sh = rh.shell < 0 ? 0 : rh.shell;
|
||||
const BraggStencil st = MakeBraggStencil(predicted[i].predicted_x, predicted[i].predicted_y, stencil);
|
||||
const BraggPanel &pn = panels[i];
|
||||
const BraggStencil st = MakeBraggStencil(pn, stencil);
|
||||
fs.fit = 1;
|
||||
fs.px = predicted[i].predicted_x;
|
||||
fs.py = predicted[i].predicted_y;
|
||||
@@ -744,7 +772,7 @@ std::vector<Reflection> BraggIntegrationEngineCPU::ProfilePasses(const Sampler &
|
||||
fs.shell = sh;
|
||||
fs.footprint = st.fp_s2t > 0.0f;
|
||||
if (!empirical) {
|
||||
const double rx = predicted[i].predicted_x - beam_x, ry = predicted[i].predicted_y - beam_y;
|
||||
const double rx = pn.plane_x - beam_x, ry = pn.plane_y - beam_y;
|
||||
const double Rpx = std::hypot(rx, ry);
|
||||
const double tan2t = Rpx / F_px;
|
||||
double s2t = shell_sigma2[sh].tan;
|
||||
@@ -758,7 +786,7 @@ std::vector<Reflection> BraggIntegrationEngineCPU::ProfilePasses(const Sampler &
|
||||
const double radial_extra = std::max(shell_sigma2[sh].rad - s2t,
|
||||
sbw * sbw + c_radial * tan2t * tan2t);
|
||||
if (Rpx > 1e-6 && radial_extra > 0.25) {
|
||||
ux = rx / Rpx; uy = ry / Rpx;
|
||||
std::tie(ux, uy) = to_panel_axes(pn, rx / Rpx, ry / Rpx);
|
||||
s2r = s2t + radial_extra;
|
||||
elong = true;
|
||||
}
|
||||
@@ -796,7 +824,7 @@ std::vector<Reflection> BraggIntegrationEngineCPU::ProfilePasses(const Sampler &
|
||||
std::vector<FitPixel> fit_pixels;
|
||||
for (const uint32_t i : FrameOrder(predicted, npredicted))
|
||||
if (setups[i].fit)
|
||||
fits[i] = FitProfile(img, owner_map, setups[i], i, shell_profiles, cells_buf, fit_pixels);
|
||||
fits[i] = FitProfile(img, owner_map, setups[i], panels[i], i, shell_profiles, cells_buf, fit_pixels);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < npredicted; ++i) {
|
||||
@@ -841,18 +869,19 @@ std::vector<Reflection> BraggIntegrationEngineCPU::ProfilePasses(const Sampler &
|
||||
static_cast<float>(var_bkg), true, rh.has_obs, rh.overloaded};
|
||||
}
|
||||
|
||||
return Finalize(predicted, npredicted, results, image_number);
|
||||
return Finalize(predicted, npredicted, panels, results, image_number);
|
||||
}
|
||||
|
||||
template std::vector<Reflection> BraggIntegrationEngineCPU::ProfilePasses(
|
||||
const BraggIntegrationEngineCPU::BufferSampler &, const BraggIntegrationEngineCPU::FlatOwnerMap &,
|
||||
const std::vector<Reflection> &, size_t, BraggIntegrationEngineCPU::PassA &, int64_t);
|
||||
const std::vector<Reflection> &, size_t, const std::vector<BraggPanel> &,
|
||||
BraggIntegrationEngineCPU::PassA &, int64_t);
|
||||
|
||||
std::vector<Reflection> BraggIntegrationEngineCPU::Run(const ImagePreprocessorBuffer &image,
|
||||
const std::vector<Reflection> &predicted,
|
||||
size_t npredicted, int64_t image_number) {
|
||||
if (image.size() != npixel)
|
||||
return Finalize(predicted, npredicted, std::vector<BraggFitResult>(npredicted), image_number);
|
||||
return Finalize(predicted, npredicted, {}, std::vector<BraggFitResult>(npredicted), image_number);
|
||||
return RunImpl(BufferSampler{image.data()}, predicted, npredicted, image_number);
|
||||
}
|
||||
|
||||
@@ -860,7 +889,7 @@ std::vector<Reflection> BraggIntegrationEngineCPU::Run(const CompressedImage &im
|
||||
const std::vector<Reflection> &predicted,
|
||||
size_t npredicted, int64_t image_number) {
|
||||
if (image.GetWidth() * image.GetHeight() != npixel)
|
||||
return Finalize(predicted, npredicted, std::vector<BraggFitResult>(npredicted), image_number);
|
||||
return Finalize(predicted, npredicted, {}, std::vector<BraggFitResult>(npredicted), image_number);
|
||||
|
||||
std::vector<uint8_t> scratch;
|
||||
const auto *ptr = image.GetUncompressedPtr(scratch);
|
||||
|
||||
Reference in new issue
Block a user