The first run against real files produced numbers that were entirely wrong, in three separate ways. The metadata now reads correctly (num_lines, frames_per_trigger), which is what exposed them. **Wrong arrays.** These files hold two populations: the MCS channels, which are the per-point scan data, and the monitored devices, sampled opportunistically while a line runs. The monitored set has more signals, so "the length shared by the most signals" landed on it -- and it is not on the scan grid at all. S00473 was analysed as 881x17 when the metadata says 203 x 428 = 86884, exactly the MCS length. The grid length is now taken from the metadata when it matches an array present in the file. **Wrong axis.** The fast axis was chosen by how monotonically a signal ramps, and picked `curr` -- the SLS ring current, which decays smoothly through any window and beats the motor at its own metric. Positioners are now identified structurally, by having a `<dev>_user_setpoint` sibling, which is what actually makes a device a motor. **Wrong assumption that both checks share one array.** They do not. Intensity lives on the scan grid; motor position lives in the monitored stream at its own rate and with its own line boundaries. The two checks now read their own data and say so. This also surfaces a real limitation: cont_grid records roughly 8 position samples per line in S00254 against 205 data points, so a partial stall can hide between samples. The script warns when sampling is that sparse rather than reporting a confident negative. **Truncated reporting hid the reported symptom.** The artefacts are said to appear towards the end of scans, and the flagged-line list was cut after 25 entries with "... and 221 more" -- which is precisely where an end-of-scan cluster would be lost. Flagged lines are now summarised by tenth of the scan, with an explicit verdict on whether they cluster at the start, the end, or not at all, and both ends of the list are printed. Bug 1 gains a matching across-scan trend, since end-of-scan degradation is a different question from end-of-line. Verified against a file shaped like the real ones: MCS grid plus a sparse motor stream, an end-of-line intensity drop, and stalls confined to the last tenth. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Debug scripts
Throwaway diagnostics for investigating beamline problems. Not part of the plugin:
nothing here is imported by csaxs_bec, and none of it needs BEC or a venv beyond the
libraries each script names.
Kept on the debug/scan-artefacts branch rather than main so that a half-finished
diagnostic never reaches a production checkout. Promote anything that turns out to be
generally useful; delete the rest once the question it answered is settled.
scan_artefact_check.py
Desk check for the July 2026 commissioning scan artefacts reported by Andreas Apseros and Kazu Hirosawa. Read-only — opens BEC master files and writes nothing.
python3 scan_artefact_check.py --root /sls/x12sa/data/p23080/raw/data \
--scan 473 --scan 450 --scan 411 --scan 254
Answers two questions without beam:
- end-of-line intensity — is the last point of every line systematically weaker, and is the first point affected too (which would mean a different mechanism)?
- dropped line motion — did the fast axis actually travel on every line? A line whose span collapsed is motion that did not happen while the scan still reported success.
Include a known-clean scan (254) so a null result distinguishes "this scan was fine" from "the analysis is wrong".
Run --list first if anything looks off; it dumps the file structure.
The motion check reads the fast-axis readback. If that axis is an open-loop stepper with no encoder, the readback is the commanded position and lost steps are invisible: a collapsed span still proves failure, but a healthy span proves nothing.