rugnux: exclude merge-rejected outliers from the error-model fit

The rotation error-model (a,b) fit built its sample pool from all usable
fulls, while the merge separately dropped symmetry outliers (> Nsigma from
the per-reflection median). So the fitted sigmas were calibrated against a
dirtier pool than the reflections that actually entered the merge.

Refactor the intensity-binned median fit into a `fit_ab` lambda and re-run
it once on the misfit-free pool (samples with dev2 <= reject_nsigma^2 *
model variance), matching the merge's own rejection. It operates on the
shared `samples` array, so the CPU and GPU error-model paths stay
bit-identical.

Neutral on lyso_ref (the median-binned fit is already robust to the few
outliers) - a correctness fix that matters more on dirtier data. Gated on
reject_outliers (default 6 sigma for rot3d).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-12 10:04:43 +02:00
co-authored by Claude Opus 4.8
parent a854523fee
commit dee679380b
2 changed files with 28 additions and 9 deletions
+1 -1
View File
@@ -604,6 +604,6 @@ A linear regression of $\log\langle I\rangle$ vs $1/d^2$ provides an estimate of
- **Rotation vs still modes** differ substantially in prediction and scaling: partiality is angle-driven in rotation data, while stills are predicted (within an excitation-error window) and scaled with unit partiality.
- **Space-group determination.** When no space group is supplied, a POINTLESS-like search scores Laue-group symmetry (CC of $I(h)$ vs $I(Rh)$ plus merge self-consistency) and detects screw/centering absences from the $P1$-merged intensities.
- **Twinning check.** A PadillaYeates $L$-test ($\langle|L|\rangle$, $\langle L^2\rangle$) and the second moment $\langle I^2\rangle/\langle I\rangle^2$ are computed and written to the merged mmCIF as a twinning diagnostic.
- **Outlier rejection.** Merging applies an optional per-observation median-based $N\sigma$ cut (default 6σ for `rot3d`) and an optional per-crystal $\Delta\mathrm{CC}_{1/2}$ image rejection (`--reject-delta-cchalf`, CrystFEL-style, off by default).
- **Outlier rejection.** Merging applies an optional per-observation median-based $N\sigma$ cut (default 6σ for `rot3d`) and an optional per-crystal $\Delta\mathrm{CC}_{1/2}$ image rejection (`--reject-delta-cchalf`, CrystFEL-style, off by default). The same $N\sigma$ cut is fed back into the error model: after an initial $a,b$ fit the parameters are re-fit once on the reflections that survive rejection (dropping any whose squared deviation exceeds $N\sigma^2\,[a\,\sigma^2 + (b\,\langle I\rangle)^2]$), so the calibrated errors describe the reflections that actually enter the merge rather than the pre-rejection pool.
- **Automatic resolution cutoff.** By default the reported/written high-resolution limit is trimmed where $\mathrm{CC}_{1/2}$ falls off (logistic, target 0.30); `--scaling-high-resolution` overrides it and `--resolution-cutoff off` disables it.
- **Intensities only.** The merged output carries intensities (mmCIF `intensity_meas`, MTZ `IMEAN`/`SIGIMEAN`); it does not convert to amplitudes $|F|$ (no FrenchWilson / truncate step) — do that downstream.