feat(flomni): warn on OSA collision risk when picking a foptz target
CI for csaxs_bec / test (push) Successful in 2m58s
CI for csaxs_bec / test (push) Successful in 2m58s
The tomo-queue "move_foptz_with_shift" dialog now shows a live warning when the entered foptz target would leave <=0 mm OSA clearance against a normal OMNY pin (same collision check fosa_in() already enforces for fosaz moves, surfaced here at data-entry time instead). Advisory only -- the queued action itself stays a plain absolute move, not gated on this. Extracted the clearance formula out of FlomniOpticsMixin._osa_remaining_space into a module-level compute_osa_remaining_space(foptz_val, fosaz_val) so the GUI (a separate process with only RPC device access, no Flomni instance to call a bound method on) can reuse the exact same formula instead of duplicating it. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NPZ9gzN2rt3wgiMnTKyrug
This commit is contained in:
1 parent
437d9e7559
commit
a5fcc73049
2 files changed
+64
-1
No files matched your search
@@ -9,6 +9,22 @@ class FlomniOpticsError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def compute_osa_remaining_space(foptz_val: float, fosaz_val: float) -> float:
|
||||
"""Clearance (mm) between the OSA and a normal OMNY pin for a given
|
||||
foptz/fosaz pair. <=0 means collision.
|
||||
|
||||
Module-level (not a method) so it can be imported and reused outside a
|
||||
live Flomni session -- e.g. by the tomo-queue GUI (tomo_params.py),
|
||||
which only has RPC device access (dev.foptz.readback.get()/
|
||||
dev.fosaz.readback.get()), not a Flomni instance to call a bound method
|
||||
on. FlomniOpticsMixin's own methods below are thin wrappers around this
|
||||
for the two directions actually used in a live session (varying fosaz
|
||||
at the current foptz, and vice versa) -- single source of truth for the
|
||||
formula/constant either way.
|
||||
"""
|
||||
return 33 - foptz_val - fosaz_val
|
||||
|
||||
|
||||
class FlomniOpticsMixin:
|
||||
@staticmethod
|
||||
def _get_user_param_safe(device, var):
|
||||
@@ -21,7 +37,7 @@ class FlomniOpticsMixin:
|
||||
"""Clearance (mm) between the OSA and a normal OMNY pin if fosaz were
|
||||
at `fosaz_target`, at the *current* foptz reading. <=0 means collision."""
|
||||
foptz_val = dev.foptz.readback.get()
|
||||
return -fosaz_target + (33 - foptz_val)
|
||||
return compute_osa_remaining_space(foptz_val, fosaz_target)
|
||||
|
||||
def _fheater_is_up(self) -> bool:
|
||||
axis_id = dev.fheater._config["deviceConfig"].get("axis_Id")
|
||||
|
||||
@@ -2186,6 +2186,53 @@ class CommandJobBuilderDialog(QDialog):
|
||||
label = f"{label} ({unit})"
|
||||
self._field_form.addRow(f"{label}:", widget)
|
||||
|
||||
if action_name == "move_foptz_with_shift" and "foptz_target" in self._step_field_widgets:
|
||||
self._build_osa_collision_warning()
|
||||
|
||||
def _build_osa_collision_warning(self) -> None:
|
||||
"""Live, advisory-only OSA-collision warning for
|
||||
move_foptz_with_shift's foptz_target field.
|
||||
|
||||
The move itself stays a plain absolute move (see
|
||||
_queue_action_move_foptz_with_shift's docstring) -- this just
|
||||
surfaces, at data-entry time, the same clearance check
|
||||
FlomniOpticsMixin.fosa_in() enforces (by refusing) for fosaz moves,
|
||||
so an operator can see a likely OSA collision before queuing a
|
||||
foptz target, without the queue action itself blocking on it.
|
||||
"""
|
||||
from csaxs_bec.bec_ipython_client.plugins.flomni.flomni_optics_mixin import (
|
||||
compute_osa_remaining_space,
|
||||
)
|
||||
|
||||
lbl = QLabel()
|
||||
lbl.setWordWrap(True)
|
||||
lbl.setStyleSheet("color: #B8860B;")
|
||||
lbl.setVisible(False)
|
||||
self._field_form.addRow("", lbl)
|
||||
|
||||
foptz_widget, _field = self._step_field_widgets["foptz_target"]
|
||||
|
||||
def _update(_value=None):
|
||||
fosaz = self._client.device_manager.devices.get("fosaz")
|
||||
if fosaz is None:
|
||||
return
|
||||
try:
|
||||
fosaz_val = fosaz.readback.get()
|
||||
except Exception:
|
||||
return
|
||||
clearance = compute_osa_remaining_space(foptz_widget.value(), fosaz_val)
|
||||
if clearance <= 0:
|
||||
lbl.setText(
|
||||
f"Warning: at this foptz target, OSA clearance would be "
|
||||
f"{clearance:.2f} mm (<=0 = collision risk with a normal OMNY pin)."
|
||||
)
|
||||
lbl.setVisible(True)
|
||||
else:
|
||||
lbl.setVisible(False)
|
||||
|
||||
foptz_widget.valueChanged.connect(_update)
|
||||
_update()
|
||||
|
||||
def _build_field_widget(self, field: dict) -> QWidget:
|
||||
field_type = field.get("type")
|
||||
if field_type == "float":
|
||||
|
||||
Reference in new issue
Block a user