From 501c93d41c29e85bbfe86fff4cd7e149a66ff73b Mon Sep 17 00:00:00 2001 From: x12sa Date: Mon, 14 Sep 2026 17:06:02 +0200 Subject: [PATCH] fix(flomni): use last completed scan number when tomo_reconstruct's cached scan list is stale 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 Claude-Session: https://claude.ai/code/session_01TUimPoyFQRvxM6R3njvuVj --- .../plugins/flomni/flomni.py | 21 +++++- .../TODO_tomo_reconstruct_stale_scan_list.md | 68 +++++++++++++++++++ 2 files changed, 86 insertions(+), 3 deletions(-) create mode 100644 csaxs_bec/bec_ipython_client/plugins/omny/AI_docs/TODO_tomo_reconstruct_stale_scan_list.md diff --git a/csaxs_bec/bec_ipython_client/plugins/flomni/flomni.py b/csaxs_bec/bec_ipython_client/plugins/flomni/flomni.py index f5d4695b..d013a68f 100644 --- a/csaxs_bec/bec_ipython_client/plugins/flomni/flomni.py +++ b/csaxs_bec/bec_ipython_client/plugins/flomni/flomni.py @@ -3118,12 +3118,27 @@ class Flomni( random_offset_x: float | None = None, random_offset_y: float | None = None, ): - """write the tomo reconstruct file for the reconstruction queue""" + """Write the tomo reconstruct file for the reconstruction queue. + + Normally called automatically at the end of tomo_scan_projection()/ + tomo_acquire_at_angle(), which keep self._current_scan_list up to + date with the scan number(s) of the projection just acquired + (possibly several, when stitching). When called directly -- e.g. + from the command line after a plain scans.flomni_fermat_scan(), + without going through either of those -- that cached list is either + stale (left over from an earlier tomo scan) or not set at all, so + fall back to just the most recently completed scan number. + """ bec = builtins.__dict__.get("bec") + next_scan_number = bec.queue.next_scan_number + last_scan_number = next_scan_number - 1 + scan_list = getattr(self, "_current_scan_list", None) + if not scan_list or scan_list[-1] != last_scan_number: + scan_list = [last_scan_number] self.reconstructor.folder_name = self.ptycho_reconstruct_foldername self.reconstructor.write( - scan_list=self._current_scan_list, - next_scan_number=bec.queue.next_scan_number, + scan_list=scan_list, + next_scan_number=next_scan_number, base_path=base_path, probe_file_propagation=probe_propagation, random_offset_x=random_offset_x, diff --git a/csaxs_bec/bec_ipython_client/plugins/omny/AI_docs/TODO_tomo_reconstruct_stale_scan_list.md b/csaxs_bec/bec_ipython_client/plugins/omny/AI_docs/TODO_tomo_reconstruct_stale_scan_list.md new file mode 100644 index 00000000..a6722d81 --- /dev/null +++ b/csaxs_bec/bec_ipython_client/plugins/omny/AI_docs/TODO_tomo_reconstruct_stale_scan_list.md @@ -0,0 +1,68 @@ +# TODO: OMNY.tomo_reconstruct() writes a stale/missing scan list + +Found while fixing the same bug in `Flomni.tomo_reconstruct()` +(`csaxs_bec/bec_ipython_client/plugins/flomni/flomni.py:3114`, branch +`flomni_fixes_during_beamtimes`). Not applied to OMNY yet to avoid conflicting +with other in-progress OMNY changes on a separate branch — do it there. + +## The bug + +`OMNY.tomo_reconstruct()` (`csaxs_bec/bec_ipython_client/plugins/omny/omny.py:1217`) +names the reconstruction queue file from a fresh `bec.queue.next_scan_number` +(so the *filename* is always correct), but writes the file's *content* from +`self._current_scan_list`: + +```python +def tomo_reconstruct(self, base_path="~/Data10/specES1"): + """write the tomo reconstruct file for the reconstruction queue""" + bec = builtins.__dict__.get("bec") + base_path = os.path.expanduser(base_path) + ptycho_queue_path = Path(os.path.join(base_path, self.ptycho_reconstruct_foldername)) + ptycho_queue_path.mkdir(parents=True, exist_ok=True) + + last_scan_number = bec.queue.next_scan_number - 1 + ptycho_queue_file = os.path.abspath( + os.path.join(ptycho_queue_path, f"scan_{last_scan_number:05d}.dat") + ) + with open(ptycho_queue_file, "w") as queue_file: + scans = " ".join([str(scan) for scan in self._current_scan_list]) + queue_file.write(f"p.scan_number {scans}\n") + queue_file.write("p.check_nextscan_started 1\n") +``` + +`self._current_scan_list` is only kept up to date by whichever internal method +last ran and then called `tomo_reconstruct()` itself right after (the OMNY +equivalents of flomni's `tomo_scan_projection()`/`tomo_acquire_at_angle()` — +check where `_current_scan_list` is assigned in `omny.py` for the exact call +sites). Call `tomo_reconstruct()` directly from the command line instead — +e.g. after a plain fermat scan run by hand, not through those internal +flows — and the file gets written with whatever scan list happened to be +cached from the *previous* tomo scan (or raises `AttributeError` if none ran +yet this session). Filename right, content wrong/stale. + +## The fix (already applied to flomni, mirror it here) + +`Flomni.tomo_reconstruct()` now falls back to just the most recently +completed scan number whenever the cached list doesn't actually match it: + +```python +bec = builtins.__dict__.get("bec") +next_scan_number = bec.queue.next_scan_number +last_scan_number = next_scan_number - 1 +scan_list = getattr(self, "_current_scan_list", None) +if not scan_list or scan_list[-1] != last_scan_number: + scan_list = [last_scan_number] +``` + +Internal callers are unaffected (their cached list's last entry always equals +`next_scan_number - 1` at the point they call `tomo_reconstruct()`), while a +direct/standalone call now correctly falls back to `[last_scan_number]` +instead of writing stale content or crashing. + +Port the same `getattr(...)`/fallback logic into `OMNY.tomo_reconstruct()` +(note OMNY's version doesn't go through the shared `PtychoReconstructor` +class like flomni's does — it writes the file inline — so the fix applies +directly to the `scans = " ".join(...)` line, not to a shared `write()` +method). + +Not scoped/designed further here — just flagging it so it isn't lost.