Skip to content

Tomo flyscan: correct time-based trigger spacing and average PandA angles per projection - #100

Merged
Jakub Wlodek (jwlodek) merged 3 commits into
NSLS2:mainfrom
sligara7:tomo-flyscan-averaging
Oct 22, 2026
Merged

Jakub Wlodek (jwlodek) merged 3 commits into
NSLS2:mainfrom
sligara7:tomo-flyscan-averaging

Conversation

@sligara7

@sligara7 Anthony Sligar (sligara7) commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

Fixes two issues Nghia hit with tomo_flyscan (2026-10-21):

  • Time-based spacing: pulse_step = move_time / num_pulses → / (num_pulses - 1). 19 projections over 0–180° stepped 9.47° and ended at 170.5°; now 10° and 180°, like position-based. A single pulse keeps move_time as its step.
  • Averaged angles: with images_to_average > 1, triggers still run evenly from start to stop (no shift, per Nghia). The exporter writes each PandA capture (e.g. rotation_angle) as one value per projection: the mean of that projection's images' angles. The raw capture stays linked as <name>_raw.

The exporter expects Tiled to shape an averaged capture as (projections, images), as ophyd-async's datakey shape implies, and refuses any other shape rather than guess.

Verification: mock/unit tests only. tests/test_flyers.py reproduced the 9.4737° step against main before the fix; tests/test_export_averaging.py covers the averaging helper. Full pytest tests --ignore=tests/gui: 326 passed. Not run on the simulated beamline (its PandA is still a mock, so it would not exercise real trigger timing) or on the real beamline.

…projections

Time-based triggers were spaced by move_time / num_pulses, so 19 projections over 0-180 stepped 9.47 deg and ended at 170.5; they now use num_pulses - 1, as position-based already did. With images_to_average > 1 the triggers are spread over a slightly wider range so each group's mean lands on start + k*(stop - start)/(N - 1). The tomo exporter writes rotation_angle (and any other 2D PandA capture) as one mean per projection, keeping the raw capture as <name>_raw.

Assisted-by: copilot:claude-opus-5-5
Copilot AI balanced review requested due to automatic review settings October 21, 2026 20:50

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Single-pulse time-based scans fail, and square captures-first arrays are averaged along the wrong axis.

2 open issues
What changed in this PR

Corrects tomography flyscan trigger spacing and centres averaged projections on requested angles, with corresponding export support.

Changes:

  • Adjusts time-based spacing and expands trigger travel when averaging.
  • Exports per-projection capture means while retaining raw links.
  • Adds trigger-position and capture-averaging tests.
File Description
tests/​test_flyers.py Tests trigger spacing and projection centring.
tests/​test_export_averaging.py Tests capture averaging and shape validation.
src/​hextools/​tomography/​flyscans.py Passes averaging settings and documents projection angles.
src/​hextools/​flyers.py Adjusts trigger spacing, travel bounds, and position offsets.
src/​hextools/​exporters/​utils.py Adds per-projection averaging helper.
src/​hextools/​exporters/​tomography.py Writes averaged captures alongside raw links.

Review effort: Balanced

Comment thread src/hextools/exporters/utils.py Resolved
Comment thread src/hextools/flyers.py Resolved
…le time-based pulse

average_per_projection now takes num_projections and accepts only (projections, images_to_average), the layout ophyd-async's datakey shape gives Tiled; a captures-first or mismatched array is refused instead of guessed, which a square array could get wrong. A time-based scan with one pulse uses move_time as its step again instead of dividing by zero. Tests for both.

Assisted-by: copilot:claude-opus-5-5
Copilot AI balanced review requested due to automatic review settings October 21, 2026 21:01

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Unresolved correctness issues and unverified hardware timing, wider travel, and Tiled capture layout require fixes and human validation.

No open issues 🎉

2 previously missed issues

In code that hasn't changed since last review

Medium severity Averaged one-dimensional captures bypass rotation-angle shape validation

src/​hextools/​exporters/​tomography.py:88

This filter bypasses shape validation for one-dimensional captures even when averaging is enabled. If Tiled supplies a flattened (95,) capture for 19 projections averaged from five images, it remains linked as rotation_angle, pairing 19 frames with 95 angles instead of rejecting the unsupported layout. Validate non-detector captures whenever averaging is enabled, and add an exporter-level test for this case.

Medium severity Single projection is not centered at the documented first-projection angle

src/​hextools/​flyers.py:177

With one projection and five images to average, this guard skips centring. For start_position=0 and stop_position=180, the triggers are at 0, 45, 90, 135 and 180 degrees, so the sole projection is centred at 90 rather than the documented first-projection angle of 0. A single unaveraged time-based pulse still fires at 0. Define singleton averaging explicitly, or reject this endpoint combination, and add a regression test.

2 resolved since last review

Review effort: Balanced

@jwlodek

Copy link
Copy Markdown
Contributor

Did nghia want the start/stop offset you're doing for the averaged scans?

@jwlodek

Copy link
Copy Markdown
Contributor

Export code changes look good to me. I'd like to have clarified whether we want the shifting behavior, and at the very least it should be configurable.

…s images' mean angle

Per Nghia: triggers run evenly from start to stop, and an averaged projection's angle is the mean of the PandA angles of its images. When averaging, every PandA capture goes through the shape check, so a flattened capture is refused.

Assisted-by: copilot:claude-opus-5-5
Copilot AI balanced review requested due to automatic review settings October 22, 2026 17:55
@sligara7

Copy link
Copy Markdown
Contributor Author

Nghia does not want the shift — removed in 6ec7d56. Triggers now run evenly from start to stop, and each averaged projection is recorded at the mean of its images' PandA angles (e.g. 5 images → (a0+…+a4)/5).

@sligara7 Anthony Sligar (sligara7) changed the title Tomo flyscan: correct time-based trigger spacing and centre averaged projections Tomo flyscan: correct time-based trigger spacing and average PandA angles per projection Oct 22, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Real PandA timing and the end-to-end Tiled capture layout remain unverified beyond mock/unit tests and need human validation.

No open issues 🎉

Review effort: Balanced

@jwlodek
Jakub Wlodek (jwlodek) merged commit 0e26cbc into NSLS2:main Oct 22, 2026
6 checks passed
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.

3 participants