Commit Graph
1214 Commits
Author SHA1 Message Date
x12saandClaude Sonnet 5 c3c1b10d7e feat(flomni): commission heater down/up sequencing and OSA safety checks
CI for csaxs_bec / test (push) Failing after 2m55s
- Add fheater userParameter (in: -11.5, enabled) and drive it to that
  position at the end of ftransfer_flomni_stage_in(), gated on "enabled"
- fosa_in()/fosa_out() now refuse to move the OSA unless fheater is
  verified fully up or fully down, instead of fosa_out() silently
  forcing the heater up
- ensure_fheater_up() reuses the new _fheater_is_up() helper
- Reorder ftransfer_flomni_stage_out() to bring the eye in and optics
  out before disabling feedback
- Tighten fosaz "out" clearance (6 -> 4mm)
- Re-enable omny_panda_continuous device config
- Update PandA position-validation doc with post-fix scan confirmation
  and updated venv path notes

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-22 15:41:08 +02:00
x01dcandClaude Sonnet 5 9cdc7dcc3f docs(flomni): document PandA Mode B recovered-position validation method
CI for csaxs_bec / test (push) Failing after 2m50s
Write-up for continuing this testing in a future session without needing to
re-derive it: the required gate_detector_active/frame_counter grouping
(and why naive per-row comparison can't be fixed by any scale/offset
correction), the exact interferometer + capacitive-sensor conversion
formula, the stale-frame_counter carryover bug and its fix (3eb6e03), and
the validation method (R²/residuals against rt_positions' trusted
average_x_st_fzp/_y). Also records the two agreed next steps: burst
acquisition testing and reduced data mode (the latter still undefined,
to be scoped in that session).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NPZ9gzN2rt3wgiMnTKyrug
2026-09-21 20:27:15 +02:00
x01dcandClaude Sonnet 5 3eb6e0355f fix(panda): drop stale frame_counter carryover in Mode B raw stream
CI for csaxs_bec / test (push) Failing after 2m51s
Diagnosed against a real scan (S06313): grouping raw interf_st_fzp_x/_y
samples by frame_counter + gate_detector_active reproduces rt_positions'
trusted average_x_st_fzp/_y to R² > 0.9999, confirming that method -- but one
point (167) was off by ~116 nm because PandA's COUNTER1.OUT is not cleared by
Arm(). The first raw samples of an acquisition can briefly carry a stale
frame_counter value left over from the previous acquisition's tail (observed:
36 samples reading a stale 167 before dropping to 0), which silently
contaminates whichever real point later in the same scan happens to share
that counter value.

PandaBoxOMNY now drops raw rows captured before it observes frame_counter ==
0 for the first time in each acquisition -- on every arm, including
on_pre_scan retries, since each Arm() reopens the same stale-value window --
and drops leftover buffered rows from an abandoned attempt at the same point.
Verified against S06313: point 167's residual drops from ~116 nm to ~0.1 nm
after the fix, in line with the rest of the scan.

Write-up, including the diagnostic method and a possible PandA-layout-level
alternative fix, in docs/developer/panda_box_free_running_setup.md.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NPZ9gzN2rt3wgiMnTKyrug
2026-09-21 20:21:23 +02:00
x12saandClaude Sonnet 5 7fe20ea3d1 docs: add note-location rule and OMNY tomo_alignment_fit TODO to AGENTS_mirko
CI for csaxs_bec / test (push) Failing after 2m55s
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-21 16:22:54 +02:00
x01dcandClaude Sonnet 5 527113340e docs(flomni): xrayeye skip button tested in the flomni simulator
CI for csaxs_bec / test (push) Failing after 2m53s
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-21 16:20:48 +02:00
x01dcandClaude Sonnet 5 337cdc45e9 fix(xrayeye): hide the Skip button until a client script opts in
CI for csaxs_bec / test (push) Failing after 2m57s
LamNI/omny never call enable_skip_button, so they only had a greyed-out
Skip button. Keep it hidden; the first enable_skip_button() call (flomni
does this at the start of the alignment) shows it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-21 16:10:09 +02:00
x12sa 7695a6293a remove the optics before rotating to 90, in case of close situation with OSA and 2d sample pins
CI for csaxs_bec / test (push) Failing after 13m23s
2026-09-21 15:58:37 +02:00
x01dcandClaude Sonnet 5 0ad6c5014d feat(flomni): Skip button on the xrayeye alignment to leave out one angle
CI for csaxs_bec / test (push) Failing after 2m12s
Flat samples are edge-on at 90 deg and cannot be centered there. The
XRayEye widget gets a Skip button (disabled unless the client enables it,
so LamNI/omny are unaffected) that signals omny_xray_gui.submit = -1.

XrayEyeAlign._align_impl leaves that step out of the fit: one of the five
angles may be skipped, at least 4 are needed. Skips of the FZP center, the
height marking, or a second angle are refused with a message and the run
continues. write_output() builds angles/offsets from the remaining steps
and raises if fewer than 4 are left; the h5 records the skipped angles.

Not yet tried on real hardware.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-21 15:56:10 +02:00
x12saandClaude Sonnet 5 0ebe55f31c docs(flomni): plan for a Skip button on the xrayeye alignment widget
CI for csaxs_bec / test (push) Failing after 2m12s
Idea only, not implemented. Includes the 4-point DAP sine-fit stability
study and the decision to send submit=-1 as the skip signal.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-21 15:43:56 +02:00
x12saandClaude Sonnet 5 e802d55112 docs(omny): TODO to port always-defined tomo_alignment_fit from flomni
CI for csaxs_bec / test (push) Failing after 2m23s
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-21 15:03:44 +02:00
x12saandClaude Sonnet 5 5b688df428 fix(flomni): always define tomo_alignment_fit
The global var was deleted on stage-in / new alignment and never created
at startup, so manual tweaks like fit[0][2] += 5.0 failed with an
undefined variable. reset_tomo_alignment_fit() now writes an all-zero
2x5 fit instead of deleting, and Flomni.__init__ creates it if missing
(an existing fit is kept so it survives client restarts).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-21 14:55:20 +02:00
x12saandClaude Sonnet 5 26df688512 fix(flomni): motion stop button stops all three Galil controllers
CI for csaxs_bec / test (push) Failing after 2m26s
The GUI "Motion Stop" button did not stop the stages when pressed during
a sample transfer:
- stop_all_axes was not in the Galil controllers' USER_ACCESS, so the
  foptx stop over RPC could never work (only logged in the GUI server).
- fsamroy's controller (port 8084) was never stopped.
- an unresolvable device in _stop_device_controller returned silently.

The widget now takes hard_stop_device_names (flomni: ftransy, foptx,
fsamroy; transfer controller first) and sends stop_all_axes() to each
controller from its own thread, so a hung RPC cannot delay the others.
Devices are resolved freshly at click time with retries, every outcome
is logged and shown in the widget's message label, and positioning mode
is restored on the first controller only after all stops were sent. If
stop_all_axes is not yet exposed by the device server, the raw
XQ#STOP,1 is sent via socket_put_and_receive. The legacy
hard_stop_device_name/extra_hard_stop_device_name kwargs still work.

Not yet tested on hardware.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-21 13:44:06 +02:00
x12sa b486e6cb5c config update 2026-09-21 10:45:06 +02:00
x12sa b2bdd3d4de sample mounting 90 deg for flat sample compatibility 2026-09-21 10:44:52 +02:00
x01dcandClaude Sonnet 5 e374dc6ae4 docs(machine): document all 8 injection_status enum values
CI for csaxs_bec / test (push) Failing after 2m16s
List the full set of AGETI-CVME-MASTER-TMA:SR-Inj-Status-I enum
strings in the config comment, not just the top-up-relevant ones, so
the PV's possible states are documented in one place.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0132KBoxsovfcMNRGJhS1Pbw
2026-09-20 20:55:41 +02:00
x01dcandClaude Sonnet 5 02144a23cc feat(machine): add SLS injection/top-up status PV
Registers AGETI-CVME-MASTER-TMA:SR-Inj-Status-I (the injection-system
enum PV) as injection_status, alongside the other machine-status PVs
(curr, ofb, shutter). readoutPriority is 'monitored', matching curr,
so the value is captured continuously throughout each scan rather
than only once at scan start -- a top-up can start or stop mid-scan.

'0' / 'Filling Storage Ring' means the ring is being refilled.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0132KBoxsovfcMNRGJhS1Pbw
2026-09-20 20:55:41 +02:00
x12saandClaude Sonnet 5 19cfee3e79 feat(flomni): add randomize_offset scan argument to flomni_fermat_scan
CI for csaxs_bec / test (push) Failing after 2m12s
The per-call random sub-step offset of the Fermat lattice could not be
switched off from the scan (seed is only an argument of the static position
function, and a seed only makes the offset reproducible). Add an optional
randomize_offset: bool = True scan argument, passed through prepare_scan()
to get_flomni_fermat_spiral_pos(); False gives offset 0 (unshifted lattice).
Default keeps today's behaviour; tomo scans do not pass it.

Document it in the flomni user doc and add an omny AI_docs TODO describing
the port.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017szgTwuHG65YhjoBGiK2Gj
2026-09-20 13:49:20 +02:00
x12saandClaude Sonnet 5 c66253709a perf(csaxs): read filter positions from cache in the fil_trans report
CI for csaxs_bec / test (push) Failing after 2m13s
_fil_trans_report is a status report, so use readback.get(cached=True) (last
published readback from redis) instead of one RPC round trip per filter axis.
A missing value still ends in the existing "readback unavailable" error. The
post-umv position check in fil_trans stays live on purpose.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017szgTwuHG65YhjoBGiK2Gj
2026-09-20 12:01:17 +02:00
x12saandClaude Sonnet 5 028e31be41 perf(csaxs): read slit positions from cache in slits_show_all()
CI for csaxs_bec / test (push) Failing after 2m10s
device.read() defaults to cached=False, i.e. one RPC round trip to the device
server per device (24 for the six slits). Use cached=True, which reads the last
published readback from redis; a missing value still shows as '---'.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017szgTwuHG65YhjoBGiK2Gj
2026-09-20 11:55:26 +02:00
x12saandClaude Sonnet 5 15cde5a0e7 docs(omny): note X-ray-eye DAP fit fix and what omny inherits from it
CI for csaxs_bec / test (push) Failing after 2m10s
The DAP start-value fix in the shared OMNY_XRayEye widget already applies to
LamNI/omny; 8-point full-period data was never affected. Records that
omny/x_ray_eye_align.py is still a LamNI copy that doesn't consume the GUI fit.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017szgTwuHG65YhjoBGiK2Gj
2026-09-20 11:53:07 +02:00
x12saandClaude Sonnet 5 bbede883b0 fix(panda): retry arming once after a forced reset instead of hanging in pre_scan
CI for csaxs_bec / test (push) Failing after 2m11s
PandaBoxOMNY inherited on_pre_scan, which waits forever for the PandA READY
event before sending Arm(). After rapid abort/retry cycles the readout thread
can be left parked, so READY never arrives and pre_scan_all_devices() hangs
with no error (flomni_fermat_scan 11998/12000).

on_pre_scan now runs a bounded arm task: wait pre_scan_timeout (default 5 s) for
READY; on failure force-reset the box, restart the readout thread (after the old
loop finished its cleanup) and try once more, printing and logging a warning with
diagnostics. If the second attempt fails too, the status fails with a
RuntimeError so the scan aborts. Arm() is sent from the task, not a status
callback, so the scan is only released after it went out. A stop is not retried.

Also records the outcome and the still-open ophyd_devices race in
AGENTS_mirko.md.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017szgTwuHG65YhjoBGiK2Gj
2026-09-20 11:47:04 +02:00
x12saandClaude Sonnet 5 bd85d5e673 fix(xrayeye): make DAP sine fit converge by fixing start values and signed amplitude
CI for csaxs_bec / test (push) Failing after 2m13s
The xray eye alignment fit (A*sin(f*x+shift)+intercept, 5 points) relied on
lmfit's SineModel.guess() for the start values. Its FFT-based shift guess is
arbitrary for 5 points and often left the fit stuck at the shift bound (2*pi)
far from the data, so the plotted fit missed the submitted points and
wrong parameters were loaded into flomni.

Override all five parameters so the DAP server skips guess(): signed
amplitude (start 30), shift start 0 within +-pi, intercept start 0,
frequency and slope still fixed. Shared by the x and y waveforms.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017szgTwuHG65YhjoBGiK2Gj
2026-09-20 11:03:06 +02:00
x01dcandClaude Sonnet 5 d01af690a9 fix(flomni,lamni): fovy/piezo-range bounds didn't match scan's strict "<"
CI for csaxs_bec / test (push) Failing after 2m12s
Real hardware failure: flomni.fovy=100.0 was accepted by the property, GUI,
and CLI (all capped at an inclusive 100.0), but FlomniFermatScan's own
ScanArgument requires fovy strictly less than 100 -- so the scan rejected it
at runtime with ScanInputValidationError, only surfacing once actually run.

- flomni.fovy property setter: now raises at >=100 (was >100), matching
  FlomniFermatScan's gt=0/lt=100. GUI/CLI max tightened 100.0 -> 99.9.
- lamni_piezo_range_x/y (become LamniFermatScan's fovx/fovy, gt=0/lt=80):
  found the same bug class at BOTH ends while writing the regression test --
  GUI/CLI min was an inclusive 0.0 (scan requires strictly >0) and max was
  an inclusive 80.0 (scan requires strictly <80). Tightened to 0.1-79.9 in
  both GUI and CLI. Property setter's large_range_scan bypass left
  untouched per earlier explicit instruction -- this fixes the GUI/CLI
  entry points, which is where the bound is actually enforced in practice.
- Added test_fov_bounds_match_scan_args.py: introspects the real
  ScanArgument gt/ge/lt/le from FlomniFermatScan/LamniFermatScan and asserts
  our configured GUI/CLI ranges are strictly inside them, so this class of
  bug (passes every check except the one that actually runs the scan)
  can't silently come back for these or future fields.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0132KBoxsovfcMNRGJhS1Pbw
2026-09-19 21:30:22 +02:00
x01dcandClaude Sonnet 5 1b802aaad6 docs(flomni,lamni): clarify tomo_countingtime is per-frame, not per-point
CI for csaxs_bec / test (push) Successful in 2m12s
tomo_countingtime is the exposure time of each individual frame within a
frames_per_trigger burst -- total dwell time at a position scales with
frames_per_trigger (see the scan's own timing model, flomni.py:2553:
normal_cadence = ... tomo_countingtime * frames_per_trigger). The GUI label
and both setups' tomo_parameters() CLI prompt/print text previously just
said "Counting time" with no qualifier, which reads as a per-point total.
Relabeled to "Counting time per frame" everywhere it appears.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0132KBoxsovfcMNRGJhS1Pbw
2026-09-19 21:24:14 +02:00
x01dcandClaude Sonnet 5 f0c5a251d9 docs(omny): note follow-up to tighten tomo-parameter ranges + CLI validation
CI for csaxs_bec / test (push) Successful in 2m13s
Not implemented for omny yet -- records the range tightening and _get_val()
min_/max_ enforcement just done for flomni/lamni (2026-09-19), and confirms
omny's parameter names mirror flomni's exactly. Also confirms tomo_params.py
has no "omny" SETUP_PROFILES entry -- omny doesn't use that shared GUI
widget at all today, so there's nothing to tighten there until its actual
parameter-entry UI (if any) is located.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0132KBoxsovfcMNRGJhS1Pbw
2026-09-19 21:17:18 +02:00
x01dcandClaude Sonnet 5 d77b5cede9 fix(lamni): tighten circfov/piezo-range GUI limits, enforce ranges in CLI
CI for csaxs_bec / test (push) Successful in 2m18s
- tomo_circfov: GUI upper bound 200.0 -> 500.0 um (floor kept at 0.0 so
  "0 = disabled" -- checked explicitly in lamni_fermat_scan.py:484 -- still
  works)
- lamni_piezo_range_x/y: GUI upper bound 200.0 -> 80.0 um, matching the
  "(max 80)" already printed in the CLI prompt. The property setter's
  large_range_scan bypass is left untouched (uncertain hardware rationale) --
  this only tightens the GUI/CLI entry points, which is where "<80" actually
  becomes enforced in practice, since both now validate before ever calling
  the (still-conditionally-permissive) property setter.
- LamNI._get_val() now supports min_/max_ (mirrors Flomni._get_val()
  exactly, added previously) -- LamNI's tomo_parameters() CLI wizard
  previously had zero range validation at all. Wired up for
  tomo_countingtime (0.001-100.0), tomo_shellstep (0.025-20.0),
  lamni_piezo_range_x/y (0.0-80.0), and tomo_circfov (0.0-500.0).
- tomo_stitch_overlap gets a brand new CLI prompt (0.0-10.0 um) -- it had no
  prompt at all before (property-only, same gap Flomni still has).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0132KBoxsovfcMNRGJhS1Pbw
2026-09-19 21:16:28 +02:00
x01dcandClaude Sonnet 5 a7e1b5ecf0 docs(flomni): fix stale comment above _TOMO_SCAN_PARAM_NAMES
CI for csaxs_bec / test (push) Successful in 2m31s
manual_shift_y is prompted by tomo_parameters() (has been all along) -- the
comment wrongly grouped it with tomo_stitch_overlap/corridor_size/
at_each_angle_hook as "only set directly as properties". Only those three
are actually property-only.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0132KBoxsovfcMNRGJhS1Pbw
2026-09-19 21:05:53 +02:00
x01dcandClaude Sonnet 5 1dd03d16d8 fix(flomni): tighten tomo_shellstep/stitch/golden_ratio_bunch_size ranges
CI for csaxs_bec / test (push) Successful in 2m17s
tomo_shellstep: 0.001-1000.0 -> 0.025-20.0 um
stitch_x/stitch_y (flomni only): 0-50 -> 0-10
golden_ratio_bunch_size: 1-10000 -> 1-100
tomo_stitch_overlap: 0.0-50.0 -> 0.0-10.0 um

Applied in both the GUI (tomo_params.py) and the tomo_parameters() CLI
wizard (flomni.py), matching the ±50 um manual_shift_y precedent. Note:
tomo_shellstep, tomo_stitch_overlap, and golden_ratio_bunch_size are built
by shared (not per-profile) GUI code, so these ranges also apply to LamNI's
Tomo Parameters panel, not just flomni's -- stitch_x/stitch_y are the only
one of the four that's flomni-specific (lamni_stitch_x/y are a separate,
untouched profile entry). tomo_stitch_overlap has no CLI prompt to update
(property-only, not part of the tomo_parameters() wizard). All existing
defaults (tomo_shellstep=1, stitch_x/y=0, tomo_stitch_overlap=0.2,
golden_ratio_bunch_size=20) remain within the new ranges.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0132KBoxsovfcMNRGJhS1Pbw
2026-09-19 21:05:16 +02:00
x01dcandClaude Sonnet 5 158dc800f0 fix(flomni): enforce GUI parameter ranges in tomo_parameters() CLI too
CI for csaxs_bec / test (push) Successful in 2m15s
_get_val() (the wizard's input prompt) previously did no range validation
at all -- only the Tomo Parameters GUI's spinboxes enforced limits, so the
CLI silently accepted any value of the right type (e.g. manual_shift_y=500
despite the GUI's ±50 µm range). _get_val() now takes optional min_/max_
and re-prompts until the value is in range; wired up for every
tomo_parameters() field that already has a GUI-defined range (tomo_countingtime,
tomo_shellstep, fermat_asymmetry, fovx, fovy, stitch_x/y, manual_shift_y,
frames_per_trigger, single_point_random_shift_max, total projections,
golden_ratio_bunch_size, golden_max_number_of_projections, projections/sub-tomo).
fermat_asymmetry reuses FlomniFermatScan's own MIN/MAX constants rather than
duplicating them.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0132KBoxsovfcMNRGJhS1Pbw
2026-09-19 20:21:20 +02:00
x01dcandClaude Sonnet 5 583435ddd6 fix(flomni): tighten manual_shift_y GUI range to ±50 µm
CI for csaxs_bec / test (push) Successful in 2m21s
manual_shift_y (the "additional offset y" that ultimately feeds
tomo_additional_offsety at the scan/RT-controller layer, where it's bounded
by rty's own ±100 hardware travel limit) had no meaningful upper bound of
its own in the Tomo Parameters GUI (-1000 to 1000 µm spinbox range) --
tighten it to ±50 µm, a sane bound at the parameter-entry level, well
inside rty's hardware limit which is left unchanged. GUI-only change
(manual_shift_y itself has no property-level range validation, matching
the existing convention for fovx/fovy/stitch_x/stitch_y). LamNI's own
manual_shift_x/y range is untouched.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0132KBoxsovfcMNRGJhS1Pbw
2026-09-19 19:34:49 +02:00
x01dcandClaude Sonnet 5 1e553b0004 docs(lamni): document lamni_stitch_x/lamni_stitch_y; note omny follow-up
CI for csaxs_bec / test (push) Successful in 2m25s
Same gap as flomni.md (fixed previous commit): lamni.md had no mention of
stitching. Add the equivalent paragraph using lamni's own parameter names
(lamni_stitch_x/y, lamni_piezo_range_x/y) and cite tomo_scan_projection(),
which passes them straight through to scans.lamni_fermat_scan().

Also add an omny/AI_docs TODO note -- omny.md has the same gap and omny's
mechanism turns out to use identical parameter names to flomni's
(stitch_x/stitch_y/tomo_stitch_overlap), so the flomni.md paragraph should
carry over directly once written.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0132KBoxsovfcMNRGJhS1Pbw
2026-09-19 18:14:31 +02:00
x01dcandClaude Sonnet 5 5096008286 docs(flomni): document stitch_x/stitch_y tomo parameters
CI for csaxs_bec / test (push) Successful in 2m25s
flomni.md had no mention of stitching at all. Add a paragraph explaining
the tiled-Fermat-scan mechanism (flomni.py:3521-3527) and tomo_stitch_overlap,
matching the existing zero_deg_reference_at_each_subtomo callout's style.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0132KBoxsovfcMNRGJhS1Pbw
2026-09-19 17:05:51 +02:00
x01dcandClaude Sonnet 5 306b93cc07 docs(omny): note unconditional 0-deg reference projection follow-up
CI for csaxs_bec / test (push) Successful in 2m19s
Not implemented for omny yet -- captures the same feature just added to
Flomni/LamNI so the intent isn't lost. Omny still needs its own retraction-
capability check and tomo_scan() entry point located before this can land.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0132KBoxsovfcMNRGJhS1Pbw
2026-09-19 10:07:06 +02:00
x01dcandClaude Sonnet 5 0a12d4892f feat(flomni,lamni): unconditional 0-deg reference projection at scan start
CI for csaxs_bec / test (push) Successful in 2m15s
Take one real 0-degree projection at the very start of every new tomogram
(subtomo_number=1, included in reconstruction like any grid projection),
independent of zero_deg_reference_at_each_subtomo /
golden_projections_at_0_deg_for_damage_estimation -- gives an immediate
radiation-damage baseline even when those flags are off. Placed right after
Flomni's existing collect_empty_frames() step; LamNI gets the same 0-deg
shot but no flat-field step, since it has no way to retract the sample out
of the beam. Omny intentionally left as a follow-up (not implemented here).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0132KBoxsovfcMNRGJhS1Pbw
2026-09-19 10:06:49 +02:00
x01dcandClaude Sonnet 5 22a882fafa docs: note proposed interferometer signal-strength trend on webpage
CI for csaxs_bec / test (push) Successful in 2m14s
Design note only -- not implemented. Captures the idea (low-rate/~hourly
trend, not per-projection), plus a 2026-09-19 survey finding that flomni/
lamni/omny each have incompatible interferometer-read primitives (different
axis counts/semantics, no shared RT-controller base), and that omny has no
working webpage generator to hook into yet (its existing file is dead code,
never imported by the real factory).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0132KBoxsovfcMNRGJhS1Pbw
2026-09-19 09:56:01 +02:00
x01dcandClaude Sonnet 5 7d21c0e43e docs(panda): note proposed gated-continuous PCAP capture variant
CI for csaxs_bec / test (push) Successful in 2m22s
Record the exposure-active-gated PCAP.gate variant discussed for reducing
idle-time data volume in raw_stream_mode (currently PCAP free-runs via
CLOCK1 regardless of detector state). Documentation only -- not implemented
or tested against hardware.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0132KBoxsovfcMNRGJhS1Pbw
2026-09-19 09:11:31 +02:00
x01dcandClaude Sonnet 5 cd838e4f73 fix(eps): enforce hard byte budget on eps_alarm_history.json uploads
CI for csaxs_bec / test (push) Successful in 2m22s
The 2026-09-11 fix capped alarm-text *count* per event (_ALARM_TEXTS_MAX),
but not text length, and _load() never re-caps an already-oversized event's
texts list -- only new appends are capped. Confirmed on x12sa: the file had
grown to 1,209,271 bytes, still tripping HTTP 413 on every upload cycle
(upload.php itself has no size check -- almost certainly nginx's default
client_max_body_size=1m). HistoryTracker.save() now shrinks a copy of the
payload to a ~250 KB budget (alarm texts, then ring trace, then oldest
events, then field length as a last resort) before writing/uploading, so
the file can no longer exceed the server's limit regardless of how the
underlying data grows. In-memory history is untouched.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0132KBoxsovfcMNRGJhS1Pbw
2026-09-18 13:46:12 +02:00
x01dcandClaude Sonnet 5 bf6f89636a feat(flomni,lamni): clear tomo queue and reset progress on account change
CI for csaxs_bec / test (push) Successful in 2m19s
The account-change check already offered to reset scan parameters to
defaults for a new experiment; extend it to also clear the tomo queue and
reset acquisition progress, so a new account doesn't inherit leftover
queued jobs or in-progress state from the previous account.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0132KBoxsovfcMNRGJhS1Pbw
2026-09-18 09:19:41 +02:00
x01dcandClaude Sonnet 5 74996f78e1 feat(flomni,lamni): add on-demand tomo timing report commands
CI for csaxs_bec / test (push) Successful in 2m24s
tomo_scan()'s elapsed/idle timing breakdown only printed on normal
completion, so it was unreachable after a KeyboardInterrupt even though
the underlying data (self.progress, a BEC global var) survives the
interrupt. Factor the report construction into _build_timing_lines() and
expose it via tomo_print_timing_report() (console only) and
tomo_print_timing_report_and_scilog() on both Flomni and LamNI. Also
flags the same pre-existing gap on OMNY in a TODO note.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-18 08:41:07 +02:00
x01dcandClaude Sonnet 5 fd01806b2f fix(xrayeye): remove self.resize(800, 600) from __init__ -- fights dock manager
CI for csaxs_bec / test (push) Successful in 2m14s
Root cause isolated via a live A/B test (Mirko): the "camera image cut/
collapsed until the window is manually moved" symptom is specific to
OMNY_XRayEye -- flomnigui_show_cameras()'s Image/z_ConsoleButtonsWidget docks
never show it, even swapped in and out of the *same* persistent window
repeatedly (ruling out window-freshness/QtAds-first-dock theories tried and
reverted earlier this session). Further isolated to screen size: reproduces
reliably on a screen too small for the assumed geometry, not on a larger one.

OMNY_XRayEye.__init__() was the only widget in this GUI calling
self.resize(800, 600) on itself. This widget is normally embedded as a dock
(gui_tools.py's flomnigui_show_xeyealign()), where the dock manager (Qt
Advanced Docking System) owns its geometry -- an explicit self-resize call
fights that, and on an undersized screen corrupts the dock's layout until a
manual move/resize forces Qt to reflow within actual available space. The
standalone `python x_ray_eye.py` test harness at the bottom of this file
already does its own win.resize(1000, 800) after construction regardless, so
this call was never actually needed even there -- pure dead weight that only
caused harm once embedded.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lx3KffiFyyDMKT8vvPENUW
2026-09-17 17:03:37 +02:00
x01dc 903e465701 Revert "fix(flomni): increase flomni GUI window settle delay after creation (experiment)"
CI for csaxs_bec / test (push) Successful in 2m15s
This reverts commit 631bdedb6c.
2026-09-17 16:02:38 +02:00
x01dcandClaude Sonnet 5 631bdedb6c fix(flomni): increase flomni GUI window settle delay after creation (experiment)
CI for csaxs_bec / test (push) Successful in 2m21s
Root cause finally isolated via a live A/B test: closing the whole "flomni"
window and reopening it (flomnigui_show_gui() takes the gui.new() branch,
creating a fresh top-level window) reproduces the "camera image squeezed/
missing until the window is moved" symptom; closing just the xeyegui dock
and reopening it (window already exists in self.gui.windows, reused as-is)
does not. Same OMNY_XRayEye construction either way -- the only variable is
whether the window itself is freshly created, which rules out the widget's
own layout code (already tried and reverted two fixes there this session).

The existing time.sleep(1) after gui.new() is itself evidence someone
already found the RPC response alone doesn't mean the window has actually
settled on screen. Bumping to 2s is a pragmatic, easily-reversible
experiment, not a confirmed fix -- flagging in case it needs to become a
poll-for-actual-geometry wait instead. LamNI's gui_tools.py has the
identical gui.new() + time.sleep(1) pattern (line 46-47) and is presumably
equally exposed, but untouched here -- not reported/tested there.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lx3KffiFyyDMKT8vvPENUW
2026-09-17 15:59:40 +02:00
x01dcandClaude Sonnet 5 3728a24c70 docs: add personal Claude Code notes for mirko
CI for csaxs_bec / test (push) Successful in 2m17s
Personal, machine-syncable notes file (not referenced by any shared
AGENTS.md/CLAUDE.md, so it has no effect on other contributors).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GCaaQQSYGCbkAsRnALWC3h
2026-09-17 15:48:39 +02:00
x01dc b43240fbdd Revert "fix(xrayeye): defer control-panel width-fixing until after first show"
This reverts commit 10b02ca2f1.
2026-09-17 15:48:07 +02:00
x01dc 99243931ac Revert "fix(xrayeye): use showEvent() instead of a one-shot timer for control-panel width"
This reverts commit a6dadafe46.
2026-09-17 15:48:07 +02:00
x01dcandClaude Sonnet 5 a6dadafe46 fix(xrayeye): use showEvent() instead of a one-shot timer for control-panel width
CI for csaxs_bec / test (push) Successful in 2m20s
The previous fix (QTimer.singleShot(0, ...) from _init_ui()) was not
reliably late enough in practice -- still reproduced live over a remote
desktop session: window opens, image briefly visible, then the control
panel's wrong fixed width squeezes it down, recoverable only by moving
or resizing the window (which doesn't fix the wrong width itself, just
gives the image enough leftover space to look normal despite it).

showEvent() is the correct Qt idiom for "run once real geometry is
available" -- it fires every time the widget is actually made visible,
not just once at construction. Also more robust than a single deferred
call: it self-corrects on any later re-show too (e.g. a saved-workspace
restore re-applying stale geometry after the fix already ran once).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lx3KffiFyyDMKT8vvPENUW
2026-09-17 15:44:23 +02:00
x01dcandClaude Sonnet 5 10b02ca2f1 fix(xrayeye): defer control-panel width-fixing until after first show
CI for csaxs_bec / test (push) Successful in 2m17s
_init_ui() locked the control panel to a fixed width computed from
sizeHint() called synchronously during construction -- before the
widget had ever been shown/laid out, with no real screen geometry and
fonts not fully resolved yet (worse over a remote desktop session).
Reported live: the widget opens correctly sized for a moment, then the
image area visibly collapses down to a sliver as the (wrong) fixed
width gets applied, recoverable only by manually resizing the window
(which doesn't fix the wrong width itself, just gives the image enough
leftover space to look normal again despite it).

Defer the actual sizeHint()/setFixedWidth() call via
QTimer.singleShot(0, ...) so it runs on the next event-loop iteration,
after the widget has actually been shown/laid out at least once --
same effect a manual resize was achieving, but automatic and correct
the first time.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lx3KffiFyyDMKT8vvPENUW
2026-09-17 15:37:25 +02:00
x01dcandClaude Sonnet 5 3d0686329a fix(sim-cameras): correct exposure_time units from ~10s default to 10ms
CI for csaxs_bec / test (push) Successful in 2m18s
_SimIDSBackend's default exposure_time (10000.0, commented "ms") and its
get_exposure_range() ceiling formula (1_000_000.0 / pixel_clock_MHz) were
both scaled as if the unit were microseconds, inconsistent with the real
IDSCamera's documented exposure_time unit (ms; see its Cpt docstring and
exposure_time_max's own 1000.0 ms placeholder default). Net effect: every
fresh sim connect seeded exposure_time.put(10000), read by the real device
layer as a literal 10 second exposure -- ~50x a 5 Hz live-mode frame period
(200 ms), and get_exposure_range() reported a ~50 s ceiling at the default
20 MHz pixel clock.

New default (10 ms) and range formula (20_000.0 / pixel_clock_MHz, giving
~1000 ms at 20 MHz) keep the same pixel-clock-dependent shape but land in a
believable ms-scale range comfortably under a 5 Hz target.

Noticed live: simulated camera's exposure/gain readout looked nonsensical
after the manual-exposure work made this value load-bearing (previously
just an unused placeholder). Sim frame *content* is independent of
exposure/gain (no brightness modeling), so this alone doesn't explain a
reported "cut" first image, but the seeded value being wildly unrealistic
was worth fixing regardless.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lx3KffiFyyDMKT8vvPENUW
2026-09-17 15:29:33 +02:00
x01dcandClaude Sonnet 5 80ccde83b2 chore(bec_widgets): regenerate client.py RPC stub for lock/unlock_vertical_center
CI for csaxs_bec / test (push) Successful in 2m12s
csaxs_bec/bec_widgets/widgets/client.py is a generated file (bw-generate-cli
--target csaxs_bec) that the BEC client uses to build its dynamic RPC proxy
classes -- it is the actual source of truth for what methods a client-side
widget reference exposes, NOT the live widget class itself. Adding
lock_vertical_center()/unlock_vertical_center() to OMNY_XRayEye without
regenerating this file meant every BEC client session (even a freshly
restarted one) built its xeyegui proxy without those two methods, causing
"AttributeError: 'OMNY_XRayEye' object has no attribute
'unlock_vertical_center'" live on a real session -- traced via
flomni.xeyegui._registry[...].__class__.__module__ == 'client', confirming
the proxy class comes from this file, not csaxs_bec.bec_widgets.widgets.xray_eye.x_ray_eye
directly.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lx3KffiFyyDMKT8vvPENUW
2026-09-17 15:20:36 +02:00
x01dcandClaude Sonnet 5 5f6520214d fix(flomni): use cached read for sample-name poll in tomo params widget
CI for csaxs_bec / test (push) Successful in 2m19s
The OMNY_TomoParams widget polled flomni_samples.sample_names.sample0
uncached every 2s to refresh a display label. Over a long interlock
lock this produced thousands of RPC calls, overflowing the client's
shared 100-entry request buffer (RequestStorage) and evicting a
pending scan request, which stalled the queue with no error. The
signal is auto-monitored and already live in Redis, so read it from
there instead of round-tripping to the device server.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GCaaQQSYGCbkAsRnALWC3h
2026-09-17 15:18:47 +02:00