Feat/xray centering lamni #270

Merged
holler merged 7 commits from feat/xray_centering_lamni into main 2026-07-24 13:02:02 +02:00
7 Commits
Author SHA1 Message Date
x01dcandClaude Sonnet 5 ddc4c0c2dd fix(LamNI): unambiguous confirmation wording, freeze frame before click
CI for csaxs_bec / test (push) Successful in 1m43s
CI for csaxs_bec / test (pull_request) Successful in 1m43s
- Reword the extended-loop accept/iterate prompt: the old either/or
  phrasing made a "yes" answer ambiguous about which half it affirmed.
- Freeze a single frame (and close the shutter/live-view per
  keep_shutter_open) before requesting the rotation-centre click, same
  as every other click site in this file -- previously the shutter and
  5 Hz live view stayed on for the whole time the operator was
  deciding where to click, exposing the sample for no benefit.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-24 12:42:30 +02:00
x01dcandClaude Sonnet 5 e8cee257c3 fix(LamNI): accumulate rotation-center shift across calibration iterations
CI for csaxs_bec / test (push) Successful in 1m44s
CI for csaxs_bec / test (pull_request) Successful in 1m47s
lamni_move_to_scan_center's shift_x/shift_y are absolute offsets from the
currently-configured lsamx_center/lsamy_center (unchanged until the operator
confirms at the end of the procedure), not incremental deltas from wherever
the stage currently sits. The extended-sample iteration loop was passing
only the latest click's delta each time, so each new iteration partially
undid the previous one's correction instead of adding to it. Fixed by
accumulating the total shift across iterations and always applying the
running total.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-23 16:21:48 +02:00
x01dc 227cbb43ec comment adjusted
CI for csaxs_bec / test (push) Successful in 2m37s
CI for csaxs_bec / test (pull_request) Successful in 3m6s
2026-07-23 15:53:51 +02:00
x01dcandClaude Sonnet 5 a3ea0a10cd refactor(LamNI): rename rotation-center calibration entry point, drop sample_type arg
CI for csaxs_bec / test (push) Successful in 1m50s
rotation_center_calibration_start(sample_type="isolated") didn't match the
xrayeye_* naming convention used by the other X-ray eye entry points, and
the sample_type string enum was easy to forget (both the parameter name
and its accepted values). Split into two entry points instead:

  lamni.xrayeye_rotation_center_calibration_isolated(keep_shutter_open=False)
  lamni.xrayeye_rotation_center_calibration_extended(keep_shutter_open=False)

Both delegate to a shared _xrayeye_rotation_center_calibration() private
helper (single copy of the KeyboardInterrupt cleanup). Updated the user
docs to match; XrayEyeAlign.find_rotation_center()'s own sample_type
parameter is unchanged since it's internal shared implementation, not
what was being objected to.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-23 15:50:18 +02:00
x01dcandClaude Sonnet 5 3378a493c7 fix(LamNI): remove redundant rotate, simplify sweep, add center precondition
Three refinements found while testing find_rotation_center() against the
simulated LamNI:

- Drop the trailing tomo_rotate(0) at the end of find_rotation_center():
  both the isolated path (explicit rotate-back before applying the
  correction) and the extended path (verification sweep ends at 0) already
  leave lsamrot at 0 by then, so it was a pure duplicate move.

- Simplify _live_sweep() to rotate directly to each waypoint instead of
  stepping through artificial step_deg-sized sub-moves with settle pauses
  in between -- a single tomo_rotate() already produces continuous physical
  rotation, so the stepping added nothing but jerkier motion and extra
  queue overhead.

- Add _ensure_at_configured_center(), called at the start of
  find_rotation_center() before lfzp_in(). lamni_move_to_scan_center's
  interferometer-drift safety check (LamNIFermatScan.py) assumes lsamx/
  lsamy start near their configured center and silently skips the entire
  corrective move if that drift exceeds 150um -- exactly the situation
  find_rotation_center() is meant to handle, since its purpose is
  recalibrating a potentially-stale center. Confirmed this was a real gap:
  a run where the stage hadn't started at its configured center produced a
  correct absolute target (verified via the interferometer reading) but a
  confusingly small apparent motor delta.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-23 15:44:13 +02:00
x01dcandClaude Sonnet 5 b66aeae2d3 fix(LamNI): ensure OSA is out before requesting the FZP-centre click
Both align() and find_rotation_center() moved the FZP in and immediately
asked the operator to click its centre, but only confirmed OSA was out
afterwards (via loptics_out(), which runs after that click). If OSA was
left in from a previous scan setup, it would still be in the beam path
during the FZP reference click. Add an explicit losa_out() call right
before lfzp_in() in both procedures; it's a cheap, skip-if-already-out
no-op otherwise.

Found while testing find_rotation_center() against the simulated LamNI.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-23 15:25:20 +02:00
x01dcandClaude Sonnet 5 c7fd0d3f1a feat(LamNI): add automated rotation-center calibration via X-ray eye
CI for csaxs_bec / test (push) Successful in 1m37s
lsamx_center/lsamy_center have to be re-measured by hand for nearly every
new sample (the rotation stage is tilted on top of lsamx/lsamy, so the
effective axis position shifts with sample thickness/mounting). Add
XrayEyeAlign.find_rotation_center()/lamni.rotation_center_calibration_start()
to automate this using the existing X-ray eye GUI and lamni_move_to_scan_center
interferometer-feedback move:

- "isolated" sample: click particle centre at 0 and 180 deg, use the
  midpoint (angle-tilt-independent) as the rotation axis position.
- "extended" sample: live 0->180->0 sweep for visual identification, single
  click, then a verification sweep and an accept/iterate prompt.

Both write the result to lsamx/lsamy's "center" userParameter after
confirmation. Heavily verbose logging throughout since this is fundamentally
an interactive, hardware-in-the-loop procedure that can't be fully exercised
by automated tests.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-23 10:00:49 +02:00