debug: recover the scan command from the file itself
CI for csaxs_bec / test (push) Successful in 1m44s

Asked where the scan command can be recovered reliably. It is in the master
file: the file writer stores the whole scan metadata under
/entry/collection/metadata/bec (file_writer.py:255), including request_inputs,
which holds the arguments the scan was actually called with -- arg_bundle,
inputs and kwargs.

That beats notebooks, logbooks and recollection, because it is written by the
component that ran the scan rather than by anyone describing it afterwards.
It also settles the open question directly: whether S00473 was 0.65 um or
6.5 um is answerable from the file, not from the email thread.

--command prints it and stops, request_inputs first.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-25 12:27:25 +02:00
co-authored by Claude Opus 5
parent f0f8f620de
commit 8007a8c8ea
+58 -2
View File
@@ -536,7 +536,57 @@ def check_line_motion(signals, grid, fast_axis) -> None:
# --------------------------------------------------------------------------- #
def analyse(path: str, do_list: bool, force_lines=None, force_points=None) -> None:
def dump_scan_command(h5: h5py.File) -> None:
"""Print what the scan was actually asked to do.
This is the authoritative record: the file writer stores the whole scan
metadata under /entry/collection/metadata/bec, including `request_inputs`,
which holds the arguments the scan was called with. It beats notebooks,
logbooks and memory because it is written by the thing that ran the scan.
"""
roots = [p for p in ("/entry/collection/metadata/bec",
"/entry/collection/metadata") if p in h5]
if not roots:
print(" no metadata group found -- cannot recover the command from this file")
return
for root in roots[:1]:
print(f" scan request, from {root}:")
shown = 0
def show(name, obj):
nonlocal shown
if not isinstance(obj, h5py.Dataset):
return
try:
val = obj[()]
except Exception: # pylint: disable=broad-except
return
if isinstance(val, bytes):
val = val.decode(errors="replace")
if isinstance(val, np.ndarray):
val = val.tolist()
text = str(val)
if len(text) > 300:
text = text[:300] + " ..."
print(f" {name:<46} {text}")
shown += 1
# request_inputs first: that is the command itself
for sub in ("request_inputs", "scan_args", "scan_parameters"):
if sub in h5[root]:
h5[f"{root}/{sub}"].visititems(lambda n, o, s=sub: show(f"{s}/{n}", o))
for key in sorted(h5[root]):
if key in ("request_inputs", "scan_args", "scan_parameters"):
continue
node = h5[f"{root}/{key}"]
if isinstance(node, h5py.Dataset):
show(key, node)
if not shown:
print(" (nothing readable -- run --list to see the raw structure)")
def analyse(path: str, do_list: bool, force_lines=None, force_points=None,
show_command: bool = False) -> None:
print("=" * 80)
print(os.path.basename(path))
print("=" * 80)
@@ -547,6 +597,10 @@ def analyse(path: str, do_list: bool, force_lines=None, force_points=None) -> No
"frames_per_trigger") if k in meta}
print(" metadata:", interesting if interesting else "(none of the expected keys found)")
if show_command:
dump_scan_command(h5)
return
if do_list:
# Per-point arrays first: the file is dominated by scalar configuration
# entries, and a naive dump buries the data under hundreds of them.
@@ -647,6 +701,8 @@ def main(argv=None) -> int:
ap.add_argument("--root", default="/sls/x12sa/data/p23080/raw/data",
help="data root used with --scan")
ap.add_argument("--list", action="store_true", help="dump the file structure and stop")
ap.add_argument("--command", action="store_true",
help="print the scan request recorded in the file, and stop")
ap.add_argument("--lines", type=int, help="override number of lines")
ap.add_argument("--points", type=int, help="override points per line")
args = ap.parse_args(argv)
@@ -663,7 +719,7 @@ def main(argv=None) -> int:
for path in paths:
try:
analyse(path, args.list, args.lines, args.points)
analyse(path, args.list, args.lines, args.points, args.command)
except Exception as exc: # pylint: disable=broad-except
print(f" FAILED on {path}: {type(exc).__name__}: {exc}")
print()