From 7bf99af849007264a96c3cc65383957373d23a77 Mon Sep 17 00:00:00 2001 From: Michael Joseph Date: Mon, 16 Sep 2019 14:52:37 -0400 Subject: [PATCH 01/19] initial eddy update --- nipype/interfaces/fsl/epi.py | 396 ++++++++++++++++++++++++----------- 1 file changed, 274 insertions(+), 122 deletions(-) diff --git a/nipype/interfaces/fsl/epi.py b/nipype/interfaces/fsl/epi.py index e7f3ff4318..5fd1cd0142 100644 --- a/nipype/interfaces/fsl/epi.py +++ b/nipype/interfaces/fsl/epi.py @@ -10,7 +10,7 @@ import nibabel as nb import warnings -from ...utils.filemanip import split_filename +from ...utils.filemanip import split_filename, fname_presuffix from ...utils import NUMPY_MMAP from ..base import traits, TraitedSpec, InputMultiPath, File, isdefined @@ -552,9 +552,8 @@ class EddyInputSpec(FSLCommandInputSpec): in_file = File( exists=True, mandatory=True, - argstr="--imain=%s", - desc=("File containing all the images to estimate " "distortions for"), - ) + argstr='--imain=%s', + desc='File containing all the images to estimate distortions for') in_mask = File( exists=True, mandatory=True, argstr="--mask=%s", desc="Mask to indicate brain" ) @@ -576,123 +575,218 @@ class EddyInputSpec(FSLCommandInputSpec): in_bvec = File( exists=True, mandatory=True, - argstr="--bvecs=%s", - desc=("File containing the b-vectors for all volumes in " "--imain"), - ) + argstr='--bvecs=%s', + desc='File containing the b-vectors for all volumes in --imain') in_bval = File( exists=True, mandatory=True, - argstr="--bvals=%s", - desc=("File containing the b-values for all volumes in " "--imain"), - ) + argstr='--bvals=%s', + desc='File containing the b-values for all volumes in --imain') out_base = traits.Str( - "eddy_corrected", - argstr="--out=%s", + default_value='eddy_corrected', usedefault=True, - desc=("basename for output (warped) image"), - ) + argstr='--out=%s', + desc='basename for output (warped) image') session = File( exists=True, - argstr="--session=%s", - desc=("File containing session indices for all volumes in " "--imain"), - ) + argstr='--session=%s', + desc='File containing session indices for all volumes in --imain') in_topup_fieldcoef = File( exists=True, - argstr="--topup=%s", - requires=["in_topup_movpar"], - desc=("topup file containing the field " "coefficients"), - ) + argstr='--topup=%s', + requires=['in_topup_movpar'], + desc='topup file containing the field coefficients') in_topup_movpar = File( - exists=True, requires=["in_topup_fieldcoef"], desc="topup movpar.txt file" - ) + exists=True, + requires=['in_topup_fieldcoef'], + desc='topup movpar.txt file') + field = File( + argstr='--field=%s', + desc=('NonTOPUP fieldmap scaled in Hz - filename has ' + 'to be provided without an extension. TOPUP is ' + 'strongly recommended')) + field_mat = File( + exists=True, + argstr='--field_mat=%s', + desc=('Matrix that specifies the relative locations of ' + 'the field specified by --field and first volume ' + 'in file --imain')) flm = traits.Enum( - "linear", "quadratic", "cubic", argstr="--flm=%s", desc="First level EC model" - ) - + 'linear', + 'quadratic', + 'cubic', + argstr='--flm=%s', + desc='First level EC model') slm = traits.Enum( - "none", "linear", "quadratic", argstr="--slm=%s", desc="Second level EC model" - ) - + 'none', + 'linear', + 'quadratic', + argstr='--slm=%s', + desc='Second level EC model') fep = traits.Bool( - False, argstr="--fep", desc="Fill empty planes in x- or y-directions" - ) - + False, argstr='--fep', desc='Fill empty planes in x- or y-directions') + initrand = traits.Bool( + False, + argstr='--initrand', + desc='Resets rand for when selecting voxels', + min_ver='5.0.10') interp = traits.Enum( - "spline", - "trilinear", - argstr="--interp=%s", - desc="Interpolation model for estimation step", - ) - + 'spline', + 'trilinear', + argstr='--interp=%s', + desc='Interpolation model for estimation step') nvoxhp = traits.Int( - 1000, + default_value=1000, usedefault=True, - argstr="--nvoxhp=%s", - desc=("# of voxels used to estimate the " "hyperparameters"), - ) - + argstr='--nvoxhp=%s', + desc=('# of voxels used to estimate the ' + 'hyperparameters')) fudge_factor = traits.Float( - 10.0, + default_value=10.0, usedefault=True, - argstr="--ff=%s", - desc=("Fudge factor for hyperparameter " "error variance"), - ) - + argstr='--ff=%s', + desc=('Fudge factor for hyperparameter ' + 'error variance')) dont_sep_offs_move = traits.Bool( False, - argstr="--dont_sep_offs_move", - desc=("Do NOT attempt to separate " "field offset from subject " "movement"), - ) - + argstr='--dont_sep_offs_move', + desc=('Do NOT attempt to separate ' + 'field offset from subject ' + 'movement')) dont_peas = traits.Bool( False, - argstr="--dont_peas", - desc="Do NOT perform a post-eddy alignment of " "shells", - ) - + argstr='--dont_peas', + desc="Do NOT perform a post-eddy alignment of " + "shells") fwhm = traits.Float( - desc=("FWHM for conditioning filter when estimating " "the parameters"), - argstr="--fwhm=%s", - ) - - niter = traits.Int( - 5, usedefault=True, argstr="--niter=%s", desc="Number of iterations" - ) - + desc=('FWHM for conditioning filter when estimating ' + 'the parameters'), + argstr='--fwhm=%s') + niter = traits.Int(5, usedefault=True, + argstr='--niter=%s', desc='Number of iterations') method = traits.Enum( - "jac", - "lsr", - argstr="--resamp=%s", - desc=("Final resampling method (jacobian/least " "squares)"), - ) + 'jac', + 'lsr', + argstr='--resamp=%s', + desc=('Final resampling method (jacobian/least ' + 'squares)')) + repol = traits.Bool( - False, argstr="--repol", desc="Detect and replace outlier slices" - ) + False, argstr='--repol', desc='Detect and replace outlier slices') + outlier_nstd = traits.Int( + argstr='--ol_nstd', + desc='Number of std off to qualify as outlier', + requires=['repol'], + min_ver='5.0.10') + outlier_nvox = traits.Int( + argstr='--ol_nvox', + desc='Min # of voxels in a slice for inclusion in outlier detection', + requires=['repol'], + min_ver='5.0.10') + outlier_type = traits.Enum( + 'sw', + 'gw', + 'both', + argstr='--ol_type', + desc='Type of outliers, slicewise (sw), groupwise (gw) or both (both)', + requires=['repol'], + min_ver='5.0.10') + outlier_pos = traits.Bool( + False, + argstr='--ol_pos', + desc='Consider both positive and negative outliers if set', + requires=['repol'], + min_ver='5.0.10') + outlier_sqr = traits.Bool( + False, + argstr='--ol_sqr', + desc='Consider outliers among sums-of-squared differences if set', + requires=['repol'], + min_ver='5.0.10') + mb = traits.Int( + argstr='--mb=%s', + desc='Multi-band factor', + min_ver='5.0.10') + mb_offs = traits.Enum( + 0, + 1, + -1, + argstr='--mb_offs=%s', + desc=('Multi-band offset (-1 if bottom slice removed, 1 if ' + 'top slice removed'), + requires=['mb'], + min_ver='5.0.10') + + mporder = traits.Int( + argstr='--mporder=%s', + desc='Order of slice-to-vol movement model', + requires=['slspec'], + min_ver='5.0.11') + s2v_niter = traits.Int( + argstr='--s2v_niter=%s', + desc='Number of iterations for slice-to-vol', + requires=['slspec'], + min_ver='5.0.11') + s2v_lambda = traits.Int( + agstr='--s2v_lambda', + desc='Regularisation weight for slice-to-vol movement (reasonable range 1-10)', + requires=['slspec'], + min_ver='5.0.11') + s2v_interp = traits.Enum( + 'trilinear', + 'spline', + argstr='--s2v_interp=%s', + desc='Slice-to-vol interpolation model for estimation step', + requires=['slspec'], + min_ver='5.0.11') + slspec = traits.File( + exists=True, + argstr='--slspec=%s', + desc='Name of text file completely specifying slice/group acquisition', + xor=['json'], + min_ver='5.0.11') + json = traits.File( + exists=True, + argstr='--json=%s', + desc='Name of .json text file with information about slice timing', + xor=['slspec'], + min_ver='6.0.1') + + estimate_move_by_susceptibility = traits.Bool( + False, + argstr='--estimate_move_by_susceptibility', + desc='Estimate how susceptibility field changes with subject movement', + min_ver='6.0.1') + mbs_niter = traits.Int( + argstr='--mbs_niter=%s', + desc='Number of iterations for MBS estimation', + requires=['estimate_move_by_susceptibility'], + min_ver='6.0.1') + mbs_lambda = traits.Int( + argstr='--mbs_lambda=%s', + desc='Weighting of regularisation for MBS estimation', + requires=['estimate_move_by_susceptibility'], + min_ver='6.0.1') + mbs_ksp = traits.Int( + argstr='--mbs_ksp=%smm', + desc='Knot-spacing for MBS field estimation', + requires=['estimate_move_by_susceptibility'], + min_ver='6.0.1') + num_threads = traits.Int( - 1, usedefault=True, nohash=True, desc="Number of openmp threads to use" - ) + 1, + usedefault=True, + nohash=True, + desc='Number of openmp threads to use') is_shelled = traits.Bool( False, - argstr="--data_is_shelled", - desc="Override internal check to ensure that " - "date are acquired on a set of b-value " - "shells", - ) - field = traits.Str( - argstr="--field=%s", - desc="NonTOPUP fieldmap scaled in Hz - filename has " - "to be provided without an extension. TOPUP is " - "strongly recommended", - ) - field_mat = File( - exists=True, - argstr="--field_mat=%s", - desc="Matrix that specifies the relative locations of " - "the field specified by --field and first volume " - "in file --imain", - ) - use_cuda = traits.Bool(False, desc="Run eddy using cuda gpu") + argstr='--data_is_shelled', + desc=('Override internal check to ensure that ' + 'date are acquired on a set of b-value ' + 'shells')) + + use_cuda = traits.Bool(False, desc='Run eddy using cuda gpu') cnr_maps = traits.Bool( False, desc="Output CNR-Maps", argstr="--cnr_maps", min_ver="5.0.10" ) @@ -707,11 +801,8 @@ class EddyOutputSpec(TraitedSpec): ) out_parameter = File( exists=True, - desc=( - "text file with parameters definining the field and" - "movement for each scan" - ), - ) + desc=('Text file with parameters defining the field and' + 'movement for each scan')) out_rotated_bvecs = File( exists=True, desc="File containing rotated b-values for all volumes" ) @@ -727,30 +818,61 @@ class EddyOutputSpec(TraitedSpec): ) out_shell_alignment_parameters = File( exists=True, - desc=( - "File containing rigid body movement parameters " - "between the different shells as estimated by a " - "post-hoc mutual information based registration" - ), - ) + desc=('Text file containing rigid body movement parameters ' + 'between the different shells as estimated by a ' + 'post-hoc mutual information based registration')) + out_shell_pe_translation_parameters = File( + exists=True, + desc=('Text file containing translation along the PE-direction ' + 'between the different shells as estimated by a ' + 'post-hoc mutual information based registration')) + out_shell_pe_translation_parameters = File( + exists=True, + desc=('Text file containing translation along the PE-direction ' + 'between the different shells as estimated by a ' + 'post-hoc mutual information based registration')) + out_outlier_map = File( + exists=True, + desc=('Matrix where rows represent volumes and columns represent ' + 'slices. "0" indicates that scan-slice is not an outlier ' + 'and "1" indicates that it is')) + out_outlier_n_stdev_map = File( + exists=True, + desc=('Matrix where rows represent volumes and columns represent ' + 'slices. Values indicate number of standard deviations off the ' + 'mean difference between observation and prediction is')) + out_outlier_n_sqr_stdev_map = File( + exists=True, + desc=('Matrix where rows represent volumes and columns represent ' + 'slices. Values indicate number of standard deivations off the ' + 'square root of the mean squared difference between observation ' + 'and prediction is')) out_outlier_report = File( exists=True, - desc=( - "Text-file with a plain language report on what " - "outlier slices eddy has found" - ), - ) - out_cnr_maps = File(exists=True, desc="path/name of file with the cnr_maps") - out_residuals = File(exists=True, desc="path/name of file with the residuals") + desc=('Text file with a plain language report on what ' + 'outlier slices eddy has found')) + out_outlier_free = File( + exists=True, + desc=('4D image file not corrected for susceptibility or eddy-' + 'current distortions or subject movement but with outlier ' + 'slices replaced')) + out_movement_over_time = File( + exists=True, + desc=('Text file containing translations (mm) and rotations ' + '(radians) for each excitation')) + out_cnr_maps = File( + exists=True, desc='path/name of file with the cnr_maps') + out_residuals = File( + exists=True, desc='path/name of file with the residuals') class Eddy(FSLCommand): """ Interface for FSL eddy, a tool for estimating and correcting eddy currents induced distortions. `User guide - `_ and + `_ and `more info regarding acqp file - `_. + `_. Examples -------- @@ -765,12 +887,12 @@ class Eddy(FSLCommand): >>> eddy.inputs.in_bval = 'bvals.scheme' >>> eddy.inputs.use_cuda = True >>> eddy.cmdline # doctest: +ELLIPSIS - 'eddy_cuda --ff=10.0 --acqp=epi_acqp.txt --bvals=bvals.scheme \ + 'eddy_cuda --ff=10.0 --fwhm=0 --acqp=epi_acqp.txt --bvals=bvals.scheme \ --bvecs=bvecs.scheme --imain=epi.nii --index=epi_index.txt \ --mask=epi_mask.nii --niter=5 --nvoxhp=1000 --out=.../eddy_corrected' >>> eddy.inputs.use_cuda = False >>> eddy.cmdline # doctest: +ELLIPSIS - 'eddy_openmp --ff=10.0 --acqp=epi_acqp.txt --bvals=bvals.scheme \ + 'eddy_openmp --ff=10.0 --fwhm=0 --acqp=epi_acqp.txt --bvals=bvals.scheme \ --bvecs=bvecs.scheme --imain=epi.nii --index=epi_index.txt \ --mask=epi_mask.nii --niter=5 --nvoxhp=1000 --out=.../eddy_corrected' >>> res = eddy.run() # doctest: +SKIP @@ -824,9 +946,11 @@ def _run_interface(self, runtime): return runtime def _format_arg(self, name, spec, value): - if name == "in_topup_fieldcoef": - return spec.argstr % value.split("_fieldcoef")[0] - if name == "out_base": + if name == 'in_topup_fieldcoef': + return spec.argstr % value.split('_fieldcoef')[0] + if name == 'field': + return spec.argstr % fname_presuffix(value, use_ext=False) + if name == 'out_base': return spec.argstr % os.path.abspath(value) return super(Eddy, self)._format_arg(name, spec, value) @@ -848,11 +972,29 @@ def _list_outputs(self): "%s.eddy_restricted_movement_rms" % self.inputs.out_base ) out_shell_alignment_parameters = os.path.abspath( - "%s.eddy_post_eddy_shell_alignment_parameters" % self.inputs.out_base - ) + '%s.eddy_post_eddy_shell_alignment_parameters' % + self.inputs.out_base) + out_shell_pe_translation_parameters = os.path.abspath( + '%s.eddy_post_eddy_shell_PE_translation_parameters' % + self.inputs.out_base) + out_outlier_map = os.path.abspath( + '%s.eddy_outlier_map' % self.inputs.out_base) + out_outlier_n_stdev_map = os.path.abspath( + '%s.eddy_outlier_n_stdev_map' % self.inputs.out_base) + out_outlier_n_sqr_stdev_map = os.path.abspath( + '%s.eddy_outlier_n_sqr_stdev_map' % self.inputs.out_base) out_outlier_report = os.path.abspath( - "%s.eddy_outlier_report" % self.inputs.out_base - ) + '%s.eddy_outlier_report' % self.inputs.out_base) + if isdefined(self.inputs.repol) and self.inputs.repol: + out_outlier_free = os.path.abspath( + '%s.eddy_outlier_free_data' % self.inputs.out_base) + if os.path.exists(out_outlier_free): + outputs['out_outlier_free'] = out_outlier_free + if isdefined(self.inputs.mporder) and self.inputs.mporder > 0: + out_movement_over_time = os.path.abspath( + '%s.eddy_movement_over_time' % self.inputs.out_base) + if os.path.exists(out_movement_over_time): + outputs['out_movement_over_time'] = out_movement_over_time if isdefined(self.inputs.cnr_maps) and self.inputs.cnr_maps: out_cnr_maps = os.path.abspath( "%s.eddy_cnr_maps.nii.gz" % self.inputs.out_base @@ -873,7 +1015,17 @@ def _list_outputs(self): if os.path.exists(out_restricted_movement_rms): outputs["out_restricted_movement_rms"] = out_restricted_movement_rms if os.path.exists(out_shell_alignment_parameters): - outputs["out_shell_alignment_parameters"] = out_shell_alignment_parameters + outputs['out_shell_alignment_parameters'] = \ + out_shell_alignment_parameters + if os.path.exists(out_shell_pe_translation_parameters): + outputs['out_shell_pe_translation_parameters'] = \ + out_shell_pe_translation_parameters + if os.path.exists(out_outlier_map): + outputs['out_outlier_map'] = out_outlier_map + if os.path.exists(out_outlier_n_stdev_map): + outputs['out_outlier_n_stdev_map'] = out_outlier_n_stdev_map + if os.path.exists(out_outlier_n_sqr_stdev_map): + outputs['out_outlier_n_sqr_stdev_map'] = out_outlier_n_sqr_stdev_map if os.path.exists(out_outlier_report): outputs["out_outlier_report"] = out_outlier_report From 1b6c5c1d5c758021dd702fce655b69a1ea126f5f Mon Sep 17 00:00:00 2001 From: Michael Joseph Date: Mon, 16 Sep 2019 20:18:04 -0400 Subject: [PATCH 02/19] update doctest --- nipype/interfaces/fsl/epi.py | 53 ++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 21 deletions(-) diff --git a/nipype/interfaces/fsl/epi.py b/nipype/interfaces/fsl/epi.py index 5fd1cd0142..0fa78a8ee7 100644 --- a/nipype/interfaces/fsl/epi.py +++ b/nipype/interfaces/fsl/epi.py @@ -586,7 +586,7 @@ class EddyInputSpec(FSLCommandInputSpec): default_value='eddy_corrected', usedefault=True, argstr='--out=%s', - desc='basename for output (warped) image') + desc='Basename for output image') session = File( exists=True, argstr='--session=%s', @@ -595,37 +595,39 @@ class EddyInputSpec(FSLCommandInputSpec): exists=True, argstr='--topup=%s', requires=['in_topup_movpar'], - desc='topup file containing the field coefficients') + desc='Topup results file containing the field coefficients') in_topup_movpar = File( exists=True, requires=['in_topup_fieldcoef'], - desc='topup movpar.txt file') + desc='Topup results file containing the movement parameters') field = File( argstr='--field=%s', - desc=('NonTOPUP fieldmap scaled in Hz - filename has ' - 'to be provided without an extension. TOPUP is ' - 'strongly recommended')) + desc=('Non-topup derived fieldmap scaled in Hz')) field_mat = File( exists=True, argstr='--field_mat=%s', - desc=('Matrix that specifies the relative locations of ' - 'the field specified by --field and first volume ' - 'in file --imain')) + desc=('Matrix specifying the relative positions of ' + 'the fieldmap, --field, and the first volume ' + 'of the input file, --imain')) flm = traits.Enum( - 'linear', 'quadratic', + 'linear', 'cubic', + usedefault=True, argstr='--flm=%s', desc='First level EC model') slm = traits.Enum( 'none', 'linear', 'quadratic', + usedefault=True, argstr='--slm=%s', desc='Second level EC model') fep = traits.Bool( - False, argstr='--fep', desc='Fill empty planes in x- or y-directions') + False, + argstr='--fep', + desc='Fill empty planes in x- or y-directions') initrand = traits.Bool( False, argstr='--initrand', @@ -634,6 +636,7 @@ class EddyInputSpec(FSLCommandInputSpec): interp = traits.Enum( 'spline', 'trilinear', + usedefault=True, argstr='--interp=%s', desc='Interpolation model for estimation step') nvoxhp = traits.Int( @@ -660,6 +663,8 @@ class EddyInputSpec(FSLCommandInputSpec): desc="Do NOT perform a post-eddy alignment of " "shells") fwhm = traits.Float( + default_value=0.0, + usedefault=True, desc=('FWHM for conditioning filter when estimating ' 'the parameters'), argstr='--fwhm=%s') @@ -668,6 +673,7 @@ class EddyInputSpec(FSLCommandInputSpec): method = traits.Enum( 'jac', 'lsr', + usedefault=True, argstr='--resamp=%s', desc=('Final resampling method (jacobian/least ' 'squares)')) @@ -721,35 +727,36 @@ class EddyInputSpec(FSLCommandInputSpec): mporder = traits.Int( argstr='--mporder=%s', desc='Order of slice-to-vol movement model', - requires=['slspec'], min_ver='5.0.11') s2v_niter = traits.Int( argstr='--s2v_niter=%s', desc='Number of iterations for slice-to-vol', - requires=['slspec'], + requires=['mporder'], min_ver='5.0.11') s2v_lambda = traits.Int( agstr='--s2v_lambda', desc='Regularisation weight for slice-to-vol movement (reasonable range 1-10)', - requires=['slspec'], + requires=['mporder'], min_ver='5.0.11') s2v_interp = traits.Enum( 'trilinear', 'spline', argstr='--s2v_interp=%s', desc='Slice-to-vol interpolation model for estimation step', - requires=['slspec'], + requires=['mporder'], min_ver='5.0.11') slspec = traits.File( exists=True, argstr='--slspec=%s', desc='Name of text file completely specifying slice/group acquisition', + requires=['mporder'], xor=['json'], min_ver='5.0.11') json = traits.File( exists=True, argstr='--json=%s', desc='Name of .json text file with information about slice timing', + requires=['mporder'], xor=['slspec'], min_ver='6.0.1') @@ -887,14 +894,18 @@ class Eddy(FSLCommand): >>> eddy.inputs.in_bval = 'bvals.scheme' >>> eddy.inputs.use_cuda = True >>> eddy.cmdline # doctest: +ELLIPSIS - 'eddy_cuda --ff=10.0 --fwhm=0 --acqp=epi_acqp.txt --bvals=bvals.scheme \ ---bvecs=bvecs.scheme --imain=epi.nii --index=epi_index.txt \ ---mask=epi_mask.nii --niter=5 --nvoxhp=1000 --out=.../eddy_corrected' + 'eddy_cuda --flm=quadratic --ff=10.0 --fwhm=0.0 \ +--acqp=epi_acqp.txt --bvals=bvals.scheme --bvecs=bvecs.scheme \ +--imain=epi.nii --index=epi_index.txt --mask=epi_mask.nii \ +--interp=spline --resamp=jac --niter=5 --nvoxhp=1000 \ +--out=.../eddy_corrected --slm=none' >>> eddy.inputs.use_cuda = False >>> eddy.cmdline # doctest: +ELLIPSIS - 'eddy_openmp --ff=10.0 --fwhm=0 --acqp=epi_acqp.txt --bvals=bvals.scheme \ ---bvecs=bvecs.scheme --imain=epi.nii --index=epi_index.txt \ ---mask=epi_mask.nii --niter=5 --nvoxhp=1000 --out=.../eddy_corrected' + 'eddy_openmp --flm=quadratic --ff=10.0 --fwhm=0.0 \ +--acqp=epi_acqp.txt --bvals=bvals.scheme --bvecs=bvecs.scheme \ +--imain=epi.nii --index=epi_index.txt --mask=epi_mask.nii \ +--interp=spline --resamp=jac --niter=5 --nvoxhp=1000 \ +--out=.../eddy_corrected --slm=none' >>> res = eddy.run() # doctest: +SKIP """ From 13dc42e89f8abc3e2ac1893020dcf5d85848e861 Mon Sep 17 00:00:00 2001 From: Michael Joseph Date: Mon, 16 Sep 2019 20:23:18 -0400 Subject: [PATCH 03/19] add test --- nipype/interfaces/fsl/tests/test_auto_Eddy.py | 251 +++++++++++++++--- 1 file changed, 211 insertions(+), 40 deletions(-) diff --git a/nipype/interfaces/fsl/tests/test_auto_Eddy.py b/nipype/interfaces/fsl/tests/test_auto_Eddy.py index cc7eff7a27..8d13b50107 100644 --- a/nipype/interfaces/fsl/tests/test_auto_Eddy.py +++ b/nipype/interfaces/fsl/tests/test_auto_Eddy.py @@ -4,39 +4,204 @@ def test_Eddy_inputs(): input_map = dict( - args=dict(argstr="%s",), - cnr_maps=dict(argstr="--cnr_maps", min_ver="5.0.10",), - dont_peas=dict(argstr="--dont_peas",), - dont_sep_offs_move=dict(argstr="--dont_sep_offs_move",), - environ=dict(nohash=True, usedefault=True,), - fep=dict(argstr="--fep",), - field=dict(argstr="--field=%s",), - field_mat=dict(argstr="--field_mat=%s", extensions=None,), - flm=dict(argstr="--flm=%s",), - fudge_factor=dict(argstr="--ff=%s", usedefault=True,), - fwhm=dict(argstr="--fwhm=%s",), - in_acqp=dict(argstr="--acqp=%s", extensions=None, mandatory=True,), - in_bval=dict(argstr="--bvals=%s", extensions=None, mandatory=True,), - in_bvec=dict(argstr="--bvecs=%s", extensions=None, mandatory=True,), - in_file=dict(argstr="--imain=%s", extensions=None, mandatory=True,), - in_index=dict(argstr="--index=%s", extensions=None, mandatory=True,), - in_mask=dict(argstr="--mask=%s", extensions=None, mandatory=True,), + args=dict(argstr='%s', ), + cnr_maps=dict( + argstr='--cnr_maps', + min_ver='5.0.10', + ), + dont_peas=dict(argstr='--dont_peas', ), + dont_sep_offs_move=dict(argstr='--dont_sep_offs_move', ), + environ=dict( + nohash=True, + usedefault=True, + ), + estimate_move_by_susceptibility=dict( + argstr='--estimate_move_by_susceptibility', + min_ver='6.0.1', + ), + fep=dict(argstr='--fep', ), + field=dict( + argstr='--field=%s', + extensions=None, + ), + field_mat=dict( + argstr='--field_mat=%s', + extensions=None, + ), + flm=dict( + argstr='--flm=%s', + usedefault=True, + ), + fudge_factor=dict( + argstr='--ff=%s', + usedefault=True, + ), + fwhm=dict( + argstr='--fwhm=%s', + usedefault=True, + ), + in_acqp=dict( + argstr='--acqp=%s', + extensions=None, + mandatory=True, + ), + in_bval=dict( + argstr='--bvals=%s', + extensions=None, + mandatory=True, + ), + in_bvec=dict( + argstr='--bvecs=%s', + extensions=None, + mandatory=True, + ), + in_file=dict( + argstr='--imain=%s', + extensions=None, + mandatory=True, + ), + in_index=dict( + argstr='--index=%s', + extensions=None, + mandatory=True, + ), + in_mask=dict( + argstr='--mask=%s', + extensions=None, + mandatory=True, + ), in_topup_fieldcoef=dict( - argstr="--topup=%s", extensions=None, requires=["in_topup_movpar"], - ), - in_topup_movpar=dict(extensions=None, requires=["in_topup_fieldcoef"],), - interp=dict(argstr="--interp=%s",), - is_shelled=dict(argstr="--data_is_shelled",), - method=dict(argstr="--resamp=%s",), - niter=dict(argstr="--niter=%s", usedefault=True,), - num_threads=dict(nohash=True, usedefault=True,), - nvoxhp=dict(argstr="--nvoxhp=%s", usedefault=True,), - out_base=dict(argstr="--out=%s", usedefault=True,), + argstr='--topup=%s', + extensions=None, + requires=['in_topup_movpar'], + ), + in_topup_movpar=dict( + extensions=None, + requires=['in_topup_fieldcoef'], + ), + initrand=dict( + argstr='--initrand', + min_ver='5.0.10', + ), + interp=dict( + argstr='--interp=%s', + usedefault=True, + ), + is_shelled=dict(argstr='--data_is_shelled', ), + json=dict( + argstr='--json=%s', + min_ver='6.0.1', + requires=['mporder'], + xor=['slspec'], + ), + mb=dict( + argstr='--mb=%s', + min_ver='5.0.10', + ), + mb_offs=dict( + argstr='--mb_offs=%s', + min_ver='5.0.10', + requires=['mb'], + ), + mbs_ksp=dict( + argstr='--mbs_ksp=%smm', + min_ver='6.0.1', + requires=['estimate_move_by_susceptibility'], + ), + mbs_lambda=dict( + argstr='--mbs_lambda=%s', + min_ver='6.0.1', + requires=['estimate_move_by_susceptibility'], + ), + mbs_niter=dict( + argstr='--mbs_niter=%s', + min_ver='6.0.1', + requires=['estimate_move_by_susceptibility'], + ), + method=dict( + argstr='--resamp=%s', + usedefault=True, + ), + mporder=dict( + argstr='--mporder=%s', + min_ver='5.0.11', + ), + niter=dict( + argstr='--niter=%s', + usedefault=True, + ), + num_threads=dict( + nohash=True, + usedefault=True, + ), + nvoxhp=dict( + argstr='--nvoxhp=%s', + usedefault=True, + ), + out_base=dict( + argstr='--out=%s', + usedefault=True, + ), + outlier_nstd=dict( + argstr='--ol_nstd', + min_ver='5.0.10', + requires=['repol'], + ), + outlier_nvox=dict( + argstr='--ol_nvox', + min_ver='5.0.10', + requires=['repol'], + ), + outlier_pos=dict( + argstr='--ol_pos', + min_ver='5.0.10', + requires=['repol'], + ), + outlier_sqr=dict( + argstr='--ol_sqr', + min_ver='5.0.10', + requires=['repol'], + ), + outlier_type=dict( + argstr='--ol_type', + min_ver='5.0.10', + requires=['repol'], + ), output_type=dict(), - repol=dict(argstr="--repol",), - residuals=dict(argstr="--residuals", min_ver="5.0.10",), - session=dict(argstr="--session=%s", extensions=None,), - slm=dict(argstr="--slm=%s",), + repol=dict(argstr='--repol', ), + residuals=dict( + argstr='--residuals', + min_ver='5.0.10', + ), + s2v_interp=dict( + argstr='--s2v_interp=%s', + min_ver='5.0.11', + requires=['mporder'], + ), + s2v_lambda=dict( + agstr='--s2v_lambda', + min_ver='5.0.11', + requires=['mporder'], + ), + s2v_niter=dict( + argstr='--s2v_niter=%s', + min_ver='5.0.11', + requires=['mporder'], + ), + session=dict( + argstr='--session=%s', + extensions=None, + ), + slm=dict( + argstr='--slm=%s', + usedefault=True, + ), + slspec=dict( + argstr='--slspec=%s', + min_ver='5.0.11', + requires=['mporder'], + xor=['json'], + ), use_cuda=dict(), ) inputs = Eddy.input_spec() @@ -48,15 +213,21 @@ def test_Eddy_inputs(): def test_Eddy_outputs(): output_map = dict( - out_cnr_maps=dict(extensions=None,), - out_corrected=dict(extensions=None,), - out_movement_rms=dict(extensions=None,), - out_outlier_report=dict(extensions=None,), - out_parameter=dict(extensions=None,), - out_residuals=dict(extensions=None,), - out_restricted_movement_rms=dict(extensions=None,), - out_rotated_bvecs=dict(extensions=None,), - out_shell_alignment_parameters=dict(extensions=None,), + out_cnr_maps=dict(extensions=None, ), + out_corrected=dict(extensions=None, ), + out_movement_over_time=dict(extensions=None, ), + out_movement_rms=dict(extensions=None, ), + out_outlier_free=dict(extensions=None, ), + out_outlier_map=dict(extensions=None, ), + out_outlier_n_sqr_stdev_map=dict(extensions=None, ), + out_outlier_n_stdev_map=dict(extensions=None, ), + out_outlier_report=dict(extensions=None, ), + out_parameter=dict(extensions=None, ), + out_residuals=dict(extensions=None, ), + out_restricted_movement_rms=dict(extensions=None, ), + out_rotated_bvecs=dict(extensions=None, ), + out_shell_alignment_parameters=dict(extensions=None, ), + out_shell_pe_translation_parameters=dict(extensions=None, ), ) outputs = Eddy.output_spec() From 38e73bcf8b49ff77531ec4f3470ca80aaab47158 Mon Sep 17 00:00:00 2001 From: mjoseph Date: Tue, 17 Sep 2019 12:17:06 -0400 Subject: [PATCH 04/19] add doctest for running eddy with s2v motion correction --- nipype/interfaces/fsl/epi.py | 24 +++++++++++++++++-- nipype/interfaces/fsl/tests/test_auto_Eddy.py | 1 + nipype/testing/data/epi_slspec.txt | 0 3 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 nipype/testing/data/epi_slspec.txt diff --git a/nipype/interfaces/fsl/epi.py b/nipype/interfaces/fsl/epi.py index 0fa78a8ee7..3e4b3e2a57 100644 --- a/nipype/interfaces/fsl/epi.py +++ b/nipype/interfaces/fsl/epi.py @@ -727,6 +727,7 @@ class EddyInputSpec(FSLCommandInputSpec): mporder = traits.Int( argstr='--mporder=%s', desc='Order of slice-to-vol movement model', + requires=['use_cuda'], min_ver='5.0.11') s2v_niter = traits.Int( argstr='--s2v_niter=%s', @@ -885,6 +886,8 @@ class Eddy(FSLCommand): -------- >>> from nipype.interfaces.fsl import Eddy + + Running eddy on an Nvidia GPU using cuda: >>> eddy = Eddy() >>> eddy.inputs.in_file = 'epi.nii' >>> eddy.inputs.in_mask = 'epi_mask.nii' @@ -899,14 +902,31 @@ class Eddy(FSLCommand): --imain=epi.nii --index=epi_index.txt --mask=epi_mask.nii \ --interp=spline --resamp=jac --niter=5 --nvoxhp=1000 \ --out=.../eddy_corrected --slm=none' + + Running eddy on a CPU using OpenMP: >>> eddy.inputs.use_cuda = False - >>> eddy.cmdline # doctest: +ELLIPSIS + >>> eddy.cmdline # doctest: +ELLIPSIS 'eddy_openmp --flm=quadratic --ff=10.0 --fwhm=0.0 \ --acqp=epi_acqp.txt --bvals=bvals.scheme --bvecs=bvecs.scheme \ --imain=epi.nii --index=epi_index.txt --mask=epi_mask.nii \ --interp=spline --resamp=jac --niter=5 --nvoxhp=1000 \ --out=.../eddy_corrected --slm=none' - >>> res = eddy.run() # doctest: +SKIP + + Running eddy with slice-to-volume motion correction: + >>> eddy.inputs.use_cuda = True + >>> eddy.inputs.mporder = 6 + >>> eddy.inputs.s2v_niter = 5 + >>> eddy.inputs.s2v_lambda = 1 + >>> eddy.inputs.s2v_interp = 'trilinear' + >>> eddy.inputs.slspec = 'epi_slspec.txt' + >>> eddy.cmdline # doctest: +ELLIPSIS + 'eddy_cuda --flm=quadratic --ff=10.0 --fwhm=0.0 \ +--acqp=epi_acqp.txt --bvals=bvals.scheme --bvecs=bvecs.scheme \ +--imain=epi.nii --index=epi_index.txt --mask=epi_mask.nii \ +--interp=spline --resamp=jac --mporder=6 --niter=5 --nvoxhp=1000 \ +--out=.../eddy_corrected --s2v_interp=trilinear --s2v_niter=5 \ +--slm=none --slspec=epi_slspec.txt' + >>> res = eddy.run() # doctest: +SKIP """ diff --git a/nipype/interfaces/fsl/tests/test_auto_Eddy.py b/nipype/interfaces/fsl/tests/test_auto_Eddy.py index 8d13b50107..78b4b39944 100644 --- a/nipype/interfaces/fsl/tests/test_auto_Eddy.py +++ b/nipype/interfaces/fsl/tests/test_auto_Eddy.py @@ -125,6 +125,7 @@ def test_Eddy_inputs(): mporder=dict( argstr='--mporder=%s', min_ver='5.0.11', + requires=['use_cuda'], ), niter=dict( argstr='--niter=%s', diff --git a/nipype/testing/data/epi_slspec.txt b/nipype/testing/data/epi_slspec.txt new file mode 100644 index 0000000000..e69de29bb2 From 9098697cea1fcf32eb11bf4fd9dab64d30b91c8e Mon Sep 17 00:00:00 2001 From: Michael Joseph Date: Wed, 18 Sep 2019 05:52:37 -0400 Subject: [PATCH 05/19] Apply suggestions from code review Co-Authored-By: Chris Markiewicz --- nipype/interfaces/fsl/epi.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/nipype/interfaces/fsl/epi.py b/nipype/interfaces/fsl/epi.py index 3e4b3e2a57..dc07597084 100644 --- a/nipype/interfaces/fsl/epi.py +++ b/nipype/interfaces/fsl/epi.py @@ -599,8 +599,9 @@ class EddyInputSpec(FSLCommandInputSpec): in_topup_movpar = File( exists=True, requires=['in_topup_fieldcoef'], - desc='Topup results file containing the movement parameters') + desc='Topup results file containing the movement parameters (movpar.txt)') field = File( + exists=True, argstr='--field=%s', desc=('Non-topup derived fieldmap scaled in Hz')) field_mat = File( @@ -710,15 +711,15 @@ class EddyInputSpec(FSLCommandInputSpec): desc='Consider outliers among sums-of-squared differences if set', requires=['repol'], min_ver='5.0.10') - mb = traits.Int( + multiband_factor = traits.Int( argstr='--mb=%s', desc='Multi-band factor', min_ver='5.0.10') - mb_offs = traits.Enum( + multiband_offset = traits.Enum( 0, 1, -1, - argstr='--mb_offs=%s', + argstr='--mb_offs=%d', desc=('Multi-band offset (-1 if bottom slice removed, 1 if ' 'top slice removed'), requires=['mb'], @@ -729,7 +730,7 @@ class EddyInputSpec(FSLCommandInputSpec): desc='Order of slice-to-vol movement model', requires=['use_cuda'], min_ver='5.0.11') - s2v_niter = traits.Int( + slice2vol_iterations = traits.Int( argstr='--s2v_niter=%s', desc='Number of iterations for slice-to-vol', requires=['mporder'], From a15f1d791e4ebfe7d8a6ce2f676c8dba8454fd32 Mon Sep 17 00:00:00 2001 From: mjoseph Date: Wed, 18 Sep 2019 14:20:01 -0400 Subject: [PATCH 06/19] update variable names --- nipype/interfaces/fsl/epi.py | 36 ++++++------- nipype/interfaces/fsl/tests/test_auto_Eddy.py | 53 +++++++++---------- 2 files changed, 42 insertions(+), 47 deletions(-) diff --git a/nipype/interfaces/fsl/epi.py b/nipype/interfaces/fsl/epi.py index dc07597084..9fbae48678 100644 --- a/nipype/interfaces/fsl/epi.py +++ b/nipype/interfaces/fsl/epi.py @@ -664,8 +664,6 @@ class EddyInputSpec(FSLCommandInputSpec): desc="Do NOT perform a post-eddy alignment of " "shells") fwhm = traits.Float( - default_value=0.0, - usedefault=True, desc=('FWHM for conditioning filter when estimating ' 'the parameters'), argstr='--fwhm=%s') @@ -722,7 +720,7 @@ class EddyInputSpec(FSLCommandInputSpec): argstr='--mb_offs=%d', desc=('Multi-band offset (-1 if bottom slice removed, 1 if ' 'top slice removed'), - requires=['mb'], + requires=['multiband_factor'], min_ver='5.0.10') mporder = traits.Int( @@ -730,24 +728,24 @@ class EddyInputSpec(FSLCommandInputSpec): desc='Order of slice-to-vol movement model', requires=['use_cuda'], min_ver='5.0.11') - slice2vol_iterations = traits.Int( - argstr='--s2v_niter=%s', + slice2vol_niter = traits.Int( + argstr='--s2v_niter=%d', desc='Number of iterations for slice-to-vol', requires=['mporder'], min_ver='5.0.11') - s2v_lambda = traits.Int( - agstr='--s2v_lambda', + slice2vol_lambda = traits.Int( + argstr='--s2v_lambda=%d', desc='Regularisation weight for slice-to-vol movement (reasonable range 1-10)', requires=['mporder'], min_ver='5.0.11') - s2v_interp = traits.Enum( + slice2vol_interp = traits.Enum( 'trilinear', 'spline', argstr='--s2v_interp=%s', desc='Slice-to-vol interpolation model for estimation step', requires=['mporder'], min_ver='5.0.11') - slspec = traits.File( + slice_order = traits.File( exists=True, argstr='--slspec=%s', desc='Name of text file completely specifying slice/group acquisition', @@ -759,7 +757,7 @@ class EddyInputSpec(FSLCommandInputSpec): argstr='--json=%s', desc='Name of .json text file with information about slice timing', requires=['mporder'], - xor=['slspec'], + xor=['slice_order'], min_ver='6.0.1') estimate_move_by_susceptibility = traits.Bool( @@ -898,7 +896,7 @@ class Eddy(FSLCommand): >>> eddy.inputs.in_bval = 'bvals.scheme' >>> eddy.inputs.use_cuda = True >>> eddy.cmdline # doctest: +ELLIPSIS - 'eddy_cuda --flm=quadratic --ff=10.0 --fwhm=0.0 \ + 'eddy_cuda --flm=quadratic --ff=10.0 \ --acqp=epi_acqp.txt --bvals=bvals.scheme --bvecs=bvecs.scheme \ --imain=epi.nii --index=epi_index.txt --mask=epi_mask.nii \ --interp=spline --resamp=jac --niter=5 --nvoxhp=1000 \ @@ -907,7 +905,7 @@ class Eddy(FSLCommand): Running eddy on a CPU using OpenMP: >>> eddy.inputs.use_cuda = False >>> eddy.cmdline # doctest: +ELLIPSIS - 'eddy_openmp --flm=quadratic --ff=10.0 --fwhm=0.0 \ + 'eddy_openmp --flm=quadratic --ff=10.0 \ --acqp=epi_acqp.txt --bvals=bvals.scheme --bvecs=bvecs.scheme \ --imain=epi.nii --index=epi_index.txt --mask=epi_mask.nii \ --interp=spline --resamp=jac --niter=5 --nvoxhp=1000 \ @@ -916,17 +914,17 @@ class Eddy(FSLCommand): Running eddy with slice-to-volume motion correction: >>> eddy.inputs.use_cuda = True >>> eddy.inputs.mporder = 6 - >>> eddy.inputs.s2v_niter = 5 - >>> eddy.inputs.s2v_lambda = 1 - >>> eddy.inputs.s2v_interp = 'trilinear' - >>> eddy.inputs.slspec = 'epi_slspec.txt' + >>> eddy.inputs.slice2vol_niter = 5 + >>> eddy.inputs.slice2vol_lambda = 1 + >>> eddy.inputs.slice2vol_interp = 'trilinear' + >>> eddy.inputs.slice_order = 'epi_slspec.txt' >>> eddy.cmdline # doctest: +ELLIPSIS - 'eddy_cuda --flm=quadratic --ff=10.0 --fwhm=0.0 \ + 'eddy_cuda --flm=quadratic --ff=10.0 \ --acqp=epi_acqp.txt --bvals=bvals.scheme --bvecs=bvecs.scheme \ --imain=epi.nii --index=epi_index.txt --mask=epi_mask.nii \ --interp=spline --resamp=jac --mporder=6 --niter=5 --nvoxhp=1000 \ ---out=.../eddy_corrected --s2v_interp=trilinear --s2v_niter=5 \ ---slm=none --slspec=epi_slspec.txt' +--out=.../eddy_corrected --s2v_interp=trilinear --s2v_lambda=1 \ +--s2v_niter=5 --slspec=epi_slspec.txt --slm=none' >>> res = eddy.run() # doctest: +SKIP """ diff --git a/nipype/interfaces/fsl/tests/test_auto_Eddy.py b/nipype/interfaces/fsl/tests/test_auto_Eddy.py index 78b4b39944..b76f482fb1 100644 --- a/nipype/interfaces/fsl/tests/test_auto_Eddy.py +++ b/nipype/interfaces/fsl/tests/test_auto_Eddy.py @@ -36,10 +36,7 @@ def test_Eddy_inputs(): argstr='--ff=%s', usedefault=True, ), - fwhm=dict( - argstr='--fwhm=%s', - usedefault=True, - ), + fwhm=dict(argstr='--fwhm=%s', ), in_acqp=dict( argstr='--acqp=%s', extensions=None, @@ -92,16 +89,7 @@ def test_Eddy_inputs(): argstr='--json=%s', min_ver='6.0.1', requires=['mporder'], - xor=['slspec'], - ), - mb=dict( - argstr='--mb=%s', - min_ver='5.0.10', - ), - mb_offs=dict( - argstr='--mb_offs=%s', - min_ver='5.0.10', - requires=['mb'], + xor=['slice_order'], ), mbs_ksp=dict( argstr='--mbs_ksp=%smm', @@ -127,6 +115,15 @@ def test_Eddy_inputs(): min_ver='5.0.11', requires=['use_cuda'], ), + multiband_factor=dict( + argstr='--mb=%s', + min_ver='5.0.10', + ), + multiband_offset=dict( + argstr='--mb_offs=%d', + min_ver='5.0.10', + requires=['multiband_factor'], + ), niter=dict( argstr='--niter=%s', usedefault=True, @@ -174,35 +171,35 @@ def test_Eddy_inputs(): argstr='--residuals', min_ver='5.0.10', ), - s2v_interp=dict( + session=dict( + argstr='--session=%s', + extensions=None, + ), + slice2vol_interp=dict( argstr='--s2v_interp=%s', min_ver='5.0.11', requires=['mporder'], ), - s2v_lambda=dict( - agstr='--s2v_lambda', + slice2vol_lambda=dict( + argstr='--s2v_lambda=%d', min_ver='5.0.11', requires=['mporder'], ), - s2v_niter=dict( - argstr='--s2v_niter=%s', + slice2vol_niter=dict( + argstr='--s2v_niter=%d', min_ver='5.0.11', requires=['mporder'], ), - session=dict( - argstr='--session=%s', - extensions=None, - ), - slm=dict( - argstr='--slm=%s', - usedefault=True, - ), - slspec=dict( + slice_order=dict( argstr='--slspec=%s', min_ver='5.0.11', requires=['mporder'], xor=['json'], ), + slm=dict( + argstr='--slm=%s', + usedefault=True, + ), use_cuda=dict(), ) inputs = Eddy.input_spec() From f4b2ae61c44631725d7f820f8f3861894e0c1e8f Mon Sep 17 00:00:00 2001 From: mjoseph Date: Wed, 18 Sep 2019 14:34:11 -0400 Subject: [PATCH 07/19] modified boolean traits to type enumerator --- nipype/interfaces/fsl/epi.py | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/nipype/interfaces/fsl/epi.py b/nipype/interfaces/fsl/epi.py index 9fbae48678..ac61efd413 100644 --- a/nipype/interfaces/fsl/epi.py +++ b/nipype/interfaces/fsl/epi.py @@ -677,8 +677,8 @@ class EddyInputSpec(FSLCommandInputSpec): desc=('Final resampling method (jacobian/least ' 'squares)')) - repol = traits.Bool( - False, argstr='--repol', desc='Detect and replace outlier slices') + repol = traits.Enum( + True, argstr='--repol', desc='Detect and replace outlier slices') outlier_nstd = traits.Int( argstr='--ol_nstd', desc='Number of std off to qualify as outlier', @@ -760,8 +760,8 @@ class EddyInputSpec(FSLCommandInputSpec): xor=['slice_order'], min_ver='6.0.1') - estimate_move_by_susceptibility = traits.Bool( - False, + estimate_move_by_susceptibility = traits.Enum( + True, argstr='--estimate_move_by_susceptibility', desc='Estimate how susceptibility field changes with subject movement', min_ver='6.0.1') @@ -793,7 +793,7 @@ class EddyInputSpec(FSLCommandInputSpec): 'date are acquired on a set of b-value ' 'shells')) - use_cuda = traits.Bool(False, desc='Run eddy using cuda gpu') + use_cuda = traits.Enum(True, desc='Run eddy using cuda gpu') cnr_maps = traits.Bool( False, desc="Output CNR-Maps", argstr="--cnr_maps", min_ver="5.0.10" ) @@ -886,7 +886,7 @@ class Eddy(FSLCommand): >>> from nipype.interfaces.fsl import Eddy - Running eddy on an Nvidia GPU using cuda: + Running eddy on a CPU using OpenMP: >>> eddy = Eddy() >>> eddy.inputs.in_file = 'epi.nii' >>> eddy.inputs.in_mask = 'epi_mask.nii' @@ -894,25 +894,23 @@ class Eddy(FSLCommand): >>> eddy.inputs.in_acqp = 'epi_acqp.txt' >>> eddy.inputs.in_bvec = 'bvecs.scheme' >>> eddy.inputs.in_bval = 'bvals.scheme' - >>> eddy.inputs.use_cuda = True - >>> eddy.cmdline # doctest: +ELLIPSIS - 'eddy_cuda --flm=quadratic --ff=10.0 \ + >>> eddy.cmdline # doctest: +ELLIPSIS + 'eddy_openmp --flm=quadratic --ff=10.0 \ --acqp=epi_acqp.txt --bvals=bvals.scheme --bvecs=bvecs.scheme \ --imain=epi.nii --index=epi_index.txt --mask=epi_mask.nii \ --interp=spline --resamp=jac --niter=5 --nvoxhp=1000 \ --out=.../eddy_corrected --slm=none' - Running eddy on a CPU using OpenMP: - >>> eddy.inputs.use_cuda = False - >>> eddy.cmdline # doctest: +ELLIPSIS - 'eddy_openmp --flm=quadratic --ff=10.0 \ + Running eddy on an Nvidia GPU using cuda: + >>> eddy.inputs.use_cuda = True + >>> eddy.cmdline # doctest: +ELLIPSIS + 'eddy_cuda --flm=quadratic --ff=10.0 \ --acqp=epi_acqp.txt --bvals=bvals.scheme --bvecs=bvecs.scheme \ --imain=epi.nii --index=epi_index.txt --mask=epi_mask.nii \ --interp=spline --resamp=jac --niter=5 --nvoxhp=1000 \ --out=.../eddy_corrected --slm=none' Running eddy with slice-to-volume motion correction: - >>> eddy.inputs.use_cuda = True >>> eddy.inputs.mporder = 6 >>> eddy.inputs.slice2vol_niter = 5 >>> eddy.inputs.slice2vol_lambda = 1 From 75205449908a19d45c99bd2dabb915c3596ecb21 Mon Sep 17 00:00:00 2001 From: mjoseph Date: Fri, 25 Oct 2019 15:06:21 -0400 Subject: [PATCH 08/19] revert enum to bool --- nipype/interfaces/fsl/epi.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/nipype/interfaces/fsl/epi.py b/nipype/interfaces/fsl/epi.py index ac61efd413..84a36ccddc 100644 --- a/nipype/interfaces/fsl/epi.py +++ b/nipype/interfaces/fsl/epi.py @@ -677,8 +677,8 @@ class EddyInputSpec(FSLCommandInputSpec): desc=('Final resampling method (jacobian/least ' 'squares)')) - repol = traits.Enum( - True, argstr='--repol', desc='Detect and replace outlier slices') + repol = traits.Bool( + False, argstr='--repol', desc='Detect and replace outlier slices') outlier_nstd = traits.Int( argstr='--ol_nstd', desc='Number of std off to qualify as outlier', @@ -760,8 +760,8 @@ class EddyInputSpec(FSLCommandInputSpec): xor=['slice_order'], min_ver='6.0.1') - estimate_move_by_susceptibility = traits.Enum( - True, + estimate_move_by_susceptibility = traits.Bool( + False, argstr='--estimate_move_by_susceptibility', desc='Estimate how susceptibility field changes with subject movement', min_ver='6.0.1') @@ -793,7 +793,7 @@ class EddyInputSpec(FSLCommandInputSpec): 'date are acquired on a set of b-value ' 'shells')) - use_cuda = traits.Enum(True, desc='Run eddy using cuda gpu') + use_cuda = traits.Bool(False, desc='Run eddy using cuda gpu') cnr_maps = traits.Bool( False, desc="Output CNR-Maps", argstr="--cnr_maps", min_ver="5.0.10" ) From 84d3ded1f2c2943ba42f840b28572483fefb9276 Mon Sep 17 00:00:00 2001 From: Michael Joseph Date: Mon, 18 Nov 2019 11:49:39 -0500 Subject: [PATCH 09/19] rebase --- nipype/interfaces/fsl/epi.py | 462 ++++++++++-------- nipype/interfaces/fsl/tests/test_auto_Eddy.py | 264 +++------- 2 files changed, 322 insertions(+), 404 deletions(-) diff --git a/nipype/interfaces/fsl/epi.py b/nipype/interfaces/fsl/epi.py index 84a36ccddc..d5e6c044d6 100644 --- a/nipype/interfaces/fsl/epi.py +++ b/nipype/interfaces/fsl/epi.py @@ -552,8 +552,9 @@ class EddyInputSpec(FSLCommandInputSpec): in_file = File( exists=True, mandatory=True, - argstr='--imain=%s', - desc='File containing all the images to estimate distortions for') + argstr="--imain=%s", + desc="File containing all the images to estimate distortions for", + ) in_mask = File( exists=True, mandatory=True, argstr="--mask=%s", desc="Mask to indicate brain" ) @@ -561,10 +562,8 @@ class EddyInputSpec(FSLCommandInputSpec): exists=True, mandatory=True, argstr="--index=%s", - desc=( - "File containing indices for all volumes in --imain " - "into --acqp and --topup" - ), + desc="File containing indices for all volumes in --imain " + "into --acqp and --topup", ) in_acqp = File( exists=True, @@ -575,225 +574,250 @@ class EddyInputSpec(FSLCommandInputSpec): in_bvec = File( exists=True, mandatory=True, - argstr='--bvecs=%s', - desc='File containing the b-vectors for all volumes in --imain') + argstr="--bvecs=%s", + desc="File containing the b-vectors for all volumes in --imain", + ) in_bval = File( exists=True, mandatory=True, - argstr='--bvals=%s', - desc='File containing the b-values for all volumes in --imain') + argstr="--bvals=%s", + desc="File containing the b-values for all volumes in --imain", + ) out_base = traits.Str( - default_value='eddy_corrected', + default_value="eddy_corrected", usedefault=True, - argstr='--out=%s', - desc='Basename for output image') + argstr="--out=%s", + desc="Basename for output image", + ) session = File( exists=True, - argstr='--session=%s', - desc='File containing session indices for all volumes in --imain') + argstr="--session=%s", + desc="File containing session indices for all volumes in --imain", + ) in_topup_fieldcoef = File( exists=True, - argstr='--topup=%s', - requires=['in_topup_movpar'], - desc='Topup results file containing the field coefficients') + argstr="--topup=%s", + requires=["in_topup_movpar"], + desc="Topup results file containing the field coefficients", + ) in_topup_movpar = File( exists=True, - requires=['in_topup_fieldcoef'], - desc='Topup results file containing the movement parameters (movpar.txt)') + requires=["in_topup_fieldcoef"], + desc="Topup results file containing the movement parameters (movpar.txt)", + ) field = File( exists=True, - argstr='--field=%s', - desc=('Non-topup derived fieldmap scaled in Hz')) + argstr="--field=%s", + desc="Non-topup derived fieldmap scaled in Hz", + ) field_mat = File( exists=True, - argstr='--field_mat=%s', - desc=('Matrix specifying the relative positions of ' - 'the fieldmap, --field, and the first volume ' - 'of the input file, --imain')) + argstr="--field_mat=%s", + desc="Matrix specifying the relative positions of " + "the fieldmap, --field, and the first volume " + "of the input file, --imain", + ) flm = traits.Enum( - 'quadratic', - 'linear', - 'cubic', + "quadratic", + "linear", + "cubic", usedefault=True, - argstr='--flm=%s', - desc='First level EC model') + argstr="--flm=%s", + desc="First level EC model", + ) slm = traits.Enum( - 'none', - 'linear', - 'quadratic', + "none", + "linear", + "quadratic", usedefault=True, - argstr='--slm=%s', - desc='Second level EC model') + argstr="--slm=%s", + desc="Second level EC model", + ) fep = traits.Bool( - False, - argstr='--fep', - desc='Fill empty planes in x- or y-directions') + False, argstr="--fep", desc="Fill empty planes in x- or y-directions" + ) initrand = traits.Bool( False, - argstr='--initrand', - desc='Resets rand for when selecting voxels', - min_ver='5.0.10') + argstr="--initrand", + desc="Resets rand for when selecting voxels", + min_ver="5.0.10", + ) interp = traits.Enum( - 'spline', - 'trilinear', + "spline", + "trilinear", usedefault=True, - argstr='--interp=%s', - desc='Interpolation model for estimation step') + argstr="--interp=%s", + desc="Interpolation model for estimation step", + ) nvoxhp = traits.Int( default_value=1000, usedefault=True, - argstr='--nvoxhp=%s', - desc=('# of voxels used to estimate the ' - 'hyperparameters')) + argstr="--nvoxhp=%s", + desc="# of voxels used to estimate the hyperparameters", + ) fudge_factor = traits.Float( default_value=10.0, usedefault=True, - argstr='--ff=%s', - desc=('Fudge factor for hyperparameter ' - 'error variance')) + argstr="--ff=%s", + desc="Fudge factor for hyperparameter error variance", + ) dont_sep_offs_move = traits.Bool( False, - argstr='--dont_sep_offs_move', - desc=('Do NOT attempt to separate ' - 'field offset from subject ' - 'movement')) + argstr="--dont_sep_offs_move", + desc="Do NOT attempt to separate field offset from subject movement", + ) dont_peas = traits.Bool( False, - argstr='--dont_peas', - desc="Do NOT perform a post-eddy alignment of " - "shells") + argstr="--dont_peas", + desc="Do NOT perform a post-eddy alignment of shells", + ) fwhm = traits.Float( - desc=('FWHM for conditioning filter when estimating ' - 'the parameters'), - argstr='--fwhm=%s') - niter = traits.Int(5, usedefault=True, - argstr='--niter=%s', desc='Number of iterations') + desc="FWHM for conditioning filter when estimating the parameters", + argstr="--fwhm=%s", + ) + niter = traits.Int( + 5, usedefault=True, argstr="--niter=%s", desc="Number of iterations" + ) method = traits.Enum( - 'jac', - 'lsr', + "jac", + "lsr", usedefault=True, - argstr='--resamp=%s', - desc=('Final resampling method (jacobian/least ' - 'squares)')) + argstr="--resamp=%s", + desc="Final resampling method (jacobian/least squares)", + ) repol = traits.Bool( - False, argstr='--repol', desc='Detect and replace outlier slices') + False, argstr="--repol", desc="Detect and replace outlier slices" + ) outlier_nstd = traits.Int( - argstr='--ol_nstd', - desc='Number of std off to qualify as outlier', - requires=['repol'], - min_ver='5.0.10') + argstr="--ol_nstd", + desc="Number of std off to qualify as outlier", + requires=["repol"], + min_ver="5.0.10", + ) outlier_nvox = traits.Int( - argstr='--ol_nvox', - desc='Min # of voxels in a slice for inclusion in outlier detection', - requires=['repol'], - min_ver='5.0.10') + argstr="--ol_nvox", + desc="Min # of voxels in a slice for inclusion in outlier detection", + requires=["repol"], + min_ver="5.0.10", + ) outlier_type = traits.Enum( - 'sw', - 'gw', - 'both', - argstr='--ol_type', - desc='Type of outliers, slicewise (sw), groupwise (gw) or both (both)', - requires=['repol'], - min_ver='5.0.10') + "sw", + "gw", + "both", + argstr="--ol_type", + desc="Type of outliers, slicewise (sw), groupwise (gw) or both (both)", + requires=["repol"], + min_ver="5.0.10", + ) outlier_pos = traits.Bool( False, - argstr='--ol_pos', - desc='Consider both positive and negative outliers if set', - requires=['repol'], - min_ver='5.0.10') + argstr="--ol_pos", + desc="Consider both positive and negative outliers if set", + requires=["repol"], + min_ver="5.0.10", + ) outlier_sqr = traits.Bool( False, - argstr='--ol_sqr', - desc='Consider outliers among sums-of-squared differences if set', - requires=['repol'], - min_ver='5.0.10') + argstr="--ol_sqr", + desc="Consider outliers among sums-of-squared differences if set", + requires=["repol"], + min_ver="5.0.10", + ) multiband_factor = traits.Int( - argstr='--mb=%s', - desc='Multi-band factor', - min_ver='5.0.10') + argstr="--mb=%s", desc="Multi-band factor", min_ver="5.0.10" + ) multiband_offset = traits.Enum( 0, 1, -1, - argstr='--mb_offs=%d', - desc=('Multi-band offset (-1 if bottom slice removed, 1 if ' - 'top slice removed'), - requires=['multiband_factor'], - min_ver='5.0.10') + argstr="--mb_offs=%d", + desc="Multi-band offset (-1 if bottom slice removed, 1 if top slice removed", + requires=["multiband_factor"], + min_ver="5.0.10", + ) mporder = traits.Int( - argstr='--mporder=%s', - desc='Order of slice-to-vol movement model', - requires=['use_cuda'], - min_ver='5.0.11') + argstr="--mporder=%s", + desc="Order of slice-to-vol movement model", + requires=["use_cuda"], + min_ver="5.0.11", + ) slice2vol_niter = traits.Int( - argstr='--s2v_niter=%d', - desc='Number of iterations for slice-to-vol', - requires=['mporder'], - min_ver='5.0.11') + argstr="--s2v_niter=%d", + desc="Number of iterations for slice-to-vol", + requires=["mporder"], + min_ver="5.0.11", + ) slice2vol_lambda = traits.Int( - argstr='--s2v_lambda=%d', - desc='Regularisation weight for slice-to-vol movement (reasonable range 1-10)', - requires=['mporder'], - min_ver='5.0.11') + argstr="--s2v_lambda=%d", + desc="Regularisation weight for slice-to-vol movement (reasonable range 1-10)", + requires=["mporder"], + min_ver="5.0.11", + ) slice2vol_interp = traits.Enum( - 'trilinear', - 'spline', - argstr='--s2v_interp=%s', - desc='Slice-to-vol interpolation model for estimation step', - requires=['mporder'], - min_ver='5.0.11') + "trilinear", + "spline", + argstr="--s2v_interp=%s", + desc="Slice-to-vol interpolation model for estimation step", + requires=["mporder"], + min_ver="5.0.11", + ) slice_order = traits.File( exists=True, - argstr='--slspec=%s', - desc='Name of text file completely specifying slice/group acquisition', - requires=['mporder'], - xor=['json'], - min_ver='5.0.11') + argstr="--slspec=%s", + desc="Name of text file completely specifying slice/group acquisition", + requires=["mporder"], + xor=["json"], + min_ver="5.0.11", + ) json = traits.File( exists=True, - argstr='--json=%s', - desc='Name of .json text file with information about slice timing', - requires=['mporder'], - xor=['slice_order'], - min_ver='6.0.1') + argstr="--json=%s", + desc="Name of .json text file with information about slice timing", + requires=["mporder"], + xor=["slice_order"], + min_ver="6.0.1", + ) estimate_move_by_susceptibility = traits.Bool( False, - argstr='--estimate_move_by_susceptibility', - desc='Estimate how susceptibility field changes with subject movement', - min_ver='6.0.1') + argstr="--estimate_move_by_susceptibility", + desc="Estimate how susceptibility field changes with subject movement", + min_ver="6.0.1", + ) mbs_niter = traits.Int( - argstr='--mbs_niter=%s', - desc='Number of iterations for MBS estimation', - requires=['estimate_move_by_susceptibility'], - min_ver='6.0.1') + argstr="--mbs_niter=%s", + desc="Number of iterations for MBS estimation", + requires=["estimate_move_by_susceptibility"], + min_ver="6.0.1", + ) mbs_lambda = traits.Int( - argstr='--mbs_lambda=%s', - desc='Weighting of regularisation for MBS estimation', - requires=['estimate_move_by_susceptibility'], - min_ver='6.0.1') + argstr="--mbs_lambda=%s", + desc="Weighting of regularisation for MBS estimation", + requires=["estimate_move_by_susceptibility"], + min_ver="6.0.1", + ) mbs_ksp = traits.Int( - argstr='--mbs_ksp=%smm', - desc='Knot-spacing for MBS field estimation', - requires=['estimate_move_by_susceptibility'], - min_ver='6.0.1') + argstr="--mbs_ksp=%smm", + desc="Knot-spacing for MBS field estimation", + requires=["estimate_move_by_susceptibility"], + min_ver="6.0.1", + ) num_threads = traits.Int( - 1, - usedefault=True, - nohash=True, - desc='Number of openmp threads to use') + 1, usedefault=True, nohash=True, desc="Number of openmp threads to use" + ) is_shelled = traits.Bool( False, - argstr='--data_is_shelled', - desc=('Override internal check to ensure that ' - 'date are acquired on a set of b-value ' - 'shells')) + argstr="--data_is_shelled", + desc="Override internal check to ensure that " + "date are acquired on a set of b-value " + "shells", + ) - use_cuda = traits.Bool(False, desc='Run eddy using cuda gpu') + use_cuda = traits.Bool(False, desc="Run eddy using cuda gpu") cnr_maps = traits.Bool( False, desc="Output CNR-Maps", argstr="--cnr_maps", min_ver="5.0.10" ) @@ -808,69 +832,75 @@ class EddyOutputSpec(TraitedSpec): ) out_parameter = File( exists=True, - desc=('Text file with parameters defining the field and' - 'movement for each scan')) + desc="Text file with parameters defining the field and" + "movement for each scan", + ) out_rotated_bvecs = File( exists=True, desc="File containing rotated b-values for all volumes" ) out_movement_rms = File( - exists=True, desc='Summary of the "total movement" in each volume' + exists=True, desc="Summary of the 'total movement' in each volume" ) out_restricted_movement_rms = File( exists=True, - desc=( - 'Summary of the "total movement" in each volume ' - "disregarding translation in the PE direction" - ), + desc="Summary of the 'total movement' in each volume " + "disregarding translation in the PE direction", ) out_shell_alignment_parameters = File( exists=True, - desc=('Text file containing rigid body movement parameters ' - 'between the different shells as estimated by a ' - 'post-hoc mutual information based registration')) + desc="Text file containing rigid body movement parameters " + "between the different shells as estimated by a " + "post-hoc mutual information based registration", + ) out_shell_pe_translation_parameters = File( exists=True, - desc=('Text file containing translation along the PE-direction ' - 'between the different shells as estimated by a ' - 'post-hoc mutual information based registration')) + desc="Text file containing translation along the PE-direction " + "between the different shells as estimated by a " + "post-hoc mutual information based registration", + ) out_shell_pe_translation_parameters = File( exists=True, - desc=('Text file containing translation along the PE-direction ' - 'between the different shells as estimated by a ' - 'post-hoc mutual information based registration')) + desc="Text file containing translation along the PE-direction " + "between the different shells as estimated by a " + "post-hoc mutual information based registration", + ) out_outlier_map = File( exists=True, - desc=('Matrix where rows represent volumes and columns represent ' - 'slices. "0" indicates that scan-slice is not an outlier ' - 'and "1" indicates that it is')) + desc="Matrix where rows represent volumes and columns represent " + 'slices. "0" indicates that scan-slice is not an outlier ' + 'and "1" indicates that it is', + ) out_outlier_n_stdev_map = File( exists=True, - desc=('Matrix where rows represent volumes and columns represent ' - 'slices. Values indicate number of standard deviations off the ' - 'mean difference between observation and prediction is')) + desc="Matrix where rows represent volumes and columns represent " + "slices. Values indicate number of standard deviations off the " + "mean difference between observation and prediction is", + ) out_outlier_n_sqr_stdev_map = File( exists=True, - desc=('Matrix where rows represent volumes and columns represent ' - 'slices. Values indicate number of standard deivations off the ' - 'square root of the mean squared difference between observation ' - 'and prediction is')) + desc="Matrix where rows represent volumes and columns represent " + "slices. Values indicate number of standard deivations off the " + "square root of the mean squared difference between observation " + "and prediction is", + ) out_outlier_report = File( exists=True, - desc=('Text file with a plain language report on what ' - 'outlier slices eddy has found')) + desc="Text file with a plain language report on what " + "outlier slices eddy has found", + ) out_outlier_free = File( exists=True, - desc=('4D image file not corrected for susceptibility or eddy-' - 'current distortions or subject movement but with outlier ' - 'slices replaced')) + desc="4D image file not corrected for susceptibility or eddy-" + "current distortions or subject movement but with outlier " + "slices replaced", + ) out_movement_over_time = File( exists=True, - desc=('Text file containing translations (mm) and rotations ' - '(radians) for each excitation')) - out_cnr_maps = File( - exists=True, desc='path/name of file with the cnr_maps') - out_residuals = File( - exists=True, desc='path/name of file with the residuals') + desc="Text file containing translations (mm) and rotations " + "(radians) for each excitation", + ) + out_cnr_maps = File(exists=True, desc="path/name of file with the cnr_maps") + out_residuals = File(exists=True, desc="path/name of file with the residuals") class Eddy(FSLCommand): @@ -974,11 +1004,11 @@ def _run_interface(self, runtime): return runtime def _format_arg(self, name, spec, value): - if name == 'in_topup_fieldcoef': - return spec.argstr % value.split('_fieldcoef')[0] - if name == 'field': + if name == "in_topup_fieldcoef": + return spec.argstr % value.split("_fieldcoef")[0] + if name == "field": return spec.argstr % fname_presuffix(value, use_ext=False) - if name == 'out_base': + if name == "out_base": return spec.argstr % os.path.abspath(value) return super(Eddy, self)._format_arg(name, spec, value) @@ -1000,29 +1030,33 @@ def _list_outputs(self): "%s.eddy_restricted_movement_rms" % self.inputs.out_base ) out_shell_alignment_parameters = os.path.abspath( - '%s.eddy_post_eddy_shell_alignment_parameters' % - self.inputs.out_base) + "%s.eddy_post_eddy_shell_alignment_parameters" % self.inputs.out_base + ) out_shell_pe_translation_parameters = os.path.abspath( - '%s.eddy_post_eddy_shell_PE_translation_parameters' % - self.inputs.out_base) - out_outlier_map = os.path.abspath( - '%s.eddy_outlier_map' % self.inputs.out_base) + "%s.eddy_post_eddy_shell_PE_translation_parameters" % self.inputs.out_base + ) + out_outlier_map = os.path.abspath("%s.eddy_outlier_map" % self.inputs.out_base) out_outlier_n_stdev_map = os.path.abspath( - '%s.eddy_outlier_n_stdev_map' % self.inputs.out_base) + "%s.eddy_outlier_n_stdev_map" % self.inputs.out_base + ) out_outlier_n_sqr_stdev_map = os.path.abspath( - '%s.eddy_outlier_n_sqr_stdev_map' % self.inputs.out_base) + "%s.eddy_outlier_n_sqr_stdev_map" % self.inputs.out_base + ) out_outlier_report = os.path.abspath( - '%s.eddy_outlier_report' % self.inputs.out_base) + "%s.eddy_outlier_report" % self.inputs.out_base + ) if isdefined(self.inputs.repol) and self.inputs.repol: out_outlier_free = os.path.abspath( - '%s.eddy_outlier_free_data' % self.inputs.out_base) + "%s.eddy_outlier_free_data" % self.inputs.out_base + ) if os.path.exists(out_outlier_free): - outputs['out_outlier_free'] = out_outlier_free + outputs["out_outlier_free"] = out_outlier_free if isdefined(self.inputs.mporder) and self.inputs.mporder > 0: out_movement_over_time = os.path.abspath( - '%s.eddy_movement_over_time' % self.inputs.out_base) + "%s.eddy_movement_over_time" % self.inputs.out_base + ) if os.path.exists(out_movement_over_time): - outputs['out_movement_over_time'] = out_movement_over_time + outputs["out_movement_over_time"] = out_movement_over_time if isdefined(self.inputs.cnr_maps) and self.inputs.cnr_maps: out_cnr_maps = os.path.abspath( "%s.eddy_cnr_maps.nii.gz" % self.inputs.out_base @@ -1043,17 +1077,17 @@ def _list_outputs(self): if os.path.exists(out_restricted_movement_rms): outputs["out_restricted_movement_rms"] = out_restricted_movement_rms if os.path.exists(out_shell_alignment_parameters): - outputs['out_shell_alignment_parameters'] = \ - out_shell_alignment_parameters + outputs["out_shell_alignment_parameters"] = out_shell_alignment_parameters if os.path.exists(out_shell_pe_translation_parameters): - outputs['out_shell_pe_translation_parameters'] = \ - out_shell_pe_translation_parameters + outputs[ + "out_shell_pe_translation_parameters" + ] = out_shell_pe_translation_parameters if os.path.exists(out_outlier_map): - outputs['out_outlier_map'] = out_outlier_map + outputs["out_outlier_map"] = out_outlier_map if os.path.exists(out_outlier_n_stdev_map): - outputs['out_outlier_n_stdev_map'] = out_outlier_n_stdev_map + outputs["out_outlier_n_stdev_map"] = out_outlier_n_stdev_map if os.path.exists(out_outlier_n_sqr_stdev_map): - outputs['out_outlier_n_sqr_stdev_map'] = out_outlier_n_sqr_stdev_map + outputs["out_outlier_n_sqr_stdev_map"] = out_outlier_n_sqr_stdev_map if os.path.exists(out_outlier_report): outputs["out_outlier_report"] = out_outlier_report diff --git a/nipype/interfaces/fsl/tests/test_auto_Eddy.py b/nipype/interfaces/fsl/tests/test_auto_Eddy.py index b76f482fb1..4a2d245a23 100644 --- a/nipype/interfaces/fsl/tests/test_auto_Eddy.py +++ b/nipype/interfaces/fsl/tests/test_auto_Eddy.py @@ -4,202 +4,86 @@ def test_Eddy_inputs(): input_map = dict( - args=dict(argstr='%s', ), - cnr_maps=dict( - argstr='--cnr_maps', - min_ver='5.0.10', - ), - dont_peas=dict(argstr='--dont_peas', ), - dont_sep_offs_move=dict(argstr='--dont_sep_offs_move', ), - environ=dict( - nohash=True, - usedefault=True, - ), + args=dict(argstr="%s",), + cnr_maps=dict(argstr="--cnr_maps", min_ver="5.0.10",), + dont_peas=dict(argstr="--dont_peas",), + dont_sep_offs_move=dict(argstr="--dont_sep_offs_move",), + environ=dict(nohash=True, usedefault=True,), estimate_move_by_susceptibility=dict( - argstr='--estimate_move_by_susceptibility', - min_ver='6.0.1', - ), - fep=dict(argstr='--fep', ), - field=dict( - argstr='--field=%s', - extensions=None, - ), - field_mat=dict( - argstr='--field_mat=%s', - extensions=None, - ), - flm=dict( - argstr='--flm=%s', - usedefault=True, - ), - fudge_factor=dict( - argstr='--ff=%s', - usedefault=True, - ), - fwhm=dict(argstr='--fwhm=%s', ), - in_acqp=dict( - argstr='--acqp=%s', - extensions=None, - mandatory=True, - ), - in_bval=dict( - argstr='--bvals=%s', - extensions=None, - mandatory=True, - ), - in_bvec=dict( - argstr='--bvecs=%s', - extensions=None, - mandatory=True, - ), - in_file=dict( - argstr='--imain=%s', - extensions=None, - mandatory=True, - ), - in_index=dict( - argstr='--index=%s', - extensions=None, - mandatory=True, - ), - in_mask=dict( - argstr='--mask=%s', - extensions=None, - mandatory=True, - ), + argstr="--estimate_move_by_susceptibility", min_ver="6.0.1", + ), + fep=dict(argstr="--fep",), + field=dict(argstr="--field=%s", extensions=None,), + field_mat=dict(argstr="--field_mat=%s", extensions=None,), + flm=dict(argstr="--flm=%s", usedefault=True,), + fudge_factor=dict(argstr="--ff=%s", usedefault=True,), + fwhm=dict(argstr="--fwhm=%s",), + in_acqp=dict(argstr="--acqp=%s", extensions=None, mandatory=True,), + in_bval=dict(argstr="--bvals=%s", extensions=None, mandatory=True,), + in_bvec=dict(argstr="--bvecs=%s", extensions=None, mandatory=True,), + in_file=dict(argstr="--imain=%s", extensions=None, mandatory=True,), + in_index=dict(argstr="--index=%s", extensions=None, mandatory=True,), + in_mask=dict(argstr="--mask=%s", extensions=None, mandatory=True,), in_topup_fieldcoef=dict( - argstr='--topup=%s', - extensions=None, - requires=['in_topup_movpar'], - ), - in_topup_movpar=dict( - extensions=None, - requires=['in_topup_fieldcoef'], - ), - initrand=dict( - argstr='--initrand', - min_ver='5.0.10', - ), - interp=dict( - argstr='--interp=%s', - usedefault=True, + argstr="--topup=%s", extensions=None, requires=["in_topup_movpar"], ), - is_shelled=dict(argstr='--data_is_shelled', ), + in_topup_movpar=dict(extensions=None, requires=["in_topup_fieldcoef"],), + initrand=dict(argstr="--initrand", min_ver="5.0.10",), + interp=dict(argstr="--interp=%s", usedefault=True,), + is_shelled=dict(argstr="--data_is_shelled",), json=dict( - argstr='--json=%s', - min_ver='6.0.1', - requires=['mporder'], - xor=['slice_order'], + argstr="--json=%s", + min_ver="6.0.1", + requires=["mporder"], + xor=["slice_order"], ), mbs_ksp=dict( - argstr='--mbs_ksp=%smm', - min_ver='6.0.1', - requires=['estimate_move_by_susceptibility'], + argstr="--mbs_ksp=%smm", + min_ver="6.0.1", + requires=["estimate_move_by_susceptibility"], ), mbs_lambda=dict( - argstr='--mbs_lambda=%s', - min_ver='6.0.1', - requires=['estimate_move_by_susceptibility'], + argstr="--mbs_lambda=%s", + min_ver="6.0.1", + requires=["estimate_move_by_susceptibility"], ), mbs_niter=dict( - argstr='--mbs_niter=%s', - min_ver='6.0.1', - requires=['estimate_move_by_susceptibility'], - ), - method=dict( - argstr='--resamp=%s', - usedefault=True, - ), - mporder=dict( - argstr='--mporder=%s', - min_ver='5.0.11', - requires=['use_cuda'], - ), - multiband_factor=dict( - argstr='--mb=%s', - min_ver='5.0.10', + argstr="--mbs_niter=%s", + min_ver="6.0.1", + requires=["estimate_move_by_susceptibility"], ), + method=dict(argstr="--resamp=%s", usedefault=True,), + mporder=dict(argstr="--mporder=%s", min_ver="5.0.11", requires=["use_cuda"],), + multiband_factor=dict(argstr="--mb=%s", min_ver="5.0.10",), multiband_offset=dict( - argstr='--mb_offs=%d', - min_ver='5.0.10', - requires=['multiband_factor'], - ), - niter=dict( - argstr='--niter=%s', - usedefault=True, - ), - num_threads=dict( - nohash=True, - usedefault=True, - ), - nvoxhp=dict( - argstr='--nvoxhp=%s', - usedefault=True, - ), - out_base=dict( - argstr='--out=%s', - usedefault=True, - ), - outlier_nstd=dict( - argstr='--ol_nstd', - min_ver='5.0.10', - requires=['repol'], - ), - outlier_nvox=dict( - argstr='--ol_nvox', - min_ver='5.0.10', - requires=['repol'], - ), - outlier_pos=dict( - argstr='--ol_pos', - min_ver='5.0.10', - requires=['repol'], - ), - outlier_sqr=dict( - argstr='--ol_sqr', - min_ver='5.0.10', - requires=['repol'], - ), - outlier_type=dict( - argstr='--ol_type', - min_ver='5.0.10', - requires=['repol'], - ), + argstr="--mb_offs=%d", min_ver="5.0.10", requires=["multiband_factor"], + ), + niter=dict(argstr="--niter=%s", usedefault=True,), + num_threads=dict(nohash=True, usedefault=True,), + nvoxhp=dict(argstr="--nvoxhp=%s", usedefault=True,), + out_base=dict(argstr="--out=%s", usedefault=True,), + outlier_nstd=dict(argstr="--ol_nstd", min_ver="5.0.10", requires=["repol"],), + outlier_nvox=dict(argstr="--ol_nvox", min_ver="5.0.10", requires=["repol"],), + outlier_pos=dict(argstr="--ol_pos", min_ver="5.0.10", requires=["repol"],), + outlier_sqr=dict(argstr="--ol_sqr", min_ver="5.0.10", requires=["repol"],), + outlier_type=dict(argstr="--ol_type", min_ver="5.0.10", requires=["repol"],), output_type=dict(), - repol=dict(argstr='--repol', ), - residuals=dict( - argstr='--residuals', - min_ver='5.0.10', - ), - session=dict( - argstr='--session=%s', - extensions=None, - ), + repol=dict(argstr="--repol",), + residuals=dict(argstr="--residuals", min_ver="5.0.10",), + session=dict(argstr="--session=%s", extensions=None,), slice2vol_interp=dict( - argstr='--s2v_interp=%s', - min_ver='5.0.11', - requires=['mporder'], + argstr="--s2v_interp=%s", min_ver="5.0.11", requires=["mporder"], ), slice2vol_lambda=dict( - argstr='--s2v_lambda=%d', - min_ver='5.0.11', - requires=['mporder'], + argstr="--s2v_lambda=%d", min_ver="5.0.11", requires=["mporder"], ), slice2vol_niter=dict( - argstr='--s2v_niter=%d', - min_ver='5.0.11', - requires=['mporder'], + argstr="--s2v_niter=%d", min_ver="5.0.11", requires=["mporder"], ), slice_order=dict( - argstr='--slspec=%s', - min_ver='5.0.11', - requires=['mporder'], - xor=['json'], - ), - slm=dict( - argstr='--slm=%s', - usedefault=True, + argstr="--slspec=%s", min_ver="5.0.11", requires=["mporder"], xor=["json"], ), + slm=dict(argstr="--slm=%s", usedefault=True,), use_cuda=dict(), ) inputs = Eddy.input_spec() @@ -211,21 +95,21 @@ def test_Eddy_inputs(): def test_Eddy_outputs(): output_map = dict( - out_cnr_maps=dict(extensions=None, ), - out_corrected=dict(extensions=None, ), - out_movement_over_time=dict(extensions=None, ), - out_movement_rms=dict(extensions=None, ), - out_outlier_free=dict(extensions=None, ), - out_outlier_map=dict(extensions=None, ), - out_outlier_n_sqr_stdev_map=dict(extensions=None, ), - out_outlier_n_stdev_map=dict(extensions=None, ), - out_outlier_report=dict(extensions=None, ), - out_parameter=dict(extensions=None, ), - out_residuals=dict(extensions=None, ), - out_restricted_movement_rms=dict(extensions=None, ), - out_rotated_bvecs=dict(extensions=None, ), - out_shell_alignment_parameters=dict(extensions=None, ), - out_shell_pe_translation_parameters=dict(extensions=None, ), + out_cnr_maps=dict(extensions=None,), + out_corrected=dict(extensions=None,), + out_movement_over_time=dict(extensions=None,), + out_movement_rms=dict(extensions=None,), + out_outlier_free=dict(extensions=None,), + out_outlier_map=dict(extensions=None,), + out_outlier_n_sqr_stdev_map=dict(extensions=None,), + out_outlier_n_stdev_map=dict(extensions=None,), + out_outlier_report=dict(extensions=None,), + out_parameter=dict(extensions=None,), + out_residuals=dict(extensions=None,), + out_restricted_movement_rms=dict(extensions=None,), + out_rotated_bvecs=dict(extensions=None,), + out_shell_alignment_parameters=dict(extensions=None,), + out_shell_pe_translation_parameters=dict(extensions=None,), ) outputs = Eddy.output_spec() From af12bf7c1725efc9e9668715fb23e7ed761035c1 Mon Sep 17 00:00:00 2001 From: mjoseph Date: Mon, 16 Sep 2019 16:06:59 -0400 Subject: [PATCH 10/19] initial eddy update --- nipype/interfaces/fsl/epi.py | 202 +++++++++++++++++------------------ 1 file changed, 100 insertions(+), 102 deletions(-) diff --git a/nipype/interfaces/fsl/epi.py b/nipype/interfaces/fsl/epi.py index d5e6c044d6..5a6ec300a3 100644 --- a/nipype/interfaces/fsl/epi.py +++ b/nipype/interfaces/fsl/epi.py @@ -587,7 +587,7 @@ class EddyInputSpec(FSLCommandInputSpec): default_value="eddy_corrected", usedefault=True, argstr="--out=%s", - desc="Basename for output image", + desc="basename for output (warped) image", ) session = File( exists=True, @@ -598,41 +598,34 @@ class EddyInputSpec(FSLCommandInputSpec): exists=True, argstr="--topup=%s", requires=["in_topup_movpar"], - desc="Topup results file containing the field coefficients", + desc="topup file containing the field coefficients", ) in_topup_movpar = File( - exists=True, - requires=["in_topup_fieldcoef"], - desc="Topup results file containing the movement parameters (movpar.txt)", + exists=True, requires=["in_topup_fieldcoef"], desc="topup movpar.txt file" ) field = File( - exists=True, argstr="--field=%s", - desc="Non-topup derived fieldmap scaled in Hz", + desc=( + "NonTOPUP fieldmap scaled in Hz - filename has " + "to be provided without an extension. TOPUP is " + "strongly recommended" + ), ) field_mat = File( exists=True, argstr="--field_mat=%s", - desc="Matrix specifying the relative positions of " - "the fieldmap, --field, and the first volume " - "of the input file, --imain", + desc=( + "Matrix that specifies the relative locations of " + "the field specified by --field and first volume " + "in file --imain" + ), ) flm = traits.Enum( - "quadratic", - "linear", - "cubic", - usedefault=True, - argstr="--flm=%s", - desc="First level EC model", + "linear", "quadratic", "cubic", argstr="--flm=%s", desc="First level EC model" ) slm = traits.Enum( - "none", - "linear", - "quadratic", - usedefault=True, - argstr="--slm=%s", - desc="Second level EC model", + "none", "linear", "quadratic", argstr="--slm=%s", desc="Second level EC model" ) fep = traits.Bool( False, argstr="--fep", desc="Fill empty planes in x- or y-directions" @@ -646,7 +639,6 @@ class EddyInputSpec(FSLCommandInputSpec): interp = traits.Enum( "spline", "trilinear", - usedefault=True, argstr="--interp=%s", desc="Interpolation model for estimation step", ) @@ -654,26 +646,26 @@ class EddyInputSpec(FSLCommandInputSpec): default_value=1000, usedefault=True, argstr="--nvoxhp=%s", - desc="# of voxels used to estimate the hyperparameters", + desc=("# of voxels used to estimate the " "hyperparameters"), ) fudge_factor = traits.Float( default_value=10.0, usedefault=True, argstr="--ff=%s", - desc="Fudge factor for hyperparameter error variance", + desc=("Fudge factor for hyperparameter " "error variance"), ) dont_sep_offs_move = traits.Bool( False, argstr="--dont_sep_offs_move", - desc="Do NOT attempt to separate field offset from subject movement", + desc=("Do NOT attempt to separate " "field offset from subject " "movement"), ) dont_peas = traits.Bool( False, argstr="--dont_peas", - desc="Do NOT perform a post-eddy alignment of shells", + desc="Do NOT perform a post-eddy alignment of " "shells", ) fwhm = traits.Float( - desc="FWHM for conditioning filter when estimating the parameters", + desc=("FWHM for conditioning filter when estimating " "the parameters"), argstr="--fwhm=%s", ) niter = traits.Int( @@ -682,9 +674,8 @@ class EddyInputSpec(FSLCommandInputSpec): method = traits.Enum( "jac", "lsr", - usedefault=True, argstr="--resamp=%s", - desc="Final resampling method (jacobian/least squares)", + desc=("Final resampling method (jacobian/least " "squares)"), ) repol = traits.Bool( @@ -725,50 +716,49 @@ class EddyInputSpec(FSLCommandInputSpec): requires=["repol"], min_ver="5.0.10", ) - multiband_factor = traits.Int( - argstr="--mb=%s", desc="Multi-band factor", min_ver="5.0.10" - ) - multiband_offset = traits.Enum( + mb = traits.Int(argstr="--mb=%s", desc="Multi-band factor", min_ver="5.0.10") + mb_offs = traits.Enum( 0, 1, -1, - argstr="--mb_offs=%d", - desc="Multi-band offset (-1 if bottom slice removed, 1 if top slice removed", - requires=["multiband_factor"], + argstr="--mb_offs=%s", + desc=( + "Multi-band offset (-1 if bottom slice removed, 1 if " "top slice removed" + ), + requires=["mb"], min_ver="5.0.10", ) mporder = traits.Int( argstr="--mporder=%s", desc="Order of slice-to-vol movement model", - requires=["use_cuda"], + requires=["slspec"], min_ver="5.0.11", ) - slice2vol_niter = traits.Int( - argstr="--s2v_niter=%d", + s2v_niter = traits.Int( + argstr="--s2v_niter=%s", desc="Number of iterations for slice-to-vol", - requires=["mporder"], + requires=["slspec"], min_ver="5.0.11", ) - slice2vol_lambda = traits.Int( - argstr="--s2v_lambda=%d", + s2v_lambda = traits.Int( + agstr="--s2v_lambda", desc="Regularisation weight for slice-to-vol movement (reasonable range 1-10)", - requires=["mporder"], + requires=["slspec"], min_ver="5.0.11", ) - slice2vol_interp = traits.Enum( + s2v_interp = traits.Enum( "trilinear", "spline", argstr="--s2v_interp=%s", desc="Slice-to-vol interpolation model for estimation step", - requires=["mporder"], + requires=["slspec"], min_ver="5.0.11", ) - slice_order = traits.File( + slspec = traits.File( exists=True, argstr="--slspec=%s", desc="Name of text file completely specifying slice/group acquisition", - requires=["mporder"], xor=["json"], min_ver="5.0.11", ) @@ -776,8 +766,7 @@ class EddyInputSpec(FSLCommandInputSpec): exists=True, argstr="--json=%s", desc="Name of .json text file with information about slice timing", - requires=["mporder"], - xor=["slice_order"], + xor=["slspec"], min_ver="6.0.1", ) @@ -812,9 +801,11 @@ class EddyInputSpec(FSLCommandInputSpec): is_shelled = traits.Bool( False, argstr="--data_is_shelled", - desc="Override internal check to ensure that " - "date are acquired on a set of b-value " - "shells", + desc=( + "Override internal check to ensure that " + "date are acquired on a set of b-value " + "shells" + ), ) use_cuda = traits.Bool(False, desc="Run eddy using cuda gpu") @@ -832,8 +823,9 @@ class EddyOutputSpec(TraitedSpec): ) out_parameter = File( exists=True, - desc="Text file with parameters defining the field and" - "movement for each scan", + desc=( + "Text file with parameters defining the field and" "movement for each scan" + ), ) out_rotated_bvecs = File( exists=True, desc="File containing rotated b-values for all volumes" @@ -848,56 +840,74 @@ class EddyOutputSpec(TraitedSpec): ) out_shell_alignment_parameters = File( exists=True, - desc="Text file containing rigid body movement parameters " - "between the different shells as estimated by a " - "post-hoc mutual information based registration", + desc=( + "Text file containing rigid body movement parameters " + "between the different shells as estimated by a " + "post-hoc mutual information based registration" + ), ) out_shell_pe_translation_parameters = File( exists=True, - desc="Text file containing translation along the PE-direction " - "between the different shells as estimated by a " - "post-hoc mutual information based registration", + desc=( + "Text file containing translation along the PE-direction " + "between the different shells as estimated by a " + "post-hoc mutual information based registration" + ), ) out_shell_pe_translation_parameters = File( exists=True, - desc="Text file containing translation along the PE-direction " - "between the different shells as estimated by a " - "post-hoc mutual information based registration", + desc=( + "Text file containing translation along the PE-direction " + "between the different shells as estimated by a " + "post-hoc mutual information based registration" + ), ) out_outlier_map = File( exists=True, - desc="Matrix where rows represent volumes and columns represent " - 'slices. "0" indicates that scan-slice is not an outlier ' - 'and "1" indicates that it is', + desc=( + "Matrix where rows represent volumes and columns represent " + 'slices. "0" indicates that scan-slice is not an outlier ' + 'and "1" indicates that it is' + ), ) out_outlier_n_stdev_map = File( exists=True, - desc="Matrix where rows represent volumes and columns represent " - "slices. Values indicate number of standard deviations off the " - "mean difference between observation and prediction is", + desc=( + "Matrix where rows represent volumes and columns represent " + "slices. Values indicate number of standard deviations off the " + "mean difference between observation and prediction is" + ), ) out_outlier_n_sqr_stdev_map = File( exists=True, - desc="Matrix where rows represent volumes and columns represent " - "slices. Values indicate number of standard deivations off the " - "square root of the mean squared difference between observation " - "and prediction is", + desc=( + "Matrix where rows represent volumes and columns represent " + "slices. Values indicate number of standard deivations off the " + "square root of the mean squared difference between observation " + "and prediction is" + ), ) out_outlier_report = File( exists=True, - desc="Text file with a plain language report on what " - "outlier slices eddy has found", + desc=( + "Text file with a plain language report on what " + "outlier slices eddy has found" + ), ) out_outlier_free = File( exists=True, - desc="4D image file not corrected for susceptibility or eddy-" - "current distortions or subject movement but with outlier " - "slices replaced", + desc=( + "4D image file not corrected for susceptibility or eddy-" + "current distortions or subject movement but with outlier " + "slices replaced" + ), ) out_movement_over_time = File( exists=True, - desc="Text file containing translations (mm) and rotations " - "(radians) for each excitation", + desc=( + "Text file containing translations (mm) and rotations " + "(radians) for each excitation" + ), ) out_cnr_maps = File(exists=True, desc="path/name of file with the cnr_maps") out_residuals = File(exists=True, desc="path/name of file with the residuals") @@ -934,27 +944,15 @@ class Eddy(FSLCommand): Running eddy on an Nvidia GPU using cuda: >>> eddy.inputs.use_cuda = True >>> eddy.cmdline # doctest: +ELLIPSIS - 'eddy_cuda --flm=quadratic --ff=10.0 \ ---acqp=epi_acqp.txt --bvals=bvals.scheme --bvecs=bvecs.scheme \ ---imain=epi.nii --index=epi_index.txt --mask=epi_mask.nii \ ---interp=spline --resamp=jac --niter=5 --nvoxhp=1000 \ ---out=.../eddy_corrected --slm=none' - - Running eddy with slice-to-volume motion correction: - >>> eddy.inputs.mporder = 6 - >>> eddy.inputs.slice2vol_niter = 5 - >>> eddy.inputs.slice2vol_lambda = 1 - >>> eddy.inputs.slice2vol_interp = 'trilinear' - >>> eddy.inputs.slice_order = 'epi_slspec.txt' - >>> eddy.cmdline # doctest: +ELLIPSIS - 'eddy_cuda --flm=quadratic --ff=10.0 \ ---acqp=epi_acqp.txt --bvals=bvals.scheme --bvecs=bvecs.scheme \ ---imain=epi.nii --index=epi_index.txt --mask=epi_mask.nii \ ---interp=spline --resamp=jac --mporder=6 --niter=5 --nvoxhp=1000 \ ---out=.../eddy_corrected --s2v_interp=trilinear --s2v_lambda=1 \ ---s2v_niter=5 --slspec=epi_slspec.txt --slm=none' - >>> res = eddy.run() # doctest: +SKIP - + 'eddy_cuda --ff=10.0 --fwhm=0 --acqp=epi_acqp.txt --bvals=bvals.scheme \ +--bvecs=bvecs.scheme --imain=epi.nii --index=epi_index.txt \ +--mask=epi_mask.nii --niter=5 --nvoxhp=1000 --out=.../eddy_corrected' + >>> eddy.inputs.use_cuda = False + >>> eddy.cmdline # doctest: +ELLIPSIS + 'eddy_openmp --ff=10.0 --fwhm=0 --acqp=epi_acqp.txt --bvals=bvals.scheme \ +--bvecs=bvecs.scheme --imain=epi.nii --index=epi_index.txt \ +--mask=epi_mask.nii --niter=5 --nvoxhp=1000 --out=.../eddy_corrected' + >>> res = eddy.run() # doctest: +SKIP """ _cmd = "eddy_openmp" From 8c30489d25c46965327f38e3aa762fa04fb17438 Mon Sep 17 00:00:00 2001 From: Michael Joseph Date: Mon, 16 Sep 2019 14:52:37 -0400 Subject: [PATCH 11/19] initial eddy update --- nipype/interfaces/fsl/epi.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/nipype/interfaces/fsl/epi.py b/nipype/interfaces/fsl/epi.py index 5a6ec300a3..ca1126053e 100644 --- a/nipype/interfaces/fsl/epi.py +++ b/nipype/interfaces/fsl/epi.py @@ -611,6 +611,17 @@ class EddyInputSpec(FSLCommandInputSpec): "strongly recommended" ), ) + field_mat = File( + exists=True, requires=["in_topup_fieldcoef"], desc="topup movpar.txt file" + ) + field = File( + argstr="--field=%s", + desc=( + "NonTOPUP fieldmap scaled in Hz - filename has " + "to be provided without an extension. TOPUP is " + "strongly recommended" + ), + ) field_mat = File( exists=True, argstr="--field_mat=%s", From ae7ab07dbafc8309d5b0d8577587c8b7102daaf3 Mon Sep 17 00:00:00 2001 From: Michael Joseph Date: Mon, 16 Sep 2019 20:18:04 -0400 Subject: [PATCH 12/19] update doctest --- nipype/interfaces/fsl/epi.py | 77 +++++++++++++++++++----------------- 1 file changed, 40 insertions(+), 37 deletions(-) diff --git a/nipype/interfaces/fsl/epi.py b/nipype/interfaces/fsl/epi.py index ca1126053e..377a245447 100644 --- a/nipype/interfaces/fsl/epi.py +++ b/nipype/interfaces/fsl/epi.py @@ -587,7 +587,7 @@ class EddyInputSpec(FSLCommandInputSpec): default_value="eddy_corrected", usedefault=True, argstr="--out=%s", - desc="basename for output (warped) image", + desc="Basename for output image", ) session = File( exists=True, @@ -598,45 +598,39 @@ class EddyInputSpec(FSLCommandInputSpec): exists=True, argstr="--topup=%s", requires=["in_topup_movpar"], - desc="topup file containing the field coefficients", + desc="Topup results file containing the field coefficients", ) in_topup_movpar = File( - exists=True, requires=["in_topup_fieldcoef"], desc="topup movpar.txt file" - ) - field = File( - argstr="--field=%s", - desc=( - "NonTOPUP fieldmap scaled in Hz - filename has " - "to be provided without an extension. TOPUP is " - "strongly recommended" - ), - ) - field_mat = File( - exists=True, requires=["in_topup_fieldcoef"], desc="topup movpar.txt file" - ) - field = File( - argstr="--field=%s", - desc=( - "NonTOPUP fieldmap scaled in Hz - filename has " - "to be provided without an extension. TOPUP is " - "strongly recommended" - ), + exists=True, + requires=["in_topup_fieldcoef"], + desc="Topup results file containing the movement parameters", ) + field = File(argstr="--field=%s", desc=("Non-topup derived fieldmap scaled in Hz")) field_mat = File( exists=True, argstr="--field_mat=%s", desc=( - "Matrix that specifies the relative locations of " - "the field specified by --field and first volume " - "in file --imain" + "Matrix specifying the relative positions of " + "the fieldmap, --field, and the first volume " + "of the input file, --imain" ), ) flm = traits.Enum( - "linear", "quadratic", "cubic", argstr="--flm=%s", desc="First level EC model" + "quadratic", + "linear", + "cubic", + usedefault=True, + argstr="--flm=%s", + desc="First level EC model", ) slm = traits.Enum( - "none", "linear", "quadratic", argstr="--slm=%s", desc="Second level EC model" + "none", + "linear", + "quadratic", + usedefault=True, + argstr="--slm=%s", + desc="Second level EC model", ) fep = traits.Bool( False, argstr="--fep", desc="Fill empty planes in x- or y-directions" @@ -650,6 +644,7 @@ class EddyInputSpec(FSLCommandInputSpec): interp = traits.Enum( "spline", "trilinear", + usedefault=True, argstr="--interp=%s", desc="Interpolation model for estimation step", ) @@ -676,6 +671,8 @@ class EddyInputSpec(FSLCommandInputSpec): desc="Do NOT perform a post-eddy alignment of " "shells", ) fwhm = traits.Float( + default_value=0.0, + usedefault=True, desc=("FWHM for conditioning filter when estimating " "the parameters"), argstr="--fwhm=%s", ) @@ -685,6 +682,7 @@ class EddyInputSpec(FSLCommandInputSpec): method = traits.Enum( "jac", "lsr", + usedefault=True, argstr="--resamp=%s", desc=("Final resampling method (jacobian/least " "squares)"), ) @@ -743,19 +741,18 @@ class EddyInputSpec(FSLCommandInputSpec): mporder = traits.Int( argstr="--mporder=%s", desc="Order of slice-to-vol movement model", - requires=["slspec"], min_ver="5.0.11", ) s2v_niter = traits.Int( argstr="--s2v_niter=%s", desc="Number of iterations for slice-to-vol", - requires=["slspec"], + requires=["mporder"], min_ver="5.0.11", ) s2v_lambda = traits.Int( agstr="--s2v_lambda", desc="Regularisation weight for slice-to-vol movement (reasonable range 1-10)", - requires=["slspec"], + requires=["mporder"], min_ver="5.0.11", ) s2v_interp = traits.Enum( @@ -763,13 +760,14 @@ class EddyInputSpec(FSLCommandInputSpec): "spline", argstr="--s2v_interp=%s", desc="Slice-to-vol interpolation model for estimation step", - requires=["slspec"], + requires=["mporder"], min_ver="5.0.11", ) slspec = traits.File( exists=True, argstr="--slspec=%s", desc="Name of text file completely specifying slice/group acquisition", + requires=["mporder"], xor=["json"], min_ver="5.0.11", ) @@ -777,6 +775,7 @@ class EddyInputSpec(FSLCommandInputSpec): exists=True, argstr="--json=%s", desc="Name of .json text file with information about slice timing", + requires=["mporder"], xor=["slspec"], min_ver="6.0.1", ) @@ -955,14 +954,18 @@ class Eddy(FSLCommand): Running eddy on an Nvidia GPU using cuda: >>> eddy.inputs.use_cuda = True >>> eddy.cmdline # doctest: +ELLIPSIS - 'eddy_cuda --ff=10.0 --fwhm=0 --acqp=epi_acqp.txt --bvals=bvals.scheme \ ---bvecs=bvecs.scheme --imain=epi.nii --index=epi_index.txt \ ---mask=epi_mask.nii --niter=5 --nvoxhp=1000 --out=.../eddy_corrected' + 'eddy_cuda --flm=quadratic --ff=10.0 --fwhm=0.0 \ +--acqp=epi_acqp.txt --bvals=bvals.scheme --bvecs=bvecs.scheme \ +--imain=epi.nii --index=epi_index.txt --mask=epi_mask.nii \ +--interp=spline --resamp=jac --niter=5 --nvoxhp=1000 \ +--out=.../eddy_corrected --slm=none' >>> eddy.inputs.use_cuda = False >>> eddy.cmdline # doctest: +ELLIPSIS - 'eddy_openmp --ff=10.0 --fwhm=0 --acqp=epi_acqp.txt --bvals=bvals.scheme \ ---bvecs=bvecs.scheme --imain=epi.nii --index=epi_index.txt \ ---mask=epi_mask.nii --niter=5 --nvoxhp=1000 --out=.../eddy_corrected' + 'eddy_openmp --flm=quadratic --ff=10.0 --fwhm=0.0 \ +--acqp=epi_acqp.txt --bvals=bvals.scheme --bvecs=bvecs.scheme \ +--imain=epi.nii --index=epi_index.txt --mask=epi_mask.nii \ +--interp=spline --resamp=jac --niter=5 --nvoxhp=1000 \ +--out=.../eddy_corrected --slm=none' >>> res = eddy.run() # doctest: +SKIP """ From 3040ef525b0b5bf622f00afa27422384b7aadd16 Mon Sep 17 00:00:00 2001 From: Michael Joseph Date: Mon, 16 Sep 2019 20:23:18 -0400 Subject: [PATCH 13/19] add test --- nipype/interfaces/fsl/tests/test_auto_Eddy.py | 31 +++++++------------ 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/nipype/interfaces/fsl/tests/test_auto_Eddy.py b/nipype/interfaces/fsl/tests/test_auto_Eddy.py index 4a2d245a23..24aee2c466 100644 --- a/nipype/interfaces/fsl/tests/test_auto_Eddy.py +++ b/nipype/interfaces/fsl/tests/test_auto_Eddy.py @@ -17,7 +17,7 @@ def test_Eddy_inputs(): field_mat=dict(argstr="--field_mat=%s", extensions=None,), flm=dict(argstr="--flm=%s", usedefault=True,), fudge_factor=dict(argstr="--ff=%s", usedefault=True,), - fwhm=dict(argstr="--fwhm=%s",), + fwhm=dict(argstr="--fwhm=%s", usedefault=True,), in_acqp=dict(argstr="--acqp=%s", extensions=None, mandatory=True,), in_bval=dict(argstr="--bvals=%s", extensions=None, mandatory=True,), in_bvec=dict(argstr="--bvecs=%s", extensions=None, mandatory=True,), @@ -32,11 +32,10 @@ def test_Eddy_inputs(): interp=dict(argstr="--interp=%s", usedefault=True,), is_shelled=dict(argstr="--data_is_shelled",), json=dict( - argstr="--json=%s", - min_ver="6.0.1", - requires=["mporder"], - xor=["slice_order"], + argstr="--json=%s", min_ver="6.0.1", requires=["mporder"], xor=["slspec"], ), + mb=dict(argstr="--mb=%s", min_ver="5.0.10",), + mb_offs=dict(argstr="--mb_offs=%s", min_ver="5.0.10", requires=["mb"],), mbs_ksp=dict( argstr="--mbs_ksp=%smm", min_ver="6.0.1", @@ -53,11 +52,7 @@ def test_Eddy_inputs(): requires=["estimate_move_by_susceptibility"], ), method=dict(argstr="--resamp=%s", usedefault=True,), - mporder=dict(argstr="--mporder=%s", min_ver="5.0.11", requires=["use_cuda"],), - multiband_factor=dict(argstr="--mb=%s", min_ver="5.0.10",), - multiband_offset=dict( - argstr="--mb_offs=%d", min_ver="5.0.10", requires=["multiband_factor"], - ), + mporder=dict(argstr="--mporder=%s", min_ver="5.0.11",), niter=dict(argstr="--niter=%s", usedefault=True,), num_threads=dict(nohash=True, usedefault=True,), nvoxhp=dict(argstr="--nvoxhp=%s", usedefault=True,), @@ -70,20 +65,18 @@ def test_Eddy_inputs(): output_type=dict(), repol=dict(argstr="--repol",), residuals=dict(argstr="--residuals", min_ver="5.0.10",), - session=dict(argstr="--session=%s", extensions=None,), - slice2vol_interp=dict( + s2v_interp=dict( argstr="--s2v_interp=%s", min_ver="5.0.11", requires=["mporder"], ), - slice2vol_lambda=dict( - argstr="--s2v_lambda=%d", min_ver="5.0.11", requires=["mporder"], - ), - slice2vol_niter=dict( - argstr="--s2v_niter=%d", min_ver="5.0.11", requires=["mporder"], + s2v_lambda=dict(agstr="--s2v_lambda", min_ver="5.0.11", requires=["mporder"],), + s2v_niter=dict( + argstr="--s2v_niter=%s", min_ver="5.0.11", requires=["mporder"], ), - slice_order=dict( + session=dict(argstr="--session=%s", extensions=None,), + slm=dict(argstr="--slm=%s", usedefault=True,), + slspec=dict( argstr="--slspec=%s", min_ver="5.0.11", requires=["mporder"], xor=["json"], ), - slm=dict(argstr="--slm=%s", usedefault=True,), use_cuda=dict(), ) inputs = Eddy.input_spec() From d7d1a36c99e1573e66a70630d50e5eacfff94cfe Mon Sep 17 00:00:00 2001 From: mjoseph Date: Tue, 17 Sep 2019 12:17:06 -0400 Subject: [PATCH 14/19] add doctest for running eddy with s2v motion correction --- nipype/interfaces/fsl/epi.py | 23 +++++++++++++++++-- nipype/interfaces/fsl/tests/test_auto_Eddy.py | 2 +- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/nipype/interfaces/fsl/epi.py b/nipype/interfaces/fsl/epi.py index 377a245447..29be815244 100644 --- a/nipype/interfaces/fsl/epi.py +++ b/nipype/interfaces/fsl/epi.py @@ -741,6 +741,7 @@ class EddyInputSpec(FSLCommandInputSpec): mporder = traits.Int( argstr="--mporder=%s", desc="Order of slice-to-vol movement model", + requires=["use_cuda"], min_ver="5.0.11", ) s2v_niter = traits.Int( @@ -959,14 +960,32 @@ class Eddy(FSLCommand): --imain=epi.nii --index=epi_index.txt --mask=epi_mask.nii \ --interp=spline --resamp=jac --niter=5 --nvoxhp=1000 \ --out=.../eddy_corrected --slm=none' + + Running eddy on a CPU using OpenMP: >>> eddy.inputs.use_cuda = False - >>> eddy.cmdline # doctest: +ELLIPSIS + >>> eddy.cmdline # doctest: +ELLIPSIS 'eddy_openmp --flm=quadratic --ff=10.0 --fwhm=0.0 \ --acqp=epi_acqp.txt --bvals=bvals.scheme --bvecs=bvecs.scheme \ --imain=epi.nii --index=epi_index.txt --mask=epi_mask.nii \ --interp=spline --resamp=jac --niter=5 --nvoxhp=1000 \ --out=.../eddy_corrected --slm=none' - >>> res = eddy.run() # doctest: +SKIP + + Running eddy with slice-to-volume motion correction: + >>> eddy.inputs.use_cuda = True + >>> eddy.inputs.mporder = 6 + >>> eddy.inputs.s2v_niter = 5 + >>> eddy.inputs.s2v_lambda = 1 + >>> eddy.inputs.s2v_interp = 'trilinear' + >>> eddy.inputs.slspec = 'epi_slspec.txt' + >>> eddy.cmdline # doctest: +ELLIPSIS + 'eddy_cuda --flm=quadratic --ff=10.0 --fwhm=0.0 \ +--acqp=epi_acqp.txt --bvals=bvals.scheme --bvecs=bvecs.scheme \ +--imain=epi.nii --index=epi_index.txt --mask=epi_mask.nii \ +--interp=spline --resamp=jac --mporder=6 --niter=5 --nvoxhp=1000 \ +--out=.../eddy_corrected --s2v_interp=trilinear --s2v_niter=5 \ +--slm=none --slspec=epi_slspec.txt' + >>> res = eddy.run() # doctest: +SKIP + """ _cmd = "eddy_openmp" diff --git a/nipype/interfaces/fsl/tests/test_auto_Eddy.py b/nipype/interfaces/fsl/tests/test_auto_Eddy.py index 24aee2c466..224612cbe1 100644 --- a/nipype/interfaces/fsl/tests/test_auto_Eddy.py +++ b/nipype/interfaces/fsl/tests/test_auto_Eddy.py @@ -52,7 +52,7 @@ def test_Eddy_inputs(): requires=["estimate_move_by_susceptibility"], ), method=dict(argstr="--resamp=%s", usedefault=True,), - mporder=dict(argstr="--mporder=%s", min_ver="5.0.11",), + mporder=dict(argstr="--mporder=%s", min_ver="5.0.11", requires=["use_cuda"],), niter=dict(argstr="--niter=%s", usedefault=True,), num_threads=dict(nohash=True, usedefault=True,), nvoxhp=dict(argstr="--nvoxhp=%s", usedefault=True,), From 46608c54c8693c8fc8e0aaa38a3b893dd6333fbb Mon Sep 17 00:00:00 2001 From: Michael Joseph Date: Wed, 18 Sep 2019 05:52:37 -0400 Subject: [PATCH 15/19] Apply suggestions from code review Co-Authored-By: Chris Markiewicz --- nipype/interfaces/fsl/epi.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/nipype/interfaces/fsl/epi.py b/nipype/interfaces/fsl/epi.py index 29be815244..1c32ad318a 100644 --- a/nipype/interfaces/fsl/epi.py +++ b/nipype/interfaces/fsl/epi.py @@ -603,9 +603,13 @@ class EddyInputSpec(FSLCommandInputSpec): in_topup_movpar = File( exists=True, requires=["in_topup_fieldcoef"], - desc="Topup results file containing the movement parameters", + desc="Topup results file containing the movement parameters (movpar.txt)", + ) + field = File( + exists=True, + argstr="--field=%s", + desc=("Non-topup derived fieldmap scaled in Hz"), ) - field = File(argstr="--field=%s", desc=("Non-topup derived fieldmap scaled in Hz")) field_mat = File( exists=True, argstr="--field_mat=%s", @@ -725,12 +729,14 @@ class EddyInputSpec(FSLCommandInputSpec): requires=["repol"], min_ver="5.0.10", ) - mb = traits.Int(argstr="--mb=%s", desc="Multi-band factor", min_ver="5.0.10") - mb_offs = traits.Enum( + multiband_factor = traits.Int( + argstr="--mb=%s", desc="Multi-band factor", min_ver="5.0.10" + ) + multiband_offset = traits.Enum( 0, 1, -1, - argstr="--mb_offs=%s", + argstr="--mb_offs=%d", desc=( "Multi-band offset (-1 if bottom slice removed, 1 if " "top slice removed" ), @@ -744,7 +750,7 @@ class EddyInputSpec(FSLCommandInputSpec): requires=["use_cuda"], min_ver="5.0.11", ) - s2v_niter = traits.Int( + slice2vol_iterations = traits.Int( argstr="--s2v_niter=%s", desc="Number of iterations for slice-to-vol", requires=["mporder"], From bf60b75094baa41689e22d69e1314143532abc1d Mon Sep 17 00:00:00 2001 From: mjoseph Date: Wed, 18 Sep 2019 14:20:01 -0400 Subject: [PATCH 16/19] update variable names --- nipype/interfaces/fsl/epi.py | 36 +++++++++---------- nipype/interfaces/fsl/tests/test_auto_Eddy.py | 29 +++++++++------ 2 files changed, 35 insertions(+), 30 deletions(-) diff --git a/nipype/interfaces/fsl/epi.py b/nipype/interfaces/fsl/epi.py index 1c32ad318a..f4cd32a61b 100644 --- a/nipype/interfaces/fsl/epi.py +++ b/nipype/interfaces/fsl/epi.py @@ -675,8 +675,6 @@ class EddyInputSpec(FSLCommandInputSpec): desc="Do NOT perform a post-eddy alignment of " "shells", ) fwhm = traits.Float( - default_value=0.0, - usedefault=True, desc=("FWHM for conditioning filter when estimating " "the parameters"), argstr="--fwhm=%s", ) @@ -740,7 +738,7 @@ class EddyInputSpec(FSLCommandInputSpec): desc=( "Multi-band offset (-1 if bottom slice removed, 1 if " "top slice removed" ), - requires=["mb"], + requires=["multiband_factor"], min_ver="5.0.10", ) @@ -750,19 +748,19 @@ class EddyInputSpec(FSLCommandInputSpec): requires=["use_cuda"], min_ver="5.0.11", ) - slice2vol_iterations = traits.Int( - argstr="--s2v_niter=%s", + slice2vol_niter = traits.Int( + argstr="--s2v_niter=%d", desc="Number of iterations for slice-to-vol", requires=["mporder"], min_ver="5.0.11", ) - s2v_lambda = traits.Int( - agstr="--s2v_lambda", + slice2vol_lambda = traits.Int( + argstr="--s2v_lambda=%d", desc="Regularisation weight for slice-to-vol movement (reasonable range 1-10)", requires=["mporder"], min_ver="5.0.11", ) - s2v_interp = traits.Enum( + slice2vol_interp = traits.Enum( "trilinear", "spline", argstr="--s2v_interp=%s", @@ -770,7 +768,7 @@ class EddyInputSpec(FSLCommandInputSpec): requires=["mporder"], min_ver="5.0.11", ) - slspec = traits.File( + slice_order = traits.File( exists=True, argstr="--slspec=%s", desc="Name of text file completely specifying slice/group acquisition", @@ -783,7 +781,7 @@ class EddyInputSpec(FSLCommandInputSpec): argstr="--json=%s", desc="Name of .json text file with information about slice timing", requires=["mporder"], - xor=["slspec"], + xor=["slice_order"], min_ver="6.0.1", ) @@ -961,7 +959,7 @@ class Eddy(FSLCommand): Running eddy on an Nvidia GPU using cuda: >>> eddy.inputs.use_cuda = True >>> eddy.cmdline # doctest: +ELLIPSIS - 'eddy_cuda --flm=quadratic --ff=10.0 --fwhm=0.0 \ + 'eddy_cuda --flm=quadratic --ff=10.0 \ --acqp=epi_acqp.txt --bvals=bvals.scheme --bvecs=bvecs.scheme \ --imain=epi.nii --index=epi_index.txt --mask=epi_mask.nii \ --interp=spline --resamp=jac --niter=5 --nvoxhp=1000 \ @@ -970,7 +968,7 @@ class Eddy(FSLCommand): Running eddy on a CPU using OpenMP: >>> eddy.inputs.use_cuda = False >>> eddy.cmdline # doctest: +ELLIPSIS - 'eddy_openmp --flm=quadratic --ff=10.0 --fwhm=0.0 \ + 'eddy_openmp --flm=quadratic --ff=10.0 \ --acqp=epi_acqp.txt --bvals=bvals.scheme --bvecs=bvecs.scheme \ --imain=epi.nii --index=epi_index.txt --mask=epi_mask.nii \ --interp=spline --resamp=jac --niter=5 --nvoxhp=1000 \ @@ -979,17 +977,17 @@ class Eddy(FSLCommand): Running eddy with slice-to-volume motion correction: >>> eddy.inputs.use_cuda = True >>> eddy.inputs.mporder = 6 - >>> eddy.inputs.s2v_niter = 5 - >>> eddy.inputs.s2v_lambda = 1 - >>> eddy.inputs.s2v_interp = 'trilinear' - >>> eddy.inputs.slspec = 'epi_slspec.txt' + >>> eddy.inputs.slice2vol_niter = 5 + >>> eddy.inputs.slice2vol_lambda = 1 + >>> eddy.inputs.slice2vol_interp = 'trilinear' + >>> eddy.inputs.slice_order = 'epi_slspec.txt' >>> eddy.cmdline # doctest: +ELLIPSIS - 'eddy_cuda --flm=quadratic --ff=10.0 --fwhm=0.0 \ + 'eddy_cuda --flm=quadratic --ff=10.0 \ --acqp=epi_acqp.txt --bvals=bvals.scheme --bvecs=bvecs.scheme \ --imain=epi.nii --index=epi_index.txt --mask=epi_mask.nii \ --interp=spline --resamp=jac --mporder=6 --niter=5 --nvoxhp=1000 \ ---out=.../eddy_corrected --s2v_interp=trilinear --s2v_niter=5 \ ---slm=none --slspec=epi_slspec.txt' +--out=.../eddy_corrected --s2v_interp=trilinear --s2v_lambda=1 \ +--s2v_niter=5 --slspec=epi_slspec.txt --slm=none' >>> res = eddy.run() # doctest: +SKIP """ diff --git a/nipype/interfaces/fsl/tests/test_auto_Eddy.py b/nipype/interfaces/fsl/tests/test_auto_Eddy.py index 224612cbe1..4a2d245a23 100644 --- a/nipype/interfaces/fsl/tests/test_auto_Eddy.py +++ b/nipype/interfaces/fsl/tests/test_auto_Eddy.py @@ -17,7 +17,7 @@ def test_Eddy_inputs(): field_mat=dict(argstr="--field_mat=%s", extensions=None,), flm=dict(argstr="--flm=%s", usedefault=True,), fudge_factor=dict(argstr="--ff=%s", usedefault=True,), - fwhm=dict(argstr="--fwhm=%s", usedefault=True,), + fwhm=dict(argstr="--fwhm=%s",), in_acqp=dict(argstr="--acqp=%s", extensions=None, mandatory=True,), in_bval=dict(argstr="--bvals=%s", extensions=None, mandatory=True,), in_bvec=dict(argstr="--bvecs=%s", extensions=None, mandatory=True,), @@ -32,10 +32,11 @@ def test_Eddy_inputs(): interp=dict(argstr="--interp=%s", usedefault=True,), is_shelled=dict(argstr="--data_is_shelled",), json=dict( - argstr="--json=%s", min_ver="6.0.1", requires=["mporder"], xor=["slspec"], + argstr="--json=%s", + min_ver="6.0.1", + requires=["mporder"], + xor=["slice_order"], ), - mb=dict(argstr="--mb=%s", min_ver="5.0.10",), - mb_offs=dict(argstr="--mb_offs=%s", min_ver="5.0.10", requires=["mb"],), mbs_ksp=dict( argstr="--mbs_ksp=%smm", min_ver="6.0.1", @@ -53,6 +54,10 @@ def test_Eddy_inputs(): ), method=dict(argstr="--resamp=%s", usedefault=True,), mporder=dict(argstr="--mporder=%s", min_ver="5.0.11", requires=["use_cuda"],), + multiband_factor=dict(argstr="--mb=%s", min_ver="5.0.10",), + multiband_offset=dict( + argstr="--mb_offs=%d", min_ver="5.0.10", requires=["multiband_factor"], + ), niter=dict(argstr="--niter=%s", usedefault=True,), num_threads=dict(nohash=True, usedefault=True,), nvoxhp=dict(argstr="--nvoxhp=%s", usedefault=True,), @@ -65,18 +70,20 @@ def test_Eddy_inputs(): output_type=dict(), repol=dict(argstr="--repol",), residuals=dict(argstr="--residuals", min_ver="5.0.10",), - s2v_interp=dict( + session=dict(argstr="--session=%s", extensions=None,), + slice2vol_interp=dict( argstr="--s2v_interp=%s", min_ver="5.0.11", requires=["mporder"], ), - s2v_lambda=dict(agstr="--s2v_lambda", min_ver="5.0.11", requires=["mporder"],), - s2v_niter=dict( - argstr="--s2v_niter=%s", min_ver="5.0.11", requires=["mporder"], + slice2vol_lambda=dict( + argstr="--s2v_lambda=%d", min_ver="5.0.11", requires=["mporder"], ), - session=dict(argstr="--session=%s", extensions=None,), - slm=dict(argstr="--slm=%s", usedefault=True,), - slspec=dict( + slice2vol_niter=dict( + argstr="--s2v_niter=%d", min_ver="5.0.11", requires=["mporder"], + ), + slice_order=dict( argstr="--slspec=%s", min_ver="5.0.11", requires=["mporder"], xor=["json"], ), + slm=dict(argstr="--slm=%s", usedefault=True,), use_cuda=dict(), ) inputs = Eddy.input_spec() From da7dd08c6720ae6ddc92b36c53e192e45c224b1c Mon Sep 17 00:00:00 2001 From: mjoseph Date: Wed, 18 Sep 2019 14:34:11 -0400 Subject: [PATCH 17/19] modified boolean traits to type enumerator --- nipype/interfaces/fsl/epi.py | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/nipype/interfaces/fsl/epi.py b/nipype/interfaces/fsl/epi.py index f4cd32a61b..1704e18d32 100644 --- a/nipype/interfaces/fsl/epi.py +++ b/nipype/interfaces/fsl/epi.py @@ -689,8 +689,8 @@ class EddyInputSpec(FSLCommandInputSpec): desc=("Final resampling method (jacobian/least " "squares)"), ) - repol = traits.Bool( - False, argstr="--repol", desc="Detect and replace outlier slices" + repol = traits.Enum( + True, argstr="--repol", desc="Detect and replace outlier slices" ) outlier_nstd = traits.Int( argstr="--ol_nstd", @@ -785,8 +785,8 @@ class EddyInputSpec(FSLCommandInputSpec): min_ver="6.0.1", ) - estimate_move_by_susceptibility = traits.Bool( - False, + estimate_move_by_susceptibility = traits.Enum( + True, argstr="--estimate_move_by_susceptibility", desc="Estimate how susceptibility field changes with subject movement", min_ver="6.0.1", @@ -823,7 +823,7 @@ class EddyInputSpec(FSLCommandInputSpec): ), ) - use_cuda = traits.Bool(False, desc="Run eddy using cuda gpu") + use_cuda = traits.Enum(True, desc="Run eddy using cuda gpu") cnr_maps = traits.Bool( False, desc="Output CNR-Maps", argstr="--cnr_maps", min_ver="5.0.10" ) @@ -963,19 +963,9 @@ class Eddy(FSLCommand): --acqp=epi_acqp.txt --bvals=bvals.scheme --bvecs=bvecs.scheme \ --imain=epi.nii --index=epi_index.txt --mask=epi_mask.nii \ --interp=spline --resamp=jac --niter=5 --nvoxhp=1000 \ ---out=.../eddy_corrected --slm=none' - - Running eddy on a CPU using OpenMP: - >>> eddy.inputs.use_cuda = False - >>> eddy.cmdline # doctest: +ELLIPSIS - 'eddy_openmp --flm=quadratic --ff=10.0 \ ---acqp=epi_acqp.txt --bvals=bvals.scheme --bvecs=bvecs.scheme \ ---imain=epi.nii --index=epi_index.txt --mask=epi_mask.nii \ ---interp=spline --resamp=jac --niter=5 --nvoxhp=1000 \ --out=.../eddy_corrected --slm=none' Running eddy with slice-to-volume motion correction: - >>> eddy.inputs.use_cuda = True >>> eddy.inputs.mporder = 6 >>> eddy.inputs.slice2vol_niter = 5 >>> eddy.inputs.slice2vol_lambda = 1 From 5cbbb147db7aeea2d10b370941e98937dafa76be Mon Sep 17 00:00:00 2001 From: mjoseph Date: Fri, 25 Oct 2019 15:06:21 -0400 Subject: [PATCH 18/19] revert enum to bool --- nipype/interfaces/fsl/epi.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/nipype/interfaces/fsl/epi.py b/nipype/interfaces/fsl/epi.py index 1704e18d32..92fad77100 100644 --- a/nipype/interfaces/fsl/epi.py +++ b/nipype/interfaces/fsl/epi.py @@ -689,8 +689,8 @@ class EddyInputSpec(FSLCommandInputSpec): desc=("Final resampling method (jacobian/least " "squares)"), ) - repol = traits.Enum( - True, argstr="--repol", desc="Detect and replace outlier slices" + repol = traits.Bool( + False, argstr="--repol", desc="Detect and replace outlier slices" ) outlier_nstd = traits.Int( argstr="--ol_nstd", @@ -785,8 +785,8 @@ class EddyInputSpec(FSLCommandInputSpec): min_ver="6.0.1", ) - estimate_move_by_susceptibility = traits.Enum( - True, + estimate_move_by_susceptibility = traits.Bool( + False, argstr="--estimate_move_by_susceptibility", desc="Estimate how susceptibility field changes with subject movement", min_ver="6.0.1", @@ -823,7 +823,7 @@ class EddyInputSpec(FSLCommandInputSpec): ), ) - use_cuda = traits.Enum(True, desc="Run eddy using cuda gpu") + use_cuda = traits.Bool(False, desc="Run eddy using cuda gpu") cnr_maps = traits.Bool( False, desc="Output CNR-Maps", argstr="--cnr_maps", min_ver="5.0.10" ) From 42d00c744c226e9e899788aacaec7bf2cec2ec65 Mon Sep 17 00:00:00 2001 From: Michael Joseph Date: Mon, 18 Nov 2019 15:21:29 -0500 Subject: [PATCH 19/19] fix formatting --- nipype/interfaces/fsl/epi.py | 106 +++++++++++++---------------------- 1 file changed, 39 insertions(+), 67 deletions(-) diff --git a/nipype/interfaces/fsl/epi.py b/nipype/interfaces/fsl/epi.py index 92fad77100..eeab08371e 100644 --- a/nipype/interfaces/fsl/epi.py +++ b/nipype/interfaces/fsl/epi.py @@ -608,16 +608,13 @@ class EddyInputSpec(FSLCommandInputSpec): field = File( exists=True, argstr="--field=%s", - desc=("Non-topup derived fieldmap scaled in Hz"), + desc="Non-topup derived fieldmap scaled in Hz", ) field_mat = File( exists=True, argstr="--field_mat=%s", - desc=( - "Matrix specifying the relative positions of " - "the fieldmap, --field, and the first volume " - "of the input file, --imain" - ), + desc="Matrix specifying the relative positions of the fieldmap, " + "--field, and the first volume of the input file, --imain", ) flm = traits.Enum( @@ -656,26 +653,26 @@ class EddyInputSpec(FSLCommandInputSpec): default_value=1000, usedefault=True, argstr="--nvoxhp=%s", - desc=("# of voxels used to estimate the " "hyperparameters"), + desc="# of voxels used to estimate the hyperparameters", ) fudge_factor = traits.Float( default_value=10.0, usedefault=True, argstr="--ff=%s", - desc=("Fudge factor for hyperparameter " "error variance"), + desc="Fudge factor for hyperparameter error variance", ) dont_sep_offs_move = traits.Bool( False, argstr="--dont_sep_offs_move", - desc=("Do NOT attempt to separate " "field offset from subject " "movement"), + desc="Do NOT attempt to separate field offset from subject movement", ) dont_peas = traits.Bool( False, argstr="--dont_peas", - desc="Do NOT perform a post-eddy alignment of " "shells", + desc="Do NOT perform a post-eddy alignment of shells", ) fwhm = traits.Float( - desc=("FWHM for conditioning filter when estimating " "the parameters"), + desc="FWHM for conditioning filter when estimating the parameters", argstr="--fwhm=%s", ) niter = traits.Int( @@ -686,7 +683,7 @@ class EddyInputSpec(FSLCommandInputSpec): "lsr", usedefault=True, argstr="--resamp=%s", - desc=("Final resampling method (jacobian/least " "squares)"), + desc="Final resampling method (jacobian/least squares)", ) repol = traits.Bool( @@ -735,9 +732,7 @@ class EddyInputSpec(FSLCommandInputSpec): 1, -1, argstr="--mb_offs=%d", - desc=( - "Multi-band offset (-1 if bottom slice removed, 1 if " "top slice removed" - ), + desc="Multi-band offset (-1 if bottom slice removed, 1 if top slice removed", requires=["multiband_factor"], min_ver="5.0.10", ) @@ -816,11 +811,8 @@ class EddyInputSpec(FSLCommandInputSpec): is_shelled = traits.Bool( False, argstr="--data_is_shelled", - desc=( - "Override internal check to ensure that " - "date are acquired on a set of b-value " - "shells" - ), + desc="Override internal check to ensure that date are acquired " + "on a set of b-value shells", ) use_cuda = traits.Bool(False, desc="Run eddy using cuda gpu") @@ -838,9 +830,7 @@ class EddyOutputSpec(TraitedSpec): ) out_parameter = File( exists=True, - desc=( - "Text file with parameters defining the field and" "movement for each scan" - ), + desc="Text file with parameters defining the field and movement for each scan", ) out_rotated_bvecs = File( exists=True, desc="File containing rotated b-values for all volumes" @@ -855,74 +845,56 @@ class EddyOutputSpec(TraitedSpec): ) out_shell_alignment_parameters = File( exists=True, - desc=( - "Text file containing rigid body movement parameters " - "between the different shells as estimated by a " - "post-hoc mutual information based registration" - ), + desc="Text file containing rigid body movement parameters " + "between the different shells as estimated by a " + "post-hoc mutual information based registration", ) out_shell_pe_translation_parameters = File( exists=True, - desc=( - "Text file containing translation along the PE-direction " - "between the different shells as estimated by a " - "post-hoc mutual information based registration" - ), + desc="Text file containing translation along the PE-direction " + "between the different shells as estimated by a " + "post-hoc mutual information based registration", ) out_shell_pe_translation_parameters = File( exists=True, - desc=( - "Text file containing translation along the PE-direction " - "between the different shells as estimated by a " - "post-hoc mutual information based registration" - ), + desc="Text file containing translation along the PE-direction " + "between the different shells as estimated by a " + "post-hoc mutual information based registration", ) out_outlier_map = File( exists=True, - desc=( - "Matrix where rows represent volumes and columns represent " - 'slices. "0" indicates that scan-slice is not an outlier ' - 'and "1" indicates that it is' - ), + desc="Matrix where rows represent volumes and columns represent " + 'slices. "0" indicates that scan-slice is not an outlier ' + 'and "1" indicates that it is', ) out_outlier_n_stdev_map = File( exists=True, - desc=( - "Matrix where rows represent volumes and columns represent " - "slices. Values indicate number of standard deviations off the " - "mean difference between observation and prediction is" - ), + desc="Matrix where rows represent volumes and columns represent " + "slices. Values indicate number of standard deviations off the " + "mean difference between observation and prediction is", ) out_outlier_n_sqr_stdev_map = File( exists=True, - desc=( - "Matrix where rows represent volumes and columns represent " - "slices. Values indicate number of standard deivations off the " - "square root of the mean squared difference between observation " - "and prediction is" - ), + desc="Matrix where rows represent volumes and columns represent " + "slices. Values indicate number of standard deivations off the " + "square root of the mean squared difference between observation " + "and prediction is", ) out_outlier_report = File( exists=True, - desc=( - "Text file with a plain language report on what " - "outlier slices eddy has found" - ), + desc="Text file with a plain language report on what " + "outlier slices eddy has found", ) out_outlier_free = File( exists=True, - desc=( - "4D image file not corrected for susceptibility or eddy-" - "current distortions or subject movement but with outlier " - "slices replaced" - ), + desc="4D image file not corrected for susceptibility or eddy-" + "current distortions or subject movement but with outlier " + "slices replaced", ) out_movement_over_time = File( exists=True, - desc=( - "Text file containing translations (mm) and rotations " - "(radians) for each excitation" - ), + desc="Text file containing translations (mm) and rotations " + "(radians) for each excitation", ) out_cnr_maps = File(exists=True, desc="path/name of file with the cnr_maps") out_residuals = File(exists=True, desc="path/name of file with the residuals")