Bragg integration: separate the three things a bandwidth used to switch
Setting a bandwidth flipped three unrelated switches at once: it changed the profile's radial capture term, it moved the width measurement from the signal disk to the whole fit grid, and it silently overrode the background clip and trim, so --background-clip under --bandwidth was ignored - the two runs were bit-identical. The width measurement was the damaging one. The fit grid is an azimuthally averaged stack, so its second moment is sigma_r^2 + sigma_t^2 and the radial smear of a bandwidth leaked into the tangential model - a tangential width of 3.04 px against a 1.06 px truth, inflating the effective background pixel count where the weak signal is. The result was a step rather than a slope: on genuinely monochromatic data, declaring a 0.2% bandwidth cost ISa 28.4 -> 22.2. Measure the two widths separately, accumulated in each spot's own radial/tangential frame over the signal disk, from the signed profile cells - away from the peak a learned cell is background noise centred on zero, so the signed sum is unbiased, while clamping it at zero turns that noise into a pedestal the r^2 weight reads as width. The radial term is then the measured excess or the analytic floor, whichever is larger. With the two widths separated there is nothing left for the broadband switch to select, so it is gone - which is the proof the three were independent. The background clip and trim now come from the settings in every case; the tuned 3-sigma broadband default moves to the rugnux front end, which is the only place that knows whether the user gave a value. Monochromatic data: declaring a 0.2% bandwidth now costs ISa 28.4 -> 27.9 rather than 22.2, and forcing the old 3-sigma clip in the new build reproduces the good result, so none of the step came from the clip. On large-bandwidth data CC1/2 improves in 8 of 10 shells. Across 12 monochromatic crystals the space groups are unchanged and CC1/2 moves by at most 0.2 points. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -57,26 +57,25 @@ BraggIntegrationEngine::BraggIntegrationEngine(const DiffractionExperiment &expe
|
||||
G = 2 * R + 1;
|
||||
GG = G * G;
|
||||
|
||||
// A set bandwidth (broadband / stills) vs monochromatic (rotation) splits the treatment: the
|
||||
// background sigma-clip and radial-elongation terms are path-dependent (see ProfileIntegrate2D).
|
||||
// The X-ray bandwidth enters ONE place: it smears a reflection radially by bw_sigma * Rpx, which
|
||||
// the per-reflection Gaussian carries as part of its radial variance. It is not a mode switch -
|
||||
// the background estimator and the parallax/capture term below are the same whatever the beam is.
|
||||
bw_sigma = experiment.GetBandwidthFWHM().value_or(0.0f) / 2.3548f;
|
||||
broadband = bw_sigma > 0.0;
|
||||
|
||||
const double c_par = parallax_var_px2(det.GetSensorMaterial(), det.GetSensorThickness_um(),
|
||||
geom.GetWavelength_A(), geom.GetPixelSize_mm() * 1000.0);
|
||||
c_radial = c_par + (broadband ? 0.0 : bragg_engine::C_CAPTURE);
|
||||
c_radial = c_par + bragg_engine::C_CAPTURE;
|
||||
F_px = geom.GetDetectorDistance_mm() / std::max(1e-6f, geom.GetPixelSize_mm());
|
||||
beam_x = geom.GetBeamX_pxl();
|
||||
beam_y = geom.GetBeamY_pxl();
|
||||
use_ellipse = !empirical && (bw_sigma > 0.0 || c_radial > 0.0);
|
||||
use_ellipse = !empirical;
|
||||
|
||||
// Robust background ring, one estimator or the other (see BraggIntegrationSettings). Broadband
|
||||
// (non-zero bandwidth: pink-beam / DMM) data keep their tuned 3 sigma high-side clip whatever the
|
||||
// settings say; monochromatic data - rotation AND stills, the discriminator is the beam, not the
|
||||
// acquisition mode - take the clip multiplier from settings, and fall back to the symmetric trim
|
||||
// only when the clip is switched off (rugnux --background-trim).
|
||||
bkg_clip_nsigma = broadband ? 3.0f : settings.GetBackgroundClipNSigma();
|
||||
bkg_trim = (broadband || bkg_clip_nsigma > 0.0f) ? 0.0f : settings.GetBackgroundTrimFraction();
|
||||
// Robust background ring, one estimator or the other (see BraggIntegrationSettings): a high-side
|
||||
// sigma-clip (rugnux --background-clip, the default) or, when the clip is switched off, a
|
||||
// symmetric trimmed mean (rugnux --background-trim). The caller owns the choice - the engine no
|
||||
// longer overrides it for broadband data.
|
||||
bkg_clip_nsigma = settings.GetBackgroundClipNSigma();
|
||||
bkg_trim = bkg_clip_nsigma > 0.0f ? 0.0f : settings.GetBackgroundTrimFraction();
|
||||
|
||||
// Radial-offset kernels for the background curvature correction. A stencil pixel at (dx, dy)
|
||||
// sits at radial offset dx*cos(phi) + dy*sin(phi) from the reflection, where phi is the
|
||||
|
||||
Reference in New Issue
Block a user