Skip to content

Port mono_t2 using skills - #7

Merged
agahkarakuzu merged 4 commits into
mainfrom
feat/model-port-mono-t2
Jul 23, 2026
Merged

Port mono_t2 using skills#7
agahkarakuzu merged 4 commits into
mainfrom
feat/model-port-mono-t2

Conversation

@agahkarakuzu

@agahkarakuzu agahkarakuzu commented Jul 23, 2026

Copy link
Copy Markdown
Member

Summary by CodeRabbit

  • New Features
    • Added monoexponential T2 mapping (mono_t2) with exponential and linear fitting options.
    • qmrust bidsify now supports 4D NIfTI inputs and NIfTI masks, preserving spatial header information and producing compatible BIDS output.
    • Added BIDS and non-BIDS mono_t2 recipes and MESE grouping for multi-echo acquisitions.
  • Bug Fixes
    • Corrected NIfTI headers for single-slice (2D) outputs to match expected qMRLab-style conventions.
  • Tests
    • Expanded end-to-end coverage (including OSF mono_t2 integration) with reference-map comparisons and affine preservation checks.
  • Documentation
    • Updated model/recipe checklist and provenance/definition-of-done requirements for mono_t2 validation.

Agah added 3 commits July 22, 2026 21:58
… overlay)

Output maps now always go through write_map_nifti (2D when z=1, 3D otherwise),
so single-slice derivatives match qMRLab's make_nii dim[0]=2 instead of a 3D
z=1 volume that misregistered against 2D references on oblique acquisitions.

Claude-Session: https://claude.ai/code/session_014DCAAax3rn83w46iL9QNEf
@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 81626854-93d6-444e-9660-3d1df82f6005

📥 Commits

Reviewing files that changed from the base of the PR and between 966b8e9 and 9ac1901.

📒 Files selected for processing (2)
  • ci/compare_maps.py
  • crates/qmrust-cli/src/bidsify.rs
🚧 Files skipped from review as they are similar to previous changes (2)
  • ci/compare_maps.py
  • crates/qmrust-cli/src/bidsify.rs

📝 Walkthrough

Walkthrough

Adds a monoexponential T2 model with exponential and linear fitting, registers it as MESE, extends qmrust bidsify to 4D NIfTI inputs with header preservation, unifies map output writing, adds paired recipes, and validates the pipeline against OSF reference data.

Changes

Mono T2 model

Layer / File(s) Summary
Configuration and fitting
crates/qmrust-core/src/models/mono_t2/*
Adds validated mono_t2 configuration, bounded exponential fitting with optional offset, linear fitting, protocol echo-time handling, and model tests.
Model and BIDS registration
crates/qmrust-core/src/models/mod.rs, crates/qmrust-core/src/registry.rs, crates/rust-bids/src/default_grouping.yaml
Registers mono_t2 with the MESE suffix and groups MESE volumes sequentially by echo.

CLI and output pipeline

Layer / File(s) Summary
NIfTI bidsify support
crates/qmrust-cli/src/main.rs, crates/qmrust-cli/src/bidsify.rs
Adds --nii-data and --nii-mask, reads NIfTI or MAT sources, preserves NIfTI headers, and writes the corresponding BIDS tree.
Unified map output writing
crates/qmrust-cli/src/commands.rs, crates/qmrust-cli/src/io/nifti.rs
Uses map writing for flat and derivative outputs, removes from_mat branching, and clears singleton-z temporal spacing in 2D headers.

Recipes and validation

Layer / File(s) Summary
Mono T2 recipes and workflow guidance
recipes/{bids,non-bids}/mono_t2_config.yaml, .claude/skills/porting-qmrlab-models/SKILL.md, docs/agents/*
Adds BIDS and non-BIDS mono_t2 recipes and documents their acquisition, masking, and provenance requirements.
OSF integration checks
ci/integration_osf.sh, ci/compare_maps.py
Runs NIfTI bidsify and BIDS fitting for mono_t2, verifies outputs, and compares the generated T2 map with the OSF reference.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

  • qMRLab/qmrust#5: Extends the same model-driven bidsify and write_bids_tree pipeline.

Sequence Diagram(s)

sequenceDiagram
  participant OSF
  participant qmrust_bidsify
  participant BIDS_Dataset
  participant qmrust_fit
  participant compare_maps
  OSF->>qmrust_bidsify: provide SEdata.nii.gz and Mask.nii.gz
  qmrust_bidsify->>BIDS_Dataset: write MESE data and EchoTime sidecars
  BIDS_Dataset->>qmrust_fit: provide BIDS recipe and protocol
  qmrust_fit->>BIDS_Dataset: write sub-01_T2map.nii.gz
  compare_maps->>BIDS_Dataset: read generated T2 map
  compare_maps->>OSF: compare against FitResults reference
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 47.06% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the main change: porting the mono_t2 model using skills.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/model-port-mono-t2

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🧹 Nitpick comments (2)
crates/qmrust-cli/src/bidsify.rs (1)

195-222: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

No unit test covers the Some(source_header) branch.

Every write_bids_tree call in this test module passes None; header preservation for NIfTI sources is only exercised by the OSF integration script, not a fast unit test.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/qmrust-cli/src/bidsify.rs` around lines 195 - 222, Add a focused unit
test for the write_bids_tree path with Some(source_header), using a distinctive
NIfTI header and verifying the generated output preserves its relevant header
fields. Keep the existing None-based tests unchanged and exercise the header
selection behavior around source_header.
ci/compare_maps.py (1)

20-35: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

read_nii ignores scl_slope/scl_inter NIfTI intensity-rescale fields.

Values are compared directly from the raw voxel buffer with no rescale applied. This is safe as long as both files are written unscaled (float64, slope=1/inter=0, as qmrust's writer guarantees), but if the qMRLab reference FitResults map ever carries a non-identity scale/intercept, this script would silently compare unscaled values.

♻️ Proposed fix
     dim = struct.unpack("<8h", b[40:56])
     datatype = struct.unpack("<h", b[70:72])[0]
+    scl_slope = struct.unpack("<f", b[112:116])[0]
+    scl_inter = struct.unpack("<f", b[116:120])[0]
     vox_offset = int(struct.unpack("<f", b[108:112])[0])
     n = 1
     for d in dim[1 : dim[0] + 1]:
         n *= d
     fmt = {16: "f", 64: "d"}.get(datatype)
     if fmt is None:
         sys.exit(f"unsupported NIfTI datatype {datatype} in {path}")
     size = struct.calcsize(fmt)
     raw = b[vox_offset : vox_offset + n * size]
-    return list(struct.unpack("<" + fmt * n, raw))
+    values = struct.unpack("<" + fmt * n, raw)
+    if scl_slope not in (0.0, 1.0) or scl_inter != 0.0:
+        slope = scl_slope if scl_slope != 0.0 else 1.0
+        return [v * slope + scl_inter for v in values]
+    return list(values)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ci/compare_maps.py` around lines 20 - 35, Update read_nii to parse the NIfTI
scl_slope and scl_inter fields and apply the intensity transform slope * voxel +
intercept to every decoded value before returning the flat list. Preserve
identity behavior for files with slope 1 and intercept 0, and handle the NIfTI
convention for an unset or zero slope appropriately.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/qmrust-cli/src/bidsify.rs`:
- Around line 49-59: Validate mask-source compatibility in the source-selection
logic around read_nifti_source and read_mat_source: reject --mask when
--nii-data is selected, and reject --nii-mask when --mat-data or --mat-dir is
selected. Preserve the existing mutually exclusive source validation and only
proceed when each mask flag matches its corresponding input source.

---

Nitpick comments:
In `@ci/compare_maps.py`:
- Around line 20-35: Update read_nii to parse the NIfTI scl_slope and scl_inter
fields and apply the intensity transform slope * voxel + intercept to every
decoded value before returning the flat list. Preserve identity behavior for
files with slope 1 and intercept 0, and handle the NIfTI convention for an unset
or zero slope appropriately.

In `@crates/qmrust-cli/src/bidsify.rs`:
- Around line 195-222: Add a focused unit test for the write_bids_tree path with
Some(source_header), using a distinctive NIfTI header and verifying the
generated output preserves its relevant header fields. Keep the existing
None-based tests unchanged and exercise the header selection behavior around
source_header.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 63ababc9-60c5-41fb-888d-b817ad685777

📥 Commits

Reviewing files that changed from the base of the PR and between a113233 and 966b8e9.

📒 Files selected for processing (19)
  • .claude/skills/porting-qmrlab-models/SKILL.md
  • ci/compare_maps.py
  • ci/integration_osf.sh
  • crates/qmrust-cli/src/bidsify.rs
  • crates/qmrust-cli/src/commands.rs
  • crates/qmrust-cli/src/io/nifti.rs
  • crates/qmrust-cli/src/main.rs
  • crates/qmrust-core/src/models/mod.rs
  • crates/qmrust-core/src/models/mono_t2/config.rs
  • crates/qmrust-core/src/models/mono_t2/fit.rs
  • crates/qmrust-core/src/models/mono_t2/mod.rs
  • crates/qmrust-core/src/models/mono_t2/model.rs
  • crates/qmrust-core/src/registry.rs
  • crates/rust-bids/src/default_grouping.yaml
  • docs/agents/ADDING-A-MODEL.md
  • docs/agents/ARCHITECTURE.md
  • docs/agents/DATA-PIPELINE.md
  • recipes/bids/mono_t2_config.yaml
  • recipes/non-bids/mono_t2_config.yaml

Comment thread crates/qmrust-cli/src/bidsify.rs
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.

1 participant