Stills integration: background ring reach measured on empty apertures, radial curvature from the whole frame
Two changes to the stills integration background, both stills-only (rotation keeps its path bit for bit): 1. The r2..r3 background ring's outer radius is measured per run. The pre-scan lays apertures on a grid over its frames, away from every found spot, and for each candidate r3 (r2+2 .. 14) takes the mean square difference between the r1 disk mean and the clipped ring mean. With nothing in the aperture that is exactly the background error the ring makes (noise + bias); the run keeps the minimum. On a photon-counting pixel detector the noise wins and the shipped r3=14 is kept; on a binned CCD the background structure wins and the narrowest ring is taken. r1 stays 6: a smaller disk (4,6,14) costs 0.0013 dimple R_free on a JUNGFRAU set, so it does not pass the photon-counting gate. --adaptive-integration-radius now defaults on for stills too (=off restores the fixed 6/8/14). The pre-scan bandwidth estimate is not applied to stills. 2. The radial background-curvature correction on stills takes its curve from the adaptive spot finder's peak-excluded per-ring background (whole frame) instead of the predicted reflections' own ring pixels, and auto applies it to every stills image (no ice-score gate: a solvent/carrier hump curves the background as much as ice). New engine call RadialBackgroundFromRings; CPU, GPU and Metal read the handed-over curve. The GPU box sum now sizes the radial bin index separately from accumulating, so a handed-over curve is read at the right radius. Measured (dimple R_free, deposited free set, battery arguments, all frames unless noted): pal86 (Rayonix 4x4, 156 um): 0.354 -> 0.218 (ring 10; at 4,6,10 0.213) lcls222 (Rayonix 4x4, 177 um): 0.205 -> 0.196 (ring 10) sacla236 (MPCCD): 0.2588 -> 0.2558 (ring 11) alvra213_int16 (JUNGFRAU): 0.1986 -> 0.1986 (ring 14, unchanged) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015CeEGgpKdfkCTJb3YNMJcu
This commit is contained in:
1 parent
987e812e23
commit
e8145d8d2f
17 files changed
+558
-42
No files matched your search
@@ -235,22 +235,37 @@ void MXAnalysisWithoutFPGA::Analyze(DataMessage &output,
|
||||
// soon as it has detected - so this must be called after detection and before integration.
|
||||
// Where no such background exists (no adaptive finder), auto leaves the correction off: the
|
||||
// plain profile carries the Bragg peaks and cannot support an absolute threshold.
|
||||
//
|
||||
// On stills the correction also takes its CURVE from that background, and auto applies it to
|
||||
// every image that has one. A serial frame has a few dozen predicted reflections, so their own
|
||||
// ring pixels - where the curve comes from otherwise - sample the radial background sparsely,
|
||||
// while the finder's rings hold every pixel of the frame. And the correction is the measured
|
||||
// curvature itself: where the background has none it is zero, so there is nothing for a gate
|
||||
// to decide. The ice score is the wrong gate there: a smooth hump that is not ice - the
|
||||
// solvent or a carrier medium - curves the background as much as an ice ring does, and the
|
||||
// score does not see it.
|
||||
const auto decide_radial_background = [this, &spot_finding_settings, &output]() {
|
||||
if (!bragg_engine->IsBackgroundRadialAuto())
|
||||
return;
|
||||
// Same condition as the score at the end of this function: the adaptive finder holds its
|
||||
// ring background from whenever it last ran, so requiring that it ran for THIS image is
|
||||
// what keeps a stale curve out.
|
||||
if (!spot_finding_settings.adaptive_threshold)
|
||||
return;
|
||||
const std::vector<float> &ring_bkg = adaptiveSpotFinder->GetRingBackground();
|
||||
if (ring_bkg.empty())
|
||||
const std::vector<float> no_rings;
|
||||
const std::vector<float> &ring_bkg = spot_finding_settings.adaptive_threshold
|
||||
? adaptiveSpotFinder->GetRingBackground() : no_rings;
|
||||
const bool stills = !experiment.IsRotationIndexing();
|
||||
if (stills)
|
||||
bragg_engine->RadialBackgroundFromRings(ring_bkg, integration.GetQBinCount(),
|
||||
integration.Settings().GetLowQ_recipA(),
|
||||
integration.Settings().GetQSpacing_recipA());
|
||||
if (!bragg_engine->IsBackgroundRadialAuto() || ring_bkg.empty())
|
||||
return;
|
||||
output.ice_ring_score = AzimuthalIntegrationProfile::IceRingScore(
|
||||
ring_bkg, integration.GetQBinCount(), integration.Settings(),
|
||||
spot_finding_settings.ice_ring_width_Q_recipA);
|
||||
bragg_engine->BackgroundRadial(*output.ice_ring_score
|
||||
>= experiment.GetScalingSettings().GetIceMinScore());
|
||||
if (stills)
|
||||
bragg_engine->BackgroundRadial(!bragg_engine->GetRadialBackground().empty());
|
||||
else
|
||||
bragg_engine->BackgroundRadial(*output.ice_ring_score
|
||||
>= experiment.GetScalingSettings().GetIceMinScore());
|
||||
};
|
||||
|
||||
// A missing min-pix (std::nullopt) means "choose it per image". This applies only to the stills
|
||||
|
||||
Reference in new issue
Block a user