From 7319e132bc0c626bc2c8ebc5aca23e1dce717d55 Mon Sep 17 00:00:00 2001 From: x01dc Date: Thu, 23 Jul 2026 15:50:18 +0200 Subject: [PATCH] refactor(LamNI): rename rotation-center calibration entry point, drop sample_type arg 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 --- .../bec_ipython_client/plugins/LamNI/lamni.py | 49 ++++++++++++++----- docs/user/ptychography/lamni.md | 8 ++- 2 files changed, 41 insertions(+), 16 deletions(-) diff --git a/csaxs_bec/bec_ipython_client/plugins/LamNI/lamni.py b/csaxs_bec/bec_ipython_client/plugins/LamNI/lamni.py index 7bb4ee1..eef0837 100644 --- a/csaxs_bec/bec_ipython_client/plugins/LamNI/lamni.py +++ b/csaxs_bec/bec_ipython_client/plugins/LamNI/lamni.py @@ -460,26 +460,53 @@ class LamNI(TomoQueueMixin, LamNIAlignmentMixin, LamNIOpticsMixin, LamniGuiTools aligner = XrayEyeAlignGUI(self.client, self) aligner.update_frame(keep_shutter_open=keep_shutter_open) - def rotation_center_calibration_start( - self, sample_type: str = "isolated", keep_shutter_open: bool = False - ): - """Determine new lsamx/lsamy rotation-center values via the X-ray eye GUI. + def xrayeye_rotation_center_calibration_isolated(self, keep_shutter_open: bool = False): + """Determine new lsamx/lsamy rotation-center values for a sparse/isolated + particle, via the X-ray eye GUI. - Creates a fresh :class:`XrayEyeAlignGUI` instance and calls its - ``find_rotation_center()`` method. The GUI window is opened - automatically. Interrupt with Ctrl-C to abort. + Compares the particle's imaged position at 0 and 180 deg -- the + midpoint of the two is the rotation axis' position, independent of + the axis tilt. No visual judgement call, no iteration. Args: - sample_type: "isolated" for a sparse/isolated particle (compares - its position at 0 and 180 deg), or "extended" for a - non-isolated sample (visual identification of the rotation - centre, with a verification sweep and iterate/accept prompt). keep_shutter_open: If True the shutter is left open between steps so the sample remains visible in live view. Returns: tuple: (new_lsamx_center, new_lsamy_center) in mm. """ + return self._xrayeye_rotation_center_calibration( + sample_type="isolated", keep_shutter_open=keep_shutter_open + ) + + def xrayeye_rotation_center_calibration_extended(self, keep_shutter_open: bool = False): + """Determine new lsamx/lsamy rotation-center values for a non-isolated/ + textured sample, via the X-ray eye GUI. + + Sweeps 0 -> 180 -> 0 deg with the live view open so the rotation + centre can be visually identified, then a single click is submitted + at 0 deg. After applying the correction, a verification sweep + (0 -> 45 -> 0 deg) runs and you're asked whether to accept the + alignment or run another iteration. + + Args: + keep_shutter_open: If True the shutter is left open between steps + so the sample remains visible in live view. + + Returns: + tuple: (new_lsamx_center, new_lsamy_center) in mm. + """ + return self._xrayeye_rotation_center_calibration( + sample_type="extended", keep_shutter_open=keep_shutter_open + ) + + def _xrayeye_rotation_center_calibration(self, sample_type: str, keep_shutter_open: bool): + """Shared implementation for the two public entry points above. + + Creates a fresh :class:`XrayEyeAlignGUI` instance and calls its + ``find_rotation_center()`` method. The GUI window is opened + automatically. Interrupt with Ctrl-C to abort. + """ aligner = XrayEyeAlignGUI(self.client, self) try: return aligner.find_rotation_center( diff --git a/docs/user/ptychography/lamni.md b/docs/user/ptychography/lamni.md index 511475b..8c9241d 100644 --- a/docs/user/ptychography/lamni.md +++ b/docs/user/ptychography/lamni.md @@ -24,12 +24,10 @@ The recommended way to (re-)measure `center` for a new sample is the GUI-driven **Automated rotation-center calibration** -`lamni.rotation_center_calibration_start(sample_type="isolated")` +This opens the X-ray eye widget and walks through the calibration interactively. Pick the function based on what's mounted: -This opens the X-ray eye widget and walks through the calibration interactively. Choose `sample_type` based on what's mounted: - -- `"isolated"` — for a sparse/isolated particle. You submit its centre position once at 0° and once at 180°; the midpoint of the two is the rotation axis' projected position (this works regardless of the axis tilt). No further confirmation step. -- `"extended"` — for a non-isolated/textured sample where the rotation centre can be identified visually. The sample sweeps 0° → 180° → 0° with the live view left open so you can watch for the point that doesn't move, then you submit a single click at 0°. The correction is applied, a short verification sweep (0° → 45° → 0°) runs, and you're asked *"Are you happy with this alignment, or shall we do another iteration?"* — answer `n` to refine further. +- `lamni.xrayeye_rotation_center_calibration_isolated()` — for a sparse/isolated particle. You submit its centre position once at 0° and once at 180°; the midpoint of the two is the rotation axis' projected position (this works regardless of the axis tilt). No further confirmation step. +- `lamni.xrayeye_rotation_center_calibration_extended()` — for a non-isolated/textured sample where the rotation centre can be identified visually. The sample sweeps 0° → 180° → 0° with the live view left open so you can watch for the point that doesn't move, then you submit a single click at 0°. The correction is applied, a short verification sweep (0° → 45° → 0°) runs, and you're asked *"Are you happy with this alignment, or shall we do another iteration?"* — answer `n` to refine further. At the end you're shown the computed `lsamx_center`/`lsamy_center` and asked to confirm before they're written via `dev.lsamx.update_user_parameter(...)` / `dev.lsamy.update_user_parameter(...)`.