Skip to content

Add TORTOISE DIFFPREP as a head-motion-correction backend#1066

Draft
tsalo wants to merge 15 commits into
mainfrom
tortoiseproc
Draft

Add TORTOISE DIFFPREP as a head-motion-correction backend#1066
tsalo wants to merge 15 commits into
mainfrom
tortoiseproc

Conversation

@tsalo

@tsalo tsalo commented Jun 18, 2026

Copy link
Copy Markdown
Member

Summary

Adds TORTOISE v4 DIFFPREP as a first-class --hmc-model option, alongside eddy, 3dSHORE, and tensor. DIFFPREP fits a signal model over arbitrary q-space, so it corrects head motion and eddy currents on non-shelled data (e.g. compressed-sensing DSI) — the gap where FSL eddy can't run (no shells) and SHORELine corrects motion but not eddy currents.

Three variants, selected by suffix:

--hmc-model Correction
diffprep_motion rigid head motion only
diffprep_quadratic rigid + 24-parameter quadratic eddy (recommended for CS-DSI)
diffprep_cubic rigid + cubic eddy

Scope

This backend is HMC-only (motion + eddy current). It follows the same "bake-in" model as eddy: TORTOISE's resampled DWI and rotated gradients become the workflow outputs, with identity per-volume affines.

It does not perform susceptibility distortion correction. If a fieldmap is present for a DWI series, the run fails fast with a clear NotImplementedError rather than silently skipping SDC — use --hmc-model eddy/3dSHORE, or --ignore fieldmaps.

Changes

  • CLI / config
    • New --hmc-model choices: diffprep_motion, diffprep_quadratic, diffprep_cubic.
    • New --diffprep-config flag (mirrors --eddy-config), backed by config.workflow.diffprep_config, validate_diffprep_config, and a default qsiprep/data/diffprep_params.json.
  • Interfaces (qsiprep/interfaces/tortoise.py)
    • TORTOISEProcess — DIFFPREP runner.
    • DIFFPREPMotionParams — per-volume rigid motion parameters for confounds / QC.
    • BmatToFSLGradients — recovers FSL bval/bvec from the TORTOISE b-matrix.
    • generate_diffprep_boilerplate — methods boilerplate.
  • Workflow (qsiprep/workflows/dwi/diffprep.py)
    • init_diffprep_hmc_wf — a drop-in peer of init_fsl_hmc_wf with an identical inputnode/outputnode contract, all in LPS+.
    • Builds a DWI-space brain mask from a pre-HMC b0 reference.
    • Routes gradients through ConformDwi so they stay consistent with the reoriented image.
    • Emits identity affines and a placeholder CNR map.
  • Dispatch (qsiprep/workflows/dwi/base.py)
    • init_dwi_preproc_wf branches to the new workflow when hmc_model.startswith('diffprep_').
    • Existing eddy / SHORELine paths, the pre-HMC LPS routing, and the --shoreline-iters guard are untouched (fully backward compatible).
  • Docs (docs/quickstart.rst)
    • Documents the three options and when to use them.

Diff: +688 / −3 across 10 files (parser, config, misc, data, interfaces, workflow, base, docs, plus tests).

Testing

10 new tests pass:

  • Interface unit tests — command-line construction, motion-param parsing, and a b-matrix → bval/bvec round-trip (including the off-diagonal eigenvector case).
  • A workflow construction / contract test for init_diffprep_hmc_wf.
  • CLI parse and config-validation tests.

Tests are intentionally offline (the TORTOISE binaries aren't available in CI), so the interface tests assert command-line structure rather than exact flag strings.

Not yet validated against the real binary

These TORTOISE-binary-dependent details still need reconciling against TORTOISEProcess inside the qsiprep container before a production run. They are deliberately isolated so they don't affect the public contract:

  • Exact TORTOISEProcess argument flag names and its output filenames.
  • The per-volume DIFFPREP transforms-file column layout (DIFFPREPMotionParams reads the first 6 columns).
  • The .bmtxt column order and b-value scale (BmatToFSLGradients — the round-trip test is internally consistent but not checked against FSLBVecsToTORTOISEBmatrix).
  • That antsApplyTransforms accepts the identity .mat files emitted for to_dwi_ref_affines.

The TORTOISE binaries themselves already ship in the qsiprep image (copied from pennlinc/qsiprep-drbuddi), so no Dockerfile change is needed.

tsalo and others added 14 commits June 18, 2026 12:31
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Add diffprep_motion, diffprep_quadratic, diffprep_cubic to --hmc-model choices
- Add --diffprep-config CLI argument mirroring --eddy-config
- Add diffprep_config to execution._paths and workflow class in config.py
- Add validate_diffprep_config() in utils/misc.py
- Add default qsiprep/data/diffprep_params.json
- Add TDD tests: parser choices + validate_diffprep_config unit tests

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Implements _TORTOISEProcessInputSpec, _TORTOISEProcessOutputSpec, and
TORTOISEProcess (wrapping the TORTOISEProcess binary in DIFFPREP mode)
in qsiprep/interfaces/tortoise.py. Adds test file
qsiprep/tests/test_interfaces_diffprep.py with cmdline construction test.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…eview)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Extracts the rigid 6-DOF (3 translations mm, 3 rotations rad) from the
per-volume DIFFPREP transforms file produced by TORTOISEProcess, writing
them to a plain-text motion file for downstream confound reporting.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…TORTOISE b-matrix

Implements the inverse of make_bmat_file: reads a TORTOISE .bmtxt (6-column
per-volume b-matrix) and recovers b-values via trace(B) and gradient directions
via principal eigenvector of B. Adds round-trip test confirming b-value and
direction recovery from hand-crafted b-matrix entries.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… 4 review)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…Task 5)

Create qsiprep/workflows/dwi/diffprep.py with init_diffprep_hmc_wf: a bake-in
HMC-only DIFFPREP workflow that is a drop-in peer of init_fsl_hmc_wf. Add
generate_diffprep_boilerplate to tortoise.py and the workflow-construction test
to test_interfaces_diffprep.py. Fixes the ExtractB0s bval_file gap noted in
the brief by wiring bmat_to_fsl.bval_file -> extract_b0s.bval_file.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… 5 review)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add import for init_diffprep_hmc_wf, module-level _diffprep_order()
helper, and elif diffprep_ dispatch in init_dwi_preproc_wf HMC block.
Add test_base_selects_diffprep pinning the helper.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…t (Task 6 review)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Document the three new --hmc-model values (diffprep_motion,
diffprep_quadratic, diffprep_cubic) and --diffprep-config flag in the
"Head motion correction model" section of docs/quickstart.rst, covering
their use case for non-shelled / CS-DSI acquisitions where FSL eddy
cannot be used and SHORELine does not correct eddy currents.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… review)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…y polarity, orientation, PATH guard (final review)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@codecov-commenter

codecov-commenter commented Jun 18, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 76.71233% with 34 lines in your changes missing coverage. Please review.
✅ Project coverage is 47.84%. Comparing base (e84d1f9) to head (19cd07f).
⚠️ Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
qsiprep/workflows/dwi/diffprep.py 66.07% 18 Missing and 1 partial ⚠️
qsiprep/interfaces/tortoise.py 87.14% 8 Missing and 1 partial ⚠️
qsiprep/cli/parser.py 25.00% 2 Missing and 1 partial ⚠️
qsiprep/workflows/dwi/base.py 50.00% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1066      +/-   ##
==========================================
+ Coverage   47.37%   47.84%   +0.46%     
==========================================
  Files          66       67       +1     
  Lines        9899    10045     +146     
  Branches     1099     1107       +8     
==========================================
+ Hits         4690     4806     +116     
- Misses       4978     5007      +29     
- Partials      231      232       +1     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

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.

2 participants