fix: compute IVIM quality mask after D*/D swap#108
fix: compute IVIM quality mask after D*/D swap#108RajdeepKushwaha5 wants to merge 2 commits intoOSIPI:mainfrom
Conversation
The quality mask in _apply_ivim_quality_and_swap() was computed before the D*/D swap, causing voxels that needed swapping to be incorrectly flagged as bad quality. After the swap the values become valid, but the quality mask had already rejected them. Move the swap logic before the quality mask computation so the domain checks (D* > D, D < 5e-3, etc.) operate on corrected values.
There was a problem hiding this comment.
Pull request overview
This PR fixes IVIM post-processing so the domain quality mask is computed after the D*/D label swap, preventing voxels that only require swapping from being incorrectly rejected and zeroed out.
Changes:
- Reordered
_apply_ivim_quality_and_swap()to perform the D*/D swap before domain quality checks. - Updated the domain quality mask to use post-swap
d_swapped/ds_swappedvalues.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| # Ensure D* > D (swap if needed) — must happen BEFORE quality check | ||
| # so the quality mask reflects post-swap values | ||
| swap = d_vals > ds_vals | ||
| d_swapped = xp.where(swap, ds_vals, d_vals) | ||
| ds_swapped = xp.where(swap, d_vals, ds_vals) | ||
|
|
||
| # Update values in-place via array views | ||
| d_map.values[...] = d_swapped | ||
| param_maps["D*"].values[...] = ds_swapped | ||
|
|
||
| # Domain quality mask (computed on post-swap values) | ||
| quality = ( | ||
| fitter_qmask | ||
| & (d_swapped > 0) | ||
| & (d_swapped < 5e-3) | ||
| & (ds_swapped > d_swapped) | ||
| & (ds_swapped < 100e-3) | ||
| & (f_vals >= 0) | ||
| & (f_vals <= 0.7) | ||
| ) |
Covers the specific scenario from issue OSIPI#107: - Swapped voxel (D > D*) passes quality after swap - Already-ordered voxel is unaffected - Out-of-bounds voxel is rejected regardless of swap
|
i want to join osipi slack workspace but i am unable to join, the links on site and github their email sign-ups are disabled and no invite link is available. pls send me an invite link or pls suggest alternative |
check out this link : https://osipi.slack.com/archives/C0AC4HK5ECC |
|
Closing as did not read the readme. |
Summary
Fixes #107 — IVIM quality mask was computed before the D*/D swap, causing voxels that needed swapping to be incorrectly flagged as bad quality.
Problem
In
_apply_ivim_quality_and_swap(), the domain quality mask included the checkds_vals > d_vals. When the optimizer returned D > D* (a common occurrence since the labels are interchangeable), this check evaluated toFalse— marking the voxel as bad quality — even though the very next code block would swap the values into the correct order.Result: valid voxels were silently zeroed out by the quality mask, reducing usable perfusion-fraction map coverage.
Fix
Moved the D*/D swap before the quality mask computation. The domain checks (
D* > D,D < 5e-3, etc.) now operate on post-swap values, so voxels that only needed a label swap are no longer falsely rejected.Changes
osipy/ivim/fitting/estimators.py: Reordered swap and quality-mask blocks in_apply_ivim_quality_and_swap()d_swapped/ds_swappedinstead ofd_vals/ds_valsTesting
pytest tests/unit/ivim/ -v)ruff check .— all checks passed