diff --git a/csaxs_bec/bec_ipython_client/plugins/flomni/flomni_optics_mixin.py b/csaxs_bec/bec_ipython_client/plugins/flomni/flomni_optics_mixin.py index a7caa26..42d9167 100644 --- a/csaxs_bec/bec_ipython_client/plugins/flomni/flomni_optics_mixin.py +++ b/csaxs_bec/bec_ipython_client/plugins/flomni/flomni_optics_mixin.py @@ -72,19 +72,50 @@ class FlomniOpticsMixin: else: print("FZP is already at the in position.") - def ffzp_in(self): + return need_move_optics + + def ffzp_in(self, force_feedback_reset=False): """ move in the flomni zone plate. - This will disable rt feedback, move the FZP and re-enabled the feedback. + This will disable rt feedback, move the FZP and re-enable the feedback. + + The FZP move requires rt feedback OFF, and moving the FZP invalidates + the interferometer zero, so feedback is re-enabled *with reset* + afterwards. That reset is expensive: it re-zeros the interferometers + and moves you away from wherever the sample currently sits, which is + undesirable when the FZP is already in and feedback is already running + (e.g. repeated alignment scans, or interleaving an alignment run into a + tomogram). + + Therefore the disable/move/reset cycle is skipped entirely when the FZP + does not actually need to move. Pass ``force_feedback_reset=True`` to + force the full disable + reset cycle even if the FZP is already in. """ - if "rtx" in dev and dev.rtx.enabled: + rtx_present = "rtx" in dev and dev.rtx.enabled + + # Only disable feedback if we're going to move the FZP (or a reset was + # explicitly requested). If the FZP is already in and feedback is + # already running, leave it untouched -- disabling and + # re-enabling-with-reset would needlessly re-zero the interferometers. + needs_move = not self._ffzp_is_in() + do_cycle = needs_move or force_feedback_reset + + if rtx_present and do_cycle: dev.rtx.controller.feedback_disable() self._ffzp_in() - if "rtx" in dev and dev.rtx.enabled: + if rtx_present and do_cycle: dev.rtx.controller.feedback_enable_with_reset() + def _ffzp_is_in(self, tol=0.003): + """True if both FZP axes (foptx, fopty) are within ``tol`` of their IN position.""" + foptx_in = self._get_user_param_safe("foptx", "in") + fopty_in = self._get_user_param_safe("fopty", "in") + return np.isclose(dev.foptx.readback.get(), foptx_in, atol=tol) and np.isclose( + dev.fopty.readback.get(), fopty_in, atol=tol + ) + def foptics_in(self): """ Move in the flomni optics, including the FZP and the OSA. @@ -290,5 +321,4 @@ class FlomniOpticsMixin: print( f" Note: OSA is {(-diff)*1000:.1f} um away from its IN position (likely parked OUT)." ) - print(f" Remaining space if OSA is moved to its IN position: \033[1m{remaining_at_in:.1f}\033[0m") - \ No newline at end of file + print(f" Remaining space if OSA is moved to its IN position: \033[1m{remaining_at_in:.1f}\033[0m") \ No newline at end of file