ice rings: add --detect-ice-rings and exclude ice-ring reflections from scaling
jfjoch_process gains --detect-ice-rings, which (a) activates the existing spot-finder ice flagging (ice spots de-prioritised in indexing) and (b) drops reflections sitting on a hexagonal-ice powder ring from scaling/combine/merge/stats, via a new shared IsOnIceRing() helper over ICE_RING_RES_A using the spot-finder's q half-width. Their integrated intensity is contaminated by the strong, variable ice background, so leaving them in mis-scales the whole frame and inflates the error model. On EP0117 (ice-ring crystal): de-novo space-group determination recovers from P1 to P2 and CC1/2 improves (31->37%). Off by default; a no-op without the flag. This is the first, non-controversial step - the residual gap needs ice-aware background/integration (follow-up). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -34,6 +34,7 @@
|
||||
#include "../image_analysis/scale_merge/Combine3D.h"
|
||||
#include "../image_analysis/scale_merge/HKLKey.h"
|
||||
#include "../image_analysis/WriteReflections.h"
|
||||
#include "../common/Definitions.h"
|
||||
#include <array>
|
||||
#include <map>
|
||||
#include <Eigen/Dense>
|
||||
@@ -532,6 +533,25 @@ ProcessResult JFJochProcess::Run(JFJochProcessObserver *observer) {
|
||||
};
|
||||
phase("Scaling and merging");
|
||||
|
||||
// Ice-ring handling (--detect-ice-rings): drop reflections sitting on a hexagonal-ice powder
|
||||
// ring before scaling. Their integrated intensity is contaminated by the strong, variable ice
|
||||
// background, so leaving them in mis-scales the whole frame (the per-image fit is dragged) and
|
||||
// inflates the error model. Removed once here, so every scaling pass, the combine, the merge
|
||||
// and the statistics all skip them.
|
||||
if (experiment_.IsDetectIceRings()) {
|
||||
const float ice_width = config_.spot_finding.ice_ring_width_Q_recipA;
|
||||
size_t total = 0, dropped = 0;
|
||||
for (auto &outcome : indexer->GetIntegrationOutcome()) {
|
||||
total += outcome.reflections.size();
|
||||
const size_t before = outcome.reflections.size();
|
||||
std::erase_if(outcome.reflections,
|
||||
[&](const Reflection &r) { return IsOnIceRing(r.d, ice_width); });
|
||||
dropped += before - outcome.reflections.size();
|
||||
}
|
||||
logger.Info("Ice-ring exclusion: dropped {} of {} reflections on ice rings (half-width {:.3f} A^-1)",
|
||||
dropped, total, ice_width);
|
||||
}
|
||||
|
||||
// Scale the images and merge. Factored so it can run twice: first in P1 to give the
|
||||
// space-group search a merged dataset, then again in the determined space group so the
|
||||
// scaling sees symmetry equivalents and the final statistics are in the right symmetry.
|
||||
|
||||
Reference in New Issue
Block a user