Skip to content

BUG: flyscan() master file missing /entry/flyscan_data/ group#13

Merged
prjemian merged 8 commits into
mainfrom
fix/12-flyscan-master-file
Jun 24, 2026
Merged

BUG: flyscan() master file missing /entry/flyscan_data/ group#13
prjemian merged 8 commits into
mainfrom
fix/12-flyscan-master-file

Conversation

@prjemian

Copy link
Copy Markdown
Contributor

Closes #12.

What

A flyscan master file's primary analysis group, /entry/flyscan_data, was silently going missing (or being written from a lossy source) when the area-detector file was unreachable at run end — most commonly because the image-files symlink next to the master was missing or mis-shaped.

This PR fixes that and makes the situation recoverable.

Changes (phased)

A — stop silent degradation

  • /entry/flyscan_data is written only from the authoritative area-detector file. If that file is not openable, no group is written and a clear WARNING explains the cause and recovery path (the lossy CA-monitor fallback is removed).
  • The unique per-frame correlation data (image_number, frame_index, timestamp) is folded into /entry/flyscan_data as subordinate datasets, with provenance attrs (source, n_frames_paired, n_frames_expected); the separate /entry/positions group is no longer written.

B — prevent recurrence

  • The image-files symlink is named per detector ({det.name}_files, e.g. eiger2_files), so multiple area detectors can coexist.
  • flyscan() auto-creates the symlink next to the master when the workstation mount (hdf1.read_path_template) is known and exists; it falls back to the manual-fix warning otherwise and never raises.

C — make masters self-repairable

  • The IOC→workstation path mapping (ad_read_path_template / ad_write_path_template) is stamped into the run start metadata.
  • New console script id3c-flyscan-repair recomputes the pairing from the area-detector file and writes /entry/flyscan_data into an existing master. The writer is extracted (write_flyscan_data) so the live plan and the tool produce identical layout.

Docs / cleanup

  • New how-to: docs/source/how_to/repair_flyscan_master.md; updated flyscan_frame_count.md.
  • Stripped historical narration from comments/docstrings and decluttered the flyscan() signature (details moved to the docstring Parameters section), per the AGENTS convention.

Also included: an unrelated one-line config fix (eiger_y PV reassignment in devices.yml) that was already staged locally.

Tests

New: test_expected_frame_count.py, test_ensure_ad_files_symlink.py, test_write_flyscan_data.py, test_flyscan_repair.py, test_path_templates.py; updated test_check_ad_files_symlink.py, test_external_link_target.py. Full suite: 119 passed.

Off-network note

Developed on a host without beamline EPICS access; tests exercise construction/file I/O and pure helpers, not live CA. The repair tool and writers are file-only and fully tested.

prjemian added 8 commits June 24, 2026 12:55
Add the convention to AGENTS.md: source comments and docstrings
describe the code as it is now, for the target audience.  Historical
narration (used to / formerly / no longer) belongs in issues, PRs,
and commit messages, not the source.
The per-frame correlation is now written solely from the authoritative
area-detector HDF1 file.  When that file is not openable, no group is
written and a clear WARNING explains the cause (missing/mis-shaped
image-files symlink) and the recovery path.

- Merge the per-frame correlation into the single /entry/flyscan_data
  NXdata group: image_number, frame_index, and timestamp join the
  image substack and position arrays; the separate /entry/positions
  group is no longer produced.
- Stamp provenance attributes (source, n_frames_paired,
  n_frames_expected) on /entry/flyscan_data.
- Add _expected_frame_count() helper (AD-file count, else start-doc
  num_frames) with unit tests.
- Update the frame-count explanation page to match.
Name the image-files symlink per detector ({det.name}_files, e.g.
eiger2_files) so a beamline with several area detectors can give each
its own root.  flyscan() now creates the symlink next to the master
file when the workstation mount (hdf1.read_path_template) is known and
exists; it falls back to the descriptive manual-fix warning otherwise
and never raises.

- Replace fixed AD_FILES_DIRNAME/AD_FILES_ROOT with per-detector
  ad_files_dirname()/ad_files_root_for() helpers.
- Add _ensure_ad_files_symlink() (auto-create, safe fallback) and
  _read_path_template(); _external_link_target() and
  _check_ad_files_symlink() use the per-detector name.
- Tests updated for the per-detector name; new
  test_ensure_ad_files_symlink.py.
Make a flyscan master file self-repairable when /entry/flyscan_data is
missing (area-detector file unreachable at run end).

- Stamp ad_read_path_template / ad_write_path_template (the
  IOC->workstation path mapping) into the start metadata so a reader
  can locate the data files from the master alone.
- Extract write_flyscan_data() into flyscan_3idc_analysis so the live
  plan and the offline tool write an identical /entry/flyscan_data.
- Add the id3c-flyscan-repair console script: recompute the pairing
  from the authoritative area-detector file and write the group.
- Add the how-to page and tests for the writer, the CLI, and the
  path-template helpers.
Remove dates, session/notes/strategy-doc references, Phase-N decision
labels, and 'empirically/formerly/revised' framing from source
comments and docstrings, keeping the present-tense technical facts.
Per the AGENTS.md convention; history lives in issues/PRs/commits.
- Reduce the flyscan() signature to a clean kwarg list; move the
  per-kwarg detail to the docstring Parameters section (and document
  _force_hdf_nonblocking there, which had been inline only).
- Convert module-level constant comments to following docstrings
  (_CONSUMER_TICK_DEFAULT, _CLEANUP_DRAIN_TICK, _FRAME_QUEUE_SIZE,
  _ACCL_FALLBACK_SECONDS, _AD_FILES_WARNED, _CAM_ERROR_STATES).
- Split dense multi-topic paragraphs into one topic per paragraph
  (flyscan() summary, read_motor_field, _FRAME_QUEUE_SIZE).
@coveralls

Copy link
Copy Markdown

Coverage Report for CI Build 28118953070

Coverage increased (+8.9%) to 64.75%

Details

  • Coverage increased (+8.9%) from the base build.
  • Patch coverage: 28 uncovered changes across 2 files (519 of 547 lines covered, 94.88%).
  • 7 coverage regressions across 1 file.

Uncovered Changes

File Changed Covered %
src/id3c/plans/flyscan_3idc.py 71 55 77.46%
src/id3c/utils/flyscan_repair.py 93 81 87.1%
Total (10 files) 547 519 94.88%

Coverage Regressions

7 previously-covered lines in 1 file lost coverage.

File Lines Losing Coverage Coverage
src/id3c/plans/flyscan_3idc.py 7 23.81%

Coverage Stats

Coverage Status
Relevant Lines: 2644
Covered Lines: 1712
Line Coverage: 64.75%
Coverage Strength: 0.65 hits per line

💛 - Coveralls

@prjemian prjemian merged commit 16fceaf into main Jun 24, 2026
5 checks passed
@prjemian prjemian deleted the fix/12-flyscan-master-file branch June 24, 2026 18:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

BUG: flyscan() master file missing /entry/flyscan_data/ group

2 participants