XrayEyeAlign.gui is a property delegating to lamni.xeyegui and has no
setter. Mock lamni.xeyegui in the update_frame tests; drop the redundant
alignment_images reset, which __init__ already handles.
Drop test_save_frame (method no longer exists). Rewrite test_update_frame
against dev.fsh/dev.cam_xeye instead of the removed LamNI.alignment module.
Patch the module-level umv in test_tomo_rotate rather than builtins.
LamNI.__init__ calls set_client(), which unconditionally accessed
client.gui. This broke test_x_ray_eye_align.py under ClientMock, which
has no gui attribute. Use getattr with a None default; behaviour on a
real BEC client is unchanged.
- Enable DAP fit parameter forwarding (self.gui.set_dap_params_forwarding),
never called before -- without it the dap_params_update signal was never
connected, so no fit data could ever reach fit_params_x/y regardless of
how long anything waited. Disabled again once the fit is read (or on
abort, via the existing KeyboardInterrupt cleanup in lamni.py).
- Replace the fixed 5s sleep before reading the DAP fit with
_wait_for_dap_fit(), which polls fit_params_x/y for the real converged
shape (up to 30s) instead of guessing a duration.
- Fix write_output()'s offset reference: was using one of the 8 angle
points as its own zero-reference (first via an off-by-one at k=1, then
at k=2), which forces that point's offset to exactly 0 by construction
and biases the fit. Now references alignment_values[0] (the FZP centre,
the only angle-independent point in the procedure), matching both
FlOMNI's own reference point and the original SPEC macro
(l_xrayeyealign.mac) exactly, including the asymmetric x/y sign
convention.
- pixel_calibration is now a property reading the cam_xeye device's
pixel_calibration user parameter, matching FlOMNI's camera-sourced
calibration, with the old hardcoded constant kept only as a fallback
(PIXEL_CALIBRATION_DEFAULT) -- by design, to match FlOMNI's own pattern.
- lamni_optics_mixin.py: lfzp_in() and loptics_out() now print before/after
re-establishing interferometer feedback, previously silent.
- device_configs: add the missing userParameter.pixel_calibration to
cam_xeye in ptycho_lamni.yaml and simulated_omny/simulated_lamni.yaml
(present on the FlOMNI side already; this is what the pixel_calibration
property above actually reads at runtime).
- Add lamnigui_stop_gui(), matching flomnigui_stop_gui()
- lamnigui_show_xeyealign(): check/enable cam_xeye live mode on every
call, not just when the xeyegui widget is first created -- matches
flomnigui_show_xeyealign()
- lamnigui_idle(): refresh the splash text on every call rather than
only at first creation -- matches flomnigui_idle()
Replace the plain self.progress dict with a global-var-backed
_ProgressProxy (same shape and key as FlOMNI's), so progress survives
a client restart. Adds heartbeat + idle-time-gap detection in
_tomo_scan_at_angle, ETA computation in _print_progress, and
tomo_start_time/reset handling in tomo_scan(). Adds
tomo_progress_reset() and _format_duration() for parity.
gui_tools.py's progress display already read these fields; no GUI
change needed.
feat(lamni): persist alignment lookup-table corrections
corr_pos_x/corr_pos_y/corr_angle (+ _2 iteration) become
global-var-backed properties (lamni_corr_pos_x, lamni_corr_pos_y,
lamni_corr_angle, ..._2) instead of plain instance lists that reset
on every client restart. No default correction file exists for
LamNI, so reset_correction()/reset_correction_2() just clear to
empty.
feat(lamni): add frames_per_trigger (burst mode) support
LamNIFermatScan already inherits from AsyncFlyScanBase and already
accepts/passes through frames_per_trigger -- only the client-side
plumbing was missing. Adds a validated, global-var-backed
frames_per_trigger property, threads it into
tomo_scan_projection()'s lamni_fermat_scan() call, and exposes it in
tomo_parameters(). Also folds it into the idle-time cadence estimate
alongside stitch tile count.
feat(lamni): add crosshair and structured HDF5 output to X-ray eye alignment
Set the alignment crosshair at the FZP centre (step k=0, raw pixel
coords), hidden on normal completion and on Ctrl-C abort.
update_frame() now actually captures and stores each frame
(previously not stored at all); roi_pixel_data is now collected at
every submit. write_output() additionally writes a timestamped HDF5
file (alignment_values, alignment_images, roi_pixel_data,
alignment_fit) alongside the existing plain-text archival file.
fix(lamni): stop resetting correction state on every XrayEyeAlign instantiation
A fresh XrayEyeAlign is constructed on every call to both
xrayeye_alignment_start() and xrayeye_update_frame(); resetting
corr_pos_x/y/angle and tomo_fit_xray_eye in __init__ meant the
latter -- meant as a lightweight frame check -- silently wiped valid
persisted correction data every time. Reset moved to the start of
align() itself.
fix(lamni): use dev.fsh instead of dev.omnyfsh for the alignment shutter
The shared XRayEye widget monitors and controls dev.fsh; the
alignment script was opening/closing a different device, which
would desync the GUI's shutter toggle from the actual hardware
state.
fix(lamni): correct stale self.align reference in MagLamNI.rotate_slowly
self.align no longer exists as an attribute now that
LamNIAlignmentMixin is mixed directly into LamNI. Use
self.tomo_fovx_offset/self.tomo_fovy_offset directly.