diff --git a/csaxs_bec/bec_ipython_client/plugins/LamNI/AI_docs/FLOMNI_LAMNI_FEATURE_GAPS_2026-07.md b/csaxs_bec/bec_ipython_client/plugins/LamNI/AI_docs/FLOMNI_LAMNI_FEATURE_GAPS_2026-07.md new file mode 100644 index 0000000..17c9112 --- /dev/null +++ b/csaxs_bec/bec_ipython_client/plugins/LamNI/AI_docs/FLOMNI_LAMNI_FEATURE_GAPS_2026-07.md @@ -0,0 +1,167 @@ +# flomni → lamni feature gaps still open (2026-07 sweep) + +Follow-up to `FLOMNI_TO_LAMNI_COMPARISON.md` (flomni's `AI_docs/`) and this +folder's `TOMO_QUEUE_PORT.md`/`TOMO_PARAMS_GUI_PORT.md` — those covered the +tomo-queue backend, the GUI, the webpage generator, and the angle-distribution +mapping, all since ported. This sweep looked for *further* flomni features +lamni still lacks, after the same session also ported: the end-of-scan timing +overview + `scan_repeat`/`scan_interlock` interruption handling, tomo-queue +tooltip filtering, the constant-shift print, `at_each_angle_hook` in +`tomo_parameters()`, and `zero_deg_reference_at_each_subtomo` for tomo_type 1. + +Every item below was independently confirmed by direct grep/read against +both files, not just taken from the sweep — file:line citations are given so +you can jump straight to the code. Ordered roughly by how promising each is +to port, most-actionable first. This is a findings list for triage, not an +implementation plan — nothing here has been started. + +## 1. Per-projection/tomogram timing log + `scilog_last_ptycho_scans()` — missing entirely + +- flomni: `flomni.py:2945` (`_TIMING_LOG_DIR`), `_log_projection_timing()` + (`2971`), `_log_tomogram_timing()` (`3019`), `_read_last_timing_records()` + (`3056`), `scilog_last_ptycho_scans()` (`3082`). +- lamni: none of these exist anywhere in `lamni.py`. +- flomni appends a JSON-lines record per completed projection and per + completed tomogram (FOV, exposure, stitch, corridor, duration, scan-number + range) to `~/data/raw/logs/timing_statistics/*.jsonl`, feeding a future + scan-time-prediction model, and exposes `scilog_last_ptycho_scans(n)` — a + user command that writes a scilog entry summarizing the last *n* + projections (scan numbers/FOV/exposure/duration) with a free-text comment + prompt. +- **Portable**: the mechanism only needs `_TOMO_SCAN_PARAM_NAMES` (lamni + already has via `TomoQueueMixin`) and generic file I/O — nothing + flomni-hardware-specific. +- Size: medium — new logging infra, but the shape can be lifted close to + verbatim. + +## 2. Tomo-parameter reset offer on experiment-account change — missing entirely + +- flomni: `Flomni.__init__` calls `_maybe_reset_params_on_account_change()` + (`flomni.py:1656`, defined `1662`) — compares the live BEC account against + a persisted `defaults_applied_for_account` global var and, on a genuine + account change, offers to reset tomo params via `_set_default_tomo_params()` + (`1694`). +- lamni: `LamNI.__init__` has no such call, no `defaults_applied_for_account` + anywhere in `lamni.py`. +- Prevents a new user silently inheriting the previous experiment's tuned + FOV/stitch/etc. +- **Portable**: pure session-lifecycle/UX logic, no hardware dependency. +- Size: small. + +## 3. `collect_empty_frames()` — flat-field acquisition at the start of a new tomo scan — missing entirely + +- flomni: `collect_empty_frames()` (`flomni.py:2419`), called unconditionally + from the "new scan" branch of `tomo_scan()` (`2533`, right after + `write_pdf_report()`/progress reset — only on a genuinely new scan, not a + resume). +- lamni: zero occurrences of `collect_empty_frames`/"empty frame"/"flat + field" anywhere in `LamNI/*.py`. +- Acquires 10 flat-field images at angle 0 with the sample shifted out of the + beam by half the FOV, logged with `subtomo_number=0` but deliberately kept + out of `tomo_reconstruct()`'s queue. +- **Judgment call, not purely a software gap**: whether this is worth porting + depends on whether lamni's ptycho reconstruction pipeline actually + uses/needs flat fields the way flomni's does — worth confirming with Mirko + before implementing, not just a code-porting decision. +- Size: small-medium (geometry needs adapting to `tomo_circfov`/lamni's + offset properties, but the shape is a direct port). + +## 4. `lfzp_in()` has no "skip the reset cycle if already in position" optimization + +- flomni: `ffzp_in(force_feedback_reset=False)` (`flomni_optics_mixin.py:98`) + + `_ffzp_is_in()` (`132`) — skips the expensive feedback-disable + + `feedback_enable_with_reset()` cycle when the FZP doesn't actually need to + move, avoiding an unnecessary interferometer re-zero/position shift during + repeated alignment scans. +- lamni: `lfzp_in()` (`lamni_optics_mixin.py:237`) always runs the full + cycle unconditionally — no `_lfzp_is_in()`-equivalent guard. +- **Portable**: identical underlying `dev.rtx.controller.feedback_disable()`/ + `feedback_enable_with_reset()` API, used the same way by both setups. +- Size: trivial-to-small — add an `_lfzp_is_in()` check + a + `force_feedback_reset` kwarg, direct port of the pattern. + +## 5. No hard-stop button wired into lamni's GUI + +- flomni: `flomnigui_show_cameras()` (`flomni/gui_tools.py:143-150`) wires up + a `ConsoleButtonsWidget` (`hard_stop_device_name="ftransy"`, + `extra_hard_stop_device_name="foptx"`) calling the shared, generic + `GalilController.hard_abort_and_restore_positioning_mode()` — added + specifically to replace an older blind stop-all-devices broadcast that + could crash the scan worker thread. +- lamni: `LamNI/gui_tools.py` has no `ConsoleButtonsWidget`/hard-stop wiring + at all. +- The original commit message explicitly notes this was "scoped to flomni + only this session (OMNY/LamNI wiring deferred)" — a known, flagged to-do, + not an oversight. +- **Portable** (the widget + `GalilController` method are already + generic/shared), but needs a home in lamni's GUI first — lamni has no + gripper-camera dock to piggyback on the way flomni does, so this needs a + decision on where it lives and which lamni Galil device(s) it targets. +- Size: small-medium. Safety-relevant — worth prioritizing despite the extra + design step. + +## 6. `tomo_alignment_scan()` — no lamni equivalent, but may be architecturally superseded + +- flomni: `tomo_alignment_scan()` (`flomni.py:2037`) — dedicated 5-point + (0/45/90/135/180°) alignment tomogram, writes scan numbers to + `~/data/raw/logs/ptychotomoalign_scannum.txt` for an external MATLAB tool + (`BEC_ptycho_align`), loaded back via `get_alignment_offset()`/ + `read_alignment_offset()` (`1439`, `1337`). +- lamni: no `tomo_alignment_scan`/`write_alignment_scan_numbers` anywhere. + Instead has a *different* mechanism: `read_additional_correction()`/ + `read_additional_correction_2()` (`lamni_alignment_mixin.py:285,291`) — a + lookup-table correction (`corr_pos_x/y` vs `corr_angle` bins) from an + externally-produced file, consumed by `compute_additional_correction()`. +- **Needs discussion, not a clear-cut gap**: is lamni's lookup-table scheme a + deliberate replacement for flomni's 5-point/MATLAB-fit approach, or would + lamni users also want a quick dedicated alignment-tomogram command? Don't + assume either way — ask before scoping. +- Size: needs its own design discussion if pursued at all. + +## 7. No OSA-collision-clearance warning in `lfzp_info()` + +- flomni: `ffzp_info()` (`flomni_optics_mixin.py:256`) compares live `fosaz` + against the nominal `fosaz_in` position (10 µm tolerance) and warns if the + OSA is currently closer to a collision than its defined IN position. +- lamni: `lfzp_info()` (`lamni_optics_mixin.py:291`) only prints + sample-to-FZP distance and a diameter/focal-distance/beam-size table — no + collision-clearance section. +- **Needs lamni-specific input**: the concept (warn if a movable optic is + closer to a known collision point than nominal) is generic, but the exact + formula (`33 - foptz_val` in flomni) is specific to flomni's optics + geometry — porting correctly needs lamni's own collision-geometry + constants, not just a code copy. +- Size: small once the geometry constants are known. + +## 8. Large block of flomni-only methods — confirmed hardware-specific, not portable + +`FlomniSampleTransferMixin` (`flomni.py`, ~46 methods): `ftransfer_*`, +gripper open/close/move, `save_reference_image()`, `laser_tracker_show_all`/ +`on`/`off`, `laser_parameters_*`, `laser_tweak`, +`umvr_fsamy_tracked`/`umv_fsamy_tracked` — all depend on flomni's automatic +gripper/tray sample changer and its `rtx`-integrated laser tracker, neither of +which lamni has (lamni samples are mounted manually — existing, known +constraint). Listed only so you can confirm none of these were expected to +have a lamni counterpart; not recommended for porting. + +## 9. `zero_deg_reference_at_each_subtomo` not yet on either status webpage — shared opportunity, not a flomni-ahead-of-lamni gap + +Neither `flomni_webpage_generator.py`'s `_CURRENT_PARAM_KEYS` +(`flomni_webpage_generator.py:62-76`) nor `LamNI_webpage_generator.py`'s +`TQ_PARAM_DISPLAY` (`LamNI_webpage_generator.py:71-86`) show +`zero_deg_reference_at_each_subtomo` (or, for lamni's tomo_type 2/3, its +`golden_projections_at_0_deg_for_damage_estimation` sibling). Since it's +missing symmetrically on both, there's no flomni feature to "port" here — +just a possible small addition to both webpages if useful, now that lamni's +tomo_type 1 property actually exists. + +## Checked and already at parity (not gaps) + +`write_to_scilog`/`_scilog_write` failure tolerance, `@scan_repeat` +retry-skip-on-definite-error, `frames_per_trigger` validation, `corridor_size` +conditional passing, `estimated_finish_time` progress field, measurement-ID +in the end-of-scan scilog summary, `at_each_angle_hook` name in that same +summary, x-ray-eye alignment image HDF5 saving, tomo-queue command-jobs/ +move/reorder-floor semantics, and `tomo_params.py`'s `SETUP_PROFILES` +capability flags (including `has_zero_deg_reference`, now symmetric) — all +confirmed present and equivalent on both sides.