Skip to content

Commit

Permalink
Calculate patch radius from number of volumes in DWI run (#892)
Browse files Browse the repository at this point in the history
* Work on patch radius.

* Determine n_volumes and use it.

* Fix type.

* Convert to integer.

* Update boilerplate.

* Fix style issue.

* Enforce odd integer value.

* Update boilerplate.

* Remove unused variables.

* Capitalize start of sentence.

* Apply suggestions from code review

Co-authored-by: Matt Cieslak <[email protected]>

---------

Co-authored-by: Matt Cieslak <[email protected]>
  • Loading branch information
tsalo and mattcieslak authored Dec 2, 2024
1 parent c50e4d9 commit 8bb6c0d
Show file tree
Hide file tree
Showing 5 changed files with 137 additions and 71 deletions.
45 changes: 37 additions & 8 deletions qsiprep/cli/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,23 @@ def _min_one(value, parser):
raise parser.error("Argument can't be less than one.")
return value

def _int_or_auto(value, parser):
"""Ensure an argument is an integer or 'auto'."""
if value.lower() == 'auto':
return value
try:
value = int(value)
except ValueError as exc:
raise parser.error('Argument must be an integer or "auto".') from exc

if value < 1:
raise parser.error('Argument must be greater than zero.')

if value % 2 == 0:
raise parser.error('Argument must be an odd integer.')

return value

def _to_gb(value):
scale = {'G': 1, 'T': 10**3, 'M': 1e-3, 'K': 1e-6, 'B': 1e-9}
digits = ''.join([c for c in value if c.isdigit()])
Expand Down Expand Up @@ -154,6 +171,7 @@ def _bids_filter(value, parser):
PathExists = partial(_path_exists, parser=parser)
IsFile = partial(_is_file, parser=parser)
PositiveInt = partial(_min_one, parser=parser)
IntOrAuto = partial(_int_or_auto, parser=parser)
BIDSFilter = partial(_bids_filter, parser=parser)

# Arguments as specified by BIDS-Apps
Expand Down Expand Up @@ -349,18 +367,25 @@ def _bids_filter(value, parser):
g_conf.add_argument(
'--dwi-denoise-window',
action='store',
type=IntOrAuto,
default='auto',
help='window size in voxels for image-based denoising, integer or "auto".'
'If "auto", 5 will be used for dwidenoise and auto-configured for '
'patch2self based on the number of b>0 images.',
help=(
'Window size in voxels for image-based denoising: odd integer or "auto". '
'Any non-"auto" value must be an odd, positive integer. '
'If using the "dwidenoise" denoising method, '
'the "auto" option will calculate a window size '
'based on the number of volumes according to the method described by the '
'dwidenoise documentation. '
'If using the "patch2self" denoising method, this argument will not be used.'
),
)
g_conf.add_argument(
'--denoise-method',
action='store',
choices=['dwidenoise', 'patch2self', 'none'],
default='dwidenoise',
help='Image-based denoising method. Either "dwidenoise" (MRtrix), '
'"patch2self" (DIPY) or none. (default: dwidenoise)',
'"patch2self" (DIPY) or "none". (default: dwidenoise)',
)
g_conf.add_argument(
'--unringing-method',
Expand Down Expand Up @@ -692,10 +717,14 @@ def parse_args(args=None, namespace=None):

# Validate the tricky options here
if config.workflow.dwi_denoise_window != 'auto':
try:
_ = int(config.workflow.dwi_denoise_window)
except ValueError:
raise Exception("--dwi-denoise-window must be an integer or 'auto'")
if config.workflow.denoise_method == 'patch2self':
config.loggers.cli.error(
'The --dwi-denoise-window option is not used when --denoise-method=patch2self'
)
elif config.workflow.denoise_method == 'none':
config.loggers.cli.warning(
'The --dwi-denoise-window option is not used when --denoise-method=none'
)

bids_dir = config.execution.bids_dir
output_dir = config.execution.output_dir
Expand Down
31 changes: 23 additions & 8 deletions qsiprep/data/boilerplate.bib
Original file line number Diff line number Diff line change
Expand Up @@ -394,13 +394,15 @@ @article{msmt5tt
}

@article{mrtrix3,
title = {MRtrix3: A fast, flexible and open software framework for medical image processing and visualisation},
author = {J-Donald and Smith, Robert and Raffelt, David and Tabbara, Rami and Dhollander, Thijs and Pietsch, Maximilian and Christiaens, Daan and Jeurissen, Ben and Yeh, Chun-Hung and Connelly, Alan"},
journal = {NeuroImage},
volume = {202},
pages = {116137},
year = {2019},
issn={1053-8119},
title={MRtrix3: A fast, flexible and open software framework for medical image processing and visualisation},
author={Tournier, J-Donald and Smith, Robert and Raffelt, David and Tabbara, Rami and Dhollander, Thijs and Pietsch, Maximilian and Christiaens, Daan and Jeurissen, Ben and Yeh, Chun-Hung and Connelly, Alan},
journal={Neuroimage},
volume={202},
pages={116137},
year={2019},
publisher={Elsevier},
url={https://doi.org/10.1016/j.neuroimage.2019.116137},
doi={10.1016/j.neuroimage.2019.116137}
}

@article{originalcsd,
Expand Down Expand Up @@ -535,7 +537,8 @@ @article{patch2self
author={Fadnavis, Shreyas and Batson, Joshua and Garyfallidis, Eleftherios},
journal={Advances in Neural Information Processing Systems},
volume={33},
year={2020}
year={2020},
url={https://proceedings.neurips.cc/paper_files/paper/2020/file/bc047286b224b7bfa73d4cb02de1238d-Paper.pdf},
}

@article{noddi,
Expand Down Expand Up @@ -640,3 +643,15 @@ @article{power2017simple
url={https://doi.org/10.1016/j.neuroimage.2016.08.009},
doi={10.1016/j.neuroimage.2016.08.009}
}

@article{cordero2019complex,
title={Complex diffusion-weighted image estimation via matrix recovery under general noise models},
author={Cordero-Grande, Lucilio and Christiaens, Daan and Hutter, Jana and Price, Anthony N and Hajnal, Jo V},
journal={Neuroimage},
volume={200},
pages={391--404},
year={2019},
publisher={Elsevier},
url={https://doi.org/10.1016/j.neuroimage.2019.06.039},
doi={10.1016/j.neuroimage.2019.06.039}
}
2 changes: 1 addition & 1 deletion qsiprep/workflows/dwi/hmc.py
Original file line number Diff line number Diff line change
Expand Up @@ -635,7 +635,7 @@ def init_dwi_model_hmc_wf(
name='outputnode',
)
workflow.__desc__ = (
'The the SHORELine method was used to estimate head motion in b>0 '
'The SHORELine method was used to estimate head motion in b>0 '
'images. This entails leaving out each b>0 image and reconstructing '
'the others using 3dSHORE [@merlet3dshore]. The signal for the left-'
f'out image serves as the registration target. A total of {num_iters} '
Expand Down
Loading

0 comments on commit 8bb6c0d

Please sign in to comment.