report: say what the measured detector tilt is worth, and what it is not

The report invited the reader to check REFINED_DETECTOR_TILT against a powder
calibration. Measured over two detectors' worth of crystals, that check
misleads: the rotation fit does one outer round, so it leaves its starting
value by only a small and crystal-dependent fraction of the distance to the
calibrated value, and on the worse of the two detectors the per-crystal median
sits an order of magnitude further from the powder answer than either method's
uncertainty. A user comparing one run against their own calibration would
conclude the calibration was wrong.

What survives the aliasing is the direct beam, which is already printed beside
it, and the MEDIAN of the tilt over several crystals on one detector - enough
to show up a placeholder or a stale value in the file, not enough to replace a
calibration. Say that, and say not to feed one run's value back into the
instrument.

The conditioning law (VIF = 4.40 tan(2theta_95)^-1.66) was tested as a per-run
gate and does NOT order the errors - the crystals whose fit stays put are found
in the best-conditioned band as often as the worst - so no threshold is added
here.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EFEJG6WBQv8th4UJFNe53N
This commit is contained in:
2026-09-01 15:15:01 +02:00
co-authored by Claude Opus 5
parent 1a25d396a8
commit 51e90f5549
2 changed files with 12 additions and 3 deletions
+1
View File
@@ -19,6 +19,7 @@
* The `rugnux` report gives the detector tilt, the measured tilt and the direct beam beside the beam centre, and a post-refined beam centre is judged against the run's own measurement rather than the file's.
* `--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 HDF5 master file and the CBOR start message carry `direct_beam_x`/`direct_beam_y`, where the undeflected beam lands on the detector, beside the `beam_center_x`/`beam_center_y` PONI.
* The `rugnux` report says what its measured detector tilt is worth: one sweep determines the direct beam rather than the tilt itself, and only the median over several crystals on one detector is comparable with a powder calibration.
* 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
+11 -3
View File
@@ -119,9 +119,17 @@ std::string RenderResultReport(const std::string &output_prefix,
if (result.refined_detector_tilt_deg)
os << " REFINED_DETECTOR_TILT is rot1/rot2 in degrees as rotation indexing MEASURED them, and is\n"
<< " NOT what this run integrated at - nothing writes a refined tilt back onto the geometry.\n"
<< " It is here to be checked against a powder calibration, which measures the tilt from ring\n"
<< " SHAPE and is the better instrument for it. rot3 is omitted because a rotation about the\n"
<< " beam is an exact null of this experiment and the fit cannot move it.\n";
<< " One crystal does not measure a detector tilt. The tilt is aliased with the beam centre,\n"
<< " so what a single sweep determines is the DIRECT_BEAM above, not the split between the\n"
<< " two, and this fit stays close to the tilt it was started from - it moves a fraction of\n"
<< " the way to the true value, and the fraction varies from crystal to crystal. Comparing\n"
<< " one run against a powder calibration will therefore disagree with it by far more than\n"
<< " either number's uncertainty. What is worth comparing is the MEDIAN of this value over\n"
<< " several crystals collected on the same detector, which does track the calibration well\n"
<< " enough to show up a placeholder or a stale tilt in the file - it does not replace the\n"
<< " calibration. Do not feed a single run's value back into the instrument.\n"
<< " rot3 is omitted because a rotation about the beam is an exact null of this experiment\n"
<< " and the fit cannot move it.\n";
// The same geometry once more, as the object jfjoch_broker takes it in: the four required
// properties of dataset_settings in broker/jfjoch_api.yaml, spelled the way the API spells them.