Build Packages / build:viewer-tgz:cpu (push) Successful in 7m11s
Build Packages / build:viewer-tgz:cuda (push) Successful in 7m42s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 9m36s
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 10m35s
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 11m20s
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 9m14s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 10m40s
Build Packages / build:rpm (rocky8) (push) Successful in 11m41s
Build Packages / build:rpm (ubuntu2204) (push) Successful in 10m38s
Build Packages / build:rpm (rocky9) (push) Successful in 11m41s
Build Packages / build:rpm (rocky9_sls9) (push) Successful in 12m42s
Build Packages / build:rpm (ubuntu2404) (push) Successful in 11m18s
Build Packages / Generate python client (push) Successful in 26s
Build Packages / Build documentation (push) Successful in 1m0s
Build Packages / Create release (push) Skipped
Build Packages / XDS test (neggia plugin) (push) Successful in 7m7s
Build Packages / XDS test (durin plugin) (push) Successful in 7m31s
Build Packages / XDS test (JFJoch plugin) (push) Successful in 7m53s
Build Packages / build:windows:nocuda (push) Successful in 16m47s
Build Packages / DIALS test (push) Successful in 10m22s
Build Packages / build:windows:cuda (push) Successful in 17m37s
Build Packages / Unit tests (push) Successful in 1h42m32s
--scale did none of the ice handling the run that wrote the _process.h5 had
done, so re-scaling a stored dataset silently produced a different - and
flatteringly more complete - answer than the pipeline it was meant to
reproduce. Three separate gaps:
* --detect-ice-rings was accepted and ignored. The --scale block returns
before the line that applies it.
* Reflections were never flagged as sitting on an ice ring, so the per-image
scale fit included them. The flag is not stored per reflection, so it has
to be recomputed from the resolution.
* RotationScaleMerge was constructed with the ice half-width hardcoded to
zero. That is what turns a resolution into a ring index, so every ice test
inside the merge was a no-op whatever was passed to it.
The CC1/2 ring test that decides which rings to drop moves into
FindDecorrelatedIceRings, shared with the full pipeline so both reach the same
verdict on the same data, and --scale now re-merges with the mask the way the
pipeline does. The stills branch re-runs only the merge: the scaling has
already been applied to the reflections and repeating it would compound it.
Measured on a rotation dataset with three decorrelated rings, --scale went
from 8765 unique / 36.3% completeness / R-meas 18.5% / <I/sig> 1.1 to
7638 / 31.6% / 18.0% / 1.3, against the full pipeline's 7692 / 31.8% / 17.9% /
1.3 - the reported completeness had been inflated by reflections the pipeline
drops. The full pipeline is bit-identical across the refactor.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
43 lines
1.7 KiB
C++
43 lines
1.7 KiB
C++
// SPDX-FileCopyrightText: 2026 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
|
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
|
|
#include <algorithm>
|
|
#include <cmath>
|
|
|
|
#include "IceRingMask.h"
|
|
#include "../../common/Definitions.h" // ICE_RING_RES_A
|
|
#include "../../common/CorrelationCoefficient.h"
|
|
|
|
std::vector<char> FindDecorrelatedIceRings(const std::vector<MergedReflection> &merged,
|
|
float half_width_q_recipA, Logger &logger) {
|
|
if (merged.empty())
|
|
return {};
|
|
|
|
constexpr float two_pi = 6.283185307f;
|
|
const float w = half_width_q_recipA;
|
|
std::vector<char> mask(ICE_RING_RES_A.size(), 0);
|
|
|
|
for (size_t i = 0; i < ICE_RING_RES_A.size(); ++i) {
|
|
const float q_ring = two_pi / ICE_RING_RES_A[i];
|
|
CorrelationCoefficient ring, shoulder;
|
|
size_t n_ring = 0, n_shoulder = 0;
|
|
for (const auto &m : merged) {
|
|
if (!(m.d > 0.0f) || !std::isfinite(m.I_half[0]) || !std::isfinite(m.I_half[1]))
|
|
continue;
|
|
const float dq = std::fabs(two_pi / m.d - q_ring);
|
|
if (dq < w) { ring.Add(m.I_half[0], m.I_half[1]); ++n_ring; }
|
|
else if (dq < 3.0f * w) { shoulder.Add(m.I_half[0], m.I_half[1]); ++n_shoulder; }
|
|
}
|
|
if (n_ring >= 20 && n_shoulder >= 20 && shoulder.GetCC() > 0.5
|
|
&& ring.GetCC() < shoulder.GetCC() - 0.05) {
|
|
mask[i] = 1;
|
|
logger.Info("Ice-ring mask: {:.2f} A ring CC1/2 {:.3f} << shoulders {:.3f}; masked from merge",
|
|
ICE_RING_RES_A[i], ring.GetCC(), shoulder.GetCC());
|
|
}
|
|
}
|
|
|
|
if (std::none_of(mask.begin(), mask.end(), [](char c) { return c != 0; }))
|
|
return {};
|
|
return mask;
|
|
}
|