partiality: fix the rotation-prediction wedge, use the stored value in scaling

BraggPredictionRot halves settings.wedge_deg to the +/- half-wedge of the
partiality erf pair, but IndexAndRefine already passed GetWedge_deg()/2, so the
two /2 compounded to a half-wedge of increment/4 - half the correct Kabsch value
(increment/2, which ScaleOnTheFly's RotationPartiality already used). Pass the
full increment so prediction's partiality matches scaling.

With prediction correct, ScaleOnTheFly now uses the stored r.partiality directly
(the value the reflection was integrated with) rather than recomputing the erf
pair per reflection - recomputing only when scaling overrides the geometry
(-w wedge refinement, --mosaicity, or a scaling wedge override). Output-neutral
on the /data/rotation_test battery (SG/cell/completeness identical, ISa/CC1/2
within run noise on the stable crystals).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-02 14:57:16 +02:00
co-authored by Claude Fable 5
parent 8c084021e6
commit cdbd0bed5d
2 changed files with 15 additions and 3 deletions
+4 -1
View File
@@ -292,7 +292,10 @@ void IndexAndRefine::QuickPredictAndIntegrate(DataMessage &msg,
float mos_deg = 0.1f;
if (experiment.GetGoniometer().has_value()) {
wedge_deg = experiment.GetGoniometer()->GetWedge_deg() / 2.0;
// Full oscillation wedge of one frame; BraggPredictionRot halves it to the +/- half-wedge of the
// partiality erf pair (Kabsch). Passing the full increment gives a half-wedge of increment/2 -
// matching ScaleOnTheFly's RotationPartiality, so the predicted partiality is used directly there.
wedge_deg = experiment.GetGoniometer()->GetWedge_deg();
if (msg.mosaicity_deg) {
mos_deg = msg.mosaicity_deg.value();