Stills: kept overloads go back to the drop where they are not concentrated at low resolution

Saturation clips the strongest spots, and those are at low resolution. On a Rayonix stills set the
saturated pixels sat almost entirely past 4 A (0.002% of the reflections coarser than 4 A against
0.59% overall) - flagged or hot pixels, not clipped spots - and keeping those observations as lower
bounds put the saturation limit into high-resolution intensities: R_split 0.12 -> 0.93, CC1/2 0.99
-> 0.33. The run now keeps overloads only where their share coarser than 4 A is at least 1.5x their
overall share; otherwise they are flagged and dropped as before, with a log line saying so.

On clipped CCD stills the share coarser than 4 A is 2.6-5.9x the overall one and nothing changes
(R_split and R_free identical); on the Rayonix set R_split returns to 0.12. A pragmatic gate until
saturation is told from bad pixels per spot. Rotation never keeps overloads and is unaffected.

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-22 13:51:47 +02:00
1 parent 5f8c739358
commit 0cf62452cd
3 files changed
+43

No files matched your search

+3
View File
@@ -62,6 +62,9 @@ struct Reflection {
// intensity at all - its brightest pixels are missing - and a rotation merge drops the whole
// rocking event it belongs to, as XDS does with an overloaded reflection.
bool overloaded = false;
// A still's overloaded reflection kept as a lower bound instead (BraggIntegrationEngine::Finalize);
// the run may still hand it back to the overload drop (RugnuxScaleMerge).
bool overload_kept = false;
};
// One full reflection of a rotation sweep as the merge used it - its partials summed into one
@@ -288,6 +288,7 @@ std::vector<Reflection> BraggIntegrationEngine::Finalize(const std::vector<Refle
refl.I = fr.I + static_cast<float>(fr.saturated * (saturation_limit - fr.bkg));
refl.sigma = std::sqrt(fr.var_bkg + std::max(refl.I, 1.0f));
refl.overloaded = false;
refl.overload_kept = true;
++counts.overloads_kept;
}
refl.observed = true;
+39
View File
@@ -549,6 +549,45 @@ bool Rugnux::ScaleMergeAndSymmetry(PipelineLocals &p) {
size_t ice_flagged = 0, ice_total = 0;
{
auto &outcomes = indexer->GetIntegrationOutcome();
// Saturation clips the strongest spots, and those are at low resolution: kept overloads of a
// still are a measurement only where they concentrate there. Where they do not, the saturated
// pixels are something else (hot or flagged pixels across the pattern), and an observation
// with such a pixel set to the saturation limit is not a lower bound but an outlier - so they
// go back to the overload drop. A pragmatic gate until saturation is told from bad pixels per
// spot.
{
std::atomic<int64_t> k_all{0}, k_low{0}, n_all{0}, n_low{0};
ParallelFor(static_cast<int>(outcomes.size()), config_.nthreads, [&](int o) {
int64_t all = 0, low = 0, kept = 0, kept_low = 0;
for (const auto &r : outcomes[o].reflections) {
const bool low_res = r.d >= OVERLOAD_LOW_RES_A;
++all;
low += low_res;
if (r.overload_kept) {
++kept;
kept_low += low_res;
}
}
n_all += all; n_low += low; k_all += kept; k_low += kept_low;
});
if (k_all > 0 && n_low > 0) {
const double frac_all = static_cast<double>(k_all) / static_cast<double>(n_all);
const double frac_low = static_cast<double>(k_low) / static_cast<double>(n_low);
if (frac_low < 1.5 * frac_all) {
for (auto &oc : outcomes)
for (auto &r : oc.reflections)
if (r.overload_kept) {
r.overloaded = true;
r.overload_kept = false;
}
result.overloads_kept = 0;
logger.Info("Overloads: the {} kept as a lower bound are not concentrated at low resolution "
"({:.3f}% of the reflections coarser than {:.0f} A, {:.3f}% of all) - not "
"saturated spots, so they are dropped as overloads",
k_all.load(), 100.0 * frac_low, OVERLOAD_LOW_RES_A, 100.0 * frac_all);
}
}
}
std::atomic<int64_t> n_all{0}, n_low{0}, n_over{0}, n_over_low{0}, n_ice{0};
ParallelFor(static_cast<int>(outcomes.size()), config_.nthreads, [&](int o) {
int64_t all = 0, low = 0, over = 0, over_low = 0, on_ice = 0;