Stills: the radial curvature correction decided per run on the same empty apertures

The first stills battery of e8145d8 lost on one Rayonix set (lcls242_s, dimple R_free 0.2302 ->
0.2323): there the whole-frame radial correction hurts. On 40,000 of its frames: battery default
0.2462, ring 12 with the correction 0.2444, ring 12 without it 0.2336, ring 14 with it 0.2467. Its
beam is strongly polarised and the azimuthally averaged ring background does not describe the local
background.

So the empty apertures now also carry the corrected difference: the frame's ring background
(RingBackground, factored out of the engine) averaged over the ring pixels minus over the disk pixels
- what the integrator's kernel takes off a reflection - is subtracted from each disk-minus-ring
difference. The ring is still chosen on the plain differences, so its reach does not rest on the
radial model; where the correction was left to auto it is then kept only if it makes that ring predict
the disk better. Decisions on 15-60 pre-scan frames:
  pal86 ring 10, correction on (240.6 -> 221.1)   lcls222 ring 10, on (6.34e4 -> 3.41e4)
  lcls242_s ring 12, off (277.2 -> 285.8)         alvra213_int16 ring 14, on (0.01424 -> 0.01422)
Choosing ring and correction jointly instead picked ring 14 with the correction on lcls222, where dimple
reads 0.204 against 0.196 at ring 10; a median instead of the mean square picked ring 14 with the
correction on lcls242_s, the worst arm there. The sequential rule is the one that agrees with dimple on
every set measured.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015CeEGgpKdfkCTJb3YNMJcu
This commit is contained in:
leonarski_fandClaude Opus 5.5 committed 2026-10-21 20:58:32 +02:00
1 parent e8145d8d2f
commit 07a43a13eb
10 files changed
+263 -103

No files matched your search

@@ -13,6 +13,7 @@
#include "../../common/JFJochMath.h" // PI (M_PI is not standard, and MSVC does not define it)
#include "../SensorAbsorption.h"
#include "RingBackground.h"
namespace {
@@ -221,45 +222,16 @@ void BraggIntegrationEngine::BuildRadialKernel(float grow) {
void BraggIntegrationEngine::RadialBackgroundFromRings(const std::vector<float> &ring_bkg, int32_t q_bins,
float low_q, float dq) {
radial_curve.clear();
if (q_bins <= 0 || !(dq > 0.0f))
const RingBackground rings(ring_bkg, q_bins, low_q, dq);
if (rings.empty())
return;
// The rings averaged over their azimuthal bins, where the profile has any.
std::vector<double> sum(q_bins, 0.0);
std::vector<int> cnt(q_bins, 0);
for (size_t i = 0; i < ring_bkg.size(); ++i)
if (std::isfinite(ring_bkg[i])) {
sum[i % q_bins] += ring_bkg[i];
++cnt[i % q_bins];
}
std::vector<double> q, b;
for (int i = 0; i < q_bins; ++i)
if (cnt[i] > 0) {
q.push_back(low_q + (i + 0.5) * dq);
b.push_back(sum[i] / cnt[i]);
}
if (q.size() < 2)
return;
// The same bins as the engines' own curve: one per pixel of distance from the beam, out to the far
// corner. Each is read off the rings by linear interpolation in q; beyond the first and the last
// ring the end value is held, which has no curvature to correct.
// corner.
const int n = static_cast<int>(std::ceil(r_max)) + 2;
const double two_k = 4.0 * PI / geom.GetWavelength_A();
radial_curve.resize(n);
size_t j = 0;
for (int r = 0; r < n; ++r) {
const double qr = two_k * std::sin(0.5 * std::atan(r / F_px));
while (j + 1 < q.size() && q[j + 1] < qr)
++j;
double v;
if (qr <= q.front())
v = b.front();
else if (j + 1 >= q.size())
v = b.back();
else
v = b[j] + (b[j + 1] - b[j]) * (qr - q[j]) / (q[j + 1] - q[j]);
radial_curve[r] = static_cast<float>(v);
}
for (int r = 0; r < n; ++r)
radial_curve[r] = static_cast<float>(rings.At(two_k * std::sin(0.5 * std::atan(r / F_px))));
}
std::vector<BraggPanel> BraggIntegrationEngine::Panels(const std::vector<Reflection> &predicted,