From efca844bce9728b1d5e9aed14a50990b25302cb4 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Mon, 31 Aug 2026 19:47:02 +0200 Subject: [PATCH] calibration: --no-refine-tilt holds the header tilt, it does not zero it GuessInitialGeometry resets rot1/rot2/rot3 to zero before seeding, and the branch that puts the header's tilt back was guarded by `refine_tilt && !tilt_refined`. With --no-refine-tilt the tilt is never free, so tilt_refined is false, so the guard is false, so the restore never ran - and the fit reported a zero tilt while the CLI printed "held at the header value". The guard only needs !tilt_refined: a tilt that was declined and a tilt nobody asked to refine both want the header put back and the beam centre and distance refitted around it. That is what the branch already does. Measured on a LaB6 sweep with a tilt imposed on the command line and asked to be held, --calibration spots: before Rot1= +0.0000 deg (+0.001400 rad from the header) after Rot1= -0.0802 deg (+0.000000 rad from the header) The rings path reaches this only when the spot-derived start wins, which is why it does not show on a file whose profile start is chosen; the spots path always did. A calibration whose header tilt is already zero is unaffected - checked, byte-equal distance either way. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01EFEJG6WBQv8th4UJFNe53N --- docs/CHANGELOG.md | 1 + .../geom_refinement/PowderCalibration.cpp | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 53fc10e73..ae1f9add3 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -17,6 +17,7 @@ * Twinning is no longer reported when the L-test contradicts it. * The `rugnux` report gives the detector tilt and the direct beam beside the beam centre, and carries the tilt in the `dataset_settings` block. * The `rugnux` report gives the detector tilt rotation indexing measured, so it can be checked against a powder calibration. +* `--no-refine-tilt` holds the detector tilt at the value in the file, instead of zeroing it, when the calibration starts from the spots. * The `jfjoch_viewer` grid scan view draws the cells in the proportion of the scan steps, so the map has the shape of the scanned area. ### 1.0.0-rc.165 diff --git a/image_analysis/geom_refinement/PowderCalibration.cpp b/image_analysis/geom_refinement/PowderCalibration.cpp index 2e4c45604..b583a6a00 100644 --- a/image_analysis/geom_refinement/PowderCalibration.cpp +++ b/image_analysis/geom_refinement/PowderCalibration.cpp @@ -295,7 +295,12 @@ CalibrationResult CalibrateFromProfile(const std::vector &profile, && (best->uncertainty.sigma_rot1_rad > 0.0 || best->uncertainty.sigma_rot2_rad > 0.0); const float significance = tilt_was_free ? TiltSignificance(best->geometry, best->uncertainty) : 0.0f; bool tilt_refined = refine_tilt && tilt_was_free && significance >= TILT_MIN_SIGNIFICANCE; - if (refine_tilt && !tilt_refined) { + // Not `refine_tilt && !tilt_refined`: with --no-refine-tilt the tilt is never free, so + // tilt_refined is false and this branch was skipped entirely - leaving the rotations at the ZERO + // that GuessInitialGeometry sets, while the CLI reported them as held at the header value. A + // declined tilt and a tilt nobody asked to refine both need the header put back and the rest + // refitted around it. + if (!tilt_refined) { // From the header's tilt, not from the one being declined. fit_from now takes a whole geometry, // so without this the "pinned" refit would pin rot1/rot2 at exactly the unvalidated values the // gate just rejected - which is the same fault the gate exists to catch, reintroduced one level @@ -346,7 +351,12 @@ CalibrationResult CalibrateFromSpots(const std::vector &spots, && (unc.sigma_rot1_rad > 0.0 || unc.sigma_rot2_rad > 0.0); const float significance = tilt_was_free ? TiltSignificance(fitted, unc) : 0.0f; const bool tilt_refined = refine_tilt && tilt_was_free && significance >= TILT_MIN_SIGNIFICANCE; - if (refine_tilt && !tilt_refined) { + // Not `refine_tilt && !tilt_refined`: with --no-refine-tilt the tilt is never free, so + // tilt_refined is false and this branch was skipped entirely - leaving the rotations at the ZERO + // that GuessInitialGeometry sets, while the CLI reported them as held at the header value. A + // declined tilt and a tilt nobody asked to refine both need the header put back and the rest + // refitted around it. + if (!tilt_refined) { fitted.PoniRot1_rad(geom.GetPoniRot1_rad()).PoniRot2_rad(geom.GetPoniRot2_rad()); OptimizeGeometry(fitted, spots, calibrant_ring_q, false, &unc); }