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
This commit is contained in:
x12sa
2026-09-14 17:06:02 +02:00
co-authored by Claude Sonnet 5
parent df7c90c5d7
commit 501c93d41c
2 changed files with 86 additions and 3 deletions
@@ -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,
@@ -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.