From 2eb9780fe2749f3193d227e99db511ba68425049 Mon Sep 17 00:00:00 2001 From: jungfrau Date: Sun, 23 Aug 2026 08:26:36 -0400 Subject: [PATCH] Weight the corrected intensity, not its factors, in the shared reference Folding the fit loop and the score loop into one reference() had to pick one of their two spellings, and it picked the fit loop's: w * I * corr * a, where the score loop had built Is = I * corr * a first and then summed w * Is. Those differ in the last place, and of the two callers it is the score that decides whether a surface is kept at all - so a gate sitting on the fence could go the other way for no reason but the order of three multiplications. Sum w * Is, which leaves the deciding path spelled as it was and matches how the rest of this file accumulates a weighted intensity. The fit's own reference moves by a last place instead; it is iterated to convergence and then scored, so that is the cheaper place to absorb it. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_011n8riB6X59oRjkrSHzNPAU --- image_analysis/scale_merge/RotationScaleMerge.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/image_analysis/scale_merge/RotationScaleMerge.cpp b/image_analysis/scale_merge/RotationScaleMerge.cpp index 6470a8a0..680e0004 100644 --- a/image_analysis/scale_merge/RotationScaleMerge.cpp +++ b/image_analysis/scale_merge/RotationScaleMerge.cpp @@ -1869,8 +1869,13 @@ void RotationScaleMerge::ApplyCellSurface(const std::vector &cell, int std::fill(swI.begin(), swI.end(), 0.0); for (const int32_t i : sel) { const Obs &o = fulls[i]; - const double a = A[cell[i]], sc = static_cast(o.sigma) * o.corr * a, w = 1.0 / (sc * sc); - sw[o.group] += w; swI[o.group] += w * static_cast(o.I) * o.corr * a; + // Keep the intensity's own product together before it is weighted: w * ((I*corr)*a) is + // what the loops this replaced summed, and w * I * corr * a rounds differently. The + // score decides whether a surface is kept, so a last-place difference here can flip a + // gain gate that is otherwise sitting on the fence. + const double a = A[cell[i]], Is = static_cast(o.I) * o.corr * a; + const double sc = static_cast(o.sigma) * o.corr * a, w = 1.0 / (sc * sc); + sw[o.group] += w; swI[o.group] += w * Is; } };