Skip to content

Read the qform ParaVision actually writes, and run the NIfTI oracle in CI (#182) - #183

Merged
headmeister merged 1 commit into
isi-nmr:masterfrom
gdevenyi:fix/nifti-oracle-reads-the-qform
Jul 27, 2026
Merged

Read the qform ParaVision actually writes, and run the NIfTI oracle in CI (#182)#183
headmeister merged 1 commit into
isi-nmr:masterfrom
gdevenyi:fix/nifti-oracle-reads-the-qform

Conversation

@gdevenyi

Copy link
Copy Markdown
Contributor

Fixes #182.

test_affine_agrees_with_the_paravision_nifti_sform tripped its own assert sform_code > 0 before it ever compared a matrix, and skipped entirely in CI — so it reported nothing either way.

Read the form the writer populates

NIfTI-1 stores the affine two independent ways and a file need only carry one. All 14 PV360_StdData exports write the quaternion (qform_code=1) and leave the sform zeroed — method 2, squarely within the standard — while the helper read offset 280 regardless.

Decoding the qform instead, the export agrees with the VisuCore-derived affine to 4.8e-07 everywhere: obliques, the negative-determinant UTE3D volume and the diffusion series included. The oracle was sound the whole time and silently confirming the geometry.

nifti_affine now takes the sform when there is one, the qform otherwise, and fails only if a file declares neither — so it keeps working if a future ParaVision writes both.

Cover what is on disk

Coverage follows the nifti/ directories that exist rather than a hardcoded five, which brings in the four diffusion reconstructions plus T2map_MSME, T2star_FID_EPI and T2star_map_MGE: 14 reconstructions, 166 volumes. Every volume of an export is checked instead of whichever one glob happened to yield first, which also pins each export as internally consistent (they are — spread 0.0 within every directory).

Where no corpus is present the parameter set is empty and the test skips cleanly, rather than erroring on next() of an empty glob as it did before.

Make it run in CI

conftest smudged only 2dseq, traj and rawdata.job*, so the .nii files stayed LFS pointers and nifti_affine took its skip branch. .nii is now required media — 54 MB of a 1.7 GB dataset.

The cache key gains a -nifti suffix, because actions/cache does not re-save on a hit: without the bump the newly required files would be re-downloaded on every run instead of once. Drop that hunk if you would rather pay the download than invalidate the cache — the rest of the change works either way.

Verification

  • 14/14 pass locally, over 166 .nii files.
  • Negative control: the assertion rejects a missing RAS flip, a 0.1 mm origin shift, and a slice-direction sign flip. It is discriminating, not vacuous.
  • Suite: 2124 passed, 12 skipped, no failures — the 5 long-standing red cases are gone and 9 net new checks replace them.

🤖 Generated with Claude Code

https://claude.ai/code/session_01NuK1cZi8U54WXAdXMmGpzy

…ixes isi-nmr#182

test_affine_agrees_with_the_paravision_nifti_sform failed its own
`assert sform_code > 0` guard before it ever compared a matrix, and skipped
entirely in CI, so it reported nothing either way.

NIfTI-1 stores the affine two independent ways and a file need only carry one.
All 14 PV360_StdData exports write the quaternion (qform_code=1) and leave the
sform zeroed, which is method 2 and within the standard; the helper read offset
280 regardless. Decoding the qform instead, the export agrees with the
VisuCore-derived affine to 4.8e-07 everywhere -- obliques, the negative
determinant UTE3D volume and the diffusion series included -- so the oracle was
sound and silently confirming the geometry all along.

The helper now takes the sform when there is one, the qform otherwise, and
fails only when a file declares neither. Coverage follows what is on disk
rather than a list of five, which brings in the four diffusion reconstructions
and T2map_MSME, T2star_FID_EPI and T2star_map_MGE: 14 reconstructions, 166
volumes. Every volume of an export is checked rather than whichever one the
filesystem yielded first, which also pins the export as internally consistent.

conftest smudged only 2dseq/traj/rawdata.job*, so the .nii files stayed LFS
pointers in CI and the check skipped itself there. They are 54 MB of a 1.7 GB
dataset, and the cache key gains a suffix so the newly required media are
fetched once rather than on every run.

2124 passed, 12 skipped, no failures.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NuK1cZi8U54WXAdXMmGpzy
Copilot AI review requested due to automatic review settings July 26, 2026 19:30

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@headmeister
headmeister merged commit 407f1ef into isi-nmr:master Jul 27, 2026
7 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.

test_affine_agrees_with_the_paravision_nifti_sform reads a header field ParaVision does not write, and never runs in CI

3 participants