From 6a49acd6d3285a23bb95960bfdc70a10b9431372 Mon Sep 17 00:00:00 2001 From: Michael Joseph Date: Mon, 18 Mar 2019 16:51:24 -0400 Subject: [PATCH 01/11] initial attempt at adding mrtrix commands --- nipype/interfaces/fsl/epi.py | 3 +- nipype/interfaces/mrtrix3/__init__.py | 2 +- nipype/interfaces/mrtrix3/preprocess.py | 145 +++++++++++++++++++++++- 3 files changed, 146 insertions(+), 4 deletions(-) diff --git a/nipype/interfaces/fsl/epi.py b/nipype/interfaces/fsl/epi.py index 3e47576ec7..bbe84149c8 100644 --- a/nipype/interfaces/fsl/epi.py +++ b/nipype/interfaces/fsl/epi.py @@ -1383,7 +1383,7 @@ def _list_outputs(self): # If the output directory isn't defined, the interface seems to use # the default but not set its value in `self.inputs.output_dir` if not isdefined(self.inputs.output_dir): - out_dir = os.path.abspath(os.path.basename(self.inputs.base_name) + '.qc.nii.gz') + out_dir = os.path.abspath(os.path.basename(self.inputs.base_name) + '.qc') else: out_dir = os.path.abspath(self.inputs.output_dir) @@ -1421,4 +1421,3 @@ def _list_outputs(self): outputs['clean_volumes'] = clean_volumes return outputs - diff --git a/nipype/interfaces/mrtrix3/__init__.py b/nipype/interfaces/mrtrix3/__init__.py index 507380c30e..c9c131dde3 100644 --- a/nipype/interfaces/mrtrix3/__init__.py +++ b/nipype/interfaces/mrtrix3/__init__.py @@ -6,7 +6,7 @@ from .utils import (Mesh2PVE, Generate5tt, BrainMask, TensorMetrics, ComputeTDI, TCK2VTK, MRMath, MRConvert, DWIExtract) from .preprocess import (ResponseSD, ACTPrepareFSL, ReplaceFSwithFIRST, - DWIDenoise) + DWIDenoise, MRDeGibbs, DWIBiasCorrect) from .tracking import Tractography from .reconst import FitTensor, EstimateFOD from .connectivity import LabelConfig, LabelConvert, BuildConnectome diff --git a/nipype/interfaces/mrtrix3/preprocess.py b/nipype/interfaces/mrtrix3/preprocess.py index fc3559c918..935d978b60 100644 --- a/nipype/interfaces/mrtrix3/preprocess.py +++ b/nipype/interfaces/mrtrix3/preprocess.py @@ -21,7 +21,7 @@ class DWIDenoiseInputSpec(MRTrix3BaseInputSpec): mask = File( exists=True, argstr='-mask %s', - position=1, + #osition=1, desc='mask image') extent = traits.Tuple((traits.Int, traits.Int, traits.Int), argstr='-extent %d,%d,%d', @@ -75,6 +75,149 @@ class DWIDenoise(MRTrix3Base): output_spec = DWIDenoiseOutputSpec +class MRDeGibbsInputSpec(MRTrix3BaseInputSpec): + in_file = File( + exists=True, + argstr='%s', + position=-2, + mandatory=True, + desc='input DWI image') + axes = InputMultiObject( + traits.Int, + value=[0], + usedefault=True, + argstr='-axes %d', + desc='select the slice axes (default = 0)') + nshifts = InputMultiObject( + traits.Int, + value=[20], + usedefault=True, + argstr='-nshifts %d', + desc='discretizaiton of subpixel spacing (default = 20)') + minW = InputMultiObject( + traits.Int, + value=[1], + usedefault=True, + argstr='-minW %d', + desc='left border of window used for TV computation (default = 1)') + maxW = InputMultiObject( + traits.Int, + value=[3], + usedefault=True, + argstr='-maxW %d', + desc='right border of window used for TV computation (default = 3)') + out_file = File(name_template='%s_unring', + name_source='in_file', + keep_extension=True, + argstr="%s", + position=-1, + desc="the output unringed DWI image") + +class MRDeGibbsOutputSpec(TraitedSpec): + out_file = File(desc="the output unringed DWI image", exists=True) + +class MRDeGibbs(MRTrix3Base): + """ + Remove Gibbs ringing artifacts. + + This application attempts to remove Gibbs ringing artefacts from MRI images + using the method of local subvoxel-shifts proposed by Kellner et al. + + This command is designed to run on data directly after it has been + reconstructed by the scanner, before any interpolation of any kind has + taken place. You should not run this command after any form of motion + correction (e.g. not after dwipreproc). Similarly, if you intend running + dwidenoise, you should run this command afterwards, since it has the + potential to alter the noise structure, which would impact on dwidenoise’s + performance. + + Note that this method is designed to work on images acquired with full + k-space coverage. Running this method on partial Fourier (‘half-scan’) data + may lead to suboptimal and/or biased results, as noted in the original + reference below. There is currently no means of dealing with this; users + should exercise caution when using this method on partial Fourier data, and + inspect its output for any obvious artefacts. + + For more information, see + + + Example + ------- + + >>> import nipype.interfaces.mrtrix3 as mrt + >>> unring = mrt.MRDeGibbs() + >>> unring.inputs.in_file = 'dwi.mif' + >>> unring.cmdline + 'mrdegibbs dwi.mif dwi_unring.mif' + >>> unring.run() + """ + + _cmd = 'mrdegibbs' + input_spec = MRDeGibbsInputSpec + output_spec = MRDeGibbsOutputSpec + + +class DWIBiasCorrectInputSpec(MRTrix3BaseInputSpec): + in_file = File( + exists=True, + argstr='%s', + position=-2, + mandatory=True, + desc='input DWI image') + mask = File( + argstr='-mask %s', + desc='mask image') + bias = File( + argstr='-bias %s', + desc='bias field') + ants = traits.Bool( + True, + argstr='-ants', + desc='use ANTS N4') + fsl = traits.Bool( + False, + argstr='-fsl', + desc='use FSL FAST', + min_ver='5.0.10') + grad = File( + argstr='-grad %s', + desc='diffusion gradient table in MRtrix format') + fslgrad = File( + argstr='-fslgrad %s %s', + desc='diffusion gradient table in FSL bvecs/bvals format') + out_file = File(name_template='%s_unbias', + name_source='in_file', + keep_extension=True, + argstr="%s", + position=-1, + desc="the output bias corrected DWI image") + +class DWIBiasCorrectOutputSpec(TraitedSpec): + out_file = File(desc="the output bias corrected DWI image", exists=True) + +class DWIBiasCorrect(MRTrix3Base): + """ + Perform B1 field inhomogeneity correction for a DWI volume series. + + For more information, see + + + Example + ------- + + >>> import nipype.interfaces.mrtrix3 as mrt + >>> bias_correct = mrt.DWIBiasCorrect() + >>> bias_correct.inputs.in_file = 'dwi.mif' + >>> bias_correct.cmdline + 'dwibiascorrect dwi.mif dwi_unbias.mif' + >>> bias_correct.run() + """ + + _cmd = 'dwibiascorrect' + input_spec = DWIBiasCorrectInputSpec + output_spec = DWIBiasCorrectOutputSpec + + class ResponseSDInputSpec(MRTrix3BaseInputSpec): algorithm = traits.Enum( 'msmt_5tt', From c32258cded70494d1ffc3ae73dc943517839efb8 Mon Sep 17 00:00:00 2001 From: Michael Joseph Date: Tue, 19 Mar 2019 18:15:15 -0400 Subject: [PATCH 02/11] additional changes to new mrtrix3 interfaces --- nipype/interfaces/mrtrix3/preprocess.py | 57 +++++++++++++++---------- 1 file changed, 35 insertions(+), 22 deletions(-) diff --git a/nipype/interfaces/mrtrix3/preprocess.py b/nipype/interfaces/mrtrix3/preprocess.py index 935d978b60..a2b434e43b 100644 --- a/nipype/interfaces/mrtrix3/preprocess.py +++ b/nipype/interfaces/mrtrix3/preprocess.py @@ -26,17 +26,22 @@ class DWIDenoiseInputSpec(MRTrix3BaseInputSpec): extent = traits.Tuple((traits.Int, traits.Int, traits.Int), argstr='-extent %d,%d,%d', desc='set the window size of the denoising filter. (default = 5,5,5)') - noise = File( + out_noise = File(name_template='%s_noise', + name_source='in_file', + keep_extension=True, argstr='-noise %s', - desc='noise map') + desc="the output noise map", + genfile=True) out_file = File(name_template='%s_denoised', name_source='in_file', keep_extension=True, argstr="%s", position=-1, - desc="the output denoised DWI image") + desc="the output denoised DWI image", + genfile=True) class DWIDenoiseOutputSpec(TraitedSpec): + out_noise = File(desc="the output noise map", exists=True) out_file = File(desc="the output denoised DWI image", exists=True) class DWIDenoise(MRTrix3Base): @@ -84,10 +89,10 @@ class MRDeGibbsInputSpec(MRTrix3BaseInputSpec): desc='input DWI image') axes = InputMultiObject( traits.Int, - value=[0], + value=[0,1], usedefault=True, - argstr='-axes %d', - desc='select the slice axes (default = 0)') + argstr='-axes %s', # how to define list? + desc='select the slice axes (default = 0,1)') nshifts = InputMultiObject( traits.Int, value=[20], @@ -99,19 +104,22 @@ class MRDeGibbsInputSpec(MRTrix3BaseInputSpec): value=[1], usedefault=True, argstr='-minW %d', - desc='left border of window used for TV computation (default = 1)') + desc='left border of window used for total variation (TV) computation ' + '(default = 1)') maxW = InputMultiObject( traits.Int, value=[3], usedefault=True, argstr='-maxW %d', - desc='right border of window used for TV computation (default = 3)') + desc='right border of window used for total variation (TV) computation ' + '(default = 3)') out_file = File(name_template='%s_unring', name_source='in_file', keep_extension=True, argstr="%s", position=-1, - desc="the output unringed DWI image") + desc="the output unringed DWI image", + genfile=True) class MRDeGibbsOutputSpec(TraitedSpec): out_file = File(desc="the output unringed DWI image", exists=True) @@ -147,9 +155,9 @@ class MRDeGibbs(MRTrix3Base): >>> import nipype.interfaces.mrtrix3 as mrt >>> unring = mrt.MRDeGibbs() >>> unring.inputs.in_file = 'dwi.mif' - >>> unring.cmdline + >>> unring.cmdline # doctest: +ELLIPSIS 'mrdegibbs dwi.mif dwi_unring.mif' - >>> unring.run() + >>> unring.run() # doctest: +SKIP """ _cmd = 'mrdegibbs' @@ -164,33 +172,38 @@ class DWIBiasCorrectInputSpec(MRTrix3BaseInputSpec): position=-2, mandatory=True, desc='input DWI image') - mask = File( + in_mask = File( argstr='-mask %s', desc='mask image') - bias = File( - argstr='-bias %s', - desc='bias field') ants = traits.Bool( True, argstr='-ants', - desc='use ANTS N4') + desc='use ANTS N4 to estimate the inhomogeneity field') fsl = traits.Bool( False, argstr='-fsl', - desc='use FSL FAST', + desc='use FSL FAST to estimate the inhomogeneity field', min_ver='5.0.10') + # only one of either grad or fslgrad should be supplied grad = File( argstr='-grad %s', desc='diffusion gradient table in MRtrix format') fslgrad = File( argstr='-fslgrad %s %s', desc='diffusion gradient table in FSL bvecs/bvals format') - out_file = File(name_template='%s_unbias', + out_bias = File(name_template='%s_biasfield', + name_source='in_file', + keep_extension=True, + argstr='-bias %s', + desc='bias field', + genfile=True) + out_file = File(name_template='%s_biascorr', name_source='in_file', keep_extension=True, argstr="%s", position=-1, - desc="the output bias corrected DWI image") + desc="the output bias corrected DWI image", + genfile=True) class DWIBiasCorrectOutputSpec(TraitedSpec): out_file = File(desc="the output bias corrected DWI image", exists=True) @@ -208,9 +221,9 @@ class DWIBiasCorrect(MRTrix3Base): >>> import nipype.interfaces.mrtrix3 as mrt >>> bias_correct = mrt.DWIBiasCorrect() >>> bias_correct.inputs.in_file = 'dwi.mif' - >>> bias_correct.cmdline - 'dwibiascorrect dwi.mif dwi_unbias.mif' - >>> bias_correct.run() + >>> bias_correct.cmdline # doctest: +ELLIPSIS + 'dwibiascorrect dwi.mif dwi_biascorr.mif' + >>> bias_correct.run() # doctest: +SKIP """ _cmd = 'dwibiascorrect' From 83bc6a4ab204dd41b1316a4ca86c8e90cbaf52f1 Mon Sep 17 00:00:00 2001 From: Michael Joseph Date: Mon, 25 Mar 2019 07:14:08 -0400 Subject: [PATCH 03/11] add noisemap to dwidenoise and fix mrdegibbs --- nipype/interfaces/mrtrix3/preprocess.py | 43 +++++++++++++------------ 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/nipype/interfaces/mrtrix3/preprocess.py b/nipype/interfaces/mrtrix3/preprocess.py index a2b434e43b..273ae468e2 100644 --- a/nipype/interfaces/mrtrix3/preprocess.py +++ b/nipype/interfaces/mrtrix3/preprocess.py @@ -26,7 +26,7 @@ class DWIDenoiseInputSpec(MRTrix3BaseInputSpec): extent = traits.Tuple((traits.Int, traits.Int, traits.Int), argstr='-extent %d,%d,%d', desc='set the window size of the denoising filter. (default = 5,5,5)') - out_noise = File(name_template='%s_noise', + out_noisemap = File(name_template='%s_noisemap', name_source='in_file', keep_extension=True, argstr='-noise %s', @@ -41,7 +41,7 @@ class DWIDenoiseInputSpec(MRTrix3BaseInputSpec): genfile=True) class DWIDenoiseOutputSpec(TraitedSpec): - out_noise = File(desc="the output noise map", exists=True) + out_noisemap = File(desc="the output noise map", exists=True) out_file = File(desc="the output denoised DWI image", exists=True) class DWIDenoise(MRTrix3Base): @@ -87,28 +87,27 @@ class MRDeGibbsInputSpec(MRTrix3BaseInputSpec): position=-2, mandatory=True, desc='input DWI image') - axes = InputMultiObject( - traits.Int, - value=[0,1], + axes = traits.ListInt( + default_value=[0,1], + sep=',', + minlen=1, + maxlen=4, usedefault=True, - argstr='-axes %s', # how to define list? + argstr='-axes %s', desc='select the slice axes (default = 0,1)') - nshifts = InputMultiObject( - traits.Int, - value=[20], + nshifts = traits.Int( + default_value=20, usedefault=True, argstr='-nshifts %d', desc='discretizaiton of subpixel spacing (default = 20)') - minW = InputMultiObject( - traits.Int, - value=[1], + minW = traits.Int( + default_value=1, usedefault=True, argstr='-minW %d', desc='left border of window used for total variation (TV) computation ' '(default = 1)') - maxW = InputMultiObject( - traits.Int, - value=[3], + maxW = traits.Int( + default_value=3, usedefault=True, argstr='-maxW %d', desc='right border of window used for total variation (TV) computation ' @@ -174,15 +173,16 @@ class DWIBiasCorrectInputSpec(MRTrix3BaseInputSpec): desc='input DWI image') in_mask = File( argstr='-mask %s', - desc='mask image') - ants = traits.Bool( - True, + desc='input mask image for bias field estimation') + _xor_inputs = ('use_ants', 'use_fsl') + use_ants = traits.Bool( argstr='-ants', - desc='use ANTS N4 to estimate the inhomogeneity field') - fsl = traits.Bool( - False, + desc='use ANTS N4 to estimate the inhomogeneity field', + xor=_xor_inputs) + use_fsl = traits.Bool( argstr='-fsl', desc='use FSL FAST to estimate the inhomogeneity field', + xor=_xor_inputs, min_ver='5.0.10') # only one of either grad or fslgrad should be supplied grad = File( @@ -206,6 +206,7 @@ class DWIBiasCorrectInputSpec(MRTrix3BaseInputSpec): genfile=True) class DWIBiasCorrectOutputSpec(TraitedSpec): + out_bias = File(desc="the output estimated bias field") out_file = File(desc="the output bias corrected DWI image", exists=True) class DWIBiasCorrect(MRTrix3Base): From ef7c805b17abe6be5e4b07c318fa54d709df96e5 Mon Sep 17 00:00:00 2001 From: Michael Joseph Date: Mon, 25 Mar 2019 13:15:18 -0400 Subject: [PATCH 04/11] update mrdegibbs and dwibiascorrect --- nipype/interfaces/mrtrix3/preprocess.py | 61 +++++++++++++------------ 1 file changed, 33 insertions(+), 28 deletions(-) diff --git a/nipype/interfaces/mrtrix3/preprocess.py b/nipype/interfaces/mrtrix3/preprocess.py index 273ae468e2..0334a7d063 100644 --- a/nipype/interfaces/mrtrix3/preprocess.py +++ b/nipype/interfaces/mrtrix3/preprocess.py @@ -30,19 +30,19 @@ class DWIDenoiseInputSpec(MRTrix3BaseInputSpec): name_source='in_file', keep_extension=True, argstr='-noise %s', - desc="the output noise map", + desc='the output noise map', genfile=True) out_file = File(name_template='%s_denoised', name_source='in_file', keep_extension=True, - argstr="%s", + argstr='%s', position=-1, - desc="the output denoised DWI image", + desc='the output denoised DWI image', genfile=True) class DWIDenoiseOutputSpec(TraitedSpec): - out_noisemap = File(desc="the output noise map", exists=True) - out_file = File(desc="the output denoised DWI image", exists=True) + out_noisemap = File(desc='the output noise map', exists=True) + out_file = File(desc='the output denoised DWI image', exists=True) class DWIDenoise(MRTrix3Base): """ @@ -89,17 +89,18 @@ class MRDeGibbsInputSpec(MRTrix3BaseInputSpec): desc='input DWI image') axes = traits.ListInt( default_value=[0,1], - sep=',', - minlen=1, - maxlen=4, usedefault=True, + sep=',', + minlen=2, + maxlen=2, argstr='-axes %s', - desc='select the slice axes (default = 0,1)') + desc='indicate the plane in which the data was acquired (axial = 0,1; ' + 'coronal = 0,2; sagittal = 1,2') nshifts = traits.Int( default_value=20, usedefault=True, argstr='-nshifts %d', - desc='discretizaiton of subpixel spacing (default = 20)') + desc='discretization of subpixel spacing (default = 20)') minW = traits.Int( default_value=1, usedefault=True, @@ -112,16 +113,16 @@ class MRDeGibbsInputSpec(MRTrix3BaseInputSpec): argstr='-maxW %d', desc='right border of window used for total variation (TV) computation ' '(default = 3)') - out_file = File(name_template='%s_unring', + out_file = File(name_template='%s_unr', name_source='in_file', keep_extension=True, - argstr="%s", + argstr='%s', position=-1, - desc="the output unringed DWI image", + desc='the output unringed DWI image', genfile=True) class MRDeGibbsOutputSpec(TraitedSpec): - out_file = File(desc="the output unringed DWI image", exists=True) + out_file = File(desc='the output unringed DWI image', exists=True) class MRDeGibbs(MRTrix3Base): """ @@ -155,7 +156,7 @@ class MRDeGibbs(MRTrix3Base): >>> unring = mrt.MRDeGibbs() >>> unring.inputs.in_file = 'dwi.mif' >>> unring.cmdline # doctest: +ELLIPSIS - 'mrdegibbs dwi.mif dwi_unring.mif' + 'mrdegibbs dwi.mif dwi_unr.mif' >>> unring.run() # doctest: +SKIP """ @@ -174,23 +175,27 @@ class DWIBiasCorrectInputSpec(MRTrix3BaseInputSpec): in_mask = File( argstr='-mask %s', desc='input mask image for bias field estimation') - _xor_inputs = ('use_ants', 'use_fsl') + _xor_methods = ('use_ants', 'use_fsl') use_ants = traits.Bool( + default_value=True, + usedefault=True, argstr='-ants', desc='use ANTS N4 to estimate the inhomogeneity field', - xor=_xor_inputs) + xor=_xor_methods) use_fsl = traits.Bool( argstr='-fsl', desc='use FSL FAST to estimate the inhomogeneity field', - xor=_xor_inputs, + xor=_xor_methods, min_ver='5.0.10') - # only one of either grad or fslgrad should be supplied - grad = File( + _xor_grads = ('mrtrix_grad', 'fsl_grad') + mrtrix_grad = File( argstr='-grad %s', - desc='diffusion gradient table in MRtrix format') - fslgrad = File( + desc='diffusion gradient table in MRtrix format', + xor=_xor_grads) + fsl_grad = File( argstr='-fslgrad %s %s', - desc='diffusion gradient table in FSL bvecs/bvals format') + desc='diffusion gradient table in FSL bvecs/bvals format', + xor=_xor_grads) out_bias = File(name_template='%s_biasfield', name_source='in_file', keep_extension=True, @@ -200,14 +205,14 @@ class DWIBiasCorrectInputSpec(MRTrix3BaseInputSpec): out_file = File(name_template='%s_biascorr', name_source='in_file', keep_extension=True, - argstr="%s", + argstr='%s', position=-1, - desc="the output bias corrected DWI image", + desc='the output bias corrected DWI image', genfile=True) class DWIBiasCorrectOutputSpec(TraitedSpec): - out_bias = File(desc="the output estimated bias field") - out_file = File(desc="the output bias corrected DWI image", exists=True) + out_bias = File(desc='the output estimated bias field') + out_file = File(desc='the output bias corrected DWI image', exists=True) class DWIBiasCorrect(MRTrix3Base): """ @@ -223,7 +228,7 @@ class DWIBiasCorrect(MRTrix3Base): >>> bias_correct = mrt.DWIBiasCorrect() >>> bias_correct.inputs.in_file = 'dwi.mif' >>> bias_correct.cmdline # doctest: +ELLIPSIS - 'dwibiascorrect dwi.mif dwi_biascorr.mif' + 'dwibiascorrect -ants dwi.mif dwi_biascorr.mif' >>> bias_correct.run() # doctest: +SKIP """ From 51b6f15923eef857bf926d17ccfda2c44f62e1cf Mon Sep 17 00:00:00 2001 From: Michael Joseph Date: Mon, 25 Mar 2019 13:19:55 -0400 Subject: [PATCH 05/11] add contribution --- .zenodo.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.zenodo.json b/.zenodo.json index 065e188d8b..dca3d7ef20 100644 --- a/.zenodo.json +++ b/.zenodo.json @@ -330,6 +330,11 @@ "name": "Liem, Franz", "orcid": "0000-0003-0646-4810" }, + { + "affiliation": "The Centre for Addiction and Mental Health", + "name": "Joseph, Michael", + "orcid": "0000-0002-0068-230X" + } { "affiliation": "UniversityHospital Heidelberg, Germany", "name": "Kleesiek, Jens" From 6512e7add754eacd5b037355742623f84eb64597 Mon Sep 17 00:00:00 2001 From: Michael Joseph Date: Mon, 25 Mar 2019 13:32:56 -0400 Subject: [PATCH 06/11] fix typo and update docstrings --- nipype/interfaces/mrtrix3/preprocess.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/nipype/interfaces/mrtrix3/preprocess.py b/nipype/interfaces/mrtrix3/preprocess.py index 0334a7d063..e67712f1b8 100644 --- a/nipype/interfaces/mrtrix3/preprocess.py +++ b/nipype/interfaces/mrtrix3/preprocess.py @@ -21,7 +21,7 @@ class DWIDenoiseInputSpec(MRTrix3BaseInputSpec): mask = File( exists=True, argstr='-mask %s', - #osition=1, + position=1, desc='mask image') extent = traits.Tuple((traits.Int, traits.Int, traits.Int), argstr='-extent %d,%d,%d', @@ -71,7 +71,7 @@ class DWIDenoise(MRTrix3Base): >>> denoise.inputs.in_file = 'dwi.mif' >>> denoise.inputs.mask = 'mask.mif' >>> denoise.cmdline # doctest: +ELLIPSIS - 'dwidenoise -mask mask.mif dwi.mif dwi_denoised.mif' + 'dwidenoise -mask mask.mif -noise dwi_noisemap.mif dwi.mif dwi_denoised.mif' >>> denoise.run() # doctest: +SKIP """ @@ -156,7 +156,7 @@ class MRDeGibbs(MRTrix3Base): >>> unring = mrt.MRDeGibbs() >>> unring.inputs.in_file = 'dwi.mif' >>> unring.cmdline # doctest: +ELLIPSIS - 'mrdegibbs dwi.mif dwi_unr.mif' + 'mrdegibbs -axes 0,1 -maxW 3 -minW 1 -nshifts 20 dwi.mif dwi_unr.mif' >>> unring.run() # doctest: +SKIP """ @@ -228,7 +228,7 @@ class DWIBiasCorrect(MRTrix3Base): >>> bias_correct = mrt.DWIBiasCorrect() >>> bias_correct.inputs.in_file = 'dwi.mif' >>> bias_correct.cmdline # doctest: +ELLIPSIS - 'dwibiascorrect -ants dwi.mif dwi_biascorr.mif' + 'dwibiascorrect -ants -bias dwi_biasfield.mif dwi.mif dwi_biascorr.mif' >>> bias_correct.run() # doctest: +SKIP """ From 059f3eedb7b38b34dc7bd5dee5b9e0f4178dc14d Mon Sep 17 00:00:00 2001 From: Michael Joseph Date: Mon, 25 Mar 2019 13:38:04 -0400 Subject: [PATCH 07/11] add autogenerated tests --- .../mrtrix3/tests/test_auto_DWIBiasCorrect.py | 76 +++++++++++++++++++ .../mrtrix3/tests/test_auto_DWIDenoise.py | 14 +++- .../mrtrix3/tests/test_auto_MRDeGibbs.py | 66 ++++++++++++++++ 3 files changed, 154 insertions(+), 2 deletions(-) create mode 100644 nipype/interfaces/mrtrix3/tests/test_auto_DWIBiasCorrect.py create mode 100644 nipype/interfaces/mrtrix3/tests/test_auto_MRDeGibbs.py diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_DWIBiasCorrect.py b/nipype/interfaces/mrtrix3/tests/test_auto_DWIBiasCorrect.py new file mode 100644 index 0000000000..07986752e8 --- /dev/null +++ b/nipype/interfaces/mrtrix3/tests/test_auto_DWIBiasCorrect.py @@ -0,0 +1,76 @@ +# AUTO-GENERATED by tools/checkspecs.py - DO NOT EDIT +from __future__ import unicode_literals +from ..preprocess import DWIBiasCorrect + + +def test_DWIBiasCorrect_inputs(): + input_map = dict( + args=dict(argstr='%s', ), + bval_scale=dict(argstr='-bvalue_scaling %s', ), + environ=dict( + nohash=True, + usedefault=True, + ), + fsl_grad=dict( + argstr='-fslgrad %s %s', + xor=('mrtrix_grad', 'fsl_grad'), + ), + grad_file=dict(argstr='-grad %s', ), + grad_fsl=dict(argstr='-fslgrad %s %s', ), + in_bval=dict(), + in_bvec=dict(argstr='-fslgrad %s %s', ), + in_file=dict( + argstr='%s', + mandatory=True, + position=-2, + ), + in_mask=dict(argstr='-mask %s', ), + mrtrix_grad=dict( + argstr='-grad %s', + xor=('mrtrix_grad', 'fsl_grad'), + ), + nthreads=dict( + argstr='-nthreads %d', + nohash=True, + ), + out_bias=dict( + argstr='-bias %s', + genfile=True, + keep_extension=True, + name_source='in_file', + name_template='%s_biasfield', + ), + out_file=dict( + argstr='%s', + genfile=True, + keep_extension=True, + name_source='in_file', + name_template='%s_biascorr', + position=-1, + ), + use_ants=dict( + argstr='-ants', + usedefault=True, + xor=('use_ants', 'use_fsl'), + ), + use_fsl=dict( + argstr='-fsl', + min_ver='5.0.10', + xor=('use_ants', 'use_fsl'), + ), + ) + inputs = DWIBiasCorrect.input_spec() + + for key, metadata in list(input_map.items()): + for metakey, value in list(metadata.items()): + assert getattr(inputs.traits()[key], metakey) == value +def test_DWIBiasCorrect_outputs(): + output_map = dict( + out_bias=dict(), + out_file=dict(), + ) + outputs = DWIBiasCorrect.output_spec() + + for key, metadata in list(output_map.items()): + for metakey, value in list(metadata.items()): + assert getattr(outputs.traits()[key], metakey) == value diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_DWIDenoise.py b/nipype/interfaces/mrtrix3/tests/test_auto_DWIDenoise.py index 769ccb34a9..cf11ac3834 100644 --- a/nipype/interfaces/mrtrix3/tests/test_auto_DWIDenoise.py +++ b/nipype/interfaces/mrtrix3/tests/test_auto_DWIDenoise.py @@ -25,18 +25,25 @@ def test_DWIDenoise_inputs(): argstr='-mask %s', position=1, ), - noise=dict(argstr='-noise %s', ), nthreads=dict( argstr='-nthreads %d', nohash=True, ), out_file=dict( argstr='%s', + genfile=True, keep_extension=True, name_source='in_file', name_template='%s_denoised', position=-1, ), + out_noisemap=dict( + argstr='-noise %s', + genfile=True, + keep_extension=True, + name_source='in_file', + name_template='%s_noisemap', + ), ) inputs = DWIDenoise.input_spec() @@ -44,7 +51,10 @@ def test_DWIDenoise_inputs(): for metakey, value in list(metadata.items()): assert getattr(inputs.traits()[key], metakey) == value def test_DWIDenoise_outputs(): - output_map = dict(out_file=dict(), ) + output_map = dict( + out_file=dict(), + out_noisemap=dict(), + ) outputs = DWIDenoise.output_spec() for key, metadata in list(output_map.items()): diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_MRDeGibbs.py b/nipype/interfaces/mrtrix3/tests/test_auto_MRDeGibbs.py new file mode 100644 index 0000000000..c9290b562b --- /dev/null +++ b/nipype/interfaces/mrtrix3/tests/test_auto_MRDeGibbs.py @@ -0,0 +1,66 @@ +# AUTO-GENERATED by tools/checkspecs.py - DO NOT EDIT +from __future__ import unicode_literals +from ..preprocess import MRDeGibbs + + +def test_MRDeGibbs_inputs(): + input_map = dict( + args=dict(argstr='%s', ), + axes=dict( + argstr='-axes %s', + maxlen=2, + minlen=2, + sep=',', + usedefault=True, + ), + bval_scale=dict(argstr='-bvalue_scaling %s', ), + environ=dict( + nohash=True, + usedefault=True, + ), + grad_file=dict(argstr='-grad %s', ), + grad_fsl=dict(argstr='-fslgrad %s %s', ), + in_bval=dict(), + in_bvec=dict(argstr='-fslgrad %s %s', ), + in_file=dict( + argstr='%s', + mandatory=True, + position=-2, + ), + maxW=dict( + argstr='-maxW %d', + usedefault=True, + ), + minW=dict( + argstr='-minW %d', + usedefault=True, + ), + nshifts=dict( + argstr='-nshifts %d', + usedefault=True, + ), + nthreads=dict( + argstr='-nthreads %d', + nohash=True, + ), + out_file=dict( + argstr='%s', + genfile=True, + keep_extension=True, + name_source='in_file', + name_template='%s_unr', + position=-1, + ), + ) + inputs = MRDeGibbs.input_spec() + + for key, metadata in list(input_map.items()): + for metakey, value in list(metadata.items()): + assert getattr(inputs.traits()[key], metakey) == value +def test_MRDeGibbs_outputs(): + output_map = dict(out_file=dict(), ) + outputs = MRDeGibbs.output_spec() + + for key, metadata in list(output_map.items()): + for metakey, value in list(metadata.items()): + assert getattr(outputs.traits()[key], metakey) == value From 572d2e60db9745dcae639e13cd5ddc0d5818088c Mon Sep 17 00:00:00 2001 From: Michael Joseph Date: Mon, 25 Mar 2019 13:46:54 -0400 Subject: [PATCH 08/11] missing comma --- .zenodo.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.zenodo.json b/.zenodo.json index dca3d7ef20..db64d56b49 100644 --- a/.zenodo.json +++ b/.zenodo.json @@ -334,7 +334,7 @@ "affiliation": "The Centre for Addiction and Mental Health", "name": "Joseph, Michael", "orcid": "0000-0002-0068-230X" - } + }, { "affiliation": "UniversityHospital Heidelberg, Germany", "name": "Kleesiek, Jens" From dde5c4f7dd4fcdc3d612ba7c6c9d1cb756514f15 Mon Sep 17 00:00:00 2001 From: Michael Joseph Date: Thu, 28 Mar 2019 12:24:09 -0400 Subject: [PATCH 09/11] revert variable name changes to dwidenoise and address code review --- nipype/interfaces/mrtrix3/preprocess.py | 24 +++++++------------ .../mrtrix3/tests/test_auto_DWIBiasCorrect.py | 13 ++-------- .../mrtrix3/tests/test_auto_DWIDenoise.py | 13 ++-------- 3 files changed, 12 insertions(+), 38 deletions(-) diff --git a/nipype/interfaces/mrtrix3/preprocess.py b/nipype/interfaces/mrtrix3/preprocess.py index e67712f1b8..7e02d4dcf8 100644 --- a/nipype/interfaces/mrtrix3/preprocess.py +++ b/nipype/interfaces/mrtrix3/preprocess.py @@ -26,12 +26,9 @@ class DWIDenoiseInputSpec(MRTrix3BaseInputSpec): extent = traits.Tuple((traits.Int, traits.Int, traits.Int), argstr='-extent %d,%d,%d', desc='set the window size of the denoising filter. (default = 5,5,5)') - out_noisemap = File(name_template='%s_noisemap', - name_source='in_file', - keep_extension=True, + noise = File( argstr='-noise %s', - desc='the output noise map', - genfile=True) + desc='the output noise map') out_file = File(name_template='%s_denoised', name_source='in_file', keep_extension=True, @@ -41,7 +38,6 @@ class DWIDenoiseInputSpec(MRTrix3BaseInputSpec): genfile=True) class DWIDenoiseOutputSpec(TraitedSpec): - out_noisemap = File(desc='the output noise map', exists=True) out_file = File(desc='the output denoised DWI image', exists=True) class DWIDenoise(MRTrix3Base): @@ -71,7 +67,7 @@ class DWIDenoise(MRTrix3Base): >>> denoise.inputs.in_file = 'dwi.mif' >>> denoise.inputs.mask = 'mask.mif' >>> denoise.cmdline # doctest: +ELLIPSIS - 'dwidenoise -mask mask.mif -noise dwi_noisemap.mif dwi.mif dwi_denoised.mif' + 'dwidenoise -mask mask.mif dwi.mif dwi_denoised.mif' >>> denoise.run() # doctest: +SKIP """ @@ -155,7 +151,7 @@ class MRDeGibbs(MRTrix3Base): >>> import nipype.interfaces.mrtrix3 as mrt >>> unring = mrt.MRDeGibbs() >>> unring.inputs.in_file = 'dwi.mif' - >>> unring.cmdline # doctest: +ELLIPSIS + >>> unring.cmdline 'mrdegibbs -axes 0,1 -maxW 3 -minW 1 -nshifts 20 dwi.mif dwi_unr.mif' >>> unring.run() # doctest: +SKIP """ @@ -196,12 +192,9 @@ class DWIBiasCorrectInputSpec(MRTrix3BaseInputSpec): argstr='-fslgrad %s %s', desc='diffusion gradient table in FSL bvecs/bvals format', xor=_xor_grads) - out_bias = File(name_template='%s_biasfield', - name_source='in_file', - keep_extension=True, + bias = File( argstr='-bias %s', - desc='bias field', - genfile=True) + desc='bias field') out_file = File(name_template='%s_biascorr', name_source='in_file', keep_extension=True, @@ -211,7 +204,6 @@ class DWIBiasCorrectInputSpec(MRTrix3BaseInputSpec): genfile=True) class DWIBiasCorrectOutputSpec(TraitedSpec): - out_bias = File(desc='the output estimated bias field') out_file = File(desc='the output bias corrected DWI image', exists=True) class DWIBiasCorrect(MRTrix3Base): @@ -227,8 +219,8 @@ class DWIBiasCorrect(MRTrix3Base): >>> import nipype.interfaces.mrtrix3 as mrt >>> bias_correct = mrt.DWIBiasCorrect() >>> bias_correct.inputs.in_file = 'dwi.mif' - >>> bias_correct.cmdline # doctest: +ELLIPSIS - 'dwibiascorrect -ants -bias dwi_biasfield.mif dwi.mif dwi_biascorr.mif' + >>> bias_correct.cmdline + 'dwibiascorrect -ants dwi.mif dwi_biascorr.mif' >>> bias_correct.run() # doctest: +SKIP """ diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_DWIBiasCorrect.py b/nipype/interfaces/mrtrix3/tests/test_auto_DWIBiasCorrect.py index 07986752e8..9ac0515314 100644 --- a/nipype/interfaces/mrtrix3/tests/test_auto_DWIBiasCorrect.py +++ b/nipype/interfaces/mrtrix3/tests/test_auto_DWIBiasCorrect.py @@ -6,6 +6,7 @@ def test_DWIBiasCorrect_inputs(): input_map = dict( args=dict(argstr='%s', ), + bias=dict(argstr='-bias %s', ), bval_scale=dict(argstr='-bvalue_scaling %s', ), environ=dict( nohash=True, @@ -33,13 +34,6 @@ def test_DWIBiasCorrect_inputs(): argstr='-nthreads %d', nohash=True, ), - out_bias=dict( - argstr='-bias %s', - genfile=True, - keep_extension=True, - name_source='in_file', - name_template='%s_biasfield', - ), out_file=dict( argstr='%s', genfile=True, @@ -65,10 +59,7 @@ def test_DWIBiasCorrect_inputs(): for metakey, value in list(metadata.items()): assert getattr(inputs.traits()[key], metakey) == value def test_DWIBiasCorrect_outputs(): - output_map = dict( - out_bias=dict(), - out_file=dict(), - ) + output_map = dict(out_file=dict(), ) outputs = DWIBiasCorrect.output_spec() for key, metadata in list(output_map.items()): diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_DWIDenoise.py b/nipype/interfaces/mrtrix3/tests/test_auto_DWIDenoise.py index cf11ac3834..7ef30c10b8 100644 --- a/nipype/interfaces/mrtrix3/tests/test_auto_DWIDenoise.py +++ b/nipype/interfaces/mrtrix3/tests/test_auto_DWIDenoise.py @@ -25,6 +25,7 @@ def test_DWIDenoise_inputs(): argstr='-mask %s', position=1, ), + noise=dict(argstr='-noise %s', ), nthreads=dict( argstr='-nthreads %d', nohash=True, @@ -37,13 +38,6 @@ def test_DWIDenoise_inputs(): name_template='%s_denoised', position=-1, ), - out_noisemap=dict( - argstr='-noise %s', - genfile=True, - keep_extension=True, - name_source='in_file', - name_template='%s_noisemap', - ), ) inputs = DWIDenoise.input_spec() @@ -51,10 +45,7 @@ def test_DWIDenoise_inputs(): for metakey, value in list(metadata.items()): assert getattr(inputs.traits()[key], metakey) == value def test_DWIDenoise_outputs(): - output_map = dict( - out_file=dict(), - out_noisemap=dict(), - ) + output_map = dict(out_file=dict(), ) outputs = DWIDenoise.output_spec() for key, metadata in list(output_map.items()): From 1334636ce774f54284c665d998effae637e41d37 Mon Sep 17 00:00:00 2001 From: Michael Joseph Date: Thu, 28 Mar 2019 17:23:44 -0400 Subject: [PATCH 10/11] add list outputs --- nipype/interfaces/mrtrix3/preprocess.py | 16 ++++++++++++++++ .../mrtrix3/tests/test_auto_DWIBiasCorrect.py | 5 ++++- .../mrtrix3/tests/test_auto_DWIDenoise.py | 5 ++++- 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/nipype/interfaces/mrtrix3/preprocess.py b/nipype/interfaces/mrtrix3/preprocess.py index 7e02d4dcf8..ba5f734621 100644 --- a/nipype/interfaces/mrtrix3/preprocess.py +++ b/nipype/interfaces/mrtrix3/preprocess.py @@ -38,6 +38,7 @@ class DWIDenoiseInputSpec(MRTrix3BaseInputSpec): genfile=True) class DWIDenoiseOutputSpec(TraitedSpec): + noise = File(desc='the output noise map', exists=True) out_file = File(desc='the output denoised DWI image', exists=True) class DWIDenoise(MRTrix3Base): @@ -75,6 +76,13 @@ class DWIDenoise(MRTrix3Base): input_spec = DWIDenoiseInputSpec output_spec = DWIDenoiseOutputSpec + def _list_outputs(self): + outputs = self.output_spec().get() + outputs['out_file'] = op.abspath(self.inputs.out_file) + if self.inputs.noise != Undefined: + outputs['noise'] = op.abspath(self.inputs.noise) + return outputs + class MRDeGibbsInputSpec(MRTrix3BaseInputSpec): in_file = File( @@ -204,6 +212,7 @@ class DWIBiasCorrectInputSpec(MRTrix3BaseInputSpec): genfile=True) class DWIBiasCorrectOutputSpec(TraitedSpec): + bias = File(desc='the output bias field', exists=True) out_file = File(desc='the output bias corrected DWI image', exists=True) class DWIBiasCorrect(MRTrix3Base): @@ -228,6 +237,13 @@ class DWIBiasCorrect(MRTrix3Base): input_spec = DWIBiasCorrectInputSpec output_spec = DWIBiasCorrectOutputSpec + def _list_outputs(self): + outputs = self.output_spec().get() + outputs['out_file'] = op.abspath(self.inputs.out_file) + if self.inputs.bias != Undefined: + outputs['bias'] = op.abspath(self.inputs.bias) + return outputs + class ResponseSDInputSpec(MRTrix3BaseInputSpec): algorithm = traits.Enum( diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_DWIBiasCorrect.py b/nipype/interfaces/mrtrix3/tests/test_auto_DWIBiasCorrect.py index 9ac0515314..ea4d3f05d8 100644 --- a/nipype/interfaces/mrtrix3/tests/test_auto_DWIBiasCorrect.py +++ b/nipype/interfaces/mrtrix3/tests/test_auto_DWIBiasCorrect.py @@ -59,7 +59,10 @@ def test_DWIBiasCorrect_inputs(): for metakey, value in list(metadata.items()): assert getattr(inputs.traits()[key], metakey) == value def test_DWIBiasCorrect_outputs(): - output_map = dict(out_file=dict(), ) + output_map = dict( + bias=dict(), + out_file=dict(), + ) outputs = DWIBiasCorrect.output_spec() for key, metadata in list(output_map.items()): diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_DWIDenoise.py b/nipype/interfaces/mrtrix3/tests/test_auto_DWIDenoise.py index 7ef30c10b8..7b6930ee82 100644 --- a/nipype/interfaces/mrtrix3/tests/test_auto_DWIDenoise.py +++ b/nipype/interfaces/mrtrix3/tests/test_auto_DWIDenoise.py @@ -45,7 +45,10 @@ def test_DWIDenoise_inputs(): for metakey, value in list(metadata.items()): assert getattr(inputs.traits()[key], metakey) == value def test_DWIDenoise_outputs(): - output_map = dict(out_file=dict(), ) + output_map = dict( + noise=dict(), + out_file=dict(), + ) outputs = DWIDenoise.output_spec() for key, metadata in list(output_map.items()): From 70150049c30168878b6d9aa6e8a420ede063940c Mon Sep 17 00:00:00 2001 From: Michael Joseph Date: Fri, 29 Mar 2019 09:47:16 -0400 Subject: [PATCH 11/11] removed non ASCII characters --- nipype/interfaces/mrtrix3/preprocess.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nipype/interfaces/mrtrix3/preprocess.py b/nipype/interfaces/mrtrix3/preprocess.py index ba5f734621..99c6c4fb03 100644 --- a/nipype/interfaces/mrtrix3/preprocess.py +++ b/nipype/interfaces/mrtrix3/preprocess.py @@ -140,11 +140,11 @@ class MRDeGibbs(MRTrix3Base): taken place. You should not run this command after any form of motion correction (e.g. not after dwipreproc). Similarly, if you intend running dwidenoise, you should run this command afterwards, since it has the - potential to alter the noise structure, which would impact on dwidenoise’s + potential to alter the noise structure, which would impact on dwidenoise's performance. Note that this method is designed to work on images acquired with full - k-space coverage. Running this method on partial Fourier (‘half-scan’) data + k-space coverage. Running this method on partial Fourier ('half-scan') data may lead to suboptimal and/or biased results, as noted in the original reference below. There is currently no means of dealing with this; users should exercise caution when using this method on partial Fourier data, and