Flomni fixes during beamtimes 1 #317

Merged
holler merged 28 commits from flomni_fixes_during_beamtimes into main 2026-09-15 08:30:21 +02:00
28 Commits
Author SHA1 Message Date
x12saandClaude Sonnet 5 cc93d563bf fix(tests): accept _internal kwarg in tomo_scan_projection test doubles
CI for csaxs_bec / test (pull_request) Successful in 2m6s
Read the Docs Deploy Trigger / trigger-rtd-webhook (push) Successful in 2s
CI for csaxs_bec / test (push) Successful in 2m8s
7d64b49 added an _internal kwarg to LamNI.tomo_scan_projection() (used
by tomo_alignment_scan/_at_each_angle to skip the redundant per-angle
filter-out-of-beam check) but left three tests' fake/lambda
replacements without it, causing them to fail in CI with
"got an unexpected keyword argument '_internal'".

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FFeiCHv3qUxxssmP9Qzhom
2026-09-15 08:27:47 +02:00
x12sa f916b2cec1 config update
CI for csaxs_bec / test (push) Failing after 2m12s
CI for csaxs_bec / test (pull_request) Failing after 2m15s
2026-09-15 08:22:55 +02:00
x12saandClaude Sonnet 5 6e8fc91924 docs(omny): fix omny_fermat_scan parameter table and add docstring example
CI for csaxs_bec / test (push) Failing after 2m10s
Reorders omny.md's parameter table to match the actual signature,
adds the previously undocumented readout_time parameter, and adds an
Examples block to OmnyFermatScan's docstring (mirroring the flomni fix).
Also rewords flomni.md's corridor_size default to read "3 um" for
consistency with omny, while noting it is auto-estimated when omitted.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FFeiCHv3qUxxssmP9Qzhom
2026-09-14 20:52:03 +02:00
x12saandClaude Sonnet 5 5141854e14 docs(flomni): fix flomni_fermat_scan parameter table to match code
CI for csaxs_bec / test (push) Failing after 2m5s
Reorders parameters to match the actual signature, adds the
undocumented burst_at_each_point parameter, and corrects the
corridor_size default (None/auto-estimated, not a literal 3 um).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FFeiCHv3qUxxssmP9Qzhom
2026-09-14 20:47:20 +02:00
x12saandClaude Sonnet 5 2753bb9243 docs(flomni): add usage example to flomni_fermat_scan docstring
CI for csaxs_bec / test (push) Failing after 2m10s
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FFeiCHv3qUxxssmP9Qzhom
2026-09-14 20:12:27 +02:00
x12saandClaude Sonnet 5 501c93d41c fix(flomni): use last completed scan number when tomo_reconstruct's cached scan list is stale
CI for csaxs_bec / test (push) Failing after 2m4s
tomo_reconstruct() named the queue file from a fresh next_scan_number but
wrote its content from self._current_scan_list, which is only kept in sync
by tomo_scan_projection()/tomo_acquire_at_angle(). Calling it directly from
the command line -- e.g. after a plain scans.flomni_fermat_scan() -- wrote
whatever scan list was left over from an earlier tomo scan, or raised
AttributeError if none had run yet this session.

Falls back to [next_scan_number - 1] whenever the cached list's last entry
doesn't match the scan that actually just completed. Internal callers are
unaffected since their cached list always matches at the point they call it.

Also notes the identical bug in OMNY.tomo_reconstruct() (a separate,
non-shared implementation) as a TODO for a later fix on its own branch.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TUimPoyFQRvxM6R3njvuVj
2026-09-14 17:06:02 +02:00
x12saandClaude Sonnet 5 df7c90c5d7 docs(omny): document manual tomo_alignment_fit offset nudge
CI for csaxs_bec / test (push) Failing after 2m5s
Port the flomni doc addition to omny -- both setups share the identical
tomo_alignment_fit mechanism (OMNYAlignmentMixin.get_alignment_offset
mirrors Flomni's), so the same command-line offset nudge applies verbatim.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FFeiCHv3qUxxssmP9Qzhom
2026-09-13 21:56:15 +02:00
x12saandClaude Sonnet 5 d100af5429 docs(flomni): document manual tomo_alignment_fit offset nudge
CI for csaxs_bec / test (push) Failing after 2m16s
Add a snippet to the XrayEye alignment section showing how to patch the
constant x/y offset terms of tomo_alignment_fit directly on the command
line, for a quick few-micron correction (e.g. after moving foptz) without
recording a new fit.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FFeiCHv3qUxxssmP9Qzhom
2026-09-13 21:54:42 +02:00
x12saandClaude Sonnet 5 5a22651c46 fix(flomni): report correct projection count in tomo PDF/SciLog for golden-ratio scans
CI for csaxs_bec / test (push) Failing after 2m7s
write_pdf_report() always derived "Number of projections" (and the
dependent sub-tomogram-count/angular-step fields) from
_tomo_type1_actual_grid(), which is only valid for tomo_type==1. For
golden-ratio scans (tomo_type 2/3) it silently reported a stale,
unrelated type-1 total left over in the persistent tomo_angle_stepsize
global var instead of golden_max_number_of_projections, causing the
PDF/SciLog entry to disagree with the web page's correct progress
display. Branch on tomo_type the same way tomo_parameters() already
does.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FFeiCHv3qUxxssmP9Qzhom
2026-09-12 20:31:24 +02:00
x12saandClaude Sonnet 5 2dae9441ec docs(ids-cameras): extend exposure/gain plan to xrayeye widget controls
CI for csaxs_bec / test (push) Failing after 2m10s
No code changes -- IDSCamera and the xrayeye widget are both used
during beamtimes. Revises the earlier plain-method design to
Cpt(Signal, kind=Kind.config) (mirroring live_mode_enabled) so the
xrayeye widget can read exposure/auto-exposure/auto-gain state via
its existing device_read_configuration subscription instead of
polling the device, and adds the corresponding GUI control knobs
(auto-exposure/auto-gain toggles, exposure spinbox) to the plan.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014s92UHyMfov6Fb934pGqcU
2026-09-11 20:30:54 +02:00
x12saandClaude Sonnet 5 ec3e7c0679 docs(ids-cameras): add plan for manual exposure/auto-gain control
CI for csaxs_bec / test (push) Failing after 2m5s
No code changes -- IDSCamera is in production use during beamtimes.
Documents the intended USER_ACCESS additions (get/set_exposure_time,
set_auto_exposure_enabled, set_auto_gain_enabled) for a future session.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014s92UHyMfov6Fb934pGqcU
2026-09-11 18:01:49 +02:00
x12saandClaude Sonnet 5 0cadd8582e fix(flomni,omny): sanitize sample name spaces in tomography_scannumbers.txt
CI for csaxs_bec / test (push) Failing after 19m49s
The scannumbers log is read column-wise by downstream tooling; a
sample name containing spaces breaks that whitespace-based parsing
since it's written as the trailing field. Replace spaces with
underscores before writing.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FB3kYVkJruYsmcVsj7RS1G
2026-09-11 16:24:12 +02:00
x12saandClaude Sonnet 5 47a9c4c444 fix(flomni,lamni): persist tomo_id across client restarts
CI for csaxs_bec / test (push) Failing after 4m17s
self.tomo_id was a plain instance attribute reset to -1 on every
Flomni/LamNI init, so resuming a tomo scan after a client/kernel restart
(tomo_scan_resume(), or tomo_queue_execute()'s automatic resume) kept
reporting/uploading under the wrong id instead of the one actually
registered with OMNY for that measurement.

Back it with the existing _GlobalVarParam descriptor on TomoQueueMixin
(the same BEC Redis-backed global-var mechanism already used for
tomo_shellstep, stitch_x, at_each_angle_hook, etc.) so it survives a
restart like the rest of the tomo-scan state already does.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013gGu5ANBo88Fh7eqmRdFbU
2026-09-11 16:19:10 +02:00
x12saandClaude Sonnet 5 da4007d7e7 fix(flomni,lamni): stop registering test/gac accounts against production omny.psi.ch
TomoIDManager.OMNY_URL and TEST_OMNY_URL both point at omny.psi.ch since
the dedicated omny-test.psi.ch host was retired, so the eaccount check no
longer redirects test/gac-* accounts anywhere different -- it just logs a
warning and still registers them in the production sample database. Skip
registration entirely for non-e-accounts and return FALLBACK_TOMO_ID
instead, to avoid polluting production with test entries.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013gGu5ANBo88Fh7eqmRdFbU
2026-09-11 16:18:51 +02:00
x12saandClaude Sonnet 5 42739fcc7a docs(flomni): flag unguarded heater-vs-OSA collision gap in fosa_in()
CI for csaxs_bec / test (push) Failing after 4m58s
Audit of heater interlocks (pre-first-use) found that fosa_in()/
foptics_in() never check fheater position before driving fosaz, even
though the OSA travels inside the heater's envelope. Heater motion
itself is well protected (ensure_osa_back()/ensure_fheater_up()), but
this one direction is open. Not fixing it yet -- documenting it so it
is remembered when fheater's userParameter is added during hardware
commissioning.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XdHenMmwbrCz1juWMi1yZc
2026-09-11 13:15:58 +02:00
x12saandClaude Sonnet 5 f56d11d730 fix(flomni): close race between sample-storage EPICS writes and reads
CI for csaxs_bec / test (push) Failing after 6m18s
ftransfer_sample_change occasionally raised "The gripper does not carry
a sample" right after a successful get, even though the gripper
physically held one. Root cause: flomni_modify_storage_non_interactive
wrote the sample_in_gripper/sample_placed signals with EpicsSignal.set()
without waiting for the write to complete, and the immediately-following
is_sample_in_gripper()/is_sample_slot_used() checks read the
auto_monitor-cached value, which could still reflect the pre-write state.

Wait on each .set() call (5s timeout, matching the existing
.set(...).wait(timeout=...) pattern used elsewhere for EPICS writes),
and force is_sample_in_gripper()/is_sample_slot_used() to do a live
get(use_monitor=False) read instead of trusting the monitor cache
(mirroring the same pattern already used in ddg_1.py). This closes the
race deterministically instead of masking it with an arbitrary sleep.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XdHenMmwbrCz1juWMi1yZc
2026-09-11 10:18:29 +02:00
x12saandClaude Sonnet 5 59cdc5c512 fix(omny): increase laser tracker on-target wait timeout, add status print
CI for csaxs_bec / test (push) Failing after 7m30s
Bump max_repeat from 25 to 100 (~12.5s to ~50s) in
laser_tracker_wait_on_target, since the tracker was timing out too
early during beamtime. Print a status message once the retry-enable
branch kicks in so it's visible the wait is still in progress.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XdHenMmwbrCz1juWMi1yZc
2026-09-11 09:11:37 +02:00
x12saandClaude Sonnet 5 d6e2ca8d1a fix(omny): mitigate scrambled Galil PUT/GET communication with settle delays
GalilController had zero delay in its socket path (write immediately
followed by a blocking read), unlike sgalil_ophyd.py's GalilController
which already sleeps 10ms in both socket_put and socket_get. This
increased the chance of partial-packet collisions/desync between
commands and responses during flomni beamtime (see command_history
showing merged/missing PUT-GET pairs).

Add a 10ms sleep to socket_put and a socket_get override (also with a
10ms sleep) that logs into command_history, mirroring the existing
sgalil_ophyd.py pattern. This reduces desync likelihood but does not
fully fix it: failed socket_get attempts are still swallowed silently
by retry_once with no trace in command_history, and receive() still
does a single recv(1024) with no terminator framing.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XdHenMmwbrCz1juWMi1yZc
2026-09-11 09:11:08 +02:00
x12saandClaude Sonnet 5 780be4bb9f config(ptycho_flomni): update axis calibration values, disable omny_panda
Update fttrx, foptx, ftransy sensor_voltage, fosax and fosay calibration
values for current beamtime alignment. Disable omny_panda device.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XdHenMmwbrCz1juWMi1yZc
2026-09-11 09:10:26 +02:00
x12saandClaude Sonnet 5 0fd52d23e4 config(main): switch active endstation config to flomni
Disable xeye/ssaxs includes and enable ptycho_flomni for flomni beamtime.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XdHenMmwbrCz1juWMi1yZc
2026-09-11 09:09:59 +02:00
x12saandClaude Sonnet 5 0627221491 config(bl_detectors): switch active detector from eiger_9 to eiger_1_5
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XdHenMmwbrCz1juWMi1yZc
2026-09-11 09:09:43 +02:00
x12saandClaude Sonnet 5 031e612394 fix(flomni): re-enable webpage generator start
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XdHenMmwbrCz1juWMi1yZc
2026-09-11 09:09:24 +02:00
x12saandClaude Sonnet 5 36d34d2858 fix(eps): cap alarm texts per event to stop eps_alarm_history.json growing unbounded
CI for csaxs_bec / test (push) Failing after 7m36s
A long-running/flapping EPS alarm appended every slightly-different
AlarmList_EPS text to the open event's texts list with no limit,
eventually growing eps_alarm_history.json past the upload server's
size limit (HTTP 413), which then retried and re-failed indefinitely.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XdHenMmwbrCz1juWMi1yZc
2026-09-11 09:07:25 +02:00
x12saandClaude Sonnet 5 e65389376d fix(flomni): fix UnboundLocalError for dev in tomo_scan_projection
CI for csaxs_bec / test (push) Failing after 2m19s
dev = builtins.__dict__.get("dev") was only executed inside the
`if not _internal:` block, but Python treats any name assigned
anywhere in a function as local to the whole function. The
unconditional dev.rtx.controller.laser_tracker_check_signalstrength()
call later in the function then raised UnboundLocalError whenever
_internal=True (e.g. tomo_alignment_scan() and the fermat branch of
_at_each_angle). Hoist the fetch above the guard so dev is always
bound.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018CUx5yV1iCBhL5sFEHEoPe
2026-09-11 07:46:23 +02:00
x12saandClaude Sonnet 5 3bea6b1a30 docs(flomni): add cSAXS_HR August 2018_chip_maxime.pdf
CI for csaxs_bec / test (push) Failing after 2m3s
New reference PDF in the flomni docs folder, served by flomnigui_docs().

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018CUx5yV1iCBhL5sFEHEoPe
2026-09-10 16:46:57 +02:00
x12saandClaude Sonnet 5 a457865768 docs(omny): TODO for filter check and missing eye/optics gate
CI for csaxs_bec / test (push) Failing after 2m3s
Notes for the OMNY branch: 1) port the filter-out-of-beam check (added
for flomni/lamni in the previous commit, shared helper already in
OMNY_shared/filter_check.py) into omny.py's tomo_scan()/
tomo_scan_projection(); 2) OMNY.tomo_scan() has no eye-out/optics-in
precondition check at all, unlike Flomni/LamNI's - a pre-existing,
unrelated gap noticed while investigating the filter check.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018CUx5yV1iCBhL5sFEHEoPe
2026-09-10 15:41:02 +02:00
x12saandClaude Sonnet 5 7d64b49918 feat(flomni,lamni): hard-warn if beam filters are not out before scans
Adds a shared filters_out_of_beam()/warn_and_confirm() helper
(OMNY_shared/filter_check.py) that checks the four cSAXS exposure-box
filter axes (filter_array_1_x..4_x) against their "out" position, reusing
cSAXSFilterTransmission's own position table.

Wired into flomni.py and lamni.py at every point a scan can start:
tomo_scan() and tomo_alignment_scan() (once per run, same interactive/
queued warn-and-confirm convention as the existing X-ray-eye/optics
check), and tomo_scan_projection() (every direct/standalone call, via a
new _internal flag on LamNI's method mirroring flomni's existing one;
internal per-angle loop calls skip the redundant re-check). Since
tomo_queue_execute() already calls tomo_scan(interactive=False) once per
queued job, queued runs get exactly one warn-and-proceed check at queue
start, not one per projection.

DataDrivenLamNI.tomo_scan() (extra_tomo.py) fully overrides the base
method, so it gets its own copy of the same top-of-scan check.

OMNY intentionally not touched here - left as follow-up on the user's
separate OMNY branch, see the OMNY AI_docs TODO in the next commit.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018CUx5yV1iCBhL5sFEHEoPe
2026-09-10 15:40:52 +02:00
x12saandClaude Sonnet 5 36e19adde4 fix(flomni): make flomnigui_show_* macros idempotent
CI for csaxs_bec / test (push) Successful in 2m8s
flomnigui_show_gui() unconditionally called self.gui.flomni.raise_window()
whenever the flomni window already existed. That RPC call is currently
buggy in bec_widgets and can hide the window instead of bringing it to
front, so calling any flomnigui_show_* macro a second time (e.g. from a
script) made the GUI disappear. Disable the raise_window() call, matching
the same workaround already applied in flomnigui_raise(); repeat calls now
just update content in place instead of re-raising.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018CUx5yV1iCBhL5sFEHEoPe
2026-09-10 14:00:48 +02:00