diff --git a/nipype/interfaces/afni/__init__.py b/nipype/interfaces/afni/__init__.py index 9cb519a2a2..b28e5961f7 100644 --- a/nipype/interfaces/afni/__init__.py +++ b/nipype/interfaces/afni/__init__.py @@ -13,7 +13,7 @@ BlurInMask, BlurToFWHM, ClipLevel, DegreeCentrality, Despike, Detrend, ECM, Fim, Fourier, Hist, LFCD, Maskave, Means, OutlierCount, QualityIndex, ROIStats, Retroicor, Seg, SkullStrip, TCorr1D, TCorrMap, TCorrelate, TNorm, - TShift, Volreg, Warp, QwarpPlusMinus, Qwarp) + TProject, TShift, Volreg, Warp, QwarpPlusMinus, Qwarp) from .svm import (SVMTest, SVMTrain) from .utils import ( ABoverlap, AFNItoNIFTI, Autobox, Axialize, BrickStat, Bucket, Calc, Cat, diff --git a/nipype/interfaces/afni/model.py b/nipype/interfaces/afni/model.py index 903d323b4e..38ddf09520 100644 --- a/nipype/interfaces/afni/model.py +++ b/nipype/interfaces/afni/model.py @@ -153,9 +153,10 @@ class DeconvolveInputSpec(AFNICommandInputSpec): 'instead of the bucket dataset, if possible.', argstr='-cbucket %s') out_file = File(desc='output statistics file', argstr='-bucket %s') - jobs = traits.Int( + num_threads = traits.Int( desc='run the program with provided number of sub-processes', - argstr='-jobs %d') + argstr='-jobs %d', + nohash=True) fout = traits.Bool( desc='output F-statistic for each stimulus', argstr='-fout') rout = traits.Bool( @@ -165,6 +166,10 @@ class DeconvolveInputSpec(AFNICommandInputSpec): vout = traits.Bool( desc='output the sample variance (MSE) for each stimulus', argstr='-vout') + nofdr = traits.Bool( + desc="Don't compute the statistic-vs-FDR curves for the bucket " + "dataset.", + argstr='-noFDR') global_times = traits.Bool( desc='use global timing for stimulus timing files', argstr='-global_times', diff --git a/nipype/interfaces/afni/preprocess.py b/nipype/interfaces/afni/preprocess.py index b266d997cf..666f4b7be1 100644 --- a/nipype/interfaces/afni/preprocess.py +++ b/nipype/interfaces/afni/preprocess.py @@ -2406,6 +2406,171 @@ class TNorm(AFNICommand): output_spec = AFNICommandOutputSpec +class TProjectInputSpec(AFNICommandInputSpec): + in_file = File( + desc='input file to 3dTproject', + argstr='-input %s', + position=1, + mandatory=True, + exists=True, + copyfile=False) + out_file = File( + name_template='%s_tproject', + desc='output image file name', + position=-1, + argstr='-prefix %s', + name_source='in_file') + censor = File( + desc="""filename of censor .1D time series + * This is a file of 1s and 0s, indicating which + time points are to be included (1) and which are + to be excluded (0).""", + argstr="-censor %s", + exists=True) + censortr = traits.List( + traits.Str(), + desc="""list of strings that specify time indexes + to be removed from the analysis. Each string is + of one of the following forms: + 37 => remove global time index #37 + 2:37 => remove time index #37 in run #2 + 37..47 => remove global time indexes #37-47 + 37-47 => same as above + 2:37..47 => remove time indexes #37-47 in run #2 + *:0-2 => remove time indexes #0-2 in all runs + +Time indexes within each run start at 0. + +Run indexes start at 1 (just be to confusing). + +N.B.: 2:37,47 means index #37 in run #2 and + global time index 47; it does NOT mean + index #37 in run #2 AND index #47 in run #2.""", + argstr="-CENSORTR %s") + cenmode = traits.Enum( + 'KILL', 'ZERO', 'NTRP', + desc="""specifies how censored time points are treated in + the output dataset: + + mode = ZERO ==> put zero values in their place + ==> output datset is same length as input + + mode = KILL ==> remove those time points + ==> output dataset is shorter than input + + mode = NTRP ==> censored values are replaced by interpolated + neighboring (in time) non-censored values, + BEFORE any projections, and then the + analysis proceeds without actual removal + of any time points -- this feature is to + keep the Spanish Inquisition happy. + * The default mode is KILL !!!""", + argstr='-cenmode %s') + concat = File( + desc="""The catenation file, as in 3dDeconvolve, containing the + TR indexes of the start points for each contiguous run + within the input dataset (the first entry should be 0). + ++ Also as in 3dDeconvolve, if the input dataset is + automatically catenated from a collection of datasets, + then the run start indexes are determined directly, + and '-concat' is not needed (and will be ignored). + ++ Each run must have at least 9 time points AFTER + censoring, or the program will not work! + ++ The only use made of this input is in setting up + the bandpass/stopband regressors. + ++ '-ort' and '-dsort' regressors run through all time + points, as read in. If you want separate projections + in each run, then you must either break these ort files + into appropriate components, OR you must run 3dTproject + for each run separately, using the appropriate pieces + from the ort files via the '{...}' selector for the + 1D files and the '[...]' selector for the datasets.""", + exists=True, + argstr='-concat %s') + noblock = traits.Bool( + desc="""Also as in 3dDeconvolve, if you want the program to treat + an auto-catenated dataset as one long run, use this option. + ++ However, '-noblock' will not affect catenation if you use + the '-concat' option.""", + argstr='-noblock') + ort = File( + desc="""Remove each column in file + ++ Each column will have its mean removed.""", + exists=True, + argstr="-ort %s") + polort = traits.Int( + desc="""Remove polynomials up to and including degree pp. + ++ Default value is 2. + ++ It makes no sense to use a value of pp greater than + 2, if you are bandpassing out the lower frequencies! + ++ For catenated datasets, each run gets a separate set + set of pp+1 Legendre polynomial regressors. + ++ Use of -polort -1 is not advised (if data mean != 0), + even if -ort contains constant terms, as all means are + removed.""", + argstr="-polort %d") + bandpass = traits.Tuple( + traits.Float, traits.Float, + desc="""Remove all frequencies EXCEPT those in the range""", + argstr='-bandpass %g %g') + stopband = traits.Tuple( + traits.Float, traits.Float, + desc="""Remove all frequencies in the range""", + argstr='-stopband %g %g') + TR = traits.Float( + desc="""Use time step dd for the frequency calculations, + rather than the value stored in the dataset header.""", + argstr='-TR %g') + mask = File( + exist=True, + desc="""Only operate on voxels nonzero in the mset dataset. + ++ Voxels outside the mask will be filled with zeros. + ++ If no masking option is given, then all voxels + will be processed.""", + argstr='-mask %s') + automask = traits.Bool( + desc="""Generate a mask automatically""", + xor=['mask'], + argstr='-automask') + blur = traits.Float( + desc="""Blur (inside the mask only) with a filter that has + width (FWHM) of fff millimeters. + ++ Spatial blurring (if done) is after the time + series filtering.""", + argstr='-blur %g') + norm = traits.Bool( + desc="""Normalize each output time series to have sum of + squares = 1. This is the LAST operation.""", + argstr='-norm') + + +class TProject(AFNICommand): + """ + This program projects (detrends) out various 'nuisance' time series from + each voxel in the input dataset. Note that all the projections are done + via linear regression, including the frequency-based options such + as '-passband'. In this way, you can bandpass time-censored data, and at + the same time, remove other time series of no interest + (e.g., physiological estimates, motion parameters). + Shifts voxel time series from input so that seperate slices are aligned to + the same temporal origin. + + For complete details, see the `3dTproject Documentation. + `_ + + Examples + ======== + + >>> from nipype.interfaces import afni + >>> tproject = afni.TProject() + >>> tproject.inputs.in_file = 'functional.nii' + >>> tproject.inputs.bandpass = (0.00667, 99999) + >>> tproject.inputs.polort = 3 + >>> tproject.inputs.automask = True + >>> tproject.inputs.out_file = 'projected.nii.gz' + >>> tproject.cmdline + '3dTproject -input functional.nii -automask -bandpass 0.00667 99999 -polort 3 -prefix projected.nii.gz' + >>> res = tproject.run() # doctest: +SKIP + + """ + _cmd = '3dTproject' + input_spec = TProjectInputSpec + output_spec = AFNICommandOutputSpec + class TShiftInputSpec(AFNICommandInputSpec): in_file = File( desc='input file to 3dTShift', diff --git a/nipype/interfaces/afni/tests/test_auto_Deconvolve.py b/nipype/interfaces/afni/tests/test_auto_Deconvolve.py index e456f97818..86f1fee093 100644 --- a/nipype/interfaces/afni/tests/test_auto_Deconvolve.py +++ b/nipype/interfaces/afni/tests/test_auto_Deconvolve.py @@ -49,7 +49,6 @@ def test_Deconvolve_inputs(): sep=' ', ), input1D=dict(argstr='-input1D %s', ), - jobs=dict(argstr='-jobs %d', ), legendre=dict(argstr='-legendre', ), local_times=dict( argstr='-local_times', @@ -59,6 +58,7 @@ def test_Deconvolve_inputs(): noblock=dict(argstr='-noblock', ), nocond=dict(argstr='-nocond', ), nodmbase=dict(argstr='-nodmbase', ), + nofdr=dict(argstr='-noFDR', ), nolegendre=dict(argstr='-nolegendre', ), nosvd=dict(argstr='-nosvd', ), num_glt=dict( @@ -70,8 +70,8 @@ def test_Deconvolve_inputs(): position=-6, ), num_threads=dict( + argstr='-jobs %d', nohash=True, - usedefault=True, ), ortvec=dict(argstr='-ortvec %s %s', ), out_file=dict(argstr='-bucket %s', ), diff --git a/nipype/interfaces/afni/tests/test_auto_TProject.py b/nipype/interfaces/afni/tests/test_auto_TProject.py new file mode 100644 index 0000000000..25a47142b9 --- /dev/null +++ b/nipype/interfaces/afni/tests/test_auto_TProject.py @@ -0,0 +1,71 @@ +# AUTO-GENERATED by tools/checkspecs.py - DO NOT EDIT +from __future__ import unicode_literals +from ..preprocess import TProject + + +def test_TProject_inputs(): + input_map = dict( + TR=dict(argstr='-TR %g', ), + args=dict(argstr='%s', ), + automask=dict( + argstr='-automask', + xor=['mask'], + ), + bandpass=dict(argstr='-bandpass %g %g', ), + blur=dict(argstr='-blur %g', ), + cenmode=dict(argstr='-cenmode %s', ), + censor=dict(argstr='-censor %s', ), + censortr=dict(argstr='-CENSORTR %s', ), + concat=dict(argstr='-concat %s', ), + environ=dict( + nohash=True, + usedefault=True, + ), + ignore_exception=dict( + deprecated='1.0.0', + nohash=True, + usedefault=True, + ), + in_file=dict( + argstr='-input %s', + copyfile=False, + mandatory=True, + position=1, + ), + mask=dict( + argstr='-mask %s', + exist=True, + ), + noblock=dict(argstr='-noblock', ), + norm=dict(argstr='-norm', ), + num_threads=dict( + nohash=True, + usedefault=True, + ), + ort=dict(argstr='-ort %s', ), + out_file=dict( + argstr='-prefix %s', + name_source='in_file', + name_template='%s_tproject', + position=-1, + ), + outputtype=dict(), + polort=dict(argstr='-polort %d', ), + stopband=dict(argstr='-stopband %g %g', ), + terminal_output=dict( + deprecated='1.0.0', + nohash=True, + ), + ) + inputs = TProject.input_spec() + + for key, metadata in list(input_map.items()): + for metakey, value in list(metadata.items()): + assert getattr(inputs.traits()[key], metakey) == value +def test_TProject_outputs(): + output_map = dict(out_file=dict(), ) + outputs = TProject.output_spec() + + for key, metadata in list(output_map.items()): + for metakey, value in list(metadata.items()): + assert getattr(outputs.traits()[key], metakey) == value diff --git a/nipype/interfaces/afni/utils.py b/nipype/interfaces/afni/utils.py index 8acdf29f92..1bd818c11d 100644 --- a/nipype/interfaces/afni/utils.py +++ b/nipype/interfaces/afni/utils.py @@ -1815,7 +1815,8 @@ def _list_outputs(self): os.getcwd(), self.inputs.show_cormat_warnings) if isdefined(self.inputs.censor_motion): outputs['out_file'] = os.path.join(os.getcwd(), - self.inputs.censor_motion[1]) + self.inputs.censor_motion[1] + + '_censor.1D') return outputs