fix(flomni): beamline detection for the trigger source by ddg1 only (exposure box motors removed)
Mirko 2026-10-27: a real (not simulated) ddg1 is sufficient. Simulated or no ddg1 -> soft trigger; a failing check still counts as beamline (hardware trigger). Docs + PDF. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017KicuVBRC7jB1TLG5hLZwx
This commit was merged in pull request #344.
This commit is contained in:
1 parent
5e3b4b50d5
commit
6e0ffa3b74
4 files changed
+11
-24
No files matched your search
+4
-5
@@ -70,11 +70,10 @@ default and is in no profile (flOMNI `FeedbackLoop/soft_trigger.md`).
|
||||
**`flomni_fermat_scan` sets the trigger source at every scan start** (2026-10-26):
|
||||
|
||||
- **At the beamline → hardware.** At the beamline means: `ddg1` is configured with a real (not simulated) device
|
||||
class, or one of the exposure box motors `ebtrx`, `ebtry`, `ebtrz`, `ebsupport` is in the session. If this cannot
|
||||
be confirmed (web HMI not reachable, refused) the scan is aborted: with the soft trigger the detector would not
|
||||
be triggered while flOMNI exposes internally. A failing check also counts as beamline.
|
||||
- **Otherwise (simulated `ddg1`, no beamline devices) → soft** with `soft_exposure_ms` = `exp_time` ×
|
||||
`frames_per_trigger` × 1000. If that fails the scan continues with a warning (alarm).
|
||||
class (only `ddg1` decides, 2026-10-27). If this cannot be confirmed (web HMI not reachable, refused) the scan is
|
||||
aborted: with the soft trigger the detector would not be triggered while flOMNI exposes internally. A failing check
|
||||
also counts as beamline.
|
||||
- **Otherwise (simulated or no `ddg1`) → soft** with `soft_exposure_ms` = `exp_time` × `frames_per_trigger` × 1000. If that fails the scan continues with a warning (alarm).
|
||||
|
||||
By hand: `flomni.rt_settings.trigger_set_soft(True, exposure_ms=100)`, `trigger_set_soft(False)`;
|
||||
`trigger_show()` shows both groups.
|
||||
|
||||
BIN
Binary file not shown.
@@ -69,10 +69,6 @@ class FlomniFermatScan(ScanBase):
|
||||
MAX_CORRIDOR_SIZE = 3 # Corridor size is capped at this value (in um) for stability
|
||||
MIN_FERMAT_ASYMMETRY = 0.1 # Practical working range for fermat_asymmetry (soft-clamped)
|
||||
MAX_FERMAT_ASYMMETRY = 10.0
|
||||
# Devices that exist only in the beamline configuration (bl_endstation.yaml: exposure box motors); with one of
|
||||
# them, or a ddg1 that is not simulated, the session is at the beamline -> hardware trigger (flOMNI soft trigger,
|
||||
# FeedbackLoop/soft_trigger.md, 2026-10-26)
|
||||
BEAMLINE_DEVICES = ("ebtrx", "ebtry", "ebtrz", "ebsupport")
|
||||
|
||||
def __init__(
|
||||
# fmt: off
|
||||
@@ -386,26 +382,20 @@ class FlomniFermatScan(ScanBase):
|
||||
|
||||
def at_beamline(self) -> tuple[bool, str]:
|
||||
"""
|
||||
Is this session at the beamline? True when ddg1 is configured with a real (not simulated) device class or
|
||||
one of BEAMLINE_DEVICES is configured; False only when both say no. A failing check counts as beamline,
|
||||
so the hardware trigger is the fallback.
|
||||
Is this session at the beamline? True when ddg1 is configured with a real (not simulated) device class
|
||||
(flOMNI soft trigger, FeedbackLoop/soft_trigger.md; ddg1 only, Mirko 2026-10-27). A failing check counts as
|
||||
beamline, so the hardware trigger is the fallback.
|
||||
|
||||
Returns:
|
||||
(at_beamline, reason)
|
||||
"""
|
||||
try:
|
||||
devices = self.device_manager.devices
|
||||
reasons = []
|
||||
if "ddg1" in devices:
|
||||
cls = str((getattr(devices["ddg1"], "_config", None) or {}).get("deviceClass", ""))
|
||||
if ".sim." not in cls and "Simulated" not in cls:
|
||||
reasons.append(f"ddg1 is {cls or 'not simulated'}")
|
||||
found = [name for name in self.BEAMLINE_DEVICES if name in devices]
|
||||
if found:
|
||||
reasons.append("beamline devices " + ", ".join(found))
|
||||
if reasons:
|
||||
return True, "; ".join(reasons)
|
||||
return False, "no beamline devices, ddg1 simulated or absent"
|
||||
return True, f"ddg1 is {cls or 'not simulated'}"
|
||||
return False, "ddg1 simulated or absent"
|
||||
except Exception as exc: # pylint: disable=broad-except
|
||||
return True, f"beamline check failed ({exc}), treated as beamline"
|
||||
|
||||
|
||||
@@ -162,7 +162,6 @@ def _trigger_stub(devices, apply_result=None, apply_exc=None, exp_time=0.1, fram
|
||||
"""A stand-in for a FlomniFermatScan instance with a device list {name: deviceClass} and the loop-settings
|
||||
device answering /api/settings/apply."""
|
||||
scan = mock.MagicMock()
|
||||
scan.BEAMLINE_DEVICES = FlomniFermatScan.BEAMLINE_DEVICES
|
||||
scan.device_manager.devices = {
|
||||
name: mock.MagicMock(_config={"deviceClass": cls}) for name, cls in devices.items()
|
||||
}
|
||||
@@ -187,9 +186,8 @@ def test_at_beamline_detection():
|
||||
assert FlomniFermatScan.at_beamline(_trigger_stub({"ddg1": SIM_DDG1}))[0] is False
|
||||
assert FlomniFermatScan.at_beamline(_trigger_stub({}))[0] is False
|
||||
assert FlomniFermatScan.at_beamline(_trigger_stub({"ddg1": REAL_DDG1}))[0] is True
|
||||
# a beamline-only device counts even with a simulated ddg1
|
||||
at_bl, reason = FlomniFermatScan.at_beamline(_trigger_stub({"ddg1": SIM_DDG1, "ebtrx": MOTOR}))
|
||||
assert at_bl is True and "ebtrx" in reason
|
||||
# only ddg1 decides: other devices (e.g. exposure box motors) do not count
|
||||
assert FlomniFermatScan.at_beamline(_trigger_stub({"ddg1": SIM_DDG1, "ebtrx": MOTOR}))[0] is False
|
||||
# a failing check counts as beamline (hardware trigger is the fallback)
|
||||
scan = _trigger_stub({})
|
||||
scan.device_manager.devices = None
|
||||
|
||||
Reference in new issue
Block a user