From 74deb3849e18f5e5202bf8a40208b017dc10c345 Mon Sep 17 00:00:00 2001 From: salma1601 Date: Sun, 8 Oct 2017 20:04:53 +0200 Subject: [PATCH 1/4] allow functions in NwarpCat inputs --- nipype/interfaces/afni/__init__.py | 2 +- .../afni/tests/test_auto_NwarpCat.py | 56 ++++++++++ nipype/interfaces/afni/utils.py | 102 ++++++++++++++++++ 3 files changed, 159 insertions(+), 1 deletion(-) create mode 100644 nipype/interfaces/afni/tests/test_auto_NwarpCat.py diff --git a/nipype/interfaces/afni/__init__.py b/nipype/interfaces/afni/__init__.py index f4089e4eda..ee79c409b1 100644 --- a/nipype/interfaces/afni/__init__.py +++ b/nipype/interfaces/afni/__init__.py @@ -22,7 +22,7 @@ from .utils import (ABoverlap, AFNItoNIFTI, Autobox, Axialize, BrickStat, Bucket, Calc, Cat, CatMatvec, CenterMass, Copy, Dot, Edge3, Eval, FWHMx, MaskTool, Merge, Notes, NwarpApply, - OneDToolPy, + NwarpCat, OneDToolPy, Refit, Resample, TCat, TCatSubBrick, TStat, To3D, Unifize, Undump, ZCutUp, GCOR, Zcat, Zeropad) diff --git a/nipype/interfaces/afni/tests/test_auto_NwarpCat.py b/nipype/interfaces/afni/tests/test_auto_NwarpCat.py new file mode 100644 index 0000000000..66153be88c --- /dev/null +++ b/nipype/interfaces/afni/tests/test_auto_NwarpCat.py @@ -0,0 +1,56 @@ +# AUTO-GENERATED by tools/checkspecs.py - DO NOT EDIT +from __future__ import unicode_literals +from ..utils import NwarpCat + + +def test_NwarpCat_inputs(): + input_map = dict(args=dict(argstr='%s', + ), + environ=dict(nohash=True, + usedefault=True, + ), + expad=dict(argstr='-expad %d', + ), + ignore_exception=dict(nohash=True, + usedefault=True, + ), + in_files=dict(argstr='%s', + descr='list of tuples of 3D warps and associated functions', + mandatory=True, + position=-1, + ), + interp=dict(argstr='-interp %s', + ), + inv_warp=dict(argstr='-iwarp', + ), + num_threads=dict(nohash=True, + usedefault=True, + ), + out_file=dict(argstr='-prefix %s', + name_source='in_file', + name_template='%s_Nwarp', + ), + outputtype=dict(), + space=dict(argstr='-space %s', + ), + terminal_output=dict(deprecated='1.0.0', + nohash=True, + ), + verb=dict(argstr='-verb', + ), + ) + inputs = NwarpCat.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_NwarpCat_outputs(): + output_map = dict(out_file=dict(), + ) + outputs = NwarpCat.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 48f1303d2f..112a3379f8 100644 --- a/nipype/interfaces/afni/utils.py +++ b/nipype/interfaces/afni/utils.py @@ -1588,6 +1588,108 @@ class NwarpApply(AFNICommandBase): input_spec = NwarpApplyInputSpec output_spec = AFNICommandOutputSpec + +class NwarpCatInputSpec(AFNICommandInputSpec): + in_files = traits.List( + traits.Either( + traits.File(), traits.Tuple( + traits.Enum('IDENT', 'INV', 'SQRT', 'SQRTINV'), traits.File())), + descr="list of tuples of 3D warps and associated functions", + mandatory=True, + argstr="%s", + position=-1) + space = traits.String( + desc='string to attach to the output dataset as its atlas space ' + 'marker.', + argstr='-space %s') + inv_warp = traits.Bool( + desc='invert the final warp before output', + argstr='-iwarp') + interp = traits.Enum( + 'linear', 'quintic', 'wsinc5', + desc='specify a different interpolation method than might ' + 'be used for the warp', + argstr='-interp %s', + default='wsinc5') + expad = traits.Int( + desc='Pad the nonlinear warps by the given number of voxels voxels in ' + 'all directions. The warp displacements are extended by linear ' + 'extrapolation from the faces of the input grid..', + argstr='-expad %d') + out_file = File( + name_template='%s_Nwarp', + desc='output image file name', + argstr='-prefix %s', + name_source='in_file') + verb = traits.Bool( + desc='be verbose', + argstr='-verb') + + +class NwarpCat(AFNICommand): + """Catenates (composes) 3D warps defined on a grid, OR via a matrix. + + .. note:: + + * All transformations are from DICOM xyz (in mm) to DICOM xyz. + + * Matrix warps are in files that end in '.1D' or in '.txt'. A matrix + warp file should have 12 numbers in it, as output (for example), by + '3dAllineate -1Dmatrix_save'. + + * Nonlinear warps are in dataset files (AFNI .HEAD/.BRIK or NIfTI .nii) + with 3 sub-bricks giving the DICOM order xyz grid displacements in mm. + + * If all the input warps are matrices, then the output is a matrix + and will be written to the file 'prefix.aff12.1D'. + Unless the prefix already contains the string '.1D', in which case + the filename is just the prefix. + + * If 'prefix' is just 'stdout', then the output matrix is written + to standard output. + In any of these cases, the output format is 12 numbers in one row. + + * If any of the input warps are datasets, they must all be defined on + the same 3D grid! + And of course, then the output will be a dataset on the same grid. + However, you can expand the grid using the '-expad' option. + + * The order of operations in the final (output) warp is, for the + case of 3 input warps: + + OUTPUT(x) = warp3( warp2( warp1(x) ) ) + + That is, warp1 is applied first, then warp2, et cetera. + The 3D x coordinates are taken from each grid location in the + first dataset defined on a grid. + + For complete details, see the `3dNwarpCat Documentation. + `_ + + Examples + ======== + + >>> from nipype.interfaces import afni + >>> nwarpcat = afni.NwarpCat() + >>> nwarpcat.inputs.in_files = ['Q25_warp+tlrc.HEAD', ('IDENT', 'structural.nii')] + >>> nwarpcat.inputs.out_file = 'Fred_total_WARP' + >>> nwarpcat.cmdline # doctest: +ALLOW_UNICODE + "3dNwarpCat -prefix Fred_total_WARP Q25_warp+tlrc.HEAD 'IDENT(structural.nii)'" + >>> res = nwarpcat.run() # doctest: +SKIP + + """ + _cmd = '3dNwarpCat' + input_spec = NwarpCatInputSpec + output_spec = AFNICommandOutputSpec + + def _format_arg(self, name, spec, value): + if name == 'in_files': + return spec.argstr%(' '.join(["'" + v[0] + "(" + v[1] + ")'" + if isinstance(v, tuple) else v + for v in value])) + return super(NwarpCat, self)._format_arg(name, spec, value) + + class OneDToolPyInputSpec(AFNIPythonCommandInputSpec): in_file = File( desc='input file to OneDTool', From 480ba5c4e586e86180991fd4be30032ade009de7 Mon Sep 17 00:00:00 2001 From: salma1601 Date: Tue, 10 Oct 2017 14:56:20 +0200 Subject: [PATCH 2/4] fix output file generation --- nipype/interfaces/afni/utils.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/nipype/interfaces/afni/utils.py b/nipype/interfaces/afni/utils.py index 112a3379f8..bb0db7ab70 100644 --- a/nipype/interfaces/afni/utils.py +++ b/nipype/interfaces/afni/utils.py @@ -1617,10 +1617,10 @@ class NwarpCatInputSpec(AFNICommandInputSpec): 'extrapolation from the faces of the input grid..', argstr='-expad %d') out_file = File( - name_template='%s_Nwarp', + name_template='%s_NwarpCat', desc='output image file name', argstr='-prefix %s', - name_source='in_file') + name_source='in_files') verb = traits.Bool( desc='be verbose', argstr='-verb') @@ -1689,6 +1689,19 @@ def _format_arg(self, name, spec, value): for v in value])) return super(NwarpCat, self)._format_arg(name, spec, value) + def _gen_filename(self, name): + if name == 'out_file': + return self._gen_fname(self.inputs.in_files[0][0], suffix='_tcat') + + def _list_outputs(self): + outputs = self.output_spec().get() + if isdefined(self.inputs.out_file): + outputs['out_file'] = os.path.abspath(self.inputs.out_file) + else: + outputs['out_file'] = os.path.abspath(self._gen_fname( + self.inputs.in_files[0], suffix='_NwarpCat+tlrc', ext='.HEAD')) + return outputs + class OneDToolPyInputSpec(AFNIPythonCommandInputSpec): in_file = File( From a6ddc0cf7375d91b8d7caee126d02b62e19261b9 Mon Sep 17 00:00:00 2001 From: salma1601 Date: Tue, 10 Oct 2017 15:06:51 +0200 Subject: [PATCH 3/4] update test --- nipype/interfaces/afni/tests/test_auto_NwarpCat.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nipype/interfaces/afni/tests/test_auto_NwarpCat.py b/nipype/interfaces/afni/tests/test_auto_NwarpCat.py index 66153be88c..6e5077e645 100644 --- a/nipype/interfaces/afni/tests/test_auto_NwarpCat.py +++ b/nipype/interfaces/afni/tests/test_auto_NwarpCat.py @@ -27,8 +27,8 @@ def test_NwarpCat_inputs(): usedefault=True, ), out_file=dict(argstr='-prefix %s', - name_source='in_file', - name_template='%s_Nwarp', + name_source='in_files', + name_template='%s_NwarpCat', ), outputtype=dict(), space=dict(argstr='-space %s', From 988b01de52279c96938cbf1f07bde30698fafc14 Mon Sep 17 00:00:00 2001 From: salma1601 Date: Fri, 27 Oct 2017 15:18:15 +0200 Subject: [PATCH 4/4] fix output default name --- nipype/interfaces/afni/utils.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/nipype/interfaces/afni/utils.py b/nipype/interfaces/afni/utils.py index bb0db7ab70..f5ed235f92 100644 --- a/nipype/interfaces/afni/utils.py +++ b/nipype/interfaces/afni/utils.py @@ -1592,8 +1592,9 @@ class NwarpApply(AFNICommandBase): class NwarpCatInputSpec(AFNICommandInputSpec): in_files = traits.List( traits.Either( - traits.File(), traits.Tuple( - traits.Enum('IDENT', 'INV', 'SQRT', 'SQRTINV'), traits.File())), + traits.File(), + traits.Tuple(traits.Enum('IDENT', 'INV', 'SQRT', 'SQRTINV'), + traits.File())), descr="list of tuples of 3D warps and associated functions", mandatory=True, argstr="%s", @@ -1684,14 +1685,15 @@ class NwarpCat(AFNICommand): def _format_arg(self, name, spec, value): if name == 'in_files': - return spec.argstr%(' '.join(["'" + v[0] + "(" + v[1] + ")'" - if isinstance(v, tuple) else v - for v in value])) + return spec.argstr % (' '.join(["'" + v[0] + "(" + v[1] + ")'" + if isinstance(v, tuple) else v + for v in value])) return super(NwarpCat, self)._format_arg(name, spec, value) def _gen_filename(self, name): if name == 'out_file': - return self._gen_fname(self.inputs.in_files[0][0], suffix='_tcat') + return self._gen_fname(self.inputs.in_files[0][0], + suffix='_NwarpCat') def _list_outputs(self): outputs = self.output_spec().get()