--mode calibration fits five parameters - beam centre, distance and the two PONI tilts - and a program that cannot express a tilted detector has nowhere to put the last two. Dropping them after the fact is worse than never fitting them: the centre and the distance of a tilted fit have already absorbed the tilt, so the flattened geometry is right nowhere. rugnux --no-refine-tilt, the "Refine detector tilt" tick box on the viewer's Calib page and RingOptimizer's refine_tilt argument hold rot1/rot2 at the value the geometry came in with and fit the remaining three. That is the best flat-detector answer, and the one such a program would refine to itself. Measured on a five-distance calibrant series. At short distance the tilt is real and reproducible - three independent fits agreeing to 0.01 deg, radial rms 1.4 -> 0.4 px - and its direct beam agrees with the background beam-centre estimator to 0.05 px, so the tilted model is the physically right one. The pinned fit then displaces the centre 2.6 px to absorb the tilt and lands within 0.03 px of the same place at every distance. Past ~300 mm, where only two rings reach the detector, the tilt is instead under-determined: it comes out with the opposite sign to every short-distance fit and drags the PONI 28 px while the rms does not move (0.960 against 0.962). The existing degeneracy guard only fires on a strictly single ring, so it does not catch that; declining a tilt that does not pay for itself in rms is left for a separate change. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MxrrPcxodNiXzhNiECCVp5
29 lines
926 B
C++
29 lines
926 B
C++
// SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
|
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
|
|
#pragma once
|
|
|
|
#include <vector>
|
|
#include "../../common/DiffractionGeometry.h"
|
|
|
|
struct RingOptimizerInput {
|
|
float x;
|
|
float y;
|
|
double q_expected;
|
|
};
|
|
|
|
class RingOptimizer {
|
|
DiffractionGeometry reference;
|
|
bool refine_tilt;
|
|
public:
|
|
// refine_tilt = false holds the detector tilt (rot1/rot2) at the value the geometry came in with
|
|
// and fits only the beam centre and the distance. A tilted PONI is exact but not every consumer
|
|
// accepts one - XDS has no place to put it - so a calibration meant for such a program is better
|
|
// measured with the tilt pinned than with it refined and then dropped.
|
|
RingOptimizer(const DiffractionGeometry& geom, bool refine_tilt = true);
|
|
DiffractionGeometry Run(const std::vector<RingOptimizerInput> &input);
|
|
};
|
|
|
|
|
|
|